How Subagent Lifecycle Events Like `agentMessage.send` Enable Parent-Child Coordination in Prime Agent
Subagent lifecycle events in Prime Agent—specifically agentMessage.send—enable parent-child coordination by attaching unique child IDs to messages and routing them through a bidirectional event system that allows parents to monitor, command, and synchronize their spawned subagents.
The Prime Agent framework implements a hierarchical agent architecture where parent sessions spawn isolated child sessions. This coordination relies on a precisely defined event protocol centered on AgentMessage objects, with agentMessage.send serving as the primary communication primitive between layers of the agent hierarchy.
Subagent Initialization and Session Registry
When a parent agent spawns a subagent, Prime Agent creates a fully independent AgentSession while maintaining registry linkage through the SubagentRuntimeHost.
In packages/coding-agent/src/subagents.ts, the runtime host instantiates child sessions and registers them in the parent's internal tracking map:
// From packages/coding-agent/src/AgentSession.ts
// Parent session maintains subagentRuntimes registry
subagentRuntimes: Map<string, SubagentRuntimeHost> = new Map();
Each child receives a unique child-ID (rlmChildId) persisted in both the parent's metadata and the child's session state. This identifier becomes the routing key for all subsequent agentMessage events. The relationship between parent and child is explicitly managed through the agentMessageRelationship helper, which categorizes connections as "parent", "child", or undefined based on stored ID pairs.
The agentMessage.send Event Mechanism
The agentMessage.send function in packages/coding-agent/src/agentMessageController.ts implements the core emission logic:
// Conceptual implementation from agentMessageController.ts
export const send = (msg: AgentMessage) => {
// Normalize message and attach originating session context
const enrichedMsg = {
...msg,
rlmChildId: this.session.id, // Source identification
agentMessageId: generateId(), // Correlation tracking
};
// Forward to parent session's message handler
parentSession.handleAgentMessage(enrichedMsg);
};
Key properties attached to every sent message:
rlmChildId– Identifies the originating child sessionrlmParentId– Present when messages flow parent-to-childagentMessageId– Unique correlation identifier for request-response matching
Parent-Side Message Handling and Routing
When a parent session receives a message via handleAgentMessage, it executes a three-phase routing sequence:
- Relationship lookup – Query
agentMessageRelationshipusing the IDs embedded in the message - Validation – Verify the sender is a known child or legitimate parent
- Dispatch – Route to appropriate handlers based on message type and relationship
The parent can perform three distinct coordination actions:
- Observe – Track child progress through
agentMessageIdcorrelation - Command – Send directive messages back to specific children
- Broadcast – Propagate messages across multiple child sessions simultaneously
Coordination Patterns: Spawn, Monitor, Control
Spawning and Initial Handshake
// Parent session spawning a subagent
const sub = await session.spawnSubagent({
prompt: "Analyze the following file",
model: "gpt-4o-mini",
});
await sub.waitForReady(); // Parent synchronizes on child initialization
Monitoring via Event Subscription
// Parent registers handler for child messages
session.on("agentMessage", (msg: AgentMessage) => {
if (msg.rlmChildId === sub.id) {
console.log(`Child ${sub.id} reports:`, msg.content);
}
});
Termination and Cleanup Lifecycle
When a child completes execution, it emits a terminal message with type: "stop":
// Child session signaling completion
await this.session.agentMessageController.send({
role: "assistant",
content: "Analysis complete",
type: "stop", // Lifecycle termination signal
rlmChildId: this.session.id,
});
The parent responds by removing the child entry from subagentRuntimes and emitting disposal confirmations. This prevents orphaned sessions and resource leaks.
Error Boundaries and Lifecycle Constraints
The framework enforces strict parent-child lifecycle integrity. Attempting to spawn or message from a child whose parent has been disposed triggers an explicit error:
Cannot spawn a subagent after its parent was disposed
This constraint—validated in regression test packages/coding-agent/test/suite/regressions/617-subagent-terminal-agent-message.test.ts—ensures that message routing never targets destroyed session hierarchies.
Persistence and Session Restoration
Subagent metadata including rlmChildId, model configuration, and effort level is serialized in packages/coding-agent/src/agent-session-serialized.ts. On session restoration:
- Parent re-instantiates child sessions from persisted state
SubagentRuntimeHostre-registers children insubagentRuntimes- Message routing resumes transparently using restored ID mappings
Performance Characteristics
- Message latency – Direct memory reference between co-located sessions
- Routing overhead – O(1) map lookup via
agentMessageRelationship - Memory scaling – Linear with active subagent count; terminal children garbage-collected post-
stopacknowledgment
Summary
- Subagent spawning creates isolated
AgentSessioninstances with uniquerlmChildIdidentifiers stored in the parent'ssubagentRuntimesregistry agentMessage.sendattaches source identification and correlation IDs, then routes throughhandleAgentMessagein the parent session- Parent coordination includes observation (progress tracking), command injection (directed messages), and broadcast synchronization (multi-child operations)
- Lifecycle termination uses
type: "stop"messages triggering cleanup and preventing orphaned sessions - Persistence layer stores subagent metadata enabling full session restoration with intact message routing
Frequently Asked Questions
How does Prime Agent prevent message routing to disposed parent sessions?
The SubagentRuntimeHost checks parent session validity before processing any agentMessage.send call. If the parent has been disposed, it throws Cannot spawn a subagent after its parent was disposed. This constraint is enforced in packages/coding-agent/test/suite/regressions/617-subagent-terminal-agent-message.test.ts.
Can a subagent communicate with sibling subagents directly?
No. All inter-subagent communication is mediated through the common parent. Sibling sessions have no direct reference to each other; they exchange messages by emitting to the parent, which may then broadcast to selected children based on agentMessageRelationship lookups.
What happens to in-flight messages during parent session restoration?
Messages queued during serialization are persisted with the session snapshot. On restoration, the parent session's agentMessageController reinitializes its routing tables from agent-session-serialized.ts, and pending messages resume processing through the restored subagentRuntimes map.
How does agentMessageId enable request-response correlation?
Each agentMessage.send generates a unique agentMessageId stored in both the sent message and the sender's pending promise registry. When the recipient responds, it includes the original agentMessageId in its reply, allowing the sender to resolve the correct promise via session.promptAndWait or equivalent async handlers.
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 →