拆 Zeta:一个 OMP 发行版是怎么维护上游、压缓存、接 Rust 的
写 Agent 的文章很多,但大部分在讲”怎么用”,很少讲”怎么把一个编码代理做成一个可持续维护的发行版”。最近我把 Zeta 的仓库从头翻了一遍,它值得拆一拆的地方不在于功能多,而在于它把几个真问题答得比较实在:fork 上游怎么不烂尾、长会话怎么压成本、重活怎么不拖后腿。这篇是记录。
先交代背景:Zeta 是 Bun-native 的编码代理发行版,构建在 OMP 运行时之上,目前 18603 个提交,monorepo 里 @linxiraos/* 包命名空间,Rust 原生引擎在 crates/ 下,构建链同时挂 Bazel 和 Nix。产品面(网页)上写的”子代理、计划模式、LSP/DAP、事后记忆、hashline 编辑、时间旅行规则”这些是结果,过程比结果有意思。
上游策略:release-tag 合并 + 语义移植,两条腿分开
任何基于开源上游做产品的团队都会遇到同一个问题:上游跑得飞快,你跟进,合并冲突爆炸;你不跟进,就烂尾成一个孤岛。Zeta 的对策是把”合并”和”移植”彻底分开,写死在文档里(document/upstream-sync.md):
- OMP(oh-my-pi)是运行时树,只在完整官方 release tag 上整合,绝不追裸上游 commit。每次发布在临时集成分支上以真实 Git 历史合并,然后单独的 commit 做 Zeta 的包名、品牌、Bun、CI 和产品适配。合并的 source tag、SHA、冲突决策、检查结果,全部记录在
upstream-sync.md里。 - Pi 和 Pi Web 只是语义移植来源,不是合并来源。Zeta 把 Pi 的上下文工程和扩展原语”翻译”进自己的架构,而不是把 Pi 的代码拉进来。
- OMP Web 是
web-ui/快照的来源。
这个策略的要点不是”我们跟进上游”,而是”跟进上游的节奏和方式被制度化”——什么能合、什么时候合、合了之后改什么,每个决策都有记录。fork 死掉通常不是技术问题,是决策没有留痕,改到哪一步没人说得清。
monorepo 与文档分层
Zeta 的主应用在 packages/coding-agent/,共享运行时包包括 packages/ai/、packages/catalog/、packages/agent/、packages/tui/、packages/natives/。有意思的是它把文档分成两棵树:
docs/是运行时文档,随产品打包——Agent 在运行时通过omp://docs/读它(已嵌入二进制和 npm 包;源码检出时读活目录)。覆盖工具、工具调用转换、skills、协议、配置和 Zeta 特性。document/是内部开发文档,永不打包——roadmap、上游同步台账、Pi 移植指南都在这里。
这个分层的动机很实际:让代理在运行时能自己读到产品文档,意味着 agent 不需要你教它”这个工具怎么用”,它自己 omp://docs/ 拉。这跟”上下文干净”是同一个哲学——把知识放在可按需读取的地方,而不是全部灌进系统提示。
缓存优先不是口号,是一套机制
Zeta 官网把”缓存优先”(cache-first)排在优先级第二。落到机制上,能对应到至少四个具体设计:
- Skills 渐进式披露——skills 是指令+工具组合的能力包,按需加载,声明目标就是不破坏提示缓存(”渐进式披露而不破坏提示缓存”是原话)。比起把几十个 skill 全量塞进上下文,只在用的时候注入。
- 自适应长期追踪(Zeta 原生能力)——持续会话观察,带常驻系统指引,目标明确写着”keep provider prefix caches stable across long sessions”(保持长会话中提供商前缀缓存稳定)。它维护的是整个系统的状态,而不是每次对话快照。
- 自动压缩——接近上下文上限时自动摘要旧消息,压缩策略可扩展定制。
- 动态上下文——扩展可在每轮前注入消息、过滤历史,甚至实现 RAG 或长期记忆。
为什么这么较真?因为长会话的成本是逐轮复利的:每轮全量送进模型的上下文,一个字节变了,整段前缀缓存就废。“缓存优先”和”功能多”是冲突的——功能越多,缓存越容易被搞碎。Zeta 的选择是:能力按需加载、工具定义组织成可缓存的结构、失败回退路径显式设计。
会话是树,不是日志
这个设计值得单独说。Zeta 的会话按树状存储:任意时刻可以回退到历史节点继续,分支和主线共存于同一个文件。配套的能力:
/export导出 HTML,/share上传成可分享链接;/collab建端到端加密的实时会话,参与者渲染同一会话、同一工具卡片;- 进程重启后
--continue回到原会话,保留完整推理与决策轨迹。
树状会话解决的是现实问题:agent 一次任务经常走岔路,走岔了你想回退到”做出错误决定之前”。日志式的会话回退只能回到某个历史时刻,树状能回到”某个时刻的某个分支之前”。--continue + 完整决策轨迹,对长项目来说基本是刚需。
命令、市场与原生扩展
Zeta 的扩展层是 TypeScript 模块,可访问工具、命令、快捷键、事件和完整 TUI。其中有几个设计值得抄:
- TypeScript 自定义命令——用户从
~/.zeta/commands/或项目命令目录定义斜杠命令,参数 schema 用arktype/typebox/zod,能访问完整运行时 API; - 命令市场——slash 命令作为 Bun 包安装和分享;
- ACP 协作内建——Agent Client Protocol 会话支持;
- 本地统计面板——
omp stats观测编码代理。
还有 /language zh 一键切换 CLI 语言、项目级 .zeta/ 与用户级 ~/.zeta/ 分层配置(Linux/Windows 位置一致)。这些单看不稀奇,但合起来指向一件事:Zeta 把”扩展”做成了协议,而不是做成了功能——权限门禁、路径保护、MCP 接入、沙箱执行、扩展发现,全是通过扩展机制提供的,而不是写死在核心里。核心只管编译、缓存和协议。
收束
翻完 Zeta 仓库,最有价值的不是某个功能,而是它处理三个永恒问题的态度:
- 上游怎么合——制度化:release tag 整合、语义移植、决策留痕;
- 成本怎么压——机制化:skills 渐进披露、前缀缓存稳定、自动压缩;
- 扩展怎么做——协议化:TS 模块、命令市场、MCP、运行时 API。
对一个工具来说,功能可以被抄,但这三套机制决定了它能不能活过上游的下一轮更新。这也是我把”OMP 兼容”当成它最值得看的设计而非营销词的原因。