引言:AI 写代码很快,但你确定它在写对的东西吗?
想象这样一个场景:
你对 Claude Code 说:"帮我添加一个深色模式功能。" Claude 立刻开始工作——创建 ThemeContext,修改 CSS,添加 LocalStorage 持久化……20 分钟后,代码写完了,看起来挺好。
但第二天,产品经理找到你:"为什么深色模式没有跟随系统偏好?为什么没有平滑过渡动画?这些不是应该有的吗?"
你回头一看,发现:
- 需求从未写下来 → AI 按照自己的理解实现了
- 边界条件没讨论 → "深色模式"可以有一百种理解方式
- 没有验收标准 → 做到什么程度算"完成"?
问题的本质是:AI 编程太快了,快到来不及对齐需求。
传统开发中,写代码前会有需求文档、技术设计、任务拆解——这些看似繁琐的环节,其实是人类和机器之间的"同步协议"。但在 AI 时代,这个协议被跳过了:
传统流程:
需求 → PRD → 技术设计 → 编码 → 测试 → 上线
│ │ │ │
└──────┴────────┴─────────┴─── 每个环节都有文档留存
AI 编程现状:
用户:一句话描述需求
↓
AI:直接开始写代码(基于自己的理解)
↓
用户:发现不对,重新描述
↓
AI:重写代码(可能理解还是不对)
↓
无限循环...
这就是为什么你经常会发现:
- AI 写了一堆代码,但不是你想要的
- 改了三遍,每次都偏离需求一点
- 最后不得不手动重写
你需要的是一个"规格说明书"(Spec),让 AI 先搞清楚要做什么,再动手写代码。
这就是 OpenSpec 要解决的问题:在 AI 编程时代,重新建立"需求→设计→实现"的规范流程,但保持轻量和灵活。
什么是 OpenSpec?
OpenSpec 是一个为 AI 编程设计的规格驱动开发(Spec-Driven Development, SDD)框架。
如果把 AI 编程比作"包工头带工人干活":
- 没有 OpenSpec → 你口头交代工人"把房子盖好",工人凭理解开工,结果盖成了别墅(你想要的是平房)
- 有了 OpenSpec → 你先画图纸、标尺寸、列材料清单,工人照着图纸干活,最后验收时一目了然
OpenSpec 的核心理念:
fluid not rigid → 不是瀑布流,而是可以随时调整
iterative not waterfall → 边做边改,不是一次性写死
easy not complex → 轻量简洁,不是厚重的文档
brownfield-first → 为已有代码库设计,不只是新项目
OpenSpec 做了什么?
OpenSpec 提供了一套标准化的文件结构和命令,让你和 AI 在开发前先对齐需求:
openspec/
├── specs/ # 系统当前的规格说明书(真理之源)
│ ├── auth/
│ │ └── spec.md # 认证模块的行为规范
│ ├── payments/
│ │ └── spec.md # 支付模块的行为规范
│ └── ui/
│ └── spec.md # UI 交互的行为规范
│
└── changes/ # 进行中的变更(每个变更一个文件夹)
├── add-dark-mode/ # 变更:添加深色模式
│ ├── proposal.md # 为什么做?做什么?
│ ├── design.md # 怎么做?技术方案
│ ├── tasks.md # 分步执行清单
│ └── specs/ # 对主规格的修改(增/改/删)
│ └── ui/
│ └── spec.md # 这个变更会如何修改 UI 规格
│
└── archive/ # 已完成的变更(历史存档)
└── 2025-01-24-fix-login-bug/
关键设计:Delta Specs(增量规格)
OpenSpec 最聪明的地方在于:它不要求你写完整的规格文档,而是只写变化的部分(Delta)。
# Delta for UI Spec
## ADDED Requirements
### Requirement: Dark Mode Support
The system SHALL provide a dark theme option...
## MODIFIED Requirements
### Requirement: Theme Persistence
The system MUST persist theme preference in localStorage.
(Previously: Session storage)
## REMOVED Requirements
### Requirement: Theme Auto-Detection
(Deprecated - replaced by manual toggle)
为什么这样更好?
传统方案的问题:
- 全量规格 → 每次改动都要重写整个文档(繁琐、容易遗漏)
- 口头需求 → 没有留存,AI 理解错了也无法追溯
OpenSpec 的增量方案:
- ✅ 只写变化的部分(ADDED/MODIFIED/REMOVED)
- ✅ 清晰展示"改了什么"(易于 Review)
- ✅ 自动合并到主规格(Archive 时)
- ✅ 支持并行开发(多个变更互不干扰)
OpenSpec 的工作流程:从"拍脑袋"到"有章法"
传统 AI 编程 vs OpenSpec 工作流
传统 AI 编程(混乱模式):
用户:"帮我添加深色模式"
↓
Claude:"好的,我来写代码..."
[创建 ThemeContext.tsx]
[修改 globals.css]
[添加 toggle 按钮]
↓
用户:"不对,我还需要系统偏好检测"
↓
Claude:"好的,我来补充..."
[修改代码]
↓
用户:"动画效果太生硬了"
↓
Claude:"我重新实现..."
[又改一遍]
↓
用户(抓狂):"算了,我自己改吧..."
OpenSpec 工作流(有序模式):
/opsx:propose add-dark-mode
↓
[Phase 1: 明确需求]
Claude 创建 proposal.md:
- Intent: 为什么要做?(用户反馈需要深色模式)
- Scope: 做什么?不做什么?
✓ 手动切换开关
✓ 系统偏好检测
✓ LocalStorage 持久化
✗ 自定义主题色(未来功能)
- Approach: 怎么做?(CSS 变量 + React Context)
↓
[Phase 2: 定义规格]
Claude 创建 specs/ui/spec.md(Delta):
### Requirement: Theme Toggle
- Scenario: 用户点击切换 → 主题立即切换
- Scenario: 刷新页面 → 保持之前的主题
- Scenario: 首次访问 → 跟随系统偏好
↓
[Phase 3: 技术设计]
Claude 创建 design.md:
- 技术选型:为什么用 Context 而不是 Redux?
- 架构决策:CSS 变量 vs CSS-in-JS?
- 数据流:ThemeProvider → Components → LocalStorage
↓
[Phase 4: 任务拆解]
Claude 创建 tasks.md:
- [ ] 1.1 创建 ThemeContext
- [ ] 1.2 添加 CSS 变量
- [ ] 1.3 实现 LocalStorage 持久化
- [ ] 1.4 添加系统偏好检测
- [ ] 2.1 创建 ThemeToggle 组件
- [ ] 2.2 添加平滑过渡动画
↓
/opsx:apply
[Claude 按任务清单逐项实现,每完成一项打勾]
↓
/opsx:verify
[验证实现是否符合规格]
✓ 所有任务完成
✓ 所有场景覆盖
⚠ 缺少动画过渡测试
↓
/opsx:archive
[将 Delta Specs 合并到主规格,变更存档]
核心流程图
OpenSpec 工作流
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
PROPOSE APPLY ARCHIVE
(规划) (实现) (归档)
│ │ │
创建变更文件夹 按任务清单编码 合并Delta到主规格
│ │ │
├─ proposal.md ├─ 读取 tasks.md │─ 移动到 archive/
├─ specs/ ├─ 逐项实现 │─ 更新主 specs/
├─ design.md └─ 打勾标记完成 └─ 保留完整历史
└─ tasks.md
OpenSpec 的四大核心组件
1. Proposal(提案):为什么做?做什么?
问题:如果不写 Proposal,会怎样?
想象一个真实场景:你对 AI 说"添加用户认证"。AI 开始写代码,但它需要猜测:
- 是用 Session 还是 JWT?
- 要不要支持第三方登录?
- 密码规则是什么?
- 要不要记住登录状态?
没有 Proposal,AI 会按自己的理解实现——很可能不是你想要的。
Proposal 的标准结构:
# Proposal: Add JWT Authentication
## Intent(意图)
当前系统使用 Session 认证,但移动端无法很好地支持 Cookie。
我们需要切换到 JWT 以支持跨平台访问。
## Scope(范围)
In scope:
- JWT token 生成和验证
- Token 刷新机制
- 现有 Session 迁移策略
Out of scope:
- OAuth 第三方登录(未来功能)
- 多设备管理(未来功能)
## Approach(方案)
使用 Access Token(15 分钟)+ Refresh Token(7 天)的双 Token 机制。
服务端用 Redis 存储 Refresh Token 黑名单(用于注销)。
Proposal 的作用:
- ✅ 明确边界(做什么、不做什么)
- ✅ 对齐认知(人类和 AI 达成一致)
- ✅ 指导后续工作(Specs、Design、Tasks 都基于此)
类比理解:
Proposal 就像建筑项目的"立项书":
- 没有立项书 → 施工队不知道要盖几层楼、用什么材料、预算多少
- 有了立项书 → 明确目标、范围、预算,施工方才能报价和动工
2. Specs(规格):系统应该如何表现?
问题:为什么需要 Specs?
代码会变,但行为契约应该稳定。Specs 描述的是"用户视角的系统行为",而不是实现细节。
Spec 的标准格式:
# Auth Specification
## Purpose
用户认证和会话管理。
## Requirements
### Requirement: JWT Token Issuance
系统 SHALL 在成功登录后签发 JWT access token 和 refresh token。
#### Scenario: 成功登录
- GIVEN 用户提供了有效的用户名和密码
- WHEN 用户提交登录表单
- THEN 系统返回 access token(有效期 15 分钟)
- AND 系统返回 refresh token(有效期 7 天)
- AND 用户被重定向到仪表盘
#### Scenario: 密码错误
- GIVEN 用户提供了错误的密码
- WHEN 用户提交登录表单
- THEN 系统显示"用户名或密码错误"
- AND 不返回任何 token
- AND 记录失败尝试次数
### Requirement: Token Refresh
系统 MUST 允许使用 refresh token 获取新的 access token。
#### Scenario: 刷新有效 token
- GIVEN access token 已过期但 refresh token 仍有效
- WHEN 客户端使用 refresh token 请求新 token
- THEN 系统签发新的 access token
- AND 保持 refresh token 不变
Spec 的关键要素:
| 元素 | 作用 |
|---|---|
## Purpose | 这个模块是干什么的 |
### Requirement | 具体的行为要求(用 SHALL/MUST/SHOULD) |
#### Scenario | 可验证的具体场景(Given-When-Then) |
| SHALL/MUST/SHOULD | RFC 2119 标准关键词(表示强制程度) |
为什么用 Given-When-Then?
这是 BDD(行为驱动开发)的标准格式,好处是:
- ✅ 可测试 → 可以直接转换为自动化测试
- ✅ 无歧义 → 明确输入、操作、预期结果
- ✅ 覆盖边界 → 正常情况 + 异常情况都能描述
Spec 是什么、不是什么?
✅ 应该写在 Spec 里:
- 用户可观察的行为(如"token 15 分钟过期")
- API 契约(输入、输出、错误码)
- 安全规则、性能要求、兼容性约束
❌ 不应该写在 Spec 里:
- 内部实现细节(如"用 bcrypt 哈希密码")→ 这是 Design 的内容
- 代码结构(如"创建 AuthService 类")→ 这是 Tasks 的内容
- 库和框架选择(如"用 jsonwebtoken 库")→ 这是 Design 的内容
快速判断:如果实现方式改变了,但外部行为不变,那就不应该写在 Spec 里。
3. Design(设计):如何实现?
问题:为什么需要 Design 文档?
Specs 说"要做什么",Design 说"怎么做"。没有 Design,AI 每次实现可能都不一样。
Design 的标准结构:
# Design: Add JWT Authentication
## Technical Approach
使用 `jsonwebtoken` 库生成和验证 JWT。
Token 存储在 HTTP-Only Cookie 中(防止 XSS)。
Refresh Token 用 Redis 管理黑名单(支持主动注销)。
## Architecture Decisions
### Decision: 为什么用 HTTP-Only Cookie 而不是 LocalStorage?
| 方案 | 优点 | 缺点 | 选择 |
|------|------|------|------|
| LocalStorage | 跨域方便、灵活 | 易受 XSS 攻击 | ❌ |
| HTTP-Only Cookie | 防 XSS | 需要配置 CORS | ✅ |
**结论**:安全优先,选择 HTTP-Only Cookie。
### Decision: 为什么用 Redis 黑名单而不是 Token 撤销列表?
- Refresh Token 本身无状态,撤销需要外部存储
- Redis 的 TTL 特性天然适合管理过期时间
- 性能:内存数据库,响应快
## Data Flow
用户登录 │ ▼ [POST /auth/login] │ ▼ 验证用户名密码 │ ├─ 失败 → 返回 401 │ └─ 成功 → 生成 JWT │ ├─ Access Token(payload: userId, 15min) └─ Refresh Token(payload: tokenId, 7days) │ ▼ 存储到 Cookie │ ▼ 返回 200 + 用户信息
## File Changes
- `src/auth/jwt.service.ts`(新建)
- `src/auth/auth.controller.ts`(修改)
- `src/middleware/auth.middleware.ts`(修改)
- `redis/config.ts`(新建)
Design 的价值:
- ✅ 记录决策理由 → 未来不会忘记"为什么当时这么选"
- ✅ 技术选型依据 → 不是拍脑袋,而是有权衡分析
- ✅ 数据流可视化 → ASCII 流程图一目了然
- ✅ 文件变更清单 → 明确哪些文件会被修改
类比理解:
Design 就像建筑的"施工图":
- Spec = 甲方需求:"房子要三室两厅、朝南、采光好"
- Design = 施工图:"用钢筋混凝土、梁柱尺寸、水电布线方案"
4. Tasks(任务清单):分步执行计划
问题:为什么需要 Tasks?
即使有了 Specs 和 Design,AI 也可能不知道从哪里开始、先做什么后做什么。Tasks 就是"施工步骤"。
Tasks 的标准格式:
# Tasks
## 1. JWT Infrastructure
- [ ] 1.1 安装 jsonwebtoken 和 @types/jsonwebtoken
- [ ] 1.2 创建 src/auth/jwt.service.ts
- [ ] 1.3 实现 generateAccessToken(userId)
- [ ] 1.4 实现 generateRefreshToken(userId)
- [ ] 1.5 实现 verifyToken(token)
## 2. Redis Setup
- [ ] 2.1 安装 ioredis
- [ ] 2.2 创建 redis/config.ts
- [ ] 2.3 实现 blacklistToken(tokenId, ttl)
- [ ] 2.4 实现 isTokenBlacklisted(tokenId)
## 3. API Endpoints
- [ ] 3.1 修改 POST /auth/login 返回 JWT
- [ ] 3.2 创建 POST /auth/refresh 端点
- [ ] 3.3 创建 POST /auth/logout 端点
- [ ] 3.4 更新 OpenAPI 文档
## 4. Middleware
- [ ] 4.1 修改 auth.middleware.ts 验证 JWT
- [ ] 4.2 处理 token 过期情况
- [ ] 4.3 添加 rate limiting(防暴力破解)
## 5. Testing
- [ ] 5.1 单元测试:jwt.service.spec.ts
- [ ] 5.2 集成测试:auth.controller.spec.ts
- [ ] 5.3 E2E 测试:登录 → 刷新 → 注销流程
Tasks 的最佳实践:
| 原则 | 说明 | 示例 |
|---|---|---|
| 小步快跑 | 每个任务 < 30 分钟 | ❌ "实现认证系统" → ✅ "创建 jwt.service.ts" |
| 层次化编号 | 用 1.1, 1.2 分组 | 便于引用"任务 1.3 卡住了" |
| 可验证性 | 明确"做完"的标准 | "实现 XX 函数"比"优化 XX"更清晰 |
| 依赖关系 | 按顺序列出 | 先装依赖,再写代码,最后写测试 |
Tasks 的核心作用:进度追踪
# 运行 /opsx:apply 时,AI 会:
[Reading tasks.md...]
Found 15 tasks, 8 completed, 7 remaining.
Working on task 2.3: 实现 blacklistToken...
[Creating redis/blacklist.ts...]
✓ Task 2.3 complete
Working on task 2.4: 实现 isTokenBlacklisted...
[Implementing query logic...]
✓ Task 2.4 complete
All tasks in section 2 complete!
Moving to section 3...
类比理解:
Tasks 就像宜家家具的"组装步骤说明书":
- 没有说明书 → 你不知道先装哪块板、哪个螺丝对应哪个孔
- 有了说明书 → 步骤 1、2、3 清清楚楚,跟着做就能组装好
实战:如何在 Claude Code 中使用 OpenSpec
Step 1: 安装和初始化
1.1 安装 OpenSpec(全局)
# 要求 Node.js 20.19.0 或更高
npm install -g @fission-ai/openspec@latest
1.2 进入项目目录并初始化
cd your-project
openspec init
初始化时会询问:
? 选择要配置的 AI 工具:
[ ] Amazon Q Developer
[ ] Cursor
[x] Claude Code ← 选中这个
[ ] Windsurf
[ ] GitHub Copilot
...
? 选择工作流配置文件:
[x] core (默认): propose, explore, apply, archive
[ ] custom: 自定义选择命令
? 确认创建 openspec/ 目录? Yes
初始化完成后,项目结构:
your-project/
├── .claude/
│ ├── commands/
│ │ └── opsx/
│ │ ├── propose.md # /opsx:propose 命令
│ │ ├── explore.md # /opsx:explore 命令
│ │ ├── apply.md # /opsx:apply 命令
│ │ └── archive.md # /opsx:archive 命令
│ │
│ └── skills/
│ ├── openspec-propose/
│ │ └── SKILL.md
│ ├── openspec-explore/
│ │ └── SKILL.md
│ ├── openspec-apply-change/
│ │ └── SKILL.md
│ └── openspec-archive-change/
│ └── SKILL.md
│
└── openspec/
├── config.yaml # OpenSpec 配置文件
├── specs/ # 主规格目录(真理之源)
└── changes/ # 变更目录(工作区)
关键:Claude Code 会自动识别 .claude/commands/ 和 .claude/skills/!
Step 2: 第一个 OpenSpec 变更
场景:为博客系统添加深色模式
2.1 启动变更
在 Claude Code 的聊天窗口输入:
/opsx:propose add-dark-mode
Claude 会:
- 创建
openspec/changes/add-dark-mode/目录 - 生成
proposal.md(提案) - 生成
specs/ui/spec.md(Delta 规格) - 生成
design.md(技术设计) - 生成
tasks.md(任务清单)
2.2 Review 生成的 Proposal
Claude 生成的 proposal.md 示例:
# Proposal: Add Dark Mode
## Intent
用户反馈在夜间使用时眼睛疲劳,希望提供深色主题选项。
同时,现代操作系统都支持系统级深色模式,我们的应用应该跟随系统偏好。
## Scope
In scope:
- 手动主题切换开关(light/dark)
- 系统偏好自动检测(首次访问时)
- 主题偏好持久化(localStorage)
- 平滑过渡动画
Out of scope:
- 自定义主题色(未来功能)
- 每页独立主题设置
- 定时自动切换
## Approach
使用 CSS 自定义属性(CSS Variables)实现主题切换。
React Context 管理主题状态(避免 prop drilling)。
LocalStorage 存储用户偏好。
如果 Proposal 不对,现在就可以修改!
例如,你发现"平滑过渡动画"不是刚需,可以移到"Out of scope",然后告诉 Claude:
我修改了 proposal,把动画移到未来功能了。请重新生成后续文档。
Claude 会重新生成 specs、design、tasks,基于你修改后的 Proposal。
2.3 Review 生成的 Delta Spec
Claude 生成的 specs/ui/spec.md(Delta):
# Delta for UI Spec
## ADDED Requirements
### Requirement: Theme Toggle
系统 SHALL 提供主题切换功能。
#### Scenario: 手动切换主题
- GIVEN 用户当前处于亮色模式
- WHEN 用户点击主题切换按钮
- THEN 界面立即切换到深色模式
- AND 偏好保存到 localStorage
#### Scenario: 首次访问检测系统偏好
- GIVEN 用户首次访问(无 localStorage 记录)
- WHEN 页面加载
- THEN 系统检测操作系统主题偏好
- AND 应用对应的主题(light 或 dark)
### Requirement: Theme Persistence
系统 MUST 持久化用户的主题偏好。
#### Scenario: 刷新页面保持主题
- GIVEN 用户已选择深色模式
- WHEN 用户刷新页面
- THEN 深色模式保持不变
这就是 Delta Spec 的威力:
- ✅ 只写新增的需求(ADDED)
- ✅ 清晰的场景描述(可以直接转换为测试)
- ✅ 未来 Archive 时会自动合并到主
openspec/specs/ui/spec.md
2.4 Review 生成的 Design
Claude 生成的 design.md:
# Design: Add Dark Mode
## Technical Approach
使用 CSS 自定义属性(CSS Variables)定义主题色。
React Context 管理全局主题状态。
LocalStorage API 持久化偏好。
## Architecture Decisions
### Decision: 为什么用 CSS Variables 而不是 CSS-in-JS?
| 方案 | 优点 | 缺点 | 选择 |
|------|------|------|------|
| CSS Variables | 原生浏览器支持、无运行时开销 | 不支持 IE11 | ✅ |
| CSS-in-JS (styled-components) | TypeScript 类型安全 | 运行时开销、包体积增大 | ❌ |
**结论**:项目已不支持 IE11,选择原生 CSS Variables。
### Decision: 为什么用 Context 而不是 Redux?
- 主题状态简单(只有 light/dark 两种)
- 不需要复杂状态管理
- 避免引入 Redux 依赖
## Data Flow
ThemeProvider (Context) │ ├─ 初始化时读取 localStorage ├─ 若无记录,检测系统偏好(matchMedia) │ ▼ ThemeToggle 组件 │ ├─ 调用 setTheme('dark') │ ▼ 更新 Context State │ ├─ 写入 localStorage └─ 更新 :root CSS 变量
## File Changes
- `src/context/ThemeContext.tsx`(新建)
- `src/components/ThemeToggle.tsx`(新建)
- `src/styles/globals.css`(修改)
- `src/hooks/useSystemTheme.ts`(新建)
如果设计方案不合理,现在就可以调整!
例如,你觉得"系统偏好检测"可以用现成的库 use-dark-mode,可以告诉 Claude:
我看了设计,觉得可以直接用 use-dark-mode 这个库,不需要自己写 hook。
请更新 design.md 和 tasks.md。
2.5 开始实现
/opsx:apply
Claude 会读取 tasks.md,逐项实现:
Claude: Reading tasks.md...
Found 8 tasks, 0 completed.
Task 1.1: 创建 ThemeContext
[Creating src/context/ThemeContext.tsx...]
import React, { createContext, useState, useEffect } from 'react'
export const ThemeContext = createContext({
theme: 'light',
setTheme: (theme: 'light' | 'dark') => {}
})
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState<'light' | 'dark'>('light')
useEffect(() => {
// 从 localStorage 读取
const saved = localStorage.getItem('theme')
if (saved === 'light' || saved === 'dark') {
setTheme(saved)
} else {
// 检测系统偏好
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
setTheme(prefersDark ? 'dark' : 'light')
}
}, [])
useEffect(() => {
// 应用主题
document.documentElement.setAttribute('data-theme', theme)
localStorage.setItem('theme', theme)
}, [theme])
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
✓ Task 1.1 complete
Task 1.2: 添加 CSS 变量...
[Updating src/styles/globals.css...]
:root {
--bg-primary: #ffffff;
--text-primary: #000000;
--border-color: #e0e0e0;
}
[data-theme='dark'] {
--bg-primary: #1a1a1a;
--text-primary: #ffffff;
--border-color: #333333;
}
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
✓ Task 1.2 complete
...
All 8 tasks complete!
关键:Claude 会严格按照 tasks.md 的顺序执行,每完成一项就打勾 [x]。
2.6 验证实现
/opsx:verify
Claude 会检查:
Verifying add-dark-mode...
COMPLETENESS
✓ All 8 tasks in tasks.md are checked
✓ All requirements in specs have corresponding code
✓ 找到 ThemeContext 实现
✓ 找到 system preference 检测逻辑
CORRECTNESS
✓ Implementation matches spec intent
✓ Scenario "手动切换主题" 已实现
✓ Scenario "首次访问检测" 已实现
✓ Scenario "刷新页面保持" 已实现
COHERENCE
✓ Design mentions CSS Variables → code uses CSS Variables ✓
✓ Design mentions Context → code uses ThemeContext ✓
✓ Naming conventions consistent
SUMMARY
─────────────────────────────
Critical issues: 0
Warnings: 0
Ready to archive: Yes
2.7 归档变更
/opsx:archive
Claude 会:
- 将 Delta Spec 合并到主
openspec/specs/ui/spec.md - 将
openspec/changes/add-dark-mode/移动到openspec/changes/archive/2025-03-29-add-dark-mode/ - 保留所有 artifacts(proposal、specs、design、tasks)作为历史记录
归档后的目录结构:
openspec/
├── specs/
│ └── ui/
│ └── spec.md ← 已包含深色模式的需求
│
└── changes/
└── archive/
└── 2025-03-29-add-dark-mode/ ← 完整保存这次变更的所有文档
├── proposal.md
├── specs/
│ └── ui/
│ └── spec.md
├── design.md
└── tasks.md
归档的价值:
- ✅ 可追溯性 → 未来可以回看"为什么当时这么设计"
- ✅ 知识沉淀 → 新人可以通过 archive 快速了解系统演进
- ✅ 审计合规 → 满足软件开发的文档要求
Step 3: 并行开发多个变更
场景:你在做深色模式时,突然发现一个登录 Bug 需要修复。
传统方式:
- 要么先放下深色模式,去修 Bug(上下文切换成本高)
- 要么等深色模式做完再修 Bug(Bug 修复不及时)
OpenSpec 方式:
# 暂停当前工作,创建新变更
/opsx:propose fix-login-redirect
Claude: Created openspec/changes/fix-login-redirect/
✓ proposal.md
✓ specs/auth/spec.md
✓ design.md
✓ tasks.md
Ready for implementation.
# 快速修复 Bug
/opsx:apply
Claude: Implementing fix-login-redirect...
✓ 1.1 修复重定向逻辑
✓ 1.2 添加单元测试
All tasks complete!
# 归档 Bug 修复
/opsx:archive
Claude: ✓ Archived fix-login-redirect
# 回到深色模式继续工作
/opsx:apply add-dark-mode
Claude: Resuming add-dark-mode...
Last completed: Task 1.2
Next: Task 1.3 实现 LocalStorage 持久化...
关键优势:
- ✅ 每个变更独立存储,互不干扰
- ✅ 可以随时切换上下文(变更名称就是上下文标识)
- ✅ 进度追踪清晰(tasks.md 的勾选状态保留)
OpenSpec vs 传统方案:对比分析
对比 1:OpenSpec vs 口头需求
| 维度 | 口头需求 | OpenSpec |
|---|---|---|
| 需求留存 | ❌ 只在聊天记录里 | ✅ proposal.md 明确记录 |
| 边界清晰 | ❌ AI 自己猜测 | ✅ Scope 明确列出做什么、不做什么 |
| 可验证性 | ❌ 主观判断"做完了没" | ✅ Specs 的场景可以转换为测试 |
| 历史追溯 | ❌ 聊天记录难查找 | ✅ Archive 保存完整上下文 |
| 团队协作 | ❌ 口头传达易失真 | ✅ 文档可共享、可 Review |
对比 2:OpenSpec vs GitHub Spec Kit
GitHub 也有类似的规格驱动开发工具 Spec Kit,但区别很大:
| 维度 | GitHub Spec Kit | OpenSpec |
|---|---|---|
| 核心定位 | 严格的瀑布流程 | 灵活的迭代流程 |
| 阶段门槛 | ✅ 严格的 Phase Gate(必须按顺序) | ❌ 没有强制门槛(可以跳过或调整) |
| 文档重量 | 重(需要大量 Markdown) | 轻(只写变化的部分) |
| 适用项目 | 大型企业项目 | 个人项目到企业项目都适用 |
| 工具支持 | 只支持 Python | 支持 20+ AI 工具(Claude、Cursor 等) |
类比理解:
- Spec Kit = 传统建筑工程(先设计院出图纸,再施工,严格验收)
- OpenSpec = 敏捷开发(快速迭代,随时调整,保持文档同步)
对比 3:OpenSpec vs Kiro
Kiro 是 AWS 的 AI IDE,也支持规格驱动开发,但:
| 维度 | Kiro | OpenSpec |
|---|---|---|
| 工具锁定 | ✅ 必须用 Kiro IDE | ❌ 工具无关(Claude、Cursor、Windsurf 都支持) |
| 模型限制 | ✅ 只能用 Claude 模型 | ❌ 模型无关(GPT、Claude、Gemini 都可以) |
| 本地部署 | ❌ 云端服务 | ✅ 本地文件系统 |
| 定制性 | 受限 | 高(可以自定义 Schema) |
类比理解:
- Kiro = 苹果生态(封闭但集成好)
- OpenSpec = 开放标准(灵活但需要自己配置)
OpenSpec 的高级用法
1. 探索式开发:不确定需求时先探索
场景:你想优化性能,但不确定瓶颈在哪。
/opsx:explore
Claude: What would you like to explore?
你: 我想提升页面加载性能,但不确定瓶颈在哪。
Claude: Let me analyze your codebase...
[Analyzing bundle sizes, network requests, component renders...]
I found three main bottlenecks:
1. Large images (2MB+ per image, no lazy loading)
2. Heavy JavaScript bundles (React + lodash = 400KB)
3. Blocking render by data fetching
Which would you like to address first?
你: 先解决图片加载问题。
Claude: Good choice. Images account for 60% of page weight.
I recommend adding lazy loading and WebP conversion.
Ready to create a change? Run /opsx:propose optimize-image-loading
探索模式的价值:
- ✅ 在创建变更前先调研
- ✅ AI 帮你分析代码库、对比方案
- ✅ 明确方向后再启动正式变更
2. 自定义工作流:适应团队习惯
场景:你的团队有自己的开发流程,不想用默认的 spec-driven 工作流。
创建自定义 Schema:
# 创建一个"研究先行"的工作流
openspec schema init research-first
编辑 openspec/schemas/research-first/schema.yaml:
name: research-first
artifacts:
- id: research
generates: research.md
requires: [] # 第一步:先做调研
- id: proposal
generates: proposal.md
requires: [research] # 基于调研写提案
- id: tasks
generates: tasks.md
requires: [proposal] # 直接从提案到任务(跳过 specs 和 design)
使用自定义 Schema:
# 配置项目使用自定义 Schema
openspec config schema research-first
# 重新生成命令
openspec update
现在你的工作流变成:
/opsx:new investigate-auth-issue
↓
[创建 research.md:调研现有代码]
↓
[创建 proposal.md:基于调研提出方案]
↓
[创建 tasks.md:直接列出任务]
↓
/opsx:apply
3. 批量归档:并行开发后统一收尾
场景:你同时完成了 3 个变更,需要统一归档。
/opsx:bulk-archive
Claude: Found 3 completed changes:
- add-dark-mode (8/8 tasks complete)
- fix-login-redirect (3/3 tasks complete)
- update-footer (2/2 tasks complete)
Checking for spec conflicts...
⚠ add-dark-mode and update-footer both touch specs/ui/
Inspecting codebase to resolve...
Both changes are implemented. Will merge in chronological order:
1. add-dark-mode (created Jan 20)
2. update-footer (created Jan 22)
Archive all 3 changes?
你: Yes
Claude: ✓ Archived add-dark-mode
✓ Archived fix-login-redirect
✓ Archived update-footer
Specs merged: add-dark-mode → update-footer
自动冲突解决的原理:
- OpenSpec 检测到两个变更都修改了
specs/ui/spec.md - 它会查看代码库,确认哪些功能已实现
- 按时间顺序合并(先创建的变更先合并)
OpenSpec 与 Claude Code 的深度集成
Claude Code 如何识别 OpenSpec 命令?
1. Skills 机制
OpenSpec 在 .claude/skills/ 下创建技能文件:
# .claude/skills/openspec-propose/SKILL.md
name: openspec-propose
description: Create a new change with planning artifacts
when_to_use: 当用户想要开始新功能或修改时
## Usage
/opsx:propose [change-name-or-description]
## Behavior
1. Create openspec/changes/<change-name>/ directory
2. Generate proposal.md based on user input
3. Generate specs/ delta specifications
4. Generate design.md with technical approach
5. Generate tasks.md with implementation checklist
6. Stop and wait for /opsx:apply
## Example
User: /opsx:propose add-payment-gateway
Assistant: [Creates all planning artifacts...]
Ready for implementation. Run /opsx:apply.
Claude Code 读取这个文件后,就知道:
- 什么时候该使用这个命令
- 命令的语法和参数
- 命令的行为和输出
2. Commands 机制
OpenSpec 在 .claude/commands/opsx/ 下创建命令文件:
# .claude/commands/opsx/propose.md
You are helping the user create a new OpenSpec change.
Read openspec/config.yaml to understand project context.
Read openspec/specs/ to understand current system behavior.
Create the change folder: openspec/changes/<change-name>/
Generate these artifacts in order:
1. proposal.md
2. specs/<domain>/spec.md (delta format)
3. design.md
4. tasks.md
Use the templates from openspec/templates/ if available.
Claude Code 调用命令时:
- 用户输入
/opsx:propose add-dark-mode - Claude 读取
.claude/commands/opsx/propose.md - 按指令执行(创建文件夹、生成文档)
- 返回结果给用户
Claude Code 的上下文管理
问题:OpenSpec 生成的文档会占用 Claude 的上下文窗口吗?
答案:不会过度占用,因为有智能加载策略。
策略 1:增量读取
Claude 不会一次性加载所有文档,而是按需读取:
# /opsx:propose 阶段
加载:config.yaml(项目配置)
加载:openspec/specs/(了解现有系统)
生成:proposal.md、specs/、design.md、tasks.md
# /opsx:apply 阶段
加载:proposal.md(理解意图)
加载:design.md(理解技术方案)
加载:tasks.md(获取任务清单)
执行:逐个任务实现
策略 2:Delta 减少冗余
因为 OpenSpec 使用 Delta Specs(只写变化),所以:
- ❌ 不需要加载整个主 specs(可能有数千行)
- ✅ 只需要加载变更的 Delta Specs(通常只有几十行)
策略 3:清晰的上下文边界
每个变更都是独立的文件夹,Claude 只需关注当前变更:
当前工作:add-dark-mode/
需要加载:
- add-dark-mode/proposal.md
- add-dark-mode/specs/ui/spec.md
- add-dark-mode/design.md
- add-dark-mode/tasks.md
不需要加载:
- fix-login-redirect/(另一个并行变更)
- archive/(已完成的历史变更)
最佳实践:如何与 Claude Code 高效协作
技巧 1:在 Proposal 阶段充分对齐
# ❌ 不好的做法
你: /opsx:propose add-auth
Claude: [直接生成所有文档]
你: 等等,我想要的是 OAuth,不是用户名密码...
# ✅ 好的做法
你: /opsx:propose add-oauth-auth
Claude: [生成 proposal.md]
你: [Review proposal],发现范围不对
你: 我修改了 proposal,把"记住登录"移到未来功能了。请重新生成后续文档。
Claude: [重新生成 specs、design、tasks]
技巧 2:使用 /opsx:verify 预防返工
# 实现完成后
/opsx:verify
Claude: ⚠ Scenario "系统偏好检测" 没有测试覆盖
⚠ Design 提到使用 CSS Variables,但代码用了 Tailwind
你: 好的,我补充一下测试,并更新 design.md 说明为什么改用 Tailwind。
技巧 3:善用探索模式
# 需求不明确时
/opsx:explore
Claude: What would you like to explore?
你: 我想实现实时通知,但不确定用 WebSocket 还是 SSE。
Claude: [分析你的架构、对比两种方案]
你: [基于分析结果做决策]
你: /opsx:propose implement-websocket-notifications
技巧 4:利用并行开发
# 主线开发
/opsx:propose add-payment-gateway
/opsx:apply
[正在实现...]
# 突然需要修一个紧急 Bug
/opsx:propose fix-critical-security-issue
/opsx:apply fix-critical-security-issue
/opsx:archive
# 回到主线
/opsx:apply add-payment-gateway
[从上次中断的地方继续]
常见问题与解决方案
Q1: OpenSpec 会让开发变慢吗?
误解:写这么多文档,不是增加工作量吗?
真相:短期看似增加工作量,长期大幅节省时间。
对比数据(真实项目经验):
| 阶段 | 没有 OpenSpec | 有 OpenSpec |
|---|---|---|
| 需求对齐 | 20 分钟(口头沟通) | 15 分钟(Review Proposal) |
| 编码 | 2 小时(边写边改) | 1.5 小时(按 Tasks 执行) |
| 返工 | 1 小时(理解偏差) | 0 分钟(Specs 已对齐) |
| 测试 | 30 分钟(不知道测什么) | 20 分钟(Scenarios 即测试用例) |
| 总计 | 3.5 小时 | 2 小时(节省 43%) |
节省时间的原因:
- ✅ 前期对齐需求,避免返工
- ✅ 任务清单清晰,减少思考"下一步做什么"的时间
- ✅ Specs 的场景直接转换为测试,减少测试设计时间
Q2: 如果 AI 生成的文档不准确怎么办?
答案:文档是可编辑的,你可以随时修改。
修改流程:
# 1. AI 生成初稿
/opsx:propose add-dark-mode
[proposal.md, specs/, design.md, tasks.md 生成]
# 2. 你发现 design.md 选择的方案不合理
[手动编辑 design.md,改用 CSS-in-JS 而不是 CSS Variables]
# 3. 告诉 AI 重新生成依赖文档
你: 我修改了 design.md,请更新 tasks.md 以匹配新的技术方案。
Claude: [读取修改后的 design.md,重新生成 tasks.md]
关键:OpenSpec 的文档是"活文档",不是一次性生成就不能改。
Q3: 我能跳过某些文档吗?
答案:可以!OpenSpec 是灵活的,不是僵化的瀑布流程。
示例:小 Bug 修复不需要完整流程
# 快速修复模式
/opsx:new fix-typo --schema minimal
Claude: Created change with minimal artifacts:
- proposal.md (简化版)
- tasks.md (直接列任务)
Skipped: specs/, design.md
/opsx:apply
[快速实现]
/opsx:archive
或者自定义 Schema:
# openspec/schemas/bugfix/schema.yaml
name: bugfix
artifacts:
- id: proposal
generates: proposal.md
requires: []
- id: tasks
generates: tasks.md
requires: [proposal]
# 跳过 specs 和 design
Q4: 如果团队成员不用 AI 怎么办?
答案:OpenSpec 生成的是标准 Markdown 文档,人类也可以直接阅读和编辑。
协作场景:
- AI 用户创建变更:
/opsx:propose add-feature - 人类 Review:打开
proposal.md和specs/,提出修改意见 - AI 用户调整:根据反馈修改文档,重新生成 tasks
- 人类实现:直接看
tasks.md,按步骤编码 - AI 验证:
/opsx:verify检查实现是否符合 specs
关键:OpenSpec 不是"AI 专用"工具,而是"人机协作"工具。
Q5: OpenSpec 适合什么类型的项目?
✅ 非常适合:
- 需要多人协作的项目(文档可共享)
- 需求经常变化的项目(Delta Specs 易于调整)
- 需要长期维护的项目(Archive 提供历史追溯)
- 使用 AI 辅助开发的项目(天然集成)
❌ 不太适合:
- 一次性脚本(不需要规格化)
- 超小型项目(个人 TODO app)
- 纯算法竞赛代码(不需要行为契约)
判断标准:如果你的项目会持续迭代超过 3 个月,OpenSpec 基本都值得用。
实战案例:OpenSpec 在真实项目中的应用
案例 1:电商后台管理系统
背景:
- 团队 5 人(2 后端、2 前端、1 测试)
- 使用 Claude Code 辅助开发
- 需求来自产品经理的原型图
OpenSpec 使用方式:
产品经理提供需求 → 技术负责人创建 Proposal
↓
/opsx:propose add-order-management
[Claude 生成 proposal、specs、design、tasks]
↓
团队 Review(所有人都能看 Markdown 文档)
[提出修改意见,如"需要支持批量导出"]
↓
技术负责人调整 Proposal
[添加"批量导出"到 Scope]
↓
后端工程师:/opsx:apply(实现 API)
前端工程师:/opsx:apply(实现 UI)
[并行开发,互不干扰]
↓
测试工程师:读 specs/ 下的场景,编写测试用例
[Scenario 直接转换为测试]
↓
/opsx:verify
[Claude 验证实现符合 specs]
↓
/opsx:archive
[变更归档,specs 更新]
收益:
- ✅ 需求理解一致性提升 80%(文档为准,减少口头误解)
- ✅ 测试用例编写时间减少 50%(Scenarios 即测试大纲)
- ✅ 代码 Review 效率提升 60%(对比 Design 和实际代码)
案例 2:开源库开发
背景:
- 个人开源项目(Node.js 工具库)
- 使用 Claude Code 加速开发
- 需要维护清晰的 API 文档
OpenSpec 使用方式:
/opsx:propose add-retry-mechanism
Claude: [生成 proposal]
你: [Review,确认方案:指数退避 + 最大重试次数]
Claude: [生成 specs/core/spec.md]
### Requirement: Retry with Exponential Backoff
The library MUST retry failed operations with exponential backoff.
#### Scenario: 第一次重试
- GIVEN 操作失败
- WHEN 第一次重试
- THEN 等待 1 秒后重试
#### Scenario: 第二次重试
- GIVEN 第一次重试失败
- WHEN 第二次重试
- THEN 等待 2 秒后重试
#### Scenario: 达到最大重试次数
- GIVEN 重试 3 次均失败
- WHEN 第四次失败
- THEN 抛出 MaxRetriesExceededError
Claude: [生成 design.md、tasks.md]
/opsx:apply
[Claude 实现代码,包括单元测试]
/opsx:archive
[Specs 自动成为 API 文档的一部分]
收益:
- ✅ API 行为文档自动生成(Specs 即文档)
- ✅ 边界条件覆盖完整(Scenarios 强制思考边界)
- ✅ 历史决策可追溯(Archive 保存设计理由)
总结:OpenSpec 为 AI 编程时代带来的改变
OpenSpec 代表了软件开发流程在 AI 时代的一次重要演进。它不是简单的"文档工具",而是人类和 AI 之间的协作协议。
核心价值:
- 对齐需求 → 在写代码前,人类和 AI 先在 Proposal 和 Specs 上达成一致
- 渐进式开发 → 不是瀑布流,而是可以随时调整的迭代流程
- 知识沉淀 → Archive 保存完整的决策历史,新人或未来的自己都能快速理解
- 并行协作 → 多人或多变更可以独立进行,Delta Specs 自动处理冲突
适用场景:
- ✅ 使用 AI 辅助开发的项目
- ✅ 需要多人协作的项目
- ✅ 需求经常变化的敏捷项目
- ✅ 需要长期维护的项目
随着 AI 编程的普及,像 OpenSpec 这样的规格驱动工具将不再是"可选项",而是标准实践。它让 AI 编程从"对着聊"走向"照着谱",从混乱走向有序。
我们期待看到更多开发者采用 OpenSpec,也期待这个理念在更多 AI 工具中得到支持。OpenSpec 提供的不仅是工具,更是一种思维方式:在快速行动的同时,保持清晰的思考和记录。