Topic 55

Orchestrator and Subagents

Delegation

The parent decides what needs doing and delegates a bounded piece of it; the subagent does that piece and reports. Three design questions decide whether the arrangement works: what goes into the task envelope, what has to come back, and who owns the decision when the answer that comes back is uncertain.

Teams get the first two roughly right by instinct and forget the third entirely. Then a subagent recommends a $140 refund on a claim it half-verified, the parent agrees because agreeing is what a fluent recommendation invites, and a payment that sits just under the approval ceiling goes out on evidence nobody in the system ever reviewed.

Down the tree by envelope, back up by schema — and one level is as far as it goes
Parent
owns the decision, every write, and the ticket's counters
12 turns and 60,000 tokens, held on the ticket rather than on the agent
envelope down
question · facts · constraints · tools · budget · return schema
built from state rows, never sliced out of the transcript
Subagent · depth 1
4 turns, 18,000 input tokens, a 9-second deadline
spent out of the parent's allowance; the remainder goes back
depth 2
refused in code, logged against the run id
before the rule: 31 model calls and $2.30 on one ticket, every layer reporting success
summary up
status · coverage · finding · confidence · evidence
validated against the versioned schema before it enters the parent's context
Parent, deciding
low confidence on anything that moves money → a second pass
an accepted recommendation is trusting prose with a schema wrapped around it

The Task Envelope

The envelope carries everything the subagent needs and nothing else. It is constructed from the parent's structured state, never copied out of the transcript, because copying the transcript hands back every token isolation was supposed to remove — along with anything a seller wrote into a product description three turns ago.

The envelope Sundry builds for the damage-pattern subagent, assembled from state rows
{
  "task": "damage_pattern_check",
  "question": "Is transit damage on this product a pattern or a one-off?",
  "facts": {"order_id": "SU-88421", "seller": "Ashcombe Furniture",
             "item": "4-shelf oak unit", "delivered": "2026-03-10"},
  "constraints": ["read only", "last 40 deliveries of this item",
                  "do not contact the seller"],
  "tools": ["search_orders", "track_parcel"],
  "budget": {"turns": 4, "input_tokens": 18000, "deadline_ms": 9000},
  "return_schema": "subagent_finding_v2"
}

Six fields, and each one closes a specific hole. The question is a single sentence, so the child cannot drift onto a different job. The facts are the structured values it would otherwise have to re-derive, which saves it two lookups. The constraints say what it may not do in language the model reads, while the tool list says what it cannot do at all, enforced in the dispatcher. The budget is the child's slice of the ticket's allowance. The return schema names the contract the result will be validated against, so a malformed answer is a caught error rather than a paragraph nobody parses.

Version that schema, as subagent_finding_v2 does. A child that starts returning a new shape is an interface change between two components, and it deserves what any other contract change gets: a version number, a diff a reviewer can read, and a run through the eval suite before it merges. Chapter 9 counts schema edits as changes that trigger the pipeline precisely because they are not application code and therefore slip through.

The Contract Back

What comes back is the structured summary from the previous topic, and the part teams under-build is the failure half. A subagent that could not complete must say so in a field — status, coverage, stop reason — because a sentence saying "I was unable to check all deliveries" is only read if the parent happens to attend to it, and attending to it is precisely what a model under a budget does not reliably do.

Validate the result before it enters the parent's context. A schema check costs microseconds and it converts three different disasters into one ordinary error: a missing status field, a confidence value that is not one of the three allowed strings, and a finding that arrived as two paragraphs of prose because the child decided to be helpful. On a validation failure Sundry re-runs the child once with the error appended in the style of Chapter 3, then escalates. It does not pass an unvalidated blob upward and hope.

Then there is the question teams forget: what the parent does when the finding is uncertain. A confidence signal is worth nothing unless some branch of the parent's code reads it, so the policy gets written down. At Sundry, low confidence on anything that moves money means a second pass with a larger budget, and low confidence twice means escalate_to_human with both findings attached. Without that rule the failure is undramatic and completely silent: a parent accepting a recommendation because the recommendation was fluent, which is trusting prose again with a schema wrapped around it.

Who Owns the Money

The parent owns the decision and every write. Subagents gather, verify and recommend. That is not an aesthetic preference about hierarchy — it is what keeps the $150 approval gate in one place, so Chapter 12's control has one code path to protect rather than one per agent.

Enforcement lives in the dispatcher, where authorization has lived since Chapter 3. Each subagent type has an allow-list in code: the damage-pattern child gets search_orders and track_parcel, and a request for issue_refund comes back as a tool error the child can read and react to, plus a logged event the eval suite treats as an invariant violation. Note what is not doing the work here. The child's prompt says it is read-only, and that sentence is a courtesy — the permission is the allow-list, and it would hold even if the child's prompt had been replaced wholesale by text a seller wrote.

