NEE's Blog

bmad-build-auto 深潜:BMAD 的无人值守工人是状态机,不是循环

October 11, 2026

BMAD 又双叒重构了——旧的 src/bmm-skills 布局没了,换成根目录下扁平的 skills/ 树,30 多个技能包。里面我还没写过的最有意思的一个:skills/bmad-build-auto,配套文档在 docs/build/autonomous-development-loops.md。两个都读了,核心设计动作是一个倒置:build-auto 是工人,不是循环。

一次调用 = 一张票:澄清意图 → 创建或恢复计划 → 实现 → 审查 → 终态。它从不自己挑下一张票,从不推进 backlog,从不协调 epic。backlog 策略属于编排者(人、一个 AI 编码会话、或外部的 bmad-loop 项目)。无人值守的工人在结构上就无法自我扩大范围。

工人与编排者之间的接口是一个文件,不是聊天窗口:

1. 计划的 frontmatter 状态就是状态机

draft → ready-for-dev → in-progress → in-review → built → done(外加 blocked、dropped)。恢复路由直接读它:draft 重入规划,in-progress 重入实现,built/done 跑一轮全新的跟进审查,blocked 立即停机。状态活在工件里,所以会话崩了什么都不丢。

2. blocked 是路由信号,不是失败

十种枚举的阻塞条件,包括 review repair loop exceeded 5 iterations (non-convergence)——循环护栏是一个有名字的停机。重试 = 修好根因,然后 tickets.py mark <ref> <status> 清掉 blocked_reason。重新派发一个 blocked 的计划会以 blocked plan supplied 再次停机。

3. intent-gap 补丁是全场最佳

当审查因为捕获的意图回答不了某个问题而无法继续时,运行会还原工作树——但会先把尝试过的变更存成计划旁边的一个补丁,从分诊日志引用。这个补丁记录了运行到底实现了意图的哪一种读法。如果那套读法后来被证明是对的:git apply,把状态设成 in-review,接着审查——不用重跑。带检查点副作用的投机执行。

4. 边界纪律

工人提交但从不 push,退出时工作树干净,而且从不把票标成 done——tickets.py mark <ref> done 是编排者专属操作。人工检查点(plan_checkpoint/done_checkpoint)靠派发协议执行(「Halt after planning.」然后重新派发),因为工人根本不读这些字段。

5. 提交账目可组合

每份计划记录 baseline_revision——实现之前的完整规范版本号——于是一张票的提交区间就是 baseline_revision..<下一张票的 baseline_revision>,退出时用 ..HEAD。风险在规划期打分,永远不低于票自带的风险,CI 可以读它来决定审查深度。

还有一个值得注意的:SKILL.md 现在是个薄启动器——它跑 _bmad/scripts/render_skill.py,然后照着打印出来的 workflow.md 路径走,配置通过 --set workflow.route=oneshot|full 和 workflow.review=none|quick|thorough 注入。「Do not run any workflow source directly.」被执行的技能是一个按项目渲染出来的工件。

如果你在搭任何无人值守的 agent 循环,偷走这两条不变量:终态属于一个耐久工件(永远别从聊天输出推断成功);修复循环必须有界,停机时带一个有名字的条件,而不是无声地收敛。

comments powered by Disqus