When you're running a product that integrates LLMs, there's one inevitable challenge:
How do you keep up with model generation changes?
Every time a new model is released, you need to update model IDs scattered across the codebase, fix tests, update documentation... Doing this manually is tedious and error-prone.
This article is about upgrading all Claude models in my workflow engine. It happened the day after my previous article (OpenAI Codex Model Migration Record), showing how the same design pattern proved its worth on the second iteration.
Context: What I'm Building and Why I Use Claude
First, some background.
I'm developing ai-workflow-agent, a workflow engine that automatically handles planning → design → implementation → testing → documentation based on GitHub Issue content.
Internally, it uses both OpenAI Codex models and Claude strategically. Code generation uses Codex, while requirement analysis and review use Claude. Users can specify models like --codex-model max or --claude-model opus using aliases, and the actual model ID resolution happens in one place in the code.
// Claude alias definitions (before migration)
export const CLAUDE_MODEL_ALIASES: Record<string, string> = {
opus: 'claude-opus-4-5-20251101', // Top tier, for complex tasks
sonnet: 'claude-sonnet-4-20250514', // Balanced
haiku: 'claude-haiku-3-5-20241022', // Lightweight, cost-efficient
};
This alias system was introduced during the previous model migration (gpt-5-codex → gpt-5.1-codex-max) when I realized "this will happen again." The design lets users work with aliases (opus, sonnet, haiku) while model ID changes are contained to this single constant definition.
I upgraded the Codex side to gpt-5.2-codex on February 8th. The next day, I decided to upgrade Claude as well.
Why Upgrade: The Claude 4.5 Family Arrives
Anthropic updated the Claude model lineup:
- Claude Opus 4.6 — Top tier (successor to Opus 4.5)
- Claude Sonnet 4.5 — Balanced (successor to Sonnet 4)
- Claude Haiku 4.5 — Lightweight & fast (successor to Haiku 3.5)
The first consideration when deciding whether to upgrade was cost.
Opus 4.5 → Opus 4.6: Input $5 / Output $25 → No change
Sonnet 4 → Sonnet 4.5: Input $3 / Output $15 → No change
Haiku 3.5 → Haiku 4.5: Input $0.80 → $1 / Output $4 → $5 (about 25% increase)
Opus and Sonnet prices stayed the same. Haiku saw a modest increase, but Haiku 4.5 reportedly delivers Sonnet 4-equivalent performance at 1/3 the price, so it's still worth it.
In the previous Codex migration, I kept mini unchanged because "5.2 series lightweight models aren't officially available yet." But for Claude, all models were ready, so I decided without hesitation to upgrade all three.
Full ID or Alias? — Changed Strategy Midway
Now for the actual work. I used Claude Code (Sonnet 4.5) to proceed.
My initial instruction to Claude Code was:
claude-opus-4-5-20251101 → claude-opus-4-6
claude-sonnet-4-20250514 → claude-sonnet-4-5-20250929
claude-haiku-3-5-20241022 → claude-haiku-4-5-20251001
I specified dated full model IDs, since that's what I did in the previous Codex migration.
But then I paused.
Just as Claude Code searched for affected areas, read files, and was about to replace—I manually canceled.
The reason: I reconsidered, "Don't Sonnet and Haiku work fine with aliases?"
Anthropic's official guidance also recommends alias formats like claude-sonnet-4-5 or claude-haiku-4-5. Aliases always point to the latest snapshot of that model family, so they automatically follow future minor updates.
In other words, what we're doing in our code (sonnet → actual model ID) is also being done by the API provider. Why not benefit from that?
I switched strategies:
claude-opus-4-6 ← Alias format (itself points to latest)
claude-sonnet-4-5 ← Undated alias
claude-haiku-4-5 ← Undated alias
However, this works for our product because we prioritize "always using the latest model for best results." For scenarios requiring strict reproducibility of generation results, pinning to dated full IDs (claude-sonnet-4-5-20250929) is the right choice. Which layer to pin at depends on your product requirements.
graph TD
A[Model ID Specification Choice] --> B{Is reproducibility<br/>the top priority?}
B -->|Yes| C[Full ID specification<br/>claude-sonnet-4-5-20250929]
B -->|No| D{Want to auto-follow<br/>minor updates?}
D -->|Yes| E[API alias<br/>claude-sonnet-4-5]
D -->|No| C
E --> F[Further abstraction with app alias<br/>sonnet → claude-sonnet-4-5]
The result was a two-layer alias structure: app alias (sonnet) → API alias (claude-sonnet-4-5) → actual snapshot. This structure wasn't consciously designed during the Codex migration—it emerged only when working on the Claude side.
Impact Scope and Legacy Model ID Debt
With the strategy decided, I proceeded with the replacement. The impact scope:
Source code (5 files):
- Alias definitions (the core)
- Type definition comments
- ContentParser default model
- Authentication validation model
- Follow-up Issue generation model (2 locations)
Test files (4 files), Documentation (4 files)
Total: 13 files, 63 lines changed.
What I noticed here: Claude side had "legacy models" remaining across multiple generations.
The Codex side only required replacing one version: gpt-5.1-codex-max. But Claude had old generation IDs specified in early development that remained scattered across locations. claude-3-sonnet-20240229 in follow-up Issue generation, claude-3-5-sonnet-20241022 as ContentParser default—like that.
Code written before the alias system was introduced just stayed there. Being able to unify all of these to claude-sonnet-4-5 in this migration was a modest but significant hygiene win.
All Tests Passed — Previous Lessons Applied
After replacement, I ran npm test. Result: all passed.
In the previous Codex migration, I had a scare when 18 test cases failed due to missed whitespace-padded alias test cases. This time Claude Code updated those test types too—but that wasn't "by chance." It's because I explicitly told it beforehand: "Update all expected values in test files too."
// Mixed case tests
expect(resolveClaudeModel('Opus')).toBe('claude-opus-4-6');
expect(resolveClaudeModel('SoNnEt')).toBe('claude-sonnet-4-5');
// Whitespace-padded tests
expect(resolveClaudeModel(' opus ')).toBe('claude-opus-4-6');
expect(resolveClaudeModel('\tsonnet\t')).toBe('claude-sonnet-4-5');
Having stumbled before taught me the insight: "You can't just search by alias name—you must also search by resolved model name or you'll miss things." Even as tools get smarter, experience gained from past failures is something humans should retain.
Operational Verification
After committing, I ran the actual workflow to verify:
2026-02-10 03:44:00 [INFO ] Using model override for Claude Agent: claude-opus-4-6 (phase=requirements)
2026-02-10 03:44:02 [INFO ] [AGENT SYSTEM] init
2026-02-10 03:44:05 [INFO ] [AGENT THINKING] I'll start by exploring the codebase...
Opus 4.6 was correctly recognized and the agent started normally. No issues.
What Two Migrations Revealed
Going through Codex and Claude migrations on consecutive days revealed something: alias system design proves its true value on the "second time."
First time (Codex): introduced the design. Second time (Claude): it paid off. Moreover, the Claude side added a layer of "API provider-supplied aliases," evolving into a two-layer design.
graph LR
subgraph App-level aliases
A[opus] --> B[claude-opus-4-6]
C[sonnet] --> D[claude-sonnet-4-5]
E[haiku] --> F[claude-haiku-4-5]
G[max] --> H[gpt-5.2-codex]
I[mini] --> J[gpt-5.1-codex-mini]
end
subgraph API alias layer
D --> D2[claude-sonnet-4-5-20250929]
F --> F2[claude-haiku-4-5-20251001]
end
Another insight: You don't need "perfect design from the start." Getting the system right on the second migration might be just the right timing. First time: notice "this will happen again." Second time: "the previous system worked—let's improve it further." As long as this cycle continues, model generation changes become manageable.
When the next model update comes, just change the alias resolution target in one line. That cycle now works for both OpenAI and Claude sides.
Diving Deeper into Claude Code
This migration work used Claude Code (Sonnet 4.5). For those interested in practical applications of Claude Code, the following books are valuable resources.
[📦 商品リンク: moshimo-book-9CeFY]
For a more introductory approach, this is also recommended.
[📦 商品リンク: moshimo-book-fINTJ]
Reference Books on Design
For those who want to learn more systematically about design patterns like the alias system, the following is recommended.
[📦 商品リンク: moshimo-book-MxbAm]