规范驱动的 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 写 PurposeRequirements、带 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-driven schema
  • 自定义:当你的团队有特殊流程(如安全审查、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 描述你的功能

参考资源