How Session Passivation Preserves Agent State Across Restarts in Prime Agent

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, 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.

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

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

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

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 Core passivation: snapshot creation, candidate selection, passivateSession, hydratePassiveRlmSubagent
packages/coding-agent/docs/settings.md idleEvictionMinutes configuration reference
packages/coding-agent/CHANGELOG.md Version history for passivation features
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, 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 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.

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 →