Book a call
LESSON16mVERIFIED 2026-08-04 · CLAUDE CODE 2.1.221 · CODEX CLI 0.146.0 · GITHUB COPILOT CLI 1.0.77 · ANTIGRAVITY CLI 1.1.9 · KIMI CODE CLI 0.31.1

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.

TEXT
Reply with exactly: ok
ModelReported costIn / outCache write (1h)Cache read
Haiku 4.5$0.0216531 / 709,49817,448
Sonnet 5$0.09472 / 414,59823,578
Opus 5$0.12132 / 411,35615,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.

TEXT
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 reported

If 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

RunCostCache writeCache read
1$0.121311,35615,185
2 (--effort low)$0.121811,35615,185
3$0.09858,87918,071
4$0.0142026,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 --effort flag with 5, 3 and 7 levels respectively so "low" is not the same across tools

  • Cursor — 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_efforts and default_effort

  • Codex — 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-20251001 with 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 — --model supports auto to let it choose

  • Cursor — 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

IN YOUR HARNESS

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:

MARKDOWN
---
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:

BASH
claude -p "…" --model opus --output-format json | jq .modelUsage

Gotcha, 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 on codex and codex exec)

  • No command-line parameter for the reasoning depth; neither codex --help nor codex exec --help mentions "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:

TOML
# ~/.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

BASH
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:

BASH
copilot -p "triage the failing check on this PR" --model auto --max-ai-credits 50

Also, 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:

BASH
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:

TEXT
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-medium

So 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:

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_model and 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

j / k to move between lessons