Field notes from the machine: how we built the orchestrator that routes each task to the optimal model, and the near miss that drew the line on what it's allowed to act on.
Every Claude Code session defaults to the model it was opened with. Ask it to rename a variable or design a whole subsystem and, left alone, it reaches for the same tier both times. That's fine until the quota notices. Tokens and time are one budget, and the top tier spends both fastest. Waste them on a variable rename and they aren't there for the subsystem. The obvious fix is a rule of thumb: low-cost model for easy stuff, expensive model for hard stuff. It sounds right. It's wrong, and working out why it's wrong is most of what this project turned out to be.
What it actually decides
The orchestrator is a routing layer, not another agent framework. It lives as markdown: a contract file, a handful of dispatch templates, an append-only ledger, all read by a session before it delegates anything. No installed dependency, no external scheduler. The bet, made on day one, was that Claude Code's own primitives were already enough, and the missing piece was a policy rather than a platform.
The policy's core move is refusing "hard versus easy" as the routing variable. What matters is task shape: how many correction rounds the work needs, and whether a given round can be checked objectively.
- Route down — one-shot, objectively checkable: tests exist, or the output validates against a schema. Push it down the cost ladder, through scripts and local models before the low-cost hosted tiers.
- Stays top — iterative and judgment-heavy: design, debugging, architecture, review. Stays with the top-tier model, in-session.
Underneath that split sit three costs the "low-cost tier for easy tasks" instinct never prices in:
- Cold-start tax — every delegated session re-derives context from nothing, so handing off a five-minute edit loses outright.
- Review tax — whoever dispatched the work still pays to read whatever comes back, and a chatty response from a low-cost tier can erase its own savings.
- Retry tax (dominant) — low-cost models fail more often at anything with judgment in it, and every failure means a redo.
The rule that survives all three isn't "is this task hard". It's whether the expected saving beats the expected cost of doing it again. Iteration-heavy work maximises the wrong side of that inequality no matter how easy it looks.
What never routes down
Four categories are pinned to the top tier permanently, however simple the task looks in isolation.
Taste-sensitive output is the first: design, copy, naming, brand voice. A component name is trivial to compute and still wants the model with taste. It turns out "easy" and "low-stakes" are different axes, an idea that arrived from outside the project and earned its place.
The terminal review is the second. Per-task reviews can run on a mid tier, but the whole-branch pass before anything ships always runs top-tier, because it catches what the narrower passes miss. A pass on a low-cost tier once sailed past a real security hole that a stronger model then caught. The rule dates from that day.
Third, a green light from a low-cost tier gates a dispatch but never substitutes for verification. Low-cost models have a structural habit of reporting success they haven't earned.
Fourth, the orchestration layer itself. A low-cost model was tried as middle manager between the session and a worker. Sixty minutes and roughly fifty tool calls later it had shipped nothing and quietly run a global install nobody asked for. Delegation stays a command the session issues directly.
› echo "nobody gets a middle manager"
Proof over promises
Every delegated run ends the same way: a status block in the chat, and a row appended to a ledger file. Neither trusts a bare claim. A "done" needs the tool output, test result, or screenshot sitting next to it.
The ledger isn't decoration. Each row records what was routed where, whether it passed, and the field that matters most: any lesson. A populated lesson is a candidate for promotion into the routing rules themselves. The policy tightens from its own field evidence, not just from design sessions.
The near miss
The hardest lesson didn't come from a cost overrun. It came from a decision that would have run correctly, in the wrong place.
A "do it everywhere at once" clause, written into one project's own decision log, would have had that project's session run git rm --cached against a sibling project's repository, one it had no business touching. The user caught it before it executed. Nothing was lost.
But it exposed the real default across every project on the machine: any session could offer to edit a neighbouring project's files, and the offer usually looked reasonable.
The fix wasn't a smarter check. It was inverting the default.
A session now treats every other project's tree in three bands:
- Read (always allowed) — reading a sibling's files is always allowed, since no desync is possible.
- Propose (the only sanctioned cross-project write) — writing a note into the sibling's root asking its own next session to decide.
- Mutate (denied by default) — editing a sibling's facts or running commands in its repo. Two narrow carve-outs: files whose whole purpose is to receive writes, like the routing ledger, and gated edits to genuinely shared config, which always name their blast radius and wait for sign-off.
Everything else routes through a proposal note. It suggests; it never asserts. The receiving project's own next session folds it into its own files, then deletes it. No queue, no index, no daemon. Three ad hoc uses proved the pattern before anyone wrote it down as a rule.
How it came together
Eleven days, roughly a session a day, each one closing with the same four working files (notes, memory, active constraints, rejected approaches) so the next session opens cold and still knows why past decisions landed where they did.
- Day 1 — Founded on native primitives. External orchestration frameworks rejected in favour of Claude Code's own agent files, skills, and hooks. First trial ran in a throwaway project on purpose, for zero regression risk while the design was unproven.
- Day 2 — The ladder tested for real. A wiki migration ran as the first live trial, with a script, a local model, and two hosted tiers all doing genuine work in one pipeline. The layered-review rule landed that same week, after a low-cost pass missed that security hole.
- ~Same week — First shipped consumer. A pension calculator's feature became the first real work routed end-to-end through the policy. It surfaced the first known gap: the local tier only speaks Python, and this task was JavaScript. Not a misroute, a disqualification, but a gap worth naming.
- Day 4 — Outside validation. An unrelated public routing framework, reviewed independently, converged on the same core shape from a completely different workload. We folded in its one genuinely new idea: taste as a routing axis distinct from difficulty. We rejected its "never run high reasoning effort" rule, since it conflicts with exactly the stages this project keeps expensive on purpose.
- Day 6 — Cross-project messaging formalised. Three ad hoc successes generalised into the proposal-note convention.
- Day 7 — The near miss, and the contract it produced. Default-deny on cross-project mutation became a standing, machine-wide rule.
- Day 10 — Fleet-wide rollout. The enforcement line, the one that makes a project's session actually consult the policy instead of silently defaulting, was offered across around eighteen sibling projects. Opt-in per project, tracked from the filesystem alone.
- Day 11 — The ledger checks itself. A staleness audit found most adopted projects had quietly stopped logging, so a hook now nudges emission at session end. The same day, a reviewer on a low-cost tier blamed an unrelated, pre-existing file change on the task it was checking. Comparing timestamps caught it, and it became a standing rule: a low-cost tier may scan, but attributing a found change to a cause needs a timestamp check first, not a guess.
What's still open
Three gaps stay visible on purpose. The local tier only routes Python-shaped work, so JavaScript tasks run top-tier by default until a second real JS consumer justifies building a driver. Reasoning effort never entered the model at all: the policy routes on which tier runs a task, not on how hard that tier is told to think, and the same model at a different effort setting is a different cost and arguably a different capability. That dimension is unexamined, not settled. And one mid-tier code-generation route sits in the ladder unproven: named, priced, ready, and untouched, because no task has gone through it yet.
A rung nobody has used is not the same as a rung that works.
Nothing above is theory. Every rule came from work that actually ran. The whole apparatus is a bet that the interesting problem was never "which model is smartest". It was knowing, task by task, when smartest is the wrong thing to be paying for.
Companion piece: Convergent evidence. Nine orchestration-shaped tools crossed the desk while this was being built, and not one became a dependency.
The policy itself, extracted and de-identified: the routing-policy repo.
Originally published at thekilted.dev/route-dont-guess.
Top comments (0)