Agent collaboration: eight implementations compared

Ask eight reference implementations the same question: how does one agent delegate to another, and can it still control that work afterward? Compare eight dimensions across all eight systems, explicitly marking absent features. Our own mechanism is described inAgent collaboration: tool surface; the design specification isagent-collaboration.md.

00 Three levels 01 Overview of eight systems 02 Can agents spawn children? 03 Can agents communicate directly? 04 Tracking and cascading cancellation 05 Preventing infinite loops 06 Restricting child toolsets 07 Identity, addressing, and implementation size 08 Our planned design

00Three levelsLevel one

This page contains levels two and three. Level one describes our implemented mechanism on a separate, mutually linked page.

Level one What we do now One primitive: deliver content to a branch, trigger a turn, and return the result automatically. Four domains and twelve tools. Separate page: Agent collaboration · Tool surface Four domains · Authority · Budgets · Archive · Scenarios Level two What other systems do Eight reference implementations and eight dimensions. Sections 01–07 cover this level. claude-code codex-cli openclaw opencode hermes-agent pi-ai pi-mono weclaw Level three What we plan to do Origins of the four-domain vocabulary and defined tool surface, deliberate differences from other systems, and remaining gaps between settled design and code. Section 08.
Diagram details: Four-domain vocabulary · Authority model · Three budgets · Archiving · Common scenarios. Verification method.Seven repositories were inspected directly, with file paths and line numbers. Claude Code uses two cross-checked sources: the leaked source tree contains only adapters (last committed in April 2026), while the actual implementation is in the locally installed 2.1.226 binary. Their designs already differ. Binary-derived conclusions use byte offsets, written asBinary @250599082. Differences between the two sources are identified individually below.

01Overview of eight systemsLevel two

Eight dimensions in one view. Every cell is expanded below with code locations.

Child spawningDirect communicationTask trackingCascading cancellation Loop preventionTool restrictionAddressingSize
Ours In-process, depth 1Yes, any-to-anytask_id, three toolsCascades Eight mechanismsRemove according to remaining allowanceBranch name / SID:HEAD4.5k
Claude Code In-process, depth 3Yes, including across machinesagentId, three toolsCascades Five mechanismsRemove by depth, then reject at invocationname@team24k
codex-cli In-process, V1 depth 1, V2 unlimitedYes, direct sibling communicationThreadId, four toolsOnly partial Two mechanismsRemove; V1 additionally rejectsPath-style /root/x7k
openclaw In-process or external process, depth 1Yes, but requires enablingrunId, list onlyCascades Eight mechanismsRemove, then recheck at spawnsession key17k
opencode In-process, implicit depth 1NoChild session idCascades Three mechanismsRemove or reject depending on rule shapeAgent type name0.4k
hermes-agent In-process thread pool, depth 1No within the tree; indirectly through the boardModel cannot obtain idsCascades Five mechanismsRemove at toolset levelAnonymous, one-shot2.9k
pi-mono Child process, unlimited depthNoNoneCascades one level only Two mechanismsRemove using allowlistName of an on-disk .md file1.3k
pi-ai NoneNoneNoneNot applicable NoneNot applicableNone0
weclaw NoneNoNoneNot applicable One mechanismNot applicable@name1.1k
Three immediate observations.Nearly all systems spawn children and converge on in-process execution with a depth limit of 1. Only four implement direct communication, one disabled by default. Tracking varies most: from exposing task_id and cancellation to withholding ids from the model entirely.

02Can agents spawn children?Level two

Three questions: is spawning supported, in-process or subprocess, and is depth limited?

