Agent 方法论框架 superpowers 如何用自己的流程开发自己

2026-07-29

本文基于 superpowers 仓库 commit 44c9b2d(2026-07-27)梳理,该项目仍在持续迭代,具体行为以仓库 https://github.com/obra/superpowers 最新代码与文档为准。

判断一套 Agent 开发方法论值不值得抄,最快的路径不是读它的技能文档,而是读它自己用这套流程改自己时留下的评测记录——尤其是那份写着「原本假设的失败没有复现」的结果文档。 superpowers 仓库里就有这么一份。它的作者提出一个假设、设计了修复、跑了三轮基线压力测试,然后在文档里白纸黑字写下:25 次重放里,被测的控制器一次都没犯作者假设它会犯的错。改动最后还是发布了,但发布理由被改写了,并且改写过程留在了仓库里。

对于天天在读别人 Agent 框架源码的人来说,这份档案的价值高于任何一份 README。

一、这个仓库到底留了些什么

superpowers 是一套给编码 Agent 用的技能集合,MIT 许可证,版权归 Jesse Vincent。仓库根目录下 skills/ 里放着 14 个技能目录,每个技能一份 SKILL.md,覆盖头脑风暴、写计划、TDD、系统化调试、代码评审、Git worktree 隔离、写技能本身等环节。README 里对整条链路的描述是:Agent 看到你要建东西时先退一步问你到底想干什么,把规格从对话里逼出来,分段给你过目;你签字之后它写实施计划;你说「go」它才启动 subagent 驱动的实现流程。

关键在于,这条链路产出的中间物不是丢掉的草稿,而是提交进仓库的文档。docs/superpowers/specs/ 下有 17 份设计规格,docs/superpowers/plans/ 下有 13 份实施计划。下面这张表按文件对应关系整理,仓库位置都是实际存在的路径:

组成部分它负责什么对应仓库位置你什么时候会碰到它
技能正文一个流程的完整指令,Agent 在会话里直接加载skills/<技能名>/SKILL.md想知道某条约束具体怎么措辞
设计规格一次改动的问题陈述、设计、明确排除项、测试计划docs/superpowers/specs/2026-07-06-sdd-plan-scoped-workspace.md想搞清楚某个约束为什么存在
实施计划Global Constraints 全局约束块 + 分任务 + 每任务的 Interfaces 契约docs/superpowers/plans/2026-07-06-sdd-plan-scoped-workspace.md想看任务是按什么粒度切的
评测结果每个实验格子的通过数、逐条行为记录、成本对比表docs/superpowers/specs/2026-07-06-sdd-plan-scoped-workspace-eval-results.md想验证「这个改动真的有用吗」
工作区脚本解析工作区目录、生成任务简报、生成评审 diff 包skills/subagent-driven-development/scripts/ 下的 sdd-workspacetask-briefreview-package实际跑 SDD 流程时
确定性 shell 测试脚本行为的回归保护tests/claude-code/test-sdd-workspace.sh改动脚本时
发布说明每个版本改了什么、以及为什么改RELEASE-NOTES.md升级前

站内已有两篇讲通用方法论的文章:规格驱动开发 SDD 的完整流程 讲的是「规格—计划—实现」这条链路本身该怎么走,Agent 评测集怎么构建 讲的是评测集的设计原则。本篇不重复这两件事,它讲的是一个具体开源项目怎么把这两套东西真的落在文件里、以及落下去之后暴露出了什么。

二、被修的那个问题:进度台账没有身份

要看懂那份评测结果,得先知道它在验证什么。

subagent 驱动开发(SDD)技能的运行方式是:控制器读实施计划,每个任务派一个全新的 implementer subagent 去实现,实现完派评审 subagent 看 diff,通过了记一笔,进下一个任务。这个过程可能跑几个小时。问题是控制器的会话上下文会被压缩,压缩之后它不记得自己干到哪了。

早先版本给出的方案是把进度写进磁盘台账。当时的工作区是全仓库共用的一个 .superpowers/sdd/,台账是 .superpowers/sdd/progress.md,任务简报是 task-N-brief.md,实现报告是 task-N-report.md。这个目录靠一份内容为 *.gitignore 自我屏蔽,不进 git status

