
这是什么
一个用 Rust 写的、本地优先的编码 agent 控制中枢。每台设备各跑一个小引擎,会话就存在那台设备上;新装的程序默认只走本地模式,不需要账号,也不需要联网,登录是一个单独的步骤,只改变引擎下一次启动时选的 profile。桌面端是套在这个引擎上的一扇 gpui 窗口——侧边栏本身就是数据,是一张按注意程度排序的会话列表,按 space(设备加文件夹的组合)分组——同一个二进制也能 headless 运行,所以一台常开的机器可以在你合上笔记本之后继续让 agent 干活。八种 agent 共用一套界面(Claude Code、Codex、Cursor、Devin、Grok、Hermes、Pi 与 Antigravity),各自走自己的子进程或 JSON-RPC 协议,再统一成同一份对话记录。同步是可选的,靠 Loro CRDT 文档经由 Cloudflare Durable Objects 传递,让终端、文件树、diff、预览和一个 iOS 应用在每一台已登录设备上都够得着。
谁做的仓库最大的两个贡献者账号挂在同一个作者名下:wing-anara 提交了 727 次,wingleeio 提交了 342 次,合计 1,690 次里的 1,069 次。José Gurruchaga 用 jsgrrchg 又提交了 402 次。一共 31 个账号贡献过代码,1,690 次提交里有 1,670 次关联到了 GitHub 账号。
它是怎么搭起来的
组成 · 6单一个 Rust 二进制,既可以是窗口也可以是守护进程,里面裹着一个掌管全部设备侧事务的引擎。引擎负责跑 agent、持有鉴权、终端、仓库与 worktree、托管 CRDT 文档,并回答一套有类型的 RPC——对独立进程走 WebSocket,界面与它同进程时走内存双工通道,并且刻意不做任何序列化上的捷径,好让这条边界保持诚实。两个后果塑造了代码。界面只是它并不拥有的状态的视口,所以侧边栏列表、transcript 和 diff 面板都是对文档更新的订阅,而不是应用自身的状态。存储边界则在引擎启动时一次性确定为一个 workspace scope——本地、同步或开发——之后鉴权的任何变化都动不了它,于是一次 token 刷新永远不会在某个正在运行的会话底下悄悄换掉数据库。
- crates/
- 十六个 crate 目录,是架构文档点名的八个的两倍:
proto放线缆类型,doc放 schema 与镜像层,sync放 CRDT 房间客户端与它的 SQLite 快照存储,harness放 agent 适配器,engine放会话、仓库、终端、账号与 diff 同步,接着是rpc、theme与ui,另有client、mobile、markdown、mcp、preview、syntax、text和update。 - crates/ui
- 界面本体:635 个文件、10.7 MB,被少数几个巨型文件主导——701 KB 的 shell、595 KB 的 transcript、590 KB 的 composer、327 KB 的 picker、213 KB 的状态存储和 197 KB 的历史视图。全部界面都在这里:markdown 与链接处理、终端、diff 面板、文件树与预览、主题编译器、设置,旁边还有一张 65 KB 的文件图标表。
- crates/engine 与 crates/harness
- 干实事的核心:会话 144 KB、RPC 表面 184 KB、文档宿主 289 KB、工作区文件 116 KB、diff 同步 76 KB;其上是 115 个 harness 文件,每个 agent 一个适配器,其中有 253 KB 的 ACP 模块、170 KB 的 OpenCode 适配器、88 KB 的 Codex 适配器,探测程序与 28 个测试夹具也在这里。
- edge/
- 跑在 Cloudflare 上的 TypeScript:一个 Worker,每种房间一个 Durable Object——聊天、注册表、设备,以及一个 65 KB 的旧会话房间,架构文档说已经没有客户端会连它——再加 R2 附件、推送通知、WorkOS 鉴权路由、一份安装脚本,以及十个对着线上 edge 跑的检查脚本。
- apps/
- iOS 客户端是一个 1,012 文件的 Swift 工程,光是生成的 core 绑定就有 412 KB;落地页是一张 81 KB 的单页,带一段 13 KB 的场动画、25 张社交帖子截图和赞助商标志。二进制 crate 本身只有五个文件:入口、守护进程命令、鉴权、更新与路径。
- docs/
- 顶层 33 个 markdown 文件,下面还有十一个子目录:22 份研究文档、十六份性能测量与回放、一次带日期的运行留下的十五份传输结果、115 个文件共 18.5 MB 的截图集、十二条音效试听、三份 2026-08-20 与 2026-08-22 的计划、两份架构决策记录、三篇回归记录,以及
docs/toolcraft/下唯一一份 agent 工作日志。
取舍,以及它替代了什么
edge 保持 TypeScript,设备侧全部用 Rust 替代 连 Durable Object 也一起用 Rust 写
架构文档点名了这个决定,并把
docs/research/durable-objects-language.md作为证据,所以这个选择是可查证的,而不是口味问题。gpui 锁定某一个 Zed 版本,但 markdown、组件与主题自己写 替代 直接复用 Zed 的 markdown、ui、theme 与 editor crate
这是一个被写成许可问题的取舍:gpui 相关 crate 锁死在一个版本上,而 Zed 那几个 GPL 的 crate 刻意不用,所以仓库里才有一套自己的 markdown 解析器、自己的组件集,以及一个把 VS Code 主题家族编译进来的编译器。
这次重写不做 token 用量显示 替代 那个覆盖了其它一切的「功能对齐」目标
排除项连原因一起写明——用户画像式的用量仪表不适合同步给 CRDT 文档——而 agent 账号上的速率限制仪表留着,因为它们是从 CLI 探测来的,从不同步。
远端工作区访问不做文件名黑名单 替代 当一台设备浏览另一台设备时拦掉已知的敏感文件名
这是一次连理由一起写下来的拒绝:忽略文件的可见性不是授权边界,只在界面里藏条目不算安全控制,而黑名单不可能完整,还会暗示一个项目给不出的保证。替代它的是由拥有该工作区的引擎在每一次远端请求上执行检查。
存储边界在引擎启动时一次性确定 替代 鉴权一变就重新解析已经打开的存储
鉴权状态与工作区范围被刻意做成两台分开的状态机,于是一次登录、token 刷新或吊销都无法悄悄换掉数据库,也无法给一个以本地模式启动的运行时挂上在线传输。代价没有藏起来,而是写进了 README:登录或登出前必须先停掉守护进程,变更在下一次启动时生效。
把「对齐」写成一份带具名缺口的文档 替代 宣布这次重写已经完成
里程碑表把两个阶段标成已交付但有缺口——composer 的附件界面与给 Rust 用的 Cursor harness 都在其中——并记下
dist/macos/下的 macOS 打包配置写了却没有执行,因为需要一台 Mac。
依据ARCHITECTURE.md(24,176 字符)、README.md(4,330 字符)、完整的 2,498 个文件树及其体积、按体积排序的目录摘要、release 与 tag 列表,以及三十条 issue 与 pull request 正文。
制作过程
6 个阶段- 01
七十二天、1,690 次提交,和一条发版流水线
仓库建于 2026-07-20,最早的提交日期是 2026-07-19,标题是
Foundation: architecture, research, Rust workspace scaffold, TS edge port;最新一条在 2026-09-30,是Bump version to v0.2.99。中间是:7 月剩下的十一天提交 151 次,8 月 894 次,9 月 645 次。报告里的 release 列表最多 20 条,从 2026-09-19 的v0.2.79一直到 2026-09-30 的v0.2.99——十二天发了二十个版本,差不多一天两个;v0.2.87有 tag,却没有对应的 release。项目有 2,506 个星、239 个 fork、2 个 watcher、191 个未关闭的 issue 与 pull request,2,498 个文件、117 MB 体积,MIT 协议。一共 31 个账号贡献过代码:最大的是 wing-anara(727 次提交)与 wingleeio(342 次),José Gurruchaga(jsgrrchg)另有 402 次。764 条共同作者尾注里,663 条署名某个 Claude 模型——517 条Claude Fable 5、64 条Claude Opus 5.5、34 条Claude Opus 5 (1M context);另有 8 条Cursor,10 条写 Devin 或 Devin AI。README 感谢一家公司赞助了这个项目,并给出 GitHub 赞助入口。 - 02
一次从头重写:留下 schema,删掉服务器
ARCHITECTURE.md开篇就说,这个项目是把更早那个 zeron——一个给 Claude Code 与 Codex 做的多设备控制器——用 Rust 加 gpui 从头重写了一遍,并且把前提写得很直白:Fresh app; no backwards compatibility required.。这次重写换来了什么、代价是什么,都被列成了清单。原样保留:会话文档的 schema 形状与常量、命令账本规则、Durable Object 的设计、render-parts 的隐私策略,以及全部动画时长。改变:Postgres 实体同步和一个旧的 Hono 服务被工作区注册表加一套 TypeScript edge 取代;Electron 与 React 换成 gpui,技法从两个被点名的项目移植过来;Node 的 harness SDK 换成子进程协议;上一代的移动端被明确划到范围之外。有一个被排除的功能连原因一起写着——token 用量显示,因为对 CRDT 来说不合适;而更小的速率限制仪表留着,因为它们是从 CLI 探测来的、并不同步。另有两个工程选择同样留下了证据文件:edge 保持 TypeScript;界面锁定 gpui 的某一个 Zed 版本,同时拒绝使用 Zed 那几个 GPL 的 crate——markdown、组件与主题因此都是自己写的。 - 03
八种封闭的 agent,用探测程序和假二进制拆开
crates/harness是别人家封闭 agent CLI 被拆解归档的地方。里面每个 agent 一个适配器——claude46 KB、codex88 KB、cursor41 KB 外加一个 30 KB 的shim.mjs、opencode170 KB、pi39 KB,还有一个 253 KB 的 ACP 模块扛着 Antigravity、Devin 与 Grok——旁边是一组留在仓库里当证据的探测程序:25 KB 的cursor_stability_probe.rs、一个 steering 探测、Devin 与 OpenCode 的模型探测、Grok 的子 agent 探测、Antigravity 的 ACP 探测。docs/research/下有三起事故各自拥有一个目录,里面是 README、results.json,其中一起还有一份 12 KB 的validation.log。测试自带 28 个夹具文件,包括fake-claude.sh、27 KB 的fake-codex.sh、fake-cursor-sdk.mjs、fake-pi-rpc.py、fake-devin-auth.sh和两份假的 Antigravity ACP 脚本。唯一被工作流盯着保持最新的第三方件是锁定的 Cursor SDK:scripts/update-cursor-sdk.py会开一个 pull request,检查 token 刷新、流式鉴权失效与会话恢复,并在正文里写明它从不自动合并。 - 04
评审队列:pull request 叠在 pull request 上
最近这三十个 issue 与 pull request 在 2026-09-29 与 2026-09-30 全都处于打开状态,编号从 653 到 682。其中 11 个来自同一位贡献者 katulevskiy——他自己只落地了 5 次提交——这些正文讲的是把工作停在大分支上、再切碎送审:一个功能「stacked on #609」,也就是那个 Android 应用,并让评审者把基线放到
upstream/zeron/android-app-implementation;一个设备间传文件的 PR 说它是从同一个 Android 分支里抽出来的,好让它能被单独评审,等它落地后再把那个 Android PR 重新叠在它上面;第三个说它依赖另一个 PR、已经包含对方的提交,请评审者只看最后一个提交,并承诺之后会 rebase。评审本身还是照常发生:在一个外观相关的 PR 下,维护者写道「any screenshots? curious what it actually looks like」,大约七十分钟后贡献者补上了一张截图。在一个「iPhone 上改模型不生效」的报告里,一位贡献者直接指出已经开着的修复,报告者回复「Oh, I see. You’re right. Thanks!」——距离提交只过了三个小时。好几份正文末尾都带着一个托管评审服务的生成式页脚,贡献者开的 PR 和 actions 机器人开的 PR 都一样。 - 05
这些 PR 正文承认了什么
这些正文对「验了什么、没验什么」写得异常具体。一个修复 iOS 已开会话里模型切换的 PR 记下
git show --check通过,然后直说:iOS 的 UI 测试没有跑,因为这个环境是 Linux,没有 Xcode。一个改 transcript 链接的 PR 报告zeron-ui里 1,315 个测试通过、markdown crate 48 个通过,而 harness crate 是303/304 unit tests passed。一个实时更新的 PR 放出一段动画,并标注它「Schematic (generated by docs/media/live-update/generate.py), not a screen recording」,随后补上第二段录制,那是scripts/live-update-demo.sh的真实输出:脚本真的起了一个 headless 引擎和一个停在提问上的脚本化 agent,再把引擎原地替换掉。别处的度量比论证活得更久:docs/performance/里有十六份 profile 与回放文件,其中一份 243 KB;docs/transport-results/2026-09-15/里是一次带日期的传输运行留下的十三个结果文件——追赶与三次流式是fixed-*与main-*成对出现,HTTP、一次中断、上传、重复上传和一条极慢的链路只有 fixed 一侧——旁边还有一份描述这次运行的元数据文件。 - 06
作者写下来的那些边界
架构文档的结尾是一张里程碑表,其中两个阶段被标成「已交付但带具名缺口」,而不是做完:终端、diff 面板、worktree 与设置都有了,而 composer 的附件界面、给 Rust 用的 Cursor harness 仍然列在缺失里;
dist/macos/下的 macOS 打包配置被记成没有执行,因为需要一台 Mac。四个开放问题被标为非阻塞地跟踪,其中包括 Rust 与 TypeScript 之间 CRDT 互通失败时的退路:一个约三百行手写的客户端。安全那一节是整份仓库里写得最锋利的文字。登录同一账号的设备是彼此信任的同伴,拥有完整的工作区访问权;打开忽略文件的可见性会把.env也暴露到远端;作者写明:忽略文件的可见性不是授权边界,只在界面里把条目藏起来不算安全控制,而且故意不做文件名黑名单,因为这种名单不可能完整,还会暗示一个项目其实给不出的保证。另有三项工作被明确写为刻意推迟,其中之一是任何被支持的自托管后端契约。
相关档案
全部档案 →第 077 号
Lody
一个让团队共用他们本来就在跑的编码 agent 的工作台:连上一台机器,把 Claude Code、Codex、Kimi 或任何其他说同一套协议的 agent 接进来,然后从桌面端、手机、网页或终端派活;会话之间可以互相派活,而代码始终留在机器主人自己连上来的那台机器上。
第 067 号
tty7
一个纯 Rust 写的终端:shell 属于后台的服务器而不是窗口,退出应用它们照跑;重启之后面板带着原有布局和最后留在屏幕上的内容回来,四条 CLI 命令能让一个编码 agent 驱动另一个,而远端工作区就是同一个服务器跑在另一台机器上。
第 061 号
Reticle
一个 MCP 服务器加一个只在开发期生效的 SDK:让编码 agent 从应用内部去读、去操作一个正在运行的 web 或桌面应用,然后给出判词和该改的文件与行号,而不是一张截图。