The eight systems occupy four categories, from absent to in-process with unlimited depth Six occupy the middle category: in-process spawning with a low depth limit. This is the current common approach. No such concept No spawning entry point pi-ai Only a protocol snapshot, without an agent loop weclaw External CLI; top-level agents Supported outside the core Example extension only pi-mono Subprocess: each child agent starts a new pi process No depth limit, and child processes reload the same extension In-process spawning with a depth limit Six systems use this category, all with low limits Ours Thread pool, depth 1; 0 means unlimited Claude Code Nested query loop, depth 3 codex-cli V1 Tokio task, depth 1 openclaw Depth 1, configurable up to 5 opencode No counter; relies on permission injection hermes-agent Thread pool, depth 1, configurable up to 3 In-process, no depth limit codex-cli V2 Computes child depth but never checks it Disabled by default Also subprocesses: openclaw host ACP; hermes ACP / board workers; Claude Code tmux / cloud agents. These paths provide isolation rather than depth control; the limits above still govern depth.
Supported?In-process or subprocessDepth limit and enforcement point
OursYes,agent In-process thread pool, 4 workers by default agent.max_spawn_depthDefault 1, with 0 meaning unlimited. Exceeding it returns “do it yourself.” A separate per-turn fan-out limit isagent.max_spawn_fanout8 by default programs/tools/agent/agent/agent.py; configuration defaults in config_schema.py
Claude CodeYes,Agent(formerlyTask) In-process nested query loop, plus tmux/iTerm subprocess teammates and cloud agents throughisolation:"remote" Depth 3, configurable through environment variableCLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH; concurrency cap 20. The leaked source tree has no depth counter; this limit exists only in the binary Binary @250599082 var WJu=3; check @258438030; concurrency @250622624 yny=20
codex-cliYes,spawn_agent In-process Tokio tasks reuse the same thread manager without creating processes V1 depth 1;V2 computes child depth but never checks it, effectively unlimited except for the concurrency cap core/src/config/mod.rs:284; V1 check handlers/multi_agents/spawn.rs:65-71; V2 calculation multi_agents_v2/spawn.rs:62
openclawYes,sessions_spawn Two runtimes:subagentIn-process,acpis an external host process, disabled in sandboxes Depth 1, configurable up to 5. Count:subagent:segments in the session key config/agent-limits.ts:8; check agents/subagent-spawn.ts:784-791
opencodeYes,taskCreate child session In-process re-entry into the same prompt loop, without creating a process No numeric limit. Inject atask: * denyrule into the child session, which removes thetasktool from its schema, making effective depth 1. If the agent itself declarespermission.task=allow, depth is unlimited tool/task.ts:133-135; agent/subagent-permissions.ts:18,25
hermes-agentYes,delegate_task In-process thread pool by default. Two subprocess paths: external ACP CLI and one hermes process per board card MAX_DEPTH=1, clamped to [1,3] tools/delegate_tool.py:133,136-137; check :1958-1972
pi-monoCore deliberately omits it; example extension implements it Subprocess: each child starts a newpi --mode json -p --no-session None. Children reload the same extension directory; theworkeragent declares no tool allowlist and therefore receives the spawning tool, creating an unbounded recursion path used by the official implementation workflow itself README.md:476"No sub-agents"; examples/extensions/subagent/index.ts:329-333; agents/worker.md:1-5
pi-aiNoneNot applicable Not applicable. The repository is a read-only snapshot of pi-mono's LLM transport layer, neither compiled nor imported README.md:1-19
weclawNone It does start subprocesses, but they are user-configured agent CLIs themselves: top-level agents Not applicable; no nesting agent/cli_agent.go:140,159; interface has only four methods in agent/agent.go:79-95

03Can agents communicate directly?Level two

Is there a channel that bypasses the parent? Some systems only support parent delegation and child results; others let siblings address each other.

