Source: ai-research/claude-blog-ai-code-migration.md — Anthropic first-party blog post, claude.com/blog/ai-code-migration, published July 16, 2026 (the newest post on the Claude blog at fetch time).
Anthropic’s own generalized methodology for large-scale code migrations with Claude Code, distilled from two internal examples run “in the last month”: Jarred Sumner’s Bun Zig-to-Rust port (previously covered in this wiki via Jarred’s own blog and the dynamic-workflows announcement — see Dynamic Workflows) and Mike Krieger’s Python-to-TypeScript port of an internal Anthropic Labs tool (new to this wiki). The article’s core thesis: “you don’t fix the code. You fix the process (loop) that produced the code.” Where the existing wiki coverage documents dynamic workflows as a Claude Code feature and the Bun port as a flagship result, this article is the first-party methodology — a reusable six-step process plus a “why now” economic argument for migrations that were previously multi-year, existential bets.
Key Takeaways
- The economics flipped, not just the capability. A production migration no longer requires freezing the roadmap for a multi-quarter, career-risking bet on 90%+ parity. The worst case is now “delete the branch and try again.” Migrations still cost tens to hundreds of thousands of dollars (Bun: ~$165,000 at API pricing; Mike’s main port: ~27 million tokens) — bounded and recoverable, not existential.
- Five properties make migrations an unusually good fit for agentic coding, more so than general feature work: the work parallelizes across thousands of independent units (files/crates); the old codebase is a comprehensive spec and reference; a test suite is a built-in, objective referee (no human arbitration needed); compiler/test failures write the next work item automatically; and violations get promoted into rulebook entries instead of silently drifting.
- The judge comes before the migration, not after. Build and validate a verification harness first: categorize which existing tests are externally expressible vs. internals-dependent, rewrite the portable ones as assertions that run against both codebases, then validate the judge itself by confirming it passes on the original code and fails on deliberately broken code.
- The rulebook-first, gap-inventory-second ordering is load-bearing. The gap inventory is defined by what the rulebook’s defaults don’t cover — building it before the rulebook exists has nothing to anchor against.
- A cheap “shakedown cruise” (Step 2) catches critical rule errors before they fan out. Jarred ran 3 files through 3 different agents (rulebook-follower, “senior engineer,” diff-to-new-rule) and caught two critical issues before they would have propagated across all 1,448 files — then threw away every translated file from the test, keeping only the rule corrections.
- Model tiering is a first-class cost lever: smaller models (Sonnet, in Mike’s case, fanned out across 12 subagents) handle high-volume implementation; the largest models are reserved for adversarial reviewers and for writing rules that every subsequent agent will follow.
- A missing test suite doesn’t block the process — Claude can build the referee itself. Mike’s team lacked a full ported test suite; Claude built a 7-scenario parity harness, then went further and designed its own end-to-end suite, running it autonomously overnight for four consecutive nights to catch paper cuts no scenario list would have predicted.
Why and When to Migrate
Teams migrate languages when a known trade-off becomes limiting, a better approach has emerged, or the original ecosystem is shrinking. Jarred’s original 2019-era choice of Zig traded some safety guarantees for C-level performance and radical simplicity — the right call for “writing Bun in 1 year in a cramped Oakland apartment pre-LLM.” By 2026, with Bun’s CLI at 10M+ monthly downloads and used extensively inside Claude Code itself, that original trade-off started to bind.
Mike’s impetus was concrete and narrow: an internal tool’s Python-toolchain compile step took roughly 8 minutes per platform (30 minutes across the full build matrix) on every release. After the TypeScript port: ~2 seconds, the binary starts 6x faster, and the team retired a separate deployment pipeline entirely.
The framing Anthropic offers: “the migration case no longer needs to be existential. A year of memory-bug patches in the changelog, or one chronic bottleneck, can now justify it.”
Why AI Changes the Migration Math
Large migrations suit agentic coding specifically because of five properties, per the source:
- The work is parallel — thousands of independent units (files, crates) let agents work simultaneously rather than queue behind each other.
- Context is clear and comprehensive — the old code is both the spec and the reference document for the translation rulebook.
- There’s a built-in referee — an existing test suite gives objective verification, so “the model can grind against a ground truth for days without a human arbitrating quality.”
- The queue writes itself — every compiler or test failure becomes the next work item automatically.
- Drift has nowhere to hide — reviewers cite the specific rule behind every finding, turning a violation into a queue item instead of a silent divergence; when an agent hits a genuine edge case, the fix is promoted into a rule every subsequent agent follows.
Both flagship migrations used Claude Fable 5 in an advisory pattern across model classes specifically to optimize token consumption — matching the “don’t use the largest model for everything” best practice below.
The Six-Step Process
Prerequisites — build and validate the judge
Before anything else, build a verification harness that can evaluate original and ported code on equal terms:
- Categorize existing tests — which are expressible as external calls (portable) vs. dependent on internals that won’t exist in the target language.
- Rewrite for portability — convert externally-expressible tests into assertions runnable against both codebases; use adversarial agents to confirm the rewrite didn’t weaken the original assertion.
- Validate the judge itself — run it against the original code (must pass) and against deliberately broken code (must fail). “A judge that doesn’t catch breakage isn’t a judge.”
Jarred had an existing TypeScript test suite to lean on; most projects won’t. Mike instead built a 7-scenario parity harness from scratch and treated any behavioral difference as a bug.
Step 1 — Rulebook, dependency map, gap inventory
Order matters: rulebook before gap inventory — the gap inventory is defined by what the rulebook’s defaults don’t cover.
-
Rulebook. Same-structure ports (Jarred’s Zig→Rust) get a lookup-table rulebook translating types/idioms, pointing to the gap inventory for hard cases. Full redesigns (Mike’s Python→TypeScript) get a design document instead. Jarred built his by chatting with Claude to form a policy per area of ambiguity, plus 8 subagents each reviewing for a different category of failure mode based on his own intuition.
-
Dependency map. Needed to order parallel workstreams (which files migrate first, which batch together). Claude Code can deploy agents to write and run a deterministic script that produces this map even for legacy codebases without explicit manifests.
-
Gap inventory. Captures where the target language has requirements the source didn’t — memory ownership (Zig’s manual free vs. Rust’s compiler-enforced drop) or interface contracts (Python’s duck typing vs. TypeScript’s declared interfaces). The source’s two worked code examples make the shape of this gap concrete:
- Zig → Rust: a Zig function returning an allocated buffer compiles fine even if the caller forgets to free it (leak surfaces only at runtime); the Rust equivalent makes double-free or forgotten-free not compile at all — ownership moves are enforced at compile time.
- Python → TypeScript: a Python
register(handler)function accepts any object with.setup()/.run()with no declared contract; the TypeScript equivalent requires an explicitinterface Handlerbefore anything compiles.
Jarred inventoried gaps up front; Mike translated first and audited for gaps afterward. “You may need to do both.”
Step 2 — Stress-test the rules (“shakedown cruise”)
A cheap mini-migration to validate the rulebook before committing to full-scale translation. Jarred ran 3 agents on 3 files each: one following the rulebook literally, one translating “like a senior Rust engineer,” and one diffing the two outputs to propose new rules. This caught two critical issues before they could fan out across all 1,448 files. Every translated file from this stress test gets thrown away — only the rule corrections survive. This step only works for structure-preserving migrations; a full redesign (Mike’s case) instead gets adversarial review of the design document directly, validated with a disposable end-to-end run.
Step 3 — Translate everything
The core implement → review → fix loop, run at scale:
- Model tiering: smaller models for implementers (Mike fanned out 12 Sonnet subagents for the main migration), larger models reserved for reviewers and rule-writing.
- Mechanical, resumable work queue: a batch script checks whether each translated file exists on disk to determine what’s left — because the queue rebuilds from disk state every time, the whole migration is resumable by construction.
- Anything an implementer can’t confidently translate gets flagged
// TODO(port): <reason>for the next step, rather than guessed at. - Two adversarial reviewers per implementer, working in separate contexts; disagreements escalate to a third agent. A mistake that recurs across files becomes one rulebook sentence plus a batch regeneration — never a per-file hand-patch.
- Compiler placement is a genuine design choice: Mike ran the TypeScript compiler inside every loop iteration (checks a unit in seconds); Jarred banned the compiler from this loop entirely, deferring it to Step 4, because a full
cargobuild takes minutes.
Steps 4–6 — Compile, run, match behavior
These three share one loop architecture and need progressively less human judgment; Step 4 can dissolve into Step 3 depending on the language.
- Step 4 (compile). Jarred’s orchestrator invoked the compiler once across the whole workspace; “fixer agents” resolved the error list in parallel under adversarial review, then rebuilt. Systemic issues surface here — e.g., thousands of Rust module errors from fixing cyclic imports that Zig’s lazy compilation had tolerated, resolved by encoding classification logic for which dependency to delete, move, or restructure.
- Step 5 (run/smoke test). Crashes are the mechanical source of truth, grouped by root cause and reviewed by adversarial subagents.
- Step 6 (match behavior). Shard the translated, compiled, smoke-tested files and run the prerequisite-stage test suite against them. A build daemon is the only process allowed to rebuild the binary — it batches incoming patches, rebuilds once, re-runs affected tests, and reports back, serializing the single most expensive operation instead of letting agents trigger redundant rebuilds. Recurring failures move the fix upstream into the rulebook and regenerate only the affected files. Where no test suite exists at all (Mike’s case), Claude built one: a 7-scenario diff harness first, then its own full end-to-end suite, run autonomously overnight for four nights straight.
Best Practices
Six practices the source states held up across every migration:
- Don’t follow this guide blindly — plan the specific migration with Claude first; treat this as a starting point.
- Don’t focus on individual failures — that’s the loop’s job (fixer agents burn those down); human attention belongs on patterns.
- Make review adversarial and verification mechanical — let scripts (compiler, diff, test suite) be the referee, not a human arbiter or the implementer’s own self-report.
- Don’t use the largest model for everything — smaller models for high-volume implementation fan-out, largest models for reviewers and rule-writers.
- Front-load the human hours — the rulebook and stress test consume the most human time; everything after is mostly queues burning down.
- Make the work queue mechanical and resumable — “done” should mean “the output file exists on disk,” nothing softer.
Results
Bun (Zig → Rust, Jarred Sumner): a million lines of code produced in under two weeks; 100% of Bun’s existing test suite passing in CI before merge; 19 post-merge regressions surfaced and all fixed; shipped inside Claude Code in June 2026; now in production. ~4% of the Rust code sits in unsafe blocks (mostly single-line pointer operations at C/C++ boundaries). A 2,000-repeated-build memory benchmark dropped from 6,745 MB to 609 MB; binary 19% smaller on Linux and Windows; 2-5% faster across HTTP serving and workloads like next build and tsc. Token cost: 5.9 billion uncached input tokens + 690 million output tokens, ≈ $165,000 at API pricing.
Internal tool (Python → TypeScript, Mike Krieger): 165,000 lines of TypeScript produced over a single weekend; hundreds of agents; 8 phase gates; 3 adversarial review rounds; a final parity check diffing every command’s output against the Python original. Compile time per platform: ~8 minutes → ~2 seconds; binary starts 6x faster; a separate deployment pipeline retired. Token cost for the main port: ~27 million tokens.
A figure worth flagging against existing wiki coverage
This source states “a million lines of code were produced” for the Bun port. Dynamic Workflows — citing both Anthropic’s original 2026-05-28 announcement and Jarred Sumner’s own July 9 first-party blog — states “~750,000 lines of Rust” for the same port. ^[ambiguous] Neither source reconciles the two figures explicitly. A plausible read is that “produced” in this newer post counts cumulative/iterative output across the stress-test and fix loops (including translated files that were deliberately discarded per Step 2 and Step 3’s regeneration cycles), while “~750,000 lines” describes the final merged Rust codebase — but this is this wiki’s own inference, not a claim either source makes, so it’s flagged rather than silently reconciled. Two smaller figures move in the same direction without tension: the test-suite pass rate improved from 99.8% (at the original announcement) to 100% (per this newer post) — plausibly just later-stage cleanup between the two publish dates — and the 19% smaller binary figure here is consistent with the “~20% smaller” already cited (rounding, not a conflict).
Why This Belongs Next to Verification-Not-Trust
This methodology is the harness-level, migration-specific instance of a discipline the wiki already documents at the loop-engineering level in Verifier-First Loops: write the verifier before the loop runs, and make “done” a fact that lives outside the agent’s own explanation. Here that takes concrete shape as “the judge” prerequisite stage, the compiler/test-suite/build-daemon gates, and the “done means the file exists on disk” rule. A True-Scale Universe Atlas Built with Fable 5 demonstrates the identical discipline in a completely different domain (orbital mechanics validated against JPL Horizons ephemeris data) — both projects refuse to let a model’s self-report stand in for an external, mechanical check. Dynamic Workflows is the Claude Code feature (parallel subagents, adversarial convergence, resumability) this methodology runs on top of; this article is Anthropic’s own procedural playbook for pointing that feature at a migration specifically.
Try It
- Before scoping a migration, build and validate the judge first — a verification harness you’ve confirmed catches deliberately broken code is the actual prerequisite, not the rulebook.
- Write the rulebook before the gap inventory, not the other way around — the gap inventory only makes sense relative to what the rulebook doesn’t already cover.
- Run a 3-file, 3-agent “shakedown cruise” before fanning out to the full codebase — it’s cheap insurance against propagating a bad rule across every file.
- Tier your models deliberately: cheaper models for implementation fan-out, your best model for adversarial review and rule-writing.
- Use the starter kit at
github.com/anthropics/code-migration-kit-with-claude-codeas a generalized template (rulebook, dependency-map, gap-inventory, stress-test, and translation-kickoff prompts, plus abuild_daemon.shscript) — explicitly not what either flagship port actually ran on, so adapt rather than copy verbatim. - For legacy-modernization or framework-upgrade work (not a language port), look at the separate
code-modernizationplugin (github.com/anthropics/claude-plugins-official) instead — the source explicitly distinguishes it from the migration kit above.
Related
- Dynamic Workflows in Claude Code — the underlying orchestration feature (parallel subagents, adversarial convergence, resumability) this migration methodology is built on top of; includes prior Bun-port coverage this article’s Results section cross-checks.
- A True-Scale Universe Atlas Built with Fable 5 — a different-domain proof of the same verification-not-trust discipline (JPL Horizons ephemeris checks, physics gates, pixel-diff CI) at production scale.
- Verifier-First Loops — the general loop-engineering discipline this methodology instantiates for the specific case of code migration.
- The Verification Frontier — why migrations sit on the cheap-to-verify side: an existing test suite (or one Claude builds) is an authoritative, mechanical judge.
- Agentic Coding and Returns to Expertise — the human role in this methodology (writing the rulebook, judging the stress test, front-loading review) matches that piece’s argument about where expertise concentrates as agents write more code.
- Claude Fable 5 and Mythos 5 — the model both flagship migrations used, including the cross-model-class advisory pattern noted above.
- Claude Opus 4.8 — the second model class used alongside Fable 5 in both migrations.
- Claude Code Agent Teams — the adjacent persistent multi-instance coordination primitive; this methodology’s “implementer + adversarial reviewers” pattern is a workflow-shaped variant.
Open Questions
- The “a million lines produced” vs. “~750,000 lines of Rust” discrepancy (see above) is unresolved — worth checking Jarred Sumner’s own writing or a future Anthropic post for which figure (if either) is the more precise final-state number.
- No detail given on how the eight subagents Jarred used for rulebook review were prompted, or what the eight specific failure-mode categories were beyond “based on his own intuition.”
- The source doesn’t state whether the “advisory pattern” using multiple model classes (Fable 5 + Opus 4.8) means Fable advises and Opus implements, the reverse, or something else — flagged as genuinely unclear rather than guessed at.
- Whether the 10 total code packages migrated “in the last month” (mentioned in the opening) beyond these two flagship examples share the same six-step structure, or whether some used different approaches — not stated.