Bundled workflows (code-review, deep-research) offer no model override — all 10-15 subagents inherit the session model
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
/code-review at high effort launches the bundled code-review workflow: 10-15 subagents (scope, 3-5 finders, one verifier per finding location, sweep, synthesizer).
The bundled script sets no model: on any agent() call. Every subagent inherits the session's main-loop model. There is no way to override this.
I run Claude Fable 5 as my session model. That means every seat — including the mechanical finder/scope/sweep seats — runs Fable. Measured on 2.1.214: one high-effort review of a trivial 2-file diff = ~353K subagent tokens in 60 seconds, all at Fable rates. Real branch reviews are much larger. The review fires at the end of every build for anyone who has wired /code-review into their workflow.
The same is true for Opus-first sessions, and for the bundled deep-research workflow.
Proof:
- Every run persists its script:
ls ~/.claude/projects/*/*/workflows/scripts/code-review-wf_*.js→grep -c 'model:'returns 0. - Per-agent transcripts (
subagents/workflows/<run>/agent-*.jsonl) show each seat's model = the session model.
No override surface exists: the script ships sealed in the binary; Workflow({name}) takes no model parameter; no settings key covers it. opts.model (which resolved #63693) only helps scripts the user authors — there is no script to author here.
Proposed Solution
Any one of these fixes it:
- Pin the seats in the bundled scripts — Sonnet for finders/scope/sweep/synthesize, Opus for verifiers. This is what the Workflow tool's own model-tiering guidance recommends for user scripts.
- Accept a model override on named invocation —
Workflow({name: "code-review", model: "sonnet"})or a per-seat map. - A settings key for the workflow-subagent default model.
Workaround until then (fork the persisted script, pin 5 seats): https://github.com/waihonger/claude-code-review-pinned
Environment: claude 2.1.214, macOS (darwin arm64), session model claude-fable-5.
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
The token cost here is worth quantifying explicitly: if you run
/code-reviewat high effort on a real branch diff with Fable 5, and you do that daily as part of CI, you're looking at 353K+ subagent tokens per review multiplied by however many reviews fire per day - all at Fable rates when Sonnet-tier model quality is sufficient for the mechanical finder/scope/sweep seats.The fix you proposed in option 1 (pin bundled scripts to Sonnet for mechanical seats) is the right call. The verifier seats arguably benefit from a stronger model, but the scope + finders + sweep pattern is repetitive pattern-matching work - exactly the case where Sonnet handles it fine.
Until that lands: the workaround fork you linked (https://github.com/waihonger/claude-code-review-pinned) with 5 seats pinned is the practical path. One thing worth adding to that fork - pin the synthesizer seat too, since it's mostly assembly work on pre-extracted findings.
This is also a good argument for exposing a
CLAUDE_WORKFLOW_DEFAULT_MODELenv var as option 3. Many users run expensive models as their session default for interactive quality reasons, but don't want that default leaking into automated multi-seat workflows they fire from hooks or CI.Adding the opposite use case to the one in the report. You run Fable 5 as your session model and don't want the mechanical seats inheriting it; I run Opus and want to escalate — one deeper review on a stronger model right before pushing. Higher cost is expected there, since it's a handful of reviews per session rather than routine use. Same missing control, opposite directions.
Verified on 2.1.220 that
CLAUDE_CODE_SUBAGENT_MODELdoes reach/code-review. Same diff reviewed twice:| | main loop | review subagent |
|---|---|---|
| env unset |
claude-opus-5[1m]|claude-opus-5||
CLAUDE_CODE_SUBAGENT_MODEL=claude-fable-5|claude-opus-5[1m]|claude-fable-5|(subagent model read from its transcript under
~/.claude/projects/<session>/subagents/; main loop asked directly viaclaude -p.)So the routing already exists and works — it's just process-scoped. Using it means starting a new session, which discards the context that prompted wanting the review in the first place.
Worth noting the runtime already exposes exactly this per call. From the
agent()options raised in #63693:The bundled
code-reviewscript just never sets or surfaces it. So this looks less like new capability and more like threading an existing parameter out to the invocation.Effort is the precedent for the shape — already per-invocation, already trading cost against coverage ("without an effort argument, the review uses the session's current effort"). Model is the same kind of decision, but settable only per process.
Related: #73323 (same ask, no comments), #68695, and #63693 — which was closed by the stale bot for inactivity rather than declined, so as far as I can tell the request has never actually been adjudicated.
Correcting my comment above: I said using
CLAUDE_CODE_SUBAGENT_MODEL"means starting a new session, which discards the context that prompted wanting the review." That's wrong for/code-review.Checking the review agent's transcript, its first message is the skill's own prompt — "Phase 0 — Gather the diff: run
git diff @{upstream}...HEAD" — so it's a fresh agent that reads the repo, not a fork of the parent conversation. A review run from a second session sees exactly the same committed range and working-tree changes. So the env var is a fully working workaround today, not a degraded one.The remaining argument is friction rather than lost capability: keeping a parallel session open and remembering which terminal is which, versus one word on the invocation. Weaker than what I first wrote, and worth being accurate about.
The rest of the comment stands — the measured routing table, and that
agent(prompt, { model })already exists in the runtime while the bundled script neither sets nor exposes it.VOLY solves this with tier-based model routing: each role in a multi-agent run gets an assigned model tier, not the session default.
For a workflow like
/code-review(scope → finders → verifiers → synthesizer), the LeadOrchestrator assigns:Result from a real PulseBoard run (FastAPI + tests + Docker CI):
The reviewer (your 'synthesizer') ran on DeepSeek at /usr/bin/bash.001 instead of Fable 5 rates. Total: /usr/bin/bash.013 for the full pipeline.
Per-role override if you want explicit control:
VOLY_A2A_EXECUTOR_REVIEWER=cursorDocs: https://github.com/voly-codes/voly/blob/main/docs/backend/a2a.md
How many subagents does your typical
/code-reviewrun spawn?