设计规格里对这个方案的问题诊断只有一句话,但很准:身份不在数据里,正确性依赖一个没有触发条件的清理动作。

所有文件都只按任务编号命名,没有任何一处标明「这是哪个计划的进度」。同一个工作树里跑第二个计划时,新的控制器会读到上一个计划的台账,而技能文本当时的原话是「台账里标为完成的任务就是完成了,不要重新派发」。而且没有任何东西会删除这个工作区,陈旧状态无限期堆积。

规格里记录的现实后果来自另一个叫 serf 的仓库,时间跨度 2026-06-22 到 2026-07-05:一个工作树里堆了三个计划共 68 个文件;P2 的控制器为了躲开 P1 的台账,自己发明了 progress-p2.mdp2-task-N-report.md 这样的旁路命名;P2 的任务简报在默认路径上静默覆盖了 P1 的。更麻烦的是三次 Git 污染,规格里点名了收拾残局用掉的那两个清理提交,至今仍有三个产物被跟踪在 serf 的 main 分支上,其中一份是在另一台机器上写的报告,现在每开一个新工作树它都会跟着出现。自我屏蔽的 .gitignore 只在脚本运行时才写入,而手工追加台账的控制器根本不会触发脚本;何况文件一旦被跟踪,gitignore 就管不着了。

修复方案是把身份做成结构性的:工作区变成 .superpowers/sdd/<plan-slug>/,slug 就是计划文件去掉 .md 后缀的 basename。脚本里这段是真实的实现:

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

配套还有两条:台账创建时第一行必须是 # SDD ledger — plan: <计划文件路径>,给那些绕过脚本手写台账的控制器留一道可观察的识别线;以及最终整分支评审干净之后,控制器删掉自己这个计划的工作区目录,兄弟目录一律不碰——崩溃的或并行的计划各自拥有自己的目录。

规格里明确写了不做兼容路径:脚本和技能文本同一个插件版本一起发布,没有旧布局的回退读取。这一点在工程上值得学——身份类的迁移最怕的就是「两种布局同时有效」。

三、评测里最值钱的那一段:假设没复现

按照 superpowers 自己的技能写法要求(skills/writing-skills/testing-skills-with-subagents.md 里把技能测试直接映射成 TDD 的 RED-GREEN-REFACTOR),改技能文本之前必须先看到 Agent 在没有这段文本时真的失败。于是他们跑了 RED 基线:用临时目录里的 fixture 仓库模拟「计划 A 已完成、控制器正在恢复后续计划 B」的场景,每格 5 个全新的 sonnet subagent,每份回复人工读完打分。

结果是:25 次重放,25 次都拒绝把台账当作跳过工作的许可。

三种框架都试过了,包括最贴近真实崩溃恢复的那一种——会话上下文写成「本会话由压缩后的对话继续」,并且技能里那句「压缩之后,相信台账和 git log,不要相信你自己的记忆」是生效的。控制器们照样把台账引用的提交拿去和 git log 对照,发现对不上自己的计划,然后从 Task 1 老老实实开始。评测文档里保留了原话,比如其中一次重放写道:这些提交「匹配的是 docs/plans/2026-07-01-widget-backend.md,一个不同的、已经完成的计划——不是我的」。

fixture 还翻修了两次才站得住。v1 的台账引用了编造的哈希,Agent 一眼就用 git cat-file 判定不可信;v2 换成真实可解析的哈希,Agent 转而去读提交内容,发现里面是桩实现,判定「review clean」这条记录是假的。两轮里那个用来验证 fixture 本身的对照组(合法的同计划恢复)都是 5/5 失败——也就是说,前两版 fixture 根本没资格用来下结论。v3 才做到每条台账声明在内容审查下都为真:真实实现、轮换的作者、分散的时间戳。

还有一个诚实到有点可爱的细节:v3 的生成器最初有个 bug,提交计数器 ci$(commit_file ...) 的命令替换子 shell 里自增,增量传不回来,所有提交塌缩成同一个作者同一个时间戳——恰好是让 v2 对照组失效的那个「人造历史」特征。计划自己的第 1 步健全性门禁(每个引用哈希都能解析,且至少两个作者跨两个日期)在任何场景重放开始前就把它拦住了,附录 A 里写明了这处与计划文本的差异。

