三周之后:OpenSpec + Superpowers 的五个问题和一个 Plugin

34 阅读19分钟

我在三周前发表了OpenSpec × Superpowers:3 小时跑完一次 SDD 实战。文章里有个具体的数字:重构在三小时内完成,86 个新测试,零回归。当时,这套组合,OpenSpec 的 propose/apply/archive 三步(框架还有 explore,但我一直在跳过它)加上我最常用的三个 Superpowers skill(brainstorming、test-driven-development、requesting-code-review),是我在 AI 参与的开发场景里找到的最好纪律。

我没说的,是因为当时还不知道,这套组合有五个隐藏的问题。它们在一次重构上没有显现,在第三次、第四次、第五次把它用在新项目上时才出来。那时候这套工作流已经是长期使用的东西,不是打完一次冲刺那么简单。

这篇文章是它的进化。如果今天要重写那篇文章,这是我会补进去的内容,在 python-agent 项目上又跑了几轮之后,我在那里有意识地让每一个问题自己说话,然后再设计修法。

前半部分列出五个问题(旧版的不足);后半部分讲我怎么处理,方法论层面的三步进化,加上命令级别的四个修法。然后展示最终形成的四命令、四阶段框架,解释为什么它仍然是你认识的那种敏捷开发,以及我打包出来的 plugin,让你不用重读这两篇文章也能跑完整个流程。

如果你没读过上一篇,原文入口在这里。本文默认你了解 OpenSpec 的四个基础命令(explore/propose/apply/archive)和我刚提到的三个 Superpowers skill。

先说一件事。没什么惊天动地的发明,都是水到渠成的改进。每一个修法都来自一个具体的时刻,旧版产出了我不信任的东西。规律是:实践,暴露问题,修正,固化。方法论是跑出来的,不是设计出来的。文末的 plugin 是副产品,不是目标。


五个问题

问题一:brainstorm 的 UI 设计在 propose 时消失了

Superpowers 的 brainstorming skill 有一个 visual-companion 流程,会打开浏览器预览,让你迭代 mockup。这是这个 skill 最好的部分之一,对于 UI 密集型功能,你在写任何代码之前就真的看到了设计。

问题出在下一步。你带着一个很好的 UI 设计完成了 brainstorming。你把控制权交给 OpenSpec 的 propose。然后 propose 产出了一个完全不引用 mockup 的计划。

为什么?因为 brainstorming 输出和 propose 输入之间的链接,就是你记得放进 prompt 里的东西。UI 设计存在于 brainstorming session 的对话记忆里。等你开始输入 propose 命令,是一个新的 context。除非你明确地把 mockup 再粘一次,而大多数人不会,因为 mockup 不是文件,设计就消失了。

我在 python-agent 的第三个功能上注意到了这一点。我在 visual-companion 里花了二十分钟确定了一个特定的 dashboard 布局。然后我运行了 propose。产出的 spec.md 描述了一个跟我刚才设计的布局毫无关系的通用表格视图。两分钟的"等等,这不是我们商量好的"之后,我在手动重申本来应该被带过去的约束。

这个模式是:对话里的设计很容易丢失,下一个 session 看不见它,除非它是一个文件。

问题二:brainstorm 不理解代码库

Superpowers 的 brainstorming 是基于文字工作的,你的描述、对话,以及你明确附上的文档。它不读你的代码。

结果是,brainstorm 可以产出一个技术上合理但操作上是错的设计。它可以提出一个新的 BaseAgent 类,而你的项目里已经有一个。它可以建议一套数据库 schema,忽视你两个月来一直在扛的迁移约束。它可以推荐一个第三方库,而它和你现有的依赖树冲突。

有些问题会在 propose 阶段被捉到,因为 OpenSpec 的 propose 会读代码库。但那时候你改的设计比应该改的要多。约束进入得越早越好。

修法事后看来很显然:OpenSpec 有一个 explore 步骤,它会读代码。正确的顺序不是 brainstorm → propose,而是 explore → brainstorm → propose。先 explore,把 brainstorm 锚定在代码库的真实情况里,然后再设计。

这个模式是:只基于文字的设计会偏离基于代码的现实。

