What this deep dive covers
Every subagent declares an allowedTools list ([Read, WebSearch, Bash] for research, [Read] only for synthesis). The SDK enforces it. Each subagent runs in a fresh isolated context with no inherited messages. Every fact it needs is embedded in the task prompt. Tool overscoping and history inheritance are the canonical failure modes.
What it is
An allowedTools list is the SDK-enforced whitelist of tools a subagent can call. It is declared at spawn time as part of the subagent's config: research subagents typically get [Read, WebSearch, Bash], verification gets [Read, WebSearch, Bash] plus a fact-check rubric, and synthesis gets [Read] only. The SDK rejects any tool call outside the list at the runtime level. You don't have to hope the subagent respects a prompt suggestion; the contract is tool-based, not language-based.
Isolation means each subagent runs in a fresh context window with no inherited messages, no parent chat history, and no shared memory between invocations. The coordinator passes context explicitly in the subagent's task prompt: User asked: [query]. Key context: [pinned facts]. Your task: [focused goal]. The subagent's intermediate work (file reads, searches, tool calls) lives in that nested context and is discarded when the subagent returns. Only the final structured summary comes back.
These two mechanisms together are the architectural payoff of the multi-agent pattern. Tool scoping prevents accidental side effects (a reviewer that should only read cannot Edit; a synthesis subagent cannot re-research mid-narrative). Context isolation prevents bloat (50 file reads in a research subagent cost zero tokens in the coordinator). The SDK enforces both at the contract level, which is why the exam treats allowedTools and isolation as load-bearing primitives, not best-effort guidelines.
How it works
At spawn time, the coordinator constructs a messages.create (or equivalent) call with three scoping fields: system (role + behavior), tools (the whitelist), and messages: [{role: 'user', content: task_prompt}] (the self-contained task). The SDK initializes a fresh agent context with only those inputs. Inside the subagent's loop, every tool call is checked against allowedTools; calls outside the list are rejected before execution. stop_reason signals when the subagent terminates, and the SDK extracts the final message as the summary.
The synthesis subagent is the canonical example. Its allowedTools is [Read] only. No WebSearch. No Bash. This isn't a prompt instruction; it's an SDK-enforced restriction. Even if the synthesis prompt drifts and the model decides it wants to verify a fact mid-sentence, the WebSearch call is rejected at runtime. The model is forced to either render from the verified-claims JSON or acknowledge a gap. That single restriction caps synthesis latency, prevents re-research, and removes a whole class of fabrication paths.
Isolation is enforced by the spawn semantics, not by the SDK alone. Every subagent's messages array starts empty (except for the coordinator-constructed task prompt). There is no resumption, no continue this conversation mode, no second turn. If the coordinator needs more work, it spawns a brand-new subagent with a fresh task. The subagent is stateless by design. The mistake junior teams make is passing the entire coordinator chat history into the subagent for more context. That actively confuses the subagent (it wasn't part of that conversation) and inflates per-subagent cost without benefit.
The 4 decisions
What allowedTools does the synthesis subagent get?
Synthesis stitches verified findings into a narrative. WebSearch enables re-research mid-narrative (3-5x latency, fabrication risk). Read-only restriction is the architectural detail.
Right answer[Read] only. No WebSearch, no Bash, no Edit
How does the coordinator pass context to a subagent?
Subagents do not inherit history. Passing prior messages confuses them (they weren't part of that conversation) and inflates token cost. Embed only what the subagent needs.
Right answerExplicitly in the task prompt as plain text
Coordinator's allowedTools is ['web_search', 'read_document']. Coordinator cannot spawn subagents. Why?
The Task tool is how the coordinator spawns. If it's not in allowedTools, the SDK blocks the spawn call. This is a verbatim CCA-F practice exam question.
Right answerTask is missing from the allowedTools list. The SDK requires it for spawning
A code-review subagent has [Read, Grep, Bash, Edit, Write]. It accidentally modifies a config file. What was the design error?
Tool scope must match the role. Prose can drift; SDK-enforced whitelists cannot. Restrict to the minimum needed for the role.
Right answerTool overscoping. A reviewer should never have Edit or Write
9 decisions the exam turns into distractors
Same as research: [Read, WebSearch, Bash]
[Read] only. No WebSearch, no Bash, no Edit
By passing the entire coordinator chat history
Explicitly in the task prompt as plain text
Subagents need a separate subagent_endpoint config
Task is missing from the allowedTools list. The SDK requires it for spawning
The model misunderstood the prompt. Add stronger prose constraints
Tool overscoping. A reviewer should never have Edit or Write
Retriever subagent has [Read, Grep, WebSearch, Bash, Edit] and accidentally writes a file mid-search. Side effect leaks into the host workspace.
Restrict to the minimum needed per role. Retriever gets [Read, Grep, Glob, WebSearch]. Reviewer gets [Read, Grep, Bash]. Synthesis gets [Read]. Lint the configs.
Coordinator passes the full chat history into the subagent for context. Subagent gets confused, references conversations it wasn't part of, and produces incoherent output.
Embed only the facts the subagent needs in a self-contained task prompt. Treat each subagent as starting from zero. Inheritance is not supported and not desirable.
Synthesis subagent has WebSearch in allowedTools. Mid-narrative it decides to re-verify a fact. Latency triples; fabrication risk reappears.
Synthesis allowedTools = [Read] only. SDK rejects WebSearch at runtime. Forces synthesis to render from verified-claims or acknowledge a gap.
Coordinator's allowedTools is ['web_search', 'read_document']. Spawning a subagent throws tool not allowed. The whole architecture is dead on launch.
Add Task to the coordinator's allowedTools. The Task tool is the spawn primitive; without it, no fan-out is possible.
Subagent has no defined output schema. Wanders for 40 turns, returns a plausible essay. Token bill is huge; coordinator can't aggregate cleanly.
Define a structured output format in the subagent's system prompt ({findings: [{claim, sources}]}). The schema doubles as a stopping cue and an aggregation contract.
5 exam-pattern questions
Work through one question at a time, check the architecture, then move through the set.
A research system decomposes 'impact of AI on creative industries' into three subtopics: visual arts, music, writing. The web-search subagent finds results for all three. The synthesis subagent produces a report covering only visual arts. Why?
Frequently asked
Can a subagent call another subagent (nested spawn)?
In theory yes; in practice avoid it. Nested subagents complicate context flow, increase latency, and obscure the orchestration graph from the coordinator. Keep the hierarchy shallow: coordinator -> leaf subagents only. If you need meta-research, have the coordinator do the decomposition step explicitly.
How do I pass a large document to a subagent if history isn't inherited?
Embed it in the task prompt as plain text, or pass a path the subagent's Read tool can fetch. The coordinator decides which approach. For documents under ~5k tokens, embed directly. For larger, write to disk and pass the path. Either way, the subagent starts with only what's in its task prompt and tools.
Are allowedTools enforced at runtime or at config-load time?
Both. Config-load validates the list against known tools (catches typos). Runtime checks every individual tool call against the allowedTools whitelist before execution. Tool calls outside the list raise tool not allowed. There is no soft-enforcement path; it's hard-rejected.