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:

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:

  1. Creation: Client sends cron_add RPC with either a cron expression or heartbeat configuration
  2. Persistence: Daemon writes the job to AgentCronJobStore on disk
  3. Ticking: AgentCronScheduler.start() initiates a 1-second periodic timer
  4. Execution: runDue(now) identifies due jobs and invokes their handlers—user commands for cron jobs, daemon pings for heartbeats
  5. 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, AgentCronJobStore reloads persisted jobs from disk, and AgentCronScheduler resumes 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 AgentCronJobStore for durable, disk-backed job persistence and AgentCronScheduler for the execution loop.
  • Cron jobs (source: "cron") handle user automation via standard cron expressions managed through cron_add and cron_cancel RPCs.
  • Heartbeat jobs (source: "heartbeat") maintain session liveness through periodic pings, supporting pause/resume via updateRlmHeartbeat().
  • 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →