Subagent orchestration is the architectural pattern where one agent, the orchestrator or lead agent, breaks a task into pieces and dispatches each piece to a separate agent instance running its own isolated context, its own tool access, and its own reasoning trajectory, then gathers and synthesizes what comes back. It’s the mechanism underneath Claude Code’s Agent tool, Anthropic’s published multi-agent research system, and most production frameworks that spin up “workers” under a “supervisor.” The pattern answers a specific problem that a single, ever-growing conversation runs into: some tasks are too broad, too parallel, or too token-hungry to fit inside one agent’s context window without that context degrading, the same failure mode covered in Context Rot.
Orchestrator-Worker, Not Peer-to-Peer
Subagent orchestration is a specific shape of multi-agent system, and it’s worth being precise about which shape. In a swarm (Swarm Architecture), control passes laterally between peer agents via handoffs, no agent is permanently “in charge.” In subagent orchestration, control is hierarchical: a lead agent stays in charge of the overall task throughout, subagents are dispatched, complete their scoped piece, report back, and typically terminate, they don’t hand control onward to each other. The lead agent, not any subagent, decides what happens next.
flowchart TB
classDef default fill:#ffffff,stroke:#4338CA,stroke-width:2px,color:#0F172A,rx:8px,ry:8px;
classDef data fill:#EEF0F7,stroke:#0D9488,stroke-width:2px,color:#0F172A,rx:8px,ry:8px;
classDef process fill:#F7F8FC,stroke:#6366F1,stroke-width:2px,color:#0F172A,rx:8px,ry:8px;
classDef output fill:#4338CA,stroke:#4338CA,stroke-width:2px,color:#ffffff,rx:8px,ry:8px;
U([User task]):::data --> O[Orchestrator / lead agent<br/>plans and decomposes]:::process
O -->|scoped task A| S1[Subagent A<br/>fresh, isolated context]:::output
O -->|scoped task B| S2[Subagent B<br/>fresh, isolated context]:::output
O -->|scoped task C| S3[Subagent C<br/>fresh, isolated context]:::output
S1 -->|summary, not transcript| O
S2 -->|summary, not transcript| O
S3 -->|summary, not transcript| O
O --> R[Synthesized result]:::data
The detail that makes this work rather than just relocating the context problem is what gets returned: a subagent’s summary, not its full working transcript. A subagent might read forty files, run a dozen searches, or make several failed attempts before succeeding, all of that stays inside the subagent’s own context and is discarded when it finishes; only the distilled result crosses back to the orchestrator. This is the core mechanism that keeps the orchestrator’s own context small no matter how much work happened underneath it.
Context Isolation Is the Point, Not a Side Effect
A subagent doesn’t start with a copy of the orchestrator’s conversation. In Claude Code’s implementation, a freshly spawned subagent gets its own system prompt, the task description it was given, relevant project files, and a scoped tool list, but explicitly not the orchestrator’s conversation history, memory, or previously used skills. That isolation is deliberate: if every subagent silently inherited the full parent context, spawning subagents would multiply the very token growth and context rot pressure orchestration exists to avoid, rather than relieving it.
# Scenario: give a subagent read-only access for an audit task, denying
# it any ability to modify code, regardless of what tools the orchestrator
# itself has available
subagent_config = {
"name": "security-auditor",
"tools": ["Read", "Grep", "Glob"], # explicit allowlist
"disallowedTools": ["Write", "Edit", "Bash"],
"model": "opus",
"description": "Read-only review for injection and auth vulnerabilities",
}
# The orchestrator can hold write access while a spawned auditor cannot,
# even though both are, at the API level, calls to the same underlying model.
Tool scoping like this does double duty: it keeps a subagent’s blast radius contained (an auditor can’t accidentally patch the code it’s reviewing), and it keeps the subagent’s own reasoning focused, since a smaller, task-relevant tool list gives the model fewer irrelevant options to consider at each step, mirroring the same “narrow the surface area” argument covered in Agent Harness.
When Parallelism Helps, and When It Just Adds Overhead
Anthropic’s own published account of building its multi-agent research system is unusually specific about where this pays off and where it doesn’t. Multi-agent orchestration, with a lead agent spinning up three to five subagents in parallel, outperformed a single agent by 90.2% on their internal research evaluation, but consumed roughly 15x the tokens of a single chat interaction to get there, against a lead agent’s overall research task showing token usage alone explains about 80% of the variance in outcome quality.
The determining factor for whether that trade is worth making is whether the subtasks are actually independent. Breadth-first tasks, “research these four competitors,” “check these ten files for a specific bug pattern,” parallelize cleanly because no subagent needs another’s output to do its job. Tasks with real dependencies, most software engineering work included, don’t: if subagent B needs subagent A’s findings before it can start, dispatching them in parallel doesn’t produce a speedup, it produces expensive serial execution with orchestration overhead layered on top, since B ends up waiting for A anyway while both burn separate context and token budgets doing it.
Interactive: Parallelism vs. Task Structure
The widget below models that trade-off directly. Increase the number of parallel subagents and switch between an independent (breadth-first) task and an interdependent (sequential) one to see why the same parallelism knob produces opposite outcomes depending on task shape:
In independent mode, adding subagents drives completion time down fast at first, then flattens out, real parallel speedup with diminishing returns. Switch to interdependent mode at the same subagent count and completion time stops improving, or gets slightly worse, while token cost keeps climbing regardless of mode, since every subagent burns its own context whether or not its work could actually run in parallel. This is the concrete shape of Anthropic’s warning that parallelism only helps when subtasks are truly independent.
Aggregation Is Where Orchestration Can Quietly Fail
The failure mode that’s easy to miss isn’t in the subagents, it’s in the orchestrator afterward. If an orchestrator dispatches ten subagents and each returns a lengthy, unsummarized report, the orchestrator’s own context balloons right back up trying to synthesize all of them, reintroducing the exact context rot risk the pattern was meant to avoid, just moved one level up the stack. Well-designed orchestration prompts subagents explicitly for a structured, bounded summary rather than raw findings, precisely to keep this aggregation step cheap.
# Scenario: forcing subagents to return a bounded, structured result
# instead of an open-ended report the orchestrator would have to
# re-digest, which just relocates the context problem upward
SUBAGENT_RETURN_CONTRACT = """
Return your findings as:
1. One-paragraph summary (≤150 words)
2. Up to 5 bullet points of supporting detail
3. Confidence: high / medium / low
Do not include your intermediate search steps or raw tool output.
"""
Orchestration Patterns Compared
| Pattern | Control flow | Best fit |
|---|---|---|
| Subagent orchestration (Claude Code, Anthropic research system) | Hierarchical: lead dispatches, subagents report back and terminate | Breadth-first research, parallel audits, large independent workstreams |
| Swarm / handoff (Swarm Architecture) | Lateral: any agent can transfer control to another | Triage-and-route workflows (support, booking) with clear ownership transitions |
| Graph state machine (LangGraph-style) | Explicit graph of nodes and edges, state passed along fixed paths | Mission-critical workflows needing checkpoints and guaranteed execution paths |
| Conversational multi-agent (AutoGen-style) | Agents “chat” with each other in a shared thread | Open-ended debate, brainstorming, simulation |
What’s New (2025-2026)
- Background and foreground subagents as a first-class distinction. Modern harnesses distinguish subagents that block the main conversation (foreground) from ones that run concurrently while the orchestrator keeps working (background), with concurrency limits (Claude Code defaults to 20 concurrent subagents, configurable) to keep runaway fan-out in check.
- Forking as a cheaper middle ground. Alongside fresh-context subagents, 2026-era harnesses added “fork” modes that inherit the full parent conversation but keep their own tool calls isolated, trading the clean-separation benefit of a fresh subagent for lower latency and reuse of the prompt cache, useful when a subtask genuinely needs the orchestrator’s accumulated context.
- Dynamic, code-defined orchestration. Rather than the orchestrator deciding subagent counts turn-by-turn in natural language, 2026 tooling increasingly lets a script explicitly define fan-out at scale, spawning dozens of subagents with programmatic control over batching and aggregation, closer to a distributed job scheduler than a chat loop.
- Depth-limited recursive spawning. Since subagents can themselves spawn subagents, harnesses now cap nesting depth (commonly three layers) to prevent uncontrolled recursive fan-out, and withhold spawning ability once that depth is reached.
- Standardizing cross-vendor coordination. Where subagent orchestration governs coordination within one harness, the Agent2Agent Protocol has emerged as a parallel effort to standardize how independently-built agents from different vendors discover and delegate to each other, the inter-organization analog of the intra-harness pattern described here.
Practical Guidance
| Situation | Recommendation |
|---|---|
| Task splits into genuinely independent pieces | Fan out to parallel subagents; expect real speedup and accept the higher token cost |
| Task has sequential dependencies (B needs A’s output) | Don’t parallelize; run sequentially in one context, or pass A’s summary explicitly into B’s task prompt |
| Subagent might need write access | Scope tools explicitly (tools: allowlist or disallowedTools: denylist); don’t grant broader access than the subtask needs |
| Orchestrating many subagents (5+) | Enforce a structured return format so the orchestrator’s own context doesn’t balloon during synthesis |
| A subtask needs the orchestrator’s full conversation history | Consider a fork instead of a fresh subagent, rather than trying to replay history into a fresh context |
| Cost-sensitive workload | Default to a single agent; reserve orchestration for tasks where the accuracy or time gain clearly outweighs the token multiplier |
Subagent orchestration trades tokens for two things a single long-running agent can’t reliably provide: true parallelism on independent work, and a hard boundary that keeps any one subtask’s mess out of the context everything else depends on. Used on genuinely independent, parallelizable work it earns that cost back in accuracy and wall-clock time; used on sequential work, it’s just a more expensive way to run the same steps one at a time.
How to Use: fanning out independent research subtasks to parallel subagents
# Scenario: "compare the pricing, feature set, and security posture of
# four competitor products": three independent research threads that
# would otherwise blow out a single agent's context window if done
# serially in one long-running chat.
from concurrent.futures import ThreadPoolExecutor, as_completed
def spawn_subagent(task_prompt: str, tools: list[str], model: str = "sonnet") -> str:
# Each call gets a FRESH context: no chat history, no sibling
# subagent's findings, just the task prompt and its own tool set.
agent = Orchestrator.new_agent(system_prompt=task_prompt, tools=tools, model=model)
return agent.run_to_completion()
def orchestrate(competitors: list[str]) -> str:
tasks = {
name: f"Research {name}'s pricing, features, and security posture. "
f"Return a structured summary, not raw notes."
for name in competitors
}
results = {}
with ThreadPoolExecutor(max_workers=len(tasks)) as pool: # parallel, not serial
futures = {pool.submit(spawn_subagent, prompt, ["WebSearch", "WebFetch"]): name
for name, prompt in tasks.items()}
for future in as_completed(futures):
results[futures[future]] = future.result()
# The lead agent's context only ever holds four summaries,
# never the raw research trail each subagent generated to get there.
synthesis_prompt = "\n\n".join(f"## {k}\n{v}" for k, v in results.items())
return lead_agent.generate(f"Synthesize a comparison:\n{synthesis_prompt}")
Ready to build?
Leverage AI technologies to build your product stack
Superteams can help you build, deploy and launch AI application stacks using open source technologies — from architecture through to production.
Talk to Superteams