DEV Community

Piekwerk
Piekwerk

Posted on

model: haiku stopped meaning one thing. Pin the exact model id.

Claude Code 2.1.293 shipped on October 7 with one line that looks like routine model plumbing: "Added Claude Haiku 5.5 (claude-haiku-5-5), now the default Haiku model on the Anthropic API." Read it twice, because one phrase is doing all the work: on the Anthropic API. The changelog does not say the alias moved everywhere. It moved on the first-party API. Bedrock and Vertex installs keep resolving haiku to 4.5. I keep a config in version control that says model: haiku, and as of this week that line means two different models depending on which endpoint the session authenticates to.

Same config, two models

Here is the setup that breaks. Your team standardizes on one checked-in settings.json with model: haiku. A developer on a first-party API key gets Haiku 5.5: 1M token context, new pricing. A teammate whose org routes through Bedrock gets Haiku 4.5: 200K context, the old rate card. Both ran the same commit of the same config the same morning. Both are sure they know what model answered. One of them is wrong, and nothing in either session shouts the difference.

The subagent bill nobody approved

Subagent definitions make it worse. A subagent pinned to haiku for cheap summarization now sees a 1M context window on first-party sessions. Work that used to fail with a context error now runs. That is mostly good news, but it changes token spend: the changelog lists $0.50/$2.50 per Mtok for prompts over 100K. A summarizer that quietly starts eating 300K-token prompts costs five times the headline rate, and it only happens on the sessions where the alias flipped. Nobody files a ticket for a cost that arrives through an alias, because there is no diff to point at.

Why bare aliases are a config smell

An alias is a promise the platform reinterprets under you. haiku meant 3.5, then 4.5, now 5.5 depending on provider. Every reinterpretation is invisible at the config layer: the line still reads model: haiku, the diff is empty, the behavior moved. This is the same failure mode as an unpinned dependency version, with one difference. You can lock a dependency and forget it. A model alias locks nothing; it is a name the vendor rebinds.

The fix costs one line per place. Write the exact id where the choice matters: claude-haiku-5-5 when you want the new model and its 1M window, claude-haiku-4-5 when you want the cheap predictable one you already tested. Keep the alias only where you genuinely mean "whatever the vendor calls Haiku this quarter," and say so in a comment, because the next person to read the config deserves the warning.

The two-minute alias audit

One grep finds every bare alias in a repo's agent config surface:

grep -rn "haiku" ~/.claude/settings.json .claude/ 2>/dev/null \
  | grep -v "haiku-[0-9]"
Enter fullscreen mode Exit fullscreen mode

Every hit is a line where the provider decides the model. Do the same for the places hooks and CI wrappers spawn the CLI with a model flag. It takes two minutes and it catches the drift while it is still a diff you choose, not a bill you explain. This is the same audit that would have flagged Copilot's model-policy split, where four config surfaces decide what runs your subagents.

What I pin and why

I run agent configs as reviewed, version-pinned files, which is the core of what AgentConfig Studio ($29) ships: 12 stacks, each with a validator that fails loud when a rule stops firing. If you want to see the shape before trusting the format, the Next.js kit is free and MIT licensed.

The quiet version is coming

The alias split this week is the loudest recent example of a setting that moved without a diff. There will be a quieter one next month, on some field nobody greps for. The discipline is the same either way: the config is code, it drifts like code, and the tools that keep code honest apply to it directly.

Sources

Top comments (0)