# How Session Passivation Preserves Agent State Across Restarts in Prime Agent

> Discover how session passivation in Prime Agent snapshots idle child sessions to disk, safeguarding agent state across restarts and preventing data loss. Learn the mechanism for seamless agent recovery.

- Repository: [Prime Intellect/prime-agent](https://github.com/PrimeIntellect-ai/prime-agent)
- Tags: deep-dive
- Published: 2026-08-12

---

**Session passivation is a memory-management mechanism that snapshots idle child sessions to disk, removes them from RAM, and later restores them unchanged—allowing the Prime Agent daemon to restart without losing work.**

Prime Agent's daemon mode uses session passivation to balance resource efficiency with durability. When sub-agents (child sessions) sit idle beyond a configured threshold, the daemon captures their runtime state, writes it to a persistent **session file**, and evicts the in-memory session. This process, implemented in [`packages/coding-agent/src/modes/daemon/daemon-mode.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/daemon/daemon-mode.ts), ensures that agent hierarchies survive process restarts, upgrades, or crashes without data loss.

## What Triggers Session Passivation

Passivation activates based on idle time, controlled by the `idleEvictionMinutes` configuration setting.

- **Default behavior**: Sessions idle for 90 minutes become passivation candidates.
- **Disable entirely**: Set `idleEvictionMinutes` to `"off"` to keep all sessions in memory indefinitely.
- **Documentation**: The setting is documented in [`packages/coding-agent/docs/settings.md`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/docs/settings.md) at lines 203–207, with changelog notes in [`packages/coding-agent/CHANGELOG.md`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/CHANGELOG.md) at lines 45–60.

The daemon evaluates candidates on every supervisor tick, running `passivateIdleChildren` to identify sessions ready for eviction.

## How the Passivation Snapshot Works

The foundation of state preservation is `sessionPassivationSnapshot` (lines 2417–2456), which captures eight critical fields:

| Field | Purpose |
|-------|---------|
| `isSessionActive` | Whether the session is currently running |
| `attachedClients` | Count of connected clients blocking passivation |
| `hasRegisteredHeartbeat` | Active heartbeat registration status |
| `hasRegisteredCronJob` | Pending scheduled jobs that need continued execution |
| `lastActivityAt` | Timestamp for idle-time calculation |
| `hasParent` | Whether this session is a root or child agent |
| `hasNonPassiveDescendants` | Whether dependent sessions also need handling |
| `isHydrating` | Whether a restore operation is already in progress |

These fields let the daemon determine if passivation is safe—no clients waiting, no in-flight jobs, no active heartbeats—before removing the session from memory.

## The Three-Stage Passivation Flow

Prime Agent executes passivation through a coordinated sequence:

### 1. Identify Candidates

`passivateIdleChildren` (lines 2534–2552) scans all live sessions and applies `canPassivateSession` filters. A session only qualifies if:

- Idle time exceeds `idleEvictionMinutes`
- No pending admissions or active children exist
- No recent state changes would invalidate the snapshot

### 2. Persist and Close

For each qualifying session, `passivateSession` (lines 2598–2616) publishes the session's durable identity, then invokes `closeSession` to shut down the runtime gracefully. The session file remains on disk throughout.

### 3. Evict from Memory

After successful closure, the child is removed from the daemon's active session map. The in-memory footprint disappears, but the persisted snapshot enables future restoration.

## Rehydration: Restoring Passivated Sessions

When a client reconnects or a parent session needs a passivated child, Prime Agent runs `hydratePassiveRlmSubagent` (lines 2562–2570). This process:

1. Waits for any in-flight passivation to complete via `waitForPassivation`
2. Reads the stored snapshot from the session file
3. Reconstructs the session runtime with identical state

The `waitForPassivation` guard prevents race conditions where a session might be simultaneously passivating and hydrating.

## Safety Guarantees During Passivation

The passivation system includes multiple guards to ensure consistency:

- **Passivation gate**: Blocks new message routing while state is being written
- **Shutdown abort**: Passivation cancels if the daemon is stopping
- **Update restart detection**: Prevents passivation during pending upgrades
- **State change detection**: Aborts if the session mutates during `closeSession`

These protections ensure the session file always contains a consistent, recoverable state.

## Practical Configuration Examples

### Enable 30-Minute Passivation Threshold

```typescript
import { AgentDaemon } from "prime-agent";

const daemon = new AgentDaemon("/tmp/prime-agent.sock", {
  idleEvictionMinutes: 30, // passivate after 30 minutes idle
});

daemon.start();
// Automatic passivation runs each supervisor tick via DaemonSupervisor

```

### Force Manual Passivation for Testing

```typescript
async function forcePassivation(daemon: AgentDaemon) {
  const count = await (daemon as any).internals.passivateIdleChildren(
    90,                     // idle threshold (minutes)
    Date.now(),            // current time reference
    2,                     // maximum sessions to passivate
  );
  console.log(`Passivated ${count} idle child sessions`);
}

```

### Manually Rehydrate a Passivated Session

```typescript
async function hydrate(daemon: AgentDaemon, sessionFile: string) {
  // Ensure no passivation is still writing the session file
  await (daemon as any).internals.waitForPassivation(sessionFile);
  
  // Locate and restore the persisted session
  const passiveSession = await (daemon as any).internals.findPassiveRlmSubagent(
    sessionFile, 
    true, // create if missing
  );
  
  const activeState = await (daemon as any).internals.hydratePassiveRlmSubagent(
    passiveSession,
  );
  
  console.log(`Session ${activeState.runtime.session.sessionId} rehydrated`);
}

```

## Key Source Files

| File | Responsibility |
|------|---------------|
| [`packages/coding-agent/src/modes/daemon/daemon-mode.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/daemon/daemon-mode.ts) | Core passivation: snapshot creation, candidate selection, `passivateSession`, `hydratePassiveRlmSubagent` |
| [`packages/coding-agent/docs/settings.md`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/docs/settings.md) | `idleEvictionMinutes` configuration reference |
| [`packages/coding-agent/CHANGELOG.md`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/CHANGELOG.md) | Version history for passivation features |
| [`packages/coding-agent/test/daemon-mode.test.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/test/daemon-mode.test.ts) | Race condition and recovery validation (lines 1114–1121) |

## Summary

- **Session passivation** preserves agent state by snapshotting idle sessions to disk and freeing memory
- **Trigger**: Configurable `idleEvictionMinutes` (default 90 minutes, or `"off"`)
- **Snapshot**: Eight metadata fields captured by `sessionPassivationSnapshot` determine passivation safety
- **Flow**: `passivateIdleChildren` → `passivateSession` → `closeSession` → persisted `sessionFile`
- **Recovery**: `hydratePassiveRlmSubagent` with `waitForPassivation` restores sessions after daemon restart
- **Safety**: Passivation gates and state-change detection guarantee consistent session files

## Frequently Asked Questions

### How does session passivation differ from simple process suspension?

Session passivation writes structured metadata to a **session file** that survives daemon restarts, while process suspension keeps state in ephemeral memory. According to the Prime Agent source code in [`daemon-mode.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/daemon-mode.ts), passivation explicitly captures `attachedClients`, `hasRegisteredHeartbeat`, and other runtime flags—enabling **rehydration** into a fresh process with identical logical state, not just frozen execution.

### What happens if the daemon restarts during passivation?

The `waitForPassivation` mechanism (lines 2562–2570) blocks rehydration until any in-flight passivation completes. If the daemon crashes mid-passivation, the session file may be partially written; on restart, `findPassiveRlmSubagent` validates the snapshot before allowing `hydratePassiveRlmSubagent` to proceed. The test suite in [`daemon-mode.test.ts`](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/daemon-mode.test.ts) specifically validates these race conditions.

### Can active sessions with connected clients be passivated?

No. The `canPassivateSession` check (lines 2534–2552) requires `attachedClients` to be zero. A session with connected clients, pending admissions, or active children will remain in memory regardless of idle time. This prevents disconnecting live users or interrupting running work.

### Does passivation affect cron jobs or scheduled tasks?

Sessions with `hasRegisteredCronJob: true` in their snapshot are excluded from passivation unless the job completes or unregisters. The snapshot field tracks this status explicitly, ensuring scheduled execution continues in memory rather than being frozen to disk where timers would stall.