Build1 publisher3 min readPublished
Bun's 535,496-line Zig codebase was rewritten in Rust and validated against TypeScript tests
Jarred Sumner's four-month rewrite checked transpiled Rust against a TypeScript suite that does not depend on the implementation language, and reaching a fully passing run cost about $165,000 in tokens.
The Engineer · Build desk
What happened
- Jarred Sumner says Bun's rewrite from Zig to Rust shipped after four months of work, against his own estimate of a full year for a small team of engineers.
- The port ran all at once on a pre-release version of Claude Fable 5, orchestrated across about 50 dynamic workflows, transpiling Zig into Rust for checking against Bun's existing TypeScript tests.
- The work was distributed across four workspace shards running 16 agents each. That is 64 Claude instances on the codebase in parallel.
- At peak velocity the system generated roughly 1,300 lines of code a minute and logged up to 695 commits an hour.
- Getting the full test suite passing took 5.9 billion uncached input tokens, 690 million output tokens and 72 billion cached input token reads, around $165,000 at API pricing.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint The method needs a test oracle that survives the rewrite untouched. A team whose tests are written in the language being replaced would have to port the tests and the code together, and ported tests are no longer an independent check on the result.
- cost Anyone budgeting a repeat has to fund two phases: the token spend to reach a green suite, and a second stretch of security review and fuzzing whose cost InfoQ did not report.
- capability The objection that a rewrite freezes bugfixes and security work for a year now has a competing number attached to it, so a large port becomes something a maintainer can schedule.
- precedent A field-level lifetime inventory is now a prerequisite others will be asked for. Whoever proposes the next port of this size should expect reviewers to want the LIFETIMES table before the spend is approved.
The loop kept writing and checking in separate processes. An implementer agent translated Zig files using two reference documents: PORTING.md, which maps Zig patterns and types onto Rust ones, and LIFETIMES.tsv, which records the lifetime of every struct field in the codebase [8]. Two adversarial reviewer agents ran in isolated context windows with access only to the file diffs, and their only job was to find bugs and behavioral divergences [9]. A fixer agent handled what they reported [11]. "The implementer doesn't review. The reviewer doesn't implement," Sumner said [10].
When the loop produced an error, the response was to improve the implementation process rather than hand-edit the generated code [12]. Running the implementers in parallel brought its own problems: concurrent updates to a shared codebase, and starvation of limited compute [24].
Held at peak, 1,300 lines a minute would reproduce 535,496 lines of Zig in about seven hours [1]. At 695 commits an hour, one commit lands every 5.2 seconds [2]. The port took four months [2], so validation and rework were the limiting step.
What made validation possible is specific to Bun. "Fortunately, Bun's own test suite is written in TypeScript which means it doesn't depend on the runtime's programming language," Sumner said [4]. The transpiled Rust, unsafe in places and flagged for refactoring later, was checked against that suite's more than one million assertions [7]. Sumner's own account of the first week is that he did not expect it to work, and changed his mind when a high percentage of the suite started passing and the Rust matched the original Zig closely [22].
Validation continued after the suite passed. The port's mechanical character introduced 19 subtle semantic regressions rooted in places where Zig and Rust look alike and mean different things [18]. Eleven rounds of security review with Claude Code Security fixed several security issues [19]. Round-the-clock coverage-guided fuzzing of every parser in Bun produced 15 pull requests [20]. According to the Bun team, the Rust implementation in v1.4.0 resolved 128 longstanding bugs present in v1.3.14, and native memory leaks were addressed [21].
Sumner's stated reason for targeting Rust is the compiler. He said a large percentage of bugs are use-after-free, double-free, and frees forgotten in an error path, and that in safe Rust those show up as compiler errors, with RAII-like automatic cleanup through Drop. He said a compiler error is a better feedback loop than a style guide [5].
Against 535,496 lines of Zig, the $165,000 token spend works out to about 31 cents a line [3]. "By hand, I think this would've taken 3 engineers with full context on the codebase about a year," Sumner said [15]. That token figure is the pre-merge number. InfoQ did not report the cost of the security review and fuzzing that came after [17].
What to watch
- Whether Bun publishes the 19 semantic regressions individually, since the classes of Zig and Rust look-alike constructs are the transferable part.
- Whether PORTING.md, LIFETIMES.tsv or the roughly 50 workflow definitions are released. With those in hand, another team could price the planning phase.
- Whether anyone repeats the method on a codebase whose tests are written in the language being replaced.