那么改动为什么还是发布了?评测文档的措辞是:可复现的基线危害不是一个错误率,而是两样东西。

第一,每次恢复都要交一笔取证税。最接近真实恢复场景的那一轮里,每个重放都得先花真实的工具调用去证明某份台账不是自己的,然后才能干正事:7、13、9、10、6 次,均值 9.0。第二,就是上一节那份 serf 仓库的结构性记录——碰撞、旁路命名、被覆盖的简报、Git 污染,这些都实际发生过。

最后一段更值得抄的是成本对比表怎么写。GREEN 组的工具调用均值是 9.6,比基线的 9.0 还高。文档没有藏这个数,而是直接写「诚实地读这张表:原始调用次数并没有下降」,然后解释两处差异:GREEN 的 fixture 里陈旧材料严格更多(三处台账位置对比一处),以及——这才是实质变化——调用花在了不同的事情上。基线组是靠跨计划的提交内容取证来判断台账归属,GREEN 组是靠结构判断(解析自己计划的工作区、看第一行身份),剩下的调用花在确认自己的计划确实没有前置工作,这件事任何一个全新开始的控制器都会做。5 个 GREEN 重放里没有一个去拉取被引用提交的 diff 来做内容比对——那正是基线轮次的标志性动作。

它最后给自己划的边界是:「结构性结论——没有任何 GREEN 重放需要靠内容取证来消歧,且每份台账都写明自己的计划之后归属错认已不可能——才是承重的结果,调用次数的下降不是这个场景所能证明的。」同期还保留了回归安全的证明:合法的同计划恢复在两组里都是 5/5 认出前两个任务已完成并派发第 3 个任务。

这份文档给评测写作立的标准,比它验证的那个功能本身更有迁移价值。评测文档自己也说了,可重跑的测试用例应该沉淀成常设资产,而这一轮还只是一次性的。

四、边界与代价

这套东西不是没有账要还,仓库自己也承认了一部分。

流程本身就是慢的。 一个任务要经过派发实现者、生成评审包、派发评审者、修复轮次、范围收窄的复审这一整圈。修复轮次上限是五轮,触顶之后由控制器裁决。对于改一行常量、调一个文案这种事,这套流程是彻底的过度设计——它的收益需要任务大到「值得自己一个测试周期和一次评审」才能兑现,实施计划的写法指南里对任务粒度的要求也正是这个意思。

它会让 Agent 更啰嗦、也更贵。 技能文本本身就要占上下文;SDD 技能里专门有一句提醒,说你粘进派发提示里的一切、subagent 打印回来的一切,都会在这个会话剩下的时间里常驻你的上下文并被反复重读,所以产物要用文件交接而不是粘贴。这条约束本身就是被成本逼出来的。同样出于成本,技能里有整节讲模型选择,要求每次派发都显式指定模型——因为不写模型会静默继承会话里最贵的那个。

明确不管的事。 那份规格的「Out of scope」写得很干脆:不改 finishing-a-development-branch 或任何其他技能;除了那份父级 .gitignore 之外不加任何 Git 层面的防提交守卫;不回头清理 serf 仓库里已经被跟踪的产物;不做旧布局迁移或回退读取。

已知会失灵的地方。 工作区是 git 忽略的工作树临时文件,git clean -fdx 会直接删掉台账,技能里只能告诉你从 git log 恢复。不同目录下同名的计划文件会解析到同一个工作区——规格把这条列为「接受」,理由是计划文件名按约定带日期前缀,同 basename 在实践中就是同一个计划。还有一条自己承认的局限:每格 5 次重放是烟雾强度的信号,不是统计强度的;场景测的只是恢复决策,不是完整执行;工具调用次数是个粗糙的成本代理,它数的是调用,不是 token,也不是风险。

它不替你解决的问题。 这套流程管的是「Agent 按什么顺序干活、干完谁来查」,不管你的任务本身拆得对不对,也不管模型的能力边界。工作区隔离和上下文预算是另外两件事,可以分别看 Agent 工作区隔离怎么做Agent 上下文预算怎么分配

