mech.app
AI Agents

Rewriting Bun in Rust: How Agentic Workflows Ported 1M+ Lines and Passed a Million Assertions

Jarred Sumner's Zig-to-Rust rewrite of Bun used multi-agent orchestration, conformance suites, and adversarial review to ship 1M+ lines in 11 days.

Source: simonwillison.net
Rewriting Bun in Rust: How Agentic Workflows Ported 1M+ Lines and Passed a Million Assertions

Jarred Sumner just published the post-mortem of Bun’s Zig-to-Rust rewrite, completed in 11 days using Claude agents. The new Rust implementation has been live in Claude Code since June 17th with minimal user impact. This is not a story about AI writing code. It is a story about orchestrating parallel agents, building conformance suites that validate their own output, and fixing the generation process instead of patching generated code.

The rewrite consumed 5.9 billion uncached input tokens, 690 million output tokens, and 72 billion cached input token reads. At API pricing, that is roughly $165,000 in token spend. The result: 1 million lines of Rust code that passed a million-assertion test suite and shipped to production without breaking user workflows.

Why Rewrite at All

Bun’s bug list was dominated by memory management issues: use-after-free, double-free, and forgotten cleanup in error paths. Zig does not enforce memory safety at compile time. Rust does. The team was mixing garbage collection with manual memory management, a pattern no mainstream language handles cleanly.

Until recently, rewriting a production runtime in a new language was a non-starter. Joel Spolsky’s 2000 essay “Things You Should Never Do, Part I” made the case that rewrites destroy institutional knowledge and introduce new bugs. Coding agents change that equation. If you can automate the port and validate it with a language-independent test suite, the risk profile shifts.

The Conformance Suite as Orchestration Anchor

Bun’s test suite was written in TypeScript, not Zig. That meant it could validate both the old Zig implementation and the new Rust implementation without modification. The suite contained roughly 1 million assertions.

This is the critical architectural decision. A language-specific test suite would have required manual translation. A language-independent suite acts as a shared contract. The agent harness could:

  1. Generate Rust code from Zig source
  2. Run the TypeScript test suite against the Rust build
  3. Iterate on failures without human review of every line

The conformance suite became the feedback loop. If a test failed, the agent could see the assertion, the expected output, and the actual output. It could then regenerate the Rust code and rerun the suite.

Adversarial Code Review as a Deployment Gate

Sumner describes “adversarial code review” as part of the workflow. This is not traditional CI/CD. Traditional CI runs linters, type checkers, and unit tests. Adversarial review means one agent generates code and another agent tries to break it.

The review agent looks for:

  • Edge cases the generator missed
  • Unsafe patterns the Rust compiler allows but should not be used
  • Semantic mismatches between Zig and Rust (e.g., integer overflow behavior)
  • Performance regressions hidden by correct output

This is a multi-agent pattern. The generator agent optimizes for passing tests. The review agent optimizes for finding failures. The tension between them surfaces issues that a single agent would miss.

Fixing the Process, Not the Code

When an agent-generated PR adds 1 million lines, you cannot hand-patch bugs. If something is wrong, you fix the generation loop and regenerate.

Sumner spent most of the 11 days monitoring workflows and prompting Claude to edit the loop. This is process-level debugging. If the agent consistently mishandles Zig’s defer keyword, you do not fix 500 instances. You update the prompt or the workflow to handle defer correctly, then regenerate.

This inverts the usual code review model. In a human-authored PR, you review the diff and request changes. In an agent-authored PR, you review the process that produced the diff. The diff is disposable. The process is the artifact.

Orchestration Primitives

The workflow used dynamic task decomposition. The agent did not receive a single prompt to “rewrite Bun in Rust.” It received a sequence of prompts, each scoped to a module or subsystem. The orchestration harness:

  • Partitioned the codebase into independent units
  • Scheduled parallel rewrites where dependencies allowed
  • Serialized rewrites where one module depended on another
  • Aggregated test results across all units
  • Triggered regeneration when a unit failed its tests

