Claude Code Subagents Can Now Spawn Subagents
In Claude Code, a subagent can spawn its own subagents. This landed in v2.1.172.
To see why that matters, you have to look at what wasn't possible before. I maintain (see "Spawn nested subagents" and "Session subagent limit")
2. Moving the orchestrator from Main Claude into an agent
Before — orchestration scattered across the terminal session
Back when nesting wasn't possible, the structure looked like this:
Main Claude ──spawn──> specifier → returns dispatch XML
Main Claude ──spawn──> planner → returns dispatch XML
Main Claude ──spawn──> scheduler → returns XML saying "builder is next"
Main Claude ──spawn──> builder → ...
Main Claude ──spawn──> verifier → ...
Main Claude ──spawn──> committer → ...
There was an agent called scheduler that did no LLM work of its own. It read the DAG and returned XML naming what to call next; the actual spawn was always done by Main Claude. Because nesting was impossible, the coordinator couldn't coordinate — it could only write coordination memos.
The consequences:
- Approval gates, context hand-off, and resume logic were all scattered across Main Claude (the terminal session)
- Every stage transition passed through Main's context — at least 3N round trips for N TASKs
- We observed trigger failures where the pipeline stalled after specifier (a row in the WORK list, but no WORK folder)
After — a single orchestrator agent
With nesting from v2.1.172, the structure became:
[WORK] tagged message
│
▼ (work-pipeline SKILL)
Main Claude ── spawns orchestrator once (raw request + REFERENCES_DIR + mode=gated|auto)
(handles gates) │ depth 1
▼
orchestrator ← flow control + TASK DAG scheduling + autonomous decisions + logging
│ nested spawn (depth 2)
┌──────────────────┼──────────────────────────────┐
▼ ▼ ▼
specifier → planner → [per TASK] builder → verifier → committer
(creates WORK) (PLAN+DAG) (DAG READY order, builder retried ≤3 on FAIL)
│
▼
Final WORK summary + list of auto-decisions returned to Main Claude
Three core principles:
The orchestrator is a coordinator. Heavy reasoning (requirements, design, implementation) is delegated by nest-spawning the existing agents. The orchestrator itself only schedules, mediates decisions, and logs.
schedulerwas deleted. It was pure coordination with no LLM work of its own, so the DAG logic was absorbed inline into the orchestrator.- Main Claude spawns nothing but the orchestrator.
How approval gates work
Because of the constraint from section 1 — nested subagents can't ask the user — gates are built on a yield model.
At a gate, the orchestrator returns an XML signal and stops (parks):
<gate type="stage" work="WORK-01" stage="specifier">
<summary>Requirement spec complete — 5 FRs, 2 NFRs</summary>
</gate>
There are two kinds of gate:
type="stage"— fixed gates: after specifier (GATE-1) and after planner (GATE-2)
type="decision"— dynamic escalation. Whenever the orchestrator or a child judges that the user has to decide something, it emits background + options + a recommendation, at any point in the run
Main Claude relays the signal, asks the user, and on approval resumes the parked orchestrator with SendMessage, preserving its context. If the handle is gone (session ended, say), it spawns a fresh orchestrator reconstructed from the activity log and DECISIONS.md on disk. Disk is always the source of truth; the parked agent handle is just an optimization.
In mode=auto (triggered when the request says "auto"), there are no gate stops: the orchestrator runs to completion in a single spawn, resolving every judgment call with its recommended option and recording each one in DECISIONS.md and the final report's auto-decisions section.
What got better
① Round trips disappeared. Six stages × N TASKs collapsed into one Main Claude spawn. Intermediate output — build logs, file contents, verification output — never reaches Main's context at all.
② Reference docs are read once. This was the unexpected win. Previously all six agents each read 5–8 reference files from disk. Now the orchestrator reads them once and slices them against the section consumption matrix at the top of each reference file, shipping the slices to each child's prompt as a <ref-cache>. Children never touch disk.
| Section | orchestrator | specifier | planner | builder | verifier | committer |
|---------|:---:|:---:|:---:|:---:|:---:|:---:|
| § 1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| § 6 | ✅ | | | ✅ | ✅ | ✅ |
...
This only works because the orchestrator assembles child prompts directly. When Main Claude did the spawning, there was no single place to enforce the distribution.
③ DAG parallelism got easy. When several TASKs are READY, the orchestrator issues multiple builder spawns in the same turn. Going through Main Claude would have chopped that at every user-turn boundary.
④ Logging has one owner. STAGE_START is written right before spawning a child; STAGE_DONE is written after the gate clears, when a gate exists. That ordering is what stops a cross-session resume from skipping an unapproved gate. Children write no logs at all and return pure artifacts.
What got worse
① Observability drops. Most of the execution happens inside the subagent tree, so all you see in the terminal is the orchestrator's summary. You have to build observability yourself, through log design.
② The user-interaction path got complicated. One gate now takes: return <gate> XML → yield → Main asks the user → resume via SendMessage → (on failure) fall back to a log-based re-spawn.
③ Context management is binary. Subagents only support auto-compaction. No manual /clear, no /compact, no partial clearing. Your options are "keep context = SendMessage" or "reset = TaskStop + re-spawn". There is no middle.
④ You're coupled to runtime policy. The whole architecture rests on one runtime behavior: that subagents receive the Agent tool. That isn't my code. (→ section 5)
3. Why do it anyway
That's not a short list of downsides. I still wouldn't go back. Two reasons.
3-1. The unit of delegation becomes the whole pipeline, not a stage
This is the essence. Before nested spawn, you could delegate one stage of work to a subagent. Now you can delegate the entire pipeline. What follows from that:
① It doesn't break at user-turn boundaries. In the old structure, the pipeline advanced only as long as Main Claude remembered to call the next agent. That's exactly why we saw stalls after specifier. Now the orchestrator loops inside itself. Throw one [WORK] at it and it runs to the end.
② Main's context stays empty. While the pipeline runs, only the final summary enters Main Claude's context. No build logs, no verification output, no file contents. A long WORK doesn't pollute your main conversation.
③ Unattended execution becomes natural. Because the delegation unit is the whole pipeline, one claude -p call takes you from requirement to commit. Queue requirements at night, review in the morning. You can't do that with stage-level delegation — Main has to intervene at every step.
④ Retry and resume become an internal loop. When verifier returns FAIL, the orchestrator re-dispatches builder (up to 3 times). None of it surfaces to the user. That retry judgment used to live in Main Claude, which made it depend on the mood of the session's conversation.
Weighed against the downsides:
| Downside | What it really is | Offset |
|---|---|---|
| Lower observability | One-time implementation cost | The activity log became canonical, which gave us cross-session resume and an audit trail. Structured logs beat terminal scrollback |
| Complex interaction path | One-time implementation cost | Gates went from "Main asks if it feels like it" to an explicit protocol. Where execution stops is now fixed in code |
| Binary context management | Standing constraint | In practice, lifetimes are per-WORK, so partial clearing almost never came up |
| Runtime coupling | Standing risk | Absorbed by capability probing + degraded mode (→ section 5) |
Most of the downsides are costs you pay once; the benefits are collected on every WORK. That asymmetry is the answer. Three of the four downsides above are already closed in code; all four benefits still show up every run.
3-2. So what about dynamic workflows?
There's an obvious question here. Claude Code already has . The sub-agents page's line about depth 5 being "fixed and not configurable" also looks like it predates the 2.1.217 change. All I can state firmly is the changelog line and the behavior I observed.
The symptom: not an error, but a quiet success
This was the core of the problem. When nested spawn was blocked, the orchestrator did not fail.
Starting up without Agent in its tool list, unable to call any children, it did everything itself. Analyzed the requirement, wrote the plan, wrote the code, verified it, committed, and reported success.
Judging by artifacts alone, everything is fine. There's a WORK folder, a Requirement.md, a commit. In reality:
Role separation was gone — whoever implemented it also verified it
Verification independence was gone — the entire reason verifier exists evaporated
Context isolation was gone — six isolated context windows collapsed into one
Failing silently is the worst failure mode. Had the pipeline crashed I'd have known immediately; instead it reported success and I didn't notice for a while.
Fix ①: pin the version
The immediate remedy is simple. I dropped back to 2.1.216. Unblocking it with the environment variable (CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH) is an option too, but for something shipped as a plugin / npm package, "an architecture that depends on the user's environment variables" is the worse choice.
Fix ②: capability probing + degraded mode
Pinning a version only saves my machine. I can't control users' environments, so the pipeline itself has to detect this and survive it.
So I added STEP 0 to the orchestrator: a capability check that runs before anything else, before reading a single file.
#### STEP 0. Capability check — is nested spawn available? (highest priority)
**Do this before anything else. Decide before reading any file.**
Check whether the `Agent` tool is present in your own tool list.
| Result | Action |
|--------|--------|
| `Agent` present | Normal path — proceed to STEP 1 |
| `Agent` absent | **Degraded** — follow the procedure below |
When it decides "degraded", the orchestrator does nothing. And "nothing" is enforced strictly:
- Perform no work inline — standing in for a child role is forbidden
Read no files — not even the references. Never callRead/Glob/Grep, not once- Create no artifacts — no WORK folder, no
Requirement.md, no activity log
As the very first response, return the following and terminate immediately
<capability-degraded reason="no-agent-tool">
<detail>Agent tool not injected into subagent; nested spawn unavailable</detail>
</capability-degraded>
The prompt even carries this note: "The block above is everything you need to return. Do not read xml-schema.md to check the format." LLMs have a habit of opening files to confirm the rules, so without an explicit prohibition, "read no files" doesn't hold.
Then Main Claude takes over the orchestrator role.
[normal] [degraded]
Main Claude (0) Main Claude (0) ← also acts as orchestrator
└─ orchestrator (1) ├─ specifier (1)
├─ specifier (2) ├─ planner (1)
├─ planner (2) └─ builder / verifier / committer (1)
└─ builder… (2)
One design decision matters here. I did not write a separate procedure for degraded mode. Main Claude simply reads orchestrator.md and executes the procedure written there. There is one canonical copy. The moment you maintain two orchestration procedures, they drift.
Exactly three things differ from the normal path:
| Item | Normal | Degraded |
|---|---|---|
| Child spawn depth | 2 (orchestrator spawns) | 1 (Main Claude spawns directly) |
| Gate handling | Orchestrator returns <gate> and yields → Main asks the user | Main asks the user directly — no <gate> XML, SendMessage, or TaskStop needed |
| Who reads the references | Orchestrator | Main Claude |
Artifact formats, log event schema, <ref-cache> assembly rules, and resume logic are all identical. The activity log records ORCHESTRATOR_DEGRADED — reason=no-agent-tool once, right after ORCHESTRATOR_START, so the log alone tells you which mode a run used.
And even in degraded mode, standing in for a child role is still forbidden. If Main Claude writes code or commits directly, role separation disappears exactly as it did when nesting was blocked. Only the depth drops to 1; the six-agent pipeline runs unchanged.
So the "standing risk" I filed under runtime coupling in section 3 turned into a fixed cost. If nesting works, it runs at depth 2; if not, depth 1. Either way, the six roles stay separated.
What I took away
① Don't assume runtime capabilities — probe for them. Agent architectures rest on assumptions about which tools exist. A single minor release can flip one. Capability checks have to run first, before any side effects. If you decide after reading even one file, you're already late.
② The failure mode of an LLM pipeline isn't a crash — it's a plausible completion. Take away a tool and the agent doesn't stop. It muddles through alone and tells you it succeeded. Where normal software would have died on a null reference, the problem with an LLM is that it doesn't die. That's why "do not stand in for a role" has to be an explicit prohibition in the prompt.
③ The degraded path needs the same single source of truth. The temptation to write a separate fallback procedure is strong, but two copies will drift. Design it as "same procedure, different executor" and you keep one place to maintain.
④ If disk is the source of truth, most things recover. Session dropped, handle lost, fell into degraded mode — with the activity log and DECISIONS.md, the run resumes at exactly the right point. The parked agent handle is only ever an optimization.
Wrapping up
Nested subagent spawn genuinely changes how you design a multi-agent pipeline. The unit of delegation rises from a stage to the whole pipeline, and the moment it does, unattended execution, context isolation, and internal retries all follow.
In exchange, you design observability and interaction yourself, and you're exposed to runtime policy changes. One flipped default in 2.1.217 demonstrated that exposure.
Use nested spawn — but design what happens when it isn't there first. And hand the parts that need volume and determinism to — installable as a Claude Code plugin or via npm (uctm).
SOCIAL SHARE CARD GENERATOR