Создатель Bun переписал весь рантайм с Zig на Rust за 11 дней с помощью Claude — модели Anthropic. Bun начинался в 2021 году как построчный порт esbuild из Go в Zig, и за год в тесной квартире в Окленде был написан первый рабочий прототип. Сегодня Bun получает 22 миллиона загрузок CLI в месяц, на нём работают Claude Code и OpenCode, а Vercel, Railway и DigitalOcean поддерживают его «из коробки».
Но масштаб создал проблемы со стабильностью. В списке багов, исправленных в Bun v1.3.14, — десятки use-after-free, double-free и утечек памяти: в node:zlib, node:http2, UDPSocket.sendMany(), tlsSocket.setSession() (каждый вызов сливал ~6,5 КБ), fs.watch(), CSS-парсере и многих других местах. Корень проблем — смешение сборщика мусора JavaScript с ручным управлением памятью в Zig.
Zig не имеет деструкторов и полагается на явный defer. Для проекта, работающего с JavaScriptCore и V8, это означает, что каждое выделение памяти надо вручную проверять: где освобождается, не освобождается ли дважды, виден ли указатель консервативному сканеру стека? Стиль кода и код-ревью не спасают — ошибки всё равно проскальзывают. C++ дал бы деструкторы, но тоже не решил бы проблему системно. В Rust же use-after-free и double-free — ошибки компиляции, благодаря borrow checker и Drop.
Автор решил не делать инкрементальную миграцию, а портировать всё сразу — механически, максимально близко к оригиналу, сохраняя ту же архитектуру и тесты. 11 дней 50 динамических воркфлоу в Claude Code генерировали, ревьюили и фиксили код. Пиковая скорость — 1300 строк в минуту. Каждую строчку проверяли два adversarial-ревьюера (отдельные инстансы Claude), которые получали только diff и пытались найти баги. Три реальных бага, пойманных до мержа: async close в libuv приводил к double-free, отрицательное время до 1970 года давало невалидный timespec, и eager unwrap_or паниковал в CSS color-mix.
В результате 535 496 строк Zig превратились в Rust-код с 6502 коммитами. Теперь Bun использует гарантии памяти на уровне компилятора вместо стилистических гайдлайнов.