feat(workflow): enforce auditable agent rules

This commit is contained in:
csh
2026-08-12 12:40:31 +08:00
parent 1d9590f6a1
commit 91b6f8453e
7 changed files with 1273 additions and 318 deletions
+256 -134
View File
@@ -1,5 +1,7 @@
# AGENT_RULES
<!-- playbook:rules:start -->
目的:为本仓库提供稳定的 Matt Pocock 工程流程与 ticket 执行约束。
`.scratch/` 是 spec、ticket、feature 队列和执行状态的唯一事实源。
@@ -45,28 +47,75 @@
## 任务入口
### 可直接执行
四个入口按成本递增排列,**从上往下取第一个满足的**。每个入口都定义了强制升级条件;条件成立
时立即停止当前路径并转入指定入口,已产生的改动只作为事实输入,不视为已批准方案。
只读分析、定位、审查,以及不改变行为的局部机械修改可以直接执行,不生成
spec/tickets。仍须遵守项目规则、验证实际结果,并只处理本次相关改动。
### 入口 1:直接执行
### 新 feature 或设计变更
只读分析、定位、审查,以及不改变可观察行为的机械修改(重命名、格式化、注释、导入整理、纯
文档措辞)。不生成 spec/tickets,不建 branch。仍须遵守项目规则、验证实际结果,并只处理本次
相关改动。
需要需求澄清、设计取舍、跨 session 调度、并发执行、迁移或回滚时,进入完整工程
主链。边界不清时也走该入口;执行中才发现存在未确认设计时停止实现,已有改动只作为
事实输入,不视为已批准方案。
**升级条件**:出现任何可观察行为变化 → 入口 2。
### 已明确预期行为的 bug
### 入口 2:单切片改动
已知正确行为且可以建立失败反馈回路的 bug,使用 `diagnosing-bugs` 完整执行 Phase 1-6
由它负责反馈回路、回归测试、修复、验证和清理,不再进入 `implement` 或重复 `tdd`,也不为
已确定的需求重新 grilling。若诊断暴露新的产品取舍、架构方向或缺失测试 seam,停止修复并
转入 `grill-with-docs`。若 bug 来自已领取 ticketPhase 6 后直接继续本地 ticket 执行协议的
提交、review 和 finish 门禁。
会改变行为、不属于入口 3 的已知 bug,且同时满足以下**全部**条件的改动走这里,不入队、不建
ticket branch
- 只涉及一个模块,或只扩展一个已存在的公开接口
- 能在已存在的测试 seam 上验证,不需要新建 seam
- 不新增公开接口、配置项、数据格式或第三方依赖
- 不涉及数据迁移、回滚、兼容性窗口或并发协调
- 预计一个 session 内交付,不需要跨 session 调度
流程:在已存在 seam 上按 `tdd` 完成一个可观察行为切片 → 运行局部验证 → 提交 → 对
`HEAD` 运行 `code-review` 的 Standards 单轴 → 修完硬 finding 后重新提交和验证。证据
写入 commit message 和 session 收尾,不写 `.scratch/`
**升级条件**(任一成立即停止并转入口 4):需要新 seam、跨出上述任一条边界、或发现
未确认的设计取舍。
### 入口 3:已明确预期行为的 bug
正确行为已知的 bug 走这里,**无论当下能否建立失败反馈回路**——建立反馈回路是
`diagnosing-bugs` 的 Phase 1,不是进入它的前提。`diagnosing-bugs` 完整执行 Phase 1-6,负责反馈回路、
复现最小化、假设、回归测试、修复、验证和清理;不另起 `tdd` 会话(Phase 5 内部已是
test-first),也不为已确定的需求重新 grilling。
两种缺口按该 skill 自身的规定处理:Phase 1 建不出可失败的命令时停下来索取环境、artifact 或
许可,不要换入口绕过;不存在正确 seam 时把"缺失 seam"本身作为发现记录,不因此中断修复,
修复落地后再建议 `improve-codebase-architecture`。诊断暴露新的产品取舍或架构方向时,先完成
Phase 5-6 让缺陷不再复现,再把取舍带入入口 4,不要把未修完的缺陷留在原地等设计结论。
若 bug 来自已领取 ticketPhase 6 后直接继续本地 ticket 执行协议的提交、review 和 finish
门禁。
### 入口 4:新 feature 或设计变更
以下任一条成立时进入完整工程主链:
- 存在需要用户决策的产品取舍或架构方向
- 需要新的测试 seam,或新增公开接口、配置项、数据格式
- 跨两个以上模块边界
- 涉及数据迁移、回滚或兼容性窗口
- 需要跨 session 调度或多 session 并发
- 预计无法在一个 session 内交付
**边界不清时先按入口 2 起步**,触到入口 2 的任一升级条件时立即转入本入口。"不确定"的正确
处置是用最小路径试探到边界,不是预付最贵的流程。
### 非交互模式下的入口 4
主链的 grilling 收敛和 seam confirmation 需要用户在场。无人值守而判定为入口 4 时:已有已领取
ticket 就 `finish --result blocked --reason "<待确认的具体决策>"`;尚无 ticket 则不得代替用户
决策、也不得降级到入口 2 硬做。用 `to-questionnaire` 把待决问题写到项目根目录的
`.scratch/questions/<slug>.md`,记录阻塞阶段、已知上下文、待决问题和恢复入口;用户回答后从
`grill-with-docs` 恢复。不得把问题清单写入临时 worktree 或稳定知识文件。
## 正式工程主链
新 feature 或设计变更使用以下顺序:
入口 4 使用以下顺序:
```text
setup-matt-pocock-skills
@@ -80,15 +129,18 @@ setup-matt-pocock-skills
```
- 每个仓库首次使用时运行 `setup-matt-pocock-skills`,本地开发选择 local markdown tracker
- 正式仓库设计使用 `grill-with-docs`
- 进入 `grill-with-docs` 或本地 ticket 执行协议前,重新读取 `memory-bank/project-brief.md`
`memory-bank/tech-context.md``memory-bank/system-patterns.md`
- `grilling` 必须走完整 design treefrontier 清空并经用户确认后才进入 `to-spec`
- `to-spec` 不重新进行已经完成的需求采访;但必须按其原始流程确认测试 seam。若
grilling 尚未确认 seam,必须先向用户完成 seam confirmation
- `tdd` 不得在未经确认 seam 上开始
- `grilling` 必须走完整 design tree**design frontier**(尚未定下的决策集合)清空并经用户
确认后才进入 `to-spec`。该词与调度语义里的 ticket frontier 无关
- seam confirmation 的责任在 `to-spec``tdd`,不在 `grilling`——后者只收敛设计决策,不涉及
测试 seam。`to-spec` 必须按其原始流程与用户确认 seam 并写入 spec 的 Testing Decisions
`tdd` 不得在未经确认的 seam 上开始
- `to-spec` 不重新进行已经完成的需求采访
- `to-tickets` 产出可独立验证的 tracer-bullet tickets,并显式声明 `Blocked by`
- 一次可以先生成多个 feature 的 spec/tickets,再按期望顺序逐个 `enqueue`
- `codebase-design` 是 seam、deep module 与依赖分类的词汇来源,供 `to-spec``tdd` 查阅,
不作为独立会话运行
## On-ramps 与 detours
@@ -101,22 +153,24 @@ setup-matt-pocock-skills
## Phase boundaries
只在阶段边界按以下顺序判断,首个满足项生效
只在阶段边界判断去向,阶段中途不做这个决定。按以下顺序首个满足项:
1. 下一阶段需要当前 primary source smart zone 足够时,继续当前 session
1. 下一阶段需要当前 session 作为 primary source,或剩余 smart zone 仍够下一阶段
(约 150k tokens)时,继续当前 session
2. 当前上下文与下一阶段无关时,使用 `clear`
3. 仅在跨 harness、跨目录/仓库、交给同事或 mid-phase 分出旁支任务时使用 `handoff`
4. 任务可独立 AFK 完成时交给 subagent
5. 其余同 harness、同目录且仍需当前上下文的情况使用 `compact`
5. 其余同 harness、同目录且仍需当前上下文的情况使用 `compact`,并附上下一阶段要保留
什么的指令
上下文过长不等于必须 `handoff``handoff` 解决的是可移植性。`compact` 是决策树的默认
落点,但不是第一选择`CONTEXT.md` 和 memory-bank 都不能替代阶段上下文
上下文过长不等于必须 `handoff``handoff` 解决的是可移植性。`compact` 是决策树的默认落点,
但不是第一选择——除 continue 以外的每个选项都把 primary source 换成 secondary source
`CONTEXT.md` 和 memory-bank 都不能替代阶段上下文。
## 本地 Ticket 执行协议
这是 Playbook 对 Matt 工程 skills 的调度适配层。它复用 `tdd``code-review`
不直接调用上游 `implement`;后者`code-review -> commit` 尾部顺序无法生成主循环要求的
固定 commit 证据。
这是 Playbook 对 Matt 工程 skills 的调度适配层,只复用 `tdd``code-review`尾部顺序与
上游`code-review -> commit` 相反:主循环要求证据绑定到固定 commit,所以先提交再 review。
对每个 claim 严格按以下顺序执行:
@@ -139,12 +193,18 @@ setup-matt-pocock-skills
- `.scratch/queue.md`feature 开发与集成顺序
- `docs/agents/*.md`tracker、领域文档布局和 skill 配置
不得手工修改 ticket 的 `Status``main-loop:ticket-state` 区块;只通过主循环变更。
不得手工修改 ticket 的 `Status``main-loop:ticket-state` 区块;只通过主循环变更。主循环
没有对应命令的状态组合按"卡死与恢复"处理,仍然不手工改。
`.scratch/` 是否纳入版本控制由项目决定并写入 `AGENT_RULES.local.md`:纳入则 spec、ticket 和
证据进入历史,可审计、新 clone 能接手队列,代价是状态变更产生提交噪音;排除则历史干净,
代价是状态只存在于本机磁盘、集成后审计线索消失,并发只靠"共享同一文件系统"兜住。无论哪种
都不得把两份 `.scratch/` 当成同一队列。
## 稳定知识维护
只记录下一 session 仍需要的稳定知识;当前 feature、ticket、owner、heartbeat、验证和
集成状态只由 `.scratch/``main_loop.py` 维护。
只记录下一 session 仍需要的稳定知识;当前 feature、ticket、owner、heartbeat、验证和集成
状态只由 `.scratch/``main_loop.py` 维护。
- 项目定位、边界、目标或成功定义长期变化时,更新 `project-brief.md`
- 技术栈、工具链、环境差异或验证入口长期变化时,更新 `tech-context.md`;写入
@@ -153,14 +213,13 @@ setup-matt-pocock-skills
- `CONTEXT.md` 只记录稳定领域词汇和定义;不把聊天流水、未验证猜测或短期进度写入
`CONTEXT.md`
- 项目特有执行规则写入 `AGENT_RULES.local.md`
- 符合 phase-boundary 窄条件的可移植上下文由 `handoff` 写入 OS 临时目录,不写入稳定
知识文件;同 harness、同目录的续作优先按决策树选择 continue、clear 或 compact
- `handoff` 的产物写入 OS 临时目录,不写入稳定知识文件
- 不为普通实现选择创建 ADR;没有长期价值的信息时不更新这些文件
## 调度语义
- feature 按 `.scratch/queue.md` 顺序调度
- 同一 feature 中 blocker 全部满足的 tickets 构成 frontier,按稳定编号领取
- 同一 feature 中 blocker 全部满足的 tickets 构成 ticket frontier,按稳定编号领取
- 同一 feature 的多个 frontier tickets 可在 worktree 模式并发执行
- 当前 feature 的 frontier 全被领取时返回 `BUSY`,不向后续 feature 扩张
- 只有前序 feature 无 frontier、无活动 claim 且确实 blocked 时,才可开发后序 feature
@@ -171,27 +230,62 @@ setup-matt-pocock-skills
-`skipped` ticket 的 feature 标记为 partial,集成时必须显式授权
- stale 只由 heartbeat 时间派生,不自动转移 owner;只有 `reclaim` 可以接管
### 读取输出而不是只看返回码
`BUSY``NOOP: ...``RETRY: ...` 都写到 stdout 并且**返回码为 0**;只有真正的错误才是
`ERROR: <msg>` 到 stderr、返回码 2。调用方必须解析 stdout,不能用返回码判断是否拿到 ticket。
`status` 输出 `FEATURE=``STATE=``PARTIAL=``FRONTIER=``CLAIM=``OWNER=`
`HEARTBEAT=``STALE=``ISOLATION=``WORKSPACE=``TICKET_ERROR=``BLOCKED=`
`FEATURE_BLOCKED=``MAIN_INTEGRATION_COMMIT=`;队列为空时输出 `NO FEATURES`
`STATE=active` 不代表可推进:tickets 只剩 `resolved``blocked` 的 feature 同样报
`STATE=active FRONTIER=-`,此时 `claim` 返回 `NOOP`。判断是否卡住要同时看 `FRONTIER=-`
是否存在 `BLOCKED=` 行。
### 心跳的实际作用
heartbeat 没有强制力:过期 claim 仍保有全部权限,原 owner 可以继续 heartbeat、`finish`
resolve。stale 的唯一后果是**别人获得 `reclaim` 的资格**。所以"每 10 分钟一次"是为了让接管
判断准确,不是为了保住 claim。
### 卡死与恢复
- claim 的环境准备失败时,主循环把该 ticket 写成 `blocked`、记录原因、把 `claimed_by` 设为
本次 owner,并以返回码 2 退出。一次失败的 claim 会占住这张 ticket
- `finish --result released` 只允许原 `claimed_by` 解除 blocked;原 session 已丢失时用
`release-ticket`
- `reclaim` 只接管 `claimed` 状态的 stale claim,不能用于 `blocked` ticket
- resume 与 `reclaim` 返回的 `BASE` 是 claim 当时记录的值,**不会刷新**feature head 已推进
时直接拿它去 `finish` 会得到 `RETRY: feature advanced`,按重试流程取新的 `FEATURE_HEAD`
## 执行隔离
`claim --isolation` 支持
`claim --isolation``in-place` 串行执行不建额外 worktree`worktree` 每个 ticket 独立
branch/worktree,适用于多 session 并发;`auto` 无其他活动 claim 时用 in-place,否则用
worktree。计划并发时第一个 session 就必须指定 `worktree`
- `in-place`:串行执行,不创建额外 worktree;claim 生命周期内其他 owner 得到 `BUSY`
- `worktree`:每个 ticket 独立 branch/worktree,适用于多 session 并发
- `auto`:无其他活动 claim 时使用 in-place,否则使用 worktree
`BUSY` 的作用域是**整个队列,不限于同一 feature**,来源有三个:请求 `in-place` 而队列里存在
任何活动 claim;队列里存在任何 `in-place` 活动 claim(此时所有 isolation 的新 claim 都
BUSY);队首可调度 feature 的 frontier 已被领完。stale claim 也算活动 claim,必须显式
`reclaim``release-ticket` 才能腾出位置。同一 owner 恢复自己的 ticket 不受这些检查影响。
计划并发时,第一个 session 就必须指定 `worktree`。明确不并发时可使用
`in-place``auto`,不必创建 worktree。
in-place 要求 checkout 无非 `.scratch` 改动、HEAD 非 detached、目标 branch 未被其他 worktree
占用。主循环不得自动 stash、reset、覆盖或丢弃改动。唯一例外:重新 claim 自己此前以 in-place
释放的同一 ticket 且 workspace/branch 都匹配时,跳过 dirty 检查以保留未提交改动。
in-place 模式要求 checkout 无非 `.scratch` 改动、HEAD 非 detached,且目标 branch
未被其他 worktree 占用。主循环不得自动 stash、reset、覆盖或丢弃改动
worktree 模式下若 `feature/<slug>` 正被 control checkout 占用,主循环会先确认它干净、再把
control checkout 切到主干以释放该 branch
`main_loop.py` 只支持 local Markdown tracker要求所有 sessions 共享同一文件系统、
control checkout 和 Git common directory。远程 tracker 可以由 Matt skills 单独使用,
但本主循环没有远程 tracker adapter,不能接入远程 claim/finish 状态跨机器或独立
clone 的并发不受支持,不得把两份 `.scratch/` 当成同一队列。
`main_loop.py` 只支持 local Markdown tracker,要求所有 sessions 共享同一文件系统、control
checkout 和 Git common directory。远程 tracker 可以由 Matt skills 单独使用,但本主循环没有
远程 tracker adapter,不能接入远程 claim/finish 状态跨机器或独立 clone 的并发不受支持。
## 主循环命令
主干 branch 名不是 `main` 时,`claim``integrate` 必须显式传 `--main-branch <name>`;其余
子命令不接触主干,也不需要 `--repo-root`
### 入队和状态
```bash
@@ -202,41 +296,42 @@ python {{PLAYBOOK_SCRIPTS}}/main_loop.py status \
--state-root .scratch
```
`enqueue` 对已入队 feature 幂等,返回 `EXISTS=<slug>`
### 领取
`<owner>` 必须是当前 session 全局唯一且稳定的标识,例如
`<agent>-<UTC timestamp>-<random suffix>`不得在并行 session 间复用 `codex``claude`
等通用名称;同一 owner 的重复 claim 只用于原 session 恢复自己的 ticket。
`<owner>` 必须全局唯一且在本 session 内稳定,例如 `<agent>-<UTC timestamp>-<random>`
不得在并行 session 间复用 `codex``claude` 等通用名称;同一 owner 重复 claim 只用于原
session 恢复自己的 ticket,其他 owner 不得接管,失联时用显式 reclaim
```bash
python {{PLAYBOOK_SCRIPTS}}/main_loop.py claim \
--state-root .scratch --repo-root . \
--owner "<owner>" --isolation in-place|worktree|auto
--owner "<owner>" --isolation in-place|worktree|auto \
[--main-branch main]
```
stdout 返回 `FEATURE``TICKET``CONTROL_ROOT`、绝对 `STATE_ROOT``WORKSPACE`
`BRANCH``BASE``ISOLATION`
- `CONTROL_ROOT` 是共享 Git control checkout
- `STATE_ROOT` 是唯一状态目录;它不必位于 `WORKSPACE`
- `WORKSPACE` 是当前 ticket 的代码工作区
stdout 返回 8 个赋值行:`FEATURE``TICKET``CONTROL_ROOT` 是共享 Git control checkout
绝对 `STATE_ROOT` 是唯一状态目录,不必位于 `WORKSPACE` 内;`WORKSPACE` 是当前 ticket 的代码
工作区;其余为 `BRANCH``BASE``ISOLATION`。也可能返回 `NO FEATURES`
`NOOP: no claimable tickets``BUSY`,或 `INTEGRATION_REQUIRED=<slug>`(队首 feature 已
ready-to-integrate,必须先 `integrate`)。
领取成功后立即读取 `<STATE_ROOT>/<FEATURE>/spec.md`
`<STATE_ROOT>/<FEATURE>/issues/<TICKET>-*.md`;不得在 claim 前根据 frontier 猜测本 session
将领取哪个 ticket。后续 review 也必须使用这两个已领取上下文,而不是 worktree 内相对
`.scratch` 的偶然副本。
`<STATE_ROOT>/<FEATURE>/issues/<TICKET>-*.md`;不得在 claim 前根据 frontier 猜测将领取哪个
ticket。后续 review 也必须用这两个已领取上下文,而不是 worktree 内相对 `.scratch` 的偶然
副本。
实现、提交和 review 必须在返回的 `WORKSPACE`/`BRANCH` 中完成。heartbeat、reclaim、
finish、status、block/release-feature 和 integrate 必须使用
`--state-root "<STATE_ROOT>"`,不得在 ticket worktree 中使用相对 `.scratch`
同一 owner 重复 claim 恢复原 ticket。其他 owner 不得接管;失联时使用显式 reclaim。
实现、提交和 review 在返回的 `WORKSPACE`/`BRANCH` 中完成;其余子命令一律用
`--state-root "<STATE_ROOT>"`,不得在 ticket worktree 中使用相对 `.scratch`。feature 集成
workspace 的路径不在 claim 输出里,只写在 `<STATE_ROOT>/<FEATURE>/.main-loop.json`
`integration_workspace`;纯 in-place 流程不创建该文件,feature 级操作在 `CONTROL_ROOT` 上做。
### 心跳和接管
claim 的 stale 租约固定为 30 分钟,调用者不得缩短。claim 存续期间至少每 10 分钟发送一次
heartbeat,并在预计耗时较长的验证、构建或 review 前后各发送一次。无法继续维持 heartbeat
时,使用 `finish --result released|blocked` 明确交还或阻塞 ticket
heartbeat,并在耗时较长的验证、构建或 review 前后各发送一次。无法继续维持时,根据是否需要
保留阻塞原因分别执行下文完整的 `--result released``--result blocked --reason` 命令
```bash
python {{PLAYBOOK_SCRIPTS}}/main_loop.py heartbeat \
@@ -248,35 +343,36 @@ python {{PLAYBOOK_SCRIPTS}}/main_loop.py reclaim \
--feature <feature> --ticket <NN> --owner "<new-owner>"
```
reclaim 只允许接管 stale claim,并保留原 branch、worktree 和未提交改动。
reclaim 只接管 stale `claimed` ticket,要求新 owner 与原 owner 不同,保留原 branch、
worktree 和未提交改动。被接管后原 owner 的 heartbeat 与 finish 立即报
`owned by another session`
### Review 适配契约
调用 Matt `code-review` 时不得依赖其自动搜索或交互补问,必须显式提供:
`code-review` 只产出 Standards 与 Spec 两段 findings,不给 pass/fail 判定,也不合并或
重排 findings。下面的 `pass` 映射是 Playbook 加的一层,由调用方把 findings 归结为判定。
- fixed pointticket review 使用 claim 的 `BASE` 或重试返回的 `FEATURE_HEAD`feature review
使用最新 `main` HEAD
- ticket review 的 Spec sources:逻辑路径 `.scratch/<feature>/spec.md`
`.scratch/<feature>/issues/<ticket>-*.md`,实际从绝对 `STATE_ROOT` 解析
- feature review 的 Spec sources`.scratch/<feature>/spec.md` 和该 feature 的全部 ticket
acceptance criteria,实际从绝对 `STATE_ROOT` 解析
调用时不得依赖其自动搜索或交互补问,必须显式提供:
只有对应 axis 零个未解决的硬 finding 时才能记录 `pass`
- fixed pointticket review 用 claim 的 `BASE` 或重试返回的 `FEATURE_HEAD`feature
review 用最新 `main` HEAD
- Spec sourcesticket review 用 `.scratch/<feature>/spec.md`
`.scratch/<feature>/issues/<ticket>-*.md`feature review 用该 spec 加本 feature 全部
ticket 的 acceptance criteria。两者都从绝对 `STATE_ROOT` 解析
- `standards=pass`没有未解决的仓库标准违规;baseline smell 属 judgement call,必须逐项记录
已修复或带理由接受,但不会仅因被提出就自动失败
- `spec=pass`没有遗漏、部分实现、错误实现或未授权范围扩张
只有对应 axis 零个未解决的硬 finding 时才能记录 `pass``standards=pass`没有未解决的
仓库标准违规(baseline smell 属 judgement call,须逐项记录已修复或带理由接受,不因被提出
就自动失败);`spec=pass`没有遗漏、部分实现、错误实现或未授权范围扩张
任一来源缺失、Spec axis 被跳过、review 尚在询问输入,或仍有未解决的硬 finding 时,
不得据此填写 `standards=pass``spec=pass`。修复会改变 `HEAD`因此必须重新运行受影响
验证和完整双轴 review,不能沿用旧报告。
不得据此填写 `standards=pass``spec=pass`。修复会改变 `HEAD`,必须重跑受影响验证和完整双轴
review,不能沿用旧报告。
### Ticket 完成或状态转换
`resolved` 前必须先提交实现,再按 Review 适配契约对 `BASE...HEAD` 运行 Matt
`code-review` 的 Standards/Spec 双轴审查。
验证证据必须包含被验证 commit,review 证据必须包含被审查 commit 和固定 base;任意
非空文本或裸 `pass` 不能替代结构化证据。
`code-review` 的 Standards/Spec 双轴审查。验证证据必须包含被验证 commit,review 证据必须
包含被审查 commit 和固定 base;任意非空文本或裸 `pass` 不能替代结构化证据。
```bash
python {{PLAYBOOK_SCRIPTS}}/main_loop.py finish \
@@ -285,48 +381,44 @@ python {{PLAYBOOK_SCRIPTS}}/main_loop.py finish \
--result resolved \
--implementation-commit <HEAD> \
--feature-head <已验证feature HEAD> --review-base <同一feature HEAD> \
--verified "commit=<HEAD>; result=pass; <实际局部验证证据>" \
--reviewed "commit=<HEAD>; base=<review-base>; standards=pass; spec=pass"
--verified "<ticket-verification.json>" \
--reviewed "<ticket-review.json>"
```
验证和 review 参数必须是下文定义的 UTF-8 JSON artifact 路径,不接受内联 `pass` 文本。
首次 review base 是 claim 返回的 `BASE`。feature HEAD 已推进时返回
`RETRY: feature advanced` 和新的 `FEATURE_HEAD`;把该 `FEATURE_HEAD` 合入 ticket branch
重新运行受影响验证,并以它作为新的 review base 重跑双轴 review。重试时
`--feature-head``--review-base` 和 review evidence 的 `base` 必须都使用该新值,验证与
review evidence 的 `commit` 必须等于新的 ticket `HEAD`。只有成功集成到 feature branch
后 ticket 才变为 `resolved`
`--feature-head``--review-base` 和 review evidence 的 `base` 用该新值,验证与 review
evidence 的 `commit` 必须等于新的 ticket `HEAD`。只有成功集成到 feature branch 后 ticket
才变为 `resolved`
其他转换:
`finish` 不检查验收勾选框;验收由 `code-review` 的 Spec axis 负责,勾选框在 resolve 前
自行更新。
其他 `finish` 转换共用上面的 `--state-root``--repo-root``--feature``--ticket``--owner`
```bash
python {{PLAYBOOK_SCRIPTS}}/main_loop.py finish \
--state-root "<STATE_ROOT>" --repo-root "<CONTROL_ROOT>" \
--feature <feature> --ticket <NN> --owner "<owner>" \
--result blocked|skipped --reason "<明确原因>"
--result blocked --reason "<明确原因>"
python {{PLAYBOOK_SCRIPTS}}/main_loop.py finish \
--state-root "<STATE_ROOT>" --repo-root "<CONTROL_ROOT>" \
--feature <feature> --ticket <NN> --owner "<owner>" \
--result released
python {{PLAYBOOK_SCRIPTS}}/main_loop.py release-ticket \
--state-root "<STATE_ROOT>" --feature <feature> --ticket <NN> \
--reason "<原 session 无法恢复的原因>"
```
release 返回 `ready-for-agent` 并保留 workspaceblocked ticket 可由原 owner release 后恢复。
### Feature 集成阻塞
ready-to-integrate feature 若因 main 同步冲突或人工决策暂时不能集成,必须显式记录;
这样主循环才会继续为后序 feature 分配开发工作:
```bash
python {{PLAYBOOK_SCRIPTS}}/main_loop.py block-feature \
--state-root "<STATE_ROOT>" --feature <feature> --reason "<明确原因>"
python {{PLAYBOOK_SCRIPTS}}/main_loop.py release-feature \
--state-root "<STATE_ROOT>" --feature <feature>
```
release 后该 feature 重新成为队首 `INTEGRATION_REQUIRED`。后序 feature 即使已开发完成,
仍不得越过它集成到 main。
`blocked``skipped` 都必须提供 `--reason``released` 回到 `ready-for-agent` 并保留 workspace
只能由原 `claimed_by` 调用。`release-ticket` 用于原 session 已丢失、无人能 release 的 blocked
ticket;它不校验 owner,保留 branch、worktree 和未提交改动,返回
`TICKET_RELEASED=<feature>/<NN>`
### Feature 顺序集成
@@ -336,40 +428,71 @@ feature 必须吸收最新 `main`,完成 feature 验证、main 候选验证和
python {{PLAYBOOK_SCRIPTS}}/main_loop.py integrate \
--state-root "<STATE_ROOT>" --repo-root "<CONTROL_ROOT>" \
--feature <feature> --feature-head <已验证feature HEAD> \
--verified "commit=<feature HEAD>; result=pass; <feature级验证证据>" \
--main-verified "commit=<feature HEAD>; result=pass; <main候选验证证据>" \
--reviewed "commit=<feature HEAD>; base=<最新main HEAD>; standards=pass; spec=pass"
--verified "<feature-verification.json>" \
--main-verified "<main-candidate-verification.json>" \
--reviewed "<feature-review.json>"
```
partial feature 还需 `--allow-partial`。返回 `RETRY: feature needs main sync` 时,
先在 feature integration workspace 合并最新 main;若发生冲突,先 `block-feature`,解决后
`release-feature`,重新验证和 review 后再调用。
partial feature 还需 `--allow-partial`;未显式授权时报错而不是静默集成。
`RETRY: feature needs main sync` 表示 `main` 不是 feature head 的祖先。此时在 feature
integration workspace(纯 in-place 流程下是 `CONTROL_ROOT`)合并最新 main,重新验证和
review 后再调用。main 合并冲突时主循环会**自动**把 feature 标记为 blocked,不需要手工
`block-feature`;解决冲突后 `release-feature` 再重试。
成功后主循环会把 control checkout 切到主干,并移除干净的 ticket worktree 与
`_integration` worktree;不干净或路径异常的保留并以 `WARNING=` 行报告。已集成的 feature
再次调用时幂等返回 `INTEGRATED=`
ready-to-integrate feature 因人工决策暂时不能集成时必须显式记录,否则主循环不会为后序
feature 继续分配开发工作:
```bash
python {{PLAYBOOK_SCRIPTS}}/main_loop.py block-feature \
--state-root "<STATE_ROOT>" --feature <feature> --reason "<明确原因>"
python {{PLAYBOOK_SCRIPTS}}/main_loop.py release-feature \
--state-root "<STATE_ROOT>" --feature <feature>
```
release 后该 feature 重新成为队首 `INTEGRATION_REQUIRED`;后序 feature 即使已开发完成,
仍不得越过它集成到 main。
## Git 与证据门禁
1. 每个 ticket 使`ticket/<feature>/<NN>-<slug>` branch
2. 每个 feature 使用 `feature/<feature>` branch
3. 按 TDD 完成一个可观察行为切片并运行局部验证
4. 提交全部实现,使 `HEAD` 成为可审查固定点
5. 首次以 claim 的 `BASE` 运行 `code-review`;同步推进后的 feature 时改用新的
`FEATURE_HEAD`
6. 修复 finding 后重新提交、验证和 review
7. `finish` 校验验证/review commit、review base 和 feature HEAD,再集成 ticket
8. `integrate` 把两级验证和最终 review 绑定到 feature HEAD,并把 review base 绑定到
最新 main HEAD
branch 命名:ticket 用 `ticket/<feature>/<NN>-<slug>`feature 用 `feature/<feature>`
执行顺序见"本地 Ticket 执行协议",证据参数见"主循环命令"。
局部 ticket 验证、feature 验证和 main 候选验证是三个独立门禁,不能互相替代。
证据必须来自实际 fresh run;无法运行时不得伪造 `pass`
`--verified``--main-verified``--reviewed` 必须指向 UTF-8 JSON artifact。验证 artifact
包含 `version=1``kind=verification``commit``result=pass``command``exit_code=0`
`output``output_sha256`review artifact 包含 `version=1``kind=review``commit``base`
`standards=pass``spec=pass``report``report_sha256`。输出和报告必须先移除 secret;摘要是
对应 UTF-8 文本的 SHA-256。
门禁校验每个 commit 真实存在、artifact schema 与摘要、implementation/verification/review
commit 与目标 branch tip 一致、review base 正确、workspace 干净且在自己的 branch 上。成功后
把规范化 artifact 快照到 `.scratch/<feature>/evidence/`,并在 ticket 或 feature 状态中记录快照
路径和 SHA-256;原始 artifact 删除后仍可审计。
artifact 能阻止空文本、字段缺失、摘要篡改和 Git 上下文错配,但无法证明命令真的执行过,也
无法证明 report 来自真实 review。证据必须来自实际 fresh run,无法运行时不得伪造 `pass`
需要机器强制时由 CI 或 pre-commit hook 生成 artifact。
## 辅助能力
以下能力在对应阶段内按需使用,不替代上面的入口路由和证据门禁:
| Skill | 触发条件 |
| ---------------- | ----------------------------------- |
| `codebase-recon` | 架构、跨模块、重构、迁移或风险不明 |
| `brooks-audit` | 架构边界和长期维护性审查 |
| `commit-message` | 需要检查 staged diff 或生成提交信息 |
| Skill | 触发条件 |
| ------------------------------- | -------------------------------------------- |
| `codebase-recon` | 架构、跨模块、重构、迁移或风险不明 |
| `brooks-audit` | 架构边界和长期维护性审查 |
| `codebase-design` | 需要 seam、deep module、依赖分类的词汇与判据 |
| `improve-codebase-architecture` | 修复落地后暴露出的结构问题 |
| `resolving-merge-conflicts` | feature 吸收 main 或集成时出现冲突 |
| `to-questionnaire` | 需要把待决问题整理成清单交回用户 |
| `commit-message` | 需要检查 staged diff 或生成提交信息 |
## 需要确认的场景
@@ -379,19 +502,18 @@ partial feature 还需 `--allow-partial`。返回 `RETRY: feature needs main syn
- 需要 spec 未授权的行为、兼容性或架构取舍
- 需要破坏性操作、覆盖他人改动或扩大任务范围
已明确预期行为的 bug 按 `diagnosing-bugs` 路由推进;符合既有模式的小改动、测试补齐和
已批准 ticket 范围内的实现不重复需求采访
无交互模式下不得替用户作设计决策;将 ticket 标记 blocked 并记录原因。
入口 1、入口 2 范围内的改动和已批准 ticket 范围内的实现不重复需求采访。无交互模式按
"非交互模式下的入口 4"处理,不得替用户作设计决策
## Session 收尾
- 运行与声明相匹配的 fresh verification
- ticket 执行必须通过 `finish` 写回;不得手工改状态
- 列出已完成、未完成、验证证据、风险和下一步
- 只提交当前 ticket/feature 相关改动,不混入其他 session 差异
- 工作未结束时在阶段边界按 Continue -> clear -> handoff -> subagent -> compact 的顺序选择
去向;不要仅因上下文过长就创建 handoff
- 工作未结束时按 Phase boundaries 决策树选择去向
---
**最后更新**{{DATE}}
<!-- playbook:rules:end -->
+17 -5
View File
@@ -42,13 +42,15 @@ templates/
- 更新标记区块时保留区块外的项目内容
- 已有的人工入口和项目补充说明继续由项目维护
### 2. 初始化后由项目维护
### 2. 流程由 Playbook 维护,补充由项目维护
- `AGENT_RULES.md`项目采用的完整工程流程与执行规则
- `AGENT_RULES.md``<!-- playbook:rules:start/end -->` 区块内的工程流程由 Playbook
维护,重新同步时刷新;项目自己的补充写在区块外,同步不会动它
- `AGENT_RULES.local.md`:项目私有规则,Playbook 不覆盖
- `memory-bank/`:稳定项目定位、技术上下文和当前系统模式,不承载机器状态
Playbook 只处理框架提供的同名文件。项目新增的 `memory-bank/*` 不会被删除。
没有标记区块的旧 `AGENT_RULES.md` 保持原样,不会被静默改写。
### 3. 参考模板
@@ -72,15 +74,23 @@ heartbeat、ticket 或集成状态;机器状态只以 `.scratch/` 和 `main_lo
### AGENT_RULES.template.md
部署为项目的 `AGENT_RULES.md`,是 Matt Pocock 工程主链、ticket 调度、worktree、
验证和集成协议的唯一流程权威。项目私有规则写入 `AGENT_RULES.local.md`;该文件由
项目维护,Playbook 不覆盖。
部署为项目的 `AGENT_RULES.md`,是任务入口路由、Matt Pocock 工程主链、ticket 调度、
worktree、验证和集成协议的唯一流程权威。`<!-- playbook:rules:start/end -->` 区块内的
内容由 Playbook 维护并在重新同步时刷新,项目补充写在区块外。项目私有规则写入
`AGENT_RULES.local.md`;该文件由项目维护,Playbook 不覆盖。
### AGENTS.template.md
部署为项目的 `AGENTS.md`,只提供语言规则、核心规则和工程上下文导航。
标记区块的更新约束见下文“AGENTS 模板标记”。
## 任务入口
四个入口按成本递增,取第一个满足的:直接执行(零行为变更)、单切片改动(单模块、
已有 seam、一个 session 内)、已明确预期行为的 bug(`diagnosing-bugs` Phase 1-6)、
新 feature 或设计变更(完整主链)。边界不清时从单切片改动起步,触到升级条件再转入
完整主链,不要预付最重的流程。判据与升级条件见 `AGENT_RULES.template.md`
## 部署
```toml
@@ -101,6 +111,8 @@ local markdown tracker。
## 正式开发流程
只有第四个入口(新 feature 或设计变更)走这条链;前三个入口不入队、不建 ticket branch。
```text
setup-matt-pocock-skills
-> grill-with-docs