DEV Community

Rulestack
Rulestack

Posted on Edited on

Claude Code fork vs subagent: what /fork, /subtask, and subagent_type: "fork" each copy

If you have ever delegated work to a Claude Code subagent and then looked at your usage, you have probably had the same reaction I did: why did that cost so much for such a small job?

The answer is that a plain subagent starts from nothing. It does not know what you have been doing, so the whole prompt prefix — system prompt, tool schemas, your CLAUDE.md, whatever else is loaded — gets sent again for that agent. When I measured this in a real fan-out, the fixed overhead came out around 436,000 tokens per agent, independent of what the agent was actually asked to do.

As of 2.1.232, there is a subagent that does not do that. The changelog line is:

Subagent forking is now on by default: a subagent_type: "fork" subagent inherits the full conversation and prompt cache, and non-teammate agent spawns in interactive sessions now run in the background by default

Two defaults changed in one line. This post is about the first one, and about a naming problem that makes it easy to misread.

Three different things in Claude Code are called "fork"

This tripped me up, so it is worth separating them before anything else. All three exist today, they do different things, and they arrived at different times.

1. context: fork in skill frontmatter — added in 2.1.0.

---
name: my-skill
description: "..."
context: fork
---
Enter fullscreen mode Exit fullscreen mode

This makes a skill or slash command run in a forked subagent context instead of inline in your session. It is a property of the skill, declared by whoever wrote the skill.

2. /fork — the slash command. Its behavior changed in 2.1.212:

/fork now copies your conversation into a new background session (its own row in claude agents) while you keep working; the in-session subagent it used to launch is now /subtask

So /fork is not a subagent anymore. It is a session copy — a second, independent session that starts from where you are. If what you wanted was the old in-session behavior, that moved to /subtask. If you learned /fork before 2.1.212 and have not touched it since, this is the one that will surprise you.

3. subagent_type: "fork" — the one that is now default in 2.1.232.

This is a subagent, spawned the normal way, that inherits your conversation and — the part that matters for cost — your prompt cache.

Same word, three layers: skill frontmatter, session command, subagent type.

What "inherits the prompt cache" actually buys you

Here is the part I got wrong in a companion post about CLAUDE.md and subagents, and a commenter on that post is the reason I went back and checked.

Inheriting the cache does not reduce the token count. Those tokens are still delivered to the model. What changes is which rate they bill at: a cache read instead of fresh input. So if you are reasoning about context window pressure, nothing improved. If you are reasoning about cost, quite a lot did.

This is the same idea as another 2.1.229 change I had originally filed as routine:

Improved workflow fan-outs to stagger same-prefix sibling agents so subsequent agents read the cached prompt prefix instead of re-paying it (CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS=0 disables)

Read those two lines together and the shape is clear. When ten agents share a prefix and all start simultaneously, none of them can read a cache that no one has written yet, so all ten pay full price. Staggering them means the first writes the cache and the other nine read it. Forking is the same trick applied to the parent conversation rather than to siblings.

Which means my ~436k-per-agent figure is best read as an upper bound: it is what a cold, unstaggered, non-forked agent costs. Under staggered fan-out, or with a forked subagent, the token count holds and the dollar figure does not. If you are measuring this yourself, split cache-read tokens from fresh tokens before you draw any conclusion — a single "total tokens" number will hide the entire effect you are trying to observe.

When you still want a cold subagent

Forking is not strictly better. Inheriting the conversation is exactly what you don't want in a few common cases:

  • Independent review. If you want a second opinion on a decision, an agent that has read your reasoning is not independent — it has already been argued into your conclusion. A cold agent that sees only the artifact is the point.
  • Context hygiene. A long session accumulates dead ends, abandoned approaches, and stale file contents. Forking carries all of it forward. A narrow task with a clean prompt often performs better with less context, not more.
  • Anything you would not want repeated. The fork inherits the full conversation, including whatever happened to be in it.

The rule I have settled on: fork when the agent needs to continue something, spawn cold when it needs to check something.

The other default in that line

The same changelog entry also says non-teammate agent spawns in interactive sessions now run in the background by default. Background execution itself is not new — subagents have defaulted to background since 2.1.198 — but the boundary moved again, and it produces a specific confusing moment: you delegate a task, immediately ask "what did it find?", and get told it is still running.

That is the agent working, not a failure. The result arrives as a completion notification in a later turn. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 makes everything synchronous if you would rather block.

How to check what you are getting

Two things are worth confirming in your own setup rather than trusting a blog post, including this one:

  1. Read the changelog for your installed version. claude --version, then check that version's entry. Defaults have moved several times in the 2.1.x line, and advice written against 2.1.180 is not advice about 2.1.232.
  2. Look at cache-read versus fresh input in your usage breakdown, not at the total. If your fan-out is billing everything as fresh input, either the prefix is not actually shared or the agents are all starting at once.

The general lesson, which outlives this particular release: in Claude Code, "how much does this cost" and "how much context does this consume" have quietly become different questions. A change can improve one and leave the other exactly where it was.


I write these as I work through Claude Code's behavior for Rulestack, a small set of packs for Claude Code, Cursor, and Codex. If you want the shorter version of these findings as I hit them, I post them at @ai-shop.bsky.social on Bluesky.

Top comments (8)

Collapse
 
alexshev profile image
Alex Shev

Fork semantics matter because copied context feels invisible after the fact. I would want every spawned session to say exactly what it inherited and what it did not.

Collapse
 
rulestack profile image
Rulestack

Would a one-line inheritance manifest at spawn cover it, or does it need to be queryable mid-run? Right now the only honest answer to 'what did this fork inherit' is 'go read the parent transcript', which is exactly the thing nobody does after the fact.

Collapse
 
alexshev profile image
Alex Shev

A one-line inheritance manifest at spawn would cover most practical reviews. Queryable mid-run would be better, but even a frozen 'this child inherited X, Y, Z' would stop a lot of hand-wavy debugging.

Thread Thread
 
rulestack profile image
Rulestack

Half of that I'd trust — the other half is that by the time anyone reads the manifest, the parent has edited the file twice. Same path, different bytes, and the manifest is still technically correct. What would you want it to say once the file has moved on?

Thread Thread
 
alexshev profile image
Alex Shev

I would want the manifest to pin content identity, not just paths. Something like path, byte hash, source session, and timestamp at spawn. If the parent edits the file later, the manifest can still say “this fork inherited these bytes,” which is the version auditors actually need.

Thread Thread
 
rulestack profile image
Rulestack

Pinning bytes over paths matches a lesson we learned shipping ZIPs: we keep a sha256 manifest per released version because "same path, different content" is exactly the dispute you can't settle after the fact. One thing I'd add to your tuple: the resolution order at spawn. Two files can both be inherited and one shadows the other, and the hash chain alone won't tell an auditor which bytes actually won.

Collapse
 
eduzsh profile image
Edu Peralta

The fixed overhead is the number people skip past. A plain subagent looks like free parallelism until you notice it reloads the system prompt, tool schemas, and project rules for a job that touched two files. Fork inheritance is the right default when the child needs the parent's context, but it also copies every bad assumption the parent already made. I treat spawn decisions as a cost question first now, and I only trust the result after reading what the child actually changed, not the summary it writes when it finishes.

Collapse
 
rulestack profile image
Rulestack

It took me too long to stop trusting the summary — it's written by the same context that made the mistake, so it's confident in exactly the wrong places. On cost, the thing that reset my defaults was that the fixed part barely moves with how much you hand the child, so splitting pays it again before any work happens. I've ended up splitting only when the work genuinely can't share a context, which turns out to be rarer than I assumed.