BoHuYeShan

Back

〇、一个账号,两千九百五十一个 PR#

roboomp。GitHub 头像是个机器人,签名写着「Hi, I’m roboomp, your friendly assistant for the oh-my-pi project!」,账号建于 2026-05-14。

到写这篇的 11 月 3 日,它在这个仓库开了 2951 个 PR。算一下:173 天,平均每天 17 个。你睡觉的时候它在开 PR,你上班的时候它在回评论,你周末的时候它在修 release CI。

最离谱的是 PR 正文,随手点开一个(#17951,修 jq 超时后线程还在吃内存):

Repro#

在 Linux 上 Shell.run({ command: "jq -n '[range(0; 1000000000)] | length'", timeoutMs: 200 }) 报超时,但进程内 jaq 求值仍在分配内存……

Cause#

crates/pi-builtins/src/jq.rs 只在 filter.id.run() 产出之后检查取消标志。jaq 的 Id::run 用嵌套迭代器构建数组,一个直到完成才输出结果的过滤器永远走不到外层检查。

Fix#

给工作区内的 jaq-core 解释器加宿主取消钩子,在 run/update/path 求值期间轮询嵌套迭代器……

Verification#

bun check 通过。bun run test:rs 通过 pi-builtins,但两个无关的 pi-vcs 测试失败……递归 40 菱形过滤器在超时后 715ms、83MB RSS 返回。

这不是「AI 帮我写了段代码」。这是一份能直接合并的工程报告:复现、根因、改法、验证,连「哪些测试没过、为什么没过」都写清楚——它最后还补了一句,因为环境不允许在 /srv/agent-home 建目录,某些套件报 EACCES。

一、它不是「AI 写代码」,是「带信用的流水线」#

最反直觉的地方:这个机器人不是一个大模型在裸奔。它是一套带信任边界的服务,源码就在 python/robomp/ 里。

架构只有两个容器,中间隔着一道墙:

  • robomp 容器:FastAPI + sqlite 事件队列 + WorkerPool。它在每个 issue 的独立 git worktree 里拉起 omp --mode rpc,让 agent 读代码、改代码、跑测试。它持有 HMAC 密钥,不持有 GitHub token。
  • gh-proxy 容器:和 robomp 挂在同一个 internal: true 网络里,持有 GITHUB_TOKEN,只做两件事——校验前者的签名请求,执行 REST 和 git push。它唯一的出网方向是 api.github.com。

于是 agent 的写权限被压缩到一条窄缝:它只能通过 host tools 请求写操作,而这些调用全部记进 tool_calls 表,参数与结果里的凭据会被打码。就算某天有人在 issue 里塞了提示词注入,让 agent 去删仓库,它手里的工具也没有那个能力——token 根本不在它那台机器上。

事件流是标准的幂等流水线:webhook → HMAC 校验 → 按 X-GitHub-Delivery 去重 → 落 sqlite → WorkerPool 用 BEGIN IMMEDIATE 领取 → 建 worktree → 起 agent。重启后未完成的事件重新入队;后续的 issue 评论、PR review 评论,用 --continue 接同一份 JSONL 会话继续聊。

roboomp:一个带信用的机器人流水线

agent 在左边改代码,写权限在右边,中间只过签名请求。

二、分流:不是所有 issue 都值得修#

它先分类,再决定动不动手:

标签动作
bug / documentation复现、在新分支上修、开 PR
question只回一条评论,末尾附一句「点 👎 保活」;作者 4 小时内没点,自动按 completed 关闭
enhancement / proposal一条评论,不开 PR
invalid / duplicate一句简短说明

那个 👎 的设计很懂人性:自动关闭最容易招骂,它给了一个「我还在」的按钮,而且任何后续评论或外部关闭都会同步取消定时任务。机器礼貌,是因为规则里写了礼貌。

它还有一条默认关闭的「release 哨兵」:监听 workflow_run 完成事件,发现发布 CI 红了,就在一份可复用的 main worktree 里诊断、原子地推修复提交、重新打 tag,然后继续等下一个结果,直到整条流水线和 GitHub Release 全绿。

三、为什么敢让它改:仓库本身就是规格书#

一个 agent 敢在陌生仓库里动刀,前提是它能判断「什么是对的」。这个前提不是模型能力,是仓库的规格密度。

我把 OMP 的主干树拉下来数了一遍:9613 个文件,6580 个 TypeScript 文件,其中 3343 个是测试文件——占一半还多(50.8%),另有 870 个 Rust 文件、133 篇 docs/ 下的设计文档。CI 里没有覆盖率阈值(我翻了 ci.yml、bunfig.toml、package.json,没找到 coverage gate),但测试件的密度比任何阈值都狠:改一个模块,跑起来就是一片红。

这就解释了它为什么不胡改。docs/ 里每篇文档都是一个功能的规格说明,AGENTS.md 写明代码风格与边界,测试文件是行为的可执行规格。agent 拿到 issue 之后的工作不是「设计一个新东西」,而是「在已有的规格里找不一致的地方,然后对齐」——修 bug 本质上是收敛,不是创造。规格越完整,收敛越安全。

反过来看,很多仓库的 AI 修 bug 修出灾难,不是因为模型笨,是因为仓库里没有「标准答案」:同一个概念三处实现,命名四套,测试只覆盖正常路径。agent 只能靠猜,猜错就是重构事故。

四、我们为什么分叉,又为什么自己养一台机器#

说点自己的账。Zeta 是 OMP 的 fork,到今天领先上游 2242 个提交(2026-11-03,本地 git rev-list --count omp-upstream/main..main 实测)。

这个数字不好看,因为分叉的成本是复利的:上游每合并一次重构,我们就要解一次冲突;而上游的节奏是每天几十个提交。

分叉的起点很朴素:vibe coding 的产物经常把 CI 跑红,而红在主干上就不能发布。所以我们单独拉了一条本地流水线——.gitea/workflows/local-ci.yml,runs-on: self-hosted,跑在自己的机器上。那台机器的主要用途不是”发布闸门”,是验证新功能:想加的东西先在自己机器上跑通,再谈往上游同步。GitHub 那边的 .github/workflows/ci.yml 仍然是 ubuntu-22.04 托管机,两条流水线的职责是分开的。

上游其实也一样。OMP 的 bun-cache-warm.yml 注释写得很直白:PR 任务只恢复缓存、从不保存(因为每个 PR 存一份约 500MB 的 store,曾经吃掉 10GB 配额里的 9.4GB),而 main 的 CI 跑在自托管机器 vmon 上,用的是模板 store,根本不走 GitHub 缓存。连上游都不指望 GitHub 的冷启动——所谓”持久热缓存、随时待命”的构建机,是自己养的。

所以两边的分工长得差不多:基础门禁在自家机器上跑,AI 顺手修完也在那跑。差别在流水线内容——我们的 workflow 和上游不是同一套,但测试的复杂度是同一个量级:改哪儿都容易红。

这事有数据。Linxira-OS/linxira-zeta 的 Actions 一共跑了 2620 次;最近 500 次里,289 次成功、154 次失败、56 次被取消——成功率 57.8%,失败率三成。所谓”一片红”不是修辞,是日常。这也是为什么自建 runner 不是洁癖:在托管机上跑这种密度,排队和重建的时间比修 bug 还长。

五、自己搭一个,要跨过哪些坑#

看完源码,这套东西的门槛不在模型,在工程。真要复刻,清单大概是这样:

  1. 一个专用账号 + 细粒度 PAT:Contents / Issues / Pull requests 读写 + Metadata 只读;release 哨兵再加 Actions 只读。别用个人 token,别给 admin。
  2. 两个容器,一条信任边界:agent 容器拿不到 token;写操作走旁路,旁路只放行 api.github.com。这是整套设计里唯一不能省的一步。
  3. 幂等事件队列:按 delivery id 去重,用数据库事务领取任务,重启后重新入队。没有这一步,一次重投就是两个 PR。
  4. 每个 issue 一个 worktree:分支名带哈希,互不干扰;会话用 JSONL 持久化,评论来了接着聊。
  5. 四段式正文模板:Repro / Cause / Fix / Verification。强制它写「验证」,它就会真的跑测试;强制它写「哪些没过」,它就没法假装全绿。
  6. 标签分流 + 礼貌的自动关闭:question 类不要开 PR,给一个保活按钮,别让机器人替人做决定。
  7. 审计表:host tool 每次调用都落库,参数脱敏。出事时你至少查得到「它当时干了什么」。
  8. 失败可续:release 哨兵、CI 修复都要能「等下一个结果再继续」,而不是一把梭。

坑也明摆着:token 权限一大就前功尽弃;worktree 不清会吃满磁盘;模型随机选(源码里 ROBOMP_MODEL 是 CSV,随机抽一个)意味着质量波动;最要命的是误判优先于误改——它把一个 enhancement 当 bug 修了,你得到的不是补丁,是一场 review 灾难。

六、结论:机器人的水平,取决于仓库的规格密度#

roboomp 让人羡慕的不是「AI 会写代码」,是它背后那个仓库:133 篇设计文档、3343 个测试文件、一条不允许随便改的主干。机器人只是把这份秩序的执行成本降到了零。

所以想在自家仓库里复制这套东西,第一件事不是找模型、不是搭容器,而是问一句:我这个仓库,有没有一份能让 AI 照着做对的规格?

有,机器人就是同事;没有,机器人就是那个每周给你提三个重构 PR、你还得逐个解释为什么不能这么改的实习生。

三千个 PR 的机器人:少爷怎么让 AI 自己上班
https://bohuyeshan.top/2026/11/03/2026-11-03-03-roboomp-bot/
作者 BoHuYeShan
发布于 2026年11月3日