← All recipes
  • models
  • subagents
  • cost

Opus plans, Sonnet builds, Haiku searches: the mix cost 2.3x Sonnet alone

We tested the viral 'run Opus, Sonnet and Haiku at once' Claude Code setup against plain Sonnet on the same 3-step feature in a 164-file repo. Sonnet alone passed every check in 3 of 3 runs for $0.283 a run. The full mixed setup passed 2 of 3 for $0.649, and Haiku did 1.8% of the work.

Cost per run Each bar is the average cost of the runs, starting at $0.

See every run, check and diff →

A widely shared post on X says the best way to run Claude Code is all three models at once: Sonnet 5.5 runs the session and writes the code, Haiku 5.5 subagents handle search, grep and test runs, and Opus 5.5 sits on call as an architect that signs off on plans and diffs. The claim is better results with way fewer tokens. The quick version is one line: CLAUDE_CODE_SUBAGENT_MODEL=haiku claude --model sonnet.

When we replied in that thread, we only had single-model numbers: on our checkout task, Haiku passed every hidden test at about a cent a run. We hadn’t tested the full loop. This is the full loop.

The setup

The same Node API we used on Wednesday, fleetdesk: 164 files, 16 modules, 18 test files. One feature, three steps, in one continuous session:

  1. Plan (plan mode): a CSV export of a tenant’s invoices at GET /billing/invoices.csv, with exact columns, money formatted “the way the rest of the codebase formats money”, inclusive date filters, sorting, RFC 4180 quoting, a header-only body when nothing matches, and 400/404 rules. “Plan the change first. Don’t edit anything yet.”
  2. Implement: “Go ahead and implement the plan, with tests. Run the tests.”
  3. Follow-ups: an optional currency filter (USD, EUR or GBP, anything else is a 400) and a line in CHANGES.md.

The seeded invoices have traps our hidden tests check: a customer name with a comma, one with double quotes, two invoices on the same date, a 105-cent amount, another tenant’s invoice and one dated the day before the range.

We ran Claude Code 2.1.312, the same version as Wednesday, with each model at its default effort. The setups:

  • Sonnet only: --model sonnet, nothing else.
  • The one-liner: Sonnet plus CLAUDE_CODE_SUBAGENT_MODEL=haiku.
  • The full tree: Sonnet, with the post’s setup in the repo: search, grep and audit subagents on Haiku (audit with isolation: worktree), an architect subagent on Opus, and the post’s CLAUDE.md rules: delegate searches and test runs to Haiku “to keep the main context under 10k tokens”, and ask the architect before a plan locks, when the same error hits twice, and before calling it done.
  • opusplan + Haiku Explore: --model opusplan (Opus in plan mode, Sonnet after), a project Explore subagent set to model: haiku, and the env var.

The post also routes “micro-forks” through JEV. JEV isn’t part of Claude Code; it’s a third-party router that sends your prompts through an outside service, so we left it out.

Nine checks graded every run afterwards, including hidden tests Claude never saw.

What happened

Sonnet only Full tree (Opus + Sonnet + Haiku) opusplan + Haiku Explore
Runs passing all 9 checks 3 of 3 2 of 3 3 of 3
Average cost per run $0.283 $0.649 $0.416
Versus Sonnet only +$0.366 (+129%) +$0.132 (+47%)
Cost range $0.264 to $0.300 $0.587 to $0.683 $0.370 to $0.464
Average spent on Opus $0 $0.275 (42.4%) $0.229 (55.0%)
Average spent on Sonnet $0.283 (100%) $0.363 (55.9%) $0.187 (45.0%)
Average spent on Haiku $0 $0.011 (1.8%) $0
Runs where Haiku ran at all 3 of 3 0 of 3
Cost of step 1 (plan) $0.110 $0.277 $0.229
Cost of step 2 (implement) $0.130 $0.314 $0.144
Cost of step 3 (follow-ups) $0.044 $0.058 $0.043
Average tokens, all models 486,092 1,250,179 455,288
Average output tokens 15,787 35,656 13,720
Largest main-session context, tokens 44,188 to 46,960 50,386 to 58,218 40,270 to 47,394
Subagent calls per run 0 4, 4 and 8 0

Claude Code 2.1.312, claude -p, 3 runs per column (averages unless marked). Token counts include cached input. Every run, check and diff: run data.