问题三:skill 调用靠的是记忆,不是机制

这是代价最高的问题,因为它藏在一个运行正常的命令后面。当我运行 /opsx:apply 时,我的意图是:用 Superpowers 的 test-driven-development skill 执行每个任务,然后对结果调用 requesting-code-review。这个顺序才能让 apply 正确地闭环,TDD 负责行为正确性,结对 review 负责检查 spec 偏移。

问题是:没有任何东西强制这个顺序。apply 是一个命令;Superpowers skill 是 skill。它们只有在我的 prompt 里点名的时候才会进入 session。如果我忘了写"用 tdd skill"和"然后跑 code review",而我经常忘,因为这个顺序在我脑子里感觉太理所当然,apply 就在没有 TDD 纪律、没有结对 review 的情况下跑完了,产出的代码看起来没问题,但跳过了两道安全网。

更深的模式在工件跨工具传递的地方随处可见:brainstorm 到 propose 之间,propose 到 apply 之间,apply 到 archive 之间。自然语言是链接的媒介。你说"用之前的设计",AI 尽力而为。如果你的 prompt 提到了 spec 但没指定哪些 section 重要,AI 自己挑它认为要遵守的 section。如果一个约束在 brainstorm 里出现了,但没有进入 propose 的 prompt,这个约束就没了。

在一次性的项目里,你把代价吸收为改稿周期。在你想反复使用的方法论里,这种损耗会累积。每一步都让信号降级一点,等 apply 跑起来,你已经距离原始意图有三次有损传递的距离。

这个模式是:靠 prompt 传递信息跑一个项目没问题,反复使用代价就很大,而且代价往往藏在"看起来没问题的代码"里,不会主动暴露。

问题四:apply 没有 UI 验证

TDD 在这套组合里处理得很好。Superpowers 有 test-driven-development skill,OpenSpec 的 apply 跑你的测试套件。对于后端行为,这个闭环关得不错,红灯,绿灯,重构,提交。

它关不上的是视觉正确性。如果 brainstorm 产出了一个 UI 设计,spec 描述了布局约束,apply 写了前端代码,没有自动检查来确认上线的东西长得像设计的东西。你读测试输出,看到绿灯,假设做完了。然后你真的打开页面,间距不对,按钮在错的角落,或者表格列不对。

让人沮丧的是,这是可以解决的,视觉差异工具存在,无头截图存在,但它不在基础组合里。这是那种你需要自己嫁接上去的东西,而大多数人不会,因为他们意识到需要之前,已经上线了通过测试但视觉不对的东西。

这个模式是:闭环才是有机制的保障。行为正确性有 TDD;视觉正确性什么都没有,而"什么都没有"是会累积的。

问题五:没有回顾的 archive 意味着重复踩坑

在旧版组合里,archive 是最后一个命令。它总结了做了什么,把功能标记为完成,就这样。在纸面上,它是回顾步骤。在实践中,它是一个收尾仪式。

三件事不会自动发生,所以根本没发生:

坑没有进 CLAUDE.md。当我在 apply 阶段碰到一个约束,比如"这个数据库适配器不支持我以为的那种批量 upsert",这个约束进了一条 commit message 和对话记忆,然后消失了。下个项目遇到类似的适配器会再发现一遍。

spec 没有迁移进 README。spec 是工作文档,README 是持久文档。一年后落地这个项目的新读者不应该翻遍 ./openspec/ 存档才能搞清楚这个项目是干什么的。迁移步骤在任何地方都不存在。

教训停在对话记忆里。什么有效、什么没效、下次我会怎么做不同,这些是一个项目产出的最高价值工件。没有文件承接,它们蒸发了。

这个模式是:停在对话里的回顾,只跑了一次。教训要离开 session,才能积累。


进化:三步走,四个命令级增强

在列出每个命令的改进之前,有一层比它们更重要的东西:方法论本身经历了三步进化。每一步都是被上一层的问题推出来的。

第一步:prompt + LLM 作为工作流媒介

