All writing

Who picks the model when a Claude Code workflow fans out

Workflow agents can quietly run on your priciest model. The four rungs that pick each agent's model, a probe that proves it, and how to own Claude's guide.

On this page

  1. One environment variable sets a cheaper floor
  2. Each role brings its own model
  3. The built-in guide tells Claude to inherit the session model
  4. A three-agent probe settled which model ran
  5. Four rungs decide every workflow agent’s model
  6. A user skill with the same name replaces the built-in
  7. Owning the guide has two costs
  8. What to do on Monday

0 of 8 sections read

Dynamic workflows let Claude Code spawn a dozen agents from one script. That’s powerful, and it’s expensive when every one of those agents silently runs on the same top-tier model as the main session. My session runs Opus. Out of the box, an agent() call with no model option ran on Opus too, including mechanical work like extracting, classifying and grepping that Sonnet handles fine.

So I traced who decides which model each workflow agent gets. The answer is a ladder of four settings, plus one lever that sits above all of them: the built-in guide Claude reads before it writes a workflow at all. I proved the ladder with a test and replaced the guide with my own. This is for anyone running Claude Code workflows, and anyone paying for them.

One environment variable sets a cheaper floor

The first fix was mine, and it wasn’t there by default. I added three lines to my user settings:

~/.claude/settings.json
{
"env": {
"CLAUDE_CODE_SUBAGENT_MODEL": "sonnet",
"CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "1",
"CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS": "8"
}
}

The first line makes Sonnet the model for any subagent or workflow agent that isn’t assigned one another way (env var reference). The other two stop agents spawning agents of their own and cap a workflow at eight agents running at once.Sidenote: CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 goes further and puts every subagent on that one model, ignoring roles. I want roles to choose, so I leave it off.

That gave me a cheap default. I wanted more than a default, though: control over which model each kind of work gets, and control over how Claude reasons about model choice when it writes the script in the first place.

Each role brings its own model

My orchestration setup has seven subagent roles, each an agent file in ~/.claude/agents/ that fixes its own model, reasoning effort and tools. The lead (the main session) picks a role, and the role brings its model with it.

Role Model Effort Writes files Job
repo-scout sonnet high no Trace code, return evidence with path:line
researcher sonnet medium no Web, docs and API research
architect fable high docs only Design from a clean context
coder opus high yes Implementation that needs judgement
fast-coder sonnet high yes Small, fully specified changes
reviewer opus high no Review the combined diff against the plan
verifier sonnet medium no Run checks, report pass or fail with output

Model choice by picking the job. A role’s model outranks the Sonnet floor, so coder and reviewer still get Opus when the work needs it.

The built-in guide tells Claude to inherit the session model

My orchestration skill had an odd line: “Where workflow-authoring says to omit model or that token cost is no constraint, these rules win.” I’d never looked at what workflow-authoring was.

It isn’t on disk anywhere in ~/.claude. It’s a bundled skill that ships inside the Claude Code CLI itself, and the Workflow tool’s description tells Claude to load it, by that exact name, before writing any script. Loading it confirmed both things my override line was fighting:

  • On models, it says to default to omitting the option, because “the agent inherits the main-loop model (the resolved session model), which is almost always correct.”
  • On cost, under ultracode (Claude Code’s opt-in mode for large multi-agent runs): “token cost is not a constraint.”

So every time Claude wrote a workflow, it first read advice pushing it towards session-model fan-outs, then read my rules pushing back. Two voices, and the louder one was Anthropic’s.

A three-agent probe settled which model ran

The built-in guide says a bare agent() inherits the session model. My docs said it uses CLAUDE_CODE_SUBAGENT_MODEL. Rather than reason about it, I ran a tiny workflow: agents that report the model ID their own system prompt names, with controls to prove the self-report tracks reality.

probe workflow
const ASK =
"Reply with only the exact model ID your system prompt says you are powered by, e.g. claude-xxx-n-n. No other text.";
const [bare, sonnet, opus] = await parallel([
() => agent(ASK, { label: "bare agent()", effort: "low" }),
() => agent(ASK, { label: "sonnet", model: "sonnet", effort: "low" }),
() => agent(ASK, { label: "opus", model: "opus", effort: "low" }),
]);
return { bare, sonnet, opus };
Probe model passed Reported model What it proves
bare agent() none claude-sonnet-5-5 The env var wins over the session model
control 'sonnet' claude-sonnet-5-5 Explicit Sonnet looks the same
control 'opus' claude-opus-5-5 The self-report changes with the model, so it’s trustworthy

