Open Spec使用教程
随着 Claude Code、Codex、Cursor 等 AI 编程工具越来越强,现在让 AI 完成一个完整功能已经不是什么难事。
麻烦反而变成了:
AI 写代码很快,但它不一定真正理解你想做什么。
比如我们直接告诉 AI:
1 | 给这个项目增加用户登录功能。 |
AI 很可能马上开始创建接口、修改数据库、增加依赖、设计 Token 机制。
等它全部写完以后,你才发现:
1 | 登录方式不是你想要的 |
这是目前 AI Coding 中很典型的问题。
而 OpenSpec 想解决的,就是让:
1 | 需求 → 代码 |
变成:
1 | 需求 |
也就是所谓的:
1 | Spec-Driven Development |
OpenSpec 并不是一个新的 Web 框架,也不会替代 Claude Code、Codex 或 Cursor。
它更像是开发者和 AI 编码助手之间的一层“协议”。
开发之前,先把:
1 | 为什么做 |
全部明确下来。
然后再允许 AI 开始修改代码。
这样,AI Coding 就不再是:
1 | 给一句 Prompt |
而变成:
1 | 先定义正确答案 |
一、OpenSpec 是什么,以及为什么需要它
传统 AI Coding 的基本流程通常是:
1 | 开发者 |
比如:
1 | 给系统增加 API 限流。 |
听起来很简单,但实际上里面包含大量没有明确的信息:
1 | 对谁限流? |
如果这些问题没有提前说明,AI 就必须自己猜。
而 OpenSpec 的思路是:
1 | 不要直接 Coding |
先建立一个 Change:
1 | 我要修改什么? |
然后逐步生成:
1 | Proposal |
最终再开始实现。
整个流程大致如下:
1 | 开发者提出需求 |
所以 OpenSpec 要解决的问题是:
1 | AI 写代码之前缺少明确约束。 |
对于简单 Demo,这种约束可能不重要。
但项目一旦变成:
1 | 长期维护 |
需求规范就会越来越重要。
OpenSpec 中最重要的两个概念
理解 OpenSpec,其实只需要先搞懂两个东西:
1 | Spec |
Spec:系统现在应该是什么样
OpenSpec 中:
1 | openspec/specs/ |
保存的是当前系统已经确认的正式规范。
例如:
1 | openspec/specs/ |
分别可能描述:
1 | 用户认证如何工作 |
因此可以把:
1 | openspec/specs/ |
理解成:
当前项目行为的长期知识库。
半年以后即使换了开发人员,甚至换了 AI Agent,只要读取 Specs,就应该能够知道:
1 | 这个系统目前应该怎么运行。 |
Change:系统准备发生什么变化
假设当前系统已经支持:
1 | 用户登录 |
现在准备增加:
1 | 用户退出登录 |
OpenSpec 不会立刻修改主 Spec。
而是先创建:
1 | openspec/changes/add-user-logout/ |
例如:
1 | openspec/ |
其中:
1 | openspec/specs/user-auth/spec.md |
表示:
1 | 当前系统正式规范 |
而:
1 | openspec/changes/add-user-logout/specs/user-auth/spec.md |
表示:
1 | 这次修改准备让 user-auth 发生什么变化 |
这部分也叫:
1 | Delta Spec |
Delta 就是:
1 | 变化量 |
所以可以简单理解:
1 | Specs |
二、安装 OpenSpec 并初始化项目
OpenSpec 本身是一个 CLI 工具,因此首先需要 Node.js。
可以检查当前版本:
1 | node --version |
如果得到类似:
1 | v22.23.0 |
就可以正常使用。
然后安装 OpenSpec:
1 | npm install -g @fission-ai/openspec@latest |
如果使用 pnpm:
1 | pnpm add -g @fission-ai/openspec@latest |
安装完成以后:
1 | openspec --version |
能够正常显示版本号,就说明安装成功。
初始化现有项目
假设项目结构:
1 | my-project/ |
进入:
1 | cd my-project |
执行:
1 | openspec init |
OpenSpec 会让你选择使用的 AI Coding 工具。
比如:
1 | Claude Code |
选择以后,OpenSpec 会自动生成对应 Agent 所需要的:
1 | Commands |
例如 Claude Code 项目中可能出现:
1 | .claude/ |
同时项目会增加:
1 | openspec/ |
目录。
基础结构一般类似:
1 | my-project/ |
如果希望指定 Agent,也可以:
1 | openspec init --tools claude,cursor |
如果暂时不需要绑定任何 Agent:
1 | openspec init --tools none |
后续 OpenSpec 更新以后,可以在项目中运行:
1 | openspec update |
更新项目中的 Agent Skill 和 Command。
一定要区分两种命令
第一次使用 OpenSpec 最容易踩的坑,就是混淆:
1 | openspec xxx |
和:
1 | /opsx:xxx |
前者属于:
1 | 终端命令 |
比如:
1 | openspec init |
这些应该输入:
1 | PowerShell |
而:
1 | /opsx:explore |
属于:
1 | AI Coding Agent |
应该输入:
1 | Claude Code |
等 AI 工具。
可以这样记:
1 | openspec xxx |
另外,不同 AI 工具对 OpenSpec Workflow 的展示方式可能不完全相同。
有的使用:
1 | /opsx:propose |
有的可能展示成:
1 | /opsx-propose |
还有一些 Agent 会直接通过 Skill 调用。
因此初始化完成以后,最好以:
1 | openspec init |
生成的实际提示为准。
三、OpenSpec 的完整开发工作流
OpenSpec 的流程可以概括为:
1 | Explore |
其中日常用得最多的是:
1 | Explore |
如果是比较重要的功能,则推荐完整使用:
1 | Explore |
下面用:
1 | 增加 API 限流 |
作为例子完整走一遍。
Explore:先分析,不要急着写代码
首先进入 Claude Code、Codex 或 Cursor。
执行:
1 | /opsx:explore |
然后描述需求:
1 | 我准备给项目增加 API 限流功能。 |
Explore 的特点是:
1 | 只分析 |
AI 可以先研究:
1 | 项目结构 |
然后告诉你:
1 | 应该在哪一层实现 |
这一步看起来会多花几分钟,但经常能够避免后面大量返工。AI Coding 里最浪费时间的,往往是方向写错以后的推倒重来,而代码写得慢反倒是小事。
Propose:把需求正式变成 Change
需求分析完成后执行:
1 | /opsx:propose add-api-rate-limit |
也可以直接描述:
1 | /opsx:propose 为公开 API 增加基于 Redis 的限流机制,每个客户端每分钟最多请求 100 次,超过以后返回 HTTP 429 |
然后 OpenSpec 会生成:
1 | openspec/changes/add-api-rate-limit/ |
一般包含:
1 | add-api-rate-limit/ |
这几个文件分别负责不同内容:
| 文件 | 作用 |
|---|---|
| proposal.md | 为什么做、准备改变什么 |
| specs/*/spec.md | 最终系统应该有什么行为 |
| design.md | 技术上如何实现 |
| tasks.md | AI 接下来要完成哪些任务 |
它们之间可以理解成:
1 | proposal |
Proposal 负责:
1 | Why |
Spec 负责:
1 | Behavior |
Design 负责:
1 | How |
Tasks 负责:
1 | Execution |
四、Proposal、Spec、Design 和 Tasks 应该怎么写
这四个文件看起来都在描述需求,但各有分工,混在一起写就失去了拆分的意义。
Proposal:说明为什么做,以及准备改变什么
例如:
1 | openspec/changes/add-api-rate-limit/proposal.md |
可以类似:
1 | # Add API Rate Limiting |
Proposal 要回答的是:
1 | 为什么要做? |
不要在这里写大量:
1 | Redis Lua 脚本 |
这些属于 Design。
所以可以记成:
1 | Proposal = Why + What |
Spec:定义什么叫“正确”
Spec 是 OpenSpec 最重要的部分。
例如:
1 | openspec/changes/add-api-rate-limit/specs/api-rate-limit/spec.md |
可以写:
1 | # Spec Delta |
这里完全没有规定:
1 | 必须使用 Redis SETEX |
它只规定:
1 | 系统最终必须表现成什么样。 |
这是 Spec 和 Design 的区别所在。
Spec 很接近:
1 | 验收标准 |
甚至可以直接对应测试。
例如:
1 | WHEN |
以后可以直接转成 Integration Test。
所以 OpenSpec 的思路是:
1 | 先定义什么叫做对 |
不用等 AI 写完以后再去判断它写得对不对。
Spec 中的 ADDED、MODIFIED、REMOVED
OpenSpec 的 Delta Spec 中常见:
1 | ## ADDED Requirements |
表示新增。
1 | ## MODIFIED Requirements |
表示修改。
1 | ## REMOVED Requirements |
表示删除。
例如已有:
1 | ### Requirement: User Login |
现在增加 Google 登录。
如果原来的邮箱登录没有改变:
1 | ## ADDED Requirements |
而如果原来:
1 | Session 7 天过期 |
现在修改成:
1 | Session 30 天过期 |
这才属于:
1 | ## MODIFIED Requirements |
还有一条规则要注意:
MODIFIED 应该写修改后的完整 Requirement,而不是只写变化的那一句。
否则归档时容易造成原有规范信息缺失。
Requirement 和 Scenario 的结构
OpenSpec Spec 中一般使用:
1 | ### Requirement: Name |
Requirement 下至少应该存在一个:
1 | #### Scenario: Name |
例如:
1 | ### Requirement: PDF Upload |
这里要特别注意标题层级:
1 | Requirement |
Scenario 不是三级标题。
另外规范最好使用:
1 | SHALL |
这类明确表达。
少写:
1 | 最好 |
因为 Spec 必须:
1 | 可以判断 |
例如:
1 | 系统应该拥有良好的性能。 |
就不是很好的规范。
因为:
1 | 什么叫良好? |
没法测试。
更好的写法:
1 | The search API SHALL return within 500 ms for 95% of requests under the defined test workload. |
至少它可以被验证。
Design:描述技术实现方式
如果 Proposal 解决:
1 | 为什么 |
Spec 解决:
1 | 系统最终应该怎么表现 |
那么 Design 解决:
1 | 怎么实现 |
例如:
1 | # Design |
如果涉及以下内容,Design 需要写得比较详细:
1 | 数据库改动 |
而如果只是:
1 | 修改按钮文字 |
Design 就可以相对简单。
Tasks:把规范拆成 AI 能执行的工作
最后生成:
1 | tasks.md |
例如:
1 | # Tasks |
Tasks 最好使用:
1 | - [ ] |
而不是:
1 | - |
因为 OpenSpec 可以通过 Checkbox 判断任务完成情况。
完成后:
1 | - [x] |
这样以后运行:
1 | openspec list |
就能看到类似:
1 | add-api-rate-limit 8/10 tasks |
五、Apply、Validate、Verify 和 Archive
Proposal、Spec、Design、Tasks 全部确认以后,才真正进入编码阶段。
这一步叫:
1 | Apply |
执行:
1 | /opsx:apply |
AI 会读取:
1 | proposal.md |
然后开始按照 Tasks 修改项目。
此时 AI 只需要按照已经确认的规范完成实现,不用再自己琢磨该怎么做。这也是 OpenSpec 和普通 Prompt Coding 的主要区别。
不要 Propose 完就直接 Apply
一个很常见的错误是:
1 | Propose |
这样其实会让 OpenSpec 退化成:
1 | AI 写代码之前 |
推荐的做法是:
1 | Propose |
OpenSpec 的用处就在这里:
代码还没写,你就能发现 AI 理解错了。
修改已经生成的 Change
如果原来 Spec 写的是:
1 | 100 requests/minute |
后来决定改成:
1 | 300 requests/minute |
最好不要直接修改代码。
应该先更新 OpenSpec。
例如让 AI:
1 | 把当前 API Rate Limit Change 修改为每分钟 300 次。 |
也可以使用:
1 | /opsx:update |
这样可以尽量保证几个 Artifact 之间保持一致。
Validate:检查规范有没有问题
日常推荐执行:
1 | openspec validate --all |
它可以检查:
1 | Spec 格式 |
例如某个 Requirement 没有 Scenario:
1 | ADDED "Rate limiting" must include at least one scenario |
或者 Scenario 标题层级写错,也可能被发现。
如果希望更严格:
1 | openspec validate --all --strict |
我的推荐是至少在两个阶段执行:
1 | Apply 之前 |
也就是:
1 | Propose |
然后:
1 | Apply |
Verify:检查实现是否真的符合规范
代码写完只是:
1 | Implementation Complete |
不代表:
1 | Requirement Complete |
例如 Spec 写:
1 | 超过限制返回 HTTP 429 |
结果 AI 实现成:
1 | HTTP 403 |
代码可能:
1 | 没有报错 |
但是:
1 | 实现 != Spec |
Verify 就是用来检查这种问题。
如果当前 OpenSpec Profile 中启用了 Verify Workflow(默认的 core Profile 不包含它,属于扩展 Workflow),可以使用:
1 | /opsx:verify |
让 Agent 对照:
1 | Proposal |
检查代码是否满足要求。
如果没有 Verify,可以运行下面的命令选择要启用的 Workflow:
1 | openspec config profile |
调整以后:
1 | openspec update |
重新生成 Agent 工作流。
对于复杂项目,我建议保留 Verify。
Sync 和 Archive 的区别
OpenSpec 还有:
1 | /opsx:sync |
它主要用于:
1 | 把当前 Change 中的 Delta Spec |
但 Change 本身仍然保持 Active。
也就是说:
1 | Sync |
而:
1 | Archive |
绝大多数普通功能开发可以直接:
1 | Archive |
只有 Change 生命周期很长,而中间已经有一部分稳定规范需要同步时,Sync 才用得上。
Archive:完成一次 OpenSpec 生命周期
功能完成以后:
1 | /opsx:archive |
或者终端:
1 | openspec archive add-api-rate-limit |
自动确认:
1 | openspec archive add-api-rate-limit -y |
Archive 通常会:
1 | 合并 Delta Spec |
例如:
1 | openspec/changes/add-api-rate-limit/ |
最终变成:
1 | openspec/changes/archive/2026-10-04-add-api-rate-limit/ |
此时:
1 | Change |
已经变成:
1 | 历史开发记录 |
而最终规范:
1 | api-rate-limit |
进入:
1 | openspec/specs/ |
成为:
1 | 当前系统事实 |
OpenSpec 的整个生命周期可以概括成:
1 | Change |
六、Claude Code、Codex 和 Cursor 中如何实际使用
OpenSpec 最适合和 AI Coding Agent 一起使用。
假设使用 Claude Code。
首先:
1 | cd my-project |
启动:
1 | claude |
然后:
1 | /opsx:explore |
告诉 Claude:
1 | 我准备增加文档搜索功能。 |
讨论完成以后:
1 | /opsx:propose add-document-search |
然后人工检查:
1 | openspec/changes/add-document-search/ |
重点查看:
1 | proposal.md |
终端运行:
1 | openspec validate add-document-search |
确认没有问题:
1 | /opsx:apply |
实现完成以后运行项目测试:
1 | pytest |
或者:
1 | npm test |
然后:
1 | /opsx:verify |
最后:
1 | /opsx:archive |
完整流程就是:
1 | 需求 |
Codex 和 Cursor 的逻辑一样,区别只在于:
1 | OpenSpec Workflow 如何暴露给 Agent |
某些工具会使用:
1 | Slash Commands |
有的则会通过:
1 | Skills |
调用。
因此最稳妥的方法是:
1 | 运行 openspec init |
而不是死记某一种固定 Command。
七、项目中的推荐实践
光会敲几条命令还用不好 OpenSpec,需要建立一套比较稳定的开发习惯。
一个 Change 尽量只解决一个问题
例如:
1 | 重构系统架构 |
如果全部写进:
1 | one-big-change |
后面一定很难维护。
更合理:
1 | add-rbac |
也就是尽量保持:
1 | One Change |
这样:
1 | Proposal 更清晰 |
Spec 写行为,Design 写实现
这是最值得记住的一条。
错误的 Spec:
1 | The system SHALL use Redis SETEX to store rate limit keys. |
这实际上是在规定技术实现。
更好的 Spec:
1 | The system SHALL limit each public client to 100 requests per minute. |
然后 Design 再写:
1 | Use Redis fixed-window counters. |
因此:
1 | Spec |
以后即使从 Redis 换成其他存储:
1 | Spec 可能完全不用改 |
已经开发一半的大项目,不要一次性补全部 Specs
很多人第一次给已有项目接 OpenSpec,会想:
1 | 让 AI 扫描整个项目 |
如果项目有几十万行代码,结果往往是:
1 | 文档很多 |
更推荐渐进式建立。
比如当前准备改:
1 | Authentication |
那就先完善:
1 | user-auth |
下一次修改:
1 | Document Upload |
再完善:
1 | document-upload |
随着项目持续开发:
1 | openspec/specs/ |
会逐渐覆盖真正重要和活跃的功能。
纯重构不一定需要 Spec
例如:
1 | 重命名变量 |
如果对:
1 | 用户可观察行为 |
没有任何变化,就没有必要硬写 Requirement。
这种 Change 可以在它的 .openspec.yaml(位于 openspec/changes/<change-name>/ 下)中配置:
1 | schema: spec-driven |
表示:
1 | 这个 Change 没有 Spec-Level Behavior Change |
但不要为了省时间,在真正存在行为变化时也跳过 Specs。
OpenSpec 最好和 Git 一起使用
比如:
1 | git switch -c feat/api-rate-limit |
创建 Change:
1 | /opsx:propose add-api-rate-limit |
先提交规范:
1 | git add . |
然后:
1 | /opsx:apply |
开发完成:
1 | git add . |
然后:
1 | /opsx:verify |
最后:
1 | /opsx:archive |
提交归档:
1 | git add . |
这样:
1 | Git |
记录:
1 | 代码什么时候变了 |
而:
1 | OpenSpec |
记录:
1 | 为什么变 |
两者互补。
PR Review 时也可以:
1 | 先看 proposal.md |
理解成本会明显降低。
八、一个完整实战示例
假设当前正在开发一个 RAG 项目,现在准备新增:
1 | 删除文档 |
表面看只是:
1 | DELETE /documents/{id} |
但实际涉及:
1 | 关系数据库 |
如果直接告诉 AI:
1 | 增加删除文档功能。 |
它很容易漏掉其中某一步。
使用 OpenSpec,可以先:
1 | /opsx:explore |
输入:
1 | 我准备给项目增加文档删除功能。 |
AI 分析完成以后:
1 | /opsx:propose add-document-delete |
然后:
1 | openspec/changes/add-document-delete/ |
可能出现:
1 | proposal.md |
Spec 可以包含:
1 | ## ADDED Requirements |
还可以增加权限场景:
1 | ### Requirement: Reject unauthorized deletion |
Design 则可以描述:
1 | 先验证 Owner |
Tasks 则拆成:
1 | - [ ] Add ownership validation |
然后执行:
1 | openspec validate add-document-delete |
没有问题后:
1 | /opsx:apply |
让 AI 开始开发。
实现完成后运行:
1 | pytest |
或者项目自己的:
1 | npm test |
随后:
1 | /opsx:verify |
最后:
1 | /opsx:archive |
这样一次开发完成以后,项目除了得到:
1 | 删除文档功能代码 |
还保存了:
1 | 为什么增加这个功能 |
常用命令速查
| 命令 | 作用 |
|---|---|
openspec init |
初始化 OpenSpec |
openspec update |
更新 Agent Workflow |
openspec list |
查看当前 Changes |
openspec list --specs |
查看现有 Specs |
openspec view |
查看 OpenSpec 状态 |
openspec show <name> |
查看某个 Change 或 Spec |
openspec validate <name> |
验证指定 Change |
openspec validate --all |
验证全部 OpenSpec 内容 |
openspec validate --all --strict |
严格验证 |
openspec archive <change> |
归档 Change |
openspec status |
查看状态 |
openspec schemas |
查看 Schema |
openspec config |
管理配置 |
AI Agent 中常用的命令:
1 | /opsx:explore |
分析需求。
1 | /opsx:propose |
建立 Change。
1 | /opsx:update |
修改规划。
1 | /opsx:apply |
正式实现。
1 | /opsx:verify |
检查代码是否满足规范。
1 | /opsx:archive |
结束并归档 Change。
如果只想记一套工作流,可以记:
1 | Explore |
总结
OpenSpec 的作用不在于让 AI 写代码更快,而是:
1 | 让 AI 更少把代码写错方向。 |
传统 AI Coding:
1 | Prompt |
而 OpenSpec:
1 | Idea |
当 Claude Code、Codex 这种 Agent 越来越强以后,代码生成能力已经不稀缺了,稀缺的是:
1 | 需求边界 |
如果没有这些东西,AI 越强,甚至可能:
1 | 越快地把错误方向实现完整。 |
OpenSpec 做的事情,就是在:
1 | 人类需求 |
和:
1 | AI 实现 |
之间建立一层可以长期保存、可以验证的规范。
第一次使用 OpenSpec,其实不用学得太复杂。
安装:
1 | npm install -g @fission-ai/openspec@latest |
进入项目:
1 | cd your-project |
初始化:
1 | openspec init |
然后进入 Claude Code、Codex 或 Cursor:
1 | /opsx:explore |
过程中用下面的命令检查规范:
1 | openspec validate --all |