Three topologies No inter-agent channel Human A B weclaw: one WeChat message can be sent to multiple agents, but they cannot see each other's replies. pi-ai has no agents at all. weclaw · pi-ai Only through the parent Parent A B Parent-child only; no sibling addresses. opencode · pi-mono · hermes-agent (within delegation trees) Direct communication Parent A B Other session/machine Siblings address each other without the parent in the path. Ours · Claude Code · codex-cli · openclaw (requires enabling) Cross-process: Claude Code reaches local/remote sessions; ours reaches other sessions; openclaw uses session keys. Hermes is exceptional: children cannot communicate within the delegation tree, but board workers exchange shared-database comments indirectly.
Direct communication?Connection and delivery
OursYes send_message(to=), from any agent to any unarchived branch, using the same path across sessions without ownership checks. Busy targets receive queued session-inbox messages consumed after their current turn programs/tools/send_message/send_message/send_message.py:82,154; address resolution addressing.py:77-156; inbox agent/inbox.py
Claude CodeYes, including across machines SendMessage.tomay be a teammate name,main(back to the main conversation),*(broadcast), uds:/path.sock(another local session),bridge:session-id(another machine), or a bare agentId. Teammates use file mailboxes~/.claude/teams/{team}/inboxes/{name}.jsonwhile in-process children use memory queues. Sending to a finished agent wakes it from its record and resumes execution tools/SendMessageTool/SendMessageTool.ts; utils/peerAddress.ts:8-21; utils/teammateMailbox.ts:4-8,56-66; wakeup tools/AgentTool/resumeAgent.ts:42-67; address table Binary @258816708
codex-cliYes, direct sibling communication send_messageandfollowup_taskdeliver directly to the target thread without the parent. Addresses are path-based and accept absolute paths, so siblings can address each other. Delivery either queues only or immediately wakes the recipient for one turn handlers/multi_agents_v2/message_tool.rs:11-24,51-131; absolute paths protocol/src/agent_path.rs:59-71; delivery core/src/agent/control.rs:171
openclawYes, disabled by default sessions_sendCross-agent communication requires a configuration switch and pairwise allowlisting. Conversation uses a bounded back-and-forth loop.Children cannot use this tooland must return through the parent's announcement queue agents/tools/sessions-send-tool.ts:193,249-256; back-and-forth loop sessions-send-tool.a2a.ts:94; child restriction agents/pi-tools.policy.ts:49-50
opencodeNo All communication is parent-child. The built-in registry has no messaging tool. A parent can append messages to a running child, still only in the parent-to-child direction tool/registry.ts:217-236 is the complete built-in registry; parent-to-child tool/task.ts:242-257
hermes-agentNo within delegation trees; indirectly through another path Children report only to parents;send_messageis on the “never available to children” list. The board path differs: each card has a worker process, workers exchange card comments through a shared database, and the root card includes a conventionally formatted shared area Denylist tools/delegate_tool.py:50; board toolsets.py:252-269; shared area hermes_cli/kanban_swarm.py:11-14,26,226-268
pi-monoNo Parent-to-child communication supplies one prompt at spawn; child-to-parent communication returns stdout on exit. In sequential mode, string substitution inserts the previous output into the next task description, the only sibling data channel examples/extensions/subagent/index.ts:530,569; parallel tasks are fully isolated :618-639
pi-aiNoneNo agents, therefore no communication
weclawNo Only human-to-multiple-agent broadcast:@a @b messagedistributes the same original message to several agents, each returning a separately prefixed reply to the human. Agents cannot see one another messaging/handler.go:456-486; command registry has only 7 entries :686-698

04Tracking delegated work and cascading cancellationLevel two

Four questions: are there task ids, can status be queried, how are results returned, and can tasks be cancelled? A fifth: does stopping a parent stop its descendants?

Three cancellation propagation patterns Cascade through all descendants Stop Ours · Claude Code · openclaw · opencode · hermes-agent Stop one only Stop codex-cli interrupt_agent, the only cancellation verb in V2 Stop one level, leaving the next orphaned Stop Orphan Orphan pi-mono: unregistered children survive parent kill All five cascading implementations traverse parent relationships with a visited set to guard malformed cycles. The difference is whether they traverse in-memory objects or durable task records.
Can the model obtain a task id?Can status be queried?How results returnCan the model cancel?Does cancellation cascade?
Ours t_prefixlist_tasks Automatically appended to the dispatcher's session for its next turn task_stop, with ownership checks Cascades. Traverseparent_job_idbreadth-first with a visited set for cycle prevention agent/job/runner.py:336-380; return delivery :1075-1186; ownership programs/tools/agent/_ownership.py:21-58
Claude Code agentIdTask registry;TaskOutputretrieves results Synchronous children return directly as tool results; background agents write to disk and send a notification TaskStop, with ownership checks; the main session can stop any agent Cascades in the binary; the leaked source treedoes not cascade: background agents there deliberately omit the parent's abort signal so user ESC does not kill background work Cascade Binary @265089223, ancestor check @253677780; non-cascade tools/AgentTool/AgentTool.tsx:694-696
codex-cli ThreadId plus pathlist_agents, get_status, with push subscriptions A completion monitor synthesizes a message for the parent;wait_agentcan wait synchronously, default 30 seconds and maximum 1 hour interrupt_agent; V1 also hasclose_agent Only partial: close_agentcascades, whileinterrupt_agentstops only one. V2 lacksclose_agententirely, leaving only non-cascading interruption Cascade core/src/agent/control/legacy.rs:86-101, descendant enumeration control.rs:732-756; non-cascade control.rs:247-257
openclaw runIdsubagentsThe tool offers only list Push rather than polling:sessions_yieldends the current turn; results arrive as the next message No model cancellation tool; cancellation uses chat command/subagents killand an HTTP endpoint Cascades recursively with a visited set; each child also clears its queue and writes an abort marker agents/subagent-control.ts:205,232,238,256; kill command auto-reply/reply/commands-subagents/action-kill.ts:27
opencode Child session id, reusable to resume that child session No query tool; the prompt explicitly prohibits status polling Foreground returns through the tool; background inserts a synthetic message into the parent session No model cancellation tool; cancellation is host-side Cascades through abort signals and breadth-first traversal of background-task metadata until a fixed point; session deletion is also recursive session/run-state.ts:116-148; tool/task.ts:296-306; tests test/tool/task.test.ts:870
hermes-agent No. Returns only index, status, summary, and usage; internal ids are operations-only No model tool; status queries are gateway RPC Fully synchronous blocking; returns all child-task results together No model control; interruption is gateway RPC Cascades recursively through active child objects, cooperatively without forcibly killing threads Result fields tools/delegate_tool.py:1684-1720; recursion run_agent.py:1690-1730
pi-mono No. The invocation id received by the tool is discarded No. Progress only reaches the UI through callbacks Read the child stdout event stream and return the final assistant text, truncated to 50KB per task No handle, only the environment abort signal One level only: abort sends SIGTERM, then SIGKILL after 5 seconds. Children are not in the shared cleanup registry, leaving orphans if the parent is forcibly killed Discarded id examples/extensions/subagent/index.ts:466; process termination :393-403; missing registration compared with src/utils/shell.ts:172
pi-ai NoneNoneNoneNone Not applicable. Only one flat abort signal for an individual HTTP request
weclaw NoneNoneSynchronous return, associated by WeChat user id No cancellation command in the registry Not applicable; no hierarchy. Only global cancellation during process shutdown messaging/handler.go:541-556; command registry :686-698