这套组合最早完全活在 prompt 里。我用自然语言,粘贴接粘贴,向 OpenSpec 和 Superpowers 描述我想要什么。这个阶段的目标只是证明集成可行,explore 能喂给 brainstorm,brainstorm 能喂给 propose,跨工具的交接能产出连贯的东西。软集成是验证期的正确选择:它让我专注于这个组合是否可行,而不是怎么让它持久。

跑一个项目可行,跑第二个效果差了一些,到第三个开始产出不一致的工件。问题出在链接上(问题三):自然语言作为纽带,模糊性会随着使用次数积累。验证阶段没问题,但要稳定使用就需要更明确的结构。

第二步:OpenSpec 自定义 schema 和命令

下一层用 schema 换掉了软集成。自定义 OpenSpec schema 定义了 brainstorm、propose 和 archive 应该产出什么,具体的文件形态、具体的 section 名称、具体的交叉引用。自定义命令让顺序在 Claude Code 内部可被强制,而不是活在我脑子里。工作流从一个我讲述的故事,变成了工具可以检查的合同。

第三步:一个 Claude plugin,脱耦于任何单个项目

第三步是在整个流程稳定到可以推荐给别人时才有的。流程一旦固化成可以检查的结构,就可以带到任何项目里去。我把 schema、命令和跨工具的连线打包成了一个 Claude plugin。Claude plugin 是一个可发现、可安装的 skill 和命令包,Claude Code 在 session 启动时加载,所以工作流会出现在我工作的任何项目里,更重要的是,出现在任何别人 clone 它的项目里。这才是我真正想要的,不只是自己用得顺,而是能直接给同事用,不需要长篇解释。

每一层都是自然往下推进的,不是提前规划好的。第一步的问题推动了第二步。在每个项目里重建第二步的代价推动了第三步。没有任何东西是提前设计的;每一层都是因为被需要而存在。

在这三步之下,有四个具体的命令级增强,解决了上面五个问题。

增强一:先 explore,再用 mock 作为文件做 brainstorm

新的顺序:/opsx:explore 在整个工作流的其他部分之前运行,在它内部,agent 先读代码库,然后调用 superpowers:brainstorming 做设计,不是反过来。等你开始设计的时候,AI 已经知道代码库的形状了。

在那次 brainstorming 里,有两个改动很重要。第一,当功能是 UI 密集型的,mockup 不是以 markdown 草图生成的,它是以 HTML 文件生成的。Anthropic 工程师最近有一个注记,说 HTML 是比 markdown 更好的 UI 需求描述媒介,这和我的经验吻合。HTML 在一个工件里承载了布局、间距、视觉层级和交互提示,markdown 承载的是感觉。

第二,visual-companion 被明确告知把 mock 保存到一个文件路径,brainstorm 输出被告知引用那个路径。/opsx:explore 产出的需求文档现在有一行类似 UI mock: ./mocks/dashboard.html 的内容。mock 是一个文件。它跨 session 持久。下一步可以读它。

代价:每个功能多花几分钟保存 HTML mock。收益:每个下游步骤现在有了一个稳定的视觉参考。问题一不再出现,因为对话不再是设计存在的唯一地方。

增强二:propose 强制链接需求和 mock

propose 产出三个工件:spec.md、design.md、task.md。在旧版里,这些是根据 prompt 提到的内容生成的。现在,propose 在生成任何东西之前先问一个上游问题:需求 reviewed 了吗?mock 附上了吗?

如果答案是"没有需求文件"或"没有 mock 引用",propose 要么拒绝,要么提示你明确建立链接。这听起来很重,实践中是 propose 开始时一个五秒钟的检查,阻止了二十分钟的 spec 错位。

让这件事可被强制的机制是:propose 现在读的是结构化输入。需求是文件,mock 是文件。spec 按路径引用两者。它产出的 task.md 写着"任务 3:按照 ./mocks/dashboard.html 和 ./spec/requirements.md 第 2 节实现 dashboard"。这就是问题三,靠 prompt 传递信息太脆,加了骨架之后的样子。

增强三:apply 跑 TDD 加视觉 diff

apply 现在忠实地调用 Superpowers 的 test-driven-development skill,写失败的测试,看它失败,实现,看它通过,提交。这是行为的闭环,默认跑,不需要 prompt 提醒。

