Bun의 Zig→Rust 포팅, 11일과 병렬 에이전트 64개가 들었다

지금까지 운영에 배포된 에이전트 작성 재작성 중 가장 큰 사례다. 그리고 흥미로운 대목은 그 과정이 통과시킨 회귀들이다.

|6분 읽기0
Ferris, the Rust programming language mascot, at the Rust assembly during the 38C3 conference — Bun's runtime now compiles as Rust rather than Zig.
Ferris, the Rust programming language mascot, at the Rust assembly during the 38C3 conference — Bun's runtime now compiles as Rust rather than Zig.

자바스크립트 런타임이자 번들러, 패키지 매니저인 Bun이 이제 Zig가 아닌 Rust 위에서 돌아간다. 거기까지 간 포팅에는 제작자가 인간 엔지니어 기준으로 잡았던 1년이 아니라, 지속 감독하에 돌린 에이전트 워크플로 11일이 들었다. 자레드 섬너는 그 과정을 상세히 기록했다. Bun v1.4가 이미 배포돼 Claude Code와 Prisma의 Compute 베타가 그 위에서 돌아가는 지금, 기계가 쓴 100만 줄짜리 시스템 코드를 믿는 데 실제로 얼마가 드는지 물어볼 만한 운영 근거가 쌓였다.

핵심 요약

  • 1,448개 파일에 걸친 Zig 코드 535,496줄을 Claude Code 워크플로 약 50개가 포팅했다. git 워크트리 4개로 샤딩해 각 트리에서 에이전트 인스턴스 16개를 돌렸고, 최고 속도는 분당 약 1,300줄, 한 시간에 커밋 695건이었다.
  • 구현 에이전트마다 적대적 리뷰어 2명이 붙었다. 리뷰어는 diff만 보고, 코드가 틀렸다고 전제하라는 지시를 받았다.
  • Bun v1.4.0은 마지막 Zig 릴리스인 v1.3.14에서 여전히 재현되는 버그 128건을 고쳤다. 반면 HTTP 처리량 개선은 2~5%에 그쳤다.

100만 줄 diff를 그나마 검토 가능하게 만든 것

전제 조건은 섬너가 몇 해 전에 쌓아 둔 행운이었다. Bun의 테스트 스위트는 타입스크립트로 짜여 있어, 아래쪽 런타임을 어떤 언어로 구현했든 상관없이 동작만 검증한다. 덕분에 포팅 내내 바뀌지 않는, 100만 개가 넘는 단언으로 된 고정 오라클이 확보됐다. 테스트가 원본 언어 안에 있었다면 이런 닻은 없었다.

두 번째는 구조에 관한 결정이었다. 에이전트 하나가 코드를 쓰고 자기 작업을 스스로 확인하게 두는 대신 섬너는 역할을 쪼갰다. 구현자 하나, 별도 컨텍스트 창에서 diff만 받는 적대적 리뷰어 둘 이상, 그리고 지적 사항을 반영하는 수정자를 따로 뒀다. 그가 밝힌 이유는 기술이 아니라 행동에 있다. 코드를 쓴 모델은 사람 작성자와 똑같이 그 코드가 병합되기를 바라므로, 리뷰어는 다른 지시를 받은 다른 인스턴스여야 한다는 것이다. 공개된 사례로는 libuv가 아직 포인터를 쥐고 있는데 드롭된 Box<uv::Pipe>, 유효한 CSS color-mix()에서 패닉을 낸 즉시 평가형 unwrap_or, 1970년 이전 파일 타임스탬프에서 음수 나노초를 만들어 낸 timespec 변환이 있다. 셋 다 컴파일은 깨끗하게 통과했다.

세 번째로, 결과물이 잘못되면 수정 대상은 산출물이 아니라 루프였다. 첫 전체 실행 2분 만에 에이전트들이 git stash로 서로의 작업을 덮어썼는데, 대응은 망가진 커밋을 손보는 대신 워크플로 지시문을 다시 쓰는 것이었다. 약 3시간의 계획 작업에서 Zig 관용구를 Rust로 대응시킨 PORTING.md와 모든 구조체 필드의 의도된 수명을 적은 LIFETIMES.tsv가 나왔고, 둘 다 한 줄도 포팅하기 전에 적대적 검토를 거쳤다.

깨끗하게 컴파일된 회귀들

