Build1 publisher3 min readPublished
AI agents ported Bun's 535,496 lines of Zig to Rust, validated by a language-independent test suite
Bun's port from Zig to Rust landed in four months because its test suite was written in TypeScript, independent of the language underneath, and because separate agents wrote the code and reviewed it.
The Engineer · Build desk
What happened
- Jarred Sumner shipped Bun rewritten from Zig to Rust, against his own published estimate that a small team of engineers would need a full year and a freeze on bugfixes, security fixes and features.
- Most of the port ran on a pre-release version of Claude Fable 5 across about 50 dynamic workflows, spread over four workspace shards of 16 agents each for 64 Claude instances at once.
- Sumner put the pre-merge spend at 5.9 billion uncached input tokens, 690 million output tokens and 72 billion cached input token reads to reach a fully passing test suite.
- More than a million lines of generated code passed that suite, after which further testing and validation surfaced additional issues.
- The Bun team says the Rust implementation in v1.4.0 resolved 128 longstanding bugs present in v1.3.14 and addressed native memory leaks.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint The precondition is an oracle that survives the language you are deleting. A team whose tests are written in that same language has to build the suite first, outside the token bill.
- decision The question at a rewrite review changes from how many lines there are to whether the test suite is coupled to the implementation language. That coupling is an auditable property of the repository.
- cost Budget holders now face a comparison between token spend and engineer-years, and Sumner's figures put the substitution well under six figures per engineer-year.
- exposure Residual risk concentrates where Zig and Rust look alike and mean different things. The borrow checker does not flag that class, so diff review and fuzzing have to.
Sumner wrote the mapping down before scaling the port. PORTING.md held the Zig-to-Rust pattern and type equivalences, and LIFETIMES.tsv recorded the lifetime of every struct field in the codebase; Sumner credits both as key success factors [10]. An implementer agent translated Zig files using those two documents [11]. Two reviewer agents ran in isolated context windows with access only to the file diffs, and their only task was to discover bugs and behavioral divergences [12]. A fixer agent handled what they reported [12]. "The implementer doesn't review. The reviewer doesn't implement," Sumner wrote [13]. When an error came out of the loop, he improved the implementation process instead of patching the generated code by hand [14].
Peak throughput was roughly 1,300 lines of code a minute and as many as 695 commits an hour [16]. Those two figures imply about 112 lines per commit [2]. Nobody reads 1,300 lines a minute, so the reviewers are models too. Running that many writers against one repository brought its own problems: concurrent updates to the shared codebase, and starvation of limited compute [25].
Reaching a fully passing suite cost about $165,000 at API pricing [17]. Across 535,496 lines of Zig that is about 31 cents a line [1]. Sumner's own comparison was labour: "By hand, I think this would've taken 3 engineers with full context on the codebase about a year," he wrote [18]. Three engineer-years at that price is roughly $55,000 an engineer-year [4].
The condition that made the loop possible is the one Sumner flags himself. "Fortunately, Bun's own test suite is written in TypeScript which means it doesn't depend on the runtime's programming language," he wrote [6]. The generated Rust was checked against more than a million assertions [9]. For the four-month figure to transfer, a codebase needs a suite that outlives the language being deleted, assertions dense enough to catch a transpiler's mistakes, and a run cheap enough to execute thousands of times. A JavaScript runtime is the easy case: its tests are written in the language it implements, not the language it is implemented in. A Zig library tested in Zig loses its oracle on day one of the port, and someone has to write the replacement suite.
The suite passed, and the testing continued. The mechanical port left 19 subtle semantic regressions rooted in syntactic similarities between Zig and Rust [20], about one per 53,000 lines of generated Rust [5]. Eleven rounds of security review from Claude Code Security fixed several security issues [21]. Round-the-clock coverage-guided fuzzing of every parser in Bun produced 15 pull requests [22].
The reason Sumner gives for accepting all of that is the feedback loop. A large share of Bun's bugs were use-after-free, double-free, and forgotten frees on error paths; in safe Rust those are compiler errors, with RAII-like automatic cleanup through Drop [26]. "Compiler errors are a better feedback loop than a style guide," Sumner wrote [7].
What to watch
- Whether more same-class semantic divergences turn up in v1.4.x bug reports now that users are running the Rust build.
- Whether Bun publishes the planning artifacts from the port, so other teams can test the method.
- Whether anyone reproduces the result on a codebase whose tests were written in the language being replaced.