Bun rewrote a million lines from Zig to Rust in eleven days
Bun — the JavaScript runtime that replaces Node, now owned by Anthropic — builds and ships its binary for six OS/architecture combinations: Linux and macOS on x64 and arm64, Windows on x64 and arm64. On May 3rd, that code was still written in Zig. By the 9th, already rewritten in Rust, it compiled cleanly and passed the full test suite on the first of those six platforms, Linux. By the 14th, at 12:23 a.m., the same was true on all six at once. In between: 6,502 commits, over a million lines added to the final pull request, and not one of those million lines written by a person. Bun had just rewritten itself from Zig to Rust in eleven days, with 64 instances of Claude Code working in parallel under a single human engineer’s supervision.
Jarred Sumner, its creator, published the full account on July 8th under the title “Rewriting Bun in Rust.” It’s a long, technical post, and for anyone who works with coding agents, a genuinely interesting one: it describes, in unusual detail, how you organize an army of models without producing a disaster. Six days later, Andrew Kelley — Zig’s creator — published his response. The headline that stuck was The Register’s: “unreviewed slop.”
What makes this story worth telling isn’t who’s right. It’s that both posts answer, from opposite ends, the question this year has made impossible to avoid: if an agent can write a million lines in a week, what does “review” even mean for that code?
A runtime that had spent years fighting its own memory
The official reason is, technically, reasonable. Zig gives full manual control over memory and has no implicit constructors or destructors: every free depends on someone remembering to write the matching defer at every call site. Bun, on top of that, mixed that model with JavaScript’s garbage collector, a combination Sumner describes with surgical precision: “mixing GC with manually-managed memory is an uncommon enough thing for software to need that no language really designs for it.” The result, over the years, was a recurring list of named crashes: a use-after-free in node:zlib, another in node:http2, a double-free in the CSS parser.
Rust doesn’t remove that class of bug through compiler talent. It turns it into a compile error. That was the core argument: change languages so the borrow checker mechanically and unconditionally does what, in Zig, depended on a human — or, increasingly, an agent — remembering to do it right every single time.
The rewrite wasn’t a rewrite, it was an assembly line
What separates this project from “I asked Claude to translate my code” is how much structure Sumner built before a single line of Rust existed. The first three hours went into process documentation, not product: a PORTING.md mapping Zig patterns to Rust ones, and a LIFETIMES.tsv analyzing the lifetime of every field in every struct in the codebase, reviewed twice adversarially before any agent touched real code.
Once the guides had been tested against themselves, the team ran a first trial on three files, using the same review architecture that would later be replicated at full scale (more on that in the next section). Only once that cycle worked at small scale did production start for real: all 1,448 .zig files converted to .rs simultaneously, spread across 4 worktrees of 16 Claudes each — 64 agents running at once. Compiler errors — around 16,000 at the peak — were grouped by crate and treated, literally, as a work queue to drain. At peak speed the system produced 695 commits per hour; in one specific minute, 58.
That number is worth pausing on: 58 commits in sixty seconds is close to one a second, sustained, generated by a process no human was reading line by line while it happened. The question isn’t whether that’s possible — clearly it is, the diff merged and compiles on six platforms. The question is what replaced human reading during that minute.
The reviewer was also Claude
Bun’s answer to that question has a name: adversarial review. The architecture used for every real change — not just the three-file trial — explicitly separated roles: one implementer Claude wrote the port, two independent reviewer Claudes received only the diff, with no context on why it had been written that way, and actively hunted for reasons to reject it. “The implementer doesn’t review. The reviewer doesn’t implement,” Sumner sums up. The example Bun itself chose to illustrate the mechanism is telling: one reviewer caught a Box<Pipe> being dropped while libuv still held an active pointer to it — exactly the family of use-after-free bug that had driven the team away from Zig in the first place. The rewrite had to prove, from the inside and with its own tools, that it could catch the very disease that caused it.
Those are the good kind of bug: the sort a compiler doesn’t flag, a shallow test doesn’t cover, and that only surfaces when someone — or something — reads the code actively asking “how do I break this?” So far, the design holds up, and it’s probably the part of this story most worth stealing for any team using agents seriously: don’t ask the same process to write and to grade itself.
But it’s worth not closing the thought there, because the design itself reintroduces, one level up, the problem it claims to solve. The “adversaries” doing the reviewing aren’t independent in the sense a human engineer would be — with memory, their own incentives, and the ability to refuse to approve something for reasons they can’t fully articulate. They’re the same model, with the same training, running the same kind of error-hunting heuristic that already has known systematic blind spots. We made this point writing about how little a company auditing its own safety is worth on its own: separating roles inside the same system reduces one kind of bias, but it isn’t a substitute for someone outside the system being able to say no.
Verifying eleven days of AI with what already existed
Where Bun’s argument gets harder to dismiss is the verification apparatus surrounding all of this, because it wasn’t built for the occasion — it already existed, and the rewrite had to survive it whole, with nothing trimmed. The test suite — language-independent, written in TypeScript — had close to a million assertions, and not a single test was skipped or removed during the process. On top of that: coverage-guided fuzzing running 24/7 against the parsers, with over a hundred billion cumulative executions and roughly 15 pull requests of fixes from that source alone; Address Sanitizer on every commit; CI across six platforms with up to 60 shards each; and, after merging, eleven additional rounds of security review.
The result of that sieve was 19 regressions caught and fixed, almost all of the kind that only shows up crossing the boundary between two languages with different semantics. The most telling one: Rust release binaries keep bounds checks that Zig’s ReleaseFast strips by default, which at one point inverted the very problem the rewrite was meant to solve — it opened an out-of-range access that hadn’t existed before. None of the 19 is a business-logic bug: all of them come from assuming that translating syntax between languages is enough to preserve behavior, when what actually changes, language to language, is the implicit contract each one makes with whoever is writing it.
The final numbers, now in v1.4.0, are consistent with that effort: memory usage on a 2,000-iteration Bun.build() test dropped from 6,745 MB to 609 MB, the binary shrank by roughly 20% depending on platform, and HTTP throughput improved by 2.8% to 4.8%. Bun also admits, without hiding it, that the port leaves around 13,000 unsafe blocks in the codebase — 78% of them single-line FFI calls into C or C++ — a figure outside analysts like Fawad Hussain Syed have flagged as the real security debt left over from a migration done at this speed, one the team itself says it’s reducing incrementally ahead of v1.4.
The project Bun left had already banned this
This is where Bun’s official account leaves out a date that changes everything. The Zig Software Foundation didn’t ban AI-generated contributions to its repository after this rewrite, as a defensive reaction. It did so before, and Bun already knew it: in late April, documenting its own fork of the Zig compiler, the Bun team wrote plainly that they had no plans to upstream those changes “as Zig has a strict ban on LLM-authored contributions.” Weeks before a single commit of the Rust rewrite existed, Bun was already developing outside the project it depended on, precisely because of the clash between how it worked and that project’s contribution policy.
The policy itself, Andrew Kelley had explained months earlier on a JetBrains podcast, with a bluntness that needed no softening: “People are sending us contributions that have no value whatsoever. They have negative value, because they take review time away from the team.” With 200 open pull requests and a reviewer team that doesn’t scale, any AI-generated contribution — flatly rated “invariably garbage” — wasn’t an average-quality problem. It was a tax on the one resource you can’t clone 64 times: the attention of a human reviewer who actually understands what they’re reading.
On July 14th, six days after Sumner’s post, Kelley published “My Thoughts on the Bun Rust Rewrite.” It’s a long piece, deliberately unruly, standing with one foot on each side: technical in one half, personal and bitter in the other. The technical half asks the obvious question with uncomfortable precision: if Bun already claimed to have a robust test suite and still accumulated the memory bugs that motivated the rewrite, what guarantees that same test suite will catch the bugs in “a million lines of unreviewed slop”? He describes years of watching “hacks on top of hacks” pile up in Bun’s codebase, and a pattern of “recklessly speeding past feature after feature with very little time taken for reflection” that, in Kelley’s telling, Zig never caused and Rust won’t cure.
The personal half is what made headlines, and fairly so: it documents that Bun’s $60,000 annual donation to the Zig Software Foundation quietly stopped, that Bun stopped attending scheduled meetings without cancelling them, and describes, in a line already circulating as a quote, the decay of a relationship that had been souring for years before a single line of Rust entered the picture — “the grapevine was large and healthy and full of juicy grapes, and all those grapes contained the juice of the same message: Jarred was a stinky manager.” Zig’s own community split reading it: on the Ziggit thread, some appreciate the honesty of a text this unfiltered coming from someone who leads a programming language; others point out, fairly, that the personal half undercuts the technical one — the half that actually deserved an answer.
Nobody at Bun has answered, and that silence might be the answer
Here it’s worth being precise about what doesn’t exist: as of today, there is no public response from Jarred Sumner, Bun, or Anthropic to Kelley’s post. No thread, no blog entry, no interview where someone on the other side directly addresses “unreviewed slop.” That’s a striking silence from a company that just published a very detailed 3,000-word post bragging, specifically, about its review process.
You can picture the response Bun would write if it wanted to, because most of it is already sitting in its own July post: the fuzzing numbers, the 19 regressions caught before reaching production, the eleven rounds of security review. A defensible argument would be that review didn’t disappear, it got automated and became more exhaustive than a team of three or four people could ever sustain by hand. But that response hasn’t come, and the absence says something the rewrite itself had already demonstrated: the explicit goal of the whole process was to stop depending on a time-limited human reading every line. Answering Kelley line by line would mean going right back to the model the rewrite existed to escape.
Rewriting is not the same as reviewing
This has been told as a language fight — Zig versus Rust, manual memory versus the borrow checker — and underneath, it isn’t one. Both sides agree on the part that matters: a single human reviewer can no longer read all the code a team produces today. Where they diverge is what to do once you accept that. Zig’s answer is to turn the volume down: fewer contributions, each reviewed by someone who genuinely understands the project, even if that means 200 pull requests sitting in a queue. Bun’s answer is to speed up the machine that replaces that person: more agents, more layers of automated verification, and a bet that a big enough testing apparatus can do the job a judgment-driven reviewer used to do.
Neither bet is settled yet. Zig’s is paid for in development speed and a growing backlog. Bun’s is paid for, for now, in 13,000 not-fully-audited unsafe blocks, in a six-thousand-word post nobody on the other side has answered, and in the question Kelley left open — one no test suite, however large, can answer by itself: who ultimately decides whether a million lines nobody read in full are actually fine.
Sources
- Rewriting Bun in Rust (Bun Blog)(bun.com)
- Bun is joining Anthropic (Bun Blog)(bun.com)
- Rewriting Bun in Rust (Simon Willison)(simonwillison.net)
- The Zig project's rationale for their firm anti-AI contribution policy (Simon Willison)(simonwillison.net)
- My Thoughts on the Bun Rust Rewrite (Andrew Kelley)(andrewkelley.me)
- Zig creator calls Bun's Claude Rust rewrite 'unreviewed slop' (The Register)(www.theregister.com)
- Zig Bans AI Code Contributions Because They're 'Invariably Garbage' (Slashdot)(developers.slashdot.org)
- My Thoughts on the Bun Rust Rewrite — discussion thread (Ziggit)(ziggit.dev)
- Zig Creator on the Bun-to-Rust Rewrite; What the Controversy Reveals (Developers Digest)(www.developersdigest.tech)
- Bun Rewrites in Rust: Technical Review of the Zig-to-Rust Migration (Fawad Hussain Syed)(fawadhs.dev)