Skip to content

AI CODING ASSISTANTS

Claude Code Nested Subagents: The Tool That Vanishes

Claude Code nested subagents stop at depth three — but not by refusing. We ran a relay chain and found the Agent tool simply missing from the deepest agent.

Claude Code nested subagents work, they stop at three levels deep, and the stop is not the error you would expect. We built a relay agent that delegates to a copy of itself and watched the chain die at depth three — not with the Subagent nesting limit reached refusal that sits in the binary, but with the deepest agent reporting that the Agent tool was not in its function list at all. The refused.depth_limit counter stayed at zero for the whole run. This guide shows the chain, the cap, and the two behaviours that surprised us. Measured 2026-09-13 on Claude Code 2.1.270, Windows 11, Node 26.7.0.

Key takeaways

  • The nesting cap is 3 by default and CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH overrides it.
  • The cap is enforced by removing the Agent tool from an agent that has reached it. There is no refusal to catch.
  • refused.depth_limit read 0 in both runs, including the one that hit the ceiling.
  • A nested Agent call runs in the background whether or not you ask: the parent turn ended in 2,113 ms while the chain ran for 33,622 ms.
  • Depth lives in a .meta.json file per agent. The transcript directory itself is flat.

What Claude Code nested subagents are

A nested subagent is a subagent launched by another subagent rather than by your session. The mechanism is the same Agent tool described in the complete guide — the only difference is who calls it. Agents spawning agents is not a separate feature with its own configuration; it is the ordinary delegation path used one level down.

Two things gate it. An agent can only nest if its definition grants the Agent tool, and the built-in read-only agents do not: Explore and Plan both exclude it, which is why the Explore subagent can search a repository but cannot hand off. And there is a depth cap, which is what this article is about.

.claude/agents/relay.md
---
name: relay
description: Relays a countdown by delegating to another relay agent.
tools: Agent, Write
model: haiku
---

That tools line is the whole opt-in. Give an agent Agent and it can delegate; leave it out and it cannot.

The relay chain we built

We needed a chain that stops on its own so the ceiling would be visible. The relay agent reads an N= value from its prompt, delegates to another relay with N minus one, and answers BOTTOM at zero. Crucially, it is told never to work around a refusal — if the Agent tool errors, it must report the error text verbatim and stop.

It lives in a throwaway directory rather than in a real project. Nothing we ship carries Agent, and a self-spawning agent is not a definition worth committing for one measurement.

Then one session, one prompt, and the JSON output format so the counters come back:

Terminal
claude -p --output-format json --model sonnet \
  "Use the Agent tool with subagent_type \"relay\" and this exact prompt:
   'N=3 — you are a relay in a chain; follow your agent instructions exactly.'"

The run took 33,622 ms of wall clock, cost $0.1352, and returned this:

subagent_stats
{
  "spawned": 3,
  "requested": { "background": 0, "foreground": 1, "unset": 2 },
  "started_in_background": 2,
  "max_depth": 3,
  "spawned_by_subagents": 2,
  "completed": 3,
  "failed": 0,
  "refused": { "depth_limit": 0, "concurrency_limit": 0, "budget": 0 }
}

Three agents, two of them launched by other agents, three completed, nothing failed and nothing refused. Read on its own, that is a chain that ran to the bottom.

Where the chain stopped

It did not run to the bottom. completed counts an agent that finished its turn, and the third one finished by giving up. Its transcript ends with a single message:

Depth-3 agent, final message
REFUSED: Agent tool not found in available functions. Only the Write tool
is available to me. I cannot complete the relay operation as specified in
the instructions.

The relay definition grants Agent, Write. At depth three the agent was handed Write and nothing else. It did not hit a limit; it looked for the tool and the tool was not there.

The cap is a missing tool, not a refusal

To confirm the mechanism rather than the coincidence, we re-ran the identical prompt with the cap lowered:

Terminal
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1 claude -p --output-format json --model sonnet "…"
CapAgents spawnedSpawned by agentsmax_depthrefused.depth_limit
3 (default)3230
11010

At a cap of one, the first agent reported the same thing the third one had: "the Agent tool is not available in my function set. Only the Write tool is available to me." Same definition, same prompt, different tool list. The rule is that an agent standing at the cap is not offered the tool, and the position of the ceiling is the only thing the environment variable moves.

Claude Code does carry a proper refusal for this. It reads Subagent nesting limit reached (depth N of M). Complete this task directly using your tools instead of spawning another agent. We never saw it, and neither counter moved off zero, because withholding the tool happens first. That also explains the note our subagents guide quoted from the binary — that depth_limit stays near zero in practice. It stays at zero because it is the second line of defence and the first one never lets anything through.

The cap itself is a feature flag with a fallback constant of 3 compiled in, and the environment variable short-circuits both. Anthropic's subagent documentation describes the tools field that grants delegation; the depth behaviour is not documented, which is the gap this measurement fills.

Agents spawning agents run in the background

The second surprise is about time rather than depth. Our top-level Agent call passed run_in_background: false and behaved: the meta file records requestShape: "foreground". Neither nested call passed the option at all, and both came back "background".

DepthRequestedActual shapeAgent tool present
1foregroundforegroundYes
2unsetbackgroundYes
3unsetbackgroundNo

The tool result the nested callers received says so plainly — "Async agent launched successfully… The agent is working in the background. You will be notified automatically when it completes." The consequence is the number that matters: the launching session finished its turn in 2,113 ms and gave its final answer, while the chain it had started ran for another half-minute. The chain's outcome arrived afterwards, as task notifications, addressed to a session that had already stopped.

This is the same lifetime trap documented in background tasks wearing different clothes. There, a backgrounded command died with its session. Here, a nested agent outlives the answer you were given.

