How Scheduled Prompts and Cron Jobs Function in Prime Agent
Prime Agent implements a lightweight, file-backed scheduler in packages/coding-agent/src/core/cron-jobs.ts that persists jobs as JSON records, parses multiple schedule syntaxes including standard cron expressions, and drives execution through a timer-based loop capable of handling both generic cron jobs and scheduled prompts (heartbeats) with configurable delivery modes.
Prime Agent, the open-source coding agent framework developed by PrimeIntellect-ai, includes a robust scheduling system for automating prompts and recurring tasks. The scheduler manages both traditional cron jobs and scheduled prompts—internally designated as "heartbeats"—through a unified architecture that persists state to disk and integrates seamlessly with the agent's session lifecycle. Understanding how scheduled prompts and cron jobs function in Prime Agent requires examining the core TypeScript implementation that handles job creation, persistence, and execution.
Core Architecture: The File-Backed Scheduler
At the heart of Prime Agent's scheduling capability lies the AgentCronJobStore class, which provides durable storage for job definitions. Unlike in-memory schedulers, this system maintains a JSON file (scheduled-jobs.json) that survives process restarts, enabling the agent to resume interrupted schedules upon reloading.
Job Model and Persistence
Each scheduled entity conforms to the AgentCronJob interface defined in packages/coding-agent/src/core/cron-jobs.ts. This interface captures essential metadata including status (active, paused, or completed), source (distinguishing between cron jobs and heartbeats), schedule (the parsed temporal definition), and deliveryMode (for heartbeats). The store supports two persistence modes: a global jobs file or session-artifact mode, which maintains separate scheduled-jobs.json files per session artifact to isolate job contexts.
The AgentCronJobStore handles atomic read/write operations to ensure consistency. When the daemon initializes, it instantiates this store with a path to the jobs file, immediately loading any persisted jobs into memory while maintaining the disk-based source of truth.
Schedule Parsing and Next-Run Calculation
The parseAgentCronSchedule function interprets four distinct schedule syntaxes:
in <n> <unit>– Executes once after a specified delay (e.g.,in 30m).every <n> <unit>– Recurring interval execution (e.g.,every 10m).at <ISO>– Fixed single execution at a specific ISO timestamp.- Standard 5-field cron – Traditional cron expressions or aliases like
@hourly.
This parser returns a structured schedule object and calculates the first nextRunAt timestamp. For subsequent executions, the nextRunAtForSchedule function recomputes the next run time by analyzing interval boundaries or matching against sets of allowed minutes, hours, days, and months derived from cron expressions.
Job Types and Creation Patterns
Prime Agent distinguishes between generic automation tasks and context-aware scheduled prompts, implementing separate factory methods while utilizing the same underlying storage mechanism.
Generic Cron Jobs
To create a standard cron job, invoke store.create() with a configuration object specifying source: "cron". This method validates the scheduleText, constructs an AgentCronJob with status "active", and persists it to the JSON store. Generic cron jobs execute arbitrary prompts on their defined schedule without special session handling beyond standard claim-and-run semantics.
Scheduled Prompts and Heartbeats
Scheduled prompts utilize the createHeartbeat() method (or createRlmHeartbeat() for RLM-specific variants), which automatically sets source: "heartbeat" (or "rlm_heartbeat") and applies the DEFAULT_HEARTBEAT_DELIVERY_MODE of "steer". Heartbeats support two delivery modes:
steer– Interrupts the current agent turn to deliver the prompt immediately.follow_up– Queues the prompt to run after the current operation completes.
The scheduler consults shouldDeferHeartbeatCronJob to determine whether a heartbeat should be deferred when the session is actively processing another task, preventing context disruption during critical operations.
Execution Lifecycle and Dispatch
The AgentCronScheduler class orchestrates the actual execution of due jobs through a timer-based loop that coordinates with the store's claim mechanisms.
The Scheduler Loop
Upon calling start(), the scheduler performs three critical operations:
- Recovery – Reloads the store and checks for any interrupted dispatches from previous runs.
- Scheduling – Calls
scheduleNext()to compute the earliest active job viastore.nextActiveRunAt()and sets a timeout accordingly. - Execution – When the timer fires,
runDue()invokesstore.claimDue()to atomically claim due jobs (preventing race conditions in multi-process scenarios) and executes them through therunJobhook supplied by the daemon.
After execution, the store updates job metadata through recordRunResult (for successful runs) or recordSkipResult (for deferred or failed attempts), incrementing runCount, updating lastRunAt, and recalculating nextRunAt for recurring jobs. One-shot jobs transition to "completed" status and cease scheduling.
Session Management and Rebinding
When a live session replaces a persisted session file (such as during workspace restoration), the rebindSessionJobs function updates all associated jobs to target the new session context. This rewriting operation modifies the activeSessionId, sessionId, sessionFile, and cwd fields within the job records, ensuring that restored schedules execute against the correct working directory and session state.
Delivery Mode and Deferral Logic
Heartbeats implement sophisticated delivery semantics through the deliveryMode property. When the scheduler detects an active session busy state, it evaluates shouldDeferHeartbeatCronJob to determine whether to skip the current cycle or force interruption. This mechanism ensures that critical periodic checks (like health heartbeats) can either respect ongoing work or assert priority based on configuration.
Practical Implementation Examples
The following examples demonstrate how to interact with the scheduler API directly:
// Create a generic cron job that runs a prompt every 10 minutes
import { AgentCronJobStore } from "packages/coding-agent/src/core/cron-jobs";
const store = new AgentCronJobStore("/path/to/scheduled-jobs.json");
const cron = store.create({
activeSessionId: "session-1",
sessionId: "session-1",
sessionFile: "/tmp/session-1.json",
cwd: process.cwd(),
label: "Reminder",
prompt: "Check inbox for new messages",
scheduleText: "every 10m", // Parsed by parseAgentCronSchedule()
source: "cron",
});
// Create a scheduled prompt (heartbeat) that fires every 5 minutes
const hb = store.createHeartbeat({
activeSessionId: "session-1",
sessionId: "session-1",
sessionFile: "/tmp/session-1.json",
cwd: process.cwd(),
label: "Periodic reminder",
prompt: "What should I work on next?",
scheduleText: "every 5m", // Uses DEFAULT_HEARTBEAT_SCHEDULE if omitted
});
To execute the scheduler (normally managed by the daemon process):
import { AgentCronScheduler } from "packages/coding-agent/src/core/cron-jobs";
const scheduler = new AgentCronScheduler(store, {
async runJob(job) {
// The daemon invokes appropriate command handling here
console.log(`⏰ Running job ${job.id}: ${job.prompt}`);
return "ran";
},
});
scheduler.start(); // Begins the timer loop
// scheduler.wake() can force an earlier evaluation after adding new jobs
Summary
- Persistent Storage: The
AgentCronJobStoreclass maintains job definitions inscheduled-jobs.json, enabling schedule recovery across process restarts. - Flexible Scheduling: The
parseAgentCronSchedulefunction supports natural language intervals (every 5m), delayed execution (in 30m), fixed timestamps (at <ISO>), and standard cron expressions. - Dual Job Types: Generic cron jobs use
source: "cron"while scheduled prompts (heartbeats) usesource: "heartbeat"with specialized delivery modes (steervsfollow_up). - Atomic Execution: The
AgentCronSchedulercoordinates with the store'sclaimDuemechanism to prevent race conditions and handles session rebinding viarebindSessionJobsduring workspace restoration. - Lifecycle Management: Jobs transition through statuses (active, completed) with automatic metadata updates via
recordRunResultandrecordSkipResult.
Frequently Asked Questions
What is the difference between a cron job and a scheduled prompt in Prime Agent?
While both use the same underlying scheduler, cron jobs (created via store.create() with source: "cron") are generic scheduled tasks, whereas scheduled prompts or heartbeats (created via store.createHeartbeat()) are specialized for agent interaction with configurable deliveryMode settings. Heartbeats can interrupt current operations (steer) or wait for completion (follow_up), and they support deferral logic when the session is busy.
How does Prime Agent persist scheduled jobs across restarts?
The AgentCronJobStore class writes all job definitions to a JSON file (default scheduled-jobs.json) atomically. Upon daemon initialization, the store reloads this file, and the AgentCronScheduler recovers any interrupted dispatches. The system also supports session-artifact mode, which maintains separate job files per session for better isolation.
What schedule syntaxes are supported for cron jobs?
According to the implementation in packages/coding-agent/src/core/cron-jobs.ts, the parseAgentCronSchedule function accepts four formats: relative delays (in 2h), recurring intervals (every 10m), absolute ISO timestamps (at 2024-01-01T00:00:00Z), and standard 5-field cron expressions including aliases like @hourly or @daily.
How does the scheduler handle session rebinding when restoring from a file?
When a persisted session file is replaced by a live session, the rebindSessionJobs function updates all associated job records in the store. It rewrites the activeSessionId, sessionId, sessionFile, and cwd fields to point to the new session context, ensuring that scheduled jobs execute against the correct working directory and session state rather than the stale persisted file.
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 →