规格驱动开发:人类与AI的合约
本机暂存
<blockquote><p>"The specification is the source of truth, and code derives from it — not the other way around."<br>规格是真理的来源,代码派生自规格——而不是反过来。</p><p>——Deepak Babu Piskala, 《Spec-Driven Development: From Code to Contract in the Age of AI Coding Assistants》, 2026 年</p></blockquote><p>Skill 是 AI Agent 的能力单元:一个 Markdown 文件定义一种行为,小而可组合,可复用可迭代。但多个 Skill 组合在一起时,它们之间的"合约"是什么?谁来保证 <code>/tdd</code> 写的测试和 <code>/grill-with-docs</code> 对齐的需求是同一件事?</p><p>这就是规格驱动开发(Spec-Driven Development,SDD)要解决的问题。如果 Skill 是原子能力,那么 Spec 就是这些能力之间的<strong>接口协议</strong>。它不定义"怎么做",而是定义"做成什么样才算对"。</p><p>三条线索:SDD 的思想史(根源比 AI 编码工具早得多,但 AI 让它从学院派理想变成了工程必需品);三个代表性工具的逐层分析(OpenSpec、GitHub Spec-Kit、AWS Kiro);跨工具的通用原则。</p><p>三个线索汇聚到一句:<strong>规格不是在浪费时间写文档——规格是你和 AI 之间最有效率的通信协议。</strong></p><span id="more"></span><h2 id="3-1-规格驱动从何而来"><a href="#3-1-规格驱动从何而来" class="headerlink" title="3.1 规格驱动从何而来"></a>3.1 规格驱动从何而来</h2><p>SDD 的思想根源比 AI 编码工具古老得多。它的前身可以追溯到四条工程实践线。</p><p><strong>TDD</strong>(Kent Beck,1990 年代末)的核心洞见——测试本身就是一个可执行的规格。写完 <code>expect(prefs.theme).toBe('system')</code>,你实际上在声明:程序行为必须满足这个断言。<strong>契约式设计</strong>(Bertrand Meyer,1986)把模块之间的关系定义成契约——前置条件、后置条件、不变式。精确、可验证、不可含糊,这三个要素至今是 SDD 的质量标准。<strong>BDD</strong>(Dan North, 2003)把测试语言翻译成行为语言 Given-When-Then,开发者、测试者、业务分析师都能读同一份文档。<strong>形式化方法</strong>从 Hoare 逻辑到 TLA+,始终在回答一个问题:实现是否满足规格,能不能被证明?它没成为主流工程实践,但钉住了一个标准——好规格必须是可验证的。</p><p>这四条线各自独立跑了几十年,直到撞上一个共同的催化剂:<strong>AI 编码 Agent 能写代码了,但它不会读心。</strong></p><p>2025 年是"Vibe Coding"元年——Karpathy 造出这个词之后,会写自然语言就能生出一个可运行的应用。但解放的另一面是失控。AI 写得极快,质量极不可靠——产物是"看起来能跑、生产环境里一碰就碎"的代码浆糊,不可测试、不可重构、不可理解。</p><p><img src="/images/image-20260523100921412.png"></p><p>2026 年风向变了。GitHub Spec Kit、OpenSpec、Kiro 三个工具同时爆发,GitHub Universe 和 AWS re:Invent 为 SDD 背书,半年内超过 20 个 AI 编码工具内置了规格驱动工作流。同年 1 月,arXiv 上的一篇论文给出了第一个系统化的 SDD 定义,并引用了受控实验数据:<strong>人工提炼过的规格可以让 LLM 生成代码的错误率降低高达 50%。</strong></p><p>SDD 从四条各自独立的工程线索,被 AI 催化成了一个完整的范式。</p><h2 id="3-2-OpenSpec:轻量级-SDD-的代表"><a href="#3-2-OpenSpec:轻量级-SDD-的代表" class="headerlink" title="3.2 OpenSpec:轻量级 SDD 的代表"></a>3.2 OpenSpec:轻量级 SDD 的代表</h2><p>OpenSpec 由 Fission-AI 团队开发,2025 年中首次发布,MIT 协议。GitHub 上 46,000+ Star,25 个以上的 AI 编码工具原生支持——从 Claude Code、Codex 到 Cursor、Windsurf、Copilot。</p><p>它的 GitHub 描述行简短:"Spec-driven development for AI coding assistants."</p><h3 id="3-2-1-设计哲学:五句话"><a href="#3-2-1-设计哲学:五句话" class="headerlink" title="3.2.1 设计哲学:五句话"></a>3.2.1 设计哲学:五句话</h3><p>OpenSpec 的设计哲学可以归结为五句话:</p><ol><li><p><strong>Fluid, not rigid</strong>(流动而非僵化)。OpenSpec 不定义刚性阶段门。你不必严格按"需求→设计→任务→实现"的顺序线性推进。你可以在设计到一半时回到需求修改,可以在实现到一半时推翻设计。规格是活的——它和你对问题的理解同步演进。</p></li><li><p><strong>Iterative, not waterfall</strong>(迭代而非瀑布)。OpenSpec 的工作单元是一个"变更"(Change)——对应于一个功能、一个修复、或一个改进。每个变更独立地走 <code>propose → apply → archive</code> 三阶段。没有全局阶段的约束——三个变更可以同时处于不同的阶段。</p></li><li><p><strong>Easy, not complex</strong>(简单而非复杂)。安装只需要 Node.js 20+ 和一句 <code>npm install -g @fission-ai/openspec</code>(详见 3.2.2 节)。没有 Python 环境、没有数据库、没有配置文件。OpenSpec 的全部状态都以 Markdown 文件的形式存储在项目仓库的 <code>openspec/</code> 目录下。</p></li><li><p><strong>Built for brownfield, not just greenfield</strong>(为存量项目而生,不只为新项目)。这是 OpenSpec 最核心的差异点。大多数规格工具假设你从空项目开始——写一份规格,按规格实现。但现实中的多数项目是存量项目——已经有几万到几十万行代码,现在要往里加功能。你没法为了加一个暗黑模式就重写整个前端的规格。</p></li></ol><p>OpenSpec 用 <strong>Delta Specs(增量规格)</strong> 应对这个场景。不需要重新描述整个系统的行为——只标记你改变了什么:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">## ADDED Requirements</span></span><br><span class="line"><span class="bullet">-</span> Theme system supports <span class="code">`light`</span>, <span class="code">`dark`</span>, and <span class="code">`system`</span> modes</span><br><span class="line"></span><br><span class="line"><span class="section">## MODIFIED Requirements</span></span><br><span class="line"><span class="bullet">-</span> Navbar component: theme prop is now required instead of optional</span><br><span class="line"></span><br><span class="line"><span class="section">## REMOVED Requirements</span></span><br><span class="line"><span class="bullet">-</span> (none)</span><br></pre></td></tr></table></figure><p>每个变更文件夹只包含<strong>相对于当前规格的变化</strong>。变更归档时,这些增量自动合并到主规格库中。这个设计让 SDD 可以在存量项目中渐进式地引入——今天为一个新功能写一份变更规格,明天为另一个功能再写一份。不需要一次性铺开。</p><ol start="5"><li><strong>Scalable</strong>(可伸缩)。从个人项目到企业级。单人开发者用三句核心命令(<code>/opsx:propose</code>、<code>/opsx:apply</code>、<code>/opsx:archive</code>)走完闭环。企业团队用 <code>/opsx:verify</code> 加 <code>openspec validate --strict</code> 将规格验证嵌入 CI。</li></ol><p><img src="/images/image-20260523102342237.png"></p><h3 id="3-2-2-安装与初始化"><a href="#3-2-2-安装与初始化" class="headerlink" title="3.2.2 安装与初始化"></a>3.2.2 安装与初始化</h3><p>OpenSpec 是一套发布在 npm 上的 CLI 工具,包名为 <code>@fission-ai/openspec</code>,MIT 协议开源。GitHub 仓库 <a href="https://github.com/Fission-AI/OpenSpec">Fission-AI/OpenSpec</a>,官方网站 <a href="https://openspec.dev/">openspec.dev</a>。</p><p><strong>前置要求:Node.js ≥ 20.19.0。</strong> 检查当前版本:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node --version</span><br></pre></td></tr></table></figure><p><strong>安装 CLI:</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># npm(推荐)</span></span><br><span class="line">npm install -g @fission-ai/openspec@latest</span><br><span class="line"></span><br><span class="line"><span class="comment"># pnpm</span></span><br><span class="line">pnpm add -g @fission-ai/openspec@latest</span><br><span class="line"></span><br><span class="line"><span class="comment"># yarn</span></span><br><span class="line">yarn global add @fission-ai/openspec@latest</span><br><span class="line"></span><br><span class="line"><span class="comment"># bun(仍需 Node.js 20.19.0+ 在 PATH 中)</span></span><br><span class="line">bun add -g @fission-ai/openspec@latest</span><br><span class="line"></span><br><span class="line"><span class="comment"># nix(直接运行,无需安装)</span></span><br><span class="line">nix run github:Fission-AI/OpenSpec -- init</span><br></pre></td></tr></table></figure><p>验证安装成功:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openspec --version</span><br></pre></td></tr></table></figure><p><strong>初始化项目:</strong></p><p>进入项目目录,运行 <code>openspec init</code>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> your-project</span><br><span class="line">openspec init</span><br></pre></td></tr></table></figure><p><code>openspec init</code> 会交互式引导你完成三件事:</p><ol><li><strong>选择 AI 编码工具</strong>——Claude Code、Cursor、Codex、Copilot、Windsurf、Gemini CLI、Cline、RooCode、Amazon Q 等 25+ 工具,OpenSpec 会为选定的工具自动配置对应的 slash 命令</li><li><strong>选择 Profile</strong>——默认 <code>core</code>(包含 5 个核心命令);可切换为扩展 profile(包含 11 个命令)</li><li><strong>配置项目上下文</strong>——技术栈、编码规范、项目描述等</li></ol><p><img src="/images/image-20260530112836249.png"></p><p>初始化完成后,项目根目录下生成 <code>openspec/</code> 目录及对应工具的配置文件。</p><p><strong>目录结构:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">openspec/</span><br><span class="line">├── specs/ ← 累积的项目规格知识库(系统真值)</span><br><span class="line">│ └── <domain>/</span><br><span class="line">│ └── spec.md</span><br><span class="line">├── changes/ ← 活动变更(每个功能一个文件夹)</span><br><span class="line">│ └── <change-name>/</span><br><span class="line">│ ├── proposal.md</span><br><span class="line">│ ├── design.md</span><br><span class="line">│ ├── tasks.md</span><br><span class="line">│ └── specs/ ← 增量规格(ADDED/MODIFIED/REMOVED)</span><br><span class="line">│ └── <domain>/</span><br><span class="line">│ └── spec.md</span><br><span class="line">└── config.yaml ← 项目配置(可选)</span><br></pre></td></tr></table></figure><p><strong>更新 CLI:</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g @fission-ai/openspec@latest</span><br></pre></td></tr></table></figure><p>更新后,在每个项目中刷新 Agent 指令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openspec update</span><br></pre></td></tr></table></figure><h3 id="3-2-3-核心工作流:propose-→-apply-→-archive"><a href="#3-2-3-核心工作流:propose-→-apply-→-archive" class="headerlink" title="3.2.3 核心工作流:propose → apply → archive"></a>3.2.3 核心工作流:propose → apply → archive</h3><p>OpenSpec 是三阶段工作流,足够简单:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">/opsx:propose add-dark-mode</span><br><span class="line"> │</span><br><span class="line"> ▼</span><br><span class="line">┌─────────────────────────────────┐</span><br><span class="line">│ openspec/ │</span><br><span class="line">│ ├── changes/ │</span><br><span class="line">│ │ └── add-dark-mode/ │</span><br><span class="line">│ │ ├── proposal.md ← 为什么要做、影响什么</span><br><span class="line">│ │ ├── specs/ ← 增量规格(ADDED/MODIFIED/REMOVED)</span><br><span class="line">│ │ ├── design.md ← 技术方案(可选)</span><br><span class="line">│ │ └── tasks.md ← 可逐个验证的任务列表</span><br><span class="line">│ └── specs/ ← 累积的项目规格知识库</span><br><span class="line">│ ├── theme-system.md │</span><br><span class="line">│ └── navigation.md │</span><br><span class="line">└─────────────────────────────────┘</span><br><span class="line"> │</span><br><span class="line"> ▼</span><br><span class="line">/opsx:apply → 逐任务实现,打勾 tasks.md</span><br><span class="line"> │</span><br><span class="line"> ▼</span><br><span class="line">/opsx:archive → 归档到 changes/archive/,增量合并到 specs/</span><br></pre></td></tr></table></figure><p><strong><code>/opsx:propose</code></strong> 是生成阶段。你告诉 AI 你要什么——可能是半句话的描述,也可能是一段详细的背景。AI 会向你提问来澄清歧义(类似 <code>/grill-me</code> 的机制,但没有那么穷举式),然后产出一个变更文件夹,包含:</p><ul><li><code>proposal.md</code>:为什么做这个变更,影响哪些现有模块,有哪些风险</li><li><code>specs/</code>:增量规格,用 ADDED/MODIFIED/REMOVED 标记</li><li><code>design.md</code>:技术实现方案(可选)</li><li><code>tasks.md</code>:分解为可逐个验证的任务列表</li></ul><p><strong><code>/opsx:apply</code></strong> 是执行阶段。AI 读取 <code>tasks.md</code>,逐个任务实现,完成一个打勾一个。关键是<strong>一次只做一个任务</strong>——这是 Pocock 在第 2 章中强调的"小而可组合"原则在规格层面的映射。如果一个任务在实现过程中发现需要偏离设计,AI 会停下来向你报告,而不是默默修改导致漂移。</p><p><strong><code>/opsx:archive</code></strong> 是收尾阶段。变更完成并通过验证后,整个变更文件夹被移到 <code>changes/archive/</code>,增量规格自动合并到主规格库中。主规格库永远反映的是系统的当前状态——不是某个时间点的快照。下一次 <code>/opsx:propose</code> 会基于最新的主规格库来生成新变更的增量。</p><p>这个工作流的巧思在<strong>归档即合并</strong>。未归档的变更堆在 <code>changes/</code> 下,每一项都在提醒"还有未完成的事"。归档不只是移动文件夹——它是变更从"临时提案"切换为"系统真值"。Meyer 的契约式设计在这里以最轻量的方式落地:每次归档,系统的契约被正式更新一次。</p><h3 id="3-2-4-扩展工作流"><a href="#3-2-4-扩展工作流" class="headerlink" title="3.2.4 扩展工作流"></a>3.2.4 扩展工作流</h3><p>三阶段之外,OpenSpec 提供了一系列可选命令,覆盖更复杂的场景:</p><table><thead><tr><th>命令</th><th>功能</th><th>使用场景</th></tr></thead><tbody><tr><td><code>/opsx:new</code></td><td>全流程初始化</td><td>项目首次接入 OpenSpec 时,建立目录结构和初始规格</td></tr><tr><td><code>/opsx:continue</code></td><td>继续未完成的变更</td><td>上次 <code>apply</code> 到一半上下文窗口耗尽了,接着做</td></tr><tr><td><code>/opsx:ff</code></td><td>快速跟进(Fast Forward)</td><td>小变更不需要走完整流程,一次性生成全部产物</td></tr><tr><td><code>/opsx:verify</code></td><td>验证一致性</td><td>检查实现是否与规格一致——对照 tasks.md 中打勾的项逐条验证</td></tr><tr><td><code>/opsx:sync</code></td><td>规格同步</td><td>从现有代码反向提取规格,更新规格库(逆向 Spec-First)</td></tr><tr><td><code>/opsx:bulk-archive</code></td><td>批量归档</td><td>多个变更并行开发完成,一次性归档并检测冲突</td></tr><tr><td><code>/opsx:onboard</code></td><td>新成员引导</td><td>生成项目的规格全景图,帮助新开发者(人或 AI)快速理解系统</td></tr></tbody></table><p><code>/opsx:sync</code> 是 OpenSpec 对"brownfield"承诺的技术兑现:可以先有代码,后有规格。对一个已有几万行代码的存量项目,运行 <code>/opsx:sync</code> 会让 AI 扫描代码库并反向生成初始规格库。这降低了 SDD 的入场成本——不需要为历史代码补写规格,AI 帮你做这件事。</p><p><code>/opsx:verify</code> 和 <code>openspec validate --all --strict --json</code>(CLI 版本)是 CI 集成的关键。前者在 Agent 会话中交互式逐任务验证;后者产出结构化的 JSON 和退出码,可以被 GitHub Actions 或 Jenkins 直接消费——实现与规格不符,CI 红灯。</p><h3 id="3-2-5-OpenSpec-的边界:它不做什么"><a href="#3-2-5-OpenSpec-的边界:它不做什么" class="headerlink" title="3.2.5 OpenSpec 的边界:它不做什么"></a>3.2.5 OpenSpec 的边界:它不做什么</h3><p>理解一个工具,也要理解它选择不做什么。OpenSpec 有四个明确的边界:</p><p><strong>不强制阶段门。</strong> OpenSpec 不会用"必须先写 design.md 才能开始实现"拦住开发者。它信任开发者的判断——如果变更简单到可以跳过设计,它不阻止。代价是如果跳过设计然后在实现中走错了方向,需要自己承担返工。</p><p><strong>不做平台绑定。</strong> OpenSpec 的规格是纯 Markdown 文件,不依赖任何特定 AI 工具的 API。同一个 <code>openspec/</code> 目录可以无缝工作在 Claude Code、Codex、Cursor、Windsurf 之间。这是第 2 章中 Pocock 提出的"模型无关"原则在规格层面的表现。</p><p><strong>不做自动代码生成。</strong> OpenSpec 帮你定义"做什么"和"怎么做",但它不自己写代码。它把规格输出交给 AI 编码 Agent(通过 <code>/opsx:apply</code>)去执行。OpenSpec 的角色是"合约管理者",不是"代码生成器"。</p><p><strong>不解决"人本身不会写规格"的问题。</strong> 所有 SDD 工具的终极瓶颈。工具可以提供模板、提出澄清问题、防止格式错误——前提是使用者具备将模糊需求转化为可验证标准的能力。OpenSpec 不会救一个描述不清楚自己需求的人——它会放大你,正如第 1 章中反复出现的那个判断。</p><p>这四个边界定义出了 OpenSpec 的定位:它处于轻量自由的一端。GitHub Spec-Kit 则站在另一端。</p><h3 id="3-2-6-实战:用-OpenSpec-生成贪吃蛇游戏"><a href="#3-2-6-实战:用-OpenSpec-生成贪吃蛇游戏" class="headerlink" title="3.2.6 实战:用 OpenSpec 生成贪吃蛇游戏"></a>3.2.6 实战:用 OpenSpec 生成贪吃蛇游戏</h3><p>下面用一个完整的例子走一遍 OpenSpec 的三阶段闭环。任务:生成一个在浏览器中可玩的贪吃蛇网页游戏。</p><p><strong>第一步:<code>/opsx:propose snake-game</code></strong></p><p>你只需要一句话:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">/opsx:propose 做一个贪吃蛇网页游戏。用方向键控制蛇的移动,吃到食物</span><br><span class="line">后蛇变长、分数增加。撞到墙壁或自己的身体则游戏结束。纯前端实现,</span><br><span class="line">HTML/CSS/JS 单文件。</span><br></pre></td></tr></table></figure><p>Agent 不会直接开始写规格。它会先追问几个澄清问题:</p><blockquote><p><strong>Q1:</strong> 游戏网格大小你期望多少?我建议 20×20——适合桌面端,移动端也不会太小。</p><p><strong>Q2:</strong> 蛇的移动速度?我推荐初始 150ms/步——有挑战但不至于太快。</p><p><strong>Q3:</strong> 分数系统怎么设计?每个食物 10 分、显示当前分数和最高分?</p><p><strong>Q4:</strong> 要不要加一个"重新开始"按钮?撞墙或咬到自己后弹出。</p></blockquote><p>你逐一确认。Agent 随后在 <code>openspec/changes/snake-game/</code> 下生成四个文件:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">openspec/</span><br><span class="line">├── changes/</span><br><span class="line">│ └── snake-game/</span><br><span class="line">│ ├── proposal.md ← 为什么做、影响范围、风险</span><br><span class="line">│ ├── specs/</span><br><span class="line">│ │ └── game-logic.md ← 增量规格(ADDED/MODIFIED/REMOVED)</span><br><span class="line">│ ├── design.md ← 技术方案(可选)</span><br><span class="line">│ └── tasks.md ← 可逐个验证的任务列表</span><br></pre></td></tr></table></figure><p><code>proposal.md</code> 长这样:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Proposal: 贪吃蛇网页游戏</span></span><br><span class="line"></span><br><span class="line"><span class="section">## Why</span></span><br><span class="line">提供一个可直接在浏览器中游玩的贪吃蛇游戏,作为项目的前端交互能力验证。</span><br><span class="line"></span><br><span class="line"><span class="section">## What Changes</span></span><br><span class="line"><span class="bullet">-</span> 新增 <span class="code">`snake-game.html`</span>,单文件包含 HTML/CSS/JS</span><br><span class="line"><span class="bullet">-</span> 不引入任何外部依赖</span><br><span class="line"></span><br><span class="line"><span class="section">## Impact</span></span><br><span class="line"><span class="bullet">-</span> 纯新增文件,不影响现有模块</span><br><span class="line"><span class="bullet">-</span> 无后端依赖,无构建步骤</span><br></pre></td></tr></table></figure><p><code>specs/game-logic.md</code> 中的增量规格只有 ADDED 部分:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">## ADDED Requirements</span></span><br><span class="line"></span><br><span class="line"><span class="section">### 游戏核心</span></span><br><span class="line"><span class="bullet">-</span> 20×20 网格,蛇初始长度 3,位于网格中央</span><br><span class="line"><span class="bullet">-</span> 方向键控制移动方向(上/下/左/右)</span><br><span class="line"><span class="bullet">-</span> 蛇不能反向移动(如向右时不能立刻向左)</span><br><span class="line"></span><br><span class="line"><span class="section">### 食物系统</span></span><br><span class="line"><span class="bullet">-</span> 食物随机出现在空白格子,每次只有一个</span><br><span class="line"><span class="bullet">-</span> 蛇吃到食物后长度 +1,分数 +10</span><br><span class="line"><span class="bullet">-</span> 新食物立即在空白位置生成</span><br><span class="line"></span><br><span class="line"><span class="section">### 游戏结束</span></span><br><span class="line"><span class="bullet">-</span> 蛇头触碰墙壁 → 游戏结束</span><br><span class="line"><span class="bullet">-</span> 蛇头触碰自身身体 → 游戏结束</span><br><span class="line"><span class="bullet">-</span> 游戏结束时显示最终得分和"重新开始"按钮</span><br><span class="line"></span><br><span class="line"><span class="section">### 非功能需求</span></span><br><span class="line"><span class="bullet">-</span> 游戏循环间隔 150ms</span><br><span class="line"><span class="bullet">-</span> 最高分存储在 localStorage,刷新后保留</span><br><span class="line"><span class="bullet">-</span> 页面在 500ms 内完成首次渲染</span><br></pre></td></tr></table></figure><p><code>tasks.md</code> 把实现拆成四个独立可验证的任务:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Tasks</span></span><br><span class="line"></span><br><span class="line"><span class="section">## 1. HTML 结构与画布渲染</span></span><br><span class="line"><span class="bullet">-</span> [ ] 创建 20×20 网格的 Canvas 元素</span><br><span class="line"><span class="bullet">-</span> [ ] 实现 <span class="code">`drawGrid()`</span> 渲染网格线</span><br><span class="line"><span class="bullet">-</span> [ ] 实现 <span class="code">`drawSnake()`</span> 渲染蛇身(绿色方块)</span><br><span class="line"><span class="bullet">-</span> [ ] 实现 <span class="code">`drawFood()`</span> 渲染食物(红色方块)</span><br><span class="line"><span class="bullet">-</span> <span class="strong">**验证**</span>:打开页面看到空网格</span><br><span class="line"></span><br><span class="line"><span class="section">## 2. 蛇的移动与键盘控制</span></span><br><span class="line"><span class="bullet">-</span> [ ] 实现方向状态管理(不允许反向)</span><br><span class="line"><span class="bullet">-</span> [ ] 实现 150ms 间隔的游戏循环</span><br><span class="line"><span class="bullet">-</span> [ ] 监听键盘方向键事件</span><br><span class="line"><span class="bullet">-</span> [ ] 实现蛇身移动逻辑(头前进、尾删除)</span><br><span class="line"><span class="bullet">-</span> <span class="strong">**验证**</span>:方向键控制蛇在网格中移动</span><br><span class="line"></span><br><span class="line"><span class="section">## 3. 碰撞检测与食物逻辑</span></span><br><span class="line"><span class="bullet">-</span> [ ] 墙壁碰撞检测 → 游戏结束</span><br><span class="line"><span class="bullet">-</span> [ ] 自身碰撞检测 → 游戏结束</span><br><span class="line"><span class="bullet">-</span> [ ] 食物碰撞检测 → 蛇变长、分数+10、新食物生成</span><br><span class="line"><span class="bullet">-</span> [ ] 食物不生成在蛇身上</span><br><span class="line"><span class="bullet">-</span> <span class="strong">**验证**</span>:吃食物蛇变长,撞墙游戏结束</span><br><span class="line"></span><br><span class="line"><span class="section">## 4. 分数系统与游戏状态</span></span><br><span class="line"><span class="bullet">-</span> [ ] 当前分数和最高分显示</span><br><span class="line"><span class="bullet">-</span> [ ] localStorage 读写最高分</span><br><span class="line"><span class="bullet">-</span> [ ] 游戏结束弹窗(显示分数 + 重新开始按钮)</span><br><span class="line"><span class="bullet">-</span> [ ] 重新开始重置所有状态</span><br><span class="line"><span class="bullet">-</span> <span class="strong">**验证**</span>:完整一局从开始到结束到重新开始</span><br></pre></td></tr></table></figure><p><img src="/images/image-20260530113137399.png"></p><p><strong>第二步:<code>/opsx:apply</code></strong></p><p>Agent 读取 <code>tasks.md</code>,从任务 1 开始逐个实现。每完成一个任务,它在 <code>tasks.md</code> 中打勾 <code>[x]</code>,然后进入下一个:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Agent: 开始任务 1——HTML 结构与画布渲染。</span><br><span class="line"> [生成 snake-game.html,包含 Canvas 元素和 drawGrid/drawSnake/drawFood 函数]</span><br><span class="line"> 打开浏览器预览 → 网格正常渲染。</span><br><span class="line"> tasks.md: 1. [x] HTML 结构与画布渲染</span><br><span class="line"></span><br><span class="line">Agent: 开始任务 2——蛇的移动与键盘控制。</span><br><span class="line"> [添加方向状态、游戏循环、键盘监听]</span><br><span class="line"> 测试:方向键控制蛇移动 → 正常。</span><br><span class="line"> tasks.md: 2. [x] 蛇的移动与键盘控制</span><br><span class="line"></span><br><span class="line">Agent: 开始任务 3——碰撞检测与食物逻辑。</span><br><span class="line"> [在游戏循环中加入碰撞检测,实现食物生成与消费]</span><br><span class="line"> 测试:吃食物蛇变长,撞墙结束 → 正常。</span><br><span class="line"> tasks.md: 3. [x] 碰撞检测与食物逻辑</span><br><span class="line"></span><br><span class="line">Agent: 开始任务 4——分数系统与游戏状态。</span><br><span class="line"> [添加分数面板、localStorage 读写、结束弹窗、重新开始按钮]</span><br><span class="line"> 测试:完整一局正常 → 正常。最高分刷新后保留 → 正常。</span><br><span class="line"> tasks.md: 4. [x] 分数系统与游戏状态</span><br></pre></td></tr></table></figure><p>四个任务全部打勾,<code>apply</code> 阶段结束。</p><p><img src="/images/image-20260530113301729.png"></p><p><strong>第三步:<code>/opsx:archive snake-game</code></strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/opsx:archive snake-game</span><br></pre></td></tr></table></figure><p>Agent 执行三个动作:</p><ol><li>将 <code>changes/snake-game/</code> 整体移到 <code>changes/archive/snake-game/</code></li><li>将 <code>specs/game-logic.md</code> 中的 ADDED 增量合并到主规格库 <code>openspec/specs/game-logic.md</code></li><li>输出归档摘要:"snake-game 已归档。主规格库中的 game-logic.md 已更新,新增 12 条行为规格。"</li></ol><p>自此,贪吃蛇游戏的完整规格永久留在了项目的 <code>openspec/specs/</code> 目录中。六个月后如果有人要重构它——比如把 Canvas 换成 DOM 渲染——规格告诉 TA 游戏应该怎么工作,不管实现层怎么变。</p><p>这就是 OpenSpec 的增量变更机制的意义。重构时不需要重新定义"游戏行为"——只需要声明"渲染层实现方式变了,行为不变"。流程如下:</p><p><strong>第一步:<code>/opsx:propose snake-dom-render</code></strong></p><p>描述变更内容,明确声明这是一个修改而非新增:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">/opsx:propose 将贪吃蛇游戏的渲染层从 Canvas 换为 DOM div 网格。</span><br><span class="line">游戏行为不变——所有游戏逻辑、碰撞检测、分数系统的行为</span><br><span class="line">保持与现有规格一致。仅替换渲染实现。</span><br></pre></td></tr></table></figure><p>Agent 检测到主规格库 <code>openspec/specs/</code> 中已存在 <code>game-logic.md</code>,自动识别被影响的 capability,生成变更文件夹:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">openspec/changes/snake-dom-render/</span><br><span class="line">├── proposal.md ← "Why: 提高语义化、可访问性"</span><br><span class="line">├── specs/</span><br><span class="line">│ └── game-logic.md ← 增量规格(只写变更部分)</span><br><span class="line">├── design.md ← "DOM 网格方案替代 Canvas API"</span><br><span class="line">└── tasks.md ← 四个迁移任务</span><br></pre></td></tr></table></figure><p><code>specs/game-logic.md</code> 的增量规格自动标注为 MODIFIED,<strong>只写变更部分</strong>,保留所有原有行为申明:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">## MODIFIED Requirements</span></span><br><span class="line"></span><br><span class="line"><span class="section">### 渲染层</span></span><br><span class="line"><span class="bullet">-</span> ~~使用 Canvas API 的 drawGrid/drawSnake/drawFood 函数~~</span><br><span class="line"><span class="bullet">-</span> 使用 DOM div 元素渲染 20×20 网格,每个格子一个 <span class="code">`<div>`</span> 节点</span><br><span class="line"><span class="bullet">-</span> 蛇身格子使用 <span class="code">`.snake`</span> CSS class,食物格子使用 <span class="code">`.food`</span> CSS class</span><br><span class="line"><span class="bullet">-</span> 渲染性能:单帧重绘 < 50ms,保持 150ms 游戏循环不受影响</span><br><span class="line"></span><br><span class="line"><span class="section">## RETAINED Requirements</span></span><br><span class="line">以下行为申明保持不变(来自主规格库 game-logic.md):</span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> 20×20 网格,蛇初始长度 3,位于网格中央</span><br><span class="line"><span class="bullet">-</span> 方向键控制移动方向(上/下/左/右)</span><br><span class="line"><span class="bullet">-</span> 蛇不能反向移动</span><br><span class="line"><span class="bullet">-</span> 食物随机出现在空白格子,每次只有一个</span><br><span class="line"><span class="bullet">-</span> 蛇吃到食物后长度 +1,分数 +10</span><br><span class="line"><span class="bullet">-</span> 撞墙或自碰 → 游戏结束</span><br><span class="line"><span class="bullet">-</span> 最高分存储在 localStorage</span><br><span class="line"><span class="bullet">-</span> 游戏循环间隔 150ms</span><br><span class="line"><span class="bullet">-</span> 首次渲染 < 500ms</span><br></pre></td></tr></table></figure><p><strong>第二步:<code>/opsx:apply</code></strong></p><p>Agent 逐任务执行。关键约束:每完成一个任务,Agent 对照 MODIFIED + RETAINED 双清单验证——新实现同时满足变更要求和保留行为:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">Agent: 开始任务 1——DOM 网格结构。</span><br><span class="line"> 将 Canvas 替换为 20×20 div 网格,每格添加 .cell class。</span><br><span class="line"> ✓ 网格渲染正常,原有行为未受影响</span><br><span class="line"></span><br><span class="line">Agent: 开始任务 2——DOM 渲染函数。</span><br><span class="line"> 实现 renderGridDom()/renderSnakeDom()/renderFoodDom()。</span><br><span class="line"> ✓ 蛇移动正常,食物生成正常,原有行为未受影响</span><br><span class="line"></span><br><span class="line">Agent: 开始任务 3——替换渲染调用。</span><br><span class="line"> gameLoop 中 Canvas 调用全部替换为 DOM 调用。</span><br><span class="line"> ✓ 碰撞检测正常,分数系统正常,原有行为未受影响</span><br><span class="line"></span><br><span class="line">Agent: 开始任务 4——无障碍与样式。</span><br><span class="line"> 添加 aria-label、键盘焦点、网格线样式。</span><br><span class="line"> ✓ 原有路径测试全部通过,game-logic.md 中的 RETAINED 行为均验证通过</span><br></pre></td></tr></table></figure><p><strong>第三步:<code>/opsx:archive snake-dom-render</code></strong></p><p>归档时,OpenSpec 将 MODIFIED 部分合并到主规格库 <code>openspec/specs/game-logic.md</code>——渲染层描述从 Canvas 更新为 DOM,RETAINED 行为不变。规格仍然是系统的准确真值。</p><p>归档即合并的威力:<strong>每次归档,规格被正式更新一次,而非重新写一次。</strong> 重构不是一次重新写规格的过程,而是一次更新规格中一个子集的过程。规格保留了所有未变行为的完整性——六个月前的游戏行为申明,六次重构后仍然可信。</p><p>整个流程用了三个命令、四个任务、一次归档。OpenSpec 的轻体现在此:它没有要求你写 constitution、没有强制阶段门、没有生成八份文档。它只做了一件事——在你写代码之前冻结了一份关于"完成意味着什么"的共识。</p><hr><h2 id="3-3-GitHub-Spec-Kit:重量级-SDD-的基建"><a href="#3-3-GitHub-Spec-Kit:重量级-SDD-的基建" class="headerlink" title="3.3 GitHub Spec-Kit:重量级 SDD 的基建"></a>3.3 GitHub Spec-Kit:重量级 SDD 的基建</h2><p>2025 年 9 月,GitHub 发布了名为 Spec-Kit 的开源工具包。它的定位简洁明确。GitHub 官方博客的原话:"Specifications don't serve code — code serves specifications."(规格不服务于代码——代码服务于规格。)</p><p>这句话翻转了传统的层级:规格才是源,代码是派生品。</p><p>Spec-Kit 在不到一年内积累了超过 92,000 个 GitHub Stars,30+ 个 AI 编码工具支持,近 100 个社区扩展。2026 年 5 月,微软在 Build 大会上为它安排了专门的培训模块和主题演讲。Thoughtworks 在 2026 年 4 月的技术雷达中将 Spec-Kit 列入"评估"环——他们的评价精准地总结了它的核心特征:"一种更重量级的方案,拥有刚性阶段门、大量的 Markdown 文档、Python 运行时。"</p><h3 id="3-3-1-设计哲学:以-constitution-md-为纲"><a href="#3-3-1-设计哲学:以-constitution-md-为纲" class="headerlink" title="3.3.1 设计哲学:以 constitution.md 为纲"></a>3.3.1 设计哲学:以 constitution.md 为纲</h3><p>Spec-Kit 用六条原则定义了它的世界观:</p><p><strong>规格是主,代码是仆。</strong> 这个表述比 OpenSpec 的"规格先行"更强硬。它隐含的推论是:如果代码和规格不一致,永远是代码错了。</p><p><strong>先定宪法,再写代码。</strong> 一个名为 <code>constitution.md</code> 的文件是 Spec-Kit 最独特的设计。这个文件不是功能需求,它是<strong>项目的不变法则</strong>:编码规范、TDD 要求、安全标准、部署约束、不合规的代价。在后续每个阶段中,Agent 都必须检查"我的产出是否符合宪法?"这就像国家在制定法律之前先有宪法的约束——一切下位法不能违宪。</p><p><strong>刚性阶段门。</strong> Spec-Kit 定义了五个强制阶段外加三个可选阶段。理论上你可以跳过某个阶段,但框架的设计强烈建议按序执行:Constitution → Specify → Plan → Tasks → Implement。每个阶段有明确的输入和输出。</p><p><strong>可扩展。</strong> 社区贡献了近 100 个扩展——Jira 集成、Azure 部署、成本追踪、无障碍检查、安全审计、多 Agent 审查。Spec-Kit 本身是一个骨架,扩展是肌肉。</p><p><strong>多 Agent 支持。</strong> 30+ 个 AI 编码工具原生支持——从 GitHub Copilot 到 Claude Code 到 Amazon Q Developer。Spec-Kit 用同一个 <code>/speckit.*</code> 命令体系跨平台运作。</p><p><strong>全生命周期覆盖。</strong> 从初始化到退役,Spec-Kit 试图覆盖一个功能在代码库中的完整生命周期——不只是"写代码",还有"理解已有代码"、"变更影响分析"、"退役清理"。</p><p><img src="/images/image-20260523102840088.png"></p><h3 id="3-3-2-核心流程:五步法-三个可选步骤"><a href="#3-3-2-核心流程:五步法-三个可选步骤" class="headerlink" title="3.3.2 核心流程:五步法+三个可选步骤"></a>3.3.2 核心流程:五步法+三个可选步骤</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">/speckit.constitution → 定义项目的不变法则</span><br><span class="line"> │</span><br><span class="line"> ▼</span><br><span class="line">/speckit.specify → 编写功能规格(用户故事、验收标准、非功能需求)</span><br><span class="line"> │</span><br><span class="line"> ▼</span><br><span class="line">/speckit.plan → 生成技术方案(架构、数据流、组件树、API 契约)</span><br><span class="line"> │</span><br><span class="line"> ▼</span><br><span class="line">/speckit.tasks → 将方案分解为可独立验证的任务清单</span><br><span class="line"> │</span><br><span class="line"> ▼</span><br><span class="line">/speckit.implement → 逐任务实现</span><br></pre></td></tr></table></figure><p>五个步骤之间是三个可选命令:</p><ul><li><strong><code>/speckit.clarify</code></strong>:在 <code>specify</code> 和 <code>plan</code> 之间插入一轮需求澄清——类似 <code>/grill-with-docs</code> 的领域建模过程</li><li><strong><code>/speckit.analyze</code></strong>:在 <code>plan</code> 之前分析变更的影响范围——哪些现有模块会被触及,风险在哪里</li><li><strong><code>/speckit.checklist</code></strong>:在 <code>implement</code> 完成后生成一个验证清单——对照原规格逐条确认</li></ul><p><code>constitution.md</code> 的设计值得深入讨论,因为它是 Spec-Kit 与 OpenSpec 之间最深层的哲学分歧。</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># constitution.md</span></span><br><span class="line"></span><br><span class="line"><span class="section">## 编码标准</span></span><br><span class="line"><span class="bullet">-</span> 语言:TypeScript,严格模式</span><br><span class="line"><span class="bullet">-</span> 格式:Prettier 默认配置</span><br><span class="line"><span class="bullet">-</span> 禁止使用 <span class="code">`any`</span> 类型(除非有明确的 ADR 记录偏差理由)</span><br><span class="line"></span><br><span class="line"><span class="section">## 测试要求</span></span><br><span class="line"><span class="bullet">-</span> 每个功能必须有单元测试,覆盖率不低于 80%</span><br><span class="line"><span class="bullet">-</span> 每个 API 端点必须有集成测试</span><br><span class="line"><span class="bullet">-</span> 不满足测试要求不得进入 implement 阶段</span><br><span class="line"></span><br><span class="line"><span class="section">## 安全要求</span></span><br><span class="line"><span class="bullet">-</span> 所有用户输入必须经过验证</span><br><span class="line"><span class="bullet">-</span> 所有外部 API 调用必须有超时和重试策略</span><br><span class="line"><span class="bullet">-</span> 敏感信息(密钥、密码、PII)禁止出现在日志中</span><br><span class="line"></span><br><span class="line"><span class="section">## 架构约束</span></span><br><span class="line"><span class="bullet">-</span> 遵循 Clean Architecture 的分层模型</span><br><span class="line"><span class="bullet">-</span> 新增依赖必须过审——优先使用现有依赖</span><br><span class="line"><span class="bullet">-</span> API 契约变更必须更新对应的 OpenAPI 文档和版本号</span><br><span class="line"></span><br><span class="line"><span class="section">## 违规后果</span></span><br><span class="line"><span class="bullet">-</span> CI 红灯,阻止 merge</span><br><span class="line"><span class="bullet">-</span> 违规需要在 ADR 中记录决策理由和批准的例外情况</span><br></pre></td></tr></table></figure><p>宪法不告诉你"做什么功能"。它告诉你"在这个仓库里,怎么写代码才算合格"。宪法不可变,或只能通过正式的修正案来修改——Agent 在每一步都知道它的行为边界在哪里。</p><p>Pocock 在第 2 章中的批评"GSD、BMAD、Spec-Kit 这类方法通过接管流程来帮助你,但同时夺走了你的控制权",指的主要是这种刚性。在 OpenSpec 中,<code>proposal.md</code> 简单到你手动改一行就能用。在 Spec-Kit 中,流程是一个系统,离开流程的代价是失去了框架提供的验证和宪法检查。</p><p>两种选择的优劣没有绝对答案。如果团队在高度监管的行业开发(医疗、金融、政府),如果需要为审计留下完整的决策记录,如果面临多个团队并行开发同一代码库的协调复杂度——Spec-Kit 的刚性的价值远超其成本。如果是一个人在做 startup 的 MVP,每天需要快速迭代验证方向——OpenSpec 的轻量自由更合适。用第 1 章的话说:<strong>工具的选择取决于你的"信号需求"——你需要多强的信号来确定代码在做你期望它做的事。</strong></p><h3 id="3-3-3-Spec-Kit-中文增强版:spec-kit-zh"><a href="#3-3-3-Spec-Kit-中文增强版:spec-kit-zh" class="headerlink" title="3.3.3 Spec-Kit 中文增强版:spec-kit-zh"></a>3.3.3 Spec-Kit 中文增强版:spec-kit-zh</h3><p>Spec-Kit 生态中还有一个给中国开发者的项目:<strong>spec-kit-zh</strong>。不是简单的汉化——它针对中文开发环境做了几项实际适配:</p><ul><li><strong>完整的汉化输出</strong>:AI 生成的规格、任务、审查报告全部以中文输出。不是机翻,而是用中文技术写作的惯用表达重构了模板</li><li><strong>国内工具链适配</strong>:预设了 Gitee、极狐 GitLab、阿里云效 Codeup 的项目模板</li><li><strong>10+ 主流 AI 编码工具支持</strong>:除了 Claude Code、Codex、Copilot 之外,还包括通义灵码、文心快码等国内 AI 编码工具</li><li><strong>中文开发场景适配</strong>:在 constitution 模板中预设了符合国内团队习惯的编码规范、commit 规范、CR 流程</li></ul><p>这代表了 SDD 生态向中国市场的延伸——它标志着 SDD 不再是一个英语社区的孤立运动,而是正在形成全球化的工具生态。</p><h3 id="3-3-4-实战:用-Spec-Kit-生成贪吃蛇游戏"><a href="#3-3-4-实战:用-Spec-Kit-生成贪吃蛇游戏" class="headerlink" title="3.3.4 实战:用 Spec-Kit 生成贪吃蛇游戏"></a>3.3.4 实战:用 Spec-Kit 生成贪吃蛇游戏</h3><p>同一个贪吃蛇任务,用 Spec-Kit 走一遍,观察流程感的差异。</p><p><strong>第零步:<code>/speckit.constitution</code></strong></p><p>Spec-Kit 要求先定宪法。启动命令后,Agent 引导你逐条确定项目的不变法则:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/speckit.constitution</span><br></pre></td></tr></table></figure><blockquote><p>Agent: 我先建议一份宪法草案,你可以逐条确认或修改。</p></blockquote><p>生成的 <code>constitution.md</code>:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># constitution.md</span></span><br><span class="line"></span><br><span class="line"><span class="section">## 编码标准</span></span><br><span class="line"><span class="bullet">-</span> 语言:HTML/CSS/JavaScript(纯前端,无框架)</span><br><span class="line"><span class="bullet">-</span> 格式:2 空格缩进,单引号,分号结尾</span><br><span class="line"><span class="bullet">-</span> 禁止使用 var,使用 const/let</span><br><span class="line"></span><br><span class="line"><span class="section">## 测试要求</span></span><br><span class="line"><span class="bullet">-</span> 每个游戏逻辑函数必须有对应的单元测试</span><br><span class="line"><span class="bullet">-</span> 使用 Jest 或 Vitest 作为测试运行器</span><br><span class="line"><span class="bullet">-</span> 关键用户路径(开始→移动→吃食物→死亡→重新开始)必须有集成测试</span><br><span class="line"></span><br><span class="line"><span class="section">## 安全要求</span></span><br><span class="line"><span class="bullet">-</span> 不使用 eval() 或 innerHTML 注入</span><br><span class="line"><span class="bullet">-</span> localStorage 读写必须有 try-catch 包裹</span><br><span class="line"></span><br><span class="line"><span class="section">## 架构约束</span></span><br><span class="line"><span class="bullet">-</span> 游戏逻辑与渲染逻辑分离</span><br><span class="line"><span class="bullet">-</span> 状态管理集中在一个 gameState 对象中</span><br><span class="line"><span class="bullet">-</span> 新增 npm 依赖需要过审</span><br><span class="line"></span><br><span class="line"><span class="section">## 违规后果</span></span><br><span class="line"><span class="bullet">-</span> 代码审查时逐条对照宪法检查</span><br><span class="line"><span class="bullet">-</span> 违规禁止合入</span><br></pre></td></tr></table></figure><p><strong>第一步:<code>/speckit.specify</code></strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/speckit.specify 做一个贪吃蛇网页游戏。方向键控制,吃食物变长得分,</span><br><span class="line">撞墙或撞到自己结束。纯前端单文件。</span><br></pre></td></tr></table></figure><p>Agent 基于宪法和需求生成 <code>spec.md</code>:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Spec: 贪吃蛇网页游戏</span></span><br><span class="line"></span><br><span class="line"><span class="section">## 用户故事</span></span><br><span class="line"></span><br><span class="line"><span class="section">### US-1: 作为玩家,我可以用方向键控制蛇的移动</span></span><br><span class="line">验收标准:</span><br><span class="line"><span class="bullet">1.</span> 按下 ↑ 键,蛇向上移动一格</span><br><span class="line"><span class="bullet">2.</span> 按下 ↓ 键,蛇向下移动一格</span><br><span class="line"><span class="bullet">3.</span> 按下 ← 键,蛇向左移动一格</span><br><span class="line"><span class="bullet">4.</span> 按下 → 键,蛇向右移动一格</span><br><span class="line"><span class="bullet">5.</span> 蛇不能反向移动(如当前向右时,← 键无效)</span><br><span class="line"></span><br><span class="line"><span class="section">### US-2: 作为玩家,吃到食物后蛇变长、分数增加</span></span><br><span class="line">验收标准:</span><br><span class="line"><span class="bullet">1.</span> 蛇头碰到食物格子时,食物消失,蛇长度 +1</span><br><span class="line"><span class="bullet">2.</span> 分数显示 +10</span><br><span class="line"><span class="bullet">3.</span> 新食物立即在空白位置随机生成</span><br><span class="line"><span class="bullet">4.</span> 新食物不与蛇身位置重叠</span><br><span class="line"></span><br><span class="line"><span class="section">### US-3: 作为玩家,撞墙或撞到自己时游戏结束</span></span><br><span class="line">验收标准:</span><br><span class="line"><span class="bullet">1.</span> 蛇头坐标超出 20×20 网格边界 → 游戏结束</span><br><span class="line"><span class="bullet">2.</span> 蛇头坐标与蛇身任一格子重叠 → 游戏结束</span><br><span class="line"><span class="bullet">3.</span> 游戏结束时显示最终得分</span><br><span class="line"><span class="bullet">4.</span> 显示"重新开始"按钮,点击后重置游戏</span><br><span class="line"></span><br><span class="line"><span class="section">### US-4: 作为玩家,最高分在刷新后保留</span></span><br><span class="line">验收标准:</span><br><span class="line"><span class="bullet">1.</span> 游戏结束时如果当前分数 > 历史最高分,更新最高分</span><br><span class="line"><span class="bullet">2.</span> 最高分存储在 localStorage 中</span><br><span class="line"><span class="bullet">3.</span> 刷新页面后最高分仍然显示</span><br><span class="line"><span class="bullet">4.</span> localStorage 不可用时游戏正常运行(仅当前分数可用)</span><br><span class="line"></span><br><span class="line"><span class="section">## 非功能需求</span></span><br><span class="line"><span class="bullet">-</span> NFR-1: 游戏循环间隔 150ms</span><br><span class="line"><span class="bullet">-</span> NFR-2: 首次渲染时间 < 500ms</span><br><span class="line"><span class="bullet">-</span> NFR-3: 不依赖任何外部库或框架</span><br></pre></td></tr></table></figure><p><strong>第二步:<code>/speckit.clarify</code>(可选)</strong></p><p>执行 <code>/speckit.clarify</code>,Agent 会再扫一轮规格中的模糊点:</p><blockquote><p>Agent: 有一个歧义需要澄清——蛇的初始方向是什么?我建议初始方向为"静止",玩家按下第一个方向键后蛇才开始移动。这样可以避免玩家还没准备好蛇就撞墙了。</p></blockquote><p>用户同意。这条澄清被追加到 US-1 的第 6 条验收标准中。</p><p><strong>第三步:<code>/speckit.plan</code></strong></p><p>Agent 读取 <code>spec.md</code> 和 <code>constitution.md</code>,生成 <code>plan.md</code>:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Plan: 贪吃蛇网页游戏</span></span><br><span class="line"></span><br><span class="line"><span class="section">## 架构概览</span></span><br></pre></td></tr></table></figure><p>index.html<br>├── <canvas id="game"> ← 游戏画布(400×400px)<br>├── <div id="score-board"> ← 分数面板<br>└── <div id="game-over-modal"> ← 结束弹窗</p><p>snake-game.js<br>├── gameState ← 集中状态管理<br>│ ├── snake: [{x, y}] ← 蛇身坐标数组<br>│ ├── food: {x, y} ← 食物坐标<br>│ ├── direction: 'UP'|'DOWN'|'LEFT'|'RIGHT'<br>│ ├── score: number<br>│ └── isGameOver: boolean<br>├── gameLoop() ← 150ms 间隔主循环<br>├── moveSnake() ← 蛇身移动逻辑<br>├── checkCollision() ← 碰撞检测(墙壁 + 自身)<br>├── checkFoodCollision() ← 食物碰撞检测<br>├── spawnFood() ← 食物随机生成<br>├── saveHighScore() / loadHighScore() ← localStorage 读写<br>└── resetGame() ← 重置状态</p><p>game.test.js ← 单元测试</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">## 数据流</span><br><span class="line">键盘事件 → 更新 gameState.direction</span><br><span class="line"> → gameLoop 每 150ms 触发</span><br><span class="line"> → moveSnake() 计算新蛇头位置</span><br><span class="line"> → checkCollision() 检测墙壁/自身 → 可能设置 isGameOver</span><br><span class="line"> → checkFoodCollision() 检测食物 → 可能更新 score、spawnFood()</span><br><span class="line"> → drawGrid() / drawSnake() / drawFood() 重绘画布</span><br><span class="line"> → 更新 score-board DOM</span><br></pre></td></tr></table></figure><p><strong>第四步:<code>/speckit.tasks</code></strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/speckit.tasks</span><br></pre></td></tr></table></figure><p>Agent 将 plan 分解为依赖排序的任务,每个任务标注对应的验收标准:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Tasks</span></span><br><span class="line"></span><br><span class="line"><span class="section">## Task 1: 项目骨架与画布渲染(依赖:无)</span></span><br><span class="line"><span class="bullet">-</span> 创建 index.html 和 snake-game.js</span><br><span class="line"><span class="bullet">-</span> 初始化 400×400 Canvas</span><br><span class="line"><span class="bullet">-</span> 实现 drawGrid / drawSnake / drawFood</span><br><span class="line"><span class="bullet">-</span> 覆盖:US-1 的前置条件(网格可见)</span><br><span class="line"><span class="bullet">-</span> 验证:打开页面看到空白网格</span><br><span class="line"></span><br><span class="line"><span class="section">## Task 2: 游戏状态管理与蛇的移动(依赖:Task 1)</span></span><br><span class="line"><span class="bullet">-</span> 实现 gameState 对象</span><br><span class="line"><span class="bullet">-</span> 实现 moveSnake() 和方向校验(禁止反向)</span><br><span class="line"><span class="bullet">-</span> 实现 150ms gameLoop</span><br><span class="line"><span class="bullet">-</span> 绑定键盘事件</span><br><span class="line"><span class="bullet">-</span> 覆盖:US-1 AC 1-5</span><br><span class="line"><span class="bullet">-</span> 验证:方向键控制蛇移动,不能反向</span><br><span class="line"></span><br><span class="line"><span class="section">## Task 3: 碰撞检测与食物系统(依赖:Task 2)</span></span><br><span class="line"><span class="bullet">-</span> 实现 checkCollision(墙壁 + 自身)</span><br><span class="line"><span class="bullet">-</span> 实现 checkFoodCollision(蛇头 vs 食物)</span><br><span class="line"><span class="bullet">-</span> 实现 spawnFood(随机、不与蛇重叠)</span><br><span class="line"><span class="bullet">-</span> 覆盖:US-2 AC 1-4, US-3 AC 1-2</span><br><span class="line"><span class="bullet">-</span> 验证:吃食物→变长得分,撞墙→游戏结束</span><br><span class="line"></span><br><span class="line"><span class="section">## Task 4: UI 与分数系统(依赖:Task 3)</span></span><br><span class="line"><span class="bullet">-</span> 实现分数面板 DOM 更新</span><br><span class="line"><span class="bullet">-</span> 实现游戏结束弹窗 + 重新开始按钮</span><br><span class="line"><span class="bullet">-</span> 实现 resetGame()</span><br><span class="line"><span class="bullet">-</span> 覆盖:US-3 AC 3-4, US-4 AC 1-4</span><br><span class="line"><span class="bullet">-</span> 验证:完整游戏流程 + 最高分持久化</span><br><span class="line"></span><br><span class="line"><span class="section">## Task 5: 测试(依赖:Task 4)</span></span><br><span class="line"><span class="bullet">-</span> 编写 game.test.js</span><br><span class="line"><span class="bullet">-</span> 游戏逻辑函数的单元测试</span><br><span class="line"><span class="bullet">-</span> 完整用户路径的集成测试</span><br><span class="line"><span class="bullet">-</span> 覆盖:所有 US 的所有 AC</span><br><span class="line"><span class="bullet">-</span> 验证:npm test 全部通过</span><br></pre></td></tr></table></figure><p>注意 Spec-Kit 和 OpenSpec 的一个关键差异:Spec-Kit 的 Task 5 是<strong>独立的测试任务</strong>——它把测试从实现中分离出来,要求你在实现完成后专门写一轮测试。而 OpenSpec 的 TDD 式工作流中,测试和实现在同一个垂直切片里交替进行。这是两种哲学的直接体现:Spec-Kit 更接近传统的"实现→验证"线性模型,OpenSpec 更接近 Pocock 的"RED→GREEN→REFACTOR"循环。</p><p><strong>第五步:<code>/speckit.implement</code></strong></p><p>Agent 从 Task 1 开始顺序执行。和 OpenSpec 的不同之处在于——每一步实现后,Agent 除了打勾任务之外,还会<strong>对照 constitution.md 检查合规性</strong>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">Agent: 开始 Task 1——项目骨架与画布渲染。</span><br><span class="line"> [创建文件,实现 Canvas 和渲染函数]</span><br><span class="line"> ✓ Task 1 完成</span><br><span class="line"> ✓ 宪法检查通过:无外部依赖、无 eval、使用 const/let</span><br><span class="line"></span><br><span class="line">Agent: 开始 Task 2——游戏状态管理与蛇的移动。</span><br><span class="line"> [实现 gameState、moveSnake、gameLoop、键盘监听]</span><br><span class="line"> ✓ Task 2 完成</span><br><span class="line"> ✓ 宪法检查通过:状态集中在 gameState 对象中</span><br><span class="line"> ⚠ 宪法提醒:gameLoop 和 moveSnake 可测试性不足——将在 Task 5 中补测试</span><br><span class="line"></span><br><span class="line">Agent: 开始 Task 3——碰撞检测与食物逻辑。</span><br><span class="line"> [...]</span><br><span class="line"></span><br><span class="line">Agent: 开始 Task 4——UI 与分数系统。</span><br><span class="line"> [...]</span><br><span class="line"></span><br><span class="line">Agent: 开始 Task 5——测试。</span><br><span class="line"> [生成 game.test.js,运行 npm test]</span><br><span class="line"> ✓ 12 个单元测试通过</span><br><span class="line"> ✓ 2 个集成测试通过</span><br><span class="line"> ✓ 宪法检查通过:测试覆盖率 94%,超过 80% 门槛</span><br></pre></td></tr></table></figure><p><strong>第六步:<code>/speckit.checklist</code>(可选收尾)</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/speckit.checklist</span><br></pre></td></tr></table></figure><p>Agent 生成最终验证清单,逐条对照原规格:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">✓ US-1: 方向键控制(AC 1-6 全部满足)</span><br><span class="line">✓ US-2: 食物与分数(AC 1-4 全部满足)</span><br><span class="line">✓ US-3: 游戏结束(AC 1-4 全部满足)</span><br><span class="line">✓ US-4: 最高分持久化(AC 1-4 全部满足)</span><br><span class="line">✓ NFR-1: 游戏循环 150ms — 实测 148-152ms</span><br><span class="line">✓ NFR-2: 首次渲染 320ms < 500ms</span><br><span class="line">✓ NFR-3: 零外部依赖</span><br></pre></td></tr></table></figure><p>Spec-Kit 用了六个命令、五个任务、外加宪法检查和 checklist 收尾。流程比 OpenSpec 长,但每一步产出的文档和验证记录更完整。如果你在合规性要求的行业,这些记录就是审计轨迹——谁来审都能追溯"这个功能为什么长这样、谁在什么时间验证了它"。</p><hr><h2 id="3-4-AWS-Kiro:SDD-内置的-IDE"><a href="#3-4-AWS-Kiro:SDD-内置的-IDE" class="headerlink" title="3.4 AWS Kiro:SDD 内置的 IDE"></a>3.4 AWS Kiro:SDD 内置的 IDE</h2><p>如果 OpenSpec 和 Spec-Kit 是"在现有 AI 编码工具上加上规格工作流",AWS Kiro 则更进一步——它是一个从头开始以 SDD 为设计中心的完整 IDE。</p><p>Kiro 于 2025 年中期发布,架设在 Amazon Bedrock 之上(Claude 推理,Amazon Nova 高吞吐量代码生成),是 AWS 在 AI 编码工具领域的旗舰产品。它的定位很清晰:<strong>规格是工作单元(Unit of Work)。</strong> 不是聊天记录,不是 prompt,不是随手写的便签——是有结构、有版本、可审计的规格文件夹。</p><h3 id="3-4-1-三种工作流:覆盖开发的全场景"><a href="#3-4-1-三种工作流:覆盖开发的全场景" class="headerlink" title="3.4.1 三种工作流:覆盖开发的全场景"></a>3.4.1 三种工作流:覆盖开发的全场景</h3><p>Kiro 在 2026 年初将它的规格体系扩展为三种互补的工作流,每一种对应一种真实的开发场景:</p><p><strong>标准工作流(Standard)</strong>:最经典的 SDD 模式——用户描述需求,Kiro 生成三份文档。</p><ul><li><code>requirements.md</code>:使用 <strong>EARS 格式</strong>(Easy Approach to Requirements Syntax)编写,一种受 IEEE 标准启发但大幅简化的需求语法。它强制每个需求写清楚触发条件("当用户点击保存按钮时")、系统响应("系统应将偏好写入 localStorage")、异常处理("如果 localStorage 不可用,系统应回退到默认值并输出 console.warn")</li><li><code>design.md</code>:技术设计——组件层次、数据流、序列图、API 契约、数据库 schema</li><li><code>tasks.md</code>:依赖排序的任务列表,每个任务绑定对应的测试</li></ul><p><strong>设计先行工作流(Design-First)</strong>:为"我已经想好技术方案了,帮我把它形式化"的场景而设计。开发者从一个已有的架构想法开始——可能是手绘的组件图、伪代码、甚至是一段被否掉的原型代码——Kiro 反向推导出 <code>requirements.md</code> 和 <code>design.md</code>,再正向生成 <code>tasks.md</code>。这个工作流降低了 SDD 的入场门槛——不需要从空白需求开始,可以从已有的设计出发。AWS 的 Stephanie Walter 评价说:"这是 Kiro 承认了现实——开发者的行为习惯胜过方法论的说教。先构思再形式化,这种混合策略让 SDD 更容易被团队接受。"</p><p><strong>Bugfix 工作流</strong>:这是三种工作流中最特别的一个,因为它代表了一种"外科手术式"的精确变更模式。在一个有几十万行代码的存量项目中,为了修一个 bug 写一份完整的功能规格是多余的开销。Bugfix 工作流只要求三样东西:</p><ul><li><strong>当前行为(Current Behavior)</strong>:WHEN-THEN 格式,精确描述 bug 的表现。"WHEN 用户在 Firefox 隐私窗口中打开设置页 THEN 页面白屏,console 报 <code>QuotaExceededError</code>"</li><li><strong>期望行为(Expected Behavior)</strong>:修复后应该发生什么。"WHEN 用户在 Firefox 隐私窗口中打开设置页 THEN 页面正常渲染,主题回退到跟随系统,console 输出警告而非报错"</li><li><strong>不变行为(Unchanged Behavior)</strong>:明确声明"修复这个 bug 时绝对不能破坏什么"——这是最容易被忽略但最重要的一条。"应用主题切换功能的所有其他行为应保持不变。localStorage 可用时的偏好保存逻辑不应被修改。相关的单元测试应继续通过。"</li></ul><p>Kiro 基于这三份描述生成两类测试:确认 bug 存在的测试(验证修复前行为)和属性测试(Property-Based Tests)——验证修复后不变行为未被破坏。这种设计将一次性的调试行为转化为持久化的测试资产,与第 2 章中 <code>/diagnose</code> 的 Phase 5(回归测试)一脉相承。</p><h3 id="3-4-2-Steering-Files:Agent-的持久记忆"><a href="#3-4-2-Steering-Files:Agent-的持久记忆" class="headerlink" title="3.4.2 Steering Files:Agent 的持久记忆"></a>3.4.2 Steering Files:Agent 的持久记忆</h3><p>Kiro 的另一个原创概念是 <strong>Steering Files</strong>(引导文件)——放在 <code>.kiro/steering/</code> 目录下的持久化 Markdown 文件,编码了跨会话的约束和知识。它的逻辑与第 2 章中 Pocock 的 <code>CONTEXT.md</code> 高度同构,但结构性更强:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">.kiro/</span><br><span class="line">├── steering/</span><br><span class="line">│ ├── coding-standards.md ← 编码规范(类似 ESLint 配置的精神,但用自然语言)</span><br><span class="line">│ ├── architecture.md ← 架构约束(不可触及的模块边界)</span><br><span class="line">│ ├── security.md ← 安全要求(认证模型、数据加密、敏感信息处理)</span><br><span class="line">│ ├── dependencies.md ← 依赖策略(新增库必须过审、版本锁定规则)</span><br><span class="line">│ └── testing.md ← 测试标准(覆盖率门槛、测试类型要求)</span><br><span class="line">└── specs/</span><br><span class="line"> └── add-dark-mode/</span><br><span class="line"> ├── requirements.md</span><br><span class="line"> ├── design.md</span><br><span class="line"> └── tasks.md</span><br></pre></td></tr></table></figure><p>Steering Files 和规格(specs)之间的关系很像第 2 章中的"全局 Skill"和"任务级指令"之间的关系。Steering Files 是"凡是这个项目的东西都要遵守"的跨功能约束,规格是"这个功能要实现的"功能级行为。两者都存放在 <code>.kiro/</code> 目录中,一起构成了项目的 AI 开发环境。</p><h3 id="3-4-3-Kiro-的位置:重量级-SDD-的企业端"><a href="#3-4-3-Kiro-的位置:重量级-SDD-的企业端" class="headerlink" title="3.4.3 Kiro 的位置:重量级 SDD 的企业端"></a>3.4.3 Kiro 的位置:重量级 SDD 的企业端</h3><p>Kiro 带来的不只是功能,更是一种工作方式的选择。它的存在主义问题是:<strong>为了获得治理能力、审计能力、安全控制,你愿意放弃多少灵活性?</strong></p><p>答案取决于场景。Dion Hinchcliffe(The Futurum Group)对此的判断是:"企业要回答的问题不是'这个工具慢不慢',而是'它能不能在可测量的程度上降低变更失败率和平均恢复时间'。"</p><p>Kiro 的定价也体现了它的定位:从免费层(50 credits/月)到 Power 层($200/月,10,000 credits)。多模型支持意味着不同复杂度的任务可以使用不同成本的模型——简单的格式化用 Qwen(0.05x),复杂的架构设计用 Claude(1x)。这和 Kiro 的"按场景选择工具"哲学一以贯之。</p><p>但 Kiro 有几个局限不全是 bug,一定程度上是 SDD 作为方法论的固有张力:</p><ul><li><strong>SDD 引入额外开销。</strong> 为一句话的改动("把按钮颜色换成蓝色")走完 <code>requirements → design → tasks → implement</code> 全流程是荒谬的。Kiro 官方的回应是"不是所有任务都需要 SDD"——但这个判断需要使用者自己下,Kiro 并没有自动推荐合适的工作流。</li><li><strong>EARS 格式可能产生"假精度"。</strong> 格式良好的需求不等于内容正确的需求。一个需求可以完美地遵循 EARS 语法,同时描述的行为完全是错的。形式不保证实质。</li><li><strong>规格漂移仍然存在。</strong> Kiro 的规格是在开发前生成的,实施完成后不会自动更新。除非配置 Agent Hooks 来检测漂移,否则规格和实现之间的鸿沟会默默扩大。</li></ul><p>Kiro 在 2026 年代表的是"企业重量级"这一端——与 OpenSpec 的自由轻量、Spec-Kit 的治理完备构成一个从轻到重的连续选择区间。</p><h3 id="3-4-4-实战:用-Kiro-生成贪吃蛇游戏"><a href="#3-4-4-实战:用-Kiro-生成贪吃蛇游戏" class="headerlink" title="3.4.4 实战:用 Kiro 生成贪吃蛇游戏"></a>3.4.4 实战:用 Kiro 生成贪吃蛇游戏</h3><p>还是同一个贪吃蛇任务。在 Kiro 中,你不需要先安装任何 CLI 或配置目录结构——打开 IDE,创建一个空白项目,直接在 Kiro 的规格面板中开始。</p><p><strong>选择工作流:Standard</strong></p><p>Kiro 启动后弹出工作流选择:Standard / Design-First / Bugfix。选 Standard——我们从一个自然语言需求开始。</p><p><strong>第一步:编写需求,Kiro 生成 EARS 格式规格</strong></p><p>在 Kiro 的规格编辑器中输入:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">做一个贪吃蛇网页游戏。方向键控制蛇移动,吃食物后蛇变长、分数增加。</span><br><span class="line">撞墙或撞到自己则游戏结束。纯前端单文件实现,最高分用 localStorage 保存。</span><br></pre></td></tr></table></figure><p>Kiro 读取这段描述,生成 <code>requirements.md</code>——使用 EARS 格式:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Requirements: 贪吃蛇网页游戏</span></span><br><span class="line"></span><br><span class="line"><span class="section">## R1: 游戏初始化</span></span><br><span class="line">WHEN 玩家打开页面时,</span><br><span class="line">THE SYSTEM SHALL 渲染一个 20×20 的游戏网格,</span><br><span class="line">AND 在网格中央放置一条长度为 3 的蛇,</span><br><span class="line">AND 在随机空白位置生成一个食物,</span><br><span class="line">AND 显示当前分数(初始为 0)和历史最高分。</span><br><span class="line"></span><br><span class="line"><span class="section">## R2: 蛇的移动</span></span><br><span class="line">WHEN 玩家按下方向键(↑ ↓ ← →)时,</span><br><span class="line">THE SYSTEM SHALL 更新蛇的移动方向为对应方向,</span><br><span class="line">UNLESS 新方向与当前方向相反(如当前向右时按 ←),</span><br><span class="line">IN WHICH CASE THE SYSTEM SHALL 忽略该按键输入。</span><br><span class="line"></span><br><span class="line">WHEN 游戏循环计时器(间隔 150ms)触发时,</span><br><span class="line">THE SYSTEM SHALL 将蛇头向当前方向移动一格,</span><br><span class="line">AND 从蛇尾移除一格。</span><br><span class="line"></span><br><span class="line"><span class="section">## R3: 食物消费</span></span><br><span class="line">WHEN 蛇头坐标与食物坐标重叠时,</span><br><span class="line">THE SYSTEM SHALL 移除该食物,</span><br><span class="line">AND 将蛇长度增加 1 格,</span><br><span class="line">AND 将当前分数增加 10 分,</span><br><span class="line">AND 在随机空白位置生成一个新食物。</span><br><span class="line"></span><br><span class="line">IF 没有空白格子可用(极罕见,蛇填满整个网格),</span><br><span class="line">THEN THE SYSTEM SHALL 判定玩家胜利,显示"你赢了!"并停止游戏循环。</span><br><span class="line"></span><br><span class="line"><span class="section">## R4: 碰撞与游戏结束</span></span><br><span class="line">WHEN 蛇头坐标超出 20×20 网格边界时,</span><br><span class="line">THE SYSTEM SHALL 判定游戏结束。</span><br><span class="line"></span><br><span class="line">WHEN 蛇头坐标与蛇身任一格子重叠时,</span><br><span class="line">THE SYSTEM SHALL 判定游戏结束。</span><br><span class="line"></span><br><span class="line">WHEN 游戏结束时,</span><br><span class="line">THE SYSTEM SHALL 停止游戏循环,</span><br><span class="line">AND 比较当前分数与 localStorage 中的最高分(若当前分更高则更新),</span><br><span class="line">AND 显示游戏结束弹窗(包含最终得分和"重新开始"按钮)。</span><br><span class="line"></span><br><span class="line"><span class="section">## R5: 重新开始</span></span><br><span class="line">WHEN 玩家点击"重新开始"按钮时,</span><br><span class="line">THE SYSTEM SHALL 重置蛇位置、蛇长度、移动方向、当前分数和食物位置,</span><br><span class="line">AND 重新启动游戏循环,</span><br><span class="line">AND 不重置 localStorage 中的最高分。</span><br><span class="line"></span><br><span class="line"><span class="section">## R6: 降级处理</span></span><br><span class="line">IF localStorage 不可用(隐私模式、存储已满),</span><br><span class="line">THEN THE SYSTEM SHALL 回退到内存存储(最高分仅在当前会话中保留),</span><br><span class="line">AND 在浏览器 console 中输出警告信息。</span><br><span class="line"></span><br><span class="line"><span class="section">## 非功能需求</span></span><br><span class="line"><span class="bullet">-</span> NFR1: 游戏循环间隔 150ms(±10ms 容差)</span><br><span class="line"><span class="bullet">-</span> NFR2: 页面首次渲染在 500ms 内完成</span><br><span class="line"><span class="bullet">-</span> NFR3: 无外部库或框架依赖</span><br><span class="line"><span class="bullet">-</span> NFR4: 键盘输入响应延迟 < 50ms</span><br></pre></td></tr></table></figure><p>EARS 的特征在此清晰:每条需求都以 WHEN/IF/THEN/SHALL/UNLESS 之一开头,触发条件和系统响应被强制分离。这种结构让自然语言需求变得可自动化验证——你可以写一个脚本逐条扫描需求文档,检查每条是否包含 WHEN 和 THEN 子句。</p><p><strong>第二步:Kiro 生成 design.md</strong></p><p>你确认需求后,Kiro 基于 <code>requirements.md</code> 和 <code>.kiro/steering/</code> 目录中的 Steering Files 生成 <code>design.md</code>。如果你还没有 Steering Files,Kiro 会提示你:"检测到 <code>.kiro/steering/</code> 为空。建议在实现前先配置 coding-standards.md 和 testing.md,或跳过此步直接使用默认设置。"</p><p>(这里我们假设已经配置了基础的编码规范。)</p><p><code>design.md</code> 的核心内容:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Design: 贪吃蛇网页游戏</span></span><br><span class="line"></span><br><span class="line"><span class="section">## 组件树</span></span><br></pre></td></tr></table></figure><p>index.html<br>└── <body><br> ├── <div class="game-container"><br> │ ├── <div class="score-board"> ← 当前分数 / 最高分<br> │ └── <canvas id="game-canvas"> ← 游戏画布 400×400<br> └── <div class="modal" id="game-over-modal"> ← 游戏结束弹窗<br> ├── <p class="final-score"><br> └── <button id="restart-btn"></p><p>snake-game.js<br>├── // === 状态层 ===<br>│ const state = {<br>│ snake: Array<{x: number, y: number}>,<br>│ food: {x: number, y: number},<br>│ direction: 'UP' | 'DOWN' | 'LEFT' | 'RIGHT',<br>│ nextDirection: 'UP' | 'DOWN' | 'LEFT' | 'RIGHT',<br>│ score: number,<br>│ highScore: number,<br>│ gameOver: boolean,<br>│ gameLoopId: number | null,<br>│ }<br>│<br>├── // === 逻辑层 ===<br>│ initGame(), moveSnake(), checkCollision(),<br>│ checkFoodCollision(), spawnFood(),<br>│ endGame(), resetGame()<br>│<br>├── // === 渲染层 ===<br>│ drawGrid(), drawSnake(), drawFood(),<br>│ updateScoreBoard(), showGameOverModal()<br>│<br>├── // === 持久化层 ===<br>│ loadHighScore(), saveHighScore()<br>│<br>└── // === 主循环 ===<br> gameLoop() → 每 150ms 调用一次</p><p>snake-game.test.js ← 单元测试 + 集成测试</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">## 序列图(游戏主循环的单次迭代)</span><br></pre></td></tr></table></figure><p>gameLoop() →<br> moveSnake() →<br> 计算新蛇头位置 →<br> 检查反向约束 →<br> 更新 state.snake<br> checkCollision() →<br> 墙壁碰撞?→ endGame()<br> 自身碰撞?→ endGame()<br> checkFoodCollision() →<br> 吃到食物?→ score += 10, spawnFood()<br> drawGrid() → drawSnake() → drawFood()<br> updateScoreBoard()</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">## 关键决策</span><br><span class="line">- 使用 `nextDirection` 缓冲解决快速连续按键的方向丢失问题</span><br><span class="line"> - 键盘事件写入 `nextDirection`,gameLoop 读取后同步到 `direction`</span><br><span class="line"> - 防止两帧之间多次按键导致蛇反向移动</span><br><span class="line">- Canvas API 而非 DOM 渲染:20×20 网格、400px 画布的渲染规模下 Canvas 性能更优</span><br></pre></td></tr></table></figure><p><strong>第三步:Kiro 生成 tasks.md</strong></p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Tasks: 贪吃蛇网页游戏</span></span><br><span class="line"></span><br><span class="line"><span class="section">## T1: 项目结构与渲染层 [预估:20min]</span></span><br><span class="line">依赖:无</span><br><span class="line"><span class="bullet">-</span> 创建 index.html 和 snake-game.js</span><br><span class="line"><span class="bullet">-</span> 初始化 Canvas 并实现 drawGrid / drawSnake / drawFood</span><br><span class="line">关联测试:testDrawGrid, testDrawSnake</span><br><span class="line">关联需求:R1</span><br><span class="line"></span><br><span class="line"><span class="section">## T2: 游戏状态管理与蛇的移动 [预估:30min]</span></span><br><span class="line">依赖:T1</span><br><span class="line"><span class="bullet">-</span> 实现 state 对象</span><br><span class="line"><span class="bullet">-</span> 实现 moveSnake() 和反向约束</span><br><span class="line"><span class="bullet">-</span> 实现 gameLoop()(150ms 间隔)</span><br><span class="line"><span class="bullet">-</span> 绑定键盘事件 → nextDirection</span><br><span class="line">关联测试:testMoveSnake, testDirectionReverseBlocked, testKeyboardBinding</span><br><span class="line">关联需求:R2</span><br><span class="line"></span><br><span class="line"><span class="section">## T3: 碰撞检测与食物系统 [预估:25min]</span></span><br><span class="line">依赖:T2</span><br><span class="line"><span class="bullet">-</span> 实现 checkCollision()(墙壁 + 自身)</span><br><span class="line"><span class="bullet">-</span> 实现 checkFoodCollision()、spawnFood()</span><br><span class="line">关联测试:testWallCollision, testSelfCollision, testFoodCollision, testSpawnFoodNotOnSnake</span><br><span class="line">关联需求:R3, R4</span><br><span class="line"></span><br><span class="line"><span class="section">## T4: 游戏结束与分数系统 [预估:20min]</span></span><br><span class="line">依赖:T3</span><br><span class="line"><span class="bullet">-</span> 实现 endGame()、showGameOverModal()</span><br><span class="line"><span class="bullet">-</span> 实现 loadHighScore()、saveHighScore()(含 localStorage 降级)</span><br><span class="line"><span class="bullet">-</span> 实现 updateScoreBoard()</span><br><span class="line">关联测试:testHighScorePersistence, testLocalStorageFallback</span><br><span class="line">关联需求:R4, R5, R6</span><br><span class="line"></span><br><span class="line"><span class="section">## T5: 重新开始与集成测试 [预估:15min]</span></span><br><span class="line">依赖:T4</span><br><span class="line"><span class="bullet">-</span> 实现 resetGame()</span><br><span class="line"><span class="bullet">-</span> 编写完整流程集成测试:开始→移动→吃食物→死亡→重新开始</span><br><span class="line">关联测试:testFullGameFlow</span><br><span class="line">关联需求:R5</span><br></pre></td></tr></table></figure><p>注意 Kiro 在 tasks.md 中多了一个字段:<strong>关联测试</strong>和<strong>关联需求</strong>。每个任务都明确标注了它覆盖哪些需求、对应哪些测试。这不是装饰——Kiro 的 Agent Hooks 会在实现完成后自动做追溯验证:运行关联测试,检查通过状态,确认每条需求的关联测试全部通过后才标记"完成"。这是 Kiro 在 SDD 三个工具中独有的能力——需求到测试的追溯矩阵是自动维护的,不需要手动管理。</p><p><strong>第四步:实现(Kiro 内置 Agent 执行)</strong></p><p>点击 "Implement All" 或逐个任务执行。Kiro 的 Agent 按 T1→T5 顺序执行,每个任务完成后自动运行关联测试。Steering Files 在整个过程中持续生效——Agent 在每次生成代码前都会检查 <code>.kiro/steering/</code> 中的约束:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">[T1] 实现中… → 检查 coding-standards.md → const/let, 单引号, 分号 ✓</span><br><span class="line">[T1] 运行关联测试 → testDrawGrid ✓, testDrawSnake ✓</span><br><span class="line">[T1] 完成 ✓</span><br><span class="line"></span><br><span class="line">[T2] 实现中… → 检查 coding-standards.md ✓</span><br><span class="line">[T2] 运行关联测试 → testMoveSnake ✓, testDirectionReverseBlocked ✓, testKeyboardBinding ✓</span><br><span class="line">[T2] 完成 ✓</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">[T5] 实现中…</span><br><span class="line">[T5] 运行关联测试 → testFullGameFlow ✓</span><br><span class="line">[T5] 运行全部测试套件 → 18/18 通过 ✓</span><br><span class="line">[T5] 完成 ✓</span><br></pre></td></tr></table></figure><p><strong>第五步:验证</strong></p><p>Kiro 自动弹出验证报告,追溯矩阵一目了然:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">需求追溯报告 — 贪吃蛇网页游戏</span><br><span class="line"></span><br><span class="line">R1 (游戏初始化) → testDrawGrid ✓, testDrawSnake ✓ → 覆盖 ✓</span><br><span class="line">R2 (蛇的移动) → testMoveSnake ✓, testDirectionReverseBlocked ✓, testKeyboardBinding ✓ → 覆盖 ✓</span><br><span class="line">R3 (食物消费) → testFoodCollision ✓, testSpawnFoodNotOnSnake ✓ → 覆盖 ✓</span><br><span class="line">R4 (碰撞与结束) → testWallCollision ✓, testSelfCollision ✓ → 覆盖 ✓</span><br><span class="line">R5 (重新开始) → testFullGameFlow ✓ → 覆盖 ✓</span><br><span class="line">R6 (降级处理) → testLocalStorageFallback ✓ → 覆盖 ✓</span><br><span class="line"></span><br><span class="line">NFR1 (150ms循环) → 实测 146-153ms ✓</span><br><span class="line">NFR2 (首次渲染) → 实测 280ms ✓</span><br><span class="line">NFR3 (零依赖) → 确认 ✓</span><br><span class="line">NFR4 (输入延迟) → 实测 8-14ms ✓</span><br><span class="line"></span><br><span class="line">全部 6 条需求覆盖通过,全部 4 条 NFR 满足。</span><br></pre></td></tr></table></figure><p>Kiro 在 2026 年的独特价值正是这个<strong>自动追溯</strong>。OpenSpec 和 Spec-Kit 都有验证机制,但两者都需要你手动运行验证命令或对照 checklist 检查。Kiro 因为规格、设计、任务、测试、Steering Files 都在同一个 IDE 环境内,能做到<strong>保存时自动验证</strong>——你改了一行代码,IDE 立刻告诉你"这个改动让 R3 的测试失败了"。这是 IDE 原生 SDD 独有的体验,也是 Kiro 和两个 CLI 工具之间最根本的差异。</p><p>三个工具,同一个贪吃蛇任务,三种不同的体验。OpenSpec 用三个命令一个归档走完全程——快,轻,存量为先。Spec-Kit 用六步流程加上宪法和 checklist——重,但每一步都有完整的文档和治理记录。Kiro 把规格、设计、任务、测试、约束整合到一个 IDE 面板中——贵,但追溯矩阵和自动验证不需要你手动维护。</p><p>选哪个?如果你在给一个现存项目加功能,OpenSpec 的增量规格不会让你写无用的文档。如果你在新项目启动阶段、需要为六个月的多人协作建立治理框架,Spec-Kit 的宪法体系能省掉大量后续的争论。如果你的团队已经在 AWS 生态中、需要为审计和合规留存完整的追溯记录,Kiro 是当前最完善的盒装方案。工具的三岔路口没有正确选项——只有和你的现状最匹配的选项。</p><hr><h2 id="3-5-SDD-的关键原则"><a href="#3-5-SDD-的关键原则" class="headerlink" title="3.5 SDD 的关键原则"></a>3.5 SDD 的关键原则</h2><p>三个工具的细节讨论完了。现在提炼<strong>跨工具的通用原则</strong>。不管你选 OpenSpec、Spec-Kit、Kiro,还是自己写 Makefile 手工管理规格,这些原则都成立。</p><h3 id="3-5-1-规格先行,代码在后"><a href="#3-5-1-规格先行,代码在后" class="headerlink" title="3.5.1 规格先行,代码在后"></a>3.5.1 规格先行,代码在后</h3><p>这是 SDD 最核心的原则,也是它和 Vibe Coding 最根本的区别。</p><p>"先写规格再写代码"的本质:<strong>冻结了承诺与验证之间的间隙。</strong> 在 Vibe Coding 中,承诺和验证发生在同一个时刻——对 AI 说"给我做一个登录页",看一眼产出的代码,"看起来不错",结束。事前没有定义"不错"的标准,事后没有对照标准来验证。用视觉直觉代替了工程判断。</p><p>在 SDD 中,承诺时间和验证时间被有意识地分离了。你先定义"登录页完成了"意味着什么——至少三条用户故事、六条验收标准、两条非功能需求——然后 AI 才被允许开始写代码。写完之后,你不是"看一眼",而是逐条对照规格中的验收标准来判定是否通过。</p><p>这个分离就是契约的本质。契约的价值不在措辞精确——在<strong>它独立于履约方存在</strong>。你可以用它评判任何代码:今天 AI 写的、明天人写的、后天另一个 AI 重构的。规格是判据,代码是答卷。</p><h3 id="3-5-2-规格是活文档"><a href="#3-5-2-规格是活文档" class="headerlink" title="3.5.2 规格是活文档"></a>3.5.2 规格是活文档</h3><p>SDD 中最难的不是"写一份好规格"——是"六个月后代码改了一百次,规格仍然是对的"。</p><p>这就是"活文档"原则的含义:<strong>规格不是写完就归档的一次性产出,而是随代码同步演进的系统真值。</strong> 它的反面是"僵尸规格"——曾经对过、现在已不反映现实、但还安静地躺在仓库里,没人敢删,也没人敢信。</p><p>僵尸规格比没有规格更危险。后者至少让人知道"我不确定这个东西的行为是什么",前者让人相信一个假的描述。AI Agent 尤其容易掉进这个陷阱——它不会怀疑一份 Markdown 文件的时效性。</p><p>活文档需要工具支撑。OpenSpec 用 <code>archive</code> 自动合并增量到主规格库;Spec-Kit 用 checklist 在实现后逐条验证;Kiro 用 Agent Hooks 在每次保存时检查漂移。工具各有不同,但原则相同:<strong>每次代码变更都必须触发一次规格的"是否仍然正确"的检查。</strong></p><h3 id="3-5-3-规格粒度适中"><a href="#3-5-3-规格粒度适中" class="headerlink" title="3.5.3 规格粒度适中"></a>3.5.3 规格粒度适中</h3><p>太粗的规格无法指导实现。"用户应该能管理自己的偏好"——太模糊了,AI 可以理解成任何东西:偏好 API?偏好 UI?偏好持久化层?歧义空间太大。</p><p>太细的规格退化为瀑布式文档。"偏好页面的保存按钮应位于页面右下角,与取消按钮间距 16px,使用 primary 色号 #1890ff"——这种级别的细节应该在设计和实现阶段自然涌现,不应该在需求规格中预设。过早过细的规格消灭了实现过程中的合理探索空间。</p><p>"适中"的粒度是什么?一个实用的标尺:<strong>一个变更一个文件夹,包含 proposal + specs + design + tasks。</strong> Proposal 说清"为什么"和"什么范围";Specs 说清功能需求和非功能需求;Design 说清"技术怎么做";Tasks 说清"先做哪个后做哪个"。四个文件之间信息不重复,每个只承担一个维度的描述责任。</p><p>这个结构和第 2 章中 Pocock 的"一个 Skill 只做一件事"在本质上是同一个原则:<strong>关注点分离。</strong> 不要把所有信息塞进一份文档——分开写,让每个文档精确、短小、可独立更新。</p><h3 id="3-5-4-规格必须可验证"><a href="#3-5-4-规格必须可验证" class="headerlink" title="3.5.4 规格必须可验证"></a>3.5.4 规格必须可验证</h3><p>一个验收标准写成"主题切换应该流畅"是无效的。"流畅"是一个主观形容词——你、我、AI 对"流畅"的定义各不相同。你对 AI 说"这个切换不够流畅",AI 不知道你的意思是慢了 100ms、卡了一帧、还是动画曲线不对。</p><p>正确的写法是:"当用户切换主题时,页面应在 100ms 内应用新的主题样式,视觉上没有可见的闪烁或样式跳跃。"这个描述可测量、可自动化测试、可被 Agent 验证。AI 知道"做完"的标准。</p><p>SDD 的精髓在这里:<strong>规格的质量由可验证性决定,不由可读性决定。</strong> 一个自检问题:你能写一个自动化测试来验证这条规格吗?如果不能,这条规格就不完整。</p><p>几个提升可验证性的技巧:</p><ul><li>每条验收标准关联至少一个测试用例</li><li>用数字代替副词——"应快速加载"变成"应在 200ms 内完成加载"</li><li>穷举边界条件——"当输入为空时"、"当输入超过长度限制时"、"当网络不可用时"</li><li>用"如果 X,那么 Y"代替"应该支持 X"——明确触发条件和预期结果</li></ul><h3 id="3-5-5-规格应与平台和模型解耦"><a href="#3-5-5-规格应与平台和模型解耦" class="headerlink" title="3.5.5 规格应与平台和模型解耦"></a>3.5.5 规格应与平台和模型解耦</h3><p>这是第 2 章中 Pocock 的"模型无关"原则在规格层面的自然延伸。好的规格用 Markdown 写,存放在 Git 仓库中,可以被任何 AI 编码工具读取。它不绑定 Claude Code 的 <code>/opsx</code> 前缀,不绑定 Kiro 的 <code>.kiro/</code> 目录结构,不绑定任何模型的特定 API。</p><p>这个原则在 2026 年特别重要,因为工具生态在快速变化。今天用 Claude Code + OpenSpec,明天团队可能换到 Copilot + Spec-Kit。如果规格是平台绑定的,迁移成本会阻止你作出正确的工具决策。如果规格是纯 Markdown,迁移只意味着改变目录结构和命令前缀——核心的规格资产不受影响。</p><h2 id="3-6-三个工具的对比"><a href="#3-6-三个工具的对比" class="headerlink" title="3.6 三个工具的对比"></a>3.6 三个工具的对比</h2><p>OpenSpec、Spec-Kit、Kiro 是 SDD 的三种选择,不是三个竞争品。它们的差异本质上是对几个核心权衡的不同立场。</p><table><thead><tr><th>维度</th><th>OpenSpec</th><th>Spec-Kit</th><th>Kiro</th></tr></thead><tbody><tr><td><strong>理念</strong></td><td>流动的增量</td><td>刚性宪法 + 全生命周期</td><td>SDD 内置 IDE,规格即工作单元</td></tr><tr><td><strong>强制力</strong></td><td>引导(建议走提案→归档)</td><td>刚性阶段门(框架强烈建议按序执行)</td><td>内置工作流(三种模式可选切换)</td></tr><tr><td><strong>安装复杂度</strong></td><td>低(npm install)</td><td>中(Python 3.11 + uv + GitHub Token)</td><td>中(IDE 安装,需 AWS 账号)</td></tr><tr><td><strong>核心创新</strong></td><td>Delta Specs(增量规格),brownfield 优先</td><td>constitution.md(项目宪法)</td><td>Steering Files + EARS 需求语法</td></tr><tr><td><strong>规格管理</strong></td><td>增量合并 + 版本归档</td><td>宪法约束 + 全文档生成</td><td>工作流模式驱动 + Hooks 自动检测</td></tr><tr><td><strong>模型/平台依赖</strong></td><td>无</td><td>无(但 Python 运行时)</td><td>AWS Bedrock(但支持多模型)</td></tr><tr><td><strong>AI 工具支持</strong></td><td>25+</td><td>30+</td><td>Kiro IDE/CLI(不支持外部 Agent 平台)</td></tr><tr><td><strong>中文适配</strong></td><td>社区 fork(openspec-cn)</td><td>官方中文版(spec-kit-zh)</td><td>支持中文输出</td></tr><tr><td><strong>CI/CD</strong></td><td>强(<code>openspec validate --json</code>)</td><td>中(有限的 CLI 支持)</td><td>中(通过 Agent Hooks)</td></tr><tr><td><strong>最佳场景</strong></td><td>存量项目、快速迭代、个人/小团队</td><td>新项目、合规性行业、大团队</td><td>重度 AWS 环境、企业治理、安全审计</td></tr></tbody></table><p>这个对比表的用意不是"选一个最好的"——根据自己的真实需求找到适合自己的工具。许多团队在实践中走混合路径:用 Kiro 做需求分析和架构设计,用 OpenSpec 管理增量变更,用 Spec-Kit 的宪法思想为仓库添加一个 <code>CONTRACT.md</code> 文件。工具可以组合,原则不变。</p><h2 id="3-7-本章小结"><a href="#3-7-本章小结" class="headerlink" title="3.7 本章小结"></a>3.7 本章小结</h2><p>规格驱动开发不是 AI 时代的发明。它的思想根源可以追溯到 1843 年 Ada Lovelace 的第一个程序规格,经过 TDD、契约式设计、BDD、形式化方法四条线索的独立演进,在 2025-2026 年被 AI 编码工具的爆发催化成一个完整的工程范式。</p><p>SDD 的核心主张凝聚在一句话里:<strong>在 AI 时代,规格不是在浪费时间写文档——规格是你和 AI 之间最有效率的通信协议。</strong></p><p>这个通信协议有三层递进:Spec-First(写代码前先写好要做什么)、Spec-Anchored(规格与代码同步演进相互锚定)、Spec-as-Source(规格是唯一人工编辑的产物,代码从规格生成)。大多数生产项目应定位于 Spec-Anchored。</p><p>OpenSpec(46,000+ Stars)追求流动、轻量、存量项目优先——用增量规格和"归档即合并"降低 SDD 的入场成本。Spec-Kit(92,000+ Stars)追求治理、完整、合规性——用宪法文件和刚性阶段门保证全生命周期的规格一致性。AWS Kiro 则将 SDD 内置于完整 IDE 中,提供了三种互补的工作流。</p><p>不管用哪个工具,六条原则通用:<strong>规格先行,代码在后;规格是活文档;规格粒度适中;规格必须可验证;规格应与平台和模型解耦;选择与任务匹配的 SDD 层级。</strong></p><p><img src="/images/image-20260523132617879.png"></p><p>第 2 章回答了"一个可复用的 AI 工程能力单元应该如何设计"。本章回答了"当多个能力单元组合在一起时,它们之间的合约应该长什么样"。Skill 和 Spec 的关系是:<strong>Skill 定义怎么做(能力单元),Spec 定义做成什么样(合约)。</strong> 前者是工具,后者是判据。两者合一,才构成完整的 AI 工程化体系。</p><p>Spec 定义了一次需要做什么。当需求在多个迭代中持续演化、当需要 AI 在循环中逐步改进自己的产出时,Spec 本身还不够——还需要一个自我循环改进的机制:AI 实现了、验证了、发现不对劲、重新修改、再次验证、直到满足 Spec。这就是下一章的主题:Ralph Loop——自主循环开发。</p>
同分类推荐文章
- Understand-Anything:代码知识图谱 (2026-06-28 16:30:00)
- Anthropic 官方插件:AI Agent 的领域知识插件 (2026-06-28 16:00:00)
- agent-skills:用生产级工程纪律武装 AI Agent (2026-06-28 15:30:00)
建议继续学习
- agent-skills:用生产级工程纪律武装 AI Agent (累计阅读 2)