对于 UI 功能,apply 还跑一次对照保存 mock 的视觉 diff。机制很直接:无头浏览器截渲染出来的 UI,和 mock 对比,设一个容差阈值,标记差异。这不是硬关卡,视觉 diff 有合理的误报,但它是一个实现偏离设计的信号,而且信号在 apply 阶段到来,而不是我自己打开页面之后。

/opsx:apply 里的另一个新增是:superpowers:requesting-code-review 作为每组任务末尾的配对步骤运行,不再是我要记得单独调用的命令。review 子 agent 读 spec,读代码,标记偏移。这捕捉了测试通过但实现不是 spec 真正说的那个意思的失败模式,和人类结对编程捉住的失败模式一样。因为它是 /opsx:propose 注入的任务模板的一部分,不管我有没有想到要求,它都会触发。

增强四:archive 变成回顾,不是总结

archive 现在做三件事,每件都有机制:

一,回顾日志。archive 末尾有一个简短的提示:你进去的时候不知道、出来知道的是什么?spec 漏掉的约束冒出来了吗?下次你会做什么不同?输出到 ./retros/YYYY-MM-DD-功能名.md。三四行够了。关键是教训离开了对话记忆,进入了文件系统。

二,CLAUDE.md 更新。apply 期间发现的新坑或约束,追加到 CLAUDE.md 的"约束"或"坑"部分。下一个 session,不管是你的还是别人的,在 session 开始时就能看到这个约束。这个模式要修的是跨项目重复踩同一个坑。

三,README 迁移。archive 跑的时候,spec 的"这个是干什么的"部分被迁移进 README 的面向用户摘要。spec 是工作文档,README 是持久文档。迁移步骤确保一年后落地这个项目的人能拿到 spec 的精髓,不用翻 ./openspec/。

这三件事的共同模式是:archive 让未来的你,以及未来的读者,继承当下的你的教训。旧的 archive 是检查清单,新的 archive 是敏捷开发回顾一直应该是的机制。


四个命令,四个阶段

进化后的组合长这个样子。形态是 OpenSpec 的:四个 /opsx: 命令,每个阶段一个,这是你需要输入的全部。右边一列的 Superpowers skill 在这些命令内部跑,自动调用。

阶段命令做什么内嵌的 Superpowers skill解决
1. 落地/opsx:explore读代码库,起草需求文档(状态:DRAFT → REVIEWED),为 UI 工作生成 HTML mocksuperpowers:brainstorming(自我 review + UI mock 的 visual-companion)问题 1 + 2
2. 计划/opsx:propose生成 proposal.md + 能力 spec + design.md + tasks.md。在入口拒绝 DRAFT 状态需求;把 RED/GREEN 对、MOCK + 视觉 DIFF 三明治和 code review 检查点直接注入任务里任务模板编码了 superpowers:test-driven-development 和 superpowers:requesting-code-review 模式问题 3(软链接)
3. 构建/opsx:apply执行 tasks.md:RED → GREEN → (MOCK → 视觉 DIFF,如有 UI)→ 每组 code review,在需要手动操作的地方暂停superpowers:test-driven-development(session 开始)、superpowers:requesting-code-review(每组)、superpowers:verification-before-completion(最后一组)问题 3(skill 调用)+ 4
4. 关闭/opsx:archive归档变更,填写能力 spec 目的,更新 spec README + CLAUDE.md 坑 + (条件)项目 README,提示开发日志(清理动作内置在命令里)问题 5

四个命令,四个阶段。阶段和你在任何 spec 驱动工作流里期待的一致,落地现实,计划,构建,关闭。和旧版的区别:每个命令带了机制,机制包括自动调用正确的 Superpowers skill。当 skill 调用从"我要记得写进 prompt 的事"变成"命令本身默认做的事",问题就不再出现了。


敏捷开发,被固化

我今年早些时候写过为什么敏捷开发原则能撑过 AI 编程的转型。那篇文章的论点是:原则仍然成立,测试优先成为闭环,小迭代变得更小,结对编程变成和 AI 结对,回顾在 SpecKit 和 OpenSpec 这样的工具里被固化。

这篇文章是这些原则变成命令之后的样子。