05Preventing infinite loopsLevel two

The matrix lists mechanisms each system actually uses. Empty cells indicate absent mechanisms, not missing investigation.

Loop prevention: mechanisms used by each system Cells show actual values. Empty cells mean the mechanism is absent, not unverified. Depth limit Fan-out limit Concurrency limit Message count Mailbox limit Deduplication Rate limit Timeout · rounds Ours 1 8 4 8 50 60 seconds 50 rounds Claude Code 3 20 50 By uuid codex-cli V1=1 V2 none 6 / 4 openclaw 1 5 8 / 4 20 By key 2 seconds 3 retries opencode Implicit 1 3 consecutive Steps ∞ hermes-agent 1 3 3 600 seconds · 50 rounds pi-mono 8 4 pi-ai weclaw 5 minutes Two immediate observations: depth limits are the only nearly universal mechanism, while only three systems count messages. codex-cli V2 removes depth limits while retaining direct sibling addressing; no counter can stop two agents repeatedly delegating to each other.
Key constants and locations
Ours Depth 1 counts only created generations; a per-chain message budget of 8 counts spawning, messages, delegation, and result return. Per-turn fan-out is 8, concurrency 4, tool calls per turn 50, and inbox size 50 with oldest eviction. Identical sender/content within 60 seconds is duplicate. Self-messages are always rejected regardless of budget. All three budgets allow 0 for unlimited. Each numeric choice is justified beside its constant by comparison with this page MAX_MESSAGES=8 send_message/depth.py; MAX_SPAWN_DEPTH=1 and MAX_SPAWN_FANOUT=8 agent/agent.py; two separate ContextVars in depth.py; 50 per turn agent/agent_loop.py:246; limit 50 and 60 seconds agent/inbox.py; self-message rejection send_message.py:139-144
Claude Code Depth 3, concurrency 20, a 50-message ring mailbox evicting oldest entries, message-uuid deduplication, a boolean fork-recursion guard, a flat teammate roster prohibiting teammates from creating teammates, and no new agents after budget exhaustion.No message rate limit or message-count cap Binary @250599082 depth 3; @250622624 concurrency 20; @253677687 mailbox 50; @253677581 uuid deduplication; fork guard tools/AgentTool/forkSubagent.ts:78-89; flat teammates AgentTool.tsx:273
codex-cli Only two limits: depth (V1=1, absent in V2) and concurrency (global 6, per-session V2 4). No deduplication, message count, rate limit, or cycle detection.V2 removes depth limits and permits sibling addressing, so no counter stops two agents repeatedly delegating to one another core/src/config/mod.rs:212-213,284; concurrency check core/src/agent/control/execution.rs:68-76
openclaw Most layered controls: depth 1 (up to 5), at most 5 children per agent (up to 20), concurrency 8 and 4, cross-agent conversations defaulting to 5 rounds with maximum 20, 2-second steering rate limit, announcement retries capped at 3, child-session-key list deduplication, and a general tool-loop detector disabled by default config/agent-limits.ts:3-8; conversation rounds agents/tools/sessions-send-helpers.ts:15-16; rate limit agents/subagent-control.ts:45,507-516; retries agents/subagent-registry-helpers.ts:35
opencode Depth is enforced through permission injection without a number. Repeated-call detection prompts for permission when the last 3 calls use the same tool and byte-identical arguments. Step limits default to unlimited DOOM_LOOP_THRESHOLD=3 session/processor.ts:35, check :519-546; steps session/prompt.ts:1281
hermes-agent Depth 1 (up to 3), 3 concurrent children, at most 50 iterations per child, a 600-second hard timeout plus heartbeat checks per child, and one global spawn-pause switch.No deduplication or message count.Recursion is additionally restricted structurally by removing the delegation toolset from leaves tools/delegate_tool.py:132-133,136-137,512-523; pause switch :149-172; toolset removal :672-680
pi-mono Only fan-out 8, concurrency 4, and per-task output truncation at 50KB.No depth limit, deduplication, rate limit, or main-loop round cap. An unbounded recursion path actually exists examples/extensions/subagent/index.ts:27-30; main loop packages/agent/src/agent-loop.ts:170
pi-aiNone. There is no tool-call loop and therefore no loop to prevent
weclaw Only two deduplication mechanisms: WeChat message ids for 5 minutes and agent names within one broadcast. No depth, count, or rate limit. Cycles are structurally impossible because agents have no return channel to the handler messaging/handler.go:273,63-64; name deduplication :246-253

