How Prime Agent's Daemon Supervisor Handles Cross-Agent Message Routing
Prime Agent's daemon supervisor routes cross-agent messages through an in-memory AgentRoster that maps session IDs to ResidentWorkers, using DaemonWorkerClient to forward commands over private Unix sockets.
The PrimeIntellect-ai/prime-agent repository implements a sophisticated daemon supervisor as the central message routing hub. Located in packages/coding-agent/src/modes/daemon/daemon-supervisor.ts, this component mediates all communication between clients (TUI, CLI consumers) and session workers running LLM models.
Core Routing Architecture
The cross-agent message routing system relies on three interconnected components:
- AgentRoster — Mutable in-memory index mapping session IDs to their owning
ResidentWorkerinstances - DaemonWorkerClient — Thin RPC client for worker communication over private Unix sockets
- Server capabilities — Protocol advertisements enabling roster subscriptions and direct peer transport
AgentRoster: The Session-to-Worker Index
The AgentRoster is imported at lines 71-78 of daemon-supervisor.ts and maintained through the roster_subscribe / roster_unsubscribe protocol:
// AgentRoster keeps live mappings: sessionId → ResidentWorker
// Synchronized via worker lifecycle events (create, detach, resume)
This roster enables O(1) worker lookup for any command targeting a specific session.
DaemonWorkerClient: Worker Communication Bridge
The DaemonWorkerClient (lines 37-39) provides the RPC interface to individual workers:
// From daemon-supervisor.ts
import { DaemonWorkerClient } from "./daemon-worker-client";
Each ResidentWorker maintains a client instance connected to the worker's private socket.
Command Routing Flow
Step 1: Client Command Reception
When a client connects via the public supervisor socket, the supervisor creates a DaemonSocketClient and registers it. The handleCommand dispatcher parses incoming JSON-L lines and matches against DAEMON_COMMAND_TYPES (starting at line 200).
Step 2: Target Worker Resolution
For session-scoped commands, the supervisor invokes matchWorkers(sessionId):
// Simplified excerpt from the command dispatcher
case "send_message":
case "append_custom_message":
const target = command.sessionId ?? command.activeSessionId;
const [match] = this.matchWorkers(target);
if (!match) throw new Error(`No worker for session ${target}`);
await match.worker.client!.requestWorker(command, /* timeout */ 30_000);
break;
This lookup occurs in the full dispatcher implementation (approximately lines 3000-3500).
Step 3: Worker Forwarding and Response
The DaemonWorkerClient.requestWorker method writes the command JSON to the worker's socket. The worker interprets commands via the session-worker protocol (daemon-worker-protocol.ts) and returns responses over the same connection.
Roster Change Propagation
Workers notify the supervisor of session lifecycle events. The supervisor updates AgentRoster and pushes roster_update messages to subscribed clients:
// Client subscribes
await daemonClient.sendCommand({ type: "roster_subscribe" });
// Supervisor broadcasts changes to promptAdmissions subscribers
for (const client of this.clients) {
if (this.promptAdmissions.has(client)) {
client.sendMessage({ type: "roster_update", entries: rosterDelta });
}
}
This publish-subscribe pattern eliminates polling overhead and ensures consistent client views.
Direct Peer-to-Peer Transport
For high-throughput scenarios, the supervisor supports bypass routing through direct_peer_transport capability (advertised at lines 182-186):
// Capability list in daemon-supervisor.ts
const capabilities = [
"agent_roster",
"direct_peer_transport", // Enables low-latency streaming
// ... baseline capabilities
];
Obtaining a Transport Ticket
const ticket = await daemonClient.sendCommand({
type: "get_direct_worker_transport",
sessionId: "session-xyz789",
});
The supervisor generates a DaemonPeerTransportTicket encoding:
- Worker's private socket path
- Short-lived authentication token
This allows clients to connect directly to workers for streaming tool-call results without supervisor intermediation.
Practical Routing Examples
Sending a Chat Message
// Client sends message
await daemonClient.sendCommand({
type: "send_message",
sessionId: "session-abc123",
content: "What is the weather tomorrow?",
});
The supervisor resolves session-abc123 through the roster and forwards via DaemonWorkerClient.
Cross-Agent Message Pattern
When sub-agents need to communicate, messages flow:
- Sub-agent A → supervisor socket
- Supervisor roster lookup → identifies Sub-agent B's worker
- Command forward → Sub-agent B's private socket
- Response traverses reverse path
Source Code Reference
| File | Responsibility |
|---|---|
packages/coding-agent/src/modes/daemon/daemon-supervisor.ts |
Core routing, roster management, command dispatch |
packages/coding-agent/src/modes/daemon/daemon-worker-client.ts |
RPC client for worker communication |
packages/coding-agent/src/modes/daemon/agent-roster.ts |
Session-to-worker index with subscription support |
packages/coding-agent/src/modes/daemon/daemon-protocol.ts |
Command envelopes, capabilities, transport tickets |
packages/coding-agent/src/modes/daemon/daemon-worker-protocol.ts |
Worker-side command interpretation |
packages/coding-agent/src/modes/daemon/daemon-socket.ts |
Public socket handling and identity verification |
Summary
- Message routing is centralized through the daemon supervisor with O(1) session-to-worker lookup via
AgentRoster - Command forwarding uses
DaemonWorkerClientover private Unix sockets with 30-second default timeouts - Roster subscriptions enable real-time client synchronization without polling
- Direct peer transport provides optional low-latency paths for high-throughput scenarios
- All routing logic is implemented TypeScript in
daemon-supervisor.tswith clear separation between public client and private worker protocols
Frequently Asked Questions
How does the supervisor locate the correct worker for a session?
The supervisor maintains an in-memory AgentRoster that maps every active session ID to its owning ResidentWorker. When a command arrives with a sessionId or activeSessionId field, the supervisor calls matchWorkers(sessionId) to retrieve the target worker reference. This lookup is synchronized with worker lifecycle events through the roster subscription protocol.
What happens if a command targets a non-existent session?
The matchWorkers method returns an empty array when no worker owns the requested session. The command dispatcher throws an explicit error: No worker for session ${target}. This fail-fast behavior prevents commands from being silently dropped and allows clients to handle session resolution failures appropriately.
Can clients communicate directly with workers without the supervisor?
Yes, through the direct_peer_transport capability. Clients request a transport ticket via get_direct_worker_transport, receiving a DaemonPeerTransportTicket containing the worker's socket path and authentication token. This bypass path reduces latency for streaming responses but requires the supervisor's initial coordination to establish trust and addressing.
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 →