One Model for Six Jobs: Why We Made Per-Task Model Selection Opt-In
Coding agents delegate to sub-agents with wildly different demands, and almost everyone runs all of them on one model. Here is the cost of that, why a shipped default would be worse, and how we built model selection that asks once and always reports what it did.
If you use a coding agent that delegates, you are running several agents with very different jobs on exactly one model. The agent that greps forty files and summarises them, and the agent that root-causes a race condition, are both running on whatever you picked at the start of the session. One of those is overpaying and the other is underpowered, and you cannot tell which from the outside.
This post is about fixing that without doing the obvious wrong thing, which is shipping a default mapping and quietly spending other people’s money on our opinion.
The spread is larger than it looks
Coograph delegates to six agents. explore reads a great deal and decides little. verifier runs commands and checks output against criteria. debugger reads little and decides everything. reviewer has to notice the thing nobody noticed. These are not variations on one job; they are different jobs that happen to share an interface.
Published rates, per million tokens, as of today:
| Model | Input | Output |
|---|---|---|
| Claude Fable 5.1 | $10 | $50 |
| Claude Opus 5 | $5 | $25 |
| Claude Sonnet 5 | $2 | $10 |
| Claude Haiku 4.5 | $1 | $5 |
A read-heavy exploration run on Haiku is about a fifth of the input cost of the same run on Opus, for work that is mostly grep-and-summarise. That is the easy win, and most people never take it because the capability is buried in agent frontmatter nobody edits.
The tempting next move is to push the same logic everywhere: cheap models for everything that is not obviously hard. That is where it stops working.
Why cheap models cost more on the hard jobs
A cheap model on a debugging task does not fail loudly. It produces a plausible root cause, you act on it, and the bug comes back. Then you spend another session. The token saving on that first run is real and irrelevant, because the unit that matters is cost per resolved problem, not cost per request.
I had a clean example of this on the day we built the feature. A scheduled function deployed to the wrong cloud region. The cause was that an ES module re-export is hoisted above the call that sets the region, so the function was constructed before the setting applied. Type checks passed. Review passed. The code read correctly. Only the built artifact showed the truth.
That is not a capacity problem you solve with more tokens. It is a judgment problem, and judgment is precisely what you are buying at the top of the price ladder. Put the cheap model there and you will pay for it twice.
Note also that the most capable model is not the cheapest place to put everything either. Fable 5.1 costs twice Opus 5. It earns that on genuinely hard, long-horizon work and wastes it on a test run.
Why we did not ship a default
Once you accept that the mapping matters, the obvious move is to pick a good one and ship it. We did not, for a reason that took a while to articulate.
The right mapping depends on the change in front of you, not on the project and not on the tool. A typo fix does not need an expensive reviewer. A migration touching an auth path does, and probably deserves the best model available on the planning step too. Any single table we shipped would be wrong most of the time, in one direction or the other, and it would be wrong silently while spending someone’s money.
There is also a straightforward ethical line. Changing what a user’s tooling costs them, by default, on an upgrade they did not read, is not a product decision we get to make on their behalf.
So a fresh install ships models.mode: unset, which is the absence of a mapping rather than a quiet one. Every agent inherits the session model, exactly as before.
Ask once, at the moment you know something
The first ticket in a project asks a single question, after investigation and before the proposal is written, because that is the first moment the shape of the work is known rather than guessed:
Coograph can run each agent on a different model. Do you want one model for everything, a saved mapping, or to be asked per ticket?
The answer is written to config and the question never returns, whatever it was. Asking on every ticket is the kind of friction that gets a useful feature switched off for the wrong reason, so the budget is one question per project, once. If it ever fires twice, that is a bug.
Two commands drive it from there. /coograph-suggest-multi-models proposes a mapping with a reason and an estimated cost delta on every line, all editable, nothing written until you accept. /coograph-disable-multi-models turns it off in one step and keeps your saved mapping, so turning it back on does not start from nothing.
The line that makes it real
Every delegated run now ends with one line:
models: reviewer=opus (mapping), explore=haiku (mapping)
It prints in every mode, including off, where it reads (inherited).
This part is not decoration, and I know that because of how the same day went. We had shipped a status line that told the user when their guardrails needed attention. It printed nothing. The user said so three times. I blamed workspace trust, twice, and was wrong both times. The actual cause was documented behaviour: that class of hook writes its output to the model’s context and never to the terminal. The line had been working perfectly, into a channel the person it was written for could not see.
An invisible feature is indistinguishable from a broken one. A model mapping you cannot verify is worse than no mapping, because you will believe it is saving you money while it silently does nothing. So the footer prints in every mode, and it names both the model and where the choice came from.
What this does not solve
Prompt caches are model-scoped. Splitting six agents across four models means six cache namespaces instead of one, and a short agent run can lose more to cache misses than it saves on the per-token rate. This is why the cheap assignments are the read-heavy agents: their runs are long enough to amortise it. A suggestion that proposes three or more models says this out loud rather than letting you find out from a bill.
The suggestion itself is a guess from ticket text and file counts. It will sometimes be wrong, which is exactly why nothing is applied without an explicit accept and every line is editable before it is saved.
And the rate table will age. The command carries the date it was recorded and states that the figures are estimates from list prices, not measured spend.
The general shape
The interesting part is not the feature, it is the constraint we kept running into while building it. Three times in one day, the same failure: something worked correctly and invisibly, and invisibility was read as breakage. A guardrail that captured signals nobody could see. A status line written to the wrong audience. A model mapping that would have been unverifiable.
The fix in each case was the same and was not more capability. It was making the system say what it just did, in one line, where the person can read it. That is a lower bar than most tooling clears, and it is worth more than another feature.
Per-task models ship in Coograph 1.3.0, opt-in, asked once, and reported every time. The docs are at /docs/models/.
削减你的 AI 编程账单 67–78%。Coograph 采用 MIT 许可、永久免费。Pro 提供定制服务。