06Restricting child toolsetsLevel two

There are only two approaches: remove tools from the list, or retain them and reject invocation. The difference is whether the model sees the tool.

Two approaches Removing tools changes definitions and misses provider prompt caches; retaining them and rejecting calls wastes a model turn on the attempted invocation. Approach A · Remove from the list Filter the tool during request construction so the model never sees it read write bash agent The name is absent from the model's next turn, so it cannot invoke it. openclaw · hermes-agent · pi-mono · codex-cli V2 Approach B · Retain the definition, reject invocation Keep definitions unchanged and enforce at the execution entry read write bash agent Invocation rejected with reason Definitions remain byte-identical, preserving prompt-cache hits. Claude Code fork path Three combinations in practice A only Removal is sufficient. Definitions differ by level, so caches are separated by level. openclaw · hermes · pi-mono · codex V2 Both A and B Remove tools and reject again at execution, protecting the turn with stale definitions. Claude Code · codex V1 · openclaw · opencode Ours: remove according to remaining allowance Remove only when both budgets are exhausted. Deliberately binary, not tiered by depth. Depth tiers change definitions and invalidate caches.
ApproachTools removed and conditions
OursA by remaining allowance, with B as fallback The sole condition isdelegation_budget_left(): only when the message budget is exhausted, removeagent, task_output, task_stopfrom the list. Every dispatch consumes one message, so these three tools can do nothing without message allowance. Exhausted generation allowance does not remove tools because work can still be assigned to existing agents. send_message, list_agents, archive_agent, list_tasksare never removed. The condition is intentionally binary: code explains that provider prompt caches require byte-identical definitions between turns; per-level definitions fragment the cache. Separate rejection messages handle each exceeded limit send_message/depth.py delegation_budget_left; integration points agent/agent.py, task_output.py:37, task_stop.py:32; list filtering functions/_helpers.py:141-147; rejection messages agent/agent.py and send_message.py
Claude CodeBoth A and B, with a historical change The leaked source tree removes unconditionally:Agentis hardcoded in the “never available to children” set. Binary 2.1.226 changes toremoval by depth: its filter retainsAgentonly below the depth limit. Invocation rechecks and rejects to cover stale tool definitions. The fork path deliberately reverses this: forked children receive the parent's complete toolset, includingAgentitself, preserving identical definitions for cache hits; recursion is rejected only at invocation Unconditional removal src/constants/tools.ts:36-46, filtering tools/AgentTool/agentToolUtils.ts:94-95; depth filtering Binary @256834811; full fork toolset tools/AgentTool/forkSubagent.ts:44-71; fork rejection AgentTool.tsx:333 and Binary @258441552
codex-cliV1 uses A+B; V2 only A Tool-list construction checks a switch and omits collaboration tools at the depth limit. V1 handlers recheck and reject, while V2 only removes. Role differences use overlaid configuration files instead of allowlists core/src/tools/spec_plan.rs:561-572,1099; V1 rejection handlers/multi_agents/spawn.rs:67-71; role configuration core/src/agent/role.rs:37,249
openclawA+B Two denylists: all children lose gateway, agent listing, session status, scheduled tasks, and cross-agent messaging. Leaves additionally lose subagent listing, session listing, session history, and spawning. Spawning rechecks depth even if its tool was removed agents/pi-tools.policy.ts:42-51,57-62,170-175; recheck agents/subagent-spawn.ts:786
opencodeA or B depending on rule shape When a deny rule's pattern is"*", remove the tool from the request schema; specific-pattern deny rules retain the definition and throw at invocation, returning the exact matched rule to the model Removal permission/index.ts:215-225 and session/llm/request.ts:198-204; rejection permission/index.ts:86-90, message packages/core/src/v1/permission.ts:84-90
hermes-agentA only, at toolset granularity Child toolsets are the intersection of requested and parent-owned sets, minus delegation, user-question, memory, and code-execution sets. No rejection message is needed because the tool is absent from the schema.One gap: send_messageis on the “never available to children” list, but that list only generates documentation. No matching toolset removal exists, so children inheriting the messaging set still receive it tools/delegate_tool.py:945-961,672-680; list :45-53; gap compared with toolsets.py:190
pi-monoA only Convert the agent's tool allowlist to child-process command-line arguments. The child filters its registry, constructs no executable wrappers for excluded tools, and rebuilds its system prompt from surviving tools core/agent-session.ts:2253-2342; allowlist source core/sdk.ts:280-286; arguments examples/extensions/subagent/index.ts:290
pi-aiNot applicableNo tool executor; definitions are merely part of the transport format
weclawNot applicable Defines no LLM tools itself; all tools are opaque inside the wrapped CLI The repository mentions tool only once, for display: agent/acp_agent.go:139

