Multi-Agent, Rebuilt: Persistent Teams and One Supervisor for Every Agent
A multi-agent system can look like it works long before it does. A worker shows "running" without a model loop behind it; a pause key does nothing; a correction sent as it finishes is never read. v1.7.0 is the release where ClawCodex's agents stop looking like they work and start working — with the scope written down as carefully as the features.

What Shipped
ClawCodex v1.7.0 rebuilds the layer that runs agents on behalf of your agent. Two changes carry it. A session-scoped supervisor now admits, tracks and interrupts every subagent — foreground, background, team and workflow — and can pause new spawns (#915, #950). And agent teams actually run: TeamCreate makes your session the leader, and named teammates stay alive between assignments, message each other, and pull work from a shared, dependency-aware task board (#950).
You drive it in plain language. Ask for a team, and the flow underneath looks like this:
you ▸ "Start a team: a reader summarizes README, a reviewer checks it."
leader ▸ TeamCreate you are the leader (.clawcodex/team.json)
leader ▸ Agent · name=reader named → a persistent teammate
leader ▸ Agent · name=reviewer
reader ▸ SendMessage → reviewer findings go peer to peer
reviewer ▸ SendMessage → leader
leader ▸ shutdown → both approve → TeamDeleteNone of that is new vocabulary — the tools existed before this release. What is new is that every step now does what its name says. The rest of this post is about the gap between those two things.
Two Spawn Paths That Never Met
ClawCodex spawned subagents down two paths. A foreground delegation ran inline and returned its answer; a background one landed in the task registry and reported back later. Only the background path was observable. A foreground delegation registered nowhere, so nothing could list it or stop it — there was no abort handle that escaped the call.
Nothing bounded how many agents could run, or how deep they could nest. A depth was computed and never compared to anything. And the terminal UI's agents dashboard called three RPCs — status, pause, interrupt — that the client routed to a catch-all returning an empty object. The status readout stayed blank, and the pause and kill keys silently did nothing. The response types for all three had been declared for some time. The backend behind them had not been written.
The team tools had the same shape of problem. TeamCreate, SendMessage and the task board existed, with mailbox helpers underneath them — but there was no production lifecycle that ran a teammate. And a follow-up sent to a finished background worker flipped it back to running without starting a new model loop. It looked resumed. Nothing was running.
One Supervisor
The fix for the first half is a single AgentSupervisor per session, shared by reference into every child context so one object sees the whole tree. Both spawn paths — and, since #950, team and workflow workers — admit before running and release when the worker actually exits.
- Two limits, as in Codex
- By default, at most 32 concurrent agents (CLAWCODEX_MAX_CONCURRENT_AGENTS) and a spawn depth of 3 (CLAWCODEX_MAX_AGENT_DEPTH). The concurrency default is a runaway backstop, not a scheduling budget — set well above any legitimate fan-out, because a background agent holds its slot until its worker exits, possibly many turns later.
- Refusal is a tool error
- A spawn past either limit comes back to the model as a tool error it can act on, rather than an exception that fails the turn.
- Foreground is interruptible
- A synchronous delegation now carries a reachable abort controller, so it can be stopped like any other agent. Parent-ESC propagation into it is preserved.
- The slot outlives the label
- An interrupt holds the slot until the worker really exits. A terminal status label is not proof the worker stopped; releasing on the label would let a replacement start while the old run is still on the wire.
The admission design follows OpenAI Codex's multi-agent runtime, which reserves a slot per spawn and refuses past a cap and a depth limit. In the terminal, /agents opens the spawn-tree dashboard — p pauses spawning, x stops the selected agent, X stops its whole subtree — and /agents pause, resume and status act without opening it. In the web client the same controls live in the header's N subagents list: Stop on each running row, Pause spawning at its foot.
Teams That Actually Run
The second half gives the team tools a real lifecycle, compared against the Claude Code reference throughout. TeamCreate establishes the leader and the roster. A named Agent call creates a persistent teammate; a managed poller consumes its mailbox, and it stays available for further assignments, keeping its context and its file-read fingerprints between them — so a teammate that read a file in one assignment can edit it in the next.
- Communication is explicit. SendMessage delivers findings to a named peer or to the leader. A teammate's final prose stays private — it does not leak into another agent's context by accident — and idle and exit notices tell the leader who is available.
- Work is shared. Team members pull from one locked, persisted task board. Automatic pickup honors dependencies, and a completion hook can veto a completion. The end-to-end suite races 24 concurrent claimers over 12 tasks.
- Control is matched. Only a leader approval that matches the teammate's own request changes its permission mode; a rejection, a stale response, or a mailbox record the runtime never issued cannot. Shutdown follows the same request/response shape, so a teammate can decline one.
- Permissions die with the worker. A teammate's permission prompt carries its identity and an abort signal. Interrupt the worker and the pending prompt is denied and removed, instead of waiting for an answer nobody can use.
- The leader stays the leader. Starting a team does not turn your root conversation into a subagent; its roster identity is stored separately. Teammates cannot create another team or spawn named teammates of their own.
The Bugs Behind "It Looked Like It Worked"
Most of #950 is lifecycle work: making the state a UI shows match the state a worker is actually in. Each row below was reproduced before it was fixed.
| Area | Before | Now |
|---|---|---|
| Background resume | A finished worker became running with no model loop behind it | A managed thread reloads its typed transcript and reuses its ID and settings |
| Late corrections | A message accepted during the final answer could stay unread | Completion checks the inbox atomically and continues the loop |
| Named launches | Concurrent launches could claim a name before either task was visible | The task is published before the name is claimed; collisions are rejected |
| Notifications | A process-wide queue could deliver another session's result | Results reach the session and parent that own them; orphans go to the root |
| Workflow stop | A task handle could precede its registry entry | An immediate TaskStop works, and a late start cannot resurrect the task |
| Workflow budget | Queued calls checked the budget before acquiring a slot | Checked after acquiring; every attempt is charged, failed ones included |
| Isolation | Agent ignored worktree requests; setup could fall back to shared files | Runs in a real Git worktree or fails before the model runs; edits are kept |
| Session exit | Background workers could outlive a closed transport | Admission pauses, owned work is interrupted, threads are joined with a bound |
How We Checked It
Multi-agent bugs hide in timing, so the new tests do not wait for a model to happen to choose the interesting sequence. They replace the provider with a script and drive the rest of the stack for real — query loops, tools, task registries, transcripts, mailboxes, worktrees, and WebSocket connections, each suite exercising its part — with some tests controlling startup timing or installing a hook to hit a specific race.
- Runtime end to end
- Real Read, foreground and background output, same-ID resume with prior history, late corrections, eight competing named launches, max-turn failure, two-session delivery, nested and orphaned notifications, workflow budget, and immediate and active TaskStop.
- Teams end to end
- Leader/member identity, peer and leader delivery, private final output, repeated assignments, dependency-aware claiming, completion-hook veto, a real Write denied after plan rejection and permitted after approval, forged controls, and shutdown rejection and approval.
- Over the wire
- A real client and server over WebSocket: TeamCreate → Agent → permission request → allow, or interrupt and retry the same worker → Write → SendMessage → summary → approved shutdown → TeamDelete.
Then one live run against a real provider — DeepSeek, deepseek-v4-pro, in a scratch workspace. It passed all four checks: a background worker used Read to fetch two values and returned their sum; the same worker resumed with its history and doubled it; one persistent teammate sent a result to another, who acknowledged it to the leader; and both approved matching shutdown requests before TeamDelete removed the team.
What It Does Not Do Yet
The boundaries are part of the release, so here they are in the same detail as the features:
- Teams are in-process. The reference's tmux and iTerm pane backends, remote-control workers and UDS permission relay are not implemented; the mailbox on disk is a delivery format, not a cross-process team backend.
- Resume is same-session. A finished worker can be resumed while its session lives; a transcript alone does not recreate an executable worker after a process restart.
- One team per workspace, and no automatic crash recovery. A normal shutdown removes an exited team; a crash may leave a stale roster in .clawcodex/team.json to remove by hand once the old process is gone.
- A workflow's token budget stops new work from starting once usage reaches it. Requests already in flight can finish above it — it is not a provider-side spending cap.
- Cancellation is cooperative. A provider blocked inside a synchronous call may finish that call before its thread exits.
Try It
pip install -U clawcodex-cli # or the one-line installer
export CLAWCODEX_MAX_CONCURRENT_AGENTS=32 # the defaults, if you
export CLAWCODEX_MAX_AGENT_DEPTH=3 # want to change them
clawcodex # then ask for a teamInside the session, /agents opens the spawn-tree dashboard:
/agents # p pause spawning · x stop · X stop subtree
/agents status # or pause / resume, without opening itAlso in v1.7.0
- clawcodex --nano, the pi-style minimal harness: a ≈2K-token fixed payload instead of ≈17K, and level with the pi harness on the full Terminal-Bench 2.1 suite — 64/89 and 63/89 in nano's two latest runs against pi's 63/89, same model, k=1 — so read it as parity on score, not a ranking.
- Bash no longer stalls on a command that prints more than ~64 KB: output was read only after the command exited, so it blocked until the timeout and came back cut off. That fix applies in every mode.
- DeepSeek-V4.1-Flash becomes the DeepSeek default, and /cost follows its peak/off-peak card.
- A model or effort pick is saved as your default for new sessions, on every interface.
- Cost-aware auto-compaction, opt-in: compact only when the savings repay the summary call.
- ChatGPT-subscription logins discover the models that account can actually use.
- In the web client: subagents in the header with a child view per run, attachments of any file type, and saved sessions that open in milliseconds instead of about 45 seconds.
- Upgrade notes: clawcodex serve now refuses a non-loopback bind without --allow-remote, and clawcodex agent-server refuses one without --token.
Conclusion
The easy version of a multi-agent feature is a tool that spawns things. The useful version is one where you can see every agent that is running, stop any of them, trust that "resumed" means resumed, and know which of your agents can talk to which. v1.7.0 is the second version — in-process for now, with its limits written down — on the same open-source runtime as everything else, so you can read the tests and check the claims yourself.
References
- docs/multi-agent-runtime-verification.md — the defect list, runtime map, test evidence and operational boundaries
- PR #915 — the session-scoped agent control plane
- PR #950 — persistent teams and worker lifecycles
- CHANGELOG.md — the full v1.7.0 entry