The One File Where Your AI Model Names Live
Model names scattered across every repo's config rot the day a model gets deprecated or repriced. One git-versioned markdown table fixes it for good.
TL;DR: If you run agents across more than one repo, your model choices are probably hardcoded in a dozen places — a
CLAUDE.mdhere, a shell alias there, a hardcoded model string in a subagent config. That’s fine until a model gets deprecated, repriced, or quietly downgraded, and now you’re grepping the filesystem for every place you typedclaude-opusby hand. The fix is one file: a git-versioned markdown table that maps task type to model, imported into every session on the machine. Change a model once, every repo inherits it. It’s not clever. It’s just the one place model names are allowed to live.
Model names rot the moment they’re hardcoded
Every agent config has a model name in it somewhere. A
CLAUDE.md that says “use Opus for planning.” A subagent
definition with model: sonnet baked into the frontmatter. A
shell script that calls a specific model ID because that’s what worked
when you wrote it eight months ago. None of this is wrong on day one.
It’s wrong on day two hundred, when the vendor ships a new model,
deprecates an old one, or moves the price on the one you’d standardized
on — and you discover you never actually standardized on anything. You
scattered the same decision across every repo you touch, and now every
one of those repos needs its own fix.
The failure mode isn’t dramatic. It’s just drag. One repo still points at a model that’s been quietly superseded. Another repo’s subagent is running a heavyweight model on work that never needed it, because nobody went back and right-sized it after the first draft. A third repo has a stale model ID that still technically works but isn’t what you’d pick today. None of this breaks anything outright — it just means every model decision you’ve ever made is still live, uncoordinated, and nobody’s the one place you’d go to see the whole picture or change it in one motion.
The tell that you have this problem: try to answer “which model handles code review across all my projects” without grepping. If you can’t, the decision isn’t a decision — it’s a pile of copies.
The one-file pattern
The fix is boring on purpose. One markdown file, versioned in git, that is the single place model names are allowed to live. Every repo and session on the machine imports it rather than declaring its own. Here’s the core of the file I run — trimmed to the table itself, row labels lightly compressed:
# Effort table — task type → model
| Task type | Effort | Model |
|---------------------------------|--------|-----------|
| Orchestration, judgment, review | high | Opus 4.8 |
| Drafting / bulk edits, subagent | medium | Sonnet 5 |
| Scans, greps, per-item grunt | low | Haiku 4.5 |Four columns in the real file, three rows. The fourth column —
trimmed here for width — is the literal model ID string
(claude-opus-4-8, claude-sonnet-5,
claude-haiku-4-5-20251001), kept right beside the
human-readable name so a rename in a vendor’s marketing doesn’t force
you to go hunting for the ID that actually ships. Task type is the thing
you’re actually deciding — not “which model is smartest” but “what kind
of work is this.” Effort is the reasoning-effort dial
(low/medium/high/max) that goes with the model, because the tier and the
dial are the same decision made twice if you split them into separate
files.
The three rows map to three kinds of work I actually do, every day, across every project: orchestration and judgment calls that are wrong-once-and-it’s-expensive go to the top tier; mid-weight drafting and bulk edits that a subagent handles go to the middle tier; mechanical grunt work — scans, greps, per-item busywork where the failure mode is cheap and obvious — goes to the bottom tier. That’s it. No fourth row for “special cases,” because special cases are exactly the kind of local knowledge that belongs in a repo’s own override, not in the shared table.
How it’s wired: one import, one override
The file lives in a git-versioned personal vault, not inside any
single project. My global Claude Code config
(~/.claude/CLAUDE.md, loaded at the start of every session
everywhere on the machine) @imports it. That’s the entire
mechanism — no build step, no registry, no service. Every repo I open
inherits the same three rows the moment the session starts, because the
import happens before the session sees any project-specific
instructions.
The override path matters as much as the import. A repo is allowed to
override one row in its own CLAUDE.md — a project that does
almost nothing but mechanical bulk edits might permanently pin the
middle tier down a notch, or a security-sensitive repo might promote
review work up a tier regardless of what the shared table says. The
override is local and explicit, which is the point: the shared file is
the default, not a mandate, and a repo that needs to diverge says so in
its own config where anyone reading that repo can see why.
The rule that keeps the whole thing from rotting the same way the scattered version did is one sentence baked into the file itself: change a model or a tier here, and only here — every consumer inherits it. That sentence is doing real work. It’s the difference between a table that stays canonical and a table that becomes one more copy the moment someone “just quickly” hardcodes an ID somewhere convenient.
It’s the same earned-entry discipline I use for CLAUDE.md itself: don’t add a row speculatively, add it because a real duplication just cost you something, and prune anything that stops being true. The table is smaller than most CLAUDE.md files for exactly that reason — three rows have survived because three rows are all the ones that have actually earned their place so far.
What a swap actually looks like
This is the part that justifies the whole exercise: what happens the day a model gets deprecated, repriced, or a better option ships.
Before the file existed, that day meant an audit. Grep every repo for the old model string, one at a time, replace it, hope you didn’t miss a subagent config buried three directories deep, hope the replacement didn’t silently change the reasoning-effort dial along with the model name because those two facts lived in different places. After the file exists, that day is a one-line diff to a single row, plus a line in the changelog section at the bottom of the file recording what changed and when. Every repo that imports the table picks up the new model on its next session, with zero repo-level edits, because none of them ever hardcoded the name — they all deferred to the one file that did.
I applied the identical move one level up, three days after I built this table. I run a separate sibling file — same mechanism, same import, same edit-once-everywhere property — that isn’t about which model to call but about how to reason once you’re in a session: read the actual intent before solving, re-derive facts instead of recalling them, mark certainty levels honestly, attack your own conclusion before shipping it. That file has nothing to do with model names; it’s the operating discipline a session should follow regardless of which model is running it. The point of building both the same way is the same point twice: neither the model choice nor the reasoning habit should be something you re-litigate per repo. Get it right once, in one file, and let everything else defer to it.
Neither the model choice nor the reasoning habit should be something you re-litigate per repo.
That’s the mechanics side of a bet I’ve made in more detail elsewhere: your accumulated agent knowledge should outlive any single agent, because nobody knows which vendor is ahead a year from now. This post is the routing half of that bet — not the argument for why portability matters, but the specific, boring artifact that makes model choice portable in practice.
Enterprises are converging on the same shape
I don’t want to oversell the parallel, but it’s worth naming plainly: this is the same architecture the largest software company on earth just described in public. Satya Nadella posted on X that the move is “using the right model for each task,” with harness, memory, context, and skills deliberately externalized outside of the model itself. I read the memo itself in the postscript to my token-capital piece — the point that belongs here is narrower. Microsoft’s version of this file is Foundry plus first-party evals plus traffic-routing infrastructure sized for a company with a model family of its own to route toward. Yours is one markdown table in a git repo. The shape is identical; the budget is the only thing that isn’t.
What this file does not do
Be precise about the boundary, because it’s easy to oversell a pattern this simple. The effort table routes. It does not evaluate. It tells you which model handles which class of work; it has no opinion on whether that assignment is actually correct, and it never will, because a static markdown table can’t watch outcomes.
The judgment about whether Haiku-tier is actually good enough for
your mechanical scans, or whether your orchestration work genuinely
needs the top tier every time, still has to come from somewhere that
watches real output against real requirements. On this site, that’s the
test suite — mix test and a domain-specific health check
that gates the SEO and content invariants I actually care about, and
doesn’t care in the slightest which model produced the diff it’s
checking. That’s the eval. The effort table just decides who gets to
attempt the work; the test suite decides whether the attempt was good
enough. Route with the table, judge with the suite, and don’t let the
first one pretend to do the second one’s job.
What to do this week
You don’t need the vault infrastructure to start — the vault itself is a separate, later decision if you get there. The table works as a standalone file on day one.
- Write the three-row table today. Task type, effort dial, model, ID. Don’t overthink the tiers — orchestration/judgment, mid-weight drafting, mechanical grunt work covers almost everything.
- Put it in git, not in a repo. A personal or team vault, versioned, separate from any single project — so it survives that project getting archived.
- Import it globally, override locally. One line in your global agent config to pull it into every session; let individual repos override a row only when they have a real reason to.
- Add the one editing rule. “Change a model or tier here, and only here.” Write it into the file itself so the discipline doesn’t depend on anyone remembering it.
- Keep a changelog at the bottom. Every swap gets a dated line. Six months from now you’ll want to know when and why a model moved tiers, and the file is the only place that history should live.
- Let your test suite stay the judge. Don’t ask the table to do more than route. If a model assignment is wrong, that shows up in your review gate or your test failures, not in the table.
If you’re building this out for a team rather than just yourself — where the override question turns into a real governance question about who gets to touch the shared file — that’s the kind of setup work I help AI startups and engineering teams get right the first time. Let’s talk.