07Agent identity, addressing, and implementation sizeLevel two

Do agents have names, and how can an existing agent be found? The distinction is between a live entity and merely a definition.

Named?Finding existing agentsAddress format
Ours Yes. Branch creation assigns a 24-character placeholder, then a background LLM improves it at turns 1, 6, 16, and 40 list_agents, with three views: current session, all sessions, and archived. Each includes a directly usable address, turn count, approximate text length, and tail preview SID:HEAD, branch name, or unique name prefix. Addresses resolve to the branch's current tip, so old heads remain valid list_agents.py:100-179; address resolution send_message/addressing.py:77-156,200-208; renaming agent/dispatcher/titles.py:339-405
Claude Code Yes. Teammate id isname@team, readable and reproducible without lookup. Child names come from the spawnnameparameter; duplicate names receive registry suffix-2, -3, mainis reserved ListAgents(formerlyListPeers). The list means recipients you can message: your children, other local sessions, cloud sessions, and other machines when remote control is connected Name / main / * / uds:path / bridge:session-id / bare agentId. Duplicate names resolve to the newest, with an additional suffix for disambiguation utils/agentId.ts:36-57; registry Binary @254742111,@254743413; ListAgents prompt Binary @250608059
codex-cli Yes, two forms. Machine addressing is path-based with root/root; human-facing nicknames come from a list of 101 scientists list_agents, filterable by path prefix. Live children are also injected into environment context and visible without a query Path-based, accepting absolute paths for sibling addressing; bare ThreadId is also accepted protocol/src/agent_path.rs:15-19,54-71,129-146; names core/src/agent/agent_names.txt; listing core/src/agent/control.rs:383-395,361-381
openclaw Yes. Agents are defined in configuration files, not Markdown frontmatter agents_list, but this tool is removed from children Session key, such asagent:<id>:…:subagent:…; label plus agentId is also accepted sessions/session-key-utils.ts:108-126; agents-list-tool.ts:37; child restriction pi-tools.policy.ts:45
opencode Names identify agent types, not live instances No independent list tool. Available names are embedded in thetasktool description. A running agent cannot be discovered; previously obtained ids only reconnect to one's own child session Bare name string tool/task.ts:46,116; names in description tool/registry.ts:252-265; agent definitions agent/agent.ts:35-55
hermes-agent Delegated children are anonymous and one-shot, addressed with objective text No list tool. Internal ids followsa-index-randomand are exposed only through operations interfaces None. The board path differs: profile names identify card owners Parameters tools/delegate_tool.py:2675-2751; internal id :920-922; board hermes_cli/kanban_db.py:5674-5679
pi-mono Yes, but names identify on-disk Markdown definitions, not live processes Cannot discover existing instances. Every invocation rescans the directory; children start without session retention and leave nothing after completion Name strings matched by linear scan. No list tool; the model learns available names only through error messages examples/extensions/subagent/agents.ts:52-56,97-116; startup arguments index.ts:288; parsing index.ts:272-286
pi-aiNoneNoneNone
weclaw Yes: configuration keys, plus built-in and custom aliases No list tool./inforeports only the current agent and is a human command, not an agent-callable tool @nameor/name config/config.go:16-33; parsing messaging/handler.go:206-265; aliases :169,187
Approximate code volume Measurement boundaries differ by directory or file ranges; compare orders of magnitude only. Tests are excluded. Claude Code 24,385 lines Leaked source tree: AgentTool + SendMessageTool + Task*Tool + swarm + tasks + coordinator openclaw 17,240 lines 73 non-test ts files codex-cli 7,059 lines Multi-agent core, plus 3676 supporting lines and 13114 test lines Ours 4,523 lines Collaboration tools 1991 + task package 1759 + inbox 343 + sub_agent_run 430 hermes-agent 2,900 lines Delegation subsystem, plus approximately 1600 lines for the Kanban multi-agent path pi-mono 1,310 lines Entire example extension; the actual mechanism is approximately 190 lines weclaw 1,050 lines All agent-related code; multi-agent routing core approximately 150 lines opencode 415 lines Delegation-specific, plus approximately 365 reused background-task infrastructure lines pi-ai 0 lines No implementation
Diagram details: Remove only when both budgets are exhausted; retain everything while either remains. Depth tiers would change definitions at every level and invalidate caches. Diagram details: Starts external CLI subprocesses, but these are top-level agents. The core explicitly omits it; an example extension implements it. Three systems also offer subprocess paths alongside in-process execution: openclaw ACP runs on the host, hermes supports external ACP CLIs and one process per board card, and Claude Code supports tmux teammates and cloud agents. Diagram details: The parent delegates and children return results; siblings have no addresses. Of four directly communicating systems, three can address beyond the current process: Claude Code reaches another local session or another machine, ours reaches arbitrary other sessions, and openclaw uses session keys across sessions. Diagram details: pi-mono: children are absent from the shared cleanup registry, so forcibly killing the parent leaves orphans. Interpret size carefully.Boundaries differ: openclaw's 17240 lines include UI commands and registries; Claude Code's 24385 lines come from leaked source while the live implementation is binary; codex-cli's 7059 excludes 13114 test lines. The robust conclusion is that a few thousand lines is reasonable; both systems exceeding ten thousand include teammates, cross-machine support, and announcement queues.