Budgets Cascade

A ticket has one allowance, and delegation divides it rather than duplicating it. Sundry's loop limit is twelve turns and Chapter 2 fixed a 60,000-token ceiling per ticket; dispatching a child spends one of the parent's turns and hands over a slice of what remains — four turns, 18,000 input tokens — which the ticket's own counters deduct. When the child returns, whatever it did not spend goes back to the parent.

Duplicate the budget instead and the arithmetic goes wrong where nobody is looking. Three children each starting fresh at twelve turns is a ticket that can legitimately reach 36 model calls while every individual limit reads as respected, and the cost report shows a single ticket at several dollars with no bug anywhere to point at. Hold the counters on the ticket, not on the agent, and the ceiling means what it says.

Depth Limits

Subagents spawning subagents is where cost stops being predictable, because the growth is multiplicative and every level of it looks like diligence from inside. Sundry learned this on one ticket. The damage-pattern child was allowed to dispatch children of its own; it fanned out per order, each of those fanned out per parcel scan, and the run finished with 31 model calls and $2.30 spent on a single ticket against an average of $0.11. Nothing errored. Every layer reported success.

The rule that followed is one level, enforced in code rather than in a prompt. The run record carries a depth counter, the dispatcher refuses any dispatch request at depth 1 and returns a tool error, and the refusal is logged with the run id so a rise in refusals is visible rather than silent. If a task genuinely needs two levels, that is a signal the parent's decomposition is wrong — the second level belongs as a sibling under the parent, where its budget is visible and its result is one the parent can actually see.

Record the parent-child relationship in every trace, with the parent's run id on each child span. A delegated run that reads as three unrelated traces costs an hour of an incident before anybody works out which child produced the finding the parent acted on. One tree, one run id, and the debugging in Chapter 13 stays possible.

Common Mistakes
  • Passing the whole parent transcript as the envelope — the isolation benefit is gone at the first handoff, and the child inherits every oversized tool result and every line of seller-written text the parent had collected.
  • Letting subagents call write tools — the audit trail fragments across runs, and the $150 ceiling can be reached twice on one ticket by two children that each stayed under it.
  • Unbounded nesting — a fan-out bug in one prompt becomes 31 model calls and $2.30 on a single ticket, and every layer of it reports success on the way down.
  • Giving each child a fresh budget — three subagents at the full twelve-turn allowance is three times the intended ticket cost, with every individual limit still reading as respected.
Best Practices
  • Define the envelope as a schema and construct it from structured state, never by slicing the parent's message list.
  • Keep write authority and approval in the parent, and enforce each child's tool allow-list in the dispatcher rather than in its prompt.
  • Hold turn and token counters on the ticket so budgets divide across children, and return the unspent remainder to the parent.
  • Enforce a depth limit of one in code, log every refusal, and record the parent run id on every child span so a delegated run reads as one tree.
Comparable toolsLangGraph orchestrator and worker nodesVendor agent SDKs subagent dispatch primitivesJob fan-out the same budget problem in ordinary systemsDistributed tracing parent and child spans in one tree

Knowledge Check

What belongs in the task envelope handed to a subagent?

  • The question, the facts it needs, its constraints, its tool list and its budget
  • The parent's message list so far, so the child has the full picture
  • The parent's reasoning about the ticket so far, so that the child follows the same logic
  • The full nine-tool surface, so the child is never blocked mid-task

A subagent verifying a damage claim asks to call issue_refund. What should happen, and why?

  • The dispatcher returns a tool error, because the allow-list is where the permission lives and writes stay with the parent
  • The call runs as long as the amount sits under the $150 ceiling, since that ceiling is the control which actually matters
  • The child's prompt is rewritten to state much more firmly that it is a read-only agent, and the request is then retried once
  • The request is forwarded up to the parent for execution, which keeps the audit trail intact and the ceiling in one single place

Why must turn and token budgets divide across subagents rather than being handed out fresh?

  • Otherwise a ticket with three children can reach 36 model calls with no individual limit ever exceeded
  • Otherwise the concurrent children trip the provider's rate limit and the whole ticket ends up queued behind itself
  • Otherwise each child builds a separate prompt prefix of its own and the cache hit rate collapses across the run
  • Otherwise the children finish out of order and their results attach to the wrong requests

What does a depth limit of one actually prevent?

  • Cost growing multiplicatively through nested fan-out, where each layer looks like diligence and nothing errors
  • A subagent that ends up calling itself recursively, which on a genuinely ambiguous ticket would never terminate at all
  • The child contexts merging into the parent's buffer once more than two levels are running
  • Two subagents deadlocking while each waits for the other's finding before reporting

You got correct