[Bug] Subagent spawn depth controlled by undocumented remote feature flag, can change without release
Environment
- CLI 2.1.247, macOS darwin-arm64, Max 20x, main loop Opus 5
What I found
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH controls how many levels of subagents can spawn beneath a subagent. Reading the resolution logic out of the 2.1.247 binary:
e = env.CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH; if (e !== undefined) return e;
...
t.maxSubagentSpawnDepthFromGrowthBook = getFeatureValue_CACHED_MAY_BE_STALE(
"tengu_hazel_trellis", Psn
);
...
var Psn = 3
So the order is: environment variable, then a remotely served GrowthBook feature flag (tengu_hazel_trellis), then a hardcoded fallback of 3.
Three consequences follow from that:
- The effective value can change without a release. It is a server-side flag, so it is not pinned to a version the user installed and does not appear in any changelog. This is consistent with what was observed from the outside: 2.1.217 behaved as depth 1, 2.1.219 behaved as depth 3. From here that reads like a version change. It may just as easily have been the flag moving.
- Nothing in the product shows the active value. There is no output in
/status,/context, or the session header stating how deep spawning is currently permitted. The value is read through a function whose own name saysCACHED_MAY_BE_STALE. - It is undocumented. No shipped documentation on this machine names the variable, and a search of this repo returns zero issues mentioning it. A user cannot look it up, and cannot discover it exists unless they read the binary.
Why it matters
Depth 3 means a subagent can spawn subagents that spawn subagents. A subagent is already invisible while it runs, and per #82104 there is no live spend readout and no per-agent cap, so a three-level tree is invisible work under invisible work with nothing bounding it. The combination is how 750k tokens land after a kill in that issue, and how the 1.37B tokens of agent re-reads in my comment there accumulate without anyone noticing.
An execution parameter that determines the branching factor of unattended, unmetered work is not a good candidate for a silent remote default.
Ask
- Show the resolved value. Print the active spawn depth wherever the session reports its configuration, along with where it came from: environment, remote flag, or fallback.
- Document the variable, including that a remote flag can override the fallback.
- Default to 1. Nesting should be opt-in. If depth 3 is intentional, say so somewhere the user can read.
- Log a line when the remote value differs from the fallback, so a change is at least observable after the fact.
Same reasoning applies to CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS, which is also environment-then-default and also undocumented.
Workaround
Set it explicitly, since the environment variable is checked first and wins over the flag:
{ "env": { "CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "1",
"CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS": "6" } }
That is the only way to know what the value is, because setting it is the only way to stop it being decided elsewhere.