잡힌 것보다 빠져나간 것이 더 많은 걸 알려 준다. 섬너는 회귀 대부분이 두 언어에서 똑같아 보이지만 다르게 동작하는 구문에서 나왔다고 전했다. Zig의 assert는 함수라 인자가 모든 빌드에서 평가된다. 반면 Rust의 debug_assert!는 매크로여서 릴리스 빌드에서 표현식 전체를 지운다. 그 단언 안에 살아 있던 부수 효과, 즉 핫 리로드 그래프에 파일을 넣는 동작이 릴리스 빌드에서 조용히 멈췄고, 디버그 빌드는 초록불인 채로 React 패스트 리프레시가 깨졌다.

나머지도 모양이 같다. 뒤에 남는 홀수 바이트 하나를 조용히 무시하던 헬퍼가 bytemuck::cast_slice로 포팅되자 그 경우에 패닉을 냈고, UTF-16 바이트 순서 표시에서 프로세스가 죽었다. 64로 남아 있던 자리표시자 상수 하나가 인터닝된 파일명 상한을 840만에서 270,272로 끌어내렸는데, 실제 프로젝트가 닿는 한계였다. Bun의 색상 마커 포매터는 Zig의 컴파일 타임 평가를 잃고 치환된 인자 안쪽의 마커까지 다시 쓰기 시작했다. InfoQ는 이런 의미 회귀를 19건으로 집계했고, 여기에 보안 검토 11회와 상시 파서 퍼징에서 나온 풀 리퀘스트 15건이 더해졌다. 이 중 메모리 안전성 실패는 하나도 없었다. 빌림 검사기는 제 몫을 했다. 전부 의미의 실패였고, 그건 어떤 컴파일러도 잡지 못하는 범주다.

다시 쓰기로 실제로 얻은 것

성능 수치는 수수하고 정직하게 보고됐다. HTTP 처리량 2~5% 상승, vite build가 1.69초에서 1.65초로 줄어든 정도다. 진짜 소득은 메모리 규율이었다. Zig에서는 defer를 호출 지점마다 적어야 했지만 Rust의 Drop은 정리 작업을 자동으로 돌린다. 한 프로세스에서 같은 프로젝트를 2,000번 번들링하는 벤치마크는 v1.3.14에서 빌드마다 약 3MB씩 상한 없이 새던 것이 이제 평평해진다. 링커 최적화와 ICU 정리를 포팅과 함께 적용하자 바이너리 크기는 리눅스와 윈도에서 약 20% 줄었다. Claude Code는 6월 v2.1.181부터 Rust 빌드를 써 왔다. 리눅스 기동 속도가 10% 빨라졌지만, 섬너의 표현대로 알아챈 사람은 거의 없었다.

Zig 제작자의 반론

Zig를 만든 앤드루 켈리는 날 선 반박을 내놨다. 프레이밍 자체가 초점을 흐린다는 것이다. 버그는 스타일 가이드와 언어 기능 중 무엇을 고르느냐가 아니라 엔지니어링 자원을 거기에 쏟아부어야 없어진다는 지적이다. 그가 던진 더 날카로운 질문은 일관성에 관한 것이다. Bun의 테스트 스위트가 Zig 코드의 버그를 잡기에 충분하지 않았다면, 그 스위트가 사람이 읽지 않은 Rust 100만 줄을 검증하기에는 충분하다고 볼 근거가 무엇이냐는 것이다.

정당한 문제 제기이고, 정직한 답은 테스트 스위트가 유일한 통제 장치는 아니었다는 것이다. 적대적 리뷰, CI의 Miri, LeakSanitizer, 24시간 퍼징이 그 위에 겹겹이 얹혔다. 그 더미가 코드에 대한 인간의 이해를 대신할 수 있는지는 아직 검증되지 않은 채로 남아 있고, 그 점이 바로 쟁점이다.

이 사례를 지켜볼 이유

섬너가 공개한 비용, 즉 병합 전까지 캐시되지 않은 입력 토큰 59억 개와 출력 토큰 6억 9천만 개로 API 가격 기준 약 16만 5천 달러라는 수치는 사실상 영구적이던 결정의 가격표를 다시 매긴다. 성숙한 코드베이스의 언어 선택은 한번 지나면 되돌아올 수 없는 문이었지만, 이제는 예산 항목이다. 2025년 12월 Bun을 인수하고 섬너를 고용한 앤트로픽은 그 결론에 분명한 이해관계가 있으며, 이는 올해 배포된 여러 에이전트 주도 재작성 가운데 하나다. 남은 질문은 유지보수다. 사람이 끝까지 읽어 본 적 없는 코드베이스도 앞으로 몇 년간 사람 손으로 확장되고 디버깅되고 이해돼야 한다. 월간 CLI 내려받기 2,200만 건의 Bun이 업계가 그 답을 확인할 무대다.