Reading the tree after the fact

Every agent in the run gets two files, and they all land in one folder:

<session id>/subagents/
agent-a6ca09801ea9c55af.jsonl        depth 1
agent-a6ca09801ea9c55af.meta.json
agent-a5226f52058d1e174.jsonl        depth 2
agent-a5226f52058d1e174.meta.json
agent-aa36daacbe6d20dd3.jsonl        depth 3
agent-aa36daacbe6d20dd3.meta.json

The directory is flat — nesting is not reflected in the layout at all. The tree is in the meta files:

agent-aa36daacbe6d20dd3.meta.json
{
  "agentType": "relay",
  "description": "Relay chain N=1",
  "parentAgentId": "a5226f52058d1e174",
  "spawnDepth": 3,
  "requestShape": "background"
}

spawnDepth and parentAgentId are the only record of who launched whom. If you want to know what a chain actually did — as opposed to how many agents it contained — sort the meta files by spawnDepth and read the transcripts in that order. The session directory these live under is the one mapped in where Claude Code stores history.

When nesting is worth it

Rarely, and the reason is arithmetic rather than principle. Every level adds a full context window, a system prompt and a startup cost, and our subagent cost measurements already found no reliable saving at one level. A second level pays the same toll again for an agent that cannot talk to you and whose answer reaches your session as a notification.

Nesting earns its keep in one shape: a coordinating agent that fans out — one agent that receives a large job, splits it, and dispatches several workers. That is delegation as a tree rather than a chain, and it is what dynamic workflows and agent teams both formalise, with the same caution: measure it against the session simply doing the work.

For a chain — A asks B, which asks C, for one answer — nesting buys nothing. Each link adds latency and a paraphrase, and the depth-three agent in our run never got to contribute at all.

What did not work

The raise-the-cap arm was never run. We intended a third arm at CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=5 to check whether a fourth level behaves like the first three. This machine's auto-mode classifier refused the command, and rather than route around a permission decision we are publishing the gap: everything here is measured at caps of 3 and 1, and the behaviour above 3 is untested.

The documented refusal was never triggered. The string exists, the counter exists, and we could not make either fire. It is possible some path reaches it; nothing in an ordinary nested run does.

Our first reading of the counters was wrong. max_depth: 3, completed: 3, failed: 0 reads as success, and the first draft of this article said the chain ran to the bottom. Only the third agent's transcript says otherwise. The counters describe how many agents ran, never whether any of them got anywhere.

Best practices

  • Grant Agent deliberately. An agent definition that lists it can start a tree you did not plan. Most agents should not have it.
  • Assume a nested agent is asynchronous. It will be, whatever the caller passes, so never design a nested step whose result the parent needs in the same turn.
  • Read spawnDepth, not the counters, when you want to know what a run did. spawned and completed cannot tell you a chain stopped early.
  • Keep the cap where it is. Three is already deeper than most work justifies, and raising it multiplies context cost without adding an accountable step.
  • Write the depth into the prompt if a chain must self-limit. The tool disappearing is not an error the agent can plan around; a countdown is.
  • Prefer one level and several workers to three levels and one worker. Width is measurable; depth mostly is not.

Common mistakes

Expecting an error when the limit is hit. There is none. The tool is absent and the agent improvises — ours reported the absence because we told it to, but an agent with no such instruction will quietly do something else instead.

Giving Explore or Plan a delegation job. Neither carries Agent, so neither can nest at any depth. The failure looks like the model ignoring your instruction.

Trusting completed as a success count. It counts turns that ended. The agent that refused is in that number.

Reading the parent's final answer as the chain's result. The parent answers when its own turn ends. In our run that was 31 seconds before the chain finished, and the real outcome arrived as a notification afterwards.

Nesting to save context. Each level is a fresh window with a fresh system prompt. Three levels do not split one budget three ways; they open three budgets.

Conclusion

Use nested subagents when one agent genuinely needs to fan work out, and stop at that single extra level — the default cap of three is already past the point where a chain earns its cost. The measurement to carry away is the mechanism: the ceiling is enforced by taking the Agent tool away, silently, from the agent standing on it, so nothing in your counters or your logs will announce that a chain stopped early. If you are running nested agents today, sort the subagents/ meta files by spawnDepth and read the deepest transcript. It is the only place the truth is written down.

Frequently asked questions

Can Claude Code subagents spawn their own subagents?
Yes, as long as the agent definition lists the Agent tool and the agent is not already at the nesting cap. We ran a relay agent that delegated to a copy of itself and got a three-deep chain: the session spawned one agent, which spawned a second, which spawned a third. The third could not continue, and the run recorded max_depth 3.
What is the Claude Code subagent depth limit?
Three by default on Claude Code 2.1.270. The value comes from a feature flag with a fallback constant of 3 in the binary, and CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH overrides both. We confirmed the knob works by lowering it to 1, which stopped the same chain after a single agent.
What happens when a subagent hits the nesting limit?
Nothing you can catch. The agent at the cap is not given the Agent tool at all, so there is no call to refuse. Ours reported the tool was not in its available functions and stopped. The binary carries a Subagent nesting limit reached error string, but it never appeared and the refused.depth_limit counter stayed at zero in both runs.
Do nested subagents run in the background?
By default, yes. Our top-level call passed run_in_background false and ran in the foreground. Neither nested call passed the option at all, and both started in the background: the launching session finished its turn in 2.1 seconds while the chain it started kept running for 33.6 seconds.
Where can I see the nesting tree after a run?
In the session's subagents directory. Every agent gets one JSONL transcript and one meta file, all in the same flat folder regardless of depth. The meta file carries spawnDepth and parentAgentId, which are the only record of which agent launched which.

Muhammad Kashif

Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.