Bun 从 Zig 到 Rust 的六天重写:AI 编程里程碑还是信任危机?——当 Claude Code 重写了它自己的运行时
引言:一个运行时重写了自己
2026 年 5 月 14 日,GitHub 上一个 PR 刷屏了整个技术圈:PR #30412,标题简洁到令人窒息——"Rewrite Bun in Rust"。
6755 个 commits,约 100 万行 Rust 代码,几乎全部由 Claude Code 智能体在 6 天内生成完成。这个 PR 把一个 9 万多 star 的 JavaScript 运行时从 Zig 语言整体迁移到了 Rust。新版本通过了 99.8% 的既有测试。
但就在六天前,Bun 创始人 Jarred Sumner 还在 Hacker News 上说:这堆代码"跑不起来","最后被全部扔掉的概率非常高"。
六天后,同样的代码变成了 Zig 版 Bun 的"最后一个版本"。
这不是一个普通的开源项目迁移故事。Bun 是 Anthropic 旗下 Claude Code 的核心基础设施——每天服务数百万开发者的 AI 编程助手运行在这个 JavaScript 运行时之上。而重写 Bun 的工具,正是 Claude Code 自己。
一个运行时,被运行在它之上的 AI 工具,用六天时间重写了自己。
这到底是 AI 编程的里程碑,还是一场信任危机的开始?
一、故事从头讲:Bun 的四年 Zig 之路
1.1 为什么是 Zig?
2022 年,前 Stripe 工程师 Jarred Sumner 发布了 Bun。目标很明确:用一个工具替代 Node.js 运行时、npm/yarn/pnpm 包管理器、Jest/Vitest 测试框架,以及部分构建工具链。
Bun 选择了 Zig 作为主要实现语言,这在当时是一个大胆的决定。Zig 是一个相对年轻的系统编程语言,主打:
- 与 C 的无缝互操作:Zig 可以直接
@cImportC 头文件,不需要 FFI 绑定层 - 手动内存管理但不隐藏分配:没有隐式分配器,每个分配都显式
- 编译期计算(comptime):Zig 的 comptime 能力让很多逻辑在编译期完成
- 没有隐式控制流:没有隐藏的错误处理、没有隐式类型转换
这些特性对 Bun 来说至关重要。Bun 需要深度嵌入 JavaScriptCore(Safari 的 JS 引擎)和大量 C/C++ 库(libuv、mimalloc、uWebSockets 等),Zig 的 C 互操作能力让这一切变得自然。
四年下来,Bun 积累了约 96 万行 Zig 代码,月下载量超 700 万次,GitHub star 破 9 万。一度是 Zig 社区最耀眼的明星项目。
1.2 Zig 的隐患:内存泄漏的噩梦
但 Zig 版 Bun 有一个持续困扰的致命问题:内存泄漏。
这个问题不是小事。2026 年 3 月 12 日,编号 #33453 的 Issue 描述了一个令人窒息的场景:Claude Code 主进程的 RSS 内存从约 1.7GB 在 3 小时内增长到 14GB 以上。泄漏源头是 Bun 运行时的 WebKit Malloc 分配器。
另一份 Issue #11377 更夸张:运行 14 小时后,Claude Code 进程占用 23GB 虚拟内存,143.8% CPU,系统直接卡死。
对于一个宣称"3 毫秒启动时间"的运行时来说,运行几小时后吃掉 14GB 内存,讽刺感十足。
Bun v1.1.13 曾宣称更换内存分配器使内存占用下降 5%,但用户不买账。Reddit 用户 Xtergo 的吐槽很有代表性:Bun 的路线图总是侧重新功能发布,而不是稳定性和 Bug 修复。
与此同时,Bun 的 GitHub 上有约 4700 个未关闭的 Issue,与 Node.js 相比问题密度明显更高。
1.3 Zig 社区的哲学冲突
内存泄漏只是表象。更深的裂痕在于 Bun 与 Zig 社区的哲学分歧。
Bun 曾 fork 了 Zig 编译器,做了一些优化。但这些优化无法 upstream 回 Zig 官方——原因是 Zig 社区严格的 "no AI policy",禁止 AI 生成的 issue、PR 和代码贡献。
一边是 Zig 社区封禁 AI 生成代码,另一边是 Bun 团队正用 Claude agent 迁移 Zig 代码。这种根本性的价值观冲突,使得 Bun 在 Zig 生态中越来越孤立。
所以当 Jarred 说"厌倦了修复内存泄漏"时,背后还有一层含义:在 Zig 的路上走下去,不仅技术上难,社区上也难。
二、Anthropic 收购:从开源明星到 AI 基础设施
2.1 数亿美元的战略卡位
2025 年 12 月 3 日,Anthropic 宣布收购 Bun。交易金额未公开,但据多个消息源透露为数亿美元。
这不是一次普通的"大厂收开源项目"。Anthropic 的核心业务是 Claude Code——一个 AI 编程助手,其年化收入在 2026 年初已突破 10 亿美元,占 Anthropic 大部分营收来源。
Claude Code 负责人曾公开表示:Bun 启动时间约 3 毫秒,Python 启动慢约 15 倍。Bun 作为 Claude Code 的运行时,直接影响用户体验。
收购的逻辑很清晰:AI 模型 ↔ 开发工具链 ↔ 运行时,闭环正在形成。
Anthropic 需要让 Claude Code 跑得更快、更稳定。Bun 是为速度而生的 JavaScript 工具链,但它的内存泄漏正在拖垮 Claude Code。
2.2 七人团队与 700 万月下载量
收购细节:Anthropic 雇用了 Bun 的 7 名员工,项目继续按 MIT 许可证开源。
一个 700 万月下载量的项目,只有 7 个人维护,还没有产生收入。这在开源世界里不算罕见,但当你把它放到"服务年收入 10 亿美元产品"的位置上时,这个数字就显得很紧张了。
7 个人要维护一个同时是运行时、包管理器、打包器、测试工具的 All-in-One 项目,还要修复困扰核心客户的内存泄漏。这不是能不能做到的问题,是资源够不够的问题。
这时候,AI 编程工具出场了。
三、六天重写:Claude Code 重写了 Bun
3.1 "实验分支"的开始
2026 年 5 月 5 日前后,Bun 仓库出现了一个名为 claude/phase-a-port 的新分支。内部有数十万行 AI 生成的 Rust 代码,与原始 Zig 实现并存,还有一份 576 行的 Zig-to-Rust 迁移指南。
Jarred 的说法很谨慎:"这只是实验,尚未承诺重写,甚至很大概率会全部丢掉。"
3.2 三天:从"跑不起来"到"勉强能动"
5 月 7 日,Jarred 透露 Rust 迁移涉及约 4000 次 commit、96 万行代码,只剩 3 个编译错误。Rust 版本已经能显示 help menu,bun run 和 package.json scripts 也能执行 JavaScript 了。
但他依然表示当前状态"勉强能动",不能交付,还需要清理代码和让 Claude 啃测试套件。
有人惊呼:"Claude 只用三天就把 Zig 版 Bun 重写成 Rust 了吗?" Jarred 确认:按代码量来看,准确。
3.3 六天:99.8% 测试通过
5 月 9 日,Rust 重写版本在 Linux x64 glibc 环境下通过了 Bun 既有测试套件的 99.8%。
5 月 11 日,Jarred 发推文:"Bun v1.3.14 将于明日发布。如果我们合并 Rust 重写版本,这将是 Zig 的最后一个版本。"
5 月 14 日,PR #30412 合并进 main。
从"可能全部扔掉"到"Zig 的最后一个版本",只用了六天。
3.4 重写的技术策略:"忠实移植"
Bun 团队采用了"忠实移植"(faithful porting)策略:Claude Code 尽可能逐行将 Zig 代码翻译为 Rust 代码,保持原有逻辑和结构不变。
这种策略的好处是:翻译速度快,行为一致性高(所以 99.8% 的测试能通过)。
但这种策略的代价极大:它直接把 Zig 的手动内存管理模式搬运到了 Rust,结果就是大量的 unsafe 代码块。
四、13,365 个 unsafe:Rust 的安全承诺被架空了吗?
4.1 一个令人震惊的数字
5 月 21 日,Bun 官方发布了一份 unsafe 审计页面,确认 Rust port 有 13,365 个 unsafe blocks。
Theo 在 X 上做了一个对比,这个对比后来被反复引用:
| 项目 | Rust 代码行数 | unsafe 调用数 |
|---|---|---|
| uv(Astral 的 Python 包管理器) | 约 35 万行 | 73 |
| Bun Rust port | 约 68.1 万行 | 13,365+ |
uv 是目前体量与 Bun 最接近的知名 Rust 项目之一。代码量差约 2 倍,unsafe 数量差约 183 倍。
4.2 为什么有这么多 unsafe?
Bun 官方的解释分三类:
- FFI 边界:Bun 需要与 JavaScriptCore、libuv、mimalloc、uWebSockets 等 C/C++ 组件深度交互,这些调用本身就需要 unsafe
- 从 Zig port 过来的 ownership idiom:Zig 是手动内存管理,没有 Rust 的所有权系统。"忠实移植"意味着直接把指针操作翻译成 unsafe Rust,而不是重构为 safe Rust 的所有权模式
- 少量性能路径:某些热点代码路径为了性能而使用 unsafe
官方声称:约 9,300 个 unsafe 可以转成 safe code,约 4,000 个会保留在必要边界上。
4.3 "可以转成 safe" ≠ "已经转成 safe"
这里有一个关键的逻辑问题:说"可以转成 safe"和"已经转成 safe"是完全不同的事情。
"忠实移植"策略产生的 unsafe 代码,本质上是 Zig 内存管理模式的 Rust 翻译。要把这些 unsafe 转成 safe,意味着要对整个代码库做一次所有权重构——这不是小修小补,而是一次与"忠实移植"策略完全相反的架构级重写。
而这次重写由谁来做?大概率又是 Claude Code。但上一次 Claude Code 的"忠实移植"已经产生了 13,365 个 unsafe。如果让 Claude Code 再做一次"安全重构",它能不能理解每个 unsafe 块背后的所有权语义?能不能正确判断哪些可以安全移除?
这是一个未解决的研究难题。 Amazon 曾专门发起项目来验证 unsafe Rust 代码的安全性。Rust 标准库自身也存在因 unsafe 导致的 CVE 漏洞。目前学术界的方法仍然有限。
4.4 unsafe 的真正风险:不是"会崩溃",而是"没人能审查"
13,365 个 unsafe blocks 分布在 700 多个文件里。这意味着:
- 平均每个文件约 19 个 unsafe 块
- 任何单个 unsafe 块都可能引入内存安全漏洞
- 审查所有 unsafe 块需要理解每个块背后的所有权 invariant
但这次重写没有人类完整审查过代码。Bun 团队依赖的是测试套件,而测试套件验证的是接口行为一致性,不是内存安全性。
一个有 13,365 个 unsafe 块的代码库,没有人完整审查过,要服务数百万用户。 这才是问题的核心。
五、社区的反应:信任危机的三个维度
5.1 yt-dlp:明确的版本上限
5 月 20 日,yt-dlp 在 GitHub issue #16766 中宣布:Bun 作为 EJS 兼容 JavaScript runtime 的支持将被限制并弃用。
它把支持范围限定到 Bun 1.2.11 到 1.3.14——也就是原 Zig 代码库的版本范围。
理由两层:
- 早期 Bun 版本构建 EJS 时可能忽略 lockfile,结合近期 npm 供应链攻击背景被认为有安全风险
- Bun 最近用 Claude 重写成 Rust,维护者认为其开发方向有"fully vibe-coded"的趋势
"vibe-coded"这个词杀伤力很大。它暗示代码不是经过深思熟虑设计的,而是凭感觉(vibe)生成的。
5.2 Electrobun:直接解耦
Electrobun 原本把 Bun 放在架构核心:官方文档写着 Electrobun app 本质上是一个 Bun app。主进程跑 Bun,通过 Bun FFI 调用原生能力。
5 月 23 日,Electrobun 作者 Yoav 在 X 上宣布 Electrobun 2.0 将与 Bun 解耦。
他的理由很直白:"如果你们不读自己的代码,那我就不敢让自己的项目站在你们的肩膀上。"
这件事的核心不是技术谁强谁弱,而是信任问题。
5.3 Sentry CLI、OpenTUI 等:静默迁移
还有一批项目在近期移除了 Bun 的痕迹:
- Sentry CLI:PR #1002,"remove Bun artifacts and convert remaining Bun APIs",这是 Bun → Node.js 迁移的 Phase 5
- OpenTUI:PR #1027,移除 Bun-specific runtime dependencies
- Variableland/dx:从 Bun runtime 迁到 Node.js
这些迁移动机不完全相同——有些发生在 Rust rewrite 合并之前,更像项目主动做 runtime-agnostic。但它们共同指向一个趋势:Bun 正在从"值得信赖的基础设施"变成"需要谨慎对待的依赖"。
六、技术深度:Zig vs Rust 在运行时场景的真实对比
6.1 C 互操作:Zig 的天然优势 vs Rust 的显式边界
Bun 需要深度交互的 C/C++ 库:
// Zig:直接 @cImport,零额外绑定层
const jsc = @cImport({
@cInclude("JavaScriptCore/JavaScript.h");
@cInclude("JavaScriptCore/JSBase.h");
});
// 直接调用,不需要写 binding
const ctx = jsc.JSGlobalContextCreate(null);
const value = jsc.JSValueMakeString(ctx, jsc.JSStringCreateWithUTF8CString("hello"));
// Rust:需要 unsafe + 显式 FFI 声明
extern "C" {
fn JSGlobalContextCreate(null: *mut c_void) -> *mut JSGlobalContextRef;
fn JSValueMakeString(
ctx: *mut JSGlobalContextRef,
str: *mut JSStringRef,
) -> *mut JSValueRef;
}
// 调用必须包在 unsafe 里
unsafe {
let ctx = JSGlobalContextCreate(null);
let value = JSValueMakeString(ctx, js_string);
}
Zig 的 @cImport 是编译期自动生成绑定,零手动工作。Rust 需要 extern "C" 声明 + unsafe 包裹 + 手动管理生命周期。这正是 Bun Rust port 有大量 unsafe 的一个根本原因——与 C/C++ 库交互本身就需要 unsafe。
6.2 内存管理:Zig 的显式分配 vs Rust 的所有权系统
// Zig:显式分配器,每个分配都可见
const Allocator = std.mem.Allocator;
fn create_buffer(alloc: Allocator, size: usize) ![]u8 {
const buf = try alloc.alloc(u8, size);
return buf;
}
// 使用时显式传分配器
var buf = try create_buffer(gpa, 1024);
defer gpa.free(buf); // 手动释放,但模式清晰
// Rust:所有权系统,自动释放
fn create_buffer(size: usize) -> Vec<u8> {
Vec::with_capacity(size) // 自动释放,当 Vec 离开作用域
}
// 但"忠实移植"版本:
unsafe fn create_buffer_raw(size: usize) -> *mut u8 {
let layout = std::alloc::Layout::from_size_align(size, 1).unwrap();
std::alloc::alloc(layout) // 手动分配,需要手动释放
}
unsafe fn free_buffer(ptr: *mut u8, size: usize) {
let layout = std::alloc::Layout::from_size_align(size, 1).unwrap();
std::alloc::dealloc(ptr, layout);
}
"忠实移植"把 Zig 的手动分配模式直接翻译成了 unsafe Rust 的 alloc/dealloc,完全绕过了 Rust 的所有权系统。这样做测试确实能通过(行为一致),但 Rust 的核心安全保证被架空了。
6.3 错误处理:Zig 的 error union vs Rust 的 Result
// Zig:error union,编译期穷举
const OpenError = error{FileNotFound || PermissionDenied || DiskFull};
fn open_file(path: []const u8) OpenError!File {
return try std.fs.cwd().openFile(path, .{});
}
// 调用时必须处理所有错误
const file = open_file("data.txt") catch |err| switch (err) {
error.FileNotFound => ...,
error.PermissionDenied => ...,
error.DiskFull => ...,
};
// Rust:Result + ? 操作符
#[derive(Debug)]
enum OpenError {
FileNotFound,
PermissionDenied,
DiskFull,
}
fn open_file(path: &str) -> Result<File, OpenError> {
std::fs::File::open(path).map_err(|e| match e.kind() {
std::io::ErrorKind::NotFound => OpenError::FileNotFound,
std::io::ErrorKind::PermissionDenied => OpenError::PermissionDenied,
_ => OpenError::DiskFull,
})?;
// ...
}
// 调用
let file = open_file("data.txt")?;
Zig 的 error union 在编译期强制穷举所有错误变体,Rust 的 Result 也通过类型系统强制处理,但模式匹配不是穷举的(可以有通配符)。两者在错误处理的哲学上不同,但"忠实移植"策略让这些差异被扁平化了。
七、AI 重写的深层问题:不只是 unsafe
7.1 测试通过率 ≠ 安全性 ≠ 可维护性
99.8% 的测试通过率说明了什么?
- 说明新实现与旧实现在已有测试覆盖的行为上一致
- 不说明代码没有未覆盖的路径
- 不说明抽象边界清晰
- 不说明未来维护者能读懂
- 不说明内存安全
- 不说明并发安全
这个道理在软件工程里是常识,但在 AI 大规模改写的语境下容易被忽略。因为"99.8%"这个数字看起来太好了。
7.2 代码审查的缺席
在 Hacker News 讨论中,人们关注的核心问题之一是:实际没人完整审查过这百万行代码。
Bun 团队依赖测试套件验证迁移结果。但测试套件验证的是接口行为一致性,不是迁移的核心目标——Jarred 说的重写理由是"安全性",而测试不验证安全性。
在正常的开源流程中,百万行级别的 PR 应该经过分阶段审查、架构讨论、安全审计。这次重写直接合并了 6755 个 commits 的巨型 PR,审查机制被 AI 的速度绕过了。
7.3 Jarred 的预言:"禁止人类贡献代码"
Jarred 曾在 X 上预言:开源软件未来可能"禁止人类贡献代码"。
Bun 重写是此预言的首次大规模公开演练。但现实比预言复杂得多——AI 能快速完成跨语言迁移,但缺少人类审查机制导致了 unsafe 泛滥、社区信任流失、依赖项目出走。
AI 可以加速迁移,但不能替代信任建设。
7.4 "后续清理"的悖论
官方说约 9,300 个 unsafe 可以转成 safe。但谁来清理?大概率又是 Claude Code。
这就产生了一个悖论:
- 第一次用 AI "忠实移植"产生了 13,365 个 unsafe
- 用 AI 清理 unsafe 需要理解每个块背后的所有权语义
- AI 的理解能力是否足以安全地移除 unsafe?不确定
- 即使 AI 能移除大部分,剩余的 4,000 个必要 unsafe 仍需人类审查
- 但人类审查 4,000 个 unsafe 块的工作量就已经非常巨大
这不是一个可以"后续清理"的问题,而是一个需要从头重新设计架构的问题。
八、更宏观的视角:AI 重写软件的大趋势
8.1 不止是 Bun
类似的 AI 驱动极限重写在多领域同步发生:
- Cloudflare:一周内借助 AI 重新实现了 Next.js API 的大部分能力
- Ladybird 浏览器:两周内将 JavaScript 引擎从 C++ 迁移到 Rust
- Crab Code:社区正在用 Rust 重写 Claude Code 本身(16 个 crate,4 层架构)
这些项目共同指向一个趋势:AI 正在把"代码重写"从"数月/数年"级别压缩到"数天/数周"级别。
8.2 速度与质量的永恒张力
每个 AI 重写案例都面临同样的张力:
| 维度 | AI 重写的优势 | AI 重写的风险 |
|---|---|---|
| 速度 | 数天完成百万行迁移 | 没有足够的审查时间 |
| 行为一致性 | 测试通过率高 | 测试覆盖不了安全性和可维护性 |
| 成本 | 远低于人工重写 | 后续清理成本可能更高 |
| 可解释性 | 代码存在但没人理解 | 出问题时定位困难 |
这不是"AI 不行"或"Rust 不行"的问题。这是如何负责任地使用工具的问题。
8.3 CTO 的新问题
未来,当 CTO 考虑代码库重写时,可能会问:"Claude 需要几天?"
但更正确的问题应该是:"Claude 重写完后,我们需要多少人来审查?审查能不能跟上?审查完了之后,我们能不能信任这段代码运行在生产环境?"
九、实用指南:如果你正在用 Bun
9.1 不要恐慌式删除
首先,Bun 1.3.14仍然是原 Zig 实现。官方也明确说 Rust port 还没进正式 release。你今天安装的 Bun 跑的仍然是 Zig 版本。
9.2 拆开看用途
把 Bun 的用途拆开看:
只是包管理器(bun install):
- 关注 lockfile 的完整性、CI 可复现性、供应链扫描
- 包管理器的风险相对较低,因为不涉及运行时行为
是测试运行器(bun test):
- 确认测试语义与 Node/Vitest/Jest 的差异是否影响结果
- 测试运行器在 CI 里跑,出了问题容易定位
是生产运行时(bun run):
- 谨慎使用 Bun-only API,尤其是 FFI、HTTP server、数据库、子进程、文件系统这些靠近系统边界的能力
- 生产运行时的风险最高,因为直接影响用户
是给外部用户安装的工具:
- 尽量不要把 Bun 作为唯一可用 runtime,至少提供 Node/Deno 路径
- 外部用户的环境不可控,Bun 的兼容性问题会被放大
9.3 关注版本锁定
如果你依赖 Bun,建议:
- 锁定版本到 1.3.x,直到 Rust port 进入正式 release 并经过社区验证
- 在 CI 中监控 Bun 内存使用,设置合理的上限
- 不使用 Bun-only API 作为核心逻辑,保持与 Node.js 的兼容路径
9.4 锁文件示例
// package.json — 保持 Node.js 兼容路径
{
"scripts": {
"dev": "node --watch server.js",
"dev:bun": "bun run --watch server.js",
"test": "vitest run",
"test:bun": "bun test"
}
}
# CI 配置 — 双路径
test:
runs-on: ubuntu-latest
strategy:
matrix:
runtime: [node-22, bun-1.3.14]
steps:
- uses: actions/checkout@v4
- name: Install
run: |
if [[ ${{ matrix.runtime }} == "bun" ]]; then
curl -fsSL https://bun.sh/install | bash -s "bun-v1.3.14"
else
npm ci
fi
十、关于 Rust 和 unsafe 的技术实践
10.1 Rust 项目中 unsafe 的正常密度
参考一些知名 Rust 项目:
| 项目 | unsafe 数量 | 代码行数 | unsafe/万行 |
|---|---|---|---|
| uv | 73 | ~35 万 | ~0.2 |
| ripgrep | ~10 | ~2 万 | ~0.5 |
| tokio | ~200 | ~15 万 | ~1.3 |
| Rust 标准库 | ~3000 | ~30 万 | ~10 |
| Bun Rust port | 13365 | ~68 万 | ~19.6 |
Bun Rust port 的 unsafe 密度约为 uv 的 100 倍,约为 Rust 标准库的 2 倍。
Rust 标准库的高 unsafe 密度是可以理解的——它本身就是构建 safe 抽象的基础层,必须使用 unsafe 来实现底层能力。但 Bun Rust port 不是基础层,它是一个应用级运行时,其 unsafe 密度应该远低于标准库。
10.2 正确的 unsafe 使用模式
// 正确模式:unsafe 块小而明确,有文档说明 invariant
/// # Safety
///
/// `ptr` must point to a valid, non-null, aligned UTF-8 string of `len` bytes.
/// The string must not be modified during the lifetime of the returned &str.
unsafe fn str_from_raw_parts(ptr: *const u8, len: usize) -> &str {
// unsafe 块尽可能小
unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len)) }
}
// 错误模式(Bun port 中的常见模式):整个函数都是 unsafe
unsafe fn transpile_module(
source: *const c_char,
source_len: usize,
allocator: *mut Allocator,
) -> *mut TranspileResult {
// 整个函数体都是 unsafe
// 没有 Safety 文档
// 没有明确的 invariant 说明
let src = unsafe { std::slice::from_raw_parts(source as *const u8, source_len) };
let result = unsafe { jsc_transpile(src, allocator) };
result
}
前者是 Rust 社区推荐的 unsafe 使用模式:小块、有文档、有 invariant。后者是"忠实移植"产生的典型模式:大块、无文档、invariant 隐含在原始 Zig 逻辑中。
10.3 一个 safe Rust 重写的想象
如果不用"忠实移植",而是用 Rust 的所有权系统重新设计 Bun 的核心模块:
// 假设:用 safe Rust 设计 JavaScriptCore 的绑定层
pub struct JSCContext {
inner: NonNull<JSGlobalContextRef>,
}
impl JSCContext {
pub fn new() -> Self {
// unsafe 被隔离在构造函数中,并最小化
let ctx = unsafe { JSGlobalContextCreate(std::ptr::null_mut()) };
Self {
inner: NonNull::new(ctx).expect("JSGlobalContextCreate returned null"),
}
}
pub fn evaluate_script(&mut self, script: &str) -> Result<JSCValue, JSCError> {
// safe API,内部 unsafe 被封装
let script_ref = JSCStringRef::from_str(script);
let result = unsafe {
JSEvaluateScript(
self.inner.as_ptr(),
script_ref.as_ptr(),
std::ptr::null_mut(), // thisObject
std::ptr::null_mut(), // sourceURL
0, // startingLineNumber
std::ptr::null_mut(), // exception
)
};
// ...
}
}
impl Drop for JSCContext {
fn drop(&mut self) {
unsafe { JSGlobalContextRelease(self.inner.as_ptr()) };
}
}
这种设计把 unsafe 隔离在构造/析构和少量 FFI 调用中,对外提供 safe API。但实现这种设计需要对 JavaScriptCore 的生命周期有深入理解,并花时间重新设计每个绑定层——这正是"忠实移植"策略跳过的步骤。
十一、Electrobun 分家的深层含义
11.1 为什么"不读代码"是致命的?
Electrobun 作者 Yoav 的决定值得深入分析。
Electrobun 是一个桌面应用框架,架构核心就是 Bun:主进程跑 Bun,通过 Bun FFI 调用原生能力。Electrobun app 本质上是一个 Bun app。
Yoav 说:"如果你们不读自己的代码,那我就不敢让自己的项目站在你们的肩膀上。"
这句话揭示了一个核心问题:基础设施项目的价值不只是代码本身,还有代码的可解释性和可审查性。
当你的项目站在别人的肩膀上时,你需要信任那个肩膀。信任的基础不是"代码能运行",而是:
- 我知道这段代码为什么这样写——可解释性
- 我知道这段代码的边界在哪里——可审查性
- 我知道出问题时谁能修复——可维护性
- 我知道升级时会发生什么——可预测性
百万行 AI 生成的代码,无论测试通过率多高,在上述四个维度上都存在不确定性。
11.2 分家的技术代价
Electrobun 2.0 要与 Bun 解耦,意味着需要:
- 替换 Bun FFI 调用为其他机制(可能用 Tauri 的方案或直接用系统原生 API)
- 重写主进程的运行时依赖(可能改用 Node.js 或 Deno)
- 重新设计进程间通信机制
这是一次不小的架构重构。Yoav 愿意承担这个代价,说明他对"信任成本"的评估已经超过了"重构成本"。
十二、从 Zig 社区的角度看
12.1 Zig 的"no AI policy"
Zig 社区的"no AI policy"在当下显得极端,但它有其逻辑基础:
- AI 生成的代码缺乏可解释性:你不知道 AI 为什么做出某个选择
- AI 生成的 issue/PR 增加维护负担:维护者需要花时间审查低质量贡献
- AI 生成的代码可能引入微妙的安全问题:AI 不会主动考虑安全问题
Bun 的 AI 重写事件某种程度上验证了 Zig 社区的担忧:13,365 个 unsafe、没人审查代码、社区信任流失——这些问题都源于 AI 生成代码的质量控制不足。
12.2 Zig 的技术价值不应被否定
Bun 选择离开 Zig,不代表 Zig 本身有问题。Zig 的 C 互操作能力、comptime、显式分配器在系统编程领域有独特价值。问题在于 Bun 项目的具体场景(JavaScript 运行时 + 大量未关闭 issue + 内存泄漏 + 与 Zig 社区的哲学冲突),而不是 Zig 语言本身。
Zig 依然是一个值得关注的语言。Bun 的离开是项目层面的决策,不是语言层面的否定。
十三、AI 编程工具的自我循环
13.1 Claude Code 重写了运行自己的运行时
这个故事的隐喻性很强:Claude Code 运行在 Bun 之上,Bun 有内存泄漏拖垮了 Claude Code,Claude Code 用自己重写了 Bun。
这是一个自我修复循环:工具修复了运行工具的基础设施。
但这个循环也暴露了一个问题:谁来验证修复是否正确?
如果 Claude Code 自己验证自己的重写结果,那这就是一个自证循环——工具自己证明自己做得对。正常的验证流程应该是独立的第三方审查,但在这次重写中,这个环节缺失了。
13.2 Anthropic 的战略考量
Anthropic 收购 Bun 的核心目标是让 Claude Code 跑得更快更稳。重写从 Zig 到 Rust 的迁移,从 Anthropic 的角度看是合理的:
- Bun 的内存泄漏直接影响 Claude Code 的用户体验
- Rust 的所有权系统理论上可以防止内存泄漏
- Claude Code 可以快速完成迁移
但战略合理性不等于执行合理性。迁移方式(忠实移植 + 直接合并巨型 PR)绕过了正常的审查流程,导致了社区信任流失。
Anthropic 可能得到了一个更快的 Bun,但失去了一个更被信任的 Bun。
十四、结论与展望
14.1 这次重写的三个关键结论
AI 可以快速完成代码迁移,但不能替代人类审查:99.8% 的测试通过率不等于安全性、可维护性、可解释性。
"忠实移植"策略在跨语言迁移中是不安全的:把一种语言的内存管理模式直接翻译成另一种语言的 unsafe 模式,绕过了新语言的安全保证。
基础设施项目的核心价值是信任,不是速度:对底层工具来说,最贵的不是写代码的时间,而是让别人相信这段代码值得运行在自己的机器上。
14.2 给开发者的启示
- 在使用 AI 重写代码时,必须安排人类审查,尤其是涉及内存安全、并发安全的代码
- 在选择基础设施依赖时,关注项目的审查流程和信任机制,不只是性能和功能
- 在设计 Rust 项目时,遵循 unsafe 最小化原则:小块、有文档、有 invariant 说明
- 在跨语言迁移时,应该重新设计架构以利用新语言的安全特性,而不是逐行翻译
14.3 给 AI 编程工具开发者的启示
- AI 编程工具应该内置安全审查机制:在生成 unsafe 代码时自动提示风险
- AI 编程工具应该生成 Safety 文档:为每个 unsafe 块自动生成 invariant 说明
- AI 编程工具应该支持分阶段审查:不是一次性生成百万行代码,而是分模块生成、审查、迭代
- AI 编程工具应该提供代码可解释性:不只是生成代码,还要解释为什么这样写
14.4 Bun 的未来
Bun 仍然有真实价值,也有足够强的工程团队。Rust rewrite 也可能最终变成一个成功案例——如果后续清理能把 unsafe 数量降到合理水平,如果社区信任能重建,如果 Rust 的所有权系统确实解决了内存泄漏问题。
但它已经给所有开源基础设施项目提了一个醒:AI 可以加快迁移,不能替代信任建设。
六天重写百万行代码的速度令人惊叹。但速度不是唯一维度。对底层工具来说,可预测性比速度更重要。你需要知道什么时候升级,怎么回滚,谁负责安全公告,谁会审查关键路径。
附录:关键时间线
| 时间 | 事件 |
|---|---|
| 2022 年 | Bun 发布,Zig 实现,Jarred Sumner 创建 |
| 2025 年 12 月 3 日 | Anthropic 收购 Bun,7 名员工加入,MIT 开源继续 |
| 2026 年 3 月 12 日 | Claude Code 内存泄漏 Issue #33453,RSS 3小时从1.7GB到14GB |
| 2026 年 5 月 5 日 | Bun 仓库出现 claude/phase-a-port 分支 |
| 2026 年 5 月 7 日 | Rust 迁移约 4000 commits,只剩 3 个编译错误 |
| 2026 年 5 月 9 日 | Rust 版本通过 99.8% 测试 |
| 2026 年 5 月 11 日 | Jarred 推文:v1.3.14 是 Zig 的最后一个版本 |
| 2026 年 5 月 14 日 | PR #30412 合并进 main:6755 commits,约100万行 Rust |
| 2026 年 5 月 21 日 | 官方发布 unsafe 审计页面:13,365 个 unsafe blocks |
| 2026 年 5 月 20 日 | yt-dlp 限制并弃用 Bun 支持 |
| 2026 年 5 月 23 日 | Electrobun 2.0 宣布与 Bun 解耦 |
参考资料
- Anthropic: Anthropic acquires Bun as Claude Code reaches $1B milestone
- Bun PR #30412: Rewrite Bun in Rust
- Bun unsafe 审计页面: Bun's unreleased Rust port has 13,365 unsafe blocks
- The Register: Bun posts Rust porting guide, says rewrite is still half-baked
- Heise: AI Porting: Claude Rewrites Bun Codebase in Rust
- yt-dlp issue #16766: Bun support is now limited and deprecated
- Yoav / Electrobun: Electrobun 2.0 will be decoupled from Bun
- Sentry CLI PR #1002: remove Bun artifacts
- OpenTUI PR #1027: remove Bun-specific runtime dependencies
- CSDN: Bun 六天完成从 Zig 到 Rust 重写,AI 重写软件大趋势下速度与质量难题待解
- CSDN: Bun 被 AI 重写后,很多开源项目开始远离 Bun
- CSDN: Bun 百万行代码 9 天由 AI 重写,99.8% 测试通过率背后超万个 unsafe 代码块藏隐患