Routing: when a cheaper model is the right answer
The same prompt on Opus cost less with a warm cache than on Haiku with a cold one. Which dial to turn before you downgrade the model, and what routing actually costs you.
"The cheap model writes worse code and I pay for it twice"
We get it, it's more expensive to implement sth using a less capable model so it's more costly But that's not the case for every type of task. Say, when you ask an LLM for an architectural decision and it provides you with a reasonable-looking output which you merge, you'll spend a day 3 weeks later realising it wasn't great. No point in saving here
But it's not about that. Before choosing a model, we should rather ask a different question: what does a single run of LLM cost? And the thing is that choosing a model is just one part of it, and it's not even the biggest one on our setup
Cost of a simple run
We ran the same prompt three times in a scratch directory, once per model, nothing else changed. ok came back every time — four output tokens.
Reply with exactly: ok| Model | Reported cost | In / out | Cache write (1h) | Cache read |
|---|---|---|---|---|
| Haiku 4.5 | $0.0216 | 531 / 70 | 9,498 | 17,448 |
| Sonnet 5 | $0.0947 | 2 / 4 | 14,598 | 23,578 |
| Opus 5 | $0.1213 | 2 / 4 | 11,356 | 15,185 |
Looking at Sonnet and Opus, you can see that there were only 2 in and 4 out (the part you actually wrote and read). The rest is a fixed overhead that the harness sends on every run, we haven't analysed what's in it. The 531/70 of Haiku is also because of sth else which we'll get back to later, it's not just about more words
The Opus figure perfectly aligns with Anthropic's pricing: $5 per MTok input, $10 per MTok one-hour cache write, $0.50 per MTok cache read and $25 per MTok output.
2 × $5 + 11,356 × $10 + 15,185 × $0.50 + 4 × $25 (all per MTok)
= $0.00001 + $0.11356 + $0.0075925 + $0.0001
= $0.1212625 ← exactly what the CLI reportedIf you spend ten minutes to reconcile your own figures they become an actual number, not just a figure you trust
The Haiku one doesn't align if you take the summary line above it which the CLI prints (it only aligns against the per-model breakdown). The Sonnet one is also $3/$15 rather than the $2/$10 introductory price they offered that day; we haven't investigated these things but it's always good to verify sth instead of assuming
What's more, this table doesn't tell you anything about prices. It's just that every model has a system prompt, and they are of different sizes. So the cache write cost varies between the runs, not because of per-token prices but because of the size of the system prompts. In this case Opus came out 5.6 times Haiku, it doesn't mean anything
The ignored control
| Run | Cost | Cache write | Cache read |
|---|---|---|---|
| 1 | $0.1213 | 11,356 | 15,185 |
2 (--effort low) | $0.1218 | 11,356 | 15,185 |
| 3 | $0.0985 | 8,879 | 18,071 |
| 4 | $0.0142 | 0 | 26,950 |
In the last one the prefix was fully cached so this is actually what a single run of Opus costs — a third less than what we'd paid for the cheapest model on a cold cache, for the same prompt and the same two-character response. One model, one prompt, an 8.6x spread
It's because on the input side cache reads are priced at 0.1 times base input price so a cached Opus 5 input token costs $0.50 per MTok which is half of $1.00 per MTok that an uncached Haiku 4.5 input token costs
So the more expensive model with a warm cache is cheaper than the less expensive model with a cold cache. But it's not about choosing a model. It's about whether the thousands of tokens you send before your prompt are billed at write or read rates
Model switch resets the cache
We also get you that caches are bound to a model so routing is a real trade-off and not free. The Anthropic's invalidation table says they all go away when you change a model:
Tools
System
Messages
But they have a documented workaround: keeping the main loop on one model and giving the cheaper one to a subagent
What's more, it's not a cheap-per-run decision that you make every time you face a simple task. Every switch starts from scratch so does the return — round trip is hard to measure but the invalidation table reflects both directions; here it was $0.0142 vs $0.12
But we can create a boundary that already exists: the subagent is their solution, a separate session or an offline batch job is the same thing but more distant, and they all have in common that in those cases you don't give the cheap model a warm prefix to spoil
Two independent controls
It's also worth noting that choosing a model and setting the reasoning effort are two independent dials, usually mixed up
The six harnesses expose both of them but place the second one differently:
Claude Code, Antigravity, Copilot — an
--effortflag with 5, 3 and 7 levels respectively so "low" is not the same across toolsCursor — in the model name (its models output is 197 lines, mostly one model at low/medium/high/xhigh/max level), and also accepts brackets around it
Kimi — in a config file per model through
support_effortsanddefault_effortCodex — no flag in the help, defined in
config.toml
It's also easy to experiment with it. It doesn't change the number of tokens that you send but the number the model outputs
In this test run 2 with --effort low produced a byte-identical usage block compared to run 1 because a four-token answer doesn't contain much reasoning to omit. That's not a statement about effort, that's a statement about this particular task — tasks with reasoning give it sth to work with and it can't change the size of the fixed part
On Opus 5 and Sonnet 5 in Claude Code and on the Claude API, effort defaults to high (the third of five levels, two higher ones available only by request)
Suitable and not-suitable work
At the end of the day it's about verification cost so let's use this as a criterion. We can route tasks to a cheaper model if they produce output that is cheap to verify in a mechanical way rather than tasks we assume the model will get right
We can give the cheap model:
file system navigation returning paths you were gonna open anyway
summaries of steps you'll read in any case
transformations with a test or a linter behind them
high-volume classifications whose output you'd sample-check anyway
We shouldn't:
give it anything it can get wrong in a credible way across files you won't read
ask about architecture, whether a bug is real, do security reviews
give it anything we can only know is wrong using the expensive model — double cost as predicted
The cheap model is safe when it's not the model that does the verification. If you need to check the output, you pay with your trust in it and that's the discount
The harnesses are routing already, and change of course
You're probably not the first router in the stack. In all our Claude Code runs there were two models:
claude-haiku-4-5-20251001with 521 input and 13 output tokens, at roughly $0.0006 per run
This line appears in the per-model breakdown; on the --model haiku run both parts of it are merged into a single line so we have this 531/70 row and this is why the usage block doesn't align with the cost figure. Remember to reconcile things against the per-model part, the summary might understate if you used more than one model
Copilot and Cursor have their own routers:
Copilot —
--modelsupportsautoto let it chooseCursor — the model list starts with auto (current, default) and their docs mention Auto Cost, Auto Balance and Auto Intelligence, plus a Cursor Router on Teams and Enterprise which chooses per Auto request based on optimisation mode
We also noticed that Claude Code's Explore subagent was using Haiku by default. As of v2.1.198 it inherits the main conversation's model but caps it to Opus on the Claude API; they must have considered a downgrade for exploration and changed their mind, so now you can define your own Explore with model: haiku if you want
It's about fan-out
The main cost is where the volume is, and the volume is in the fan-out. A session on the trusted model and N subagents on the cheap one, each with its own context. This is what they say in Claude Code docs:
Control costs by routing tasks to faster, cheaper models like Haiku
But the price on your workload:
A subagent starting from scratch needs to build a prefix so fan-out of N doesn't mean N times the per-token difference
If you can't verify it, it's not just about verification but N times verification, and what works is when the results converge into sth you read
The order
These are ranked by impact:
Stop rewarming what you already had — a one-hour cache write costs 2 times base input and according to Anthropic it pays off after two reads at this duration; not rewarming it is more beneficial than changing the model
Route the fan-out, not the main loop — a subagent is where you don't give the cheap model your warm prefix and this is what they say in their docs
Set lower effort before setting a lower model on work where thinking dominates output — reversible, no trust transfer to a different model
Change the model and measure it — the 5.6x wasn't a price ratio so yours won't be either; run your workload both ways and read the outcome
Move off-the-interactive-path deferrable work — Anthropic's Batch API is 50% off on input and output tokens for async work with no functional gaps compared to a downgrade; it's about a trade shape: Opus 5 to Haiku 4.5 is an 80% drop in the input rate so batching gives you less discount if a downgrade was safe and more if it wasn't; none of the six CLIs has a batch flag, so this speaks for relocating the job rather than altering your session
Routing in Claude Code
Pick a model: For routing which model to be used in Claude Code there's an option of using --model flag, it accepts either short alias or full model name. In the help text you can see that fable, opus and sonnet are aliases, while claude-fable-5 is a valid example of the full name. Haiku also works (as seen in tests resolves to claude-haiku-4-5-20251001), despite not being mentioned in the help text.
Pick a depth: There's also an --effort flag, which sets reasoning power; there are levels called low, medium, high, xhigh and max, they're not connected with the model choice and should be the first knob you reach for.
Route a subagent instead of the session. If you want to send a subagent instead of session down a tier it's the way described in the docs, as it runs in its own context leaving the context of the session intact. In this case you set the model field of the subagent frontmatter to either an alias or to inherit:
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Glob, Grep
model: haiku
---
You are a code reviewer. Report every issue you find...You can also use --agent <name> flag to run the entire session under a subagent, in which case (as per docs) main thread inherits system prompt, tool restrictions and model from this subagent.
See what it actually billed: The best way to verify is to use --output-format json and look for modelUsage section, indexed by models; it's more reliable than the top-level usage, in all our experiments with using multiple models we've observed that those two never align. To see the modelUsage you can e.g. run the program in print mode with --output-format json and pipe it through jq to extract the modelUsage:
claude -p "…" --model opus --output-format json | jq .modelUsageGotcha, and it cost us a minute of confusion: --fallback-model is not a routing tool, as per help text it's "automatic fallback to specified model(s) when the default model is overloaded or not available". It's a safety measure to make sure there's always sth to talk to, rather than a way to save money by using lower-tier models. It works only with --print and when set it doesn't mean that you'll be using cheaper models; it just means that on high load the app will automatically fall back to them and then try the main model again every time the user says sth.
Second gotcha: Every run involves a tiny Haiku call, so honestly they're all multi-model, for like $0.0006 (so not much).
Choosing the model and setting the reasoning depth in Codex CLI
The two levers are:
-m, --model <MODEL>(available both oncodexandcodex exec)No command-line parameter for the reasoning depth; neither
codex --helpnorcodex exec --helpmentions "effort" or "reasoning", and there's no flag for it at all.
The setting is config-based instead; you can find model_reasoning_effort in the 0.146.0 binary, alongside model_reasoning_summary and model_verbosity. They're just binary strings, so we can't confirm the actual behaviour, but that's the only evidence we have for it. Anyway, as it's not mentioned anywhere in the help text, treat the spelling as checked and the semantics as unverified.
The recommended way is to go for profiles (via -p, --profile <CONFIG_PROFILE_V2>), which are a mechanism for the config to be "stacked" with $CODEX_HOME/<name>.config.toml; as described in codex --help. That way, one parameter lets you point to a file that contains a set of settings — model and the rest — which is better for routing than --model, because usually, a low-cost model comes with other settings being dialled down.
For example: You can create a config profile file like this:
# ~/.codex/cheap.config.toml — layered on top of the base config with `-p cheap`
model = "<the cheaper model your account has>"
model_reasoning_effort = "low"and run
codex exec -p cheap "summarise the failing tests in ./out/junit.xml"to summarise failing tests in JUnit XML (but replacing the placeholder with a real model ID; see below). The model ID is a placeholder as we haven't explored this tool's model catalogue at all, and one taken from another product's docs is exactly the kind of thing that looks good but isn't correct — you need to query /model once you're in the session to find out.
The third lever is -c, --config <key=value>, which lets you override any config key for a single invocation (using dotted notation to access nested keys). codex --help has this example: -c model="o3". But if you don't want to define an entire profile, this might be a better option.
Just be mindful that config profiles are "stacked", not replaced. If some setting is missing in the profile, it'll fall back to ~/.codex/config.toml, which might be not what you want if you wanted to have a blank slate. Verify the resolved config before using it.
Finally, we haven't used Codex with any LLM for this chapter, so all the flag names and wording are from codex --help and codex exec --help (at 0.146.0), and the config key is from the binary strings; the figures included in the companion half of the chapter come from Claude Code.
Routing in GitHub Copilot CLI
The routing controls in the GitHub Copilot CLI tool allow you to choose the AI model and set how deep the AI thinks.
To select the model, use the --model flag. The built-in help describes it as a way to set the AI model to use, and using auto value lets Copilot pick automatically. For example: copilot --model gpt-5.4
To set how deep the AI thinks, use --effort (or its alternative name --reasoning-effort) flag with a value from one of seven ranges: none, minimal, low, medium, high, xhigh, max. That means that if you were to use a flag from another tool that had a similar functionality, you'd need to keep in mind it has a different position on this 7-rung ladder.
The cost is the most transparent to analyse here, as GitHub has a table with prices for all models grouped by vendors per token. The rule is also simple, and they state it themselves: "The cost of an interaction depends on two things: the model and the number of tokens consumed." So if you know the latter (by counting input or output tokens) and check the table, you can calculate it easily. It's expressed in USD, with 1 AI credit set to $0.01 by GitHub, so no conversion is needed.
The prices span from 25ct per million input tokens and 2$ per million output tokens for the cheapest model (Raptor mini), to 10$ per million input tokens and 50$ per million output tokens for Claude Fable 5 — so 40 times difference on input between the cheapest and the most expensive, selectable with a single flag.
You can also cap your spend for a run using the --max-ai-credits flag with a number of credits. That's more bulletproof than going for the cheapest model and "hoping" it'll be used. For instance:
copilot -p "triage the failing check on this PR" --model auto --max-ai-credits 50Also, the table with per-model multipliers (1x vs 13x) is a legacy from the era of request-based billing. GitHub moved to usage-based billing on June 1st, 2026 and now prices are per token (like everywhere else). The multipliers stay in place only for users on annual plans with Pro or Pro+ tier who were on the old request-based billing model. Under usage-based billing, prices are still per token, so you calculate a cost as a product of rate and number of tokens, just like anywhere else. So if you're planning to run some workload with Copilot, make sure to check which plan you're on.
Lastly, for the code review feature of Copilot, it chooses its own model automatically, so the per-token price may vary from one run to another. Therefore, it's not possible to route it.
Disclosure: The flags here are from copilot --help on 1.0.77; the prices and the interaction-cost rule are from GitHub's models-and-pricing reference, and the multiplier history from their separate legacy request-based-billing page. We didn't do a billed Copilot run.
Routing in Cursor
Pick a model: Model selection in the Cursor CLI works by choosing a model using the --model flag when running cursor-agent, and then you can list the available models with either --list-models or the models subcommand.
Look at that list before you do anything else. Before choosing a model, it's always a good idea to check what's available by listing them. If you run this on your side, you'll see we have 197 lines but in reality, there are just a few different models, the rest is the same models with different levels of reasoning (for example claude-opus-5 with low/medium/high/thinking-max and gpt-5.5 from none up to extra-high) and many of them have -fast versions too.
There's no separate effort flag per se but there are two ways you can specify the level of effort: either by using the suffix in the model name (like claude-opus-5-thinking-max) or by using a bracket syntax after the model name (like claude-opus-5[effort=low]). The bracket notation is actually documented, if you look at the help for cursor-agent (cursor-agent --help), it says that "Parameterized models accept quoted bracket overrides, e.g. 'claude-opus-4-8[context=1m,effort=high,fast=false]'" and there's a similar sentence at the end of the models output too. Personally, we find it more useful to reduce the effort using the bracket notation as it is not possible to tell when you run a command if you've changed the suffix or the actual model. So you can either list the models and then run a command like this:
cursor-agent models | sed -n 3p # auto - Auto (current, default)
cursor-agent -p "…" --model 'claude-opus-5[effort=low]'The default is a router. The thing is that the first entry isn't a model, it's a router called auto (and also labelled as "current default"). There are three auto modes in the Cursor docs: Auto Cost (billed at Model API prices for whichever model is used depending on what you actually use), Auto Balance and Auto Intelligence. The latter two are actually routers that choose the model on the fly. If you're on a Teams or Enterprise plan, it's the Cursor Router which chooses an appropriate model based on the selected optimisation mode for every request. So often it's not about choosing a model but between routers.
Gotcha: Also, the subscription obscures the consequences of this choice for some time as it's all about how many tokens you have in your balance. The docs say that the price is per 1m tokens and the model you choose determines how fast you'll be burning through this balance. So within the monthly cap, if you choose a more expensive model, you'll spend the same amount of money per run but will use up the monthly cap faster. After the cap is depleted, it's pay-as-you-go at the same rates, so you'll be paying more per run then too.
Disclosure: The list and the flags are from our local cursor-agent (2026.07.23-e383d2b); the pricing and the Auto-mode wording is Cursor's documentation. We didn't do a billed Cursor run.
Routing in Antigravity CLI
The routing around models in Antigravity CLI is controlled by the following:
Pick a model: --model flag, in its help text described as "Model for the current CLI session", while agy models subcommand lists the available options.
Pick a depth: --effort flag, described in help text as "Reasoning effort for the current CLI session (low|medium|high)". The latter one is not consistent across different harnesses though — there are different scales and thus, for instance, "high" in Claude Code doesn't mean the same as "high" in Copilot which is not the same as "high" in Kimi (the last one has only 3 levels and no "medium").
Given the small number of options it's easier to route here compared to other harnesses — in version 1.1.9 of Antigravity CLI, for instance, there were 11 models available; here's what agy models subcommand lists in its output:
gemini-3.6-flash-high gemini-3.5-flash-high gemini-3.1-pro-high
gemini-3.6-flash-medium gemini-3.5-flash-medium gemini-3.1-pro-low
gemini-3.6-flash-low gemini-3.5-flash-low
claude-sonnet-4-6 claude-opus-4-6-thinking gpt-oss-120b-mediumSo basically it's 2 Google tiers (flash and pro), with flash available for all levels, while pro only for high and low; 2 Anthropic models, and a gpt-oss as if it's an OSS weights-based foundation. In practice, choosing flash vs pro is the actual routing, everything else is about the depth of reasoning.
The thing is, the "effort" is defined in two places — via flag and by a suffix in the model name like gemini-3.6-flash-low, but there's no indication in the help what happens if they're different (no precedence). Also, for instance, the vendor's models documentation page was 404'd on the day we looked, so it'd be best to set it to single value and stick with it until you experiment yourself to find out which one has higher precedence.
Disclosure: The whole thing here comes from the installed binary — agy --help and agy models on 1.1.9. No vendor page behind it, because the one we went for wasn't there, and no billed run behind it either.
Routing in Kimi Code CLI
The model and "effort" routing (aka depth) in the new Kimi Code CLI, here's what we found (given you have the new build; if you still use the old one, it doesn't work this way):
From what we remember these are the signals our setup had:
version was 0.31.1
it was a native binary instead of the Python wrapper
it had config dir set to ~/.kimi-code/
it included migrate subcommand (which was about migrating data from the previous kimi-cli installation to the new kimi-code)
All these are true for the new build but having any of them is not enough, you need all of them. We only outline this in case you're not sure which build you have.
Pick a model: The model itself can be selected via -m or --model flag, its description says it's an alias for a LLM (large language model) and if you don't provide one it falls back to default_model defined in config.toml.
There's no models subcommand on 0.31.1 so we can only know which aliases are valid based on what you have in [models.*] tables in your config.toml; it's actually very sensible that this file is human-readable so you can check it.
Pick a depth: The "effort" (aka depth) is not a flag but sth defined in the config, split into 2 places:
per-model table defining which "efforts" the model supports
a global thinking table
Here's an example of how this looks like in config.toml:
default_model = "kimi-code/k3"
[models."kimi-code/k3"]
provider = "managed:kimi-code"
model = "k3"
max_context_size = 262144
support_efforts = [ "low", "high", "max" ]
default_effort = "high"
[thinking]
enabled = true
effort = "high"So as you can see, the model supports low, high and max effort but doesn't support medium (which is available in Claude Code, Antigravity or Copilot), so if you copy a medium value over from any of those tools, you're asking for sth this one doesn't have.
Route a profile, not just a model: The agents are routed via --agent or --agent-file flags, the first one uses a name to pick an agent profile for the session, the second one uses a path to load an agent profile from a Markdown file; it's similar to using subagents in other tools (choosing a package instead of recalling a flag), though in the new Kimi Code there's no routing layer so:
Gotcha:
The only way to tell the CLI to use a cheaper model for less important tasks is to select a cheaper model every time you run the command
We looked in the config.toml file that comes with the new build and didn't find any keys responsible for routing like secondary/fallback etc, only
default_modeland what's set via-m, so there's no automation around this. Sending cheap tasks to a cheap LLM is a manual choice in every run.
Disclosure: We examined this based on kimi --help of the 0.31.1 version of the new build, also opened the config.toml file from ~/.kimi-code/ and had a look (but haven't modified it). We didn't find any page on the Moonshot's docs site that is about model selection or routing so it's hard to point you to smth. No Kimi runs were done for this one too.
After measuring once
You'll probably not change much but it's good to have a number instead of an estimate. In these runs it was also pointing towards the session rather than the model name. Once you feel that a run is expensive, check what part of it was the prefix before what model it was