I Stopped Choosing Which Model Writes My Code
A few months ago I wrote that the best coding-agent architecture wasn't the strongest model everywhere — it was the one that let me choose which model did which job. Plan with an expensive model where ambiguity is high; execute bounded work on a cheap one. I was proud of that sentence.
It was also a confession that I was doing the routing by hand, one --story-model flag at a time.
This week baro started doing it itself. And the moment it did, the interesting problem stopped being which model and became a different, harder one: can I trust the cheap one it just picked?
Routing you don't configure
The old flow put the routing decision on me. I knew planning should be expensive and execution cheap, so I typed it out: a hybrid backend, a frontier planner, a deepseek-v4-flash story model. It worked, but it was a config I had to remember, and it treated every task the same — a one-line fix and a repo-wide feature got the same routing because I set it once and forgot it.
A task isn't one thing, though. It has phases, and the phases have wildly different value. Reading a messy repo and deciding where the seams belong is worth a premium. Writing the twelfth DTO once the plan is clear is not. So baro now makes the decision per task, on its own:
- It reads the goal and sizes the work — one focused agent, an ordered sequence, or a parallel fleet.
- It routes planning to a frontier model when the goal is genuinely ambiguous, and to a cheap floor model when it's a focused fix. You pay the premium only where it's earned.
- It runs execution on a fast, inexpensive model — always. Building code against a precise plan is commodity work.
- It escalates only the parts that fail to a stronger model, instead of pricing every story at frontier rates up front.
No flags. You describe a goal and get a pull request; baro decides how big the job is and which model each phase deserves. The model became the commodity. The routing became the product.
A run this week made the shape concrete. A goal on a real repo — an I/O-heavy TypeScript codebase with Notion integrations and route handlers, the kind where mocking is half the work. baro planned it on a frontier model, fanned five stories out in parallel, and ran every one of them on the cheap execution model.

The executor lane did about 4.2 million tokens of work. On the cheap model that was sixty-one cents. The same tokens on the frontier model I'd used for planning would have been closer to six dollars— ten times the price, for work where the plan had already removed the ambiguity. That gap, multiplied across every story of every run, is the entire argument for a routing layer.
The catch nobody screenshots
Cheap execution is only a saving if you can trust the output. And a coding agent that opens pull requests has a specific, brutal failure mode: developers don't average their experience with a tool. They remember the worst thing it ever did to them. One incoherent, green-but-broken PR and they're back in their editor for good — even if it was an edge case.
So while I was congratulating myself on the routing, I went and read every run real strangers had ever made with baro. The good news held up: the people who pointed it at their own repo got real work — one of them ran it four times on a private codebase and merged every one. But reading closely, I found the version of "worst thing" that scares me.
baro decided a story passed by asking a model, not by running the tests.
The critic that gave each story its pass/fail verdict was an LLM reading the diff and the agent's own narration. If an agent ran its tests with a trailing || true and then cheerfully reported "all tests pass," the critic could believe it. Nothing objective stood between a story with red tests and a green-looking PR. On a frontier model you might get away with that on vibes. Route execution to a cheap model and lean on "the critic said it's fine," and you're one confident-but-wrong narration away from shipping the exact thing that loses the user.
Why the obvious fix is wrong
The obvious answer is "just run the tests and fail the story on a non-zero exit." It doesn't work, and the reason is the same parallelism that makes the routing cheap. Stories run at once, each in its own git worktree, against a repo where sibling stories are still mid-flight. A story's own tests can be green while the suite is red because another agent hasn't finished the thing it depends on. That's precisely why agents reach for || true — a raw failure in a shared, half-built tree is usually not theirs to own.
Gate each story on the full suite and you'd false-fail constantly, blaming stories for their siblings' incomplete work. So the honest place to check isn't the story. It's the end.
A gate at the merge, not the vibe
baro now runs an objective verification pass on the fully-merged branch — after every story has landed and the tree is whole, where a failure is real and attributable. It detects the project's own build and test commands (npm, pnpm, yarn, cargo, go — only the scripts that actually exist) and runs them. If they pass, the PR is genuinely green. If a command that ran comes back non-zero, baro doesn't pretend.
It downgrades the pull request to a checkpoint and writes the failing command and its output into the PR body. "Here's what I built, here's the test that's red, here's the log." An honest checkpoint you can act on beats a green checkmark you can't trust — because the falsely-green PR is the worst thing, and the whole game is never shipping the worst thing.
If you remember one thing
- Route, don't configure. Pay the premium where ambiguity lives (planning); run the rest cheap.
- Cheap only counts if it's trusted. Verify the merged result objectively — build and test, not a model's opinion.
- Fail out loud. A checkpoint PR that says "this test is red" builds more trust than a green one that lies.
What this is really about
The economics post I wrote earlier ended on a sentence I still believe: the best architecture wasn't the one that used the strongest model everywhere — it was the one that let me choose. This is the next step of the same idea, and it flips the ownership. I stopped choosing. baro routes each phase to the model that fits it, sizes the work to the goal, and — the part that actually makes it usable — proves the result before it calls it done.
Models will keep getting cheaper and more interchangeable; that's the direction of the whole market. When the model is a commodity, the durable product isn't a bigger model. It's the layer that decides which model does what, runs them in parallel without chaos, and refuses to lie to you about whether it worked. That layer is the thing worth building.
baro is on npm and GitHub, and you can run it on baro's own cloud without wiring up a model at all. The event bus underneath it is Mozaik.
If this kind of agent architecture is interesting to you, join us in the JigJoy Discord. We talk a lot about baro, Mozaik, model routing, and what actually happens when you run this stuff on real codebases.
You can also follow or DM me on X / Twitter if you want to compare notes or argue with the design.
Different is better than better.
Made with baro, a frontier model for the thinking, and about a dollar of a cheap one for the rest.
