ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenSpec+Superpowers:打造AI编码时代的SDD+TDD工作流

OpenSpec+Superpowers:打造AI编码时代的SDD+TDD工作流 先亮个观点在 AI 辅助编码已经稀松平常的今天最让我头疼的从来不是“AI 不会写代码”而是“AI 写出来的东西看着对跑起来就离谱”。需求稍微复杂一点上下文一多模型就开始自由发挥接口、边界、命名全都飘。后来我把工作流改成了 OpenSpec Superpowers 这套组合用 OpenSpec 做规格驱动开发SDD用 Superpowers 里的 TDD 技能把测试驱动开发TDD的流程固化下来情况才真正改观。这篇文章就把完整的搭建过程、实操细节和踩坑经验整理出来。这个组合非常适合三类人正在用 Claude Code、Codex CLI、Curson 这类编程代理写真实项目的开发者被 AI 频繁改坏功能、需求总在变但又希望代码保持可控的技术负责人以及想系统学习 SDD 和 TDD 怎么落地到 AI 工作流的同学。按照下面的步骤走你能直接得到一个“先写规范、再拆任务、测试先行、验证后合并”的完整闭环而不是靠运气和反复试 prompt 硬掰 AI。1. 为什么我需要一套“规格测试”双驱动的工作流1.1 直接甩需求给 AI翻车是常态我试过很多次把一个大功能直接丢给 AI“帮我做一个用户注册接口要支持邮箱登录密码要加密还要防止重复注册。”看起来需求很清楚但 AI 实现出来的结果往往会有三个问题第一个是隐含信息全靠猜比如“加密”是用 bcrypt 还是 argon2邮件格式校验要不要做密码强度策略是什么第二个是上下文漂移同一个项目里这次生成的代码风格和上次完全不一样接口命名一会儿是createUser一会儿是signUp第三个是最致命的——AI 会给你写一堆看起来合理但没有任何测试保护的代码改动一个地方其他地方悄悄坏掉你还很难发现。这些问题的本质不是模型不够聪明而是我们的输入方式太模糊。传统软件开发早就给出了解法先用需求规格把行为定住再用自动化测试把行为锁死。只是在 AI 编码时代很多人反而把这些基本功丢了指望模型靠概率直接生成完美代码。OpenSpec 就是来解决前面半步的Superpowers 是来解决后面半步的。1.2 OpenSpec 的 SDD 思路先把“做什么”钉死在纸面上OpenSpec 是一个规约驱动的开发工具它不绑定具体编程语言核心是一套标准目录和命令行规范。你在项目根目录跑一次openspec init就会生成.openspec/目录里面默认有project.md、constraints.md、concepts.md、standards.md这些项目级文档还有changes/目录专门放变更提案。它的思路很简单任何功能改动都先走一次“变更提案change”的流程。一个 change 里有proposal.md说明价值和范围有spec.md描述具体技术规格和验收条件有tasks.md把实施步骤拆成可勾选的清单。AI 不是直接去写代码而是先把这些文档读完照着规格实现。这等于给 AI 戴上了一个“需求锚点”不管上下文多长它都能随时回到.openspec/目录里确认“我到底该做什么”。我一开始觉得这很烦后来发现它其实是在帮我们节省更多时间。没有 SDD 的时候AI 写出代码你还要逐行 review 猜测意图有了 spec代码只需要对着规格检查哪些做了、哪些没做、哪些多做了一眼就能看出来。1.3 Superpowers 的 TDD 思路让 AI 学会“先测试再实现”光有规格还不够规格只解决了“做什么”没有解决“怎么保证做得对”。这时候需要 TDD。问题在于虽然提示词里可以让 AI “先写测试”但大部分模型并没有内化完整的 TDD 纪律经常写着写着就跳步甚至先写实现再补齐测试伪装成 TDD。Superpowers 解决的就是这个问题。它本质上是一个“技能包”集合通过 Markdown 指令的方式给 AI 插拔工程能力。其中最核心的一个技能就是 TDD它会命令 AI 严格走 RED → GREEN → REFACTOR 循环先写一个失败测试运行确认它确实失败再写最小实现让测试通过最后重构并重新跑测试。整个训练过程被写成了 AI 能直接读取的指令你只需要说一句“使用 TDD 技能开始这个任务”AI 就会老老实实按流程干活。Superpowers 不只有 TDD还包括调试、重构、系统思考等一堆技能。但在这套 SDDTDD 工作流里TDD 技能是主力其他技能可以按需调用。1.4 组合后的工作流长什么样把两个工具串起来以后完整的工作流是这样的在项目初始化阶段用 OpenSpec 把项目背景、技术栈、编码约束写进.openspec/。每次有需求变更用openspec new change创建一个 change在proposal.md里写清楚为什么做、做什么、不做什么。根据 proposal 编写spec.md和tasks.md把大需求拆成可验证的小任务。对每个 task调用 Superpowers 的 TDD 技能让 AI 先写失败测试再实现功能直到测试通过。每个任务完成后运行一次全部测试和openspec validate确保规格与实现一致再提交合并。这个流程最大的好处是AI 的自由度被限制在“任务”级别而不是“整个功能”级别。任务足够小就算 AI 跑偏影响面也有限测试全绿又能证明每个小步都没有破坏既有功能。2. 环境准备安装 OpenSpec 和 Superpowers2.1 准备清单开始之前你需要确认手上这几样东西都齐了Node.js 18 或更高版本因为 OpenSpec 的 CLI 是用 Node 写的新版依赖不少。Git项目初始化和版本提交都离不开。一个 AI 编程工具优先推荐 Claude Code 或 Codex CLI。这两种工具能很好地加载本地 skills 和目录上下文如果你主力是用编辑器的 AI 插件比如 Cursor后面需要把 skills 目录手动指给插件。npm 或者 pnpm用来装 OpenSpec。一个真实的代码仓库别在空目录里练最好是个小型 Node/TS 项目后面演示 TDD 更方便。这套组合其实不挑语言但你用 Node/TypeScript 配合 Vitest 做演示是最顺的因为测试命令和包管理器都统一。2.2 安装 OpenSpec 并初始化目录安装很简单一行命令npm install -g openspec/cli装完验证一下openspec --version如果你不想全局安装也可以用npx openspec直接跑但我建议全局装因为后面会频繁用到openspec new change、openspec validate这些命令全局安装最顺手。然后在你的项目根目录执行openspec init执行完以后项目里会出现.openspec/目录。我建议你马上打开看一眼这些文件别急着跳过。project.md里写项目整体背景constraints.md里写死的限制standards.md里写团队编码规范concepts.md里写业务领域概念。这四个文件是你和 AI 之间的“共同记忆”。后面每次生成代码AI 都可以回去翻阅它们。2.3 安装 Superpowers 到你的 AI 工具Superpowers 的安装方式和你用的 AI 工具强相关。最通用、也最适合折腾的方式是把它的 skills 目录直接克隆到本地然后再让 AI 扫描。以 Claude Code 为例官方推荐用插件机制在 Claude Code 交互界面里输入/plugin install github.com/obra/superpowers等插件加载完你就能在技能列表里看到 TDD、调试、重构这些技能。如果你用的是 Codex CLI 或者 Cursor把仓库克隆下来然后把skills目录软链到对应位置即可。比如git clone https://github.com/obra/superpowers ~/superpowers mkdir -p ~/.codex/skills ln -s ~/superpowers/skills/* ~/.codex/skills/具体目录名要以你用的工具为准但思路都一样让 AI 能在项目上下文里找到那些 skill 的 Markdown 指令。安装完以后最好先让 AI“看一下有哪些 skills”确认它真的读到了这些文件再开始正式开发。2.4 用一次 openspec new change 建立第一个变更安装完成先别急着写代码我用一个最小的“hello world”变更来测试整条链路跑不跑得通。openspec new change hello-flow执行后.openspec/changes/hello-flow/下会生成三个文件proposal.md、spec.md、tasks.md。这时候你可以手动编辑它们也可以直接把需求告诉 AI 让它帮忙填。我的习惯是自己先写一版 proposal因为这是全流程里最需要“人味儿”的部分写清楚“为什么做”能极大减少 AI 乱猜。跑完这一步说明环境已经 OK 了。接下来进入真正的核心把这套双驱动工作流完整建起来。3. 搭建 SDDTDD 工作流五个阶段逐层拆解3.1 阶段一用 project.md 和 constraints.md 固定上下文很多人用 AI 编程喜欢在每次对话开头反复粘贴项目背景既啰嗦又容易漏一旦窗口被冲掉AI 又开始犯傻。OpenSpec 给出的方案是把这些背景沉淀成文件让 AI 每次开工前先读。我的project.md一般会包含几块内容项目是干什么的、目标用户是谁、当前技术栈是什么、代码仓库结构大概什么样、有没有需要特别注意的已有模块。不需要写得很长重点是让 AI 拿到这个文件后能迅速进入状态。constraints.md就更关键了它规定的是“绝对不能做的事”。我会把下面这些内容写进去后端必须使用 TypeScript禁止使用any如果无法推断类型需要显式定义 interface。所有代码必须使用 Vitest 编写单元测试测试文件与源码文件同名后缀为.test.ts。禁止直接修改数据库表结构所有变更要走 migration。外部 API 请求必须做超时和错误处理不允许裸 try/catch 吞异常。提交信息必须符合 Conventional Commits。这些约束可能看起来严苛但它们正是 AI 容易犯错的雷区。有了 constraintsAI 每执行一个任务前都会过一遍“边界清单”出格的概率大大降低。3.2 阶段二用 proposal 说清楚“为什么做”一个 change 的proposal.md本质上是给这次改动立一个“军令状”。模板通常长这样# 提案用户注册接口 ## 背景 当前系统没有注册能力用户只能通过管理员后台手动创建账号。运营同学反馈流程太重需要开放自助注册。 ## 目标 - 支持邮箱密码注册。 - 注册成功后自动创建用户并返回 JWT。 - 同一邮箱不能重复注册。 ## 非目标 - 不做邮箱验证码只做邮箱格式校验。 - 不做手机号注册。 - 不做找回密码流程。 ## 验收标准 - POST /api/auth/register 在合法请求时返回 201。 - 重复邮箱返回 409。 - 密码经过 bcrypt 哈希不能明文入库。注意“非目标”这块很多人不重视但它其实非常重要。写清楚“这次不做的事”能有效阻止 AI 顺手把整个用户中心都给你实现了——这种情况我遇到太多次了。3.3 阶段三用 spec 和 tasks 把“怎么做”拆到可执行proposal 是从产品视角回答“做什么”spec 则是从技术视角回答“怎么做”。spec.md里我通常会写接口定义、数据模型、异常处理方式、关键算法和测试用例。继续拿用户注册来举例spec 里的接口定义长这样## 接口 POST /api/auth/register ### 请求 { email: 字符串长度 5-100必须符合邮箱格式, password: 字符串长度 8-32必须包含字母和数字 } ### 响应 201: { token: JWT 字符串 } 400: { error: email 格式不正确 | password 不符合复杂度要求 } 409: { error: 邮箱已被注册 } ### 存储 - 表 usersid、email、password_hash、created_at。 - 邮箱统一小写存储。 - password_hash 使用 bcryptsalt rounds 为 10。写完 spec下一步是拆 tasks。一份合格的tasks.md是阶梯式的每个 task 都能对应一个可运行、可验证的结果# 任务清单用户注册接口 - [ ] 1. 创建 User 模型和 users 表 migration - [ ] 2. 实现密码哈希工具bcrypt 封装 - [ ] 3. 实现 email 格式校验函数 - [ ] 4. 实现 register service包含重复邮箱检查 - [ ] 5. 实现 POST /api/auth/register 路由 - [ ] 6. 集成测试正常注册、重复邮箱、非法参数拆的原则很简单每个 task 不要超过 20 分钟的编码量。AI 一次只负责一个小块就算跑偏也容易纠正。3.4 阶段四让 Superpowers 驱动 TDD 完成每个任务tasks 拆好之后终于轮到 Superpowers 出场。我不会直接把整个 tasks 列表丢给 AI 说“去实现”而是按顺序一个个来并且每次都明确要求使用 TDD 技能。一个典型的执行指令是这样的请先阅读 .openspec/project.md、.openspec/constraints.md 以及当前 change 的 proposal.md 和 spec.md。 然后使用 TDD 技能从 task 1 开始。 如果实现中需要新增接口请按 spec 里的定义执行。每次先写测试运行确认失败再实现再重构。 每个 task 完成后运行全部测试给我一个简短的状态说明。Superpowers 里的 TDD 技能会要求 AI 进入循环写一个失败测试跑它并确认失败写最少代码让它变绿然后重构并重新跑测试。这个过程听上去简单但对 AI 来说非常反直觉因为 AI 天然想直接写最终结果。技能包存在的意义就是强制改变它的行为模式让它按纪律工作。3.5 阶段五验证、提交、合并每个 task 完成我都建议立即提交一次代码。提交信息用规范化的风格例如git add . git commit -m feat: 实现用户密码哈希工具等一个 change 里的所有 task 都完成了跑一次总验证npx vitest run openspec validateopenspec validate会检查当前 change 的文档是否完整、tasks 是否都勾选、spec 是否引用了不存在的模块等。这步通过后你才有底气把分支推到远端提 PR。这样一套流程走下来每个 PR 都自带完整的背景、规格、任务和测试记录代码审查的时候reviewer 不再是拿着代码猜逻辑而是对着 spec 一项项核对效率完全不一样。4. 完整实操做一个用户注册接口这一节我会完整走一遍包括我实际用到的文件内容、命令和测试代码。虽然示例是 Node TypeScript Vitest但思路可以嫁接到任何语言。4.1 初始化项目与 change假设我从零开始mkdir demo-auth cd demo-auth git init npm init -y npm install -D typescript vitest types/node npx tsc --init openspec init openspec new change add-user-register现在.openspec/changes/add-user-register/下有三个文件。我打开proposal.md把上一节写的提案内容填进去。然后打开constraints.md补充几条技术边界。4.2 编写一份合格的 proposal我的proposal.md全文如下# 提案开放用户注册接口 ## 背景 当前用户只能由管理员创建无法支撑外部用户自助接入产品。 ## 目标 - 允许用户使用邮箱注册账号。 - 注册成功后直接返回登录 token。 - 同一邮箱不能重复注册。 ## 非目标 - 不引入邮箱验证码。 - 不实现找回密码。 ## 验收标准 - 合法注册返回 201。 - 非法邮箱/密码返回 400。 - 重复邮箱返回 409。 - 密码以 bcrypt 哈希保存。写完后我习惯再让 AI 读一遍问它“有没有不一致的地方”这能提前发现理解偏差。4.3 生成 spec 与任务清单接下来填充spec.md。我会让 AI 根据 proposal 起草然后自己再改一遍。最终核心内容是这样的# 技术规格用户注册 ## 路由 POST /api/auth/register ## 请求体 - email: string长度 5-100正则 ^[^\s][^\s]\.[^\s]$ - password: string长度 8-32必须包含数字和字母 ## 成功响应 HTTP 201 { token: jwt } ## 错误响应 HTTP 400 { error: email 格式不正确 | password 不符合复杂度要求 } HTTP 409 { error: 邮箱已被注册 } ## 数据表 users: - id: string (uuid) - email: string unique - password_hash: string - created_at: datetimetasks.md拆成 6 个 task。注意每个 task 都以“可验证”为导向。4.4 第一个 TDD 循环RED → GREEN → REFACTOR做完 task 1“创建 User 模型”时还看不出 TDD 的威力真正能体现 TDD 的是 task 2“实现密码哈希工具”。我先给 AI 下这样一条指令请使用 TDD 技能实现 task 2密码哈希工具。 先编写测试文件 src/utils/passwordHash.test.ts测试 bcrypt 哈希后能被 verify 通过。 运行测试确认失败再实现具体代码运行测试确认通过最后重构。AI 会先写出passwordHash.test.tsimport { describe, expect, it } from vitest; import { hashPassword, verifyPassword } from ./passwordHash; describe(passwordHash, () { it(hashPassword 返回的哈希可以通过 verifyPassword, async () { const hash await hashPassword(abc12345); await expect(verifyPassword(abc12345, hash)).resolves.toBe(true); }); it(verifyPassword 对错误密码返回 false, async () { const hash await hashPassword(abc12345); await expect(verifyPassword(wrong-pass, hash)).resolves.toBe(false); }); });因为passwordHash.ts还不存在测试必然失败这正是 RED 状态。要确认失败需要真的运行一次npx vitest run src/utils/passwordHash.test.ts看到测试失败信息后AI 才开始写passwordHash.tsimport bcrypt from bcryptjs; const SALT_ROUNDS 10; export async function hashPassword(password: string): Promisestring { return bcrypt.hash(password, SALT_ROUNDS); } export async function verifyPassword(password: string, hash: string): Promiseboolean { return bcrypt.compare(password, hash); }写完后再次运行测试两个用例变绿。接着进入 REFACTOR可能把常量抽出来或者补充注释。这个循环看似朴素但它是整个工程质量的地基。后面每个 task 都这样走累积下来测试覆盖率和实现正确率会稳定很多。4.5 跑通全部任务并验证6 个 task 都完成后我习惯做一次收尾检查npx vitest run openspec validate git add . git commit -m feat: 完成用户注册接口openspec validate通过后我再打开tasks.md核对所有选项是不是都已勾选。这里有个小技巧直接让 AI 在完成每个 task 后自动把对应方括号改成[x]这样最后的 validate 不会因为漏勾而报错。5. 避坑指南我从这套流程里踩过的坑5.1 OpenSpec 使用中的典型问题第一个坑是手动创建 change 目录。我一开始觉得用命令行麻烦直接自己建目录结果目录编号和命名格式不对openspec list根本识别不了。后来我就老老实实只用openspec new change。第二个坑是改了 proposal 忘了同步 spec。有时候需求讨论着讨论着就调整了范围但我只更新了 proposal没去更新 spec。结果 AI 对着旧 spec 写代码把已经砍掉的邮箱验证码又实现了一遍。现在每次改 proposal我都会强制检查 spec 和 tasks 是否同步。第三个坑是 change 拆得太大。一个 change 里塞了注册、登录、找回密码三个功能tasks 拆出来二十多个测试一跑红一大片根本没法定位。后来我坚持一个 change 只解决一个可独立交付的小需求宁多勿大。5.2 Superpowers 加载与执行的问题Superpowers 最常见的坑是“装上了但 AI 没加载”。你说了“使用 TDD 技能”AI 可能在敷衍地说“好的我将采用 TDD 方式”但实际并没有读技能文件。我会用一个办法确认要求 AI 先总结 TDD 技能里的三个步骤再开始干活。如果它答不出来说明技能没被正确加载需要回去检查安装路径。第二个坑是上下文爆炸。Superpowers 包含很多技能如果让 AI 一次读完全部 skill会白白占用大量上下文窗口甚至导致后面代码上下文不足。正确做法是按需加载哪个任务需要就让 AI 读哪个技能文件。第三个坑是版本更新频繁。Superpowers 更新很快如果你发现 AI 的行为和之前不一样很可能是技能内容变了。定期git pull或者重新拉取插件即可。5.3 组合工作流的协作技巧OpenSpec 管“规格”Superpowers 管“实施”但两边的步骤需要对齐。我一开始是让 AI 一次性读完整个 change 的所有 spec 和 tasks然后自由选择从哪开始。结果 AI 在 task 2 时把 task 5 的代码也顺手写了测试结构瞬间乱掉。现在我要求它严格按 tasks 顺序执行每个 task 完成后停下来汇报我再决定是否继续。另外每次开启新会话之前我都会在 prompt 里显式声明请先阅读 .openspec/project.md、.openspec/constraints.md 和 .openspec/changes/add-user-register/ 下的全部文件然后再开始任务。这个声明看着啰嗦但它保证了 AI 不会在上下文丢失后靠猜测写代码。5.4 问题速查表下面这张表是我自己经常翻阅的如果你也遇到类似现象可以直接对照处理。现象可能原因解决办法openspec validate报 tasks 未完成tasks.md 中未勾选完成项让 AI 完成后自动更新[x]或手动修改AI 写出的代码偏离 spec没先读 .openspec 文件或 spec 太模糊强化 prompt要求先读 spec把 spec 写得足够细致测试一直红任务拆太大AI 一次改了太多文件把 change 拆小一次只做一个 task调用 TDD 技能后 AI 仍先写实现技能未被加载让 AI 复述 TDD 步骤检查 skills 安装路径多个 change 之间互相干扰同一个分支同时改多个 change一个 change 一个分支合并后再开新 change上下文不够用加载了所有技能改为按需加载每次只读一个 skill6. 从个人开发到团队协作这套流程还能怎么延伸6.1 用 openspec validate 接进 CIOpenSpec 的价值在个人项目里已经很明显但放到团队里威力更大。你可以在 GitHub Actions 里加一个简单的检查任务name: validate on: [pull_request] jobs: openspec-validate: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm install -g openspec/cli - run: openspec validate - run: npm test这样每个 PR 进来CI 都会自动检查规格完整性和测试通过情况比人工催更靠谱得多。6.2 在 PR 模板里内置 SDD 清单团队协作时PR 描述也可以和 OpenSpec 绑定。我见过做得好的团队PR 模板里有几行必填项本次变更对应的 OpenSpec change 路径proposal 是否更新tasks 是否全部勾选openspec validate是否通过新增测试用例列表。这样 reviewer 无需在代码里摸索规范感一下就上来了。6.3 把 Superpowers 的其它技能也纳入流程除了 TDDSuperpowers 里的调试技能和重构技能也值得放进工作流。比如当一个 task 的测试一直红可以让 AI 先调用调试技能去定位当一个 change 完成后可以再调用重构技能做一轮代码清理。Skill 本身是按需加载的不会增加日常复杂度需要时用就是了。最后再分享一个我个人的体会这套流程刚开始跑的时候确实会觉得多了一步“写文档”的功夫但它省下的是后面成倍的返工和 review 成本。现在我接任何新需求第一反应已经变成了“先建 change再写 proposal再让 AI 干活”。如果哪天 AI 真的能完全理解复杂业务也许这套仪式可以简化掉但至少在今天OpenSpec Superpowers 是我试过的所有 AI 编码组合里最稳、最不靠运气的那一套。
返回列表