# How Prime Agent's Daemon Supervisor Architecture Manages Worker Processes

> Discover Prime Agent's daemon supervisor architecture. Learn how it manages worker processes using a Unix-domain socket, JSON state persistence, JSON-L RPC, and lifecycle events for seamless operations.

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

---

**Prime Agent's daemon supervisor acts as a central controller that owns a Unix-domain socket, persists worker state to JSON descriptors, routes client commands to session workers via JSON-L RPC, and manages lifecycle events including idle eviction and zero-downtime updates.**

The PrimeIntellect-ai/prime-agent repository implements a resilient multi-process architecture where a **daemon supervisor** orchestrates background session workers. This **daemon supervisor architecture** ensures fault tolerance across process crashes, supports seamless updates without losing session state, and efficiently manages system resources through intelligent worker lifecycle controls.

## Core Components of the Daemon Supervisor Architecture

### Socket Ownership and Singleton Enforcement

The supervisor claims exclusive control of the communication socket through a leasing mechanism. During initialization in `DaemonSupervisor.start()`, the system invokes `acquireDaemonSocketPathLease()` and `acquireDaemonSupervisorOwnership()` to write a lease file recording the supervisor's PID【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L42-L47】. This prevents multiple supervisor instances from interfering with each other, establishing a singleton pattern for the daemon process.

### Worker Descriptor Persistence

Worker processes are stateful entities tracked via JSON descriptors stored in `<agentDir>/daemon-workers/<hash>/`. Each descriptor contains the worker's PID, private socket path, authentication token, and lifecycle state. When the supervisor starts, `loadWorkerDescriptors()` reads these files to build an in-memory `workers` map【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L115-L130】.

### Command Routing and RPC Mediation

Clients connect to the supervisor's Unix-domain (or Windows named-pipe) socket and communicate via JSON-L lines. The `handleConnection()` method registers a JSON-L reader, while `handleLine()` parses incoming commands against the `DAEMON_COMMAND_TYPES` whitelist【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L104-L117】. For validated commands, `forwardToWorker()` transmits the request to the appropriate worker through a `DaemonWorkerClient` and returns the response to the client【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L260-L280】.

## Worker Process Lifecycle Management

### Spawning and Recovery

The `runDaemonSupervisorMode()` function creates the supervisor instance and initiates the recovery flow, while `adoptOrRecoverWorker()` either launches new workers or reconnects to existing ones via their private sockets【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L72-L78】. This allows the system to survive supervisor restarts without losing active sessions.

### Prompt Admission Handling

Commands such as `prompt` and `prompt_and_wait` require a two-phase admission process. The `parseCommandAndRegisterPromptAdmission()` method creates a `SupervisorPromptAdmission` object, registering it in the `promptAdmissions` map before the worker assumes ownership of the session【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L181-L210】. This ensures orderly handoff between client requests and worker session execution.

### Idle Eviction Strategy

To conserve resources, the supervisor implements a configurable idle eviction mechanism. The `scheduleIdleEvictionSweep()` method initiates a periodic check, while `runIdleEvictionSweep()` iterates through workers, refreshing activity summaries and identifying candidates for eviction based on `lastActivityAt` timestamps【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L88-L118】【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L145-L162】. Workers exceeding the configured idle timeout are passively shut down after requesting they passivate idle children.

### Update-Restart Coordination

During updates, the supervisor executes a *drain → fence → prepared* sequence to achieve zero-downtime restarts. The `updateRestartPhase` field and `mutationDrain` object coordinate this process, using `await this.mutationDrain.waitForDrain()` to pause new mutations, gracefully stop workers, and hand off the socket to a fresh supervisor instance【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L90-L102】【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L270-L285】. This architecture supports command-recovery journaling to guarantee at-least-once delivery of mutating commands across restarts.

## Signal Handling and Cleanup

Robust shutdown behavior is implemented through `registerSignalHandlers()`, installed during `start()` to catch `SIGINT` and `SIGTERM` events【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L71-L84】. The `cleanupSupervisorResources()` method releases the socket lease, terminates worker processes, and deletes descriptor files to ensure clean state removal.

## Implementation Examples

Below are practical code patterns for interacting with the daemon supervisor architecture.

### Starting the Daemon Supervisor

```typescript
// packages/coding-agent/src/modes/daemon/daemon-mode.ts
import { runDaemonSupervisorMode } from "./daemon-supervisor.js";

export async function startDaemonSupervisor(socketPath?: string) {
  // Build a default session config – normally read from the agent's settings
  const defaultConfig = { agentDir: "/var/lib/prime-agent" };
  await runDaemonSupervisorMode({ socketPath, defaultSessionConfig: defaultConfig });
}

```

