三个独立入口,下层不依赖上层——单任务用 inner、一组独立任务用 B、要拆+集成的大任务用 epic。本文每节:何时用 → 前置 → 步骤(quick-action + 等价命令行)→ 看什么 → 收尾。
环境搭建见
README.md「从零搭建环境」。工程上下文/约定/坑见CLAUDE.md。
- plan = 散文 + 一段
## 验收标准:每条AC-N是可观测断言,可选标签[test](机械门测它)/[judge](裁判读 diff 判它)。 - 两道闸:① 机械门 = 跑脚本看退出码(
gate.sh/top-gate.sh,0=过);② 裁判 = 另一个模型只读 diff 逐 AC 判 met/unmet(默认不信、查测试有没有被改弱)。 - 坑(最重要):运行期类断言(「测试全绿」「构建通过」)只能进机械门,别写进裁判 AC——裁判只读 diff、验不了运行期,会判 unmet 空转。裁判 AC 只描述 diff 里看得见的(某文件/函数存在 + 断言内容)。
- 退出码:
0=全满足 ·2=停滞/超时/到顶(交人)·3=撞配额(可 resume)。 - 无状态、可 resume:状态全在
.herdr-loop/文件里,中断后重跑同一条命令即续。
何时用:一个边界清楚的任务,要它在"写→验→改"里收敛到验收项全过。
前置:在该任务的 feature worktree 里跑(不是主 worktree,免得 loop 在 main 上改码)。没有就先建:prefix+↓「02 新建 worktree」(等价 herdr-new-worktree <repo> <branch>),它会自动铺 agent/nvim/lazygit/term 四 tab 布局并跳进去。
步骤
- 铺骨架 —
prefix+↓「05 初始化 loop」(等价herdr-loop --init .):生成- plan:
.herdr-loop/plans/<分支名>.md(分支里的/压成-) - 机械门:
.herdr-loop/gate.sh(仓库级一份;不需要就删掉它)
- plan:
- 填 plan + gate:plan 写散文 +
## 验收标准(AC-N可观测断言,标[test]/[judge]);gate.sh写这个仓的构建/测试命令(退出 0=过)。 - 跑 —
prefix+↓「06 跑内层 loop」选写手(Claude 写/Codex 判,或反之)。它经herdr-in-tab跑在**命名 tab「loop」**里(切走能从 tab 条找回)。等价命令行:herdr-loop --writer claude . # 在 feature worktree 内
- 看:每轮 = 写手改码 +
git commit→ 机械门 → 跨模型裁判逐 AC → 未满足集喂回下一轮。中断了重跑同一条命令 = resume。 - 收尾:
exit 0(全满足)后你审一眼 →prefix+↓「12 合并到 main」(本地合,保守:脏树/冲突即拒)或「13 完成并开 PR」。plan 随 merge 落进plans/规格库。
测试钩:HERDR_LOOP_DRY_RUN=1 herdr-loop .(走控制流、不调 agent,验环境)。
何时用:多个相互独立的小任务,想一次并发跑完、收一张总表。B = 给每个任务开一个 worktree 跑 inner,管并发/配额/收集。
前置:任务之间必须相互独立(各自的文件、不互相依赖)。有依赖的拆到不同批,别塞进同一队。
步骤
- 铺收件箱 —
prefix+↓「07 初始化 fleet」(等价herdr-fleet-init <repo>):建<repo>/.herdr-loop/fleet-plans/+ 一份子任务模板,并把.herdr-loop/加进.git/info/exclude(坑·B①:收件箱躺主树会让git status脏、挡后面的 merge)。 - 写任务:在
fleet-plans/下每个任务一个<name>.md(散文 +## 验收标准;文件名 = 分支名),可选同名<name>.gate.sh(该任务专属机械门)。 - 派发 —
prefix+↓「08 派发队列」选写手(alternate=跨任务交替 claude/codex 摊两个配额池,推荐;或全 claude / 全 codex)。经herdr-in-tab跑在**命名 tab「fleet」**里。等价命令行:herdr-loop-fleet --plans <repo>/.herdr-loop/fleet-plans --repo <repo> --cap 3 --writer alternate
- 看:每个任务一个
loop:<name>tab 流式可见;并发上限默认 3(--cap);撞配额 →exit 3暂停全队(可 resume)。收齐出results.json+ 汇总表(在~/.herdr/fleet/<run-id>/)。 - 收尾:收敛的分支你审一眼 →
herdr-worktree-merge合进 main(B 永不自动合);做完把该 plan 从fleet-plans/清掉(已合进的 plan 随 merge 落进plans/规格库)。
坑:① fleet-plans/ 要 gitignore(herdr-fleet-init 已办)② 别把「构建/测试通过」设成裁判 AC(那是机械门的活,见共通概念)。
测试钩:HERDR_FLEET_DRY_RUN=1(纯控制流)/ HERDR_FLEET_INNER_DRY=1(真走管道、内层 dry、省配额)。样例 plan 见 docs/example-fleet-plans/。
何时用:一个有集成性的大任务——要拆成几个子任务、再把它们接起来,直到顶层 AC 全满足。A = 在 inner/B 之上加一层「拆解 → 调 B → 整合进集成分支 E → 顶层验证 → 没过再转」。
步骤
- 铺起手件 —
prefix+↓「09 初始化 epic」(等价herdr-epic-init <repo>):铺<repo>/.herdr-loop/epic.md(散文 + 顶层 AC 骨架)+top-gate.sh(全仓集成测试,自动探构建工具填命令)+ gitignore.herdr-loop/(坑·A②)。 - 填 epic.md + top-gate.sh:epic.md 写散文 +
## 验收标准(顶层AC-N,可选[gate]/[judge])+ 顶部<!-- epic: 名 -->(决定集成分支epic/<名>);top-gate.sh 写全仓集成测试命令。坑·A:[gate]AC 别写运行期子句(「swift test全绿」之类)——交给 top-gate.sh,AC 只描述 diff 里看得见的。 - 跑 —
prefix+↓「10 跑 epic 循环」选写手。经herdr-epic-run在**命名 tab「epic」**里起循环 + 防重复(同 epic 已跑就拒)。等价命令行:herdr-loop-epic --epic <repo>/.herdr-loop/epic.md --repo <repo> --cap 2 --writer alternate
- 每轮:内联拆解座(默认)。A 跑到拆解座会就地:AI 起草本轮相互独立的子plan(
herdr-epic-draft读 epic +M0...Ediff + 上轮缺口)→${EDITOR:-nvim}打开让你审/改 →:qa退出即放行——全在「epic」这一个 tab 里。放行后主 worktree 切到集成分支 E,B 从 E 扇出子任务、各自收敛、自动合回 E。- 想手写而非 AI 起草:拆解座问
[Y/n]选 n,改它播的骨架,:qa。 - 非交互 / 想从别处填:在 shell 里跑
herdr-epic-seat,或直接touch round-<n>/plans/.go。
- 想手写而非 AI 起草:拆解座问
- 顶层验证 → 再转:A 跑顶层 gate(集成测试 on E)+ 顶层裁判(读
M0...E,跨模型);没过 → 把缺口喂回下一轮拆解座(再转:子任务各自过 ≠ 整体达成)。全满足 → 打印 E→main 人闸命令。 - 收尾(人闸,手动):A 不自动合 E→main。你审完手动:
git checkout main && git merge --no-ff epic/<名>
测试钩:HERDR_EPIC_DRY_RUN=1(纯外层控制流)/ HERDR_EPIC_INNER_DRY=1(真建 worktree/合 E、内层 dry、省配额)。完整样例(epic spec + top-gate + 两轮子plan)见 docs/example-epic/;设计见 docs/A-epic-loop-plan.md、docs/epic-draft-plan.md。
| 你的任务 | 用 | 入口 |
|---|---|---|
| 一个边界清楚的任务 | inner | 〔内层〕05 初始化 → 06 跑 |
| 一组相互独立的小任务 | B 队列 | 〔队列〕07 初始化 → 08 派发 |
| 一个要拆+集成的大任务 | epic | 〔epic〕09 初始化 → 10 跑 |
三种规模在菜单上都「初始化 → 跑」成对;收尾(合并/PR/清理)用 〔收尾〕11–16 共享。