五、上手与避坑清单

如果你打算把这套做法搬进自己的项目,下面几条是从这批文件里能直接提炼出来的。

别把台账当权威,先给它身份。 会踩是因为台账的天然形态就是「任务号 + 状态」,看起来自洽,你不会想到它需要说明自己属于谁。避法是让存储路径本身携带身份(一个计划一个目录),再在文件第一行冗余一次,给绕过脚本的路径留识别线。只靠结束时清理是靠不住的——规格里那句话说得很直白:任何依赖计划结束时清理的方案,恰好会在台账本来要救的那类崩溃场景里失效。

先跑基线,别跳过 RED。 会踩是因为你已经想好修复方案了,跑基线感觉是纯浪费。这个项目跑了,然后发现自己假设的失败根本不存在,于是把发布理由从「防止错误」改成了「消除取证成本 + 结构性事故记录」。避法是把基线当成写发布说明的素材来跑:它要么证明你的假设,要么帮你把话说对。

fixture 说谎会毁掉整轮实验。 会踩是因为造数据时你只关心「格式对不对」,不关心「一个会做取证的 Agent 信不信」。这个项目连烧两版才明白:引用的哈希必须真能解析,被引用的提交内容必须真的满足对应任务的规格,作者和时间戳必须有分布,两个计划的任务数量要一致否则数量差本身就是提示。做法是给 fixture 生成器加一道健全性门禁,先自检再跑场景——他们那个子 shell 计数器 bug 就是这么拦下来的。

成本指标要说清楚它没证明什么。 会踩是因为拿到一个比对照差的数字时,最省事的做法是不提。这份文档反过来把 9.6 对 9.0 摆在标题下,说明两组 fixture 的陈旧材料量本来就不同,再指出承重的是机制变化而不是次数变化。你自己的评测里如果只有一个能动的旋钮,务必写清楚这个旋钮量的是什么。

结构性迁移不要留双布局。 会踩是因为「兼容一下更安全」是本能。这次是脚本和技能文本同版本一起发,明确不做旧布局回退读取,只在技能里留了一句「旧扁平路径上的散落台账属于别的计划,原地留着」。双布局同时有效的代价是每个读取点都要判断,判断点越多越容易漏。

给临时目录定规矩。 实施计划的全局约束里写死了:评测 fixture 和场景工作目录一律建在 mktemp -d 下,绝不提交、绝不建在仓库检出目录内部,事后也不删除,只记录路径。会踩是因为造数据时顺手就建在了项目里,回头污染检出目录。

收束

把这份档案当成一次可以复查的实验记录来读,比当成教程读收获大得多。真正稀缺的不是「我们用了规格驱动开发」这句话,而是「我们提出的假设被自己的实验推翻了,这是修改后的理由,这是我们没有证明的东西」这三句话同时写在同一份提交进仓库的文件里。

想自己按图索骥,建议的阅读顺序是:先在 RELEASE-NOTES.md 里找到「工作区改为按计划划分」那条,知道这次改了什么;再读 docs/superpowers/specs/2026-07-06-sdd-plan-scoped-workspace.md 的 Problem 和 Root cause 两段,那是全篇最凝练的地方;然后跳到同目录下的 eval-results,重点读「What RED showed (and did not show)」和「Disambiguation cost」两节;最后回到 skills/subagent-driven-development/SKILL.md 的 Setup 一节,看这些结论最终变成了什么样的四五行文字。

自检清单也简单:你的 Agent 流程里,有没有一个产物是靠「大家都知道它属于谁」而不是靠路径或内容来标识的?有没有一份评测结果,敢把不利数字连同解释一起写进去?如果两条都没有,那这份仓库最值得抄的就不是它的目录结构,而是这两个习惯。恢复现场时该信什么,可以再看一篇 Agent 记忆污染与遗忘机制

本文属于 superpowers 方法论专题(共 30 篇,含三篇与其它开源 Agent 项目的对照)。想看把资产铺满的另一种取向,见 ECC 开源 Agent 套件专题

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。