aieveryminute

The env var sold as a 90% saving cost 8% more

CLAUDE_CODE_FORK_SUBAGENT is widely recommended for cutting parallel subagent costs. Across 28 runs it raised total context 38% on a cold session and 66% on a warm one, and cost 8% and 16%. Cache creation, the thing it is supposed to eliminate, moved 2 to 5%.

Yesterday this site measured that every parallel subagent re-pays for your configuration, taking the cost per agent from 20,398 tokens to 92,304 on a configured machine. The advice circulating for that problem is a single environment variable, CLAUDE_CODE_FORK_SUBAGENT=1, described as letting “parallel child agents share their parent’s prompt cache prefix, cutting input token costs by up to 90% for children 2-N”.

It is a real flag. It engages. And on both workloads measured here it made things more expensive.

Cells are medians of four runs.

Claude Code 2.1.227, 4 subagents Flag off Flag on Change
Cold session, total context 490,652 678,007 +38.2%
Cold session, cost $1.6626 $1.7975 +8.1%
Warm session, total context 539,261 892,774 +65.6%
Warm session, cost $1.9503 $2.2552 +15.6%

At four agents the arms do not merely differ on average, they do not overlap at all: every one of the four flag-on runs used more context and cost more than every one of the four flag-off runs, cold and warm alike. That separation, rather than any single percentage, is the claim worth carrying.

The number that explains it

The saving is supposed to come from children reusing the parent’s cached prefix instead of writing their own. If that happened, cache creation would fall. It did not.

4 subagents Cache creation Cache read
Cold, flag off 207,496 283,023
Cold, flag on 211,088 (+1.7%) 466,800 (+64.9%)
Warm, flag off 237,613 304,079
Warm, flag on 250,388 (+5.4%) 647,100 (+112.8%)

Creation moved 1.7% and 5.4%, both upward. About 97% of the extra tokens arrived as cache reads. That is the signature of children carrying more context, not of children skipping a prefix.

Which is what forking does. A forked child inherits the parent’s conversation so its request prefix stays byte-identical to the parent’s. The prefix is then cheap to read, and there is a great deal more of it. Cheap-per-token and fewer-tokens are different things, and only the second one reduces a bill.

Per agent, the flag makes fan-out worse

Taking the cold ladder at one agent and four gives the marginal cost of each additional agent:

Tokens per added agent
Flag unset 92,525
Flag explicitly off 92,618
Flag on 135,232

Turning the flag on raises the marginal cost per agent by 46%. The flag-off arm independently reproduces yesterday’s published 92,304 from a different session and a different harness, 0.24% apart, which is the strongest evidence here that the measurement is sound rather than an artefact of this rig.

Where the effect is not reliable, which matters

At one subagent the cost difference is inside the noise: flag-off runs spanned $0.7795 to $0.8161 and flag-on runs $0.8156 to $0.9017, so the two overlap and no cost claim is defensible there. Context still separates cleanly at one agent (213,243 highest off against 271,000 lowest on), but cost does not.

So the honest shape is that the cost penalty grows with the width of the fan-out, which is what the mechanism predicts: more children, more inherited history, more to re-read. One agent, no reliable cost difference. Four agents, +8.1% cold and +15.6% warm with no overlap.

Ranges matter here because the flag-on arm is the noisier one. Taking the worst and best pairings rather than the medians, the cold four-agent cost effect spans +6.7% to +10.6% and the warm one +1.0% to +25.6%. The medians are the best estimate; the separation is what is solid.

The warm case was tested because the claim depends on it

Every version of this advice is phrased around an established session: “a warm session with 100K tokens of history spawning 8 parallel forks”, “reuses the parent’s prompt cache”. A cold parent has no history to share, so testing only cold would have answered a question nobody asked.

So the warm arm builds real history first. The parent reads a 150KB file, a warm-up that itself billed between 284,678 and 616,512 tokens across its round trips, and only then is asked to fan out. That figure is what the warm-up cost, not how large the parent’s context ended up: modelUsage totals sum across API calls, so treating one as a context size would overstate it. Warmth is not assumed either: the file ends with a marker planted past the end of the payload, and the parent has to echo it back or the run is recorded unscored. All eight warm runs passed, and the per-run result is published.

Warming made the flag worse, not better. Cost went from +8.1% cold to +15.6% warm and context from +38.2% to +65.6%, because a warmer parent means more inherited history per child.

What this does not show

It does not show the flag can never save anything. These children need none of the parent’s context; they write four bytes each. The scenario where forking should win is one where you would otherwise paste the same large context into every child by hand, so the inherited history replaces work you were going to pay for anyway. That case is untested here, and it is the honest reading of the mechanism.

What the measurement does show is that the advice as circulated carries no such condition. “Cutting input token costs by up to 90%” is offered as a setting to switch on. On the two workloads measured, it was an 8% and a 16% increase.

One machine, one workload shape. Absolute figures depend on the configuration loaded; the flag-off arm here carries a real user-level config, which is the situation the flag is pitched at. The percentages are the transferable part.

Two details worth having, both read from the shipped binary

The gate that decides whether forking is active, in 2.1.227:

if (coordinatorMode())                 return "disabled";
if (truthy(CLAUDE_CODE_FORK_SUBAGENT)) return "env";
if (falsy(CLAUDE_CODE_FORK_SUBAGENT))  return "disabled";
if (!isInteractive())                  return "disabled";
if (rolloutEnabled())                  return "gb_rollout";
return "disabled";

The explicit env opt-in is checked before the interactive test, so at least one write-up claiming the flag is “incompatible with print mode” is wrong: print mode only blocks the gradual rollout, not an explicit =1. That is what made this measurable with claude -p at all.

And =0 is not equivalent to leaving it unset in general. Unset falls through to the rollout check, so a server-side rollout could switch forking on without you changing anything; an explicit 0 returns disabled before that check and pins it off. Here the two arms tracked each other closely: 0.07% apart on total context at four agents, 0.10% on tokens per added agent, and 0.44% at the widest, on single-agent cost. Note the 0 arm is two runs against the others’ four. That says the rollout was not active on this machine at this time, and it is also why the 0 arm is a control on the harness rather than filler: a difference of tenths of a percent between two ways of switching the flag off, against 38% and 46% when it is switched on, shows the effect is the flag and not drift.

Controls. Arrival control 28 of 28: every run had to leave exactly N files on disk, and files_created is published per run so the check is verifiable rather than asserted. Warmth control 8 of 8 on the warm arm, also recorded per run. Tokens come from modelUsage, which counts subagent usage where .usage does not, and are reported split rather than summed, because summing creation and read into one number would have hidden the entire effect.

Every run is published in fork-subagent-cost.json.

POSTaieveryminute.com#context-costbuilt 2026-08-31 17:47 UTC