08What we plan to doLevel three

Four domains each own a distinct noun. The tool surface uses one primitive: deliver content to a branch, trigger one turn, and automatically return results. The tool surface is detailed onanother page; this section only explains its relationship to the eight systems above.

Plan

todo

A written plan

A manually maintained checklist. Editing it does not run any agent.

todo_createtodo_updatetodo_list
Execution

task

A running task

One task_id, one status, and a guaranteed result return. Cancellable with cascading cancellation.

list_taskstask_outputtask_stop
Entity

agent

The entity executing work

An agent is a branch in the session graph. Create it, delegate to existing ones, list, or archive.

agentlist_agentsarchive_agent
Communication

message

Messaging and history reading

Send a message without creating a task record, or read any branch's complete transcript without triggering it.

send_messageread_conversation
Our choiceSourceRationale
Align tool names with Claude Code
agent list_agents send_message task_output task_stop
Claude Code Models familiar with those names already recognize these tools.task_outputEven parameter shapes are copied
Rename the planning checklist totodo_*Deliberately differs from Claude Code ItsTaskListis a planning board, not a view of running tasks. Changing the prefix letslist_tasksretain its literal meaning: running tasks
Address a branch, not a process
SID:HEADor branch name
Similar to codex-cli path addresses and openclaw session keys Agent conversations already form branches in the session graph. (Session id, head node) uniquely identifies one without another agent entity table
Any agent can message any agent without ownership checks Less restrictive than openclaw; comparable to codex-cli V2 and Claude Code Messages create no task record, cannot be cancelled, and do not cascade; the worst outcome is no response. openclaw disables messaging for children; we retain it
Separate delegation from messaging
agent(to=)creates a task;send_messagedoes not
No other compared system separates them this way Guaranteed result return, cancellation, and cascading cancellation belong to tasks, requiring ownership checks. Messages provide none of these promises, so anyone may send
Prevent loops with a per-chain message budget
Depth 1, messages 8, including return flow; separate counters
Only openclaw and ours use this message-counting mechanism Depth limits alone cannot stop existing agents from repeatedly delegating to one another; codex-cli V2 lacks precisely this counter while allowing sibling links. The value 8 is informed by openclaw's default 5 alternating replies and maximum 20. Our count also includes spawning and delegation, so it falls between them. Return delivery rebinds the completed task's counter rather than incrementing it: one round trip costs 1, permitting eight round trips. Generation depth is separate, increasing only on creation and restoring the dispatcher's value on return. Reading results is not creation, so coordinators can dispatch another batch afterward
Do not copy Claude Code's depth 3
Five systems use 1; so do we
Comparable to openclaw, codex-cli V1, hermes, and opencode Claude Code's 3 cannot be copied directly: the leaked source has no depth counter, andAgentis removed from every child's tool pool unlessUSER_TYPE=ant, making effective external-user depth 1. Its asynchronous-tool allowlist also excludesAgent, so background children cannot spawn regardless of the counter. Depth 3 applies only to synchronous nesting where the parent tool call blocks until completion while a human is present. Our unattended path isrun_in_background=True, where they also use 1 Leaked source src/constants/tools.ts:36-46 and :55-71; filtering tools/AgentTool/agentToolUtils.ts:94-113
Add a per-turn fan-out limit
agent.max_spawn_fanout8 by default
Only openclaw has a true fan-out limit Spawning passes counters to children without changing the parent's copy, so neither chain counter counts siblings. Before this limit, a turn could repeatedly invokeagentuntil the 50-iteration cap stopped it. openclaw allows at most 5 live children per parent (configurable 1–20), a reusable unit. Hermes's 3 and pi-mono's 8 validate batch-argument length per invocation and cannot be copied becauseagentcreates only one child per call. Eight is twice our four-worker pool: fill it, queue one more batch, then reject the ninth and direct the agent to its existing eight children
No steering rate limit or child hard timeout openclaw uses 2 seconds; hermes uses 600 seconds The 2-second rate limit protects openclaw steer, which aborts the child's current turn, clears its queue, and restarts it; closely spaced steer calls can abort each other. Its non-interrupting send path has no rate limit. Oursend_messageis non-interrupting and queues in a busy target's inbox, with nothing to interrupt. Hermes's 600 seconds is caller-sideFuture.result(timeout=…)rather than process termination: it sets a cooperative interrupt flag and abandons the thread, while children blocked in I/O continue. We already provide both parts more strongly:task_output(timeout=)provides the same wait, and task_stopalso terminates the runtime and forces terminal state after 30 seconds
Restrict tools by remaining allowance, deliberately binary Other systems remove unconditionally or by depth tier Depth tiers change definitions at every level and invalidate provider prompt caches. Claude Code's fork path chooses full exposure with invocation-time rejection for the same reason
Three additional tools
list_tasks archive_agent read_conversation
No Claude Code equivalents The model must inspect background work itself. Without archiving, agent lists accumulate finished workers. Reading other histories requires a readable transcript rather than raw session files
Three settled-design gaps remaining in code, verified individually against code: truncate oversized results at both ends and save full text to a file (agent-collaboration.md §5.6) is absent from return delivery; visibility metadata excluding internal branches from session pickers (§5.9) is absent beyond current archive fields; session cancellation clearing the inbox (§5.3) is connected only to the Web entry, not CLI stop
Closing statement: child spawning is common, generally in-process with a low depth limit. Direct communication distinguishes four systems. Loop prevention varies from eight mechanisms to none. We use more loop controls than most and uniquely remove tools according to remaining allowance, deliberately binary to preserve prompt caching. This comparison informed our values: retain depth 1 and message budget 8, add per-turn fan-out 8, and omit steering rate limits and child hard timeouts after inspecting their actual purposes. Each rationale is recorded beside its constant.