How Prime Agent Schedules Tasks with Cron Jobs and Heartbeats
Prime Agent implements a lightweight, in-process scheduler using AgentCronJobStore for disk persistence and AgentCronScheduler for periodic execution to manage both user-defined cron jobs and internal heartbeat jobs that prevent session timeouts.
The PrimeIntellect-ai/prime-agent repository provides a coding agent infrastructure where background task scheduling and session health monitoring are critical. The system handles both user automation through cron expressions and internal "heartbeat" mechanisms that keep agent sessions alive, all orchestrated through a unified scheduling layer in packages/coding-agent/src/core/cron-jobs.ts.
Core Architecture: Store and Scheduler
The scheduling subsystem centers on two complementary classes that separate persistence from execution.
AgentCronJobStore (Persistence)
The AgentCronJobStore class handles durable storage of job definitions on disk, typically under ~/.prime-agent/cron-jobs/. It provides atomic CRUD operations including create(), createHeartbeat(), list(), cancel(), and updateRlmHeartbeat(). Each job entry tracks its source (either "cron" or "heartbeat"), status (active, paused, or cancelled), and the nextRunAt timestamp that determines execution order.
AgentCronScheduler (Execution Engine)
The AgentCronScheduler class manages an internal timer that ticks every second by default. On each tick, it calls runDue(date) to query the store for jobs whose nextRunAt timestamp has passed. When jobs are due, the scheduler invokes their handlers and recomputes the next execution time. The scheduler exposes start() and stop() methods to control the timing loop lifecycle.
How Cron Jobs Work
User-defined cron jobs are stored with source: "cron" and contain a standard cron expression (e.g., */5 * * * *) or a single-run at timestamp. The creation flow begins when a client sends a cron_add RPC to the daemon, which validates the payload and persists it via AgentCronJobStore.create(). When the scheduler’s tick detects the job is due, it executes the associated handler function and reschedules the job based on its expression.
Cancellation flows through the cron_cancel RPC, which updates the job’s status to "cancelled" in the store, causing the scheduler to skip it on subsequent ticks. Integration tests in packages/coding-agent/test/daemon-supervisor-process.test.ts validate this RPC-to-scheduler pipeline.
Maintaining Session Liveness with Heartbeats
Heartbeat jobs are specialized cron entries created via AgentCronJobStore.createHeartbeat(), distinguished by source: "heartbeat". These jobs periodically emit lightweight "ping" messages to the daemon to update the session’s last-seen timestamp, preventing timeout eviction.
Key heartbeat characteristics include:
intervalSeconds: Configurable execution interval (defaults to 30 seconds)status: Supports"active","paused", and"cancelled"states- Recovery: Survives daemon restarts by reloading from disk, validated by
packages/coding-agent/test/suite/regressions/4657-update-heartbeat-recovery.test.ts
When paused via `updateRlmHeartbeat(sessionId, jobId, { status: "pause" })", the scheduler temporarily skips the job without removing it from the store, allowing seamless resumption later.
The Scheduling Lifecycle
The complete execution flow follows these distinct stages:
- Creation: Client sends
cron_addRPC with either a cron expression or heartbeat configuration - Persistence: Daemon writes the job to
AgentCronJobStoreon disk - Ticking:
AgentCronScheduler.start()initiates a 1-second periodic timer - Execution:
runDue(now)identifies due jobs and invokes their handlers—user commands for cron jobs, daemon pings for heartbeats - Rescheduling: Upon completion, the handler updates
nextRunAt(or removes one-off jobs)
Resilience and Edge Cases
Prime Agent’s scheduler handles several failure modes to ensure robust operation:
- Process Isolation: Each agent process runs its own scheduler instance; a supervisor process aggregates jobs across workers to prevent orphaned heartbeats if a worker crashes (see
packages/coding-agent/test/suite/regressions/4527-worker-heartbeat-scheduling.test.ts) - Graceful Degradation: Jobs marked
"cancelled"are immediately dropped from the execution queue without requiring a scheduler restart - State Recovery: If the daemon restarts,
AgentCronJobStorereloads persisted jobs from disk, andAgentCronSchedulerresumes the ticking loop without losing pending executions
Implementation Examples
The following TypeScript patterns demonstrate how to interact with the scheduling API:
import { AgentCronJobStore, AgentCronScheduler } from '../core/cron-jobs';
// Initialize the store and scheduler
const cronStore = new AgentCronJobStore();
const cronScheduler = new AgentCronScheduler(cronStore);
// Create a regular cron job running every minute
const regularJob = cronStore.create({
prompt: "remind me",
schedule: "*/1 * * * *",
source: "cron",
handler: async () => {
await client.request({ type: "message", content: "⏰ One minute passed" });
},
});
// Create a heartbeat that pings the daemon every 30 seconds
const heartbeat = cronStore.createHeartbeat({
intervalSeconds: 30,
source: "heartbeat",
handler: async () => {
await client.request({ type: "heartbeat" });
},
});
// Start the scheduler (typically called by the daemon on startup)
cronScheduler.start();
// Pause the heartbeat without cancelling it
cronStore.updateRlmHeartbeat(sessionId, heartbeat.id, { status: "pause" });
Summary
- Prime Agent uses
AgentCronJobStorefor durable, disk-backed job persistence andAgentCronSchedulerfor the execution loop. - Cron jobs (
source: "cron") handle user automation via standard cron expressions managed throughcron_addandcron_cancelRPCs. - Heartbeat jobs (
source: "heartbeat") maintain session liveness through periodic pings, supporting pause/resume viaupdateRlmHeartbeat(). - The system recovers gracefully from daemon restarts by reloading jobs from
~/.prime-agent/cron-jobs/, as validated by regression test suites. - Per-process isolation ensures that crashed workers do not leak scheduler resources or stale heartbeats.
Frequently Asked Questions
What is the default heartbeat interval in Prime Agent?
The default interval is 30 seconds, configurable via the intervalSeconds parameter when calling AgentCronJobStore.createHeartbeat().
How does Prime Agent recover scheduled jobs after a daemon restart?
The daemon reloads the AgentCronJobStore from its disk location (~/.prime-agent/cron-jobs/), allowing the scheduler to resume ticking without losing pending jobs. This behavior is validated by the regression test in packages/coding-agent/test/suite/regressions/4657-update-heartbeat-recovery.test.ts.
Can heartbeat jobs be paused without cancelling them?
Yes. Calling updateRlmHeartbeat() with status: "pause" suspends the heartbeat execution while preserving its configuration, enabling later resumption without re-creating the job.
What distinguishes a heartbeat job from a regular cron job in the source code?
Heartbeat jobs have source: "heartbeat" versus source: "cron" for user tasks, are created via createHeartbeat() instead of create(), and support specific lifecycle states (active, paused, cancelled) tailored to session management rather than general automation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →