All Articles
CategoryAI
Reading Time
15 min read
Published
2026-09-06
Word Count
3,770words

Grab a coffee — this one is a deep dive!

Claude Code Subagent Model Assignment and Orchestration Cost

Summary

The Claude Code subagent model resolution chain now goes call parameter > frontmatter > env > main model. Learn the inherit trap and how to match the right model to each task.

  • The resolution order is now: per-invocation model parameter > agent frontmatter > CLAUDE_CODE_SUBAGENT_MODEL env > main conversation model (before v2.1.251, env came first).
  • model: inherit, or no model set at any layer (call parameter, frontmatter, env), binds a subagent to the main conversation's model — even a simple discovery task on an expensive main model gets expensive.
  • The prompt_cache field in /cost and the status line now shows the likely reason for a cache miss (tool definitions or system prompt changed, TTL expired).
  • Agent teams consumes significantly more tokens than a single subagent; reserve it for work that genuinely needs real-time coordination.
Claude Code Subagent Model Assignment and Orchestration Cost

One of four places decides which model actually runs when you trigger a subagent in Claude Code, and which of those four wins changed in the summer of 2026. An orchestration flow built on a wrong assumption can end up running even a simple file-scan task on the most expensive model — a leak that's hard to notice and shows up fast on the bill. This guide walks through the current resolution chain, why inherit quietly turns expensive, and how to match the right model to the right task type, step by step.

💡 Pro Tip: Whenever you don't explicitly pass a model parameter on a subagent call, and the agent frontmatter and CLAUDE_CODE_SUBAGENT_MODEL are both empty, that call inherits the model of the main conversation — forgetting this is the most common source of hidden cost.

Table of Contents

The model resolution chain: call parameter > agent frontmatter > env default > parent

Claude Code decides which model a subagent runs on by checking four points in order. Per the official documentation, the order is: first the per-invocation model parameter on the Agent call, then the model field in the subagent definition's YAML frontmatter, then the CLAUDE_CODE_SUBAGENT_MODEL environment variable, and finally — if none of those are set — the main conversation's (parent) model kicks in.

This ordering wasn't always this way. Before v2.1.251, the CLAUDE_CODE_SUBAGENT_MODEL environment variable sat at the front of the chain — overriding both the per-invocation model parameter and a model: inherit setting in the frontmatter. A team that set the env variable thinking it was just a "default" was actually force-binding every call to that model, no matter what a call explicitly requested. v2.1.251 reversed this and demoted the env variable to a true default: a floor that kicks in only when nothing else is explicitly set.

Why this ordering matters

