Building a subagent team
A roster is not a feature list. Every subagent you add is a routing decision the parent has to get right, and a description it pays for whether it delegates or not.
The parts
You declare subagents through the subagents parameter, and the parent reaches them with the task tool. The exact field names inside a subagent declaration are a reference lookup, and the casing differs between Python and TypeScript, so this lesson teaches the design rather than the schema. That is the right trade for a semi open book exam: the fields are one click away, the judgement is not.
What matters is that a subagent is another agent. Everything you know about model choice, tools, prompts and context applies to it unchanged. That is the architectural reading rather than a stated rule, and it holds because the whole library is one layer built out of the one below.
Descriptions are routing, not documentation
The corollary is the design rule for a team: descriptions must be mutually distinguishable. If two of them could plausibly cover the same request, the parent is not choosing badly, it is choosing between indistinguishable options. That is a writing problem, and reaching for a bigger model to fix it is treating a design fault as a capability shortfall.
Give each child the narrowest reach
A subagent that only reads and searches should not be holding execute. Two reasons, and the second is the one people skip.
Safety. A tool it does not have is a tool it cannot be talked into using, and module 2 established that nothing in the sandbox story defends against being talked into things.
Cost. Every tool the child holds contributes a description to the child’s context on every one of its turns. A forty-turn subagent pays that forty times.
Prompt instructions are not a substitute here. A prompt is a request; an absent tool is a constraint. The layered version, in increasing strength: shape the offering with LLMToolSelectorMiddleware, scope filesystem reach with permissions, bound the environment with the backend, and gate the irreversible with interrupt_on. Simply not registering the tool beats all of them and costs nothing.
Brief and contract
Because the parent never sees the child’s intermediate work, two things carry the whole relationship.
The brief is the child’s entire world. It cannot ask you a question halfway through and, in the default isolated mode, it does not inherit your reasoning. Anything you left out is not merely unmentioned, it is absent. (deepagents has one experimental exception, mode="fork", covered in the previous lesson; the default, and the exam, assume isolation.)
The output contract matters more than the instructions. The transcript is discarded. Whatever the child chose not to report is unrecoverable without re-running the whole thing, so specifying what comes back is a higher-leverage sentence than specifying how to work.
Write the contract as a shape the parent can act on. Return the three candidate files with a one-line reason each is a contract. Investigate thoroughly is a hope.
Try it yourself
What a subagent description is for
A subagent's description sits in the parent's context so the parent knows who is on the roster. What job is it doing?
Show answer
Correct answer: C — Letting the parent decide whether to hand this piece of work over
It is a routing decision, exactly like a skill's description: enough for the parent to choose, and nothing more. The second option is the natural mistake, because the word description invites you to explain the job, and the parent then pays for that explanation on every run whether it delegates or not. Instructions belong in the subagent's own prompt, where only the subagent pays for them.
The two constraints that actually bite
Both of these come from the isolation property rather than from any documented rule, and both are the sort of thing you learn once by getting it wrong.
What two properties of a subagent matter most in practice, given that the parent never sees its intermediate work?
Reveal answer
Its input brief and its output contract. The brief is the subagent's entire world, because it cannot ask a clarifying question mid-flight and it does not inherit the parent's reasoning, so anything omitted is simply absent. The output contract matters more than the instructions, because the transcript is discarded and whatever the subagent chose not to report is unrecoverable without re-running the whole thing. Isolation is what makes both of these expensive to get wrong.
Narrowing a child's reach
A research subagent only ever needs to read and search. It currently inherits an execute tool it will never legitimately use. What is the cheapest correct response?
Show answer
Correct answer: D — Give it only the tools its job requires, scoping the rest via backend and permissions
Do not hand it the capability. A tool it does not have is a tool it cannot misuse, and it also stops costing description tokens. Instructing it in the prompt is the tempting answer because it is the fastest thing to type, but a prompt is a request rather than a constraint, and an agent under pressure from a context injection is exactly the case where requests stop being honoured.
A team-design smell
An agent has nine subagents and the parent frequently picks the wrong one. What is the most likely cause?
Show answer
Correct answer: D — The subagent descriptions overlap, so the routing decision is ambiguous
Routing quality is a function of how distinguishable the descriptions are, and overlapping descriptions make a correct choice impossible rather than merely hard. The model-size option is tempting because more options genuinely is a harder decision, but it treats a design problem as a capability problem, and swapping to a bigger model would paper over ambiguity you could simply remove. The supported-maximum option invents a limit; do not assume caps that were never stated.
Read the roster
A two-agent roster. One entry has its content in the wrong field.
subagents = [
{
"name": "contract-reader",
"description": (
"Reads a contract end to end, extracts every clause "
"mentioning renewal, notice periods or auto-escalation, "
"ignores boilerplate, and returns them verbatim with "
"page numbers, working paragraph by paragraph."
),
"system_prompt": "You read contracts.",
"tools": [read_file, grep],
},
{
"name": "crm-lookup",
"description": "Answers questions about accounts, owners and stages.",
"system_prompt": "You query the CRM and report what you find.",
"tools": [crm_search, crm_get],
},
]Show answer
Correct answer: B — contract-reader, because its description carries the child's working instructions
contract-reader's description explains how to do the job, and the parent pays for all of it on every run whether it delegates or not. Those instructions belong in the child's own prompt. The first option is the honest-looking distractor: crm-lookup's description really is terse, but terse and distinguishable is exactly what a routing decision needs, so it is the one that is right.
Design a two-agent team
Twenty minutes with a scratch file. This is a design exercise, and the point is the justification rather than the syntax.
- Pick a task you would genuinely automate, and split it into exactly two subagent roles.
- For each, write a one-line description aimed at the parent, then a separate prompt aimed at the child.
- For each, list the narrowest tool set that does the job, and write the output contract as a shape the parent can act on.