The session was on Opus 5.5. The bare agent ran on Sonnet. My settings line is doing its job, and the built-in guide’s “inherits the session model” is wrong for my setup. It describes Claude Code with no floor set, which is how mine ran before I added one.Sidenote: A model naming itself is weak evidence on its own. The Opus control is what makes it usable: if the report hadn’t changed with the model, the probe would have proved nothing.

Anthropic’s own docs agree with the probe, not the guide. The sub-agents page lists the order, and the workflows page says workflow agents follow the same one. The guide Claude reads before writing a script skips a rung that the reference docs include.Sidenote: Tested on Claude Code 2.1.287 in an Opus 5.5 session. The version matters: before 2.1.251, the env var outranked both a role’s model and a per-call one.

Four rungs decide every workflow agent’s model

Putting the test together with those docs gives the full order Claude Code uses to choose a workflow agent’s model. A higher rung wins.

  1. Session model

    Used only when no other rung is set. Tested.

  2. Subagent model env var

    My Sonnet floor in settings.json. Tested.

  3. The role's frontmatter

    Picked with agentType. Documented, not re-tested.

  4. model on the agent() call

    One call's override. Tested.

Used last to Wins

The model a workflow agent runs on, from the fallback to the override that beats everything. A fork is the exception: it always inherits the session model.

My orchestration rules add policy on top. Every agent() names a role, so the model comes from the job. A per-call model override may only escalate, with the reason logged. Six agents per phase at most, and two session-model stages per workflow.

All of that constrains what a script can do. None of it changes what Claude thinks a good script looks like before it writes a line. That’s the guide’s job.

A user skill with the same name replaces the built-in

Knowing the ladder only gets you so far if Claude reads Anthropic’s advice before it writes each script. The cleanest lever is to replace that advice. I created my own skill with the same name, ~/.claude/skills/workflow-authoring/SKILL.md, starting as a word-for-word copy of the built-in so I had a faithful template to edit.

Anthropic’s skills docs say it should: when a personal skill shares a bundled skill’s name, “your skill replaces the bundled command” (skills docs). I wanted to see it happen before relying on it, so I added a visible marker line (“Chad’s strawman copy”) and checked from a fresh headless session.

The two checks where the model reported what it loaded disagreed. Asked for the first line under the heading, it skipped my marker and quoted Anthropic’s opening paragraph. Asked whether the skill contained “strawman”, it said yes. Only the raw output settled it:

Terminal
echo "Invoke the Skill tool with skill workflow-authoring, then reply OK." \
| claude --print --model haiku --allowedTools Skill \
--output-format stream-json --verbose \
| grep -c "Chad's strawman copy"

The loaded skill body contained the marker. My copy wins.

Skills are cached for each session, so a session that loaded the built-in keeps it. After /reload-skills, the Skill tool reported its base directory as ~/.claude/skills/workflow-authoring, and the skill list showed a single workflow-authoring, sorted in with my own skills. Two independent confirmations.

Owning the guide has two costs

  • My copy goes stale. The built-in documents the runtime API: agent() options, budget, workflow(), resume. When Claude Code changes those, my copy won’t know, and nothing tells me. It’s the same problem as Claude Code’s silent A/B tests: behaviour I depend on can move with no note.
  • Edits get mixed in. Once my rules are woven through Anthropic’s text, I can’t cleanly take their next version.

The mechanism itself is documented, so the risk is in the content, not the override. If you take over the guide, split it in two so both costs stay manageable.

Put your own rules in SKILL.md and edit them freely. Keep Anthropic’s runtime reference in a separate file such as references/runtime-api.md, word for word, and refresh it rather than edit it. Note the Claude Code version you copied it from, and re-run the headless check when claude --version moves. The first rule worth writing is the one the built-in gets wrong: replace “inherits the main-loop model” with the ladder above.

What to do on Monday

Set CLAUDE_CODE_SUBAGENT_MODEL in your settings. Nothing sets it by default, and without it every bare workflow agent runs on whatever model your session uses.

Then run the three-agent probe on your own machine. It takes a minute, and it tells you which rung you’re on rather than which one the docs say you’re on.

Last, search your own rules for lines that argue with something you’ve never read, like my “these rules win”. Each one is a sign of a bundled instruction pulling the other way. Find it, read it, and decide whether to keep arguing with it or replace it.

Who picks the model when a workflow fans out? Out of the box, a guide you never see. Now, I do.

More on GenAI

Topic
Type