规范驱动的 Vibe Coding:OpenSpec 实践指南
用结构化规范对齐人类与 AI,让 AI 代码生成从"氛围抽卡"变成可控的工程流程。
为什么 Vibe Coding 需要规范?
Vibe Coding 的核心问题是需求藏在聊天记录里:缺乏版本控制、缺乏验收标准、AI 输出质量完全取决于 prompt。"再让 AI 改改"会迅速失控。
解决方案:在写任何代码之前,人类和 AI 先就"要做什么"达成书面共识。
OpenSpec 是什么?
OpenSpec(官网,GitHub,48k+ stars,MIT License)是一个轻量级的**规范驱动开发(Spec-Driven Development,SDD)**框架,专为 AI coding assistant 设计。它的核心思想很简单:在写任何代码之前,人类和 AI 先就"要做什么"达成书面共识。
核心特性
- 无需 API Key:纯本地工具,兼容任何 AI 编码助手
- 规范活在代码库中:作为 Markdown 文件版本控制,与代码同在
- Brownfield-First:专为存量代码库设计,不是只能用于新项目
- AI 原生:内置对 Claude Code、Cursor、Windsurf 等 20+ 工具的配置和提示词优化
- 显式状态管理:分离"当前真相"(
specs/)和"提议变更"(changes/)
安装与初始化
# 全局安装
npm install -g @fission-ai/openspec@latest
# 在项目中初始化
cd your-project
openspec init
初始化后项目结构:
openspec/
├── specs/ # 当前系统行为的事实来源
│ └── <domain>/
│ └── spec.md
├── changes/ # 提议的变更(每个变更一个文件夹)
│ └── <change-name>/
│ ├── proposal.md # 为什么 + 做什么
│ ├── specs/ # Delta 规范
│ ├── design.md # 怎么做(技术设计)
│ └── tasks.md # 实现检查清单
└── config.yaml # 项目配置(可选)
OpenSpec 的核心概念
1. 规范(Spec)
Spec 是用结构化 Markdown 描述系统行为的文件,每个规范包含需求(Requirement)和场景(Scenario)。
# 认证规范
## Purpose
应用程序的用户认证与会话管理。
## Requirements
### Requirement: 用户认证
系统必须在成功登录后发放 JWT token。
#### Scenario: 有效凭证登录
- **GIVEN** 用户拥有有效凭证
- **WHEN** 用户提交登录表单
- **THEN** 返回 JWT token
- **AND** 用户被重定向到仪表盘
#### Scenario: 无效凭证登录
- **GIVEN** 用户使用无效凭证
- **WHEN** 用户提交登录表单
- **THEN** 显示错误消息
- **AND** 不发放任何 token
RFC 2119 关键词:
| 关键词 | 含义 |
|---|---|
| SHALL / MUST | 绝对需求 |
| SHOULD | 推荐,但允许例外 |
| MAY | 可选 |
2. Delta 规范(Delta Spec)
这是 OpenSpec 最重要的创新。当你要修改现有系统时,不需要重写整个规范——你写 Delta,只描述变化的部分。
# Auth 变更
## ADDED Requirements
### Requirement: 双因素认证
系统必须支持基于 TOTP 的双因素认证。
#### Scenario: 2FA 注册
- **GIVEN** 用户未启用 2FA
- **WHEN** 用户在设置中启用 2FA
- **THEN** 显示二维码供身份验证器应用扫描
- **AND** 用户必须验证代码后才能激活
## MODIFIED Requirements
### Requirement: 会话超时
系统必须在 **15 分钟**无活动后使会话过期。
(原来:60 分钟)
#### Scenario: 空闲超时
- **GIVEN** 已认证的会话
- **WHEN** 30 分钟无活动发生
- **THEN** 会话被失效
- **AND** 用户必须重新认证
## REMOVED Requirements
### Requirement: 记住我功能
(已被双因素认证取代,不再需要)
Archive 时发生的事:
| 部分 | 含义 | Archive 后 |
|---|---|---|
## ADDED Requirements |
新增行为 | 追加到主规范 |
## MODIFIED Requirements |
变更行为 | 替换现有版本 |
## REMOVED Requirements |
废弃行为 | 从主规范中删除 |
3. 变更工件(Artifacts)
每个变更文件夹包含 4 种工件:
| 工件 | 目的 |
|---|---|
proposal.md |
为什么做这个变更——意图、范围、影响 |
specs/ |
Delta 规范——需求变化 |
design.md |
怎么做——技术方案和架构决策 |
tasks.md |
实现检查清单,带复选框 |
4. 双文件夹模型
openspec/
├── specs/ → 当前事实来源(按领域组织:auth/, payments/ 等)
└── changes/ → 提议的修改(每个变更一个文件夹)
工作流命令
OpenSpec 提供 slash commands 与 AI coding assistant 交互。不同 profile 提供的命令数量不同:
Profile 对比
| Profile | 命令数 | 包含命令 |
|---|---|---|
| core(默认) | 5 | /opsx:propose, /opsx:explore, /opsx:apply, /opsx:sync, /opsx:archive |
| workflows(扩展) | 11 | core + /opsx:new, /opsx:continue, /opsx:ff, /opsx:verify, /opsx:bulk-archive, /opsx:onboard |
核心命令(core profile)
| 命令 | 用途 |
|---|---|
/opsx:propose |
创建变更 + 生成所有规划工件(一气呵成) |
/opsx:explore |
思考想法,调查问题 |
/opsx:apply |
实现任务,更新检查清单 |
/opsx:sync |
将 delta 规范合并到主规范 |
/opsx:archive |
完成变更,移至归档 |
扩展命令(workflows profile,需配置)
openspec config profile # 选择 workflows
openspec update # 应用更改
| 命令 | 用途 |
|---|---|
/opsx:new |
启动新变更脚手架 |
/opsx:continue |
根据依赖关系创建下一工件 |
/opsx:ff |
快速创建所有规划工件 |
/opsx:verify |
验证实现是否符合工件 |
/opsx:bulk-archive |
批量归档多个变更 |
/opsx:onboard |
引导式完整流程教程 |
CLI 辅助命令
openspec list # 列出所有变更
openspec view # 交互式仪表盘
openspec validate # 验证规范格式
openspec status # 查看变更完成状态
openspec archive # 归档完成的变更
规范的结构:固定的还是可变的?
有固定结构,但不是铁板一块。 OpenSpec 的规范格式是明确规定的——你需要用 Markdown 写 Purpose、Requirements、带 RFC 2119 关键词的 Requirement、以及 Given/When/Then 的 Scenario。这是 AI 能解析和验证的基础。
必须有的元素
# 规范标题
## Purpose ← 必须有:领域的用途描述
## Requirements ← 必须有:需求列表
### Requirement: X ← 必须用 SHALL/MUST/SHOULD
#### Scenario: Y ← 必须用 GIVEN/WHEN/THEN
验证机制
OpenSpec CLI 的 openspec validate 会检查:
- 每个 Requirement 包含 RFC 2119 关键词(SHALL/MUST)
- 每个 Scenario 使用
####标题级别 - Scenario 包含 GIVEN/WHEN/THEN 关键词
可以自定义的部分
如果你需要不同的结构,可以创建 Custom Schema:
| 可自定义 | 默认值 | 说明 |
|---|---|---|
| 工件类型 | proposal, specs, design, tasks | 你可以增删改 |
| 依赖关系 | specs requires proposal | 可以重新定义 DAG |
| 格式模板 | 内置 Markdown 模板 | 可以完全替换 |
| 规范结构 | ## Purpose + ## Requirements |
不建议改——AI 依赖这个 |
何时用默认,何时自定义?
- 用默认:大多数项目,直接用
spec-drivenschema - 自定义:当你的团队有特殊流程(如安全审查、UX 评审需要单独工件),Fork 后改
自定义 schema 复制到 openspec/schemas/ 后即可使用,openspec schema validate 帮你检查语法。
谁该写什么?
OpenSpec 设计哲学是人类给方向,AI 生成结构。各工件的写作分工:
| 工件 | 主要作者 | AI 能帮你做什么 |
|---|---|---|
proposal.md |
人类 | 帮你把模糊的想法组织成结构化的 Why/What/Impact |
specs/*.md |
AI 生成,人类审查 | 根据 proposal 生成带 RFC 2119 关键词的 Requirements 和 Given/When/Then Scenarios |
design.md |
AI 生成,人类审查 | 根据 specs 生成技术方案、目录结构、API 设计 |
tasks.md |
AI 生成,人类审查 | 根据 design 生成细粒度的实现检查清单 |
典型流程
人类:/opsx:propose user-auth 添加用户认证功能
AI → 生成完整的 proposal.md(需要人类补充 Why 部分)
AI → 生成 specs/auth/spec.md(基于 proposal 的意图)
AI → 生成 design.md(技术方案)
AI → 生成 tasks.md(检查清单)
人类 → 审查、修改各工件
人类 → 用 /opsx:apply 开始实现
关键原则
- Proposal 是你的:给出足够的信息(功能愿景、约束、优先级),AI 才能生成好的规范
- Specs 是 AI 的:生成后必须审查,确保没有理解偏差
- 不要跳过任何工件:即使 AI 生成得很顺利,审查环节不可省略——这是验收的依据
完整示例:给项目添加暗色主题
Step 1: 创建变更
# 方式一:用 slash command
/opsx:propose add-dark-mode 添加暗色主题支持
# 方式二:用 CLI
openspec new add-dark-mode
Step 2: 编辑 proposal.md
# proposal.md
## Why
用户反馈在低光环境下使用应用时亮色主题过于刺眼。需要支持系统级暗色主题切换。
## What
- 添加主题切换组件
- 实现 CSS 变量驱动的颜色系统
- 支持跟随系统偏好
- 持久化用户偏好到 localStorage
## Impact
- UI 层变更,无后端影响
- 需要更新样式指南文档
Step 3: 编辑 specs/ 中的 Delta 规范
# specs/ui/spec.md
## ADDED Requirements
### Requirement: 暗色主题支持
系统必须支持暗色主题,并允许用户切换。
#### Scenario: 手动切换主题
- **GIVEN** 用户在设置页面
- **WHEN** 用户点击主题切换控件
- **THEN** 页面主题从亮色切换为暗色(或相反)
- **AND** 偏好被保存到 localStorage
#### Scenario: 系统偏好跟随
- **GIVEN** 用户未手动设置主题偏好
- **WHEN** 用户打开应用
- **THEN** 主题跟随操作系统偏好(prefers-color-scheme)
Step 4: 编辑 design.md
# design.md
## Technical Approach
使用 CSS 变量定义颜色主题:
```css
:root {
--bg-primary: #ffffff;
--text-primary: #1a1a1a;
}
[data-theme="dark"] {
--bg-primary: #1a1a1a;
--text-primary: #ffffff;
}
Components
ThemeToggle:切换按钮组件ThemeProvider:React Context 提供主题状态
Dependencies
- 无新依赖,使用原生 CSS 变量
### Step 5: 实现并验证
```bash
/opsx:apply # 开始实现,检查任务
# ... 实现代码 ...
/opsx:verify # 验证实现符合规范
/opsx:archive # 归档,delta 合并到主规范
完整示例:从零构建博客 API(Greenfield)
对于全新项目,规范驱动开发同样有效,只是起点不同——你先创建初始规范,再让 AI 按规范实现。
Step 1: 初始化 OpenSpec
mkdir my-blog-api && cd my-blog-api
npm init -y
openspec init
项目结构初始为空:
my-blog-api/
└── openspec/
├── specs/ # 空,等待创建初始规范
├── changes/ # 空
└── config.yaml
Step 2: 创建初始规范
用 /opsx:propose 创建一个名为 initial-setup 的变更:
/opsx:propose initial-setup 构建博客 API 初始版本
Step 3: 编辑 proposal.md
# proposal.md
## Why
团队需要一个博客 API,用于文章发布和管理。前端计划用 Next.js 构建,需要 RESTful 接口。
## What
- 用户注册与认证(JWT)
- 文章 CRUD(创建、读取、更新、删除)
- 文章列表分页
- Markdown 内容存储
## Impact
- 新项目,无历史包袱
- 选用 Express.js + SQLite(开发轻量,生产可替换为 PostgreSQL)
Step 4: 编写初始规范(不是 Delta)
由于是 greenfield 项目,变更中的 specs/ 目录写的是初始完整规范,不是 delta:
# specs/api/spec.md
## Purpose
博客 API 提供用户认证、文章管理和内容查询接口。
## Requirements
### Requirement: 用户注册
系统必须允许用户通过邮箱和密码注册。
#### Scenario: 成功注册
- **GIVEN** 邮箱未被占用
- **WHEN** 用户提交有效的注册信息(email, password, username)
- **THEN** 创建新用户账户
- **AND** 返回 JWT token
- **AND** 用户被自动登录
#### Scenario: 邮箱被占用
- **GIVEN** 邮箱已被其他用户注册
- **WHEN** 用户提交注册信息
- **THEN** 返回 409 错误
- **AND** 提示"该邮箱已被注册"
### Requirement: 用户登录
系统必须允许已注册用户登录。
#### Scenario: 有效凭证登录
- **GIVEN** 用户拥有有效账户
- **WHEN** 用户提交正确的 email 和 password
- **THEN** 返回 JWT token
- **AND** token 有效期为 24 小时
#### Scenario: 无效凭证
- **GIVEN** 用户使用了错误的密码
- **WHEN** 用户提交登录表单
- **THEN** 返回 401 错误
- **AND** 提示"邮箱或密码错误"
### Requirement: 文章创建
系统必须允许认证用户创建文章。
#### Scenario: 成功创建文章
- **GIVEN** 用户已登录
- **WHEN** 用户提交文章(title, content, tags)
- **THEN** 创建文章记录
- **AND** 作者设为当前用户
- **AND** 返回创建的完整文章对象
### Requirement: 文章列表
系统必须提供文章列表查询接口,支持分页。
#### Scenario: 默认分页
- **GIVEN** 数据库中存在多篇文章
- **WHEN** 请求 GET /articles
- **THEN** 返回第一页(默认 10 篇)文章摘要列表
- **AND** 包含 total 计数和分页元数据
#### Scenario: 指定页码
- **WHEN** 请求 GET /articles?page=2&limit=20
- **THEN** 返回第 2 页,每页 20 篇文章
### Requirement: 文章详情
系统必须允许通过 slug 获取单篇文章完整内容。
#### Scenario: 有效 slug
- **GIVEN** 存在 slug 为 "my-first-post" 的文章
- **WHEN** 请求 GET /articles/my-first-post
- **THEN** 返回完整文章内容
- **AND** 增加阅读数
#### Scenario: 无效 slug
- **WHEN** 请求 GET /articles/non-existent
- **THEN** 返回 404 错误
Step 5: 编辑 design.md
# design.md
## Tech Stack
- **Runtime**:Node.js 18+
- **Framework**:Express.js
- **Database**:SQLite(better-sqlite3)
- **Auth**:JWT(jsonwebtoken)
- **Validation**:Zod
## Directory Structure
```
src/
├── index.js # 入口,启动服务器
├── routes/
│ ├── auth.js # /auth 路由
│ └── articles.js # /articles 路由
├── middleware/
│ └── auth.js # JWT 验证中间件
├── models/
│ ├── user.js # 用户模型
│ └── article.js # 文章模型
└── db/
└── index.js # 数据库初始化
```
## API Endpoints
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| POST | /auth/register | No | 用户注册 |
| POST | /auth/login | No | 用户登录 |
| GET | /articles | No | 文章列表(分页) |
| GET | /articles/:slug | No | 文章详情 |
| POST | /articles | Yes | 创建文章 |
| PUT | /articles/:slug | Yes | 更新文章 |
| DELETE | /articles/:slug | Yes | 删除文章 |
## Database Schema
```sql
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
content TEXT NOT NULL,
author_id INTEGER NOT NULL,
read_count INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
);
```
Step 6: 编辑 tasks.md
# tasks.md
## 实现检查清单
### 1. 项目初始化
- [ ] 初始化 npm 项目
- [ ] 安装依赖:express, better-sqlite3, jsonwebtoken, zod, cors
- [ ] 创建目录结构
### 2. 数据库层
- [ ] 创建 `src/db/index.js`,初始化 SQLite
- [ ] 创建 users 表
- [ ] 创建 articles 表
### 3. 模型层
- [ ] 实现 `src/models/user.js`:注册、登录、密码验证
- [ ] 实现 `src/models/article.js`:CRUD 操作,slug 生成
### 4. 中间件
- [ ] 实现 `src/middleware/auth.js`:JWT 验证
### 5. 路由
- [ ] 实现 `src/routes/auth.js`:/auth/register, /auth/login
- [ ] 实现 `src/routes/articles.js`:完整 CRUD
### 6. 入口
- [ ] 创建 `src/index.js`,启动 Express 服务器
- [ ] 监听端口 3000
### 7. 测试
- [ ] 手动测试注册/登录流程
- [ ] 手动测试文章 CRUD
- [ ] 验证分页逻辑
Step 7: 实现与归档
/opsx:apply # 按 tasks.md 逐项实现
# ... AI 按规范生成代码 ...
/opsx:verify # 验证符合规范
/opsx:archive # 归档,初始规范写入 openspec/specs/
归档后,openspec/specs/api/spec.md 成为系统的事实来源,后续变更都基于它写 delta。
Greenfield vs Brownfield 对比
| 方面 | Greenfield | Brownfield |
|---|---|---|
| 初始规范 | 完整写出系统行为 | 通过 delta 描述变化 |
| 变更类型 | 新建系统 | 修改已有功能 |
| 起点 | changes/ → specs/ |
specs/ 已存在,变更写 delta |
| 适用场景 | 从零开始的新项目 | 已有代码库的功能迭代 |
项目配置
在 openspec/config.yaml 中设置项目级默认值和上下文:
schema: spec-driven
context: |
技术栈:TypeScript, React, Node.js, PostgreSQL
API 风格:RESTful,JSON 响应
测试:Jest + React Testing Library
我们重视所有公开 API 的向后兼容性
rules:
proposal:
- 包含回滚计划
- 识别受影响的团队
specs:
- 场景使用 Given/When/Then 格式
- 引用现有模式而非发明新模式
design:
- 复杂流程包含时序图
自定义 Schema
如果默认的 spec-driven workflow 不适合你的团队,可以创建自定义 schema:
# 复制内置 schema 到项目
openspec schema fork spec-driven my-workflow
# 自定义 openspec/schemas/my-workflow/schema.yaml
schema.yaml 结构:
name: my-workflow
version: 1
description: 我的团队自定义 workflow
artifacts:
- id: proposal
generates: proposal.md
description: 初始提案文档
requires: []
- id: design
generates: design.md
description: 技术设计
requires: [proposal]
- id: tasks
generates: tasks.md
description: 实现检查清单
requires: [design]
快速开始
# 1. 安装
npm install -g @fission-ai/openspec@latest
# 2. 初始化项目
cd your-project
openspec init
# 3. 开始变更
/opsx:propose my-feature 描述你的功能
参考资源
- 官网:https://openspec.dev/
- GitHub:https://github.com/Fission-AI/OpenSpec
- 文档:https://lzw.me/docs/openspec/en/
- 最新版本:v1.3.1(2026-04-21)
- 支持工具:Claude Code, Cursor, Windsurf, GitHub Copilot, Gemini CLI 等 20+
- RFC 2119:关键词含义(SHALL/MUST/SHOULD/MAY)