Skip to main content
Delegation is one of the two ways a team coordinates — the point-to-point one. The coordinator does not call members over the network or embed them in a prompt. It delegates through built-in tools that Vetta injects into every team session, and each delegated call opens a new, isolated session for the member. The other mechanism, the durable one, is the team board. They compose, and the pattern that runs in production uses both.

Which thread gets which tool

send_to_agent is not merely refused for a member — it is never constructed, so a member cannot delegate, cannot be talked into delegating, and does not pay the tokens its schema would cost on every turn. That is how the one-level depth bound is enforced at runtime; the save-time check is the other half.
One line of the table reads differently on claude_code and hermes. Those two run a CLI as a process in a micro-VM, on that CLI’s own toolset, and reach these three tools over a session-scoped tool endpoint the machine is given rather than through the toolset Vetta assembles for a turn. They all work — a coordinator on either harness delegates, reads and writes the board normally — with one caveat: wait_for_agents does not pause the turn there. The coordinator parks once its turn goes idle and the delegated threads open correctly, so the cost is a few extra model calls between the fan-out and the park, not a wrong answer. See Harness capabilities.

The delegation tools

tool
Hand one teammate one brief. It returns immediately — with the new thread’s id and status: "running" — so a coordinator can start several and then wait once, rather than serialising them. The member’s answer arrives later, when the coordinator wakes.
tool
Park until the delegations you name are done. The coordinator’s turn ends here and resumes with the results. A session yielding here reports the awaiting_delegation stop reason and nothing else — awaiting_input would claim a person can unblock it and end_turn would claim the task is finished, and a caller acts on both.With nothing outstanding it is an immediate no-op — { parked: false, outstanding: 0 } — rather than a park, because parking a coordinator that has delegated nothing is a session that never wakes.The park is the turn’s, not the call’s. send_to_agent returns at once, so a coordinator can start four and wait once; the whole fan-out is dispatched when the turn ends, and this is what ends it. Calling it in a turn that delegated reports awaiting_delegation. Calling it in a turn that delegated nothing — you were resumed by one teammate and another is still running — parks the session idle instead, and the wake gate resumes you on the last one. Either way the turn stops here: it does not run on and it does not poll.
tool
Who is on the team, and how much of the concurrency budget is spent. Each teammate comes back with its name, id, pinned version, description (truncated to 160 characters), harness, and typed — whether that harness can honour an output_schema at all. Alongside them: concurrency: { running, limit }.
typed is derived for the model rather than left for it to infer from harness, because the model does not carry the harness catalogue and this is the one fact that decides whether a send_to_agent call may carry output_schema.

Nothing throws — a refusal is a tool result

Every way a delegation can fail to happen comes back as a tool result the model can read and act on, never as an exception that would end the turn.

Delegation is about context isolation

The point of delegation is not parallelism first and foremost — it is context isolation and cost. When the coordinator calls send_to_agent, the member’s session starts fresh: its opening context is only the brief, not the coordinator’s (possibly enormous) transcript. That has two consequences:
  • Focus. The member reasons over a small, relevant context instead of wading through unrelated history.
  • Cost. Every model call in that session carries far fewer tokens, so the same work is materially cheaper than expanding the coordinator’s own context. See Context & budgets.
If you find yourself pasting large context into a single agent’s prompt, that is often a signal to delegate: split the work so each member holds only the slice it needs.

Isolated sessions, and what carries between them

Every member runs in its own session with its own conversation history. Two sessions never share conversation context: a member cannot see the coordinator’s transcript or any sibling’s, only the brief it was handed and its own turns. That isolation is the point, but it means the brief is the whole hand-off. There is no argument that continues an earlier member session — a delegation is one-shot. If a member needs to know what another member already did, that has to reach it some other way, and the way is the board: a card’s notes are readable by every thread on the team, which a transcript is not.
A member’s board write also wakes a parked coordinator, even before that member’s session finishes. So a member that discovers something the coordinator should act on now does not have to finish first — it comments on a card, and the coordinator gets a turn. That is the clearest case of the two mechanisms composing.

Typed results

By default a member returns free-form text. Pass an output_schema on send_to_agent and the hand-off becomes a typed contract instead: the member’s session must go idle producing a structured_output object that validates against the schema. Not every harness can do this. list_agents reports typed per member, and a call carrying output_schema for a member that cannot is refused up front as no_structured_output — named, rather than quietly served as prose the coordinator’s merge code then has to parse. The refusal is deliberately at call time and not at save time: whether any delegation will carry a schema is unknowable when the roster is written, and banning a text-only teammate outright would also ban the prose work it serves well.
This is what makes fan-out composable: when every member returns the same shape, the coordinator merges results deterministically rather than re-reading a pile of transcripts.
One catalogue entry is currently optimistic. The vetta harness declares structured_output and is reported as typed, but its loop has no way to submit one — so a typed delegation to a vetta member is admitted by every gate and can then only fail at the turn. Until that lands, delegate to a vetta member without an output_schema and ask for the shape you want in the brief. The pi harness serves typed results today.

Fan-out: several members at once

The coordinator may have several members running at the same time — each in its own session with its own isolated history — and then park once on wait_for_agents. Give each the same output_schema and merging the batch is just collecting typed objects.
CLI
The coordinator’s session events carry the fan-out: thread.created when a member session is spawned (with its agent_id and member name), and thread.idle as each result folds back. See Context & budgets. Each member is billed independently and quoted against the org balance before it runs.

Bounds

Delegation is deliberately shallow and bounded to keep teams reproducible and cost-safe.
One level only. You cannot build a tree of coordinators. If you add a roster member whose config is itself a coordinator, the save is rejected. Use self for homogeneous recursion within a single level — a self copy runs the coordinator’s base behavior on its own brief.

Next: the team board

The other mechanism — durable, broadcast, and the one that outlives the run.