Jak Bun přepsali ze Zigu do Rustu – a proč to zvládl z velké části Claude

Přepsat více než půl milionu řádků kódu do jiného jazyka by ještě nedávno znamenalo měsíce až roky práce. Tvůrce runtime Bun to ale zvládl během jedenácti dnů s pomocí Claude Code. Jak takový přepis probíhal a co vypovídá o budoucnosti vývoje softwaru?
V červenci 2026 zveřejnil Jarred Sumner, tvůrce runtime prostředí Bun, obsáhlý zápis o tom, jak jeho tým přepsal celý projekt z jazyka Zig do Rustu. Zvláštní na tom není jen samotné rozhodnutí měnit programovací jazyk u zavedeného projektu, to bývá považováno za jeden z nejrizikovějších kroků ve vývoji softwaru, ale hlavně způsob, jakým to proběhlo: přepis odvedl z drtivé části model Claude (konkrétně předběžná verze Claude Fable 5), který během jedenácti dní vygeneroval přes milion řádků kódu. Bun v prosinci 2025 koupil Anthropic, takže tým dnes pracuje právě tam.
Tenhle článek shrnuje, co se v příspěvku píše, proč se tým k tak drastickému kroku odhodlal a jak konkrétně celý proces probíhal.
Odkud Bun vzešel
Bun začínal jako doslovný, řádek po řádku převod transpileru esbuild z Go do Zigu. Sumner napsal svůj první řádek Zigu v dubnu 2021 poté, co ho na Hacker News zaujala jednostránková jazyková reference Zigu a jeho příslib nízkoúrovňové kontroly nad během programu a důrazu na výkon.
Záběr projektu byl od začátku obrovský. Bun v sobě spojuje transpiler, minifikátor a bundler pro JavaScript, TypeScript i CSS, správce balíčků kompatibilní s npm, testovací nástroj ve stylu Jestu, systém rozlišování modulů kompatibilní s Node.js a TypeScriptem, HTTP/1.1 a WebSocket klienta a implementace řady modulů z Node.js jako fs, net nebo tls.
První verzi napsal Sumner sám za jeden rok, ještě před nástupem velkých jazykových modelů, v malém bytě v Oaklandu. Sám přiznává, že běžným osudem podobně ambiciózních projektů je hřbitov mrtvých vedlejších projektů na profilu na GitHubu – a že bez Zigu by tolik funkcionality za rok nikdy nezvládl. Dnes se CLI Bunu stahuje přes 22 milionů krát měsíčně a sázejí na něj nástroje jako Claude Code či OpenCode a platformy jako Vercel, Railway nebo DigitalOcean.
Proč vůbec něco měnit
Právě ten rozsah se ale stal zdrojem problémů se stabilitou. Sumner v článku uvádí vzorek chyb opravených jen v jedné verzi (v1.3.14) a je to zdlouhavý seznam pádů typu use-after-free, double-free a úniků paměti – v modulech jako node:zlib, node:http2, v práci s UDP sockety, v CSS parseru, v kryptografii a jinde. Většina těchto chyb má společného jmenovatele: špatně ošetřenou životnost paměti.
Tým přitom nedělal málo. Do kompilátoru Zigu si sami dopatchovali podporu Address Sanitizeru a s ním spouštěli testy při každém commitu, na Windows dodávali bezpečnostně kontrolované buildy, nepřetržitě fuzzovali runtime pomocí nástroje Fuzzilli (fuzzeru používaného i pro V8 a JavaScriptCore) a měli řadu testů na úniky paměti. To je víc, než dělá spousta projektů.
Jádro problému ale nebyla nedbalost, nýbrž samotná kombinace, kterou Bun potřebuje: JavaScript je jazyk se sběrem odpadků (garbage collectorem), zatímco Zig, podobně jako C, paměť za programátora nespravuje. Míchání ručně spravované paměti s pamětí spravovanou garbage collectorem je natolik netypický požadavek, že s ním prakticky žádný jazyk nepočítá. Zig navíc záměrně nemá konstruktory ani destruktory a čištění se očekává explicitně na každém místě přes klíčové slovo defer. U každé alokace tak bylo potřeba pečlivě hlídat, kde a jen jednou se paměť uvolní, jestli je pointer viditelný pro skener zásobníku a jestli je řádně ošetřena případná JavaScriptová výjimka. Sumner výslovně píše, že Zig za to neviní – jiné projekty v Zigu tyhle problémy nemají, protože nemíchají oba modely správy paměti.
Proč zrovna Rust
Velká část chyb ze zmíněného seznamu jsou právě use-after-free, double-free a „zapomněl jsem uvolnit paměť v chybové větvi“. V bezpečném (safe) Rustu jsou tyto chyby chybami při kompilaci a čištění probíhá automaticky přes mechanismus Drop ve stylu RAII. Chyba při kompilaci je podle Sumnera výrazně lepší zpětná vazba než stylistická příručka, kterou lze vynutit jen kontrolou kódu.
Tým zvažoval i alternativy. Mohl si napsat vlastní chytré ukazatele (smart pointery) v Zigu, a nějakou dobu to i dělal, jenže domácí řešení nabízelo horší ergonomii než Rust a žádnou z jeho záruk. Mohl přejít na C++, jehož je v Bunu už dnes zhruba 20 % kódu a které nabízí konstruktory i destruktory, ale i tak by zůstala závislost na stylistických příručkách vynucovaných recenzemi a i s Address Sanitizerem by k poškození paměti a únikům dál docházelo.
Přepis je přitom historicky považován za velmi špatný nápad. Bun má bez komentářů 535 496 řádků Zigu; ruční přepis by malému týmu zabral celý rok, během kterého by se muselo zmrazit opravování chyb, bezpečnostních děr i vývoj nových funkcí. To nebyla reálná varianta. Klíčovou výhodou ale bylo, že testovací sada Bunu je napsaná v TypeScriptu, takže je nezávislá na tom, v jakém jazyce je runtime napsaný – stejné testy se daly použít na ověřování nové implementace.
Sumner si proto položil otázku: co kdyby místo toho strávil týden zkoušením, jestli nový model od Anthropicu dokáže Bun do Rustu přepsat? Zpočátku nečekal, že to bude fungovat. Po pár dnech ale začalo procházet vysoké procento testů a nový Rustový kód nápadně odpovídal původnímu Zigu. Jeho postoj se posunul z „stojí to za pokus“ na „tohle chci mergnout“.
Jak přepis probíhal
Sumner zdůrazňuje, že nešlo o naivní „Claude, přepiš Bun do Rustu a nedělej chyby“. Přemýšlel, jak by to udělal člověk, a hned na začátku vyřešil dvě zásadní otázky.
První byla, jestli přepisovat postupně, nebo všechno najednou. Z vlastní zkušenosti s převodem esbuildu z Go do Zigu věděl, že všechno najednou je lepší – postupný přepis totiž plodí dočasný kód, o kterém jen doufáte, že ho jednou smažete. Druhá otázka byla jak zachovat stejnou architekturu, výkon a funkce a zároveň získat výhody Rustu jako borrow checker. Odpověď: udělat přepis tak, aby vypadal jako mechanický převod Zigu do Rustu, a teprve po vydání verze 1.4 ho postupně refaktorovat směrem k idiomatičtějšímu Rustu s méně unsafe bloky.
Smyčky, které píší a recenzují kód
Celý přepis Sumner postavil na zhruba padesáti dynamických workflow běžících nepřetržitě v Claude Code po dobu jedenácti dnů. Každé workflow byla smyčka: vzít úkol, napsat kód, nechat ho zrecenzovat a zapracovat připomínky. Jednotlivá workflow řešila třeba vytvoření průvodce převodem mapujícího vzory Zigu na vzory Rustu, mechanický převod každého .zig souboru na .rs, opravu chyb kompilátoru v jednotlivých crate, zprovoznění podpříkazů jako bun test nebo bun build a nakonec zprůchodnění celé testovací sady.
Adversariální recenze
Nejzajímavější částí procesu je způsob kontroly. U lidí platí, že kód recenzuje někdo jiný než jeho autor – a autor je obvykle motivovaný kód protlačit, což může zkreslit jeho úsudek. Claude se podle Sumnera chová stejně: ten Claude, který kód napsal, ho chce prosadit, a ten, který recenzuje, v něm chce najít chyby. Proto tým oddělil role do samostatných kontextových oken: jeden implementátor a nejméně dva „adversariální“ recenzenti na každého implementátora. Recenzent dostal jen samotný diff, nic víc (žádné odůvodnění autora) a měl jediný úkol: najít, čím je kód špatný, s instrukcí předpokládat, že špatný je.
Tento přístup zachytil chyby, které se všechny bez problémů zkompilovaly a působily naprosto věrohodně. Příkladem je asynchronní uv_close z libuv, kde se Box uvolnil na konci větve, zatímco si libuv dál držel ukazatel na uvolněnou paměť – což vede k use-after-free a následně double-free; oprava spočívala v úniku boxu přes Box::leak. Další chyba se týkala převodu záporného, neceločíselného času (datum modifikace souboru před rokem 1970), kde trunc vytvořil neplatný timespec se zápornými nanosekundami. Třetí chyba byla v CSS funkci color-mix(), kde unwrap_or vyhodnocuje svůj argument dychtivě a spadl na panice ještě předtím, než by ho vůbec ignoroval – řešením bylo líné unwrap_or_else s uzávěrem.
Přípravné práce a zkušební běh
Než se napsal jediný řádek produkčního kódu, strávil Sumner zhruba tři hodiny rozhovorem s Claudem o tom, jak co nejvěrněji namapovat vzory z jejich Zigového kódu na Rust. Výsledek Claude serializoval do dokumentu PORTING.md. Následovalo další workflow, které prošlo každé pole každé struktury v celém kódu, vysledovalo tok řízení, navrhlo pro dané pole životnost, nechalo ji zrecenzovat dvěma adversariálními agenty a zapsalo do souboru LIFETIMES.tsv.
Místo toho, aby Claude rovnou překládal všech 1 448 souborů .zig, začal Sumner jen třemi. Pro každý z nich jeden implementátor napsal nový .rs, dva recenzenti ověřili, že se chová stejně jako originál a dodržuje oba průvodce, a jeden „opravář“ zapracoval připomínky.
Falešné starty
Ne všechno šlo hladce. Když Sumner pustil workflow na všech 1 448 souborů, po dvou minutách si jednotliví Claudové začali navzájem šlapat na paty: jeden spustil git stash, jiný git stash pop, další git reset --hard. Řešením byla instrukce nikdy nespouštět git stash, git reset ani žádný git příkaz, který necommituje jeden konkrétní soubor – a žádné pomalé příkazy včetně cargo. Práci pak rozdělil do čtyř shardů, každý ve vlastním pracovním stromu, kde běželo 16 Claudů. Díky té paralelizaci psal Claude ve špičce zhruba 1 300 řádků kódu za minutu, přičemž každý řádek prošel dvěma recenzenty a kolem opravy, a přitom zpočátku vůbec nic z toho nefungovalo.
Chyby kompilátoru jako fronta práce
Po napsání kódu následovalo workflow na opravu všech chyb kompilátoru, crate po crate. Sumner chtěl původně jednolitý Zigový kód (v podstatě jedna kompilační jednotka) rozdělit do zhruba stovky crate, aby se Rust kompiloval rychleji, jenže bylo potřeba vyhnout se cyklickým závislostem. Jejich rozplétání odhalilo asi 16 000 chyb kompilátoru. To je ohromné číslo pro jednoho člověka, ale zvládnutelné pro 64 Claudů najednou. Workflow pro každou crate spustilo cargo check, seskupilo chyby podle souboru, nechalo je opravit, dvěma recenzenty zkontrolovat a jedním opravářem zapracovat.
I tady došlo na falešné starty: Claude si zpočátku vyložil „ať se to zkompiluje“ jako „vyplň funkce s chybami zástupnými implementacemi“ a začal přidávat podezřele dlouhé vysvětlující komentáře k obcházení problémů. Sumner na to zavedl pravidlo pro recenzenty: pokud potřebuješ celý odstavec komentáře, abys obhájil nějaké obejití, je ten kód špatně = oprav kód.
Od smoke testů k zelenému CI
Když prošel cargo check, přišly na řadu linker errory, pak okamžitý pád při startu, pak zprovoznění bun --version a bun test <soubor>. Následovalo workflow běžící na jednotlivých testovacích souborech. Náročné byly testy na úniky paměti, integrační testy trvající přes minutu i zátěžové testy, které vyčerpávají maximum TCP socketů, zapisují gigabajty na disk nebo spouštějí zhruba 10 000 procesů – kvůli izolaci se použil systemd-run s cgroups, a i tak stroji několikrát došlo místo na disku.
Dva dny po prvním běhu v CI klesl počet padajících testovacích souborů z 972 na 23. O den a půl později byl Linux plně zelený a poprvé to začalo vypadat, že přepis skutečně vyjde. Jednotlivé platformy ale ještě chvíli blikaly červeně, dokud nespadly poslední chyby; jako poslední doběhly Windows.
Kolik to stálo a co to znamená
Před mergnutím spotřeboval celý proces zhruba 5,9 miliardy necachovaných vstupních tokenů, 690 milionů výstupních tokenů a 72 miliard cachovaných čtení – v přepočtu na ceny API kolem 165 000 dolarů. Podle Sumnerova odhadu by to tři inženýry s plným přehledem o kódu stálo asi rok práce, během kterého by tým nemohl zlepšovat kompatibilitu s Node.js, opravovat chyby ani přidávat funkce. Reálná alternativa přitom nebyla „udělat to ručně za rok“, ale „neudělat nic a opravovat ty chyby ze začátku článku donekonečna“.
Celé workflow běželo na předběžné verzi Claude Fable 5 (model třídy Mythos) a dynamická workflow v Claude Code udržela 64 Claudů v běhu po celých jedenáct dní.
Co přepis přinesl
Verze 1.4.0 opravuje 128 chyb, které se v poslední Zigové verzi 1.3.14 daly reprodukovat – od úniků paměti přes pády až po špatně obarvený text nápovědy. Kromě toho tým přidal nepřetržité fuzzování všech parserů v Bunu a prošel jedenácti koly bezpečnostní revize.
Konkrétní zlepšení jsou měřitelná:
Spotřeba paměti výrazně klesla. Rustový Drop, který se automaticky zavolá při opuštění platnosti hodnoty, opravil několik úniků. Ukázkovým příkladem je opakované volání Bun.build() v jednom procesu: ve verzi 1.3.14 každý build unikal asi 3 MB navždy, takže po 2 000 buildech paměť narostla na 6 745 MB, zatímco ve verzi 1.4.0 se ustálila kolem 609 MB. Dřívější pokus tohle vyřešit v Zigu se nedostal do produkce právě proto, že bez ekvivalentu Drop chyběla jistota při mergování.
Binárka se zmenšila. Samotný přepis ušetřil několik megabajtů (do velké míry proto, že Zigový kód používal příliš mnoho comptime), a v kombinaci s dalšími úpravami jako Identical Code Folding a optimalizace ICU se velikost binárky zmenšila zhruba o 20 % na Linuxu i Windows.
Spotřeba místa na zásobníku klesla. Rekurzivní parsery (JSON, YAML, JavaScript, TypeScript, TOML a další) teď díky tomu, jak Rust generuje LLVM IR se značkami životnosti proměnných, používají výrazně méně místa na zásobníku, což umožnilo správně odmítat příliš zanořené vstupy.
Výkon se zvedl o 2 až 5 procent. Rust umožňuje link-time optimalizaci napříč jazyky mezi C/C++ a Rustem, tedy i inlining přes hranice jazyků. HTTP propustnost Bun.serve vzrostla o 4,8 %, podobně se zrychlily i běžné buildovací úlohy jako next build nebo tsc.
V produkci a co dál
Přepsaná verze už běží v produkci. Prisma na Rustovém Bunu spustila veřejnou betu své služby Prisma Compute a podle jejího vyjádření dřívější problémy s úniky paměti a s connection poolem, který se nedokázal zotavit po pozastavení a obnovení virtuálního stroje, nová verze zvládla bez potíží. Claude Code od verze 2.1.181 (vydané 17. června) používá Rustový port Bunu – start na Linuxu se zrychlil o 10 %, jinak si toho skoro nikdo nevšiml. A to je, jak Sumner poznamenává, dobře: nuda je v tomhle případě žádoucí.
Verze 1.3.14 byla poslední Bun napsaný v Zigu, verze 1.4.0 je první napsaná v Rustu a je k dispozici v canary kanálu (bun upgrade --canary). V době psaní příspěvku sedí asi 4 % Rustového kódu Bunu uvnitř unsafe bloků, přičemž 78 % z nich je jednořádkových – typicky ukazatel z C++ nebo volání do C knihovny. Toto číslo má podle Sumnera klesat, jak se kód bude refaktorovat od věrného Zigového portu k idiomatičtějšímu Rustu, ale kvůli dalšímu používání C a C++ knihoven jako JavaScriptCore bude vždy vyšší než u čistě Rustových projektů.
Sumner celý příspěvek uzavírá tím, co je pro něj hlavní pointou: přepis, který by tým inženýrů s plným přehledem o kódu zabral rok, zvládl jeden inženýr s modelem Fable a pečlivě sledovaným Claude Code za jedenáct dní. Jeden inženýr dnes zvládne mnohem víc než před rokem.
… reposted this!
Článek zajímavý, ale hrozně špatně se čte. Dost jistě je to jen strojově přeložené. Pokud je to tak, pak chybí odkaz na zdroj a nějaké review.
Díky za přečtení. Zdroj v článku je hned v první větě, kde odkazuji na Sumnerův zápis na blogu Bunu, ze kterého celý text vychází. Není to strojový překlad, obsah jsem zpracoval sám na základě originálu, s formulacemi jsem si místy pomáhal AI, ale výběr, struktura i kontrola byly na mně.
… liked this!