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.
- Default behavior: Sessions idle for 90 minutes become passivation candidates.
- Disable entirely: Set
idleEvictionMinutesto"off"to keep all sessions in memory indefinitely. - Documentation: The setting is documented in
packages/coding-agent/docs/settings.mdat lines 203–207, with changelog notes inpackages/coding-agent/CHANGELOG.mdat 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:
- Waits for any in-flight passivation to complete via
waitForPassivation - Reads the stored snapshot from the session file
- 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
sessionPassivationSnapshotdetermine passivation safety - Flow:
passivateIdleChildren→passivateSession→closeSession→ persistedsessionFile - Recovery:
hydratePassiveRlmSubagentwithwaitForPassivationrestores 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →