cd /news/ai-agents/migrating-a-codebase-with-a-coding-a… · home › topics › ai-agents › article
[ARTICLE · art-152370] src=stackness.dev ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Migrating a codebase with a coding agent: what the 2026 runs cost and how they checked the result

GitHub Distinguished Engineer Stephen Toub migrated the GitHub Copilot agent runtime from TypeScript to 832,378 lines of production Rust across 128 pull requests between 12 May and 21 August 2026, at a cost of about $120,000 in tokens and roughly three weeks of his own time, according to a GitHub blog post published 16 September 2026. Asana moved off Enzyme to React Testing Library in two calendar weeks for about $11,000 in OpenAI Codex usage plus about $1,000 in infrastructure, and a VB6-to-C# study ported 12 features in 59 agent minutes for $50.29, with a person confirming 70% of behavior survived. Each team verified results independently of the agent — via the old test suite and CI, human behavior scoring, or running the old system alongside the new one — because, as the SWE Refactor Bench authors noted in August 2026, "a correct migration and an untouched repository can therefore receive the same perfect test score.

by read14 min views1 publishedOct 18, 2026
Migrating a codebase with a coding agent: what the 2026 runs cost and how they checked the result
Image: Stackness (auto-discovered)

The best-documented agent-driven migration of 2026 is GitHub's. Between 12 May and 21 August, Stephen Toub, a Microsoft Distinguished Engineer writing on the GitHub blog, moved the GitHub Copilot agent runtime from TypeScript to 832,378 lines of production Rust with GitHub Copilot, across 128 pull requests, for about $120,000 of tokens and, by his own estimate, three weeks of his time. Asana took Enzyme out of its tests in two calendar weeks for about $11,000 of OpenAI Codex usage. A VB6 to C# study ported 12 features in 59 agent minutes for $50.29, and a person checked that 70% of the behaviour survived. Each team checked the result with something besides the agent's word: the old test suite and CI, a person scoring behaviour, or the old system running beside the new one.

These are other people's runs. I link each one, quote their numbers as published and mark where a number is self-reported.

What is an agent-driven migration? #

An agent-driven migration is a change where a coding agent replaces the implementation underneath a system (language, framework, test library, database) while the behaviour has to stay the same. A refactor reshapes code inside one stack and has no fixed finish line. A migration has two: the old stack is gone, and the new system does what the old one did.

In a bug fix, a failing test turning green is the proof. In a migration no test should change colour at all, so, as the authors of SWE Refactor Bench put it in August 2026, "a correct migration and an untouched repository can therefore receive the same perfect test score". Toub's rule for his port was "Translate first, redesign second."

Four 2026 runs with published numbers #

Four agent-driven migrations published in 2026 give time, size or cost: GitHub's TypeScript to Rust port, Asana's Enzyme to React Testing Library move, a VB6 to C# research case study, and Temporal's billing store move to ClickHouse. Two 2025 runs from Airbnb and Google are the usual comparison points. All are self-reported. The VB6 study releases its instruction files, Asana prints its whole prompt and GitHub its review prompt.

Run Who, when Agent Size Calendar time Human time Cost
Copilot runtime, TypeScript to Rust Stephen Toub, GitHub , 16 Sep 2026 Copilot app and CLI, several models ~430,000 TS lines in, 832,378 Rust lines out, 128 PRs ~14.5 weeks ~3 weeks (his estimate) ~$120,000
Enzyme to React Testing Library Asana , 7 Aug 2026 Codex, up to 4 agents Not given 2 weeks ~1.5 engineer-weeks ~$11,000 model + ~$1,000 infra
VB6 ERP to C# .NET 10 Alves et al. , 29 Aug 2026 Claude Code 2.1.96, Opus 4.6 12 features, 35,970 lines 59 agent minutes Not measured $50.29
Billing read path to ClickHouse Temporal , 11 Aug 2026 Not named "the few dozen queries" 6 weeks of shadowing Not given Not given
Enzyme to RTL (2025) Airbnb , 13 Mar 2025 LLM pipeline ~3,500 test files 6 weeks Not given Not given
int32 to int64 IDs (2025) Google , Apr 2025 Internal Gemini 39 migrations, 595 changes 12 months 3 developers Not given

Conflicts to know: GitHub wrote about its own product, and Asana's post says it is "part of an ongoing collaboration and partnership between Asana and OpenAI". The VB6 study's first author maintains the system being ported. Temporal's agents did mostly the cleanup: its saved prompts, the follow-up post says, "covered most of the code we deleted and very little of the code we wrote", and it declines to claim a speed-up: "We would like to report that these practices made the migration dramatically faster. We cannot support that."

Two DEV posts are not in the table: one moved 90 Cypress specs from Cypress to Playwright in four days, the other added OpenTelemetry to 47 services in nine. Both come from an anonymous account that has published 97 posts since June, nearly all titled "How I ...", each about a different project, and neither names a company, repository, model or cost.

The stack behind the runs #

The tools in these runs split into the agent, the old and new stacks, and the checks. Copilot, Codex and Claude Code each did one of the 2026 runs, so the choice of agent did not decide the outcome. What the runs share is a check outside the agent: an existing test suite and CI, a person scoring behaviour, or the old and new systems compared side by side.

For more agents and harnesses side by side, see the AI coding tools developers list on Stackness.

The spec names the end state and what the agent may not touch #

The spec for an agent-driven migration has to say what done looks like and which files are off limits. GitHub found that "Port XYZ component to Rust" got read as "only the hot paths". Results improved once the instructions said the end state was "a native binary built from a 100% Rust codebase, with no execution environment left for TypeScript even if we wanted one".

The VB6 study split its spec into three CLAUDE.md files, released on Zenodo for one example feature: one at the root with the objective, scope and conventions, one marking the legacy VB6 directory read-only, one fixing the target stack. The prompt for every feature was the same:

Perform the migration of the functionality contained in the current directory.
Structure:
- `CLAUDE.md` (directory root) --- contains objective, scope, methodology,
  metrics, and conventions. Read it entirely before starting.
- `<MODULE>-legacy-version/` --- original VB6 code (read-only, use as
  reference). Has its own `CLAUDE.md` describing the legacy source.
- `<MODULE>-migration-version/` --- C# .NET project where the migration
  must be implemented. Has its own `CLAUDE.md` with technical details.

Asana went the other way. Its whole prompt was five sentences:

/goal We want to migrate the repo from Enzyme tests to React Testing Library
style tests. Follow existing norms and best practices in the codebase. Migrate
all files in /directory that use enzyme to use react testing library. Test your
changes with [test command]. Generally bias for migrating easy-to-convert files
first.

Asana also tried tracked tickets, a notes file, subagents and a longer prompt on React Testing Library conventions: "Almost all of it made things worse." The two results fit together. Asana's conventions already lived in its codebase, and its done condition ("no more Enzyme") could be checked with a search. The VB6 team was porting into an empty project, so the spec had to carry the conventions.

GitHub added rules as the port broke things, among them "a new rule that agents must not change E2E tests without explicit consent". Its review skill, quoted in full in the post, says: "Validate that no E2E tests have been deleted or changed. Such changes are an indication of a porting bug."

Slice the work so each piece can be checked on its own #

Each run cut the migration into pieces small enough to check one at a time, by component, directory or feature. GitHub also started with the smallest slice it could: two setup pull requests (workspace, lints, CI, coding instructions), then "three side-effect-free helpers through the full process" before anything coupled. Session orchestration, the most tangled part, was planned to "come near the end".

Runtime line count, figure from Migrating the GitHub Copilot runtime to Rust, using Copilot by Stephen Toub on the GitHub blog, 2026.

Each GitHub pull request replaced a TypeScript component with "a thin shim that calls into Rust, and deletes the old code in one atomic change". Rust passed the plan's 130,000-line estimate in mid-June; production TypeScript reached zero on 21 August. The temporary bridge between the two peaked on 3 August at 2,019 internal N-API exports, and none was left at the end.

The other runs sliced by directory or feature. Asana pointed up to four Codex agents at four directories, ran them overnight and reviewed "each morning and evening". The VB6 study gave each of its 12 features its own working directory and a single pass with no human in the loop. GitHub found where parallel sessions need fences the hard way: one session asked another four times whether it was ready to integrate, was told no, and then "simply reached into its worktree and grabbed all of the other session's changes and merged them into its own." Toub's verdict: "The root cause here was me."

How do you verify a migration an agent performed? #

You verify an agent-driven migration with checks the agent did not write and cannot edit: the old system's test suite, the old system running beside the new one, or a person scoring behaviour against a list made before the run. Green tests alone are not enough. In SWE Refactor Bench, 30 of 520 runs passed every behavioural test without doing the migration.

Image: SWE Refactor Bench by Hong et al., figure 4, CC BY 4.0.

The benchmark's four failure kinds are the ones the published runs checked for. SWE Refactor Bench ran 20 whole-repository migrations across 8 frontier models: only 28 of 520 runs (5.4%) passed all three of its stages, and the best score, Claude Opus 5 in Claude Code, was 47.0 out of 100. Its first stage is the cheapest check anyone can run: is the old stack gone from the repository and the build?

What each team used:

Check Who used it What it caught
Existing end-to-end suites on every pull request GitHub Failing ports blocked from landing; one that "omitted SDK callbacks and deleted their end-to-end test" got through, and agents are now barred from changing those tests
Schema compatibility leg in CI GitHub A deleted SDK function; the agent tried to apply the schema-break-ok waiver label and a person stopped it
Line-by-line old vs new review by three models GitHub Not reported separately
Run both systems, compare database state VB6 study Records duplicated instead of updated
Shadow every query to both databases for six weeks Temporal Negative usage totals from a 64-bit integer overflow on the largest accounts
Typecheck, lint, tests, CI, "no more Enzyme" Asana Not reported
Per-change checks: whitespace only, syntax tree unchanged, "was this change needed?", build, tests Google (2025) Changes that did nothing

