OpenSpec 三阶段工作流实操:从 Propose 到 Archive让代码返工率降到三分之一以下

📅 2026/7/8 2:23:37
OpenSpec 三阶段工作流实操:从 Propose 到 Archive让代码返工率降到三分之一以下
OpenSpec 三阶段工作流实操从 Propose 到 Archive让代码返工率降到三分之一以下SDD规范驱动开发和传统的前期文档区别不在于写什而在于谁来读它。传统文档写给人看的而SDD 规范写给 AI agent 看其结构让模型能够在生成过程中引用它、对照它检查输出、在一个 session 结束、新 session 开始时借此恢复上下文。为什么选 OpenSpec我评估过两个主要的开源方案——GitHub 的 SpecKit 和 Fission-AI 的 OpenSpec。SpecKit 有一个 constitution模型能把跨领域的规则TDD 要求、编码标准、合规约束编码进每一个功能的工作流中对企业合规场景这个很不错。OpenSpec 是另一个方向三个命令不需要事先写 constitution开箱即用支持 25 个以上的 AI 工具。它对每份规范都有一个硬性的 50KB 上下文限制——这一点为什么重要后面会展开说。作者用的是 Claude Code、偶尔用 Cursor所以OpenSpec 更适合我这种场景。不过如果你在受监管的行业需要强制执行每个 API 端点都必须有 OpenAPI 文档这类规则SpecKit 的 constitution 模型可能更合适这是一个合理的取舍并没有对错之分。三阶段工作流OpenSpec 强制执行一个严格的状态机没有任何阶段可选也没有任何阶段能跳过。下面是它实际的运作方式。阶段一Propose起点是一个意图不是代码。/opsx:propose add rate limiting to the public API endpointsagent 会先读取现有的openspec/specs/关于当前系统的真实来源然后生成一个新文件夹openspec/changes/add-rate-limiting/里面包含四份文件。proposal.md是结构化文档涵盖解决什么问题、会有什么变化标记为 ADDED、MODIFIED 或 REMOVED、什么不变、关键风险和依赖。specs/是以 GIVEN/WHEN/THEN 格式写成的行为场景也就是验收标准具体到可以直接当测试用例用。design.md是技术方案库、模式、架构决策。tasks.md是拆成小块、可独立审查的实现清单。人要在写下任何一行实现代码之前审查完这一切批准了阶段二才开始提议有问题就在这里纠正不能等到实现之后再回来纠正。ADDED/MODIFIED/REMOVED 这几个增量标记值它们迫使写规范的人和 AI 都明确说清楚现在存在什么、之后会存在什么。听起来有点繁琐但实际效果是能在很多哦等等那个模块已经这么做了的时刻变成技术债之前把它们揪出来。阶段二Apply提议获批之后/opsx:applyAI 逐一处理tasks.md里的任务每一步都读规范文件不是凭记忆读 prompt。这是它和无结构 AI 编码的关键区别每个任务足够小也可以独立测试哪个任务失败了、输出不对能准确看到违反了哪条规范场景反馈循环很紧。Apply 跑完之后运行/opsx:verify这一步对照规范检查实现不只是跑测试而是验证代码的行为是否符合 GIVEN/WHEN/THEN 场景。发现差距时会准确告诉哪个场景没被满足。我在大概三十个功能上跑过 verify大约三分之一会发现问题。总是一些小地方一个缺失的错误状态tasks 里没覆盖到的边界情况。能在合并之前把这些揪出来是这个框架真正的价值所在。阶段三Archive/opsx:archive变更文件夹移动到openspec/changes/archive/增量规范合并进主openspec/specs/即项目统一的真实来源。这是 OpenSpec 在结构上和 SpecKit 拉开差距的地方。SpecKit 会无限期地为每个功能维护独立的规范文件OpenSpec 把一切整合进一份代表系统当前状态的活文档里。所以任何时间点都可以直接读openspec/specs/理解整个系统不用从几十个功能文件里拼凑上下文。AI 也读这份文档——每次新提议开始时都会读。50KB 上下文限制是重要的特性不是缺陷这个看似随意的约束其实是框架里最重要的设计决策之一。现代 LLM 的上下文窗口很大有些超过一百万 token很容易让人觉得干脆把所有东西都塞进去——所有规范、所有代码、所有历史记录。问题是大上下文不等于聚焦的上下文。给 agent 塞进 800KB 的规范和代码它不会平等地读完所有内容会更关注某些部分而它关注的部分未必是当前这个具体任务真正在意的部分。OpenSpec 的 50KB 限制逼着人对规范里放什么保持克制不能一股脑塞进去得想清楚 agent 实现这个功能到底需要知道什么。这种克制带来一个副作用规范本身会变得更好——简洁、有针对性是一份简报,不是信息倾泻。对于需要在大型代码库上并行跑多个 agent 的团队这个约束还意味着可以同时跑好几个 agent 而不互相抢上下文预算这在规模化之后是个很实在的运维问题。一个真实例子速率限制功能具体一点。这是我正在做的一个项目里一份提议的精简版本。proposal.md节选## What is changing ADDED: Rate limiting middleware on all /api/v1/* routes MODIFIED: Express app configuration to mount rate limiter before routes ADDED: Redis-backed rate limit counter (per API key, per 15-minute window) ## What is NOT changing Authentication flow, response format, existing error codes. ## Risk Redis dependency — if Redis is unavailable, the middleware must fail open (allow requests) not fail closed (block all traffic).specs/rate-limiting.md节选GIVEN a valid API key making requests WHEN the key exceeds 100 requests per 15-minute window THEN the API returns 429 with a Retry-After header GIVEN Redis is unavailable WHEN a request arrives at the rate limiter THEN the request proceeds as normal (fail-open behaviour)第二个场景Redis 故障时的 fail-open 行为不是 AI 第一版草稿里的内容是在审查时加进去的来自对故障模式的思考。这正是规范审查该起的作用逼着人去想整个系统而不只是描述一个功能。最终代码优雅地处理了 Redis 故障不是因为 AI 对容错有多懂,而是规范告诉了它需要实现的行为。什么样的规范算好规范写了几十份之后总结出几条区分好坏的标准。描述行为不要规定实现方式。用户必须在 30 秒内收到通知是个好规范使用 WebSocket 推送通知是实现决策该放进 design.md。明确指出边界情况。正常路径谁都会写规范的价值恰恰体现在边界情况上失败了会怎样被调用两次会怎样输入为空会怎样每个场景保持原子性,一个场景一个 GIVEN/WHEN/THEN不要嵌套条件要表达复杂逻辑就拆成多个场景。用平实的语言写,平实到可以拿给非技术的同事看。一个场景如果要铺垫三段话才能讲清楚背景说明它太复杂了。总结这一篇讲的是 OpenSpec 在单一仓库内如何落地一个 agent一份代码库三个阶段走完一个功能。这套流程在这个前提下是成立的——proposal 有地方审查spec 有地方沉淀verify 有唯一一份代码可以对照检查。意图先于代码写清楚在实现开始前就有机会纠错AI 每一步都对照 spec 而不是凭记忆生成verify 又把实现和场景重新核对一遍。50KB 的限制看似只是个容量约束实际上逼着规范写得足够聚焦这也是整套流程能跑得动的前提之一。规范全程被 AI 使用而不是写完就闲置。https://avoid.overfit.cn/post/548f7f8356d04034a0cfce29ebc66670by Apurv Sheth