자주 묻는 질문

Bun의 Rust 코드를 AI가 감독 없이 전부 썼나

아니다. 섬너는 11일 내내 워크플로를 지켜보며 출력을 직접 읽었고, 에이전트가 나쁜 결과를 내놓을 때마다 루프를 고쳤다. 적대적 리뷰어들이 실제 차이를 잡아내고 있는지 확인하는 방식으로 포팅을 검토했고, Zig와 Rust 코드를 나란히 놓고 상당 부분을 직접 읽었다.

보도는 4개월이라는데 포팅은 왜 11일인가

11일은 착수부터 모든 플랫폼에서 전체 테스트 스위트를 통과하기까지, 포팅 그 자체에 걸린 기간이다. 더 긴 수치는 추가 검증과 릴리스까지 흐른 시간을 반영한다. 기록 글은 2026년 7월에 나왔고 안정판 Bun v1.4.0은 8월에 뒤따랐다.

Bun에 Zig가 조금이라도 남아 있나

없다. Bun v1.3.14가 마지막 Zig 릴리스였고 v1.4.0이 첫 Rust 릴리스다. Bun의 약 20%는 여전히 C++이며 JavaScriptCore와 uWebSockets 같은 내장 의존성이 여기 포함되는데, 이번 재작성은 그 부분을 건드리지 않았다.

이 기사에 대한 반응을 남겨주세요!

SJ
로딩 중...

관련 기사

Perplexity는 에이전트 수백 개에 DB 코드를 맡겼다. 배포 권한만은 사람이 쥐었다.
Developer Tools

Perplexity는 에이전트 수백 개에 DB 코드를 맡겼다. 배포 권한만은 사람이 쥐었다.

Perplexity가 DynamoDB를 CobbleDB로 교체했다. 엔지니어 두 명과 배포 권한이 없는 에이전트 수백 개가 두 달 만에 만든 4만 줄짜리 Rust 저장소다.

Seung Jung4일 전
포럼 이미지 버그로 OpenAI 내부 저장소가 뚫렸다
Developer Tools

포럼 이미지 버그로 OpenAI 내부 저장소가 뚫렸다

Hacktron AI가 libheif 힙 오버플로와 OpenAI SSO 결함을 엮어 직원 Codex 계정과 openai/openai 모노레포에 도달했다. 두 취약점은 모두 수정됐다.

Seung Jung3일 전
14.5주 만에 Rust 83만 줄, 에이전트가 끌고 간 런타임 재작성
Developer Tools

14.5주 만에 Rust 83만 줄, 에이전트가 끌고 간 런타임 재작성

GitHub가 코딩 에이전트를 동원해 TypeScript 43만 줄을 14.5주 만에 Rust 83만 2,378줄로 옮겼다. 메모리 사용량은 1,383MB에서 126MB로 떨어졌다.

Seung Jung3일 전
Claude Code Projects, 병렬 클라우드 스레드를 지휘하는 조정자로 돌아왔다
Developer Tools

Claude Code Projects, 병렬 클라우드 스레드를 지휘하는 조정자로 돌아왔다

새로 설계된 Claude Code Projects는 작업 스레드 위에 조정자를 둔다. 스레드는 저마다 자기 브랜치에서 도는 완전한 클라우드 세션이고, 메모리는 함께 쓴다.

Seung Jung4일 전
Zed의 Delta, 풀 리퀘스트를 에이전트 스레드로 대체한다
Developer Tools

Zed의 Delta, 풀 리퀘스트를 에이전트 스레드로 대체한다

Zed의 Delta는 풀 리퀘스트를 에이전트와 리뷰어가 같은 맥락에서 일하는 공유 스레드로 바꾼다. 자사 저장소는 이미 PR을 꺼둔 상태다.

Seung Jung12시간 전
OpenAI "자체 모델이 Jalapeño 설계를 9개월로 줄였다"
Tech & Business

OpenAI "자체 모델이 Jalapeño 설계를 9개월로 줄였다"

AI가 작성한 커널이 OpenAI 전문가의 구현을 최대 1.8배 앞섰다. Jalapeño의 첫 InferenceX 벤치마크 결과가 공개됐다.

Seung Jung26일 전