In practice, this means you can choose the model at three different layers:

  • At call time (the model parameter inside the Agent tool or workflow agent()) — most specific, and always wins while the force flag is off.
  • In the agent definition (the model: field in .claude/agents/*.md frontmatter) — a fixed preference that applies every time you call that agent.
  • In the environment variable (CLAUDE_CODE_SUBAGENT_MODEL) — the last-resort default that kicks in only when nothing else is explicitly set.

If all three are empty, the subagent inherits the main conversation's model — this applies to the built-in Explore and Plan agents too. One more note for Explore: on the Claude API, the inherited model is capped at Opus.

What 'inherit' means and why it quietly turns expensive

When an agent definition says model: inherit, that subagent uses the main conversation's model. This looks like a quick default, but in practice it can surprise you in two different ways.

The first is simple: if the env variable isn't set (or the frontmatter already says inherit) and the main conversation is running on an expensive model, then the subagent you called for "just scan the files" runs on that same expensive model. For discovery and mechanical work, this means an unnecessarily costly turn.

The second is a lesser-known trap: CLAUDE_CODE_SUBAGENT_MODEL alone doesn't affect built-in agents like Explore and Plan. To also bind those, you need CLAUDE_CODE_SUBAGENT_MODEL_FORCE set to 1. The flag's semantics: (a) with both set, subagents run on the model in CLAUDE_CODE_SUBAGENT_MODEL — while the flag is on, every subagent's model field, including Explore and Plan, is ignored, and the per-invocation parameter can't be passed either; (b) with only CLAUDE_CODE_SUBAGENT_MODEL_FORCE set, subagents run on the main model, while Explore keeps its own ceiling; (c) even with both set, a fork and a subagent-run skill with model: inherit still stay on the main model; (d) the flag requires Claude Code v2.1.257+.

Practical checklist

  • Review every agent definition that says model: inherit — this is a cost decision tied to how expensive the main model is.
  • If you want to steer built-in agents like Explore/Plan, CLAUDE_CODE_SUBAGENT_MODEL alone isn't enough; you need CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 (v2.1.257+), and account for the fact that while the flag is on, a fork and a model: inherit skill still stay on the main model.
  • Don't assume the env variable is a rule that "overrides everything" — after v2.1.251 it's only the last-resort default.

The task-to-model matching table (discovery/mechanical · well-specified code · hard verify)

The official cost guide recommends specifying a cheap model in the subagent configuration for simple subagent tasks. The bundled claude-api skill clarified this further: even when choosing cheap worker/subagent models, they still need to be "current-generation." The record doesn't say more than that: cheapness alone isn't a sufficient criterion — the model also has to be current-generation.

Task type
Example work
Recommended model class
Why
Discovery / mechanical
File scanning, grep inventory, link checking, simple format conversion
Cheap, current-generation model
Low reasoning, high volume — running it on an expensive model is pure waste
Well-specified code
Writing a function/endpoint to a defined interface, a migration with a clear schema
Mid-to-upper-tier model
If the spec is clear, you don't need the "strongest" model, but accuracy still needs to beat a cheap model
Hard verify / adversarial judge
Verifying a security-critical flow, post-migration integrity checks, an adversarial review
Strongest / highest-effort model
The cost of a false negative (a missed bug) is highest here

The default behavior of the general-purpose subagent

A general-purpose subagent, with no explicit model setting and an empty env variable, falls straight through to the main conversation's model. In a flow that frequently calls it, you need to explicitly control which model it gets rather than assuming — especially if the main model is expensive.

This becomes especially visible in a multi-step orchestration script. If a workflow calls general-purpose dozens of times without ever passing a model parameter, its total cost hinges on a single variable — which model the main conversation opened with. Run the same script one day with an expensive main model and the next with a cheap one, and total cost can differ significantly though the code never changed. That's why adding a task-appropriate model value to every agent() call is the one practical step that makes a workflow's cost predictable at the code level.

Three questions to ask when deciding

Three questions, asked in order, turn the table above into practice:

  1. How much reasoning does this task require? A mechanical file scan and verifying a security flow don't deserve the same model class.
  2. How costly is a wrong result? A file a discovery agent misses is usually caught in the next step; a security vulnerability a verify agent misses is far more costly.
  3. How often will this call repeat? A high-volume, frequently repeated task turns even a small price difference between model classes into a large aggregate impact.

The silent trap: an agent dropping to a 200K context when the `[1m]` tag gets ignored

In a setup using a long-context pin (the [1m] tag on ANTHROPIC_DEFAULT_FABLE_MODEL), agents defined as model: fable were, for a while, ignoring this tag and silently dropping to a 200K context window. The insidious part: the agent didn't error out, it just worked with a shorter context — a subagent scanning a large codebase could produce a result based on half the information, unnoticed.

This has since been fixed; but the lesson remains: verify which model a subagent actually runs on, rather than assuming. Your definitive signal is the modelUsage field in the result message — it gives the actual model identity; "I set a pin, it must be working" isn't sufficient evidence. Keep the distinction clear: modelUsage reports which model identity ran, not the context window.

Why this is especially dangerous in subagents

It's easier to notice a context narrowing in the main conversation because you're following it directly. But when a subagent runs in the background, in its own isolated window, and quietly returns with a narrowed context, you only realize the result is incomplete afterward — maybe when a later step reveals an inconsistency. For a subagent task needing a long context (say, a discovery agent scanning an entire codebase), verifying once which model identity actually ran is far cheaper than debugging it after the fact.

Behaviors that miss prompt cache, and /cost's new 'why it missed' line

Prompt cache lowers cost by avoiding reprocessing the previous context on consecutive requests sharing the same system prompt and tool definitions. But it's fragile: even a small change in the request prefix can miss the cache. The first four items below are concrete behaviors from the official changelog; the last is a direct consequence of this general caching mechanic:

  • Tool definitions or the system prompt changing — using a different tool set or a different system prompt between subagent calls changes the request's prefix and invalidates the cache.
  • TTL expiring — the cache drops after a certain time (TTL); a session sitting idle through that window misses the cache on its next request.
  • First-turn announcements being re-sent in agent teams — in-process teammates were re-sending first-turn tool and skill announcements on the second turn, changing the request prefix and missing the cache. This behavior has since been fixed.
  • Post-tool context not being cached in Fable 5.1 — in Fable 5.1 sessions, context added after a tool result was previously left outside the cache scope, and got re-sent as uncached input on every tool-call turn. This is another one of the behaviors that has been fixed.
  • Small prompt variations breaking the same prefix — a system prompt phrased slightly differently on each call counts as a different request for caching purposes, even if it's technically "the same job."

The new signal in /cost and the status line

Now, /cost output and the status line's prompt_cache field also show a possible reason when a miss happens — e.g. "tool definitions changed" or "TTL expired." A signal that previously only said "cache missed, total cost is X" now says "here's why it missed." Know its scope: it only covers the main conversation, not subagents. When cost unexpectedly spikes, check this line first to see which tool-set or system-prompt change broke the cache.

Passing a long subagent prompt from a file (--append-subagent-system-prompt-file)

The text form of appending a long, reusable system prompt to a subagent (--append-subagent-system-prompt) has been around a while; it's passed in non-interactive (headless) mode and appended to every subagent's system prompt, including nested ones. It has one permanent limitation: a forked subagent doesn't receive it, since it reuses the conversation's own prompt. --append-subagent-system-prompt-file doesn't remove that limitation — it only solves the case where the text is too long for the command line; you save the prompt to a file and pass its path instead. Requires Claude Code v2.1.261+.

This has two practical benefits:

  • Readability — instead of embedding a string hundreds of characters long into the command line, you can keep the prompt in a separate file tracked in version control.
  • Reusability — by referencing the same file across different subagent calls, you can update the prompt from a single place.
bash
1# Append a long subagent system prompt from a file
2claude --append-subagent-system-prompt-file ./prompts/security-reviewer.md \
3 -p "Review the auth changes in this PR"

It's an ergonomic improvement for teams who, in an orchestration script, want the same long instruction set kept in one central file rather than repeated inline, updated from a single place when it changes.

The token overhead of agent teams and when it's worth it

Agent teams is an experimental mode letting multiple agents work together at once (enabled with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1, off by default). The official documentation warns directly: this mode consumes significantly more tokens than a single session — each teammate carries its own independent context window, making it structurally more expensive than doing the same work synchronously with one subagent.

That's why, instead of making agent teams your default, reserve it for work that genuinely requires real-time coordination — agents that need to see each other's intermediate output as they progress. For sequential work or work on the same file, it isn't recommended; that completes far more cheaply with a single Agent tool call (fire-and-return).

A simple decision rule

text
1Is the task parallel AND do the agents genuinely need
2each other's intermediate results in real time?
3 YES → agent teams (accepting the token overhead)
4 NO → single subagent / sequential Agent calls

The cache-miss fix in v2.1.261 (eliminating the repeated second-turn announcements) somewhat reduces agent teams' cost disadvantage, but it doesn't eliminate the structural token gap — the fact that each teammate carries a separate context window hasn't changed.

Verification: proving which model actually ran with /tasks and modelUsage

A configuration "looking right" and it "actually working that way" are different things. Verify which model a subagent ran on with two concrete signals, rather than assuming:

  • /tasks — shows which model a running or finished subagent ran on.
  • The modelUsage field in --output-format json output — the definitive signal carrying the actual model identity; since the stderr model warning is suppressed in JSON mode, read the real model from here.

Checking the model doesn't stop at the env variable or the call parameter — it also has to cover the model: field in the subagent's own frontmatter, since frontmatter comes before env in the chain.

Signal
Where to look
What it shows
/tasks
Terminal command
Which model a running/finished subagent ran on
modelUsage
--output-format json output
The actual model identity (a definitive signal independent of stderr warnings)
prompt_cache field
/cost or status line
The likely reason if a cache miss happened — main conversation only; doesn't cover subagents
bash
1# Read the running model identities (use /tasks for per-subagent breakdown)
2claude -p "..." --output-format json | jq '.modelUsage'

After configuring model assignment in an orchestration flow, checking one of these signals at least once — especially for a cost-critical subagent — turns "I set it, it must be working" into "I set it, I verified it." That difference prevents a mismatch between the final bill and what you expected.

GOLDEN TIP

The most valuable insight in this article

This tip holds the article's most important takeaway.

Easter Egg

You found a hidden gem!

There's a hidden detail in this section. Want to uncover it?

Reader Reward

Below is a single checklist for putting this guide into practice. Check off each item in your own setup and you can be sure your model assignment is both correct and verified.

FAQ

Which model does a subagent use in Claude Code, and how do I force it?

The resolution order has four steps: the per-invocation model parameter, then the YAML frontmatter model field (inherit picks the main model), then CLAUDE_CODE_SUBAGENT_MODEL, and finally the main conversation's model. The env variable is now only a default kicking in when nothing else is set; for real forcing, set CLAUDE_CODE_SUBAGENT_MODEL_FORCE to 1 (v2.1.257+) — with both set, every subagent, including Explore and Plan, runs on the env model.

How expensive does it get if I call a subagent without specifying a model?

If no model is specified, the subagent inherits the main conversation's model — Explore and Plan behave this way too. In a session on an expensive main model, even a simple discovery task runs there. Verify which model ran with /tasks or the modelUsage field in --output-format json output.

Why does prompt cache get missed, and how do I see why?

The prompt_cache field in /cost and the status line directly shows the likely reason (tool definitions or system prompt changed, TTL expired, etc.); it covers the main conversation only, not subagents. Also fixed in agent teams: in-process teammates were re-sending first-turn announcements on the second turn, changing the request prefix and missing the cache.

Is agent teams or a single subagent cheaper?

A single subagent (a synchronous Agent tool call) is structurally cheaper — it carries one context window. Agent teams, per the official docs, consumes significantly more tokens than a single session, since each teammate carries its own window. Prefer it only when genuine real-time coordination is needed; not recommended for sequential or same-file work.

Why can the `[1m]` tag get ignored?

The [1m] tag on a long-context pin was a behavior where agents defined as model: fable would, for a while, ignore this tag and silently drop to a 200K context window. This has since been fixed, but the core lesson remains: verifying which model identity actually ran via modelUsage is safer than assuming.

Which task should go to which model class?

Routing discovery and mechanical work (file scanning, inventory, format conversion) to a cheap, current-generation model, well-specified code writing to a mid-to-upper-tier model, and hard verify/adversarial judge work like security-critical verification to the strongest/highest-effort model balances both cost and accuracy.

Conclusion

Subagent model assignment in Claude Code now relies on a predictable chain: call parameter, agent frontmatter, env default, then the main model. Knowing this order isn't enough — verify via modelUsage, /tasks, and /cost when inherit quietly turns expensive, which model identity actually ran, and which behaviors miss the prompt cache. Turning on agent teams only for work needing real-time coordination, and using a single subagent elsewhere, also minimizes the structural token gap.

If you want to go deeper on your orchestration setup, check out the guide to multi-agent teams and parallel work in Claude Code or architectural planning with plan mode. To go deeper on prompt caching on the API side, the guide to cutting cost 10x with Claude prompt caching is a complementary resource. If you want to set up hook-based automation, the Claude Code hooks automation guide can help, and for MCP integrations, the Claude Code MCP guide is also a resource.

Sources

Tags

#Claude Code#subagent#model routing#prompt caching#agent teams#orchestration#cost optimization
Muhittin Çamdalı

Muhittin Çamdalı

Lead Mobile Engineer

Lead Mobile Engineer with 12+ years of experience. Expert in iOS, Android and cross-platform architectures with Swift, SwiftUI, Kotlin and Flutter. I build performant, user-friendly mobile apps.

iOS Development News

Weekly Swift tips, SwiftUI tricks and iOS best practices. No spam, only valuable content.

We respect your privacy. You can unsubscribe at any time.

Share