# How Scheduled Prompts and Cron Jobs Function in Prime Agent

> Discover how Prime Agent's file-backed scheduler manages cron jobs and scheduled prompts using JSON records and a timer loop. Learn about its flexible schedule parsing and delivery modes.

- Repository: [Prime Intellect/prime-agent](https://github.com/PrimeIntellect-ai/prime-agent)
- Tags: how-to-guide
- Published: 2026-08-09

---

**Prime Agent implements a lightweight, file-backed scheduler in [`packages/coding-agent/src/core/cron-jobs.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/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`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/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`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/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`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/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:

1. **Recovery** – Reloads the store and checks for any interrupted dispatches from previous runs.
2. **Scheduling** – Calls `scheduleNext()` to compute the earliest active job via `store.nextActiveRunAt()` and sets a timeout accordingly.
3. **Execution** – When the timer fires, `runDue()` invokes `store.claimDue()` to atomically claim due jobs (preventing race conditions in multi-process scenarios) and executes them through the `runJob` hook 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:

```typescript
// 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):

```typescript
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 `AgentCronJobStore` class maintains job definitions in [`scheduled-jobs.json`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/scheduled-jobs.json), enabling schedule recovery across process restarts.
- **Flexible Scheduling**: The `parseAgentCronSchedule` function 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) use `source: "heartbeat"` with specialized delivery modes (`steer` vs `follow_up`).
- **Atomic Execution**: The `AgentCronScheduler` coordinates with the store's `claimDue` mechanism to prevent race conditions and handles session rebinding via `rebindSessionJobs` during workspace restoration.
- **Lifecycle Management**: Jobs transition through statuses (active, completed) with automatic metadata updates via `recordRunResult` and `recordSkipResult`.

## 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`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/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`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/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.