Skip to content
echogeco
Harnesses and multi-agent workflows · Multi-agent

Subagents and orchestration

Decide when to hand a read to a subagent with a fresh context, write its brief and return schema, and count what the parent actually pays for.

Lesson · 7 min · 59 of 77
On this page

A subagent is a model call with its own fresh context, a narrow brief and a short return. The parent writes the brief, the subagent does the reading in its own window, and only a summary comes back, so the parent pays for briefs and summaries, not for the reading. That is how one task gets through 480k tokens of code when no window holds more than the course's 200k, from the four numbers, and it works only when the pieces of reading do not depend on each other.

The mistake: one context reads everything

A platform team needs an audit: in each of 12 services, find every call to the payments client made without an idempotency key. The relevant code is about 40k tokens per service, 480k in all. Version one is one agent with a file-reading tool, told to go through the services in turn.

The window decides the outcome before quality does. With a 4k system prompt and 40k per service, the context passes 160k during the fourth service, and with output reserved the fifth does not fit. The loop fails or compacts, and compaction summarises the early findings in whatever form the model chooses, under no schema, while it is still reading. With an unlimited window the bill would be the problem instead: one service per turn means turn n carries 4k + 40k × (n − 1), so twelve turns read 12 × 4k + 40k × 66 ≈ 2.7M input tokens to examine 480k of code. And by the end, everything read early sits in the middle of a long context, where recall is weakest — the finding behind tokens and the context window.

Briefs out, summaries back

Version two fans out. The parent writes 12 briefs of about 600 tokens and starts 12 subagents. Each has read-only file tools and a fresh window, reads one service over a handful of tool calls, and returns at most 500 tokens in a fixed schema. The parent reads 12 × 500 = 6k of findings and writes the report.

The parent never holds the code. It holds twelve briefs it wrote and twelve summaries it reads.
100%SVG (opens in a new tab)

Pinch to zoom · drag to pan

Counted:

parent context     3k system + 7k of briefs written + 6k of summaries  ≈ 16k
each subagent      ~100k input over its own turns, ~1.5k output
all subagents      12 × 100k                                           ≈ 1.2M input

The reading is still paid — once, in twelve windows that each hold one service, and in parallel. What disappears is the resend: no service's code rides along on the turns spent on another. 1.2M input against 2.7M, a parent context of 16k against a window that overflowed, and the wall time of one subagent, a few minutes, against twelve in series.

The compression ratio is the number to check. 40k read for 500 returned is 80 to 1. A subagent that reads 3k and returns 500 is 6 to 1, and its brief, system prompt and extra call cost more than the reading it saves; that read belongs in the parent.

When to fan out, and when not to

Fan out when the reads are independent: each subtask can be done knowing only its brief, and its result fits a fixed schema. Auditing 12 services for one rule, searching five sources for one question, and checking 30 files against one checklist all qualify.

Do not fan out over shared state. Three subagents editing one file produce three edits made against a version that no longer exists. A migration plan in which service 3's change depends on what service 1 decided cannot be split, because no brief can carry a decision not yet made. Debugging fans out badly too: the clue is often a detail the subagent did not know mattered, and the summary is exactly where it gets dropped.

The test is one question per subtask: could someone holding only the brief, who can never ask a follow-up, do it correctly? If not, keep it in one context and manage that context with memory and context management. A partial case is common. If 3 of the 12 services reach the payments client through a shared wrapper library, the wrapper is shared state: audit it first, in one subagent, and put its verdict into the other briefs. Two waves instead of one.

Writing the brief and the return

A brief is a prompt for a reader who cannot ask a question, the discipline of writing tool descriptions the model can use. It carries the goal in one sentence, the exact scope (paths, not "the payments code"), what counts as a finding, the return schema, and what not to do. The subagent never sees the parent's conversation; anything not in the brief does not exist for it.

The return is where most fan-outs fail. Twelve prose summaries in twelve shapes cannot be merged reliably; twelve objects validated against one schema can, and code can do the merge. The structured outputs discipline applies:

{
  "service": "orders",
  "files_read": 31,
  "findings": [
    { "file": "orders/refund.py", "line": 88,
      "quote": "client.charge(amount)", "issue": "no idempotency key" }
  ],
  "not_read": ["orders/legacy/ (generated code)"]
}

files_read and not_read exist so that "no finding" and "never looked" look different. Subagents that read other people's code get read-only tools: an instruction planted in a comment, the indirect path in prompt injection and least-privilege tools, can then at worst corrupt one summary, which the parent treats as data.

Who orchestrates: the model or the harness

Anthropic's "Building effective agents (opens in a new tab)" names this pattern orchestrator-workers: a central model breaks the task down, delegates the pieces and synthesises the results. A model should orchestrate when the decomposition needs judgment, as in an open research question where the next subtasks depend on what the first ones found.

When the subtasks are known in advance — twelve services listed in a file — code should orchestrate. A loop writes the briefs from a template, starts the subagents with a token budget each, validates every return against the schema, retries a malformed one once, and calls the model only to write the report. That version is cheaper, bounded and testable, for the reasons in why reliability lives in the harness. When the model does orchestrate, its spawn tool gets a cap, say 12 subagents per task, or a confused parent fans out forty.

In an interview

The question is usually "this doesn't fit in the context — what do you do?", and what is tested is whether you can say what the parent pays for. Put numbers on it: 480k to read, twelve windows of 40k, 6k back to the parent, so the parent's context stays near 16k. Then give the independence test and one case where it fails, such as a shared library or a refactor across files.

The mistake that loses points is fanning out by default: splitting work that shares state, sending 3k reads through subagents, or accepting prose summaries that nothing can merge.

Check yourself

1. Read 8 papers of about 25k tokens each and answer one comparison question. Fan out, or one context?

8 × 25k = 200k, which does not fit one window with a system prompt and output reserved. Fan out to 8 subagents, each returning a 600-token structured summary against the same fields — method, dataset, headline number, limitation — so the parent reads about 5k. The comparison itself needs judgment across papers, so the parent makes it from the summaries; if a field is missing, re-brief that one subagent rather than reading the paper in the parent.

2. A refactor renames a function used in 40 files. One agent, or 40 subagents each editing one file?

Neither by default; this is shared state. The edits must agree on the new name and the imports, and the tests pass only when all 40 change together. A codemod does it deterministically. If a model is needed for ambiguous call sites, one agent holding the full list keeps the edits consistent; forty briefs would cost more than the files and return forty interpretations.

3. Thirty subagents each return 3k tokens of prose instead of 500 of JSON. What changes?

The parent reads 90k instead of 15k, almost half a window before it writes a word, and the merge becomes a model reading thirty styles instead of code joining thirty validated lists. Missing findings and unread files become indistinguishable. Fix the brief: a schema, a 500-token cap, validation on return and one retry.