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 company board. They compose: a card is the hand-over, a message is a nudge — see A card, or a message? below.

Which thread gets which tool

All of the first four follow the agent’s handoffs: false and none is offered. A member that asks for wait: true is refused as a tool result — it cannot delegate and cannot be talked into delegating — which is how the one-level depth bound is enforced at runtime; the save-time check is the other half. A member may still hand work on with wait: false, which starts a top-level session on the target’s own budget rather than a thread of this team.
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
Send one agent one message. It returns immediately — with the new session’s id, status, and the wait it ran under — so a coordinator can start several and then wait once, rather than serialising them. With wait: true the member’s answer arrives later, when the coordinator wakes; with wait: false nothing comes back, and the target’s session is its own.
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 this agent may send work to, and how much of the concurrency budget is spent. Takes an optional query that narrows by a word in the name or description. Each agent comes back with its name, description (truncated to 160 characters), project, team — whether it is on this agent’s roster, so wait: true runs its pinned version — and typed — whether its 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 message, 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 message 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 card, or a message?

send_to_agent and the board both hand work to a teammate, and they are not interchangeable.
  • A card is the hand-over. It is durable, on the record, and it starts the teammate: assign a todo card with no open blocker to an agent by name, and the board’s clock starts a top-level session of that agent on it — on the agent’s own budget, with the card’s notes and comments as its brief, expected to end by moving the card to done with a note or blocked with a comment. That session is a member of the crew: seated on the coordinator’s board by roster, answerable to the board, and not a thread of anyone’s session. The coordinator does not park on it; it hears back through the board’s digest.
  • A message is a nudge. send_to_agent({ wait: true }) starts a member thread of your own session, on your budget, and you park until it answers. Nothing about it is on the record but the thread itself. It is the right tool for a question whose answer you need inside this turn — a fact to check, a shape to fill — not for work that has an owner and a state.
  • wait: false is neither. It hands a message to a normal top-level session of the target’s own, marked metadata.handoff, and nothing comes back. Use it to hand work off your team; use a card to hand work within it, where the teammate’s progress should be readable.
A member thread and a crew session are both seated on the board, so either can read a card and comment on it. What a card gives a coordinator that a message cannot is the record: who holds it, whether it is doing or stuck and on what, and the note the holder left when it finished — none of which survives a transcript. The coordinator page sets the two side by side.
A coordinator that has delegated and parked wakes when its threads finish, not on a teammate’s board write. Cards that reach done or blocked reach the coordinator as one digest session per board, on the next tick after the change.

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.