数据截至 (上游 commit 565d53515b54)
原生核心:进程内、无 fork-exec 的 Rust 层
30 秒导读: 大多数编码 agent 想搜代码就
spawn("rg", ...)、想跑命令就spawn("bash", ...)。oh-my-pi 反其道:把这些活写成一层约六万行的 Rust,通过 N-API(Node/Bun 的原生扩展接口)直接在 agent 进程内调用——搜索、发现、结构摘要、分词、语法高亮全程不起子进程;连 bash 都是内嵌的解释器。本章讲这层怎么搭、跨 macOS/Linux/Windows 三平台怎么取舍、JS 和 Rust 之间的绑定契约长什么样。
1. 这是什么(零基础也能懂)
一句话定义: 原生核心是 oh-my-pi 的"手脚下沉层"——把编码 agent 每天要用的重活(文件搜索、内容 grep、目录遍历、AST 结构摘要、token 计数、shell 执行、工作区克隆)用 Rust 实现,编译成一个 .node 动态库,让 JavaScript 侧像调普通函数一样直接调用。
它替谁干活: 一个 agent 主循环(见 主循环与回合模型)在一次回合里可能要 grep 上万个文件、给上下文算 token 预算、把长文件折叠成结构摘要。别的 harness 通常这么干:
别的 harness: Node 进程 ──spawn──▶ rg 子进程 (读文件、匹配、把结果打回 stdout)
──spawn──▶ fd 子进程
──spawn──▶ bash 子进程
──spawn──▶ tiktoken(Python)
每个 spawn 都要:找到二进制、拉起进程、串行化参数、等 stdout、解析文本、清理僵尸进程。启动开销、跨进程拷贝、平台差异(Windows 没有 fork)全砸在你脸上。
oh-my-pi 的做法: 把这些做进同一个进程。
oh-my-pi: Node/Bun 进程
└─ N-API ─▶ Rust: grep() (grep-searcher 库,直接读内存/mmap)
glob()/fuzzyFind()
summarizeCode() (tree-sitter)
countTokens() (tiktoken-rs)
Shell.run() (brush:内嵌 bash 解释器)
为什么值得: 三个直接好处——
| 好处 | 原因 |
|---|---|
| 快 | 没有进程启动开销;结果通过 N-API 直接变成 JS 对象,不经过"文本序列化→再解析"这一圈 |
| 跨平台一致 | Rust 一份代码编译到三平台;不用担心用户机器上装没装 rg/fd,也不用为 Windows 缺 fork 单开逻辑 |
| 可控 | 取消、超时、并发上限、性能采样都是自己的代码说了算,不是"祈祷子进程听 SIGTERM" |
一句话直觉: 把"外包给命令行工具"改成"自己长出这些器官"。ripgrep 不再是一个你 exec 的程序,而是一个你 use 的库(grep-searcher、grep-regex);bash 不再是 /bin/bash,而是一个用 Rust 写的、活在你进程里的 bash 解释器(brush)。
一处诚实的边界(先说,后面 §6 展开): "无 fork-exec" 是这层搜索/发现/编辑/分词类工具的性质,不是全部。真正绕不开子进程的地方它照样 spawn:PTY 交互式命令要拉起真实进程(pty.rs),工作区隔离的兜底后端要调 git worktree(rcopy.rs)。内嵌的 bash 解释器本身在进程内,但你脚本里写 git status,那个 git 仍然是外部子进程。本章会把"哪些真进程内、哪些仍 spawn"标清楚。