*Source:* `runDaemonSupervisorMode()` instantiates `DaemonSupervisor` and invokes `start()`【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L72-L78】.

### Worker Recovery Loop

```typescript
// Inside DaemonSupervisor.start()
const workersToAdopt = [...this.workers.values()];
await Promise.all(workersToAdopt.map(w => this.adoptOrRecoverWorker(w)));

```

*Source:* The adoption loop processes existing worker descriptors during startup【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L86-L98】.

### Forwarding Commands to Workers

```typescript
// From DaemonSupervisor.handleCommand()
const response = await this.forwardToWorker(worker, {
  type: "get_messages",
  activeSessionId: "session-123",
});

```

*Source:* `forwardToWorker()` handles JSON-L request transmission via `DaemonWorkerClient`【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L490-L505】.

### Idle Eviction Implementation

```typescript
private async runIdleEvictionSweep(now = Date.now()) {
  // Refresh summaries for all workers
  await Promise.all([...this.workers.values()].map(w => this.refreshWorkerSummaries(w)));

  // Pick candidates based on canEvictWorker()
  const candidates = [...this.workers.values()].filter(w =>
    canEvictWorker(this.workerEvictionSnapshot(w), this.settingsManager.getIdleEvictionMinutes(), now)
  );

  // Stop each idle worker
  await Promise.all(candidates.map(w => this.stopWorker(w, true)));
}

```

*Source:* Full sweep logic in `runIdleEvictionSweep()`【/packages/coding-agent/src/modes/daemon/daemon-supervisor.ts#L88-L118】.

### Worker-Side Client Connection

```typescript
// packages/coding-agent/src/modes/daemon/daemon-worker-client.ts
const client = new DaemonWorkerClient("/var/run/prime-agent/daemon.sock");
await client.connect();
await client.authenticateWorker(token, { workerId, socketPath, authenticationToken });
const hello = await client.waitForHello(); // receives daemon_hello
const resp = await client.request({ type: "get_state", activeSessionId: "sess-42" });

```

*Source:* `DaemonWorkerClient` methods for worker authentication and communication【/packages/coding-agent/src/modes/daemon/daemon-worker-client.ts#L45-L88】.

## Summary

- **Singleton Enforcement**: The supervisor uses `acquireDaemonSupervisorOwnership()` and PID-based lease files to ensure only one instance controls the socket at a time.
- **Stateful Recovery**: Worker processes persist their state to JSON descriptors, enabling the supervisor to recover or adopt workers after crashes or restarts via `adoptOrRecoverWorker()`.
- **RPC Mediation**: Client commands are validated against `DAEMON_COMMAND_TYPES`, then forwarded to workers through `DaemonWorkerClient` using JSON-L framing.
- **Resource Optimization**: Configurable idle eviction via `runIdleEvictionSweep()` automatically terminates inactive workers based on `lastActivityAt` timestamps.
- **Zero-Downtime Updates**: The `mutationDrain` and `updateRestartPhase` mechanism supports graceful handoffs during updates without losing session state or in-flight commands.

## Frequently Asked Questions

### How does the daemon supervisor prevent multiple instances from running?

The supervisor calls `acquireDaemonSocketPathLease()` and `acquireDaemonSupervisorOwnership()` during startup in `DaemonSupervisor.start()`. These methods write a lease file containing the supervisor's PID to the agent directory. If another instance attempts to start, it detects the existing lease and aborts, ensuring singleton enforcement across the system.

### What happens to worker processes when the supervisor restarts?

When restarting, the supervisor executes `loadWorkerDescriptors()` to read persisted JSON state from `<agentDir>/daemon-workers/<hash>/`. It then calls `adoptOrRecoverWorker()` for each descriptor to either reconnect to existing workers via their private sockets or cleanly replace them. This recovery mechanism preserves session state and active admissions across supervisor restarts.

### How are client commands routed to the correct worker?

Clients send JSON-L commands to the supervisor's Unix socket. The supervisor's `handleConnection()` and `handleLine()` methods parse these requests, validate them against the `DAEMON_COMMAND_TYPES` whitelist, and determine the target worker based on the session ID. The `forwardToWorker()` method then relays the command via a `DaemonWorkerClient` instance and returns the worker's response to the client.

### How does idle eviction manage system resources?

The supervisor schedules periodic sweeps via `scheduleIdleEvictionSweep()`, which executes `runIdleEvictionSweep()` to check worker activity. Workers exceeding the configured idle timeout (determined by `canEvictWorker()` checking `lastActivityAt`) are passively shut down after requesting they passivate idle children. This prevents resource exhaustion while maintaining hot workers for active sessions.