/opsx:explore 是小迭代 + 先计划再执行 + 结对编程,根据代码库校准工作单元,在内部用 superpowers:brainstorming 做设计,在交接前把 mock 保存成文件。

/opsx:propose 是以可运行软件作为进度度量,spec 的存在是为了产出能跑的代码,RED/GREEN/视觉 DIFF/code review 任务在写任何代码之前就烘焙进计划里。

/opsx:apply 是测试优先作为闭环加结对编程,被固化,superpowers:test-driven-development 和 superpowers:requesting-code-review 在这里不是可选的附加;它们在 session 开始时被调用,在每组任务上跑。

/opsx:archive 是回顾,能力 spec 目的被填写,spec README 被更新,CLAUDE.md 的坑被捕捉,开发日志被提示。

上一篇写:文件提供记忆,你提供纪律。这篇是那个纪律。

还有一个值得说的小观察。我设计这四个增强,不是为了体现敏捷开发原则,是为了解决四个具体让我难受的地方。敏捷开发的形态自然浮现,是因为它本来就是软件开发者对这类问题的底层回应,只是在 AI 时代之前总结出来的。约束收敛的地方,方法论也会收敛。

这次进化一句话:它把我学到的敏捷开发理念,烘焙进了 skill 和工作流本身,让纪律在我记不记得调用它的时候都能跑。


上线——opsx-superpowers

Plugin 在 github.com/austinxyz/o…。完整的工作流文档在 docs/workflow.md,包括四个命令如何链接的图,以及让 fork 和 OpenSpec 上游保持同步的维护流程。

三步启动:

一,clone 并安装。git clone github.com/austinxyz/o… ~/.claude/plugins/opsx-superpowers。plugin 把四个 /opsx: 命令注册为 Claude Code slash 命令;它们调用的 Superpowers skill 随附打包。

二,配置你的项目。如果没有 CLAUDE.md,在项目根目录放一个。plugin 从它那里读约束、约定和坑。它会在第一次跑的时候用模板 section 填充这个文件。

三,跑你的第一个 explore。在项目内部:用 /opsx:explore 话题 在一个小功能上调用。命令读代码库,跑 superpowers:brainstorming 做设计,(对 UI 工作)打开 visual-companion 做 mockup,一个阶段全搞定。当需求文件翻到 Status: REVIEWED,链上 /opsx:propose 话题。第一个完整四阶段循环在一个小功能上需要三十到六十分钟。之后,熟悉了节奏,你就不再注意到这个结构了。

plugin 比单独的工作流文档多给你的:命令自动强制链接和回顾。你不用记得把 mock 保存成文件,/opsx:explore 保存它。你不用记得把 spec 迁移进 README,/opsx:archive 做这件事。机制内置了,所以纪律成了默认,而不是一种意志力行为。

关于采用的一个注意:不要试图把完整的进化版组合强行套进深度使用旧 flow 的项目。下一个功能用新组合开始。跑两三个功能之后,熟悉了节奏,再决定要不要把老项目也切过来。方法论是有粘性的;转型在面向未来的时候效果更好。


结尾

目前为止经历了三次进化。第一次证明了集成可行,第二次把它固定进 schema,第三次让它以 plugin 的形式可移植。每一次进化都是跑着跑着暴露出缺陷,再从缺陷里找到修法。没有任何东西是提前规划的,都是自然积累的。

这个节奏是让这个项目成为敏捷开发的东西,不是我映射到命令上的敏捷开发原则。每一次进化都产出了一个端到端能跑的 flow。每一次下一个都比上一次跑得更好。每个版本都是可上线的;每个下一版本都是上一版本的 spec。方法论进步的方式,和它产出的软件进步的方式一样,迭代着,被使用推着走。

你的下一次进化,会以同样的方式获利。跑这套组合。注意什么让你难受。修下一件事。等修法足够稳固,稳固到你可以不用长篇解释就递给同事,打包它。这是方法论积累的方式,不是在一个人的版本里,而是在实践者之间。

如果你读到这里,下一步大概是开始你自己的第一次进化。Plugin 就在那里,工作流文档也在。问题是你自己去发现的。

方法论还没完。它不会完。这就是重点。

感谢你一路读下来。