OpenSpec 深度解析:让 AI 编程从"对着聊"到"照着谱"

0 阅读28分钟

引言: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/SHOULDRFC 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 会:

  1. 创建 openspec/changes/add-dark-mode/ 目录
  2. 生成 proposal.md(提案)
  3. 生成 specs/ui/spec.md(Delta 规格)
  4. 生成 design.md(技术设计)
  5. 生成 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 会:

  1. 将 Delta Spec 合并到主 openspec/specs/ui/spec.md
  2. openspec/changes/add-dark-mode/ 移动到 openspec/changes/archive/2025-03-29-add-dark-mode/
  3. 保留所有 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 KitOpenSpec
核心定位严格的瀑布流程灵活的迭代流程
阶段门槛✅ 严格的 Phase Gate(必须按顺序)❌ 没有强制门槛(可以跳过或调整)
文档重量重(需要大量 Markdown)轻(只写变化的部分)
适用项目大型企业项目个人项目到企业项目都适用
工具支持只支持 Python支持 20+ AI 工具(Claude、Cursor 等)

类比理解:

  • Spec Kit = 传统建筑工程(先设计院出图纸,再施工,严格验收)
  • OpenSpec = 敏捷开发(快速迭代,随时调整,保持文档同步)

对比 3:OpenSpec vs Kiro

Kiro 是 AWS 的 AI IDE,也支持规格驱动开发,但:

维度KiroOpenSpec
工具锁定✅ 必须用 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 调用命令时:

  1. 用户输入 /opsx:propose add-dark-mode
  2. Claude 读取 .claude/commands/opsx/propose.md
  3. 按指令执行(创建文件夹、生成文档)
  4. 返回结果给用户

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 文档,人类也可以直接阅读和编辑。

协作场景:

  1. AI 用户创建变更/opsx:propose add-feature
  2. 人类 Review:打开 proposal.mdspecs/,提出修改意见
  3. AI 用户调整:根据反馈修改文档,重新生成 tasks
  4. 人类实现:直接看 tasks.md,按步骤编码
  5. 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 之间的协作协议

核心价值:

  1. 对齐需求 → 在写代码前,人类和 AI 先在 Proposal 和 Specs 上达成一致
  2. 渐进式开发 → 不是瀑布流,而是可以随时调整的迭代流程
  3. 知识沉淀 → Archive 保存完整的决策历史,新人或未来的自己都能快速理解
  4. 并行协作 → 多人或多变更可以独立进行,Delta Specs 自动处理冲突

适用场景:

  • ✅ 使用 AI 辅助开发的项目
  • ✅ 需要多人协作的项目
  • ✅ 需求经常变化的敏捷项目
  • ✅ 需要长期维护的项目

随着 AI 编程的普及,像 OpenSpec 这样的规格驱动工具将不再是"可选项",而是标准实践。它让 AI 编程从"对着聊"走向"照着谱",从混乱走向有序。

我们期待看到更多开发者采用 OpenSpec,也期待这个理念在更多 AI 工具中得到支持。OpenSpec 提供的不仅是工具,更是一种思维方式:在快速行动的同时,保持清晰的思考和记录。