The one-liner got a single smoke-test run: it passed all 9 checks for $0.297, made 0 subagent calls, and Haiku never ran. Sonnet only cost $0.275 in the same smoke test. Because it routed nothing to Haiku, we dropped it from the 3-run test to stay near our budget, as our test plan allowed.

What we learned

The full tree cost 2.3 times as much, and Haiku was almost none of it. Claude followed the CLAUDE.md rules: every run called the search agent once, the audit agent once and the architect twice (once on the plan, once on the final diff). But Haiku’s share was 1.1 cents a run. Opus averaged $0.275 a run, nearly what Sonnet alone cost for the whole job, and Sonnet itself still spent $0.363, more than in the Sonnet-only runs. Total tokens across all models were about 2.6 times higher (1,250,179 vs 486,092).

The main context never got near 10k tokens. The setup promises to keep it “under 10k”. Claude Code’s own starting context was already about 20,670 tokens in these runs, and the largest main-session context was 50,386 to 58,218 tokens, higher than Sonnet alone (44,188 to 46,960).

The audit agent never tested the actual edits. isolation: worktree gives the subagent a fresh git worktree from the default branch, so it doesn’t see edits you haven’t committed. In two runs, the audit agent’s git status came back clean and its npm test ran the old code; in the third its test command was blocked by our permission settings. In one run Sonnet noticed and sent four extra Haiku agents to run the tests in the real tree.

The one full-tree miss came from following the architect. In that run, the Opus architect wrote “I lean towards CRLF” line endings because the prompt named RFC 4180, and Sonnet switched to \r\n. RFC 4180 does use CRLF, so that’s a defensible call, but our hidden tests expect \n and the run failed them. Sonnet alone and opusplan used \n every time.

CLAUDE_CODE_SUBAGENT_MODEL=haiku alone moved nothing. The subagent docs say the env var doesn’t change the built-in Explore and Plan helpers (Explore runs on the main model, Plan inherits it), and forks always run on the main model. In our runs Claude didn’t start any subagent with or without it, so there was nothing for Haiku to do. The same goes for the project Explore override in the opusplan column: set up correctly, called 0 times.

opusplan was the cheapest way to get Opus into the loop. Opus did the plan step ($0.229 on average) and Sonnet did the rest. It passed 3 of 3 at $0.416 a run, 47% more than Sonnet alone. On this feature, the Opus plan didn’t buy anything we could measure: Sonnet alone also passed 3 of 3.

What failed, and the limits of this test

  • One full-tree run failed 2 of the 4 hidden CSV tests, because of the CRLF line endings above. Every other check passed in every run.
  • The one-liner had 1 run, not 3. It routed nothing to Haiku in that run, which matches the docs, but 1 run is 1 run.
  • One feature, one repo, 3 runs per setup. A task with far more searching than this one might give Haiku more to do.
  • Default subagent behavior only. Claude decides when to delegate. With the full tree’s CLAUDE.md telling it to, it delegated in every run; in the other setups it never did.
  • We didn’t compare time. We ran the runs in parallel to finish on schedule, so wall-clock times aren’t comparable.
  • Over budget. Smoke test $1.50 plus 9 runs $4.04 is $5.54 in API charges, above our usual $5 per recipe.
  • API cost only. We measured dollars and tokens at API prices, not how much of a Pro or Max plan’s weekly limit the same work would use.
  • JEV not tested (third-party service, see above).

The recipe

  1. Start with Sonnet alone. On this feature it passed every check in 3 of 3 runs at the lowest cost, $0.283 a run.
  2. Don’t expect the env var to bring in Haiku. CLAUDE_CODE_SUBAGENT_MODEL=haiku only applies to subagents that actually start, and it doesn’t move Explore or Plan. If you want Haiku for searches, define a project subagent named Explore with model: haiku, or set CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 (docs), then check that it’s being called.
  3. If you want Opus in the loop, opusplan is the cheaper way. It put Opus on the plan for $0.132 a run more than Sonnet alone. An Opus architect subagent on every plan and diff cost more than twice as much.
  4. Don’t use isolation: worktree for an agent that should test your current edits. It works from the default branch, not your uncommitted changes.
  5. Check what the models actually did. A configured subagent isn’t a used one. Look at the cost by model in your session or transcript before you assume the cheap model is doing the work.