This is not a single LLM call. It is a state machine with branching, retries, and conditional execution. The harness needs to track:

  • Which modules have been rewritten
  • Which modules are blocked on dependencies
  • Which modules failed and need regeneration
  • Which modules passed and are locked

The harness also needs observability. Sumner manually read outputs to check for systemic issues. If the agent starts generating unsafe code across multiple modules, you need to catch it before it compounds.

Token Economics and Caching

The $165,000 token spend breaks down as:

  • 5.9 billion uncached input tokens
  • 690 million output tokens
  • 72 billion cached input token reads

Caching is critical. The Zig source code, the TypeScript test suite, and the Rust standard library documentation do not change between iterations. Cached reads are 10x cheaper than uncached reads. Without caching, the cost would have been closer to $900,000.

The ratio of input to output tokens is 8.5:1. This is typical for code generation. The agent reads far more context than it writes. The context includes:

  • The Zig source file being ported
  • The Rust module being generated
  • The test suite for that module
  • Documentation for Rust equivalents of Zig constructs
  • Previous iterations of the same module (for regeneration)

Deployment and Validation

The new Rust implementation shipped in Claude Code v2.1.181 on June 17th. Startup got 10% faster on Linux. Otherwise, users noticed nothing. Boring is good.

The deployment strategy was:

  1. Run the Rust build in parallel with the Zig build for two weeks
  2. Compare outputs on every request
  3. Log divergences but serve the Zig output
  4. Fix divergences by regenerating the Rust code
  5. Flip the switch once divergences dropped to zero

This is shadow mode deployment. The Rust build runs in production but does not serve traffic. If it diverges from the Zig build, you know immediately. You do not wait for user reports.

Trade-Offs and Failure Modes

DimensionBenefitRisk
Conformance suiteLanguage-independent validation, no manual reviewAssumes test coverage is complete; untested paths ship broken
Adversarial reviewCatches edge cases and unsafe patternsAdds latency to the loop; may reject valid code
Process-level fixesScales to millions of linesRequires disposable code; hard to debug one-off issues
Parallel workflowsFaster than serial rewritesNeeds dependency tracking; failures cascade
Token caching10x cost reductionCache invalidation is hard; stale context breaks generation

The biggest failure mode is incomplete test coverage. If the TypeScript suite does not exercise a code path, the agent will not know it is broken. The Rust compiler catches memory safety issues, but it does not catch logic bugs.

The second failure mode is systemic prompt drift. If the agent starts generating code that passes tests but violates invariants (e.g., using unsafe blocks unnecessarily), you need to catch it early. Once 500 modules use the pattern, regenerating all of them is expensive.

Observability Gaps

Sumner manually monitored workflows. This does not scale. For a rewrite of this size, you need:

  • Real-time dashboards showing pass/fail rates per module
  • Alerts when a module fails repeatedly
  • Diffs between iterations to see what changed
  • Logs of agent reasoning (why did it choose this Rust construct?)
  • Metrics on token usage per module (to catch runaway context)

None of this is built into Claude or any other LLM API. You have to build it yourself. The orchestration harness needs to instrument every agent call and surface the data.

Technical Verdict

Use this pattern if you have a language-independent conformance suite with 80%+ coverage, a modular codebase that can be partitioned into independent units, and the budget to regenerate code instead of hand-patching it. You also need real-time observability into agent workflows and the engineering capacity to build an orchestration harness with state tracking, dependency resolution, and retry logic. The target language should offer stronger compile-time guarantees than the source language (Rust vs. Zig, TypeScript vs. JavaScript). If the rewrite eliminates entire bug classes, the $165,000 token cost pays for itself.

Avoid this pattern if your test suite is language-specific, has low coverage, or cannot run against both implementations in parallel. Do not use it if the migration requires deep semantic changes beyond syntax translation, if the codebase has tight coupling that prevents parallel rewrites, or if you need to preserve git history and code comments. If you cannot afford to build observability tooling (dashboards, alerts, diff logs), manual monitoring will not scale past a few dozen modules. If you lack access to frontier models at cost, the token economics break down quickly.