Reescribir Bun en Rust
(bun.com)- Bun, que comenzó con Zig, creció hasta convertirse en un runtime con más de 22 millones de descargas al mes, pero los problemas recurrentes de estabilidad provocados por la combinación de un motor de JavaScript basado en GC y la gestión manual de memoria llevaron a iniciar la migración a Rust
- En lugar de dedicar un año de trabajo humano a trasladar 535,496 líneas de código Zig, ejecutaron en paralelo durante 11 días unas 50 workflows dinámicas de Claude Code y hasta 64 instancias de Claude
- El port se validó con
PORTING.md,LIFETIMES.tsv, 1 implementador y al menos 2 revisores adversariales, además del test suite existente en TypeScript, y logró pasar al 100% en CI sobre 6 plataformas - Tras el cambio a Rust, Bun v1.4.0 corrige 128 bugs reproducibles en v1.3.14, elimina todas las fugas de memoria instrumentables y reduce aproximadamente un 20% el tamaño de los binarios en Linux y Windows
- Bun v1.3.14 es la última versión en Zig y v1.4.0 es la primera versión en Rust, disponible en canary; el equipo usa borrow checker, Miri, LeakSanitizer y fuzzing con cobertura 24/7 como herramientas para mejorar la estabilidad
Bun comenzó con Zig y sus problemas de estabilidad
- Bun arrancó como un proyecto que hizo un port línea por línea del transpiler de JavaScript y TypeScript de esbuild, de Go a Zig
- El primer código en Zig se escribió el 16 de abril de 2021, y el control de bajo nivel de Zig junto con su diseño orientado al rendimiento hicieron posible la implementación inicial de Bun
- El Bun inicial fue escrito en Zig por una sola persona durante un año, y su alcance era muy amplio
- Transpiler, minifier y bundler de JavaScript, TypeScript y CSS
- Gestor de paquetes compatible con npm
- Test runner similar a Jest
- Resolución de módulos compatible con Node.js y TypeScript
- Clientes HTTP/1.1 y WebSocket
- Implementación de APIs de Node.js como
fs,netytls
- Actualmente, Bun CLI supera las 22 millones de descargas mensuales, y Claude Code y OpenCode lo usan como runtime, mientras que Vercel, Railway y DigitalOcean ofrecen soporte de 1st-party
Bugs repetidos de seguridad de memoria
- Entre los ejemplos de bugs corregidos en Bun v1.3.14 se incluyen use-after-free, double-free, fugas de memoria, accesos out-of-bounds y race conditions
node:zlib: heap-use-after-free al llamar.reset()durante una.write()asíncronanode:http2: un callback de JS reentrante provocaba un rehash del hashmap y dejaba inválidos punteros internos de streams, causando un use-after-free- En
UDPSocket.send()ysendMany(), callbacks devalueOf()otoString()podían hacer detach deArrayBuffer - En
Buffer#copyyBuffer#fill, coerciones de argumentos que hacían detach o resize deArrayBufferprovocaban crashes y lecturas out-of-bounds - Fugas de memoria relacionadas con
crypto.scrypt,tlsSocket.setSession()yfs.watch() - Double-free al procesar vendor prefixes y backgrounds multicapa en el parser de CSS
- Crashes por race condition de
MessageEventdurante acceso concurrente aBroadcastChanneloMessagePort
- Ya usaban varios mecanismos para reforzar la estabilidad
- Parchearon el compilador Zig para dar soporte a Address Sanitizer y ejecutaban el test suite con ASAN en cada commit
- En Windows distribuían builds ReleaseSafe de Zig con verificaciones de seguridad
- Hacían fuzzing 24/7 de la API runtime de Bun con Fuzzilli
- Operaban múltiples pruebas end-to-end de fugas de memoria
- No sostienen que Zig sea el problema en sí; la principal fuente de los problemas de estabilidad era la necesidad de manejar al mismo tiempo valores con GC y memoria gestionada manualmente
Por qué eligieron Rust
- JavaScript es un lenguaje con GC, y motores como JavaScriptCore y V8 tienen reglas estrictas para el manejo de excepciones y GC
- Zig, al igual que C, no administra memoria automáticamente; no tiene constructores ni destructores, y la limpieza normalmente debe declararse en cada call site con
defer - En Bun, manejar correctamente el lifetime de los valores con GC y de los valores gestionados manualmente era una fuente importante de problemas de estabilidad
- Había que verificar dónde se liberaban los bytes asignados
- Había que garantizar que solo se liberaran una vez
- Había que comprobar correctamente el manejo de excepciones de JavaScript
- Había que asegurar que los punteros de GC fueran visibles para el conservative stack scanner
- El enfoque de limpieza en Zig usa
deferyerrdeferexplícitos; C++ usa destructors y move, y Rust usaDrop - En el código Zig existente de Bun había una mezcla de lifetime de arena, reference counting y revisiones minuciosas
- Se pueden imponer reglas de ownership con guías de estilo y code review, pero en código seguro de Rust, use-after-free, double-free y free omitidos en rutas de error se convierten en errores de compilación
- Aproximadamente el 20% del código de Bun está en C++ e integra varias bibliotecas C/C++
- JavaScriptCore
- uWebSockets y usockets
- lshpack y lsquic
- BoringSSL
- SQLite
- C++ también podía haber sido una opción, pero seguiría dependiendo de guías de estilo y code review, y aun con ASAN pueden ocurrir corrupciones de memoria y fugas
Estrategia de reescritura: de una sola vez y de forma mecánica
- El código Zig existente de Bun tenía 535,496 líneas sin contar comentarios, y se estimó que una reescritura tradicional tomaría alrededor de un año a un pequeño equipo de ingeniería
- Como no podían detener durante un año las correcciones de bugs y seguridad ni el desarrollo de funciones, eligieron como enfoque de menor riesgo un port mecánico que minimizara los cambios en el comportamiento para los usuarios
- El test suite de Bun estaba escrito en TypeScript, por lo que no dependía del lenguaje de implementación del runtime
- Consideraron que una reescritura incremental sería dolorosa a corto y mediano plazo, porque obliga a crear código temporal con la esperanza de eliminarlo después, así que trasladaron todo de una sola vez
- Decidieron escribir el código Rust para que pareciera código Zig transpilado, y después de Bun v1.4 ir reduciendo gradualmente
unsafey refactorizando hacia un Rust más idiomático
Workflow dinámica de Claude Code
- Para la reescritura en Rust, en Claude Code se ejecutaron de forma continua durante 11 días unas 50 workflows dinámicas
- Las workflows abarcaron desde redactar la guía de porting hasta convertir archivos, corregir errores de compilación, restaurar subcommands, pasar todas las pruebas y hacer limpiezas a gran escala
- Crear una guía de porting que mapeaba patrones y tipos de Zig a patrones y tipos de Rust
- Hacer el port mecánico de todos los archivos
.ziga.rssiguiendoPORTING.mdyLIFETIMES.tsv - Corregir errores del compilador por crate
- Restaurar el funcionamiento de subcommands como
bun testybun build - Lograr que pasara el test suite completo
- Realizar refactorizaciones y cleanup a gran escala
- Durante la mayor parte del tiempo, una persona leía la salida de las workflows, verificaba problemas y bugs, y ajustaba los prompts para que Claude corrigiera el loop
- Como trabajo previo, dedicaron unas 3 horas a discutir con Claude cómo mapear los patrones del codebase Zig a Rust, y el resultado se serializó en
PORTING.md - Para añadir lifetimes de Rust al código con gestión manual de memoria, ejecutaron un workflow que analizaba los lifetimes de todos los fields de los structs
- Identificar fields con lifetimes complejos
- Proponer lifetimes
- Revisarlos con 2 agents de revisión adversarial
- Incorporar el feedback y guardarlo en
LIFETIMES.tsv
Método de revisión adversarial
- Cada implementación de Claude se emparejó con un Claude revisor adversarial en una ventana de contexto separada, y se le indicó al revisor que buscara bugs asumiendo que el código estaba mal teniendo solo el diff
- La estructura básica consistía en 1 implementador, 2 o más revisores adversariales y 1 fixer
- Todos los bugs que los revisores detectaron compilaban correctamente, pero tenían problemas de comportamiento
uv_closees asíncrono, peroBox<uv::Pipe>se destruía al final del match arm, lo que hacía que libuv conservara memoria ya liberada, causando un use-after-free y double-free- Error de
timespecdonde usartrunc()en un file time negativo no entero generabansecnegativos - Error donde
unwrap_orevaluaba sus argumentos de forma eager y provocaba un panic cuando se omitía el porcentaje encolor-mix()
- Igual que en una revisión humana, se separó el contexto del autor y del revisor para reducir el sesgo que puede surgir cuando el implementador quiere hacer merge
Ejecución del porting a gran escala y paralelización
- Antes de mover los 1,448 archivos
.zig, primero validaron el procedimiento con 3 archivos- 1 implementador escribía el archivo
.rs - 2 revisores verificaban que coincidiera con el comportamiento de
.zigy que siguieraPORTING.mdyLIFETIMES.tsv - 1 fixer aplicaba las sugerencias
- 1 implementador escribía el archivo
- Al inicio del port completo, varios Claude ejecutaban
git stash,git stash popygit reset HEAD --hard, interfiriendo entre sí - Después añadieron reglas al workflow que prohibían
git stash,git reset, comandos degitque no fueran commits de archivos específicos y comandos lentos comocargo - Al final usaron 4 workflow shards y 4 worktrees, y en cada shard 16 Claude hacían commit y push de archivos
- Gracias a la paralelización y a la preparación previa, en el pico Claude escribió unas 1,300 líneas de código por minuto
- La rama del port tuvo 6,502 commits excluyendo merges, la hora pico fue de 695 commits, y el diff final integrado fue de +1,009,272 líneas
- También hubo un problema porque no aumentaron los IOPS por defecto de la instancia EC2: un solo
greplento podía detener la lectura y escritura del disco durante varios minutos
Errores de compilación y separación en crates
- Después de escribir todo el código, el workflow de Claude corrigió los errores del compilador
- La base de código Zig era en la práctica una sola compilation unit, y el código Rust se quería dividir en unos 100 crates para compilar más rápido
- La categoría de errores más complicada fue la de las dependencias circulares
- El PR de separación en crates justo antes de la reescritura en Rust no fue suficiente
- Un workflow aparte clasificó y registró dónde debía colocarse el código con dependencias circulares
- Otro workflow realizó ese refactor
- Tras resolver las dependencias circulares, quedaron expuestos unos 16,000 errores del compilador
- Esos errores se procesaron en paralelo por crate
- En cada crate se ejecutaba
cargo check - La salida se agrupaba y guardaba por archivo
- Se corregían los errores de compilación de ese crate
- 2 revisores adversariales revisaban los cambios
- 1 fixer aplicaba las correcciones
- En cada crate se ejecutaba
- También hubo un falso arranque en el que Claude interpretó “hagamos que todos los crates compilen” como generar stubs de funciones
- Cuando empezó a aparecer el patrón de justificar workarounds con comentarios explicativos largos, se añadió una regla de revisión: “si hace falta un comentario del tamaño de un párrafo, el código está mal y hay que arreglar el código”
El camino hasta pasar las pruebas
- Después de que
cargo checkpasó, fueron resolviendo en orden los errores de linkeo, panic al iniciar,bun --versiony la ejecución debun test <file> - Usaron un workflow que guardaba en archivos los stack traces de fallas por subcomando del CLI y los corregía con un loop de implementador, revisor y fixer
- El workflow de archivos de prueba dividía unos 100 archivos de test aleatorios en 4 worktrees, guardaba los stack traces y errores de cada fallo, y luego los corregía
- La suite de pruebas incluía pruebas de memory leaks e integración que podían agotar el tiempo en debug build
- Una prueba que ejecutaba
next devy verificaba que hot module reloading detectara 100 cambios - Una stress test que agotaba el número máximo de TCP sockets
- Pruebas de lectura y escritura de disco a escala de gigabytes
- Una prueba que hacía spawn de unos 10 mil procesos
- Una prueba que ejecutaba
- Para aislarlas, limitaron el uso de memoria y CPU con
systemd-runy cgroups, y separaron el pid namespace - Aun así, la máquina se cayó varias veces por falta de espacio en disco
- Dos días después de la primera ejecución de CI, los archivos de prueba fallando bajaron de 972 a 23, y un día y medio después Linux quedó completamente en verde
- Al final pasó toda la suite de CI en 6 plataformas
- macOS x64
- macOS arm64
- Linux x64
- Linux arm64
- Windows x64
- Windows arm64
- Tras llegar al 100% de pruebas aprobadas, una persona verificó manualmente que las pruebas realmente se ejecutaran y no hubieran sido omitidas, y entonces hizo el merge
- El momento en que se hizo merge a
mainno fue un release versionado; todavía no había suficiente confianza para lanzarlo, pero sí la suficiente para comprometerse con la reescritura
Escala de pruebas y costo
- Durante 11 días, desde el 3 de mayo hasta el merge del 14 de mayo, se generaron 6,778 commits
- Las pruebas no se eliminaron ni se marcaron como skip
- La escala de pruebas por plataforma fue la siguiente
- Debian 13 x64:
expect()1,386,826 veces, 60,624 pruebas, 4,174 archivos - macOS 14 arm64:
expect()1,259,953 veces, 58,850 pruebas, 4,175 archivos - Windows 2019 x64:
expect()1,007,544 veces, 57,337 pruebas, 4,173 archivos
- Debian 13 x64:
- El trabajo previo al merge usó 5.9 mil millones de uncached input tokens, 690 millones de output tokens y 72 mil millones de cached input tokens read
- El costo según precios de API fue de aproximadamente 165 mil dólares
- Se estima que, si lo hubieran hecho personas directamente, 3 ingenieros con contexto de toda la base de código habrían tardado alrededor de 1 año
- El modelo usado fue la pre-release Claude Fable 5, y se incluyó una divulgación de que Bun fue adquirida por Anthropic en diciembre de 2025
Revisión de seguridad, fuzzing y estado de unsafe
- Después del merge del port a Rust, completaron 11 rondas de revisión de seguridad con Claude Code Security y atendieron los hallazgos
- Se añadió fuzzing continuo 24/7 basado en cobertura para todos los parsers de Bun
- JavaScript
- TypeScript
- JSX
- CSS
- JSON5
- JSONC
- TOML
- YAML
- Markdown
- INI
- scripts de Bun Shell
- rangos de semver
- archivos
.patch - colores CSS
- El fuzzer envía a Claude los bugs que encuentra para que presente PRs con reproducción y corrección, y luego una persona revisa esos PR
- Hasta ahora, la ejecución de parsers llegó a 100 mil millones de veces y derivó en unos 15 PR
- Al momento de escribir esto, alrededor del 4% del código Rust está dentro de bloques
unsafe- Unos 13,000
unsafekeywords - Unas 27,000 líneas / de un total de unas 780,000 líneas
- El 78% de los bloques
unsafeson de una sola línea y provienen de punteros heredados de C++ o llamadas a librerías C
- Unos 13,000
- Aclaran que, como siguen usando librerías C/C++ como JavaScriptCore, siempre habrá más
unsafeque en un proyecto de Rust puro
Regresiones encontradas tras el cambio a Rust
- La reescritura en Rust fue un cambio a gran escala y creó 19 regresiones conocidas; todas ya fueron corregidas
- La mayoría surgió de código cuya sintaxis es parecida en ambos lenguajes, pero cuyo significado es distinto
-
Side effects dentro de
debug_assert!- El
assertde Zig es una función, así que sus argumentos se ejecutan en todos los builds debug_assert!de Rust es una macro, así que en los builds de release se elimina la expresión completa- La llamada a
insert_staledesapareció en los builds de release y rompió cierto caso de HMR en proyectos de rutas HTML que usan React - Issue relacionado: #30678
- El
-
Slices de longitud impar
- El helper de Zig de Bun
reinterpretSlice(u16, bytes)usaba@divTrunc, por lo que ignoraba el byte impar sobrante al final bytemuck::cast_slicede Rust hace panic cuando la longitud es impar- Hubo una regresión donde
Blob.text()con un byte impar después del BOM UTF-16 hacía panic en el proceso en vez de devolver una cadena - La corrección volvió a ignorar el byte impar usando
&buf[..buf.len() & !1] - Issue relacionado: #31188
- El helper de Zig de Bun
-
Bounds checks
- El código Zig en macOS y Linux se compilaba con
ReleaseFast, por lo que se eliminaban los bounds checks, mientras que los builds release de Rust los conservan - El tamaño del bloque de overflow del module resolver de Bun quedó con el placeholder
64, lo que bajó el techo de 8.4 millones de nombres de archivo internados a 270,272 - El off-by-one portado de
ptrs[4095]pasó a ser alcanzable en proyectos reales, y Rust hizo panic en vez de escribir fuera de límites - Issue relacionado: #31503
- El código Zig en macOS y Linux se compilaba con
-
Cadenas de formato
comptime- En Zig,
Output.prettytienefmtcomocomptime, así que los marcadores de color<r>y<d>se convierten en escapes ANSI antes de sustituir los argumentos - La función de Rust no tenía un parámetro comptime, así que procesaba los marcadores en la cadena ya terminada y también reescribía mal los argumentos
- En
bun update -i, la terminación del hipervínculo OSC 8 y el marcador final<r>entraban en conflicto, por lo querse imprimía como texto - En Rust se necesitaba la macro
bun_core::pretty!("<r>{}<r>", hyperlink) - Issue relacionado: #30693
- En Zig,
Bugs corregidos y fugas de memoria
- Bun v1.4.0 corrige 128 bugs reproducibles en v1.3.14
- El alcance incluye fugas de memoria, crashes y hasta texto de ayuda coloreado incorrectamente
Dropen Rust llama automáticamente a la funcióndropcuando un valor sale de scope- En Zig, había que agregar
deferen cada call site, por lo que era fácil omitir limpieza o duplicarla Dropen Rust es una elección que acepta el hidden control flow a cambio de reducir footguns comunesDropcorrigió varias fugas de memoria relacionadas con rutas de archivo en el código de manejo de errores- Se mejoró la integración de Bun con LeakSanitizer para rastrear todas las asignaciones de memoria de código nativo
- Todas las fugas de memoria instrumentables fueron corregidas
-
Mejoras a la fuga de
Bun.build()- En Bun v1.3.14, en cada llamada in-process a
Bun.build(), el texto fuente parseado y la tabla de símbolos del AST sobrevivían más que la vida útil del build, filtrando varios MB cada vez - En una prueba que empaquetaba el mismo proyecto de 60 módulos 2,000 veces en un solo proceso, v1.3.14 seguía filtrando alrededor de 3 MB por build
- En Bun v1.4.0, el uso de memoria se estabiliza
- | Builds | Bun v1.3.14 | Bun v1.4.0 |
- | --- | ---: | ---: |
- | 500 | 1,914 MB | 526 MB |
- | 1,000 | 3,506 MB | 586 MB |
- | 1,500 | 5,097 MB | 608 MB |
- | 2,000 | 6,745 MB | 609 MB |
- En Bun v1.3.14, en cada llamada in-process a
Tamaño del binario, uso de stack y rendimiento
- El tamaño del binario se redujo solo con los cambios iniciales de la reescritura en Rust
- Windows: 3.8 MB menos
- macOS: 5.5 MB menos
- Linux: 6.8 MB menos
- La causa principal fue el uso excesivo de
comptimeen el código Zig - Después también se aplicaron identical code folding, eliminación de datos no usados de ICU y descompresión diferida de parte de libicu con un diccionario zstd
- Si se combinan la reescritura en Rust, los cambios en ICU e identical code folding, el tamaño del binario de Bun se reduce alrededor de 20% en Linux y Windows
| Version | Platform | Size |
|---|---|---|
| Bun v1.4.0 canary | Windows | 76 MB |
| Bun v1.3.14 | Windows | 94 MB |
| Bun v1.4.0 canary | Linux | 70 MB |
| Bun v1.3.14 | Linux | 88 MB |
- El parser de TOML y los parsers recursive-descent de Bun ahora usan menos espacio de stack
- El codegen de LLVM IR de Rust emite las intrinsics
llvm.lifetime.startyllvm.lifetime.endpara variables de stack, lo que permite a LLVM reutilizar stack slots - Antes, se refactorizaban manualmente funciones especialmente grandes en varias más pequeñas para esquivar un issue abierto de Zig
- Rust soporta link-time optimization entre C/C++ y Rust, lo que permite inlining entre lenguajes
-
Benchmark de Linux x64
- Se comparó Bun v1.3.14 con Bun v1.4.0 en un EC2 Xeon Platinum 8488C con Linux x64
- El throughput HTTP se midió con oha y la carga de trabajo de la app con hyperfine
- | server | Bun v1.3.14 | Bun v1.4.0 | Δ |
- | --- | ---: | ---: | ---: |
- | Bun.serve | 169.6k req/s | 177.7k req/s | +4.8% |
- | node:http | 103.8k req/s | 108.5k req/s | +4.5% |
- | Elysia | 158.9k req/s | 163.3k req/s | +2.8% |
- | express | 64.5k req/s | 66.6k req/s | +3.2% |
- | fastify | 91.5k req/s | 95.9k req/s | +4.8% |
- | workload | Bun v1.3.14 | Bun v1.4.0 | Δ |
- | --- | ---: | ---: | ---: |
- | next build | 13.62 s | 13.03 s | +4.5% |
- | vite build | 1.69 s | 1.65 s | +2.2% |
- |
tsc -b --force| 0.94 s | 0.89 s | +4.7% |
Casos de uso reales y estado de lanzamiento
- Prisma lanzó la beta pública de Prisma Compute sobre la reescritura de Bun en Rust
- Según Prisma, probaron en la reescritura en Rust un pool de conexiones que no se recuperaba después de pause/resume de la VM y un modo de fallo por memory leak, y afirmaron que ese modo de fallo se manejó bien
- Claude Code v2.1.181 y las versiones lanzadas después del 17 de junio usan Bun porteado a Rust
- El arranque de Claude Code en Linux fue 10% más rápido, y por lo demás la mayoría de los usuarios casi no notó cambios
- Bun v1.3.14 fue la última versión de Bun escrita en Zig
- Bun v1.4.0 es la primera versión de Bun escrita en Rust y se ofrece como canary
Herramientas que obtuvo el equipo y trabajo pendiente
- La nueva base de código en Rust mantiene una forma muy similar a la base de código existente en Zig
- Se escribió de modo que quienes entienden el código original en Zig también puedan entender el código en Rust traducido mecánicamente
- La revisión del PR de la reescritura en Rust se realizó verificando que un agente de revisión hostil detectara correctamente discrepancias entre Zig y Rust, la guía de porting y el cumplimiento de la guía de lifetimes, mientras que las personas leían mucho código lado a lado
- Bun v1.4 hace a Bun más rápido y pequeño, reduce el uso de memoria y proporciona herramientas para mejorar la estabilidad
- Rust borrow checker
- Miri
- LeakSanitizer
- fuzzing guiado por cobertura 24/7 para el parser
- Aún quedan partes por refactorizar, y se enlaza bun-unsafe-audit
- Un ingeniero monitoreó de cerca Fable y Claude Code, y se llegó en solo 11 días al punto en que toda la suite de pruebas pasaba en todas las plataformas
1 comentarios
Opiniones en Lobste.rs
extern "C", pero seguirían dependiendo de una guía de estilo impuesta mediante revisión de código y, aun con ASAN, seguirían apareciendo corrupciones y fugas de memoria.Curiosamente, Node.js funciona bien incluso en C++, pero nunca he visto a Bun como un proyecto serio. Ahora parece un banco de pruebas del departamento de marketing de Anthropic, así que pienso seguir manteniéndome lejos.
Spoiler: en la práctica, no son tan cuidadosos y sí cometen errores.
unsafe, y el 78% de ellos son de una sola línea” parece una forma de tranquilizar, pero no importa si un bloqueunsafetiene una sola línea o no. Si dentro de él se rompen las garantías de seguridad, todo el código fuera del bloque también puede quedar potencialmente sin soundness.La integración inicial del port a Rust de Bun contenía unsoundness evidente de este tipo: https://github.com/oven-sh/bun/issues/30719
Ese issue se abordó cuando los mantenedores activaron en CI la herramienta Miri de Rust, y en la sección “What's Next” del artículo también aparece Miri (which runs for a growing chunk of code in CI), así que parece bien que estén trabajando en eso.
Siendo justos, incluso Rust con violaciones de seguridad puede ser más fácil de mantener dependiendo de la calidad del código Zig al que reemplazó. Aun así, las líneas de código por bloque unsafe no son un indicador de calidad, sobre todo si esos bloques no tenían otras prácticas de codificación, experiencia ni verificaciones automáticas.
unsafeno surgieron del proceso de porting, sino de los requisitos del proyecto. Si llamas a una biblioteca en C, necesitas bloquesunsafe, y no hay forma de eliminarlos solo con refactorización.Claro, sería posible si también reescribieran esa biblioteca en C, pero eso quizá puedan evaluarlo más adelante.
En el anuncio “Bun is joining Anthropic”, Jarred dijo que contratarían más ingenieros para trabajar en Bun, pero viendo solo GitHub, el equipo de Bun más bien parece haberse reducido. No sé bien qué conclusión sacar de eso, salvo que “Bun es un equipo pequeño”.
El método en sí es interesante, pero el artículo se lee como una pieza de marketing. También falta análisis sobre cuánto costó, no se mencionan los riesgos de una reescritura en Rust y, para empezar, tampoco hay una explicación concreta de por qué ocurrió la reescritura. Si tuviera que especular, podría ser por la política de no IA de Zig, o porque dentro de Anthropic había una política de enfocarse en Rust.
Y creo que el artículo cuenta una historia bastante coherente sobre por qué lo reescribieron. Bun tomó medidas para detectar problemas, pero seguía crasheando, y los desarrolladores querían una forma más sistemática de evitar estos problemas.
El plan inicial era imponer con más rigor cierto estilo de codificación e introducir smart pointers, pero Jared consideró que sus smart pointers propios tenían peor usabilidad que Rust y no ofrecían garantías. Entonces pasó a ser “¿qué tal si probamos durante una semana si el nuevo modelo de Anthropic puede reescribir Bun en Rust?”, y cuando la tasa de aprobación de la suite de pruebas subió, el flujo parece haber pasado de “vale la pena intentarlo” a “lo vamos a integrar”.
Es decir, no parece que hayan decidido desde el inicio reescribir en Rust, sino algo más cercano a: “Rust parece dar una solución al problema, pero no podemos hacerlo por el costo de reescritura. Pero al probar un port con LLM, parece posible. Entonces vayamos con una reescritura mediante LLM”.
Felicitaciones a Jarred, al equipo de Bun y a Anthropic por haberlo logrado.