Daemon Protocol Message Shapes for Session Recovery: A Complete Guide to Prime Agent's Resumable Sessions

Prime Agent's daemon protocol defines four core message shapes—DaemonAttachClientMetadata, DaemonUpdateRestartManifest, DaemonUpdateRestartSession, and DaemonSessionSnapshot—that enable client-owned session recovery across worker restarts.

Session recovery is a critical capability in long-running AI coding agents. When a daemon worker restarts or disconnects, the Prime Agent codebase must reconstruct session state without losing in-flight work. This requires strict message contracts defined in [packages/coding-agent/src/modes/daemon/daemon-protocol.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/modes/daemon/daemon-protocol.ts). This guide breaks down the exact TypeScript shapes, their fields, and how they orchestrate recovery.

DaemonAttachClientMetadata: The Recovery Trigger

The recovery flow begins when a client attaches or reattaches to a daemon. The DaemonAttachClientMetadata type extends the standard attach metadata with an optional recoveryConfig field:

// Lines 94-102 in daemon-protocol.ts
type DaemonAttachClientMetadata = {
  type: "attach" | "reattach";
  activeSessionId: string;
  recoveryConfig?: AgentSessionRuntimeConfig; // Enables owned-session recovery
  env?: Record<string, string>;
  launch?: LaunchConfig;
  // ... additional standard fields
};

When recoveryConfig is present, the daemon enters recovery mode. This triggers the owned session recovery compatibility gate, requiring both client and server to negotiate the OWNED_SESSION_RECOVERY_CONTEXT capability.

DaemonUpdateRestartManifest: Persisted Recovery State

Before a worker shuts down, the daemon writes a DaemonUpdateRestartManifest to disk. This manifest acts as a checkpoint:

// Lines 73-78 in daemon-protocol.ts
type DaemonUpdateRestartManifest = {
  formatVersion: 1;
  sessions: DaemonUpdateRestartSession[];
  timestamp: number;
};

The manifest's formatVersion ensures forward compatibility. The sessions array contains one entry per active session that must survive the restart.

DaemonUpdateRestartSession: Per-Session Recovery Details

Each session entry in the manifest is a DaemonUpdateRestartSession containing exhaustive reconstruction data:

// Lines 55-71 in daemon-protocol.ts
type DaemonUpdateRestartSession = {
  activeSessionId: string;
  sessionId: string;
  folderPath: string;
  cwd: string;
  config: AgentSessionConfig;
  runtimeConfig: AgentSessionRuntimeConfig;
  env: Record<string, string>;
  queuedActions: QueuedAction[];
  wasStreaming: boolean;
  hadRunningRlmChildren: boolean;
  hadPendingDetach: boolean;
  treeContext?: TreeContextSnapshot;
};

Key boolean flags (wasStreaming, hadRunningRlmChildren, hadPendingDetach) tell the recovering daemon what operations were interrupted, allowing it to resume or clean up appropriately.

DaemonSessionSnapshot: Live State for Client Reconstruction

After successful attachment, the daemon returns a DaemonSessionSnapshot that mirrors the manifest data for the client's benefit:

// Lines 107-124 in daemon-protocol.ts
type DaemonSessionSnapshot = {
  activeSessionId: string;
  summary: SessionSummary;
  state: AgentConnectionState;
  messageLog: MessageLogEntry[];
  treeContext?: TreeContextSnapshot;
  children: {
    sessionId: string;
    type: "rlm" | "subagent";
    state: ChildSessionState;
  }[];
};

The children array is particularly important—it captures nested RLM (Reinforcement Learning Model) and subagent sessions that were spawned before the restart, ensuring the entire session tree can be reconstructed.

Capability Negotiation: OWNED_SESSION_RECOVERY_CONTEXT

Recovery only proceeds if both parties support it. The OWNED_SESSION_RECOVERY_CONTEXT constant defines this capability:

// Lines 124-129 in daemon-protocol.ts
const OWNED_SESSION_RECOVERY_CONTEXT = "owned_session_recovery_context";
const DAEMON_SERVER_CAPABILITIES = [
  // ...
  OWNED_SESSION_RECOVERY_CONTEXT,
] as const;

type DaemonClientCapability = 
  | "client_owned_sessions"  // Client can own and recover sessions
  | "streaming_responses"
  // ... other capabilities
  ;

The client's hello message must include "client_owned_sessions" in its capability list. The daemon's attach handler then validates this via meetsDaemonCommandCompatibility before accepting a recoveryConfig.

The Complete Recovery Sequence

Here is how these shapes work together in practice:

  1. Client initiates recovery by sending an attach command with recoveryConfig populated.

  2. Daemon validates capabilities using the compatibility check. If the client lacks "client_owned_sessions", the daemon rejects the attach.

  3. Daemon loads the manifest from its persistence layer, iterating through DaemonUpdateRestartSession entries.

  4. Session reconstruction occurs in daemon-supervisor.ts, which:

    • Restores the working directory and environment
    • Replays queued actions
    • Reattaches to child sessions based on the flags
  5. Daemon responds with DaemonAttachResult containing the full DaemonSessionSnapshot.

  6. Client reconciles its local state against the snapshot, resuming the user experience seamlessly.

Example: Initiating Recovery from a Client

import { DaemonAttachClientMetadata } from "./daemon-protocol";

const recoveryAttach: DaemonAttachClientMetadata = {
  type: "attach",
  activeSessionId: "sess-abc-123",
  recoveryConfig: {
    model: "claude-sonnet-4-20250514",
    temperature: 0.2,
    maxTokens: 8192,
    // ... additional runtime parameters
  },
  env: process.env,
  launch: {
    command: "node",
    args: ["--inspect", "server.js"]
  }
};

// Send to daemon; response includes DaemonSessionSnapshot
const result = await daemon.sendAttach(recoveryAttach);
console.log("Recovered session:", result.snapshot.activeSessionId);
console.log("Child sessions restored:", result.snapshot.children.length);

Summary

  • DaemonAttachClientMetadata triggers recovery via the optional recoveryConfig field and negotiates capabilities.
  • DaemonUpdateRestartManifest persists recovery state to disk with versioned format and session array.
  • DaemonUpdateRestartSession captures exhaustive per-session details including queues, flags, and child context.
  • DaemonSessionSnapshot returns live reconstructed state to clients, including the full child session tree.
  • Capability negotiation via OWNED_SESSION_RECOVERY_CONTEXT and client_owned_sessions prevents incompatible recovery attempts.

Frequently Asked Questions

What happens if the client doesn't support client_owned_sessions?

The daemon rejects the attach command with a compatibility error. As implemented in daemon-supervisor.ts, the recovery flow throws before any state mutation occurs, protecting session integrity. The client must reconnect without recoveryConfig and accept a fresh session.

Can a daemon recover sessions from a different format version?

No. The formatVersion: 1 field in DaemonUpdateRestartManifest is strictly validated. If a future version introduces breaking changes, the daemon will ignore incompatible manifests and treat the session as non-recoverable, logging a warning for operators.

How does the daemon handle child session recovery?

The children array in DaemonSessionSnapshot and the hadRunningRlmChildren flag in DaemonUpdateRestartSession coordinate this. When hadRunningRlmChildren is true, the supervisor re-establishes communication channels with each child session ID listed, verifying their liveness before marking the parent session ready.

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 →