update backend
This commit is contained in:
355
.codebuddy/skills/subagent-driven-development/SKILL.md
Normal file
355
.codebuddy/skills/subagent-driven-development/SKILL.md
Normal file
@ -0,0 +1,355 @@
|
||||
---
|
||||
name: subagent-driven-development
|
||||
description: 当在当前会话中执行包含独立任务的实现计划时使用
|
||||
version: "1.0.0"
|
||||
license: MIT
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [agents, development]
|
||||
---
|
||||
|
||||
# 子智能体驱动开发
|
||||
|
||||
通过为每个任务分派一个全新的实现子智能体来执行计划:每个任务完成后做一次任务审查(规格合规性 + 代码质量),全部任务结束后再做一次覆盖整个分支的宽范围审查。
|
||||
|
||||
**为什么用子智能体:** 你把任务委派给具有隔离上下文的专用智能体。通过精心设计它们的指令和上下文,确保它们专注并成功完成任务。它们绝不应继承你会话的上下文或历史记录——你要精确构造它们所需的一切。这样也能为你自己保留用于协调工作的上下文。
|
||||
|
||||
**核心原则:** 每个任务一个全新子智能体 + 任务审查(规格 + 质量)+ 结尾宽范围审查 = 高质量、快速迭代
|
||||
|
||||
**旁白:** 工具调用之间最多说一句简短的旁白——进度账本和工具结果本身就是记录。
|
||||
|
||||
**持续执行:** 不要在任务之间停下来向你的人类伙伴确认。不间断地执行计划里的所有任务。唯一该停下的理由是:你无法解决的 BLOCKED 状态、确实妨碍推进的歧义,或所有任务已完成。"我该继续吗?"之类的询问和进度小结都在浪费他们的时间——他们让你执行计划,那就执行。
|
||||
|
||||
**做裁决,不要停摆。** 一个正在跑的计划不等人。冲突、歧义、计划缺陷、你本来想申请突破的上限——你自己定。规格是有约束力的权威,计划是它的论证,两者都答不上来的部分由你的判断来定。每个决定都以 `Ruling: <你决定了什么> — <为什么> — <如果错了代价是什么>` 记进账本,然后继续。一个错误的裁决,代价是你人类伙伴看得见、也撤得掉的返工;一个停在问题上的会话,代价是他们的一整天,而且什么也换不来。
|
||||
|
||||
只有四件事会让你停下,也只有这四件:不可逆或破坏性的操作;涉及安全的动作;这个工作树之外、按惯例应当先问一声的副作用(合并、推送到共享分支、发布);以及一个坏到每条前进路径都只能靠猜的计划。遇到这四类,停下来问。
|
||||
|
||||
## 何时使用
|
||||
|
||||
```dot
|
||||
digraph when_to_use {
|
||||
"有实现计划?" [shape=diamond];
|
||||
"任务基本独立?" [shape=diamond];
|
||||
"留在当前会话?" [shape=diamond];
|
||||
"subagent-driven-development" [shape=box];
|
||||
"executing-plans" [shape=box];
|
||||
"手动执行或先头脑风暴" [shape=box];
|
||||
|
||||
"有实现计划?" -> "任务基本独立?" [label="是"];
|
||||
"有实现计划?" -> "手动执行或先头脑风暴" [label="否"];
|
||||
"任务基本独立?" -> "留在当前会话?" [label="是"];
|
||||
"任务基本独立?" -> "手动执行或先头脑风暴" [label="否 - 紧密耦合"];
|
||||
"留在当前会话?" -> "subagent-driven-development" [label="是"];
|
||||
"留在当前会话?" -> "executing-plans" [label="否 - 并行会话"];
|
||||
}
|
||||
```
|
||||
|
||||
**与 Executing Plans(并行会话)的对比:**
|
||||
- 同一会话(无上下文切换)
|
||||
- 每个任务全新子智能体(无上下文污染)
|
||||
- 每个任务后做审查(规格合规性 + 代码质量),结尾做宽范围审查
|
||||
- 更快的迭代(任务间无需人工介入)
|
||||
|
||||
## 流程
|
||||
|
||||
```dot
|
||||
digraph process {
|
||||
rankdir=TB;
|
||||
|
||||
subgraph cluster_per_task {
|
||||
label="每个任务";
|
||||
"分派实现子智能体 (./implementer-prompt.md)" [shape=box];
|
||||
"实现者有疑问?" [shape=diamond];
|
||||
"回答问题,提供上下文" [shape=box];
|
||||
"实现者实现、测试、提交、自审" [shape=box];
|
||||
"生成审查包,分派任务审查者 (./task-reviewer-prompt.md)" [shape=box];
|
||||
"规格 ✅ 且质量通过?" [shape=diamond];
|
||||
"发现与计划原文冲突?" [shape=diamond];
|
||||
"对冲突作出裁决, 把裁决记进账本" [shape=box];
|
||||
"第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" [shape=box];
|
||||
"分派定向复审 (./re-review-prompt.md)" [shape=box];
|
||||
"所有发现都已解决?" [shape=diamond];
|
||||
"R = 5?" [shape=diamond];
|
||||
"逐条裁定未解决的发现" [shape=box];
|
||||
"存在承重的发现?" [shape=diamond];
|
||||
"裁决并继续; 只有每条路都靠猜时才停" [shape=box];
|
||||
"把发现连同裁定搁置进账本" [shape=box];
|
||||
"往账本追加完成行,标记待办完成" [shape=box];
|
||||
}
|
||||
|
||||
"准备: 工作树、查账本、读计划、起飞前审查" [shape=box];
|
||||
"还有任务?" [shape=diamond];
|
||||
"分派最终代码审查者 (../requesting-code-review/code-reviewer.md)" [shape=box];
|
||||
"最终审查有发现? 一次修复分派、一次定向复审、裁定残留项" [shape=box];
|
||||
"最终审查干净: 删除本计划的工作区" [shape=box];
|
||||
"使用 finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen];
|
||||
|
||||
"准备: 工作树、查账本、读计划、起飞前审查" -> "分派实现子智能体 (./implementer-prompt.md)";
|
||||
"分派实现子智能体 (./implementer-prompt.md)" -> "实现者有疑问?";
|
||||
"实现者有疑问?" -> "回答问题,提供上下文" [label="是"];
|
||||
"回答问题,提供上下文" -> "实现者实现、测试、提交、自审";
|
||||
"实现者有疑问?" -> "实现者实现、测试、提交、自审" [label="否"];
|
||||
"实现者实现、测试、提交、自审" -> "生成审查包,分派任务审查者 (./task-reviewer-prompt.md)";
|
||||
"生成审查包,分派任务审查者 (./task-reviewer-prompt.md)" -> "规格 ✅ 且质量通过?";
|
||||
"规格 ✅ 且质量通过?" -> "往账本追加完成行,标记待办完成" [label="是"];
|
||||
"规格 ✅ 且质量通过?" -> "发现与计划原文冲突?" [label="否"];
|
||||
"发现与计划原文冲突?" -> "对冲突作出裁决, 把裁决记进账本" [label="是"];
|
||||
"对冲突作出裁决, 把裁决记进账本" -> "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型";
|
||||
"发现与计划原文冲突?" -> "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" [label="否"];
|
||||
"第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" -> "分派定向复审 (./re-review-prompt.md)";
|
||||
"分派定向复审 (./re-review-prompt.md)" -> "所有发现都已解决?";
|
||||
"所有发现都已解决?" -> "往账本追加完成行,标记待办完成" [label="是"];
|
||||
"所有发现都已解决?" -> "R = 5?" [label="否"];
|
||||
"R = 5?" -> "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" [label="否 - 进入下一轮"];
|
||||
"R = 5?" -> "逐条裁定未解决的发现" [label="是 - 熔断触发"];
|
||||
"逐条裁定未解决的发现" -> "存在承重的发现?";
|
||||
"存在承重的发现?" -> "裁决并继续; 只有每条路都靠猜时才停" [label="是"];
|
||||
"存在承重的发现?" -> "把发现连同裁定搁置进账本" [label="否"];
|
||||
"把发现连同裁定搁置进账本" -> "往账本追加完成行,标记待办完成";
|
||||
"往账本追加完成行,标记待办完成" -> "还有任务?";
|
||||
"还有任务?" -> "分派实现子智能体 (./implementer-prompt.md)" [label="是"];
|
||||
"还有任务?" -> "分派最终代码审查者 (../requesting-code-review/code-reviewer.md)" [label="否"];
|
||||
"分派最终代码审查者 (../requesting-code-review/code-reviewer.md)" -> "最终审查有发现? 一次修复分派、一次定向复审、裁定残留项";
|
||||
"最终审查有发现? 一次修复分派、一次定向复审、裁定残留项" -> "最终审查干净: 删除本计划的工作区";
|
||||
"最终审查干净: 删除本计划的工作区" -> "使用 finishing-a-development-branch";
|
||||
}
|
||||
```
|
||||
|
||||
## 准备
|
||||
|
||||
确保工作发生在一个隔离的工作区里:用 using-git-worktrees 创建一个,或者核实已有的那个。没有你人类伙伴的明确同意,绝不在 main/master 分支上开始实现。
|
||||
|
||||
会话记忆无法在上下文压缩(compaction)中存活。在真实会话里,丢失了位置的控制者曾重新分派整段已经完成的任务序列——这是观察到的最昂贵的失败。把进度记在一个账本文件里,而不只是记在待办里。
|
||||
|
||||
- **每个计划拥有自己的工作区:** 技能启动时,运行本技能的 `scripts/sdd-workspace PLAN_FILE`——它会打印这个计划专属的、被 git 忽略的目录(`<repo-root>/.superpowers/sdd/<计划文件名>/`),**本计划**的一切产物都放在那里:账本、简报、报告、审查包。别的计划的目录不属于你,不读也不写。
|
||||
- 到 `<工作区>/progress.md` 查本计划的账本。如果它的第一行点名的是你的计划文件,那么带有 `Task <N>: complete` 行的任务就是**已完成**——不要重新分派它们;从第一个没有该行的任务处继续。如果某个任务的最后一行是一轮修复,说明它正卡在修复循环中:从下一轮继续。如果账本第一行点名的是**另一个**计划文件——或者你在旧的扁平路径 `.superpowers/sdd/progress.md` 发现了一个游离的账本——那是别人的进度:原地别动,另起你自己的新账本。
|
||||
- 创建账本时,把它的身份写在第一行:`# SDD ledger — plan: <计划文件路径>`。
|
||||
- 这个账本是你的恢复地图:它点名的那些提交,即使你的上下文已经不记得创建过它们,也确实存在于 git 中。压缩之后,相信账本和 `git log`,而不是你自己的记忆。
|
||||
- `git clean -fdx` 会毁掉这个工作区(它是被 git 忽略的临时文件);万一发生了,就从 `git log` 恢复。
|
||||
|
||||
把计划**读一遍**,记下它的上下文和全局约束,并为每个任务建一条待办。如果计划点名了一份规格(Spec),把规格也读了:规格是计划据以论证的权威,计划内部的冲突要拿它来裁。计划里找不到可达的规格,就在账本里记一条说明——没有规格作出的裁决都是临时的。
|
||||
|
||||
在分派任务 1 之前,把计划通扫一遍找冲突,边查边把你查过的东西写下来:
|
||||
|
||||
- 互相矛盾的任务,或与计划的"全局约束"矛盾的任务
|
||||
- 计划明确要求、但审查标准会判为缺陷的东西(比如一个什么都不断言的测试、一整块逻辑的逐字复制)
|
||||
|
||||
这次扫描的产出是一张**表**,不是一句结论。每一对共用文件或接口的任务占一行:这两个任务、一个产出的东西对上另一个消费的东西、以及你发现了什么。每个任务再占一行:它自己的文本是否自洽——它规定的测试对上它规定的代码,它创建的文件对上它后面又要碰的文件。没有这些行的"扫描是干净的",不算你真扫过。
|
||||
|
||||
把这张表写进账本。在执行开始之前就对你找到的每一条作出裁决——每条发现都并列上要求它的那段计划原文——并把每条裁决记进账本。如果扫描是干净的,就不要多说,直接开始。对它翻出的每个冲突作出裁决——规格是有约束力的权威,计划是它的论证——把裁决记在那一行旁边,然后分派任务 1。审查循环仍然是那些只有在实现中才浮现的冲突的兜底网。
|
||||
|
||||
## 模型选择
|
||||
|
||||
在能胜任的前提下,为每个角色选用最弱的模型,以节省成本、提升速度。
|
||||
|
||||
**机械性实现任务**(孤立的函数、清晰的规格、1-2 个文件):用快而便宜的模型。计划写得好时,大多数实现任务都是机械性的。
|
||||
|
||||
**集成与判断类任务**(跨文件协调、模式匹配、调试):用标准模型。
|
||||
|
||||
**架构与设计类任务**:用可用的最强模型。覆盖整个分支的最终审查就属于这一类——用可用的最强模型去分派它,不要用会话默认模型。
|
||||
|
||||
**审查任务**:用同样的判断来选模型,并按 diff 的体量、复杂度和风险来缩放。一个小的机械性 diff 不需要最强模型;一个微妙的并发改动需要。小修复 diff 的定向复审用便宜到中档的层级即可。
|
||||
|
||||
**修复循环的升级(第 4-5 轮)**:用比那个卡住了的实现者**至少高一档**的模型。
|
||||
|
||||
**分派子智能体时永远显式指定模型。** 省略模型会继承你会话的模型——往往是最强也最贵的那个——这会悄无声息地让本节的努力全部失效。
|
||||
|
||||
**轮次数比 token 单价更要紧。** 墙钟时间和上下文成本是随子智能体花掉多少轮次而增长的,而最便宜的模型在多步工作上经常要花 2-3 倍轮次——总账反而更贵。审查者、以及依据散文式描述工作的实现者,都以中档模型为下限。当任务的计划原文里已经包含了要写的完整代码时,实现就是抄写加测试:这种实现者用最便宜的层级。单文件的机械性修复也用最便宜的层级。
|
||||
|
||||
**任务复杂度信号(实现类任务):**
|
||||
- 涉及 1-2 个文件且规格完整 → 便宜模型
|
||||
- 涉及多个文件且有集成考量 → 标准模型
|
||||
- 需要设计判断或对代码库的广泛理解 → 最强模型
|
||||
|
||||
## 任务循环
|
||||
|
||||
**把同形状的小活打包。** 当计划里列了好几个任务,每个都是同一类的小改动——同样的一行修复、同样的常量替换、同样的字段新增,只是散在不同文件里——不要一个任务派一个子智能体。写**一份**分派简报,把每个文件和它的改动都列上,整批交给同一个子智能体,把它的 diff 当作一个单位来审查。一个任务一次分派,留给那些需要自己的判断、自己的测试、自己的审查面的活。
|
||||
|
||||
你粘进分派提示词里的一切、以及子智能体打印回来的一切,都会在本次会话余下的时间里常驻你的上下文,并且在之后每一轮被重新读一遍。**产物要用文件来交接。**
|
||||
|
||||
**等待已分派的子智能体:** 绝不用短超时去轮询等待接口,也绝不干坐在一次沉默的、没有上限的等待里。只要你手上还有本地活可干——更新账本、打包下一次审查、读报告——就接着干;子智能体的结果会自己送到。当你真的空了,就分段等待,每段有上限(在你的平台允许的范围内,五到十分钟),两段之间发一行状态,并对账你还活着的子智能体:把它们列出来,追一下那些干完了却没报告的。分段等待几乎保留了长等待的全部效率,同时保证一个卡住或丢失的子智能体在几分钟内就被发现,而不是拖到会话最后。
|
||||
|
||||
### 1. 分派实现者
|
||||
|
||||
分派之前记录 BASE(`git rev-parse HEAD`)——审查包和各轮修复的 diff 都要用它。
|
||||
|
||||
- **任务简报:** 分派实现者之前,运行本技能的 `scripts/task-brief PLAN_FILE N`——它把该任务的完整文本抽取到一个唯一命名的文件并打印路径。组织你的分派,让这份简报保持为需求的唯一来源。你的分派应包含:(1) 一行说明这个任务在项目中的位置;(2) 简报路径,引入语为"先读这个——它是你的需求,里面有要逐字使用的精确取值";(3) 简报无从知晓的、来自前序任务的接口和决策;(4) 你对简报中注意到的任何歧义的裁定;(5) 报告文件路径和报告契约。精确取值(数字、魔法字符串、签名、测试用例)只出现在简报里。**绝不**让子智能体去读整个计划文件。
|
||||
- **报告文件:** 实现者的报告文件按简报来命名(简报 `…/task-N-brief.md` → 报告 `…/task-N-report.md`),并写进分派提示词。实现者把完整报告写在那里,只回传状态、提交、一行测试小结和疑虑。
|
||||
- 一个分派提示词描述的是**一个任务**,不是会话的历史。不要把累积的前序任务小结("任务 1-3 之后的状态")粘进后面的分派——真实会话里曾出现过 42k 字符的分派,其中 99% 是粘贴的历史。一个全新的子智能体需要的是:它的任务、它要碰的接口、以及全局约束。别无其他。
|
||||
- 如果前面某个任务把一条发现搁置在本任务要碰的区域,就在分派里带上指向那条账本记录的指针。
|
||||
- 分派本身携带**不派子智能体**的契约(它就写在实现者模板里):实现者绝不分派子智能体——不派帮手,更不派审查者。审查由你在报告之后送达。在真实会话里,工作者自己派出的每一个审查者,都在重复控制者本来就会分派的那次任务审查——每个任务白白多出一个完整的审查席位。
|
||||
- **记下分派结果里实现者的智能体身份**——第 1-3 轮修复要唤回这个智能体。
|
||||
- 绝不并行分派多个实现子智能体(会冲突)。
|
||||
|
||||
模板:[implementer-prompt.md](implementer-prompt.md)
|
||||
|
||||
### 2. 处理报告
|
||||
|
||||
实现子智能体会回传四种状态之一。分别处理:
|
||||
|
||||
**DONE:** 生成审查包(在本技能目录下运行 `scripts/review-package PLAN_FILE BASE HEAD`——它会打印出自己写入的那个唯一文件路径;BASE 是你在分派实现者之前记录下来的那个提交——**绝不用** `HEAD~1`,那会悄悄丢掉多提交任务里除最后一个之外的所有提交),然后把打印出的路径交给任务审查者去分派。
|
||||
|
||||
**DONE_WITH_CONCERNS:** 实现者完成了工作但提出了疑虑。继续之前先读这些疑虑。如果疑虑关乎正确性或范围,在审查之前先处理掉。如果只是观察(比如"这个文件变大了"),记下来,继续走审查。
|
||||
|
||||
**NEEDS_CONTEXT:** 实现者需要没被提供的信息。补上缺失的上下文并重新分派。
|
||||
|
||||
**BLOCKED:** 实现者无法完成任务。评估这个阻塞:
|
||||
1. 如果是上下文问题,补充上下文并用同一个模型重新分派
|
||||
2. 如果任务需要更多推理,用更强的模型重新分派
|
||||
3. 如果任务太大,拆成更小的块
|
||||
4. 如果是计划本身错了,对这个更正作出裁决,记进账本,并把裁决带进重新分派的提示词里
|
||||
|
||||
**绝不**忽视一次上报,也**绝不**在什么都没改的情况下强迫同一个模型重试。如果实现者说它卡住了,那就一定有东西需要改变。
|
||||
|
||||
如果实现者提问——不论是开始前还是任务中途——清楚完整地回答,需要时补充上下文,不要催着它进入实现。
|
||||
|
||||
### 3. 审查任务
|
||||
|
||||
逐任务审查是**任务范围内的关卡**。宽范围审查只做一次,在最终的整分支审查那里。绝不跳过任务审查,也绝不接受一份缺少任一结论的报告——规格合规性**和**任务质量两者都必须有。实现者的自审永远不能替代任务审查;两者都需要。
|
||||
|
||||
- **把 diff 作为文件交给审查者:** 运行本技能的 `scripts/review-package PLAN_FILE BASE HEAD`,把它打印出的文件路径交给审查者(若没有 bash:对该区间跑 `git log --oneline`、`git diff --stat`、`git diff -U10`,重定向到一个唯一命名的文件)。这些输出永远不会进入你自己的上下文,而审查者在一次 Read 调用里就能看到提交列表、stat 摘要和带上下文的完整 diff。用你在分派实现者之前记录下的 BASE——**绝不用** `HEAD~1`,那会悄悄截断多提交任务。**绝不**在没有 diff 文件的情况下分派任务审查者。
|
||||
- **审查者的输入:** 任务审查者拿到三个路径——同一份简报文件、报告文件、审查包——外加约束该任务的全局约束。
|
||||
- 你交给审查者的全局约束块是它的**注意力透镜**。从计划的"全局约束"一节或规格里**逐字**抄下有约束力的需求:精确的取值、精确的格式,以及组件之间被明确规定的关系("与 X 相同的布局"、"匹配 Y")。审查者的模板里已经带了流程规则(YAGNI、测试卫生、审查方法)——约束块是用来装**这个项目**的规格所要求的东西的。
|
||||
- 不要在没有具体的、任务专属的理由时,加上"检查所有用法"或"有用的话跑一下竞态测试"这类开放式指令
|
||||
- 不要让审查者重跑实现者已经在同一份代码上跑过的测试——实现者的报告承载着测试证据
|
||||
- **不要替审查者预先给发现定性**——绝不指示审查者忽略或不要标记某个具体问题。如果你认为某条发现会是误报,让审查者提出来,然后在审查循环里裁定它。如果你正在写的提示词里出现了"不要标记"、"不要把 X 当缺陷"、"顶多按 Minor 处理"、"计划选择了"——停下:你正在预先定性,而且通常是为了让自己少走一轮审查循环。
|
||||
|
||||
任务审查者可能报告"⚠️ 无法从 diff 核实"的条目——那些活在未改动代码里、或者跨任务的需求。这些不阻塞审查的其余部分,但在标记任务完成之前**你必须自己逐条解决它们**:你掌握着审查者所缺的计划和跨任务上下文。如果你确认某一条是真实的缺口,就把它当作规格审查失败来处理——它和其他发现一起进入修复循环。
|
||||
|
||||
模板:[task-reviewer-prompt.md](task-reviewer-prompt.md)
|
||||
|
||||
### 4. 修复循环
|
||||
|
||||
当审查报告规格 ❌、任何 Critical 或 Important 发现、或者你确认为真实缺口的 ⚠️ 条目时,循环触发。
|
||||
|
||||
循环开始之前,有两条路会立刻离开它:
|
||||
|
||||
- **Minor 发现**随手记进进度账本(`Task <N>: minor (deferred): <一句话>`),并把最终的整分支审查指向那份清单,让它去甄别哪些必须在合并前修掉。**没人读的汇总等于静默丢弃。** Minor 发现永远不进入循环。
|
||||
- 被标为"计划要求的"发现——或任何与计划原文所要求的内容冲突的发现——**由你来裁决**:把这条发现放到计划原文旁边掂量,以规格为有约束力的权威作出决定,并在据此行动之前把裁决记进账本。不要因为计划要求就驳回这条发现,也不要在没有一条记录在案的裁决的情况下分派一个与计划相违的修复。
|
||||
|
||||
其他一切都进入循环。**一轮修复 = 一次修复分派 + 一次定向复审。每个任务最多五轮。**
|
||||
|
||||
**第 1-3 轮——唤回原来那个实现者(resume)。** 把未解决的发现**逐字**发给它。它的上下文是完整的:它知道任务、知道代码、知道自己做过的选择。如果你的运行环境无法给一个活着的子智能体再发消息,就分派一个全新实现者,带上简报路径、报告文件路径和那些发现——无论走哪条路,报告文件都是那份持久化记忆。
|
||||
|
||||
**第 4-5 轮——用更强的模型分派一个全新实现者**(按"模型选择"),带上简报路径、报告文件路径、未解决的发现,以及这样的框定语:"某个此前的实现者尝试过这个任务 [N] 次;现在它归你了。读报告文件了解已经试过什么。"一个熬过三次唤回的循环,通常意味着实现者看不见自己的问题——换新眼睛加提升能力,一步到位。
|
||||
|
||||
**每一轮,无论走哪条路:** 实现者修复、重跑覆盖被改动代码的测试、把修复报告追加到**同一个**报告文件、回传那个简短契约。重新分派审查者之前,先确认修复报告里含有覆盖用的测试、跑过的命令、以及输出;三者齐备才分派复审。在修复消息里点名覆盖用的测试文件——一行的修复不需要整包套件。
|
||||
|
||||
**复审是定向的。** 运行 `scripts/review-package PLAN_FILE FIX_BASE HEAD`,其中 FIX_BASE 是上一次审查所看到的那个 head,然后用 [re-review-prompt.md](re-review-prompt.md) 分派,附上发现清单、简报、报告文件和打印出的 diff 路径。复审者对每条发现给出 ADDRESSED 或 NOT ADDRESSED 的结论,并且**只**标记修复 diff 里的新破坏。修复 diff 里新出现的 Critical/Important 破坏加入未解决发现清单。范围外的观察作为延后的 Minor 进账本——它们永远不延长循环。
|
||||
|
||||
**每轮结束后**往账本追加:
|
||||
`Task <N>: fix round <R>/5 (<X> addressed, <Y> open — <发现的一句话概括>; commits <a7>..<b7>)`
|
||||
|
||||
**绝不在控制者会话里自己修发现**——你的上下文要保持干净以供协调,而且控制者的修复会跳过审查。
|
||||
|
||||
**熔断。** 当第 5 轮的复审仍然留下未解决的发现时,**停止分派**。你自己逐条裁定这些未解决的发现——你掌握着审查者所缺的计划和跨任务上下文:
|
||||
|
||||
- **审查者错了,或者这一点是可争议的:** 搁置它——`Task <N>: parked — <发现> — Ruling: <为什么代码可以维持原样>`。最终审查会看到双方说法。
|
||||
- **是真实的,但下游没有任何东西建立在它之上:** 同样搁置,裁定里写明它是真的、被延后了。
|
||||
- **真实且承重**——后面的任务建立在它之上,或者它揭示了一个计划缺陷:对**能解开后续工作的最小改动**作出裁决,以 `Task <N>: Ruling: <发现> — <你决定了什么,以及为什么>` 记进账本,并把它带进下一个任务的分派里。把一个结构性失败悄悄搁置掉,会让每个依赖它的任务都建立在它之上。只有当这个缺陷让每条前进路径都只能靠猜时,才停下来。
|
||||
|
||||
**只在触及上限时才裁定。** 为了结束循环而提早裁定,只是换了个名字的"预先定性"。每一次裁定都是一条账本记录——**静默丢弃是禁止的**。
|
||||
|
||||
### 5. 完成任务
|
||||
|
||||
当审查干净地返回——或者在触及上限时每条未解决的发现都已带着裁定被搁置——在你做其他记账的同一条消息里,往账本追加完成行:
|
||||
|
||||
- `Task <N>: complete (commits <base7>..<head7>, review clean)`
|
||||
- 熔断触发过的话:`Task <N>: complete (commits <base7>..<head7>, <K> parked)`
|
||||
|
||||
然后标记待办完成,继续下一个。**绝不**在审查还有未解决的 Critical/Important 问题、而它们既没被修复也没在上限处带裁定搁置时,就进入下一个任务。
|
||||
|
||||
## 最终审查
|
||||
|
||||
覆盖整个分支的最终审查也拿到一个审查包:运行 `scripts/review-package PLAN_FILE MERGE_BASE HEAD`(MERGE_BASE = 分支起点的那个提交,例如 `git merge-base main HEAD`),把打印出的路径放进最终审查的分派里,这样最终审查者读一个文件就行,不必用 git 命令重新推导整个分支的 diff。用可用的最强模型分派(见"模型选择"),使用 requesting-code-review 的 [code-reviewer.md](../requesting-code-review/code-reviewer.md)。把它指向账本里那些"延后的 Minor"和"已搁置"的行,让它甄别哪些必须在合并前修掉。
|
||||
|
||||
如果覆盖整个分支的最终审查返回了发现,用**一个**修复子智能体带着**完整的**发现清单去分派——不要一条发现一个修复者。逐条发现各派一个修复者,每个都要重建上下文、重跑测试套件;真实会话里,一次最终审查的修复浪潮花掉的成本超过它全部任务的总和。然后对这波修复跑**恰好一次**定向复审(对修复区间跑 `scripts/review-package PLAN_FILE FIX_BASE HEAD`,用 [re-review-prompt.md](re-review-prompt.md))。残留的发现按任务循环里熔断那套来裁定:带裁定搁置,或者对承重项作出裁决并把你的决定记进账本。只有上面那四类才会在这里让你停下。**没有第二波修复**——残留的承重发现会在 finishing-a-development-branch 呈现选项时浮到你人类伙伴面前。
|
||||
|
||||
## 收尾
|
||||
|
||||
在你删除任何东西之前,把账本里每一条含 `Ruling:` 的记录都收集起来——预检裁决、搁置的发现、熔断裁定,全部——按你作出它们的顺序,放进你最终消息的「我作出的裁决」一节里,每条都附上如果错了代价是什么。这份清单是穷尽的:账本里有的裁决,清单里就要有。这份清单是你代你的人类伙伴作出的那些决定唯一能抵达他们的地方——他们读它,并返工你搞错的部分。一条随工作区一起消失的裁决,就是一个在暗中作出的决定。
|
||||
|
||||
当覆盖整个分支的最终审查干净、且它的修复已合并时,删除**本计划**的工作区(`rm -rf <工作区>`)——现在 git 历史就是记录了。同级目录属于别的计划,别去动它们。
|
||||
|
||||
使用 finishing-a-development-branch。
|
||||
|
||||
## 常见的合理化借口
|
||||
|
||||
| 借口 | 现实 |
|
||||
|------|------|
|
||||
| "规格合规性上差不多就行了" | 审查者发现了规格差距 = 未完成。修掉,或者走到上限去裁定——只有这两个出口。 |
|
||||
| "我自己修就好了,分派是额外开销" | 控制者的修复会污染你的上下文并跳过审查。唤回实现者。 |
|
||||
| "再来一轮就收敛了" | 过了上限,轮次不会收敛——那个失败是结构性的。裁定并分流。 |
|
||||
| "反正审查者总会再挑出新东西" | 定向复审只核实修复,它不能到处乱逛。未改动代码上的新发现进账本,不进循环。 |
|
||||
| "这条发现明显错了,我直接丢掉" | 你只在上限处裁定,而且每条裁定都是账本记录。静默丢弃是禁止的。 |
|
||||
| "修复很小,跳过复审吧" | 未经审查的修复正是回归产生的方式。每一轮都以一次定向复审结束。 |
|
||||
| "审查把循环拖慢了" | 没有审查的循环只是未经核实的空转。审查是这个循环的刹车和方向盘。 |
|
||||
| "记账本是额外开销" | 账本是能在压缩中存活下来的东西。没有账本的控制者曾重新分派整段已完成的任务序列。 |
|
||||
| "实现者自己派了个审查者——白送的额外保障" | 那是一个重复的席位,按全价审查同一份 diff,而且它的裁定不算数。审查由控制者分派。 |
|
||||
|
||||
## 示例工作流
|
||||
|
||||
```
|
||||
你:我正在用子智能体驱动开发来执行这个计划。
|
||||
|
||||
[准备:工作树已核实]
|
||||
[把计划文件读一遍:docs/superpowers/plans/feature-plan.md]
|
||||
[解析工作区:scripts/sdd-workspace docs/superpowers/plans/feature-plan.md —— 里面没有账本,全新开始]
|
||||
[为所有任务创建待办]
|
||||
|
||||
任务 1:Hook 安装脚本
|
||||
|
||||
[对任务 1 运行 task-brief;分派实现者,附带简报 + 报告路径 + 上下文]
|
||||
|
||||
实现者:"开始之前——这个 hook 应该装在用户级还是系统级?"
|
||||
|
||||
你:"用户级(~/.config/superpowers/hooks/)"
|
||||
|
||||
实现者:[稍后]
|
||||
- 实现了 install-hook 命令
|
||||
- 加了测试,5/5 通过
|
||||
- 自审:发现漏了 --force 标志,已补上
|
||||
- 已提交
|
||||
|
||||
[运行 review-package PLAN_FILE BASE HEAD;把打印出的路径交给任务审查者去分派]
|
||||
任务审查者:规格 ✅ —— 所有需求都满足,没有多余的东西。
|
||||
优点:测试覆盖良好,代码整洁。问题:无。任务质量:通过。
|
||||
|
||||
[账本:Task 1: complete (commits a1b2c3d..d4e5f6a, review clean)]
|
||||
|
||||
任务 2:恢复模式
|
||||
|
||||
[对任务 2 运行 task-brief;分派实现者,附带简报 + 报告路径 + 上下文]
|
||||
|
||||
实现者:[无疑问]
|
||||
- 加了 verify/repair 模式
|
||||
- 8/8 测试通过
|
||||
- 已提交
|
||||
|
||||
[运行 review-package PLAN_FILE BASE HEAD;把打印出的路径交给任务审查者去分派]
|
||||
任务审查者:规格 ❌:
|
||||
- 缺失:进度上报(规格说"每 100 项上报一次")
|
||||
问题(Important):魔法数字(100)
|
||||
|
||||
[第 1 轮修复:唤回原实现者,带上这两条发现]
|
||||
实现者:加了进度上报,把 PROGRESS_INTERVAL 提成了常量。
|
||||
重跑了 test/recovery.test.js —— 10/10 通过。修复报告已追加。
|
||||
|
||||
[运行 review-package PLAN_FILE FIX_BASE HEAD;分派定向复审]
|
||||
复审者:缺失进度上报 —— ADDRESSED(src/recovery.js:41)。
|
||||
魔法数字 —— ADDRESSED(src/recovery.js:7)。新破坏:无。
|
||||
结论:所有发现均已解决。
|
||||
|
||||
[账本:Task 2: fix round 1/5 (2 addressed, 0 open; commits d4e5f6a..b7c8d9e)]
|
||||
[账本:Task 2: complete (commits d4e5f6a..b7c8d9e, review clean)]
|
||||
|
||||
...
|
||||
|
||||
[所有任务之后]
|
||||
[运行 review-package PLAN_FILE MERGE_BASE HEAD;分派最终代码审查者,用最强模型]
|
||||
最终审查者:所有需求都满足。延后的 Minor 已甄别:没有阻塞合并的。
|
||||
|
||||
[删除本计划的工作区 —— 现在记录活在 git 里]
|
||||
|
||||
搞定!使用 finishing-a-development-branch。
|
||||
```
|
||||
@ -0,0 +1,144 @@
|
||||
# 实现子智能体提示词模板
|
||||
|
||||
分派实现子智能体时使用此模板。
|
||||
|
||||
```
|
||||
Subagent (general-purpose):
|
||||
description: "实现任务 N:[任务名称]"
|
||||
model: [模型 —— 必填:按 SKILL.md 的"模型选择"来选;省略模型会默默
|
||||
继承会话里最贵的那个]
|
||||
prompt: |
|
||||
你正在实现任务 N:[任务名称]
|
||||
|
||||
## 任务描述
|
||||
|
||||
先读你的任务简报:[BRIEF_FILE]
|
||||
它包含计划中该任务的完整文本。
|
||||
|
||||
## 上下文
|
||||
|
||||
[场景铺设:这个任务在哪个环节、依赖关系、架构上下文]
|
||||
|
||||
## 开始之前
|
||||
|
||||
如果你对以下内容有疑问:
|
||||
- 需求或验收标准
|
||||
- 方案或实现策略
|
||||
- 依赖或假设
|
||||
- 任务描述中任何不清楚的地方
|
||||
|
||||
**现在就问。** 在开始工作之前提出任何疑虑。
|
||||
|
||||
## 你的工作
|
||||
|
||||
当你确认需求清晰后:
|
||||
1. 严格按照任务指定的内容实现
|
||||
2. 编写测试(如果任务要求则遵循 TDD)
|
||||
3. 验证实现是否正常工作
|
||||
4. 提交你的工作
|
||||
5. 自审(见下文)
|
||||
6. 汇报
|
||||
|
||||
工作目录:[directory]
|
||||
|
||||
**工作过程中:** 如果遇到意料之外或不清楚的情况,**提问**。
|
||||
随时可以暂停并澄清。不要猜测或做假设。
|
||||
|
||||
迭代过程中,只跑你正在改动的那部分的聚焦测试;在提交前跑一次
|
||||
完整测试套件,而不是每次编辑后都跑。
|
||||
|
||||
## 你不派发子代理
|
||||
|
||||
这个任务的全部工作由你自己做完。绝不为了实现任务的一部分而派生子代理,尤其绝不派生一个审查者来检查你自己的工作。下面说的「自审」指的是读你自己的 diff。审查是控制者的职责:你汇报之后,它会针对你的 diff 派发一个全新的审查者。你派生出来的审查者只是按全价重复那次审查,而它的批准在流程里不作数。如果你发现自己在想「独立审一遍会让我的报告更有说服力」—— 那次审查已经排好队了。去汇报就行。
|
||||
|
||||
## 代码组织
|
||||
|
||||
你在能一次性放入上下文的代码上推理效果最好,文件聚焦时你的编辑也更可靠。
|
||||
请牢记:
|
||||
- 遵循计划中定义的文件结构
|
||||
- 每个文件应有单一明确的职责和定义清晰的接口
|
||||
- 如果你正在创建的文件超出了计划的意图规模,停下来并以
|
||||
DONE_WITH_CONCERNS 状态报告——不要在没有计划指导的情况下自行拆分文件
|
||||
- 如果你正在修改的现有文件已经很大或很混乱,小心操作,
|
||||
并在报告中将其标注为疑虑
|
||||
- 在已有代码库中,遵循已建立的模式。像一个好的开发者那样
|
||||
改善你接触到的代码,但不要重构你任务范围之外的东西。
|
||||
|
||||
## 当你力不从心时
|
||||
|
||||
随时可以停下来说"这对我来说太难了"。劣质的工作比不做更糟。
|
||||
上报不会受到惩罚。
|
||||
|
||||
**遇到以下情况时停下来上报:**
|
||||
- 任务需要在多个有效方案之间做架构决策
|
||||
- 你需要理解提供内容之外的代码但找不到清晰答案
|
||||
- 你对自己的方案是否正确感到不确定
|
||||
- 任务涉及计划未预期的现有代码重构
|
||||
- 你一直在逐个读文件试图理解系统但没有进展
|
||||
|
||||
**如何上报:** 以 BLOCKED 或 NEEDS_CONTEXT 状态汇报。具体描述
|
||||
你卡在哪里、尝试了什么、需要什么样的帮助。
|
||||
控制者可以提供更多上下文、用更强的模型重新分派,
|
||||
或将任务拆分为更小的部分。
|
||||
|
||||
## 汇报前:自审
|
||||
|
||||
用全新的视角审查你的工作。问自己:
|
||||
|
||||
**完整性:**
|
||||
- 我是否完全实现了规格中的所有内容?
|
||||
- 我是否遗漏了任何需求?
|
||||
- 是否有我没处理的边界情况?
|
||||
|
||||
**质量:**
|
||||
- 这是我最好的工作吗?
|
||||
- 命名是否清晰准确(匹配事物做什么,而非怎么做)?
|
||||
- 代码是否整洁且可维护?
|
||||
|
||||
**纪律:**
|
||||
- 我是否避免了过度构建(YAGNI)?
|
||||
- 我是否只构建了被要求的内容?
|
||||
- 我是否遵循了代码库中的已有模式?
|
||||
|
||||
**测试:**
|
||||
- 测试是否真正验证了行为(而非只是 mock 行为)?
|
||||
- 如果要求了 TDD,我是否遵循了?
|
||||
- 测试是否全面?
|
||||
- 测试输出是否干净(没有零散的告警或噪声)?
|
||||
|
||||
如果在自审中发现问题,在汇报前就修复。
|
||||
|
||||
## 审查发现之后
|
||||
|
||||
如果任务审查发现了问题,你会被带着那些发现重新唤起(resume)。
|
||||
修复它们,重跑覆盖被改动代码的测试,然后往你的报告文件里追加一份
|
||||
修复报告:你改了什么、你跑了哪些覆盖用的测试、命令是什么、输出是什么。
|
||||
审查者不会替你重跑测试——你的报告就是测试证据。然后用与第一份报告
|
||||
相同的那个简短状态契约回复。
|
||||
|
||||
## 报告格式
|
||||
|
||||
把你的完整报告写到 [REPORT_FILE]:
|
||||
- 你实现了什么(如果被阻塞,则是你尝试了什么)
|
||||
- 你测试了什么以及测试结果
|
||||
- **TDD 证据**(如果本任务要求了 TDD):
|
||||
- RED:跑的命令、实现前相关的失败输出、以及为什么这个失败是预期的
|
||||
- GREEN:跑的命令、以及实现后相关的通过输出
|
||||
- 修改了哪些文件
|
||||
- 自审发现(如果有)
|
||||
- 任何问题或疑虑
|
||||
|
||||
然后只汇报以下内容(不超过 15 行——细节都在报告文件里):
|
||||
- **状态:** DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
|
||||
- 创建的提交(短 SHA + 标题)
|
||||
- 一行测试小结(例如"14/14 通过,输出干净")
|
||||
- 你的疑虑,如果有
|
||||
- 报告文件路径
|
||||
|
||||
如果是 BLOCKED 或 NEEDS_CONTEXT,把具体细节放进最终消息本身——
|
||||
控制者会直接据此行动。
|
||||
|
||||
如果你完成了工作但对正确性有疑虑,使用 DONE_WITH_CONCERNS。
|
||||
如果你无法完成任务,使用 BLOCKED。如果你需要未提供的信息,
|
||||
使用 NEEDS_CONTEXT。绝不默默产出你不确定的工作。
|
||||
```
|
||||
@ -0,0 +1,104 @@
|
||||
# 定向复审提示词模板
|
||||
|
||||
在一轮修复之后分派复审时使用此模板。复审者核实那些发现是否已被解决,
|
||||
并检查修复 diff 有没有引入新的破坏。这**不是**一次全新审查——完整审查
|
||||
早已做过了。
|
||||
|
||||
**目的:** 核实上一次审查的每一条发现都已解决,且修复本身没有破坏任何东西。
|
||||
|
||||
```
|
||||
Subagent (general-purpose):
|
||||
description: "复审任务 N 第 R 轮修复"
|
||||
model: [模型 —— 必填:按 SKILL.md 的"模型选择"来选;省略模型会默默
|
||||
继承会话里最贵的那个]
|
||||
prompt: |
|
||||
你正在复审一个任务的一轮修复。之前的审查产生了一批发现,
|
||||
一个实现者已经尝试修复它们。你的工作是给每条发现下结论、
|
||||
并检查这次修复的 diff——仅此而已。
|
||||
|
||||
## 任务
|
||||
|
||||
读取任务简报:[BRIEF_FILE]
|
||||
|
||||
## 待核实的发现
|
||||
|
||||
[FINDINGS]
|
||||
|
||||
## 修复
|
||||
|
||||
读取实现者的报告(修复报告追加在文件末尾):
|
||||
[REPORT_FILE]
|
||||
|
||||
**修复基线:** [FIX_BASE_SHA](上一次审查所看到的那个 head)
|
||||
**Head:** [HEAD_SHA]
|
||||
**diff 文件:** [DIFF_FILE]
|
||||
|
||||
把 diff 文件一次读完——它包含修复的提交、stat 摘要,以及带上下文的
|
||||
修复 diff。不要重新跑 git 命令。如果 diff 文件不存在,自己取 diff:
|
||||
`git diff --stat [FIX_BASE_SHA]..[HEAD_SHA]` 和
|
||||
`git diff [FIX_BASE_SHA]..[HEAD_SHA]`。
|
||||
|
||||
你的审查对这个 checkout 是只读的。不要以任何方式改动工作树、索引、
|
||||
HEAD 或分支状态。
|
||||
|
||||
## 你不派发子代理
|
||||
|
||||
这次审查全部由你自己做完。绝不为了审查 diff 的一部分而派生子代理,也绝不为了「再要一个意见」而派生另一个审查者。这套流程已经给了这份工作应有的每一个审查席位;你派生出来的审查者只是按全价重复其中一个,而它的结论不作数。如果 diff 大到一遍看不完,就自己分几遍看,并在报告里说明。
|
||||
|
||||
## 范围
|
||||
|
||||
你的范围就是那份发现清单和这次修复的 diff。**每一条发现都要给结论。**
|
||||
检查修复 diff 里有没有修复本身引入的新问题。**不要**去复审这次修复
|
||||
没有碰过的代码:如果你注意到一个完全在修复 diff 之外的问题,
|
||||
把它写进"范围外的观察"——它不阻塞本任务,也不会延长修复循环。
|
||||
覆盖整个分支的宽范围审查会在所有任务完成后另行进行。
|
||||
|
||||
## 测试
|
||||
|
||||
实现者已经重跑了覆盖被改动代码的那些测试,并把结果追加到了报告文件里。
|
||||
把报告当作**未经核实的声明**来对待:确认修复报告点名了覆盖用的测试
|
||||
并给出了它们的输出,再拿这些声明去对照 diff 核验。不要为了确认它的报告
|
||||
而重跑整个测试套件。只有当读代码引出了某个现有运行结果无法回答的
|
||||
具体疑问时才跑测试——而且只跑一个聚焦的测试,绝不跑整包套件。
|
||||
|
||||
## 输出格式
|
||||
|
||||
你的最终消息就是报告本身:直接从第一条发现的结论开始。每一行都应该是
|
||||
一个结论、一条带 file:line 的发现,或者一项你实际做过的检查——
|
||||
不要开场白,不要过程旁白。
|
||||
|
||||
### 各条发现的结论
|
||||
|
||||
按"待核实的发现"里的顺序,逐条给出:
|
||||
- **[发现的一句话概括]** —— ADDRESSED(已解决)| NOT ADDRESSED(未解决),
|
||||
附 file:line 证据。"尝试过了"不算已解决:那个具体缺陷必须已经不存在。
|
||||
|
||||
### 修复 diff 里的新破坏
|
||||
|
||||
修复本身破坏或引入的任何东西,附严重度(Critical/Important/Minor)
|
||||
和 file:line。干净就写"无"。
|
||||
|
||||
### 范围外的观察
|
||||
|
||||
你注意到的、完全位于修复 diff 之外的问题。不阻塞;控制者会把这些
|
||||
记进账本留给最终审查。没有就写"无"。
|
||||
|
||||
### 结论
|
||||
|
||||
**本轮修复:** [所有发现均已解决,无新的 Critical/Important 破坏 |
|
||||
仍有发现未解决] —— 把未解决的那些列出来。
|
||||
```
|
||||
|
||||
**占位符:**
|
||||
- `[MODEL]` —— 必填:审查者模型,按 SKILL.md 的"模型选择"来选;小修复 diff
|
||||
的定向复审用便宜到中档的层级即可
|
||||
- `[BRIEF_FILE]` —— 任务简报文件(与实现者所依据的是同一个文件)
|
||||
- `[FINDINGS]` —— 上一次审查里的 Critical/Important 发现和规格差距,
|
||||
逐字抄下来,每条一个 bullet
|
||||
- `[REPORT_FILE]` —— 实现者的报告文件(修复报告追加在其末尾)
|
||||
- `[FIX_BASE_SHA]` —— 上一次审查所看到的那个 head
|
||||
- `[HEAD_SHA]` —— 当前提交
|
||||
- `[DIFF_FILE]` —— `scripts/review-package PLAN_FILE FIX_BASE HEAD` 打印出的那个路径
|
||||
|
||||
**复审者返回:** 逐条发现的结论(ADDRESSED / NOT ADDRESSED)、
|
||||
修复 diff 里的新破坏、范围外的观察,以及一个本轮结论。
|
||||
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
# Generate a review package: commit list, stat summary, and the net
|
||||
# diff with extended context, written to a file the reviewer reads in one
|
||||
# call. Using the recorded per-task BASE (not HEAD~1) keeps multi-commit
|
||||
# tasks intact.
|
||||
#
|
||||
# Usage: review-package PLAN_FILE BASE HEAD [OUTFILE]
|
||||
# Default OUTFILE: <repo-root>/.superpowers/sdd/<plan-basename>/review-<base7>..<head7>.diff
|
||||
# (named per range, so a re-review after fixes gets a distinct fresh file).
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -lt 3 ] || [ $# -gt 4 ]; then
|
||||
echo "usage: review-package PLAN_FILE BASE HEAD [OUTFILE]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
plan=$1
|
||||
base=$2
|
||||
head=$3
|
||||
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
||||
|
||||
git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
|
||||
git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; }
|
||||
|
||||
if [ $# -eq 4 ]; then
|
||||
out=$4
|
||||
else
|
||||
dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
|
||||
out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff"
|
||||
fi
|
||||
|
||||
{
|
||||
echo "# Review package: ${base}..${head}"
|
||||
echo
|
||||
echo "## Commits"
|
||||
git log --oneline "${base}..${head}"
|
||||
echo
|
||||
echo "## Files changed"
|
||||
git diff --stat "${base}..${head}"
|
||||
echo
|
||||
echo "## Diff"
|
||||
git diff -U10 "${base}..${head}"
|
||||
} > "$out"
|
||||
|
||||
commits=$(git rev-list --count "${base}..${head}")
|
||||
echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes"
|
||||
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# Resolve and ensure the working-tree directory SDD uses for one plan's
|
||||
# short-lived artifacts: task briefs, implementer reports, review packages,
|
||||
# and the progress ledger. Print the plan directory's absolute path.
|
||||
#
|
||||
# One directory per plan (.superpowers/sdd/<plan-basename>/) so a follow-up
|
||||
# plan in the same working tree can never read or overwrite another plan's
|
||||
# artifacts. A stale ledger misread as current progress makes controllers
|
||||
# skip whole task sequences — plan-scoping removes that failure structurally.
|
||||
#
|
||||
# The workspace lives in the working tree (not under .git/) because Claude Code
|
||||
# treats .git/ as a protected path and denies agent writes there — which blocks
|
||||
# an implementer subagent from writing its report file. A self-ignoring
|
||||
# .gitignore at .superpowers/sdd/ keeps every plan's workspace out of
|
||||
# `git status` and out of accidental commits without modifying any tracked file.
|
||||
#
|
||||
# Single source of truth for the workspace location, so task-brief and
|
||||
# review-package cannot drift to different directories.
|
||||
#
|
||||
# Usage: sdd-workspace PLAN_FILE
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "usage: sdd-workspace PLAN_FILE" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
plan=$1
|
||||
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
||||
|
||||
slug=$(basename "$plan" .md)
|
||||
[ -n "$slug" ] && [ "$slug" != "." ] && [ "$slug" != ".." ] \
|
||||
|| { echo "cannot derive a workspace name from: $plan" >&2; exit 2; }
|
||||
|
||||
root=$(git rev-parse --show-toplevel)
|
||||
base="$root/.superpowers/sdd"
|
||||
dir="$base/$slug"
|
||||
mkdir -p "$dir"
|
||||
printf '*\n' > "$base/.gitignore"
|
||||
cd "$dir" && pwd
|
||||
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# Extract one task's full text from an implementation plan into a file the
|
||||
# implementer reads in one call, so the task text never has to be pasted
|
||||
# through the controller's context.
|
||||
#
|
||||
# Usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]
|
||||
# Default OUTFILE: <repo-root>/.superpowers/sdd/<plan-basename>/task-<N>-brief.md
|
||||
# (per plan and per worktree; concurrent runs of the SAME plan in the same
|
||||
# working tree share it).
|
||||
#
|
||||
# 中文 fork 适配:上游只识别英文任务标题 "## Task N",而 superpowers-zh
|
||||
# 的 writing-plans 产出的是 "### 任务 N:..."。下方 awk 同时匹配
|
||||
# "Task" 与 "任务",两种计划都能抽取。
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -lt 2 ] || [ $# -gt 3 ]; then
|
||||
echo "usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
plan=$1
|
||||
n=$2
|
||||
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
||||
|
||||
if [ $# -eq 3 ]; then
|
||||
out=$3
|
||||
else
|
||||
dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
|
||||
out="$dir/task-${n}-brief.md"
|
||||
fi
|
||||
|
||||
awk -v n="$n" '
|
||||
/^```/ { infence = !infence }
|
||||
!infence && /^#+[ \t]+(Task|任务)[ \t]*[0-9]+/ {
|
||||
intask = ($0 ~ ("^#+[ \t]+(Task|任务)[ \t]*" n "([^0-9]|$)"))
|
||||
}
|
||||
intask { print }
|
||||
' "$plan" > "$out"
|
||||
|
||||
if [ ! -s "$out" ]; then
|
||||
echo "task ${n} not found in ${plan} (no heading matching 'Task ${n}' / '任务 ${n}')" >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
echo "wrote ${out}: $(wc -l < "$out" | tr -d ' ') lines"
|
||||
@ -0,0 +1,184 @@
|
||||
# 任务审查者提示词模板
|
||||
|
||||
分派任务审查子智能体时使用此模板。审查者一次性读取该任务的 diff,
|
||||
返回两个结论:规格合规性和代码质量。
|
||||
|
||||
**目的:** 核实一个任务的实现与其需求匹配(不多不少)且构建良好(整洁、有测试、可维护)
|
||||
|
||||
```
|
||||
Subagent (general-purpose):
|
||||
description: "审查任务 N(规格 + 质量)"
|
||||
model: [模型 —— 必填:按 SKILL.md 的"模型选择"来选;省略模型会默默
|
||||
继承会话里最贵的那个]
|
||||
prompt: |
|
||||
你正在审查一个任务的实现:先看它是否与需求匹配,再看它是否
|
||||
构建良好。这是一个任务范围内的关卡,不是合并审查——覆盖整个
|
||||
分支的宽范围审查会在所有任务完成后另行进行。
|
||||
|
||||
## 要求的内容
|
||||
|
||||
读取任务简报:[BRIEF_FILE]
|
||||
|
||||
来自规格/设计、约束本任务的全局约束:
|
||||
[GLOBAL_CONSTRAINTS]
|
||||
|
||||
## 实现者声称构建了什么
|
||||
|
||||
读取实现者的报告:[REPORT_FILE]
|
||||
|
||||
## 待审查的 Diff
|
||||
|
||||
**Base:** [BASE_SHA]
|
||||
**Head:** [HEAD_SHA]
|
||||
**Diff 文件:** [DIFF_FILE]
|
||||
|
||||
一次性读取这个 diff 文件——它包含提交列表、stat 摘要,以及
|
||||
带上下文的完整 diff,它就是你对本次改动的视图。diff 的上下文行
|
||||
**就是**那些被改动的文件:不要单独去 Read 某个被改动的文件,除非
|
||||
你必须判断的某个 hunk 在函数中途被截断——并在报告中说明这一点。
|
||||
不要重跑 git 命令。如果 diff 文件缺失,就自己取 diff:
|
||||
`git diff --stat [BASE_SHA]..[HEAD_SHA]` 和 `git diff [BASE_SHA]..[HEAD_SHA]`。
|
||||
不要爬取更广的代码库。只有为了评估一个你能点名的具体风险,才去
|
||||
查看 diff 之外的代码——每个点名的风险做一次聚焦检查,并在报告中
|
||||
同时点名这个风险和你检查了什么。横切改动是正当的、可点名的风险:
|
||||
如果 diff 改动了锁顺序、某个函数或 API 契约、或共享的可变状态,
|
||||
检查其调用点就是正确的方法。
|
||||
|
||||
你的审查在这个 checkout 上是只读的。不要以任何方式改动工作树、
|
||||
索引、HEAD 或分支状态。
|
||||
|
||||
## 你不派发子智能体
|
||||
|
||||
这次审查全部由你自己做。绝不派一个子智能体去审查 diff 的一部分,
|
||||
也绝不为了第二意见再派一个审查者。这套流程已经提供了这份工作
|
||||
应得的每一个审查席位;你派出的审查者只是按全价重复其中之一,
|
||||
而且它的裁定不算数。如果这份 diff 大到一遍看不完,就自己分几遍
|
||||
看,并在报告里说明。
|
||||
|
||||
## 不要信任报告
|
||||
|
||||
把实现者的报告当作关于代码的、未经核实的说法。它可能不完整、
|
||||
不准确或过于乐观。对照 diff 去核实这些说法。报告里的设计理由
|
||||
同样是说法:"出于 YAGNI 留着没做""特意保持简单"或任何其他辩解,
|
||||
都是实现者在给自己的工作打分。就代码本身评判它的优劣——一句
|
||||
陈述出来的理由永远不会降低一个发现的严重度。
|
||||
|
||||
你看不见的证据,不等于不存在的证据。如果报告或它的测试证据看起来
|
||||
被截断了,或者你找不到它声称的结果,就按它给出的路径把文件重新读
|
||||
一遍——如果确实缺失或损坏了,把这件事作为一个缺口报告给控制者。
|
||||
为了重新生成你没读到的东西而重跑测试套件,不是核实;证据不可读,
|
||||
不等于证据不成立。
|
||||
|
||||
## 测试
|
||||
|
||||
实现者已经跑过测试,并为正是这份代码报告了带 TDD 证据的结果。
|
||||
不要为了确认他们的报告而重跑测试套件。只有当阅读代码引出一个
|
||||
现有任何运行都无法回答的具体疑问时,才去跑测试——而且是聚焦
|
||||
测试,绝不是包级套件、竞态检测运行、或反复的/高次数的循环。
|
||||
如果看起来确实需要重度验证,就在报告里建议它,而不是自己去跑。
|
||||
如果你在这个环境里无法运行命令,就点名你会跑的那个测试。
|
||||
|
||||
实现者报告的测试输出里的告警或其他噪声都是发现——测试输出
|
||||
应当是干净的。
|
||||
|
||||
## 第一部分:规格合规性
|
||||
|
||||
把 diff 对照"要求的内容"来看:
|
||||
|
||||
- **缺失:** 他们跳过、遗漏、或声称却未实现的需求
|
||||
- **多余:** 未被要求的功能、过度工程、不需要的"锦上添花"
|
||||
- **理解偏差:** 正确的功能却用错了方式来构建,解决了错误的问题
|
||||
|
||||
如果某个需求无法仅从这份 diff 中核实(它藏在未改动的代码里、
|
||||
或横跨多个任务),就把它作为一个 ⚠️ 事项报告出来,而不是
|
||||
扩大你的搜索范围。
|
||||
|
||||
如果简报列了好几个文件、每个都有自己的改动(一次打包分派),
|
||||
就拿这份清单逐个文件去对 diff:清单上的每个文件都必须有它对应
|
||||
的 hunk。清单上有、diff 却从没碰过的文件,是一条"缺失"发现,
|
||||
无论这一批里其余部分看起来多干净。
|
||||
|
||||
## 第二部分:代码质量
|
||||
|
||||
**代码质量:**
|
||||
- 关注点分离是否干净?
|
||||
- 错误处理是否恰当?
|
||||
- 是否做到 DRY 而没有过早抽象?
|
||||
- 边界情况是否处理了?
|
||||
|
||||
**测试:**
|
||||
- 新增和改动的测试是否验证了真实行为,而非 mock?
|
||||
- 本任务的边界情况是否被覆盖?
|
||||
|
||||
**结构:**
|
||||
- 每个文件是否有单一明确的职责和定义清晰的接口?
|
||||
- 各单元是否拆分得足以独立理解和测试?
|
||||
- 实现是否遵循了计划中的文件结构?
|
||||
- 本次改动是否创建了已经很大的新文件,或显著增大了现有文件?
|
||||
(不要标记已有的文件大小问题——聚焦于本次改动带来的贡献。)
|
||||
|
||||
你的报告应指向证据:每一个发现、以及任何你本来会用一句干巴巴的
|
||||
"是"来回答的检查,都要给出 file:line 引用。一份引用了行号的
|
||||
紧凑报告,就把控制者需要的一切都给它了。
|
||||
|
||||
你的最终消息就是报告本身:直接从规格合规性结论开始。每一行
|
||||
要么是一个结论、要么是一个带 file:line 的发现、要么是你跑过的
|
||||
一个检查——没有开场白、没有流程叙述、没有结尾小结。
|
||||
|
||||
## 校准
|
||||
|
||||
按实际严重度给问题分类。不是所有东西都是 关键。
|
||||
重要 意味着这个任务在修好之前不可信:不正确或脆弱的行为、
|
||||
一个漏掉的需求、或你会为之拦下合并的可维护性损害——逻辑块的
|
||||
逐字重复、被吞掉的错误、什么都不断言的测试。"覆盖面可以更广"
|
||||
和打磨类建议是 次要。
|
||||
如果计划或简报明确强制了某个本评分标准称之为缺陷的东西(一个
|
||||
什么都不断言的测试、逻辑块的逐字重复),那**就是**一个发现——
|
||||
把它报告为 重要,并标注为"计划强制"。计划的作者身份不能给它
|
||||
自己的工作打分;由人类来决定。
|
||||
在列出问题之前,先承认做得好的地方——准确的赞扬能帮实现者
|
||||
信任其余的反馈。
|
||||
|
||||
## 输出格式
|
||||
|
||||
### 规格合规性
|
||||
|
||||
- ✅ 符合规格 | ❌ 发现问题:[缺失/多余/理解偏差的内容,
|
||||
附带 file:line 引用]
|
||||
- ⚠️ 无法从 diff 中核实:[你无法仅凭 diff 核实的需求,以及
|
||||
控制者应当检查什么——与你能核实的一切的 ✅/❌ 结论一起报告]
|
||||
|
||||
### 优点
|
||||
[哪些做得好?要具体。]
|
||||
|
||||
### 问题
|
||||
|
||||
#### 关键(必须修复)
|
||||
#### 重要(应当修复)
|
||||
#### 次要(锦上添花)
|
||||
|
||||
每个问题:file:line、哪里错了、为什么重要、如何修复(如果不明显)。
|
||||
|
||||
### 评估
|
||||
|
||||
**任务质量:** [通过 | 需要修复]
|
||||
|
||||
**理由:** [1-2 句技术性评估]
|
||||
```
|
||||
|
||||
**占位符:**
|
||||
- `[模型]` —— 必填:按 SKILL.md 的"模型选择"选审查者模型
|
||||
- `[BRIEF_FILE]` —— 必填:任务简报文件(`scripts/task-brief PLAN N`
|
||||
会打印路径;与实现者所用的是同一个文件)
|
||||
- `[GLOBAL_CONSTRAINTS]` —— 从计划的"全局约束"一节或规格里逐字抄下的、
|
||||
有约束力的需求:精确的取值、格式、以及组件之间被明确规定的关系
|
||||
(不是流程规则——那些已经在本模板里了)
|
||||
- `[REPORT_FILE]` —— 必填:实现者写入其详细报告的那个文件
|
||||
- `[BASE_SHA]` —— 本任务之前的提交
|
||||
- `[HEAD_SHA]` —— 当前提交
|
||||
- `[DIFF_FILE]` —— 必填:控制者写入审查包的那个路径
|
||||
(`scripts/review-package PLAN_FILE BASE HEAD` 会打印它写入的唯一路径;
|
||||
审查包永远不会进入控制者的上下文)
|
||||
|
||||
**审查者返回:** 规格合规性结论(✅/❌/⚠️)、优点、问题
|
||||
(关键/重要/次要)、任务质量结论
|
||||
Reference in New Issue
Block a user