# How Heartbeats Re-Enter Sessions at Specific Intervals in Prime Agent

> Learn how Prime Agent's cron-job heartbeat system re-enters sessions via the promptHeartbeat method using configurable delivery modes to maintain active connections.

- Repository: [Prime Intellect/prime-agent](https://github.com/PrimeIntellect-ai/prime-agent)
- Tags: internals
- Published: 2026-09-06

---

**Prime Agent implements a cron-job-based heartbeat system where `AgentCronJob` objects schedule recurring prompts that automatically inject back into active sessions via the `promptHeartbeat` method, using configurable `deliveryMode` settings to handle busy states.**

The PrimeIntellect-ai/prime-agent repository provides a robust mechanism for periodic session re-entry through scheduled heartbeats. These heartbeats ensure long-running coding tasks receive periodic check-ins by automatically injecting prompts at defined intervals. This architecture relies on three core modules—[`cron-jobs.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/cron-jobs.ts), [`agent-session.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/agent-session.ts), and [`messages.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/messages.ts)—to handle scheduling, persistence, and runtime injection.

## Heartbeat Architecture and Scheduling

Heartbeats in Prime Agent are modeled as persistent cron jobs rather than simple timers. The system defines a default recurrence pattern and flexible delivery semantics to accommodate various session states.

### The AgentCronJob Data Model

Each heartbeat is stored as an `AgentCronJob` object with a strict schema. According to [`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 default interval is defined by the constant:

```typescript
DEFAULT_HEARTBEAT_SCHEDULE = "every 5m"

```

This schedule string follows a natural language format (e.g., "every 5m", "every 1h") that the system parses into concrete `nextRunAt` timestamps. Each job also carries a `deliveryMode` property that dictates insertion behavior when the session is occupied:

- **`"steer"`** – Immediately interrupts the current turn to inject the heartbeat prompt
- **`"follow_up"`** – Queues the heartbeat to execute after the current operation completes

## Creating and Persisting Heartbeat Jobs

When a session initializes, the system invokes `AgentCronJobStore.createHeartbeat` to register the periodic check-in. This method performs several critical validations before persistence.

According to the source code 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 creation flow:

1. Parses the `scheduleText` (e.g., "every 5m") using `parseAgentCronSchedule`
2. Validates that the schedule represents a recurring pattern rather than a one-time execution
3. Constructs the `AgentCronJob` with the provided `prompt`, `schedule`, and `deliveryMode`
4. Persists the job to [`scheduled-jobs.json`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/scheduled-jobs.json) for durability across process restarts

```typescript
// Creating a heartbeat for the current session
const hb = cronStore.createHeartbeat({
  activeSessionId: session.id,
  sessionId: session.id,
  sessionFile: session.file,
  cwd: process.cwd(),
  label: "Keep-alive",
  prompt: "Check whether the long-running task needs another step.",
  scheduleText: "every 5m",           // ← interval definition
  deliveryMode: "steer",              // ← interrupt if busy
});

```

The job state—including `nextRunAt`, `runCount`, and `lastRunAt`—is maintained in [`scheduled-jobs.json`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/scheduled-jobs.json) and evaluated on each scheduler tick.

## Runtime Re-Entry and Message Injection

When the scheduler determines that `nextRunAt` has elapsed, the heartbeat must re-enter the session context. This occurs through the `AgentSession.promptHeartbeat` method implemented in [`packages/coding-agent/src/core/agent-session.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/core/agent-session.ts).

The re-entry mechanism follows this sequence:

1. **Message Construction** – `createHeartbeatPromptMessage(job)` (defined in [`packages/coding-agent/src/core/messages.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/core/messages.ts)) builds a specialized message object:

```typescript
const msg = createHeartbeatPromptMessage(hb);
// → {
//     role: "custom",
//     customType: HEARTBEAT_PROMPT_CUSTOM_TYPE,
//     content: hb.prompt,
//     details: { jobId: hb.id, schedule: hb.schedule, runCount: hb.runCount },
//   }

```

2. **Session Injection** – `promptHeartbeat` calls `_promptInjectedMessage` with specific parameters to ensure proper re-entry:
   - `followUpQueueKey`: Set to `` `heartbeat:${job.id}` `` to isolate heartbeat messages from user traffic
   - `resumeIfIdle`: Set to `true` so the session resumes execution even if currently idle
   - `customType`: Uses `HEARTBEAT_PROMPT_CUSTOM_TYPE` to identify the message as a system heartbeat rather than user input

```typescript
// Simplified scheduler tick logic
if (new Date() >= new Date(hb.nextRunAt!)) {
  await session.promptHeartbeat(hb); // Re-enters session with heartbeat prompt
}

```

## Handling Session State and Delivery Modes

Once injected, the heartbeat's behavior depends on the concurrency model selected at creation time. The `deliveryMode` determines how `AgentSession` processes the prompt relative to ongoing activity.

**`"steer"` Mode (Interrupt)**
- Immediately pauses current agent reasoning
- Injects the heartbeat prompt into the active context
- Suitable for critical health checks or timeout prevention

**`"follow_up"` Mode (Queue)**
- Appends the heartbeat to the session's follow-up queue
- Executes only after the current turn completes
- Prevents disruption of complex multi-step operations

After successful execution, the scheduler increments `runCount`, recalculates the next execution time via `parseAgentCronSchedule`, and atomically updates [`scheduled-jobs.json`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/scheduled-jobs.json) with the new `nextRunAt` timestamp.

## Summary

- **Heartbeats use `AgentCronJob`** objects with a default `DEFAULT_HEARTBEAT_SCHEDULE` of `"every 5m"` 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)
- **`AgentCronJobStore.createHeartbeat`** parses and validates schedules, persisting job state to [`scheduled-jobs.json`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/scheduled-jobs.json) for durability
- **`AgentSession.promptHeartbeat`** re-enters sessions by injecting messages via `_promptInjectedMessage` with `resumeIfIdle: true` and a unique `followUpQueueKey`
- **`deliveryMode`** controls concurrency behavior: `"steer"` interrupts active turns while `"follow_up"` queues for later execution
- **Message typing** via `HEARTBEAT_PROMPT_CUSTOM_TYPE` enables proper UI rendering and runtime tracking in [`packages/coding-agent/src/core/messages.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/core/messages.ts)

## Frequently Asked Questions

### What is the default heartbeat interval in Prime Agent?

The default interval is defined by the constant `DEFAULT_HEARTBEAT_SCHEDULE = "every 5m"` 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 can be overridden by passing a custom `scheduleText` parameter when calling `createHeartbeat`.

### How does Prime Agent handle heartbeats when a session is busy?

The system checks the `deliveryMode` property of the `AgentCronJob`. When set to `"steer"`, the heartbeat interrupts the current operation immediately. When set to `"follow_up"`, the heartbeat is queued in the session's follow-up queue using the key `` `heartbeat:${job.id}` `` and executes after the current turn completes.

### Can heartbeats resume an idle session?

Yes. The `promptHeartbeat` method explicitly passes `resumeIfIdle: true` to `_promptInjectedMessage` when injecting the heartbeat prompt. This parameter ensures that even if the session has entered an idle state, the scheduler will wake it to process the periodic check-in.

### Where are heartbeat jobs stored between scheduler ticks?

All heartbeat jobs are persisted to a file named [`scheduled-jobs.json`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/scheduled-jobs.json) in the working directory. This allows the scheduler to maintain `nextRunAt` timestamps, `runCount` statistics, and delivery configurations across application restarts without losing the temporal state of periodic tasks.