博客 · 2026-09-19

Claude Code 无人值守跑起来之后,谁来按合并

让 Claude Code 自己跑不难,难的是它写完之后谁决定能不能进主干。这篇写我这一个月的做法:评审换一个会话、合并前重查三个条件、发版交给状态机,一个月 431 个 PR 我一行代码没读。

想让 Claude Code 无人值守,网上的做法大多停在同一步:接进 GitHub Actions,或者写个循环让它自己跑。这一步好办。麻烦的是跑完之后那个 PR,测试绿了,代码是它写的,评审也是它做的,谁来按合并。

我这边现在的答案是没有人按。一个月 431 个 PR 合进主干,416 张 Issue 走完全流程,发了 40 个版本。代码我基本不读。

听起来像在赌,其实中间有几样东西必须存在,下面一个个说。

模型不是瓶颈

大家担心的是模型写错。这确实会发生,测试能拦住大部分。真正贵的是另一种:判断「这东西可以合了」的,还是写它的那个会话;或者是一个三周前就不再认真看了的人。

所以第一条:评审的不能是写代码的那一个。同一个会话里换个 prompt 再跑一遍不算,得另起一个进程、全新上下文、等 PR 建好之后读冻结的 diff。它不知道实现时在想什么。我一开始觉得这是缺点,后来发现正好:一段代码要是非得知道作者当时怎么想才看得懂,那它还没写完。

评审发现问题可以自己改、推到同一个分支,然后对新的 head 重新出结论。带着问题结束的那一轮不叫合并,叫下一轮。轮次上限是五轮,用完还没过就停下来等人,不会含糊过去。

合并的瞬间重查三个条件

光有评审结论不够,因为评审和合并之间隔着时间。合并前对着远端重新查三件事:

落到命令上就是一行,关键在那个 pin:

gh pr merge "$PR" --squash --match-head-commit "$REVIEWED_HEAD"

评审之后远端的 head 要是动过,这条命令直接失败,而不是把没人看过的东西合进去。三条都过,才按评审过的那个 commit 合进去。任何一条不过,票要么等下一跳,要么停下来等人。没有一条路径是「看起来没问题」就合的。

这三条本身很普通,任何团队在代码评审时都会念叨。区别只在于它们是状态机里的三行代码,不是某个人脑子里的三个习惯,所以第九十个 PR 在凌晨三点也照样生效。

人还剩下什么活

我写票。这就是全部的活,而且比听起来费劲:一张票一个可观察的结果,验收条件要写到「做完了没有」能被一个不能反过来问我的东西判断。票写得含糊,交付出来的就是一个理直气壮的错东西,而且下游任何闸门都拦不住,因为闸门查的是代码有没有做到票上写的事。

我还写发版票:版本号和范围。发版本身是一个确定性的状态机,不是模型会话。它冻结 base、等 CI 绿、改版本号、打 tag、发布、关里程碑。任何一步不对就停下来等我。

这两张票之间我不介入。中途想看进度就去 Issue 里翻评论,那里有每一轮的记录。

想自己搭的话

不用换掉现在用的东西。Claude Code 是执行层,缺的是做决定那一层。按收益排,加三样:

  1. 评审换一个会话,读冻结的 diff,有权判交付失败。
  2. 合并前重查 CI、head、base,不信任十分钟前的结论。
  3. 发版走确定性流程,别让模型决定「应该可以发了吧」。

Orbi 就是我按这三条做的实现,fair-code,可以自己部署,而且它在自己身上跑:上面那 431 个 PR 全是公开的,每一轮评审结论也都在 Issue 的评论里,随便点开一张看。底下的引擎可以用 Claude Code、Codex 或者任何 OpenAI 兼容的模型,所以你现在的模型那一侧不用动。

或者干脆把这三个条件搬进你自己的流程里,用什么工具执行都行。