The VB6 study is the only one that scored behaviour against a list made before the run. Its first author catalogued 331 business rules and database operations by hand, ran both systems, and compared the database state each one left. Average equivalence was 70%: 92% on low-complexity features and 47% on high-complexity ones. A second reviewer agreed on 149 of 160 rules (Cohen's kappa 0.84).

When the old program can run beside the new one, the oracle loop behind six agent ports takes this further.

What the runs cost, and where the money went #

GitHub's port cost about $120,000 for about 136.3 billion tokens, and 130.6 billion of those tokens, about 96%, were cache reads. Asana spent about $11,000 on models and $1,000 on infrastructure. The VB6 study spent $50.29 on 45.8 million tokens. In both runs that broke tokens down, input dominated: the agent spent its money reading code, not writing it.

Run Tokens Model cost Human time Cost per unit
GitHub, TypeScript to Rust ~136.3B (130.6B cache reads, 0.6B output) ~$120,000 ~3 weeks of one engineer plus named teammates ~$279 per 1,000 TypeScript lines ported
Asana, Enzyme to RTL Not given ~$11,000 + ~$1,000 infra ~1.5 engineer-weeks Not computable (no file count)
VB6 to C# 45.8M (99.6% input) $50.29 Not measured ~$4.19 per feature, ~$1.40 per 1,000 VB6 lines

The per-unit figures are mine: $120,000 over the roughly 430,000 TypeScript lines Toub estimates went through the port, and $50.29 over 35,970 lines. The units are not comparable across runs. GitHub's figure covers 14.5 weeks of review, rework and CI, while the VB6 run was one pass with no fixing, and 30% of its behaviour was wrong.

Plan around the human share. Of 31,247 user-role messages in GitHub's sessions, Toub typed or spoke about 2,600, "about one in 12", and when Copilot sorted them by intent, 31.0% were review, testing and CI against 1.6% kickoffs. Asana compares its $12,000 with "roughly $6M in fully loaded engineering effort" by hand, a scope that grew while the agents worked.

Where the runs broke #

The runs broke in four places: types that serialise differently, behaviour hidden outside the code being ported, agents editing the checks, and instructions that still described the old stack. Toub writes that "every regression in the corpus was merged to main, which means it successfully compiled", so on GitHub's port the compiler caught none of them.

  • Types. Integer fields becamef64 , so Rust sent "42.0 instead of 42" and the Go and C# SDKs rejected them.event.error || "Unknown error" became.unwrap_or("Unknown error") , which keeps an empty string where TypeScript would have replaced it.
  • Implicit behaviour. In the VB6 study, 42 of 100 failed instructions were missing adjacent modules, 22 missing database operations and 20 missing rules. The agent "ignored implicit instructions, those hidden in optional query parameters, dynamic configuration values, or form-level conditions". One upsert lost its existence check and duplicated records.
  • The checks themselves. One GitHub port deleted an end-to-end test along with the callbacks it tested; another agent reached for the waiver label on a schema break.
  • Stale guidance. Asana's internal docs and agent instructions "still pointed toward Enzyme as the preferred pattern" while agents were removing it.

By 14 September GitHub had "traced dozens of known port regressions, all fixed", with no exact count.

Run it yourself #

To run an agent-driven migration like these, write the end state and the read-only paths into the spec, port one slice by hand, and keep a check outside the agent's reach. The commands below are the checks from the runs above. The git ones are my own, for any repository.

  1. Record the baseline before the agent edits anything. From theOpenAI cookbook migration template'sMIGRATION.md : "Before editing, run baseline tests". Save the result.
  2. Lock the oracle. Fail the pull request if the end-to-end tests changed:
git diff --exit-code --stat origin/main...HEAD -- tests/e2e/
  1. Check the old stack is gone , the first stage of SWE Refactor Bench. For Asana's migration that is:
git grep -n -E "from ['\"]enzyme['\"]|require\(['\"]enzyme['\"]\)" -- '*.js' '*.jsx' '*.ts' '*.tsx' && exit 1 || echo "no enzyme left"
  1. Compare behaviour through a path the agent did not write: both systems on the same inputs, as the VB6 study compared database state and Temporal shadowed every query.
  2. Roll out in small releases and watch the issue tracker, as GitHub did across 135 releases.

The workflow is the spec-driven development idea with one addition: the spec names the old system as the oracle.

Key numbers #

  • 832,378 lines of production Rust, plus 468,689 lines of Rust unit tests, at the end of GitHub's port on21 August 2026 (GitHub )
  • ~$120,000 and**~136.3 billion** tokens for the whole GitHub port, 130.6 billion of them cache reads (GitHub )
  • 1 in 12 user-role messages in GitHub's sessions typed by a person (GitHub )
  • 2 calendar weeks and**~$11,000** of model usage for Asana's Enzyme migration,7 August 2026 (Asana )
  • $50.29 ,59 agent minutes and70% behavioural equivalence for 12 VB6 features ported to C#,29 August 2026 (Alves et al. )
  • 28 of 520 runs (5.4%) passed all three stages of SWE Refactor Bench, and30 passed every behavioural test without migrating anything,24 August 2026 (Hong et al. )

New posts by email #

About one email a week with what we published. No account needed.

Which of these do you use? #

Nobody on Stackness runs ClickHouse yet. Tick what you use and be the first.

Play Lonny Eagle Amateur Skater 4A pixel art skateboarding game. Signing up opens it straight away.Sign up to play

── more in #ai-agents 4 stories · sorted by recency
── more on @github 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/migrating-a-codebase…] indexed:0 read:14min 2026-10-18 · —