Subagent Invocation, Context Passing & Spawning
Spawning a subagent is like handing a brief to a contractor who has never seen your project: they get only what you write in the brief. No shared inbox, no shared memory.
A coordinator delegates by calling the Task tool (also used as Agent in Anthropic's Managed Agents docs).
Subagent context is never auto-inherited - every fact the subagent needs must be written into the prompt the coordinator sends.
Here we learn the mechanics of invocation, configuration, and context passing.
1. Core Concept
Where D1.2 module asks, "should I use multi-agent?", This module asks, "how do I actually wire the spawn, the config, and the data hand-off so the subagent succeeds?"
The official bullets, grouped:
| Area | Bullet |
|---|---|
| Spawning mechanism | The Task tool spawns subagents; coordinator's allowedTools must include "Task" (for Managed Agents: "Agent") |
| Context isolation | Subagent context must be explicitly provided in the prompt; no auto-inheritance of history, system prompt, prior messages, other subagents' results, or shared memory |
| Configuration | AgentDefinition: description drives selection, system prompt, per-subagent tool restrictions |
| Forking | Fork-based session management for divergent exploration from a shared baseline (more details in [[d1.7-session-state |
| Passing findings | Include complete prior-agent findings directly in the subagent's prompt |
| Attribution | Structured data formats to separate content from metadata (URLs, doc names, page numbers) |
| Parallelism | Spawn parallel subagents via multiple Task calls in one coordinator response |
| Prompt style | Specify goals + quality criteria, not step-by-step procedures |
2. The Task Tool — the Spawning Mechanism
A coordinator does not "create" a subagent through some side channel. It calls a tool, exactly like calling search or edit. That tool is the Task tool. The subagent runs its own agentic loop and returns a result that arrives back in the coordinator's context as a tool_result.
Taskis just a tool. If it is not inallowedTools, the coordinator literally cannot delegate. The capability does not exist for that agent.
Coordinator agentic loop
│
├── emits tool_use: Task(subagent="web_search", prompt="...")
│ │
│ └── subagent runs its OWN loop → returns final text
│
└── tool_result(Task) added to coordinator context
2.1 Naming: Task Vs Agent
They refer to the same delegation mechanism:
| Surface | Tool name | Where seen |
|---|---|---|
| Claude Code / Agent SDK framing | Task |
allowedTools includes "Task" |
| Managed Agents docs | Agent |
coordinator's allowedTools/toolset includes "Agent" |
Trap:
A coordinator that "can't seem to delegate" or "ignores its subagents" most often has
Task/Agentmissing fromallowedTools. Adding more subagent definitions does nothing if the coordinator lacks the tool to invoke them.
# Coordinator must be granted the delegation tool
coordinator = AgentDefinition(
description="Researcher: decomposes queries and delegates to specialists.",
prompt="You are a researcher. Delegate to specialists and synthesize.",
tools=["Task"],
)
3. Context Is NOT Inherited
A subagent starts effectively blank. Spawning it does not carry over anything from the coordinator.
| Does the subagent automatically get... | No, unless passed in the prompt |
|---|---|
| The coordinator's conversation history? | ❌ |
| The coordinator's system prompt? | ❌ |
| Prior messages / earlier turns? | ❌ |
| Results from other subagents? | ❌ |
| Shared memory / global state? | ❌ |
| Its own prior invocations (call 1 → call 2)? | ❌ |
If a subagent needs to know it, the coordinator must write it into the
prompt. The prompt is the only channel.
3.1 Why This Is the Right Design?
Isolation is a feature: it keeps each subagent's context lean and high-signal. The cost is that the coordinator becomes responsible for explicitly packaging every relevant fact.
Trap:
Misdiagnosing incomplete subagent output.
When a subagent returns something thin or off-target, the first diagnostic question is "Did the coordinator pass enough context?" - not "is the subagent broken?" The default answer for an under-informed subagent is fix the context passing, not retrain/replace the subagent.
# WRONG — assumes the subagent "remembers" the earlier search agent's output
Task(subagent="synthesis", prompt="Now synthesize the findings.")
# RIGHT — the coordinator hands over the actual findings
Task(subagent="synthesis", prompt=f"""
Synthesize a cited answer to: "{question}".
Findings from prior agents are below. Use ONLY these.
{search_findings_json}
{doc_analysis_findings_json}
""")
4. AgentDefinition Configuration
Each subagent type is declared by an AgentDefinition. Three fields matter most:
| Field | Purpose | Exam emphasis |
|---|---|---|
description |
What the subagent is for | Drives selection - the coordinator reads descriptions to decide which subagent fits a subtask |
System prompt (prompt) |
Defines the subagent's role/behavior | The subagent's only standing instructions (it does NOT inherit the coordinator's system prompt) |
Tool restrictions (tools) |
Scopes capabilities per role | Least privilege per agent |
Sample AgentDefinition():
web_search =
AgentDefinition(
description="Searches the public web; returns sources with URLs, titles"
"Use for current events and external evidence. NOT for internal",
prompt="You are a web research specialist. Return structured findings: "
"each claim with its source URL, title, and publication date.",
tools=["web_search", "web_fetch"], # scoped to its role
)
synthesis =
AgentDefinition(
description="Combines findings from other agents into a cited answer. "
"Does NOT search or fetch — operates only on provided findings.",
prompt="You are a synthesis specialist. Reconcile and cite the findings",
tools=[], # no search tools → cannot misuse them
)
4.1 description Is the Selection Mechanism
The coordinator picks subagents by reading their
descriptionfields, just the same way an LLM picks a tool by reading its description.
A vague description ("analyzes things") causes wrong routing; a precise one with "use this when… / not for…" boundaries routes reliably.
Trap:
If the coordinator keeps sending work to the wrong specialist, the fix is usually sharpen the
description(and tool scoping), not add a routing classifier or hard-code the pipeline.
4.2 Tool Restrictions Enforce Specialization
Giving a synthesis agent web-search tools invites it to "just search instead of synthesizing." Restricting tools=[] makes the role boundary structural, not advisory. This is the per-agent application of least privilege.
5. Fork-Based Session Management
Forking creates independent branches from a shared analysis baseline so multiple divergent approaches can be explored without redoing the shared groundwork.
Shared baseline (e.g. completed codebase analysis)
│
fork_session ─┬─→ Branch A: try testing strategy X
├─→ Branch B: try testing strategy Y
└─→ Branch C: try refactor approach Z
│
Compare branch outcomes; pick the winner
| Concept | Meaning |
|---|---|
fork_session |
Creates an independent branch from a shared session/analysis state |
| Use case | Compare divergent approaches (two testing strategies, two refactors) that share one expensive analysis |
| Benefit | Each branch reasons from the same baseline; branches don't pollute each other |
5.1 Forking Vs Spawning a Fresh Subagent:
Fresh Task spawn |
fork_session |
|
|---|---|---|
| Starting context | Blank (only the prompt) | Inherits the shared baseline at the fork point |
| Best for | New, independent subtask | Divergent exploration from common groundwork |
Trap:
Forking is not the same as parallel fan-out. Fan-out splits different subtasks; forking explores alternative approaches to the same subtask from a shared baseline.
6. Passing Complete Findings into the Subagent Prompt
The coordinator must put complete prior findings directly in the subagent's prompt. The classic case is the research pipeline: the web-search agent and document-analysis agent each return findings, and the coordinator must hand both sets to the synthesis agent verbatim — synthesis cannot fetch them itself.
# Coordinator aggregates upstream outputs, then injects them whole
synthesis_prompt = f"""
GOAL: Produce a cited answer to "{question}". Coverage target: all major subtopics.
WEB SEARCH FINDINGS:
{web_findings}
DOCUMENT ANALYSIS FINDINGS:
{doc_findings}
Use ONLY the findings above. Cite every claim to its source. Flag any subtopic
with no supporting evidence as a coverage gap.
"""
Task(subagent="synthesis", prompt=synthesis_prompt)
Trap:
"Have the synthesis agent rerun the searches itself to get the data" is wrong - it duplicates work, violates separation of concerns, and discards the upstream agents' results. The coordinator carries the findings forward.
7. Structured Data to Preserve Attribution
When passing findings between agents, separate content from metadata using a structured format. Metadata = source URLs, document names, page numbers, publication dates.
If findings are flattened into prose, attribution is lost during synthesis (cross-ref D5.6 on provenance).
{
"claim": "Global solar capacity grew 24% in 2024.",
"evidence_excerpt": "...added 24% year-over-year...",
"source": {
"type": "web",
"url": "https://example.org/solar-2024",
"title": "Solar Capacity Report 2024",
"published": "2025-01-15"
}
}
{
"claim": "The methodology used a 5-year historical window.",
"evidence_excerpt": "We model on 2019–2023 data.",
"source": {
"type": "document",
"doc_name": "DCF_Model_Methodology.pdf",
"page": 7
}
}
| Why structured | Effect |
|---|---|
| Content separated from metadata | Synthesis agent can quote the claim and keep the citation |
| Survives the handoff | Attribution isn't compressed away |
| Enables conflict annotation | Conflicting stats keep their distinct sources |
The synthesis agent can only cite what arrives structured. Prose-only findings arrive citation-free.
8. Parallel Spawning: Multiple Task Calls In One Response
To run subagents in parallel, the coordinator emits multiple Task tool calls in a single response — the same way parallel tool use works. Spreading the calls across separate turns serializes them.
ONE coordinator response:
tool_use: Task(subagent="search", prompt="subtopic: solar")
tool_use: Task(subagent="search", prompt="subtopic: wind")
tool_use: Task(subagent="search", prompt="subtopic: geothermal")
↓ all three run concurrently; results return together
| Pattern | Result |
|---|---|
Multiple Task calls in one assistant response |
Parallel execution (correct for independent subtasks) |
One Task call per turn, across turns |
Serial execution (slower; only needed for dependent steps) |
Trap:
"Emit one Task call, wait for the result, then emit the next" is the serial anti-pattern when the subtasks are independent.
9. Decision / Heuristics Table
| Situation | Do this |
|---|---|
| Coordinator can't delegate at all | Add "Task" (or "Agent") to allowedTools |
| Subagent output is thin / off-target | First suspect: coordinator didn't pass enough context |
| Coordinator routes work to wrong specialist | Sharpen each AgentDefinition.description; scope tools |
| Synthesis agent needs prior findings | Inject complete findings into its prompt (don't make it re-fetch) |
| Need attribution to survive synthesis | Pass findings as structured content + metadata |
| Independent subtasks, want speed | Emit multiple Task calls in ONE response (parallel) |
| Dependent subtasks (A feeds B) | Sequence the Task calls across turns |
| Explore divergent approaches from shared analysis | fork_session from the baseline (D1.7) |
| Subagent over-using a tool outside its role | Remove that tool from its AgentDefinition.tools |
| Want adaptive, high-quality subagent work | Prompt with goals + criteria, not procedures |
10. Common Exam Anti-Patterns
| Anti-pattern | Why it's wrong | Better |
|---|---|---|
| Assuming subagents inherit coordinator history | No auto-inheritance — prompt is the only channel | Explicitly pass needed context |
Coordinator missing Task/Agent in allowedTools |
Delegation capability literally absent | Grant the delegation tool |
| Blaming the subagent for thin output | Usually a context-passing failure | Audit what the coordinator sent |
| Making synthesis re-run searches | Duplicates work; discards upstream results | Carry findings forward in the prompt |
| Passing findings as flat prose | Source URLs/pages/dates lost | Structured content + metadata |
One Task per turn for independent work |
Serializes parallelizable work | Batch Task calls in one response |
Vague AgentDefinition.description |
Coordinator misroutes | Precise "use when / not for" descriptions |
| Giving every subagent every tool | Cross-specialization misuse (D2.3) | Scope tools per role |
| Step-by-step procedural delegation prompts | Caps adaptability and quality | Goals + quality criteria |
Confusing fork_session with fan-out or --resume |
Different mechanisms | Fork = divergent branches from shared baseline (D1.7) |
11. Memory hooks
Task(a.k.a.Agent) is the spawn tool — it must be inallowedToolsor no delegation happens.- Nothing is inherited. The prompt is the only channel into a subagent.
- Thin subagent output? Suspect the coordinator's context passing first, not the subagent.
AgentDefinition= description (drives selection) + system prompt + tool restrictions.- Carry findings forward into the prompt — don't make the synthesis agent re-fetch.
- Structured content + metadata = attribution survives the handoff.
- Parallel = many
Taskcalls in ONE response; serial = one per turn (only for dependencies). fork_session= divergent branches from a shared baseline (≠ fan-out, ≠--resume; see D1.7).- Delegation prompts: goals + quality criteria, never step-by-step procedures.
- Repeated invocations of the same subagent are independent — re-inject prior output.