概念
本指南阐释 OpenSpec 背后的核心理念及其相互关联。如需实际应用,请参阅快速入门和工作流程。
设计哲学
OpenSpec 围绕四项原则构建:
流动而非僵化 —— 无阶段门控,按需推进工作
迭代而非瀑布 —— 边构建边学习,持续优化
简易而非复杂 —— 轻量配置,最小化仪式感
棕地优先 —— 适用于现有代码库,而非仅限绿地开发为何这些原则至关重要
流动而非僵化。 传统规范系统将您锁定在固定阶段:先规划,再实施,最后完成。OpenSpec 更具灵活性——您可以按照对工作有意义的任何顺序创建工件。
迭代而非瀑布。 需求会变化,理解会深化。最初看似可行的方案,在接触代码库后可能不再适用。OpenSpec 拥抱这一现实。
简易而非复杂。 某些规范框架需要繁琐的配置、僵化的格式或重量级流程。OpenSpec 不会妨碍您的工作。数秒内即可初始化,立即开始工作,仅在需要时进行定制。
棕地优先。 多数软件工作并非从零开始——而是修改现有系统。OpenSpec 基于增量的方法,便于定义对现有行为的变更,而不仅仅是描述新系统。
全景概览
OpenSpec 将您的工作组织到两个主要区域:
┌────────────────────────────────────────────────────────────────────┐
│ openspec/ │
│ │
│ ┌─────────────────────┐ ┌───────────────────────────────┐ │
│ │ specs/ │ │ changes/ │ │
│ │ │ │ │ │
│ │ Source of truth │◄─────│ Proposed modifications │ │
│ │ How your system │ merge│ Each change = one folder │ │
│ │ currently works │ │ Contains artifacts + deltas │ │
│ │ │ │ │ │
│ └─────────────────────┘ └───────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘规范 是事实来源——它们描述了您的系统当前的行为方式。
变更 是提议的修改——它们存放在单独的文件夹中,直到您准备好合并它们。
这种分离是关键。您可以并行处理多个变更而不会产生冲突。您可以在变更影响主要规范之前对其进行审查。当您归档一个变更时,它的差异会干净地合并到事实来源中。
规范
规范使用结构化的需求和场景来描述您系统的行为。
结构
openspec/specs/
├── auth/
│ └── spec.md # 认证行为
├── payments/
│ └── spec.md # 支付处理
├── notifications/
│ └── spec.md # 通知系统
└── ui/
└── spec.md # UI 行为和主题按领域组织规范——对您的系统有意义的逻辑分组。常见模式:
- 按功能区域:
auth/、payments/、search/ - 按组件:
api/、frontend/、workers/ - 按限界上下文:
ordering/、fulfillment/、inventory/
规范格式
一个规范包含需求,每个需求都有场景:
markdown
# 认证规范
## 目的
应用程序的认证和会话管理。
## 需求
### 需求:用户认证
系统 SHALL 在成功登录后颁发一个 JWT 令牌。
#### 场景:有效凭据
- GIVEN 一个拥有有效凭据的用户
- WHEN 用户提交登录表单
- THEN 返回一个 JWT 令牌
- AND 用户被重定向到仪表板
#### 场景:无效凭据
- GIVEN 无效凭据
- WHEN 用户提交登录表单
- THEN 显示一条错误消息
- AND 不颁发任何令牌
### 需求:会话过期
系统 MUST 在 30 分钟不活动后使会话过期。
#### 场景:空闲超时
- GIVEN 一个已认证的会话
- WHEN 30 分钟过去且没有活动
- THEN 该会话被失效
- AND 用户必须重新认证关键要素:
| 元素 | 目的 |
|---|---|
## 目的 | 此规范所属领域的高级描述 |
### 需求: | 系统必须具备的特定行为 |
#### 场景: | 需求在实际中的具体示例 |
| SHALL/MUST/SHOULD | RFC 2119 关键词,表示需求强度 |
为何以这种方式构建规范
需求是“什么” —— 它们陈述系统应该做什么,而不指定实现。
场景是“何时” —— 它们提供可以验证的具体示例。好的场景:
- 是可测试的(您可以为它们编写自动化测试)
- 覆盖正常路径和边缘情况
- 使用 Given/When/Then 或类似的结构化格式
RFC 2119 关键词(SHALL、MUST、SHOULD、MAY)传达意图:
- MUST/SHALL —— 绝对要求
- SHOULD —— 推荐,但存在例外
- MAY —— 可选
规范是什么(以及不是什么)
规范是行为契约,而不是实现计划。
好的规范内容:
- 用户或下游系统依赖的可观察行为
- 输入、输出和错误条件
- 外部约束(安全性、隐私性、可靠性、兼容性)
- 可以测试或明确验证的场景
规范中应避免的内容:
- 内部类/函数名称
- 库或框架选择
- 逐步实现细节
- 详细的执行计划(这些属于
design.md或tasks.md)
快速测试:
- 如果实现可以在不改变外部可见行为的情况下发生变化,那么它很可能不属于规范。
保持轻量级:渐进式严谨
OpenSpec 旨在避免官僚主义。使用最轻量级的水平,只要变更仍然可验证即可。
精简规范(默认):
- 简短的、以行为为先的需求
- 明确的范围和非目标
- 几个具体的验收检查
完整规范(用于更高风险):
- 跨团队或跨仓库的变更
- API/契约变更、迁移、安全/隐私问题
- 歧义可能导致昂贵返工的变更
大多数变更应保持在精简模式。
人机协作
在许多团队中,人类进行探索,智能体起草工件。预期的循环是:
- 人类提供意图、上下文和约束。
- 智能体将其转换为以行为为先的需求和场景。
- 智能体将实现细节保留在
design.md和tasks.md中,而不是spec.md中。 - 验证在实现之前确认结构和清晰度。
这使得规范对人类可读,对智能体一致。
变更
变更是对您系统的一项提议修改,打包为一个包含理解并实现它所需一切的文件夹。
变更结构
openspec/changes/add-dark-mode/
├── proposal.md # 为什么以及是什么
├── design.md # 如何做(技术方案)
├── tasks.md # 实现清单
├── .openspec.yaml # 变更元数据(可选)
└── specs/ # 差异规范
└── ui/
└── spec.md # ui/spec.md 中正在更改的内容每个变更都是自包含的。它包含:
- 工件 —— 捕获意图、设计和任务的文档
- 差异规范 —— 关于正在添加、修改或删除内容的规范
- 元数据 —— 此特定变更的可选配置
为什么变更采用文件夹形式
将变更打包为文件夹有几个好处:
所有内容在一起。 提案、设计、任务和规范位于一处。无需在不同位置寻找。
并行工作。 多个变更可以同时存在而不会冲突。在
fix-auth-bug也在进行的同时,可以处理add-dark-mode。清晰的历史记录。 归档时,变更会连同其完整上下文一起移动到
changes/archive/。您可以回顾并理解不仅是什么发生了变化,还有为什么变化。便于审查。 变更文件夹易于审查——打开它,阅读提案,检查设计,查看规范差异。
工件
工件是变更中指导工作的文档。
工件流程
proposal ──────► specs ──────► design ──────► tasks ──────► implement
│ │ │ │
why what how steps
+ scope changes approach to take工件相互构建。每个工件为下一个提供上下文。
工件类型
提案 (proposal.md)
提案在高层级捕获意图、范围和方法。
markdown
# 提案:添加深色模式
## 意图
用户要求添加深色模式选项,以减少夜间使用时的眼睛疲劳并匹配系统偏好。
## 范围
范围内:
- 设置中的主题切换
- 系统偏好检测
- 在 localStorage 中持久化偏好
范围外:
- 自定义颜色主题(未来工作)
- 每页主题覆盖
## 方法
使用 CSS 自定义属性进行主题设置,并使用 React Context 进行状态管理。首次加载时检测系统偏好,允许手动覆盖。何时更新提案:
- 范围发生变化(缩小或扩大)
- 意图更加清晰(对问题有了更好的理解)
- 方法发生根本性转变
规范(specs/ 中的差异规范)
差异规范描述相对于当前规范正在更改的内容。请参阅下面的差异规范。
设计 (design.md)
设计捕获技术方案和架构决策。
markdown
# 设计:添加深色模式
## 技术方案
通过 React Context 管理主题状态,避免属性逐层传递。
CSS 自定义属性支持运行时切换,无需切换类。
## 架构决策
### 决策:Context 优于 Redux
使用 React Context 管理主题状态,原因如下:
- 简单的二元状态(明/暗)
- 无复杂状态转换
- 避免引入 Redux 依赖
### 决策:CSS 自定义属性
使用 CSS 变量而非 CSS-in-JS,原因如下:
- 兼容现有样式表
- 无运行时开销
- 浏览器原生方案
## 数据流
```
ThemeProvider (context)
│
▼
ThemeToggle ◄──► localStorage
│
▼
CSS Variables (applied to :root)
```
## 文件变更
- `src/contexts/ThemeContext.tsx` (新建)
- `src/components/ThemeToggle.tsx` (新建)
- `src/styles/globals.css` (修改)何时更新设计:
- 实现过程中发现原方案不可行
- 发现更优解决方案
- 依赖项或约束条件发生变化
任务 (tasks.md)
任务是实施清单 —— 带有复选框的具体步骤。
markdown
# 任务
## 1. 主题基础设施
- [ ] 1.1 创建包含亮/暗状态的 ThemeContext
- [ ] 1.2 添加颜色的 CSS 自定义属性
- [ ] 1.3 实现 localStorage 持久化
- [ ] 1.4 添加系统偏好检测
## 2. 用户界面组件
- [ ] 2.1 创建 ThemeToggle 组件
- [ ] 2.2 在设置页面添加切换开关
- [ ] 2.3 更新 Header 以包含快速切换
## 3. 样式
- [ ] 3.1 定义暗色主题调色板
- [ ] 3.2 更新组件以使用 CSS 变量
- [ ] 3.3 测试对比度以确保可访问性任务最佳实践:
- 将相关任务分组在标题下
- 使用层级编号 (1.1, 1.2 等)
- 保持任务足够小,可在一次会话中完成
- 完成任务后勾选复选框
增量规范
增量规范是使 OpenSpec 适用于棕地开发的关键概念。它们描述正在发生的变化,而不是重述整个规范。
格式
markdown
# Auth 的增量规范
## 新增需求
### 需求:双因素认证
系统必须支持基于 TOTP 的双因素认证。
#### 场景:2FA 注册
- 假设一个未启用 2FA 的用户
- 当用户在设置中启用 2FA 时
- 则显示一个二维码用于设置认证器应用
- 并且用户必须在激活前通过验证码进行验证
#### 场景:2FA 登录
- 假设一个已启用 2FA 的用户
- 当用户提交有效凭据时
- 则会显示 OTP 验证挑战
- 并且仅在有效的 OTP 验证后才完成登录
## 修改需求
### 需求:会话过期
系统必须在 15 分钟不活动后使会话过期。
(之前:30 分钟)
#### 场景:空闲超时
- 假设一个已认证的会话
- 当 15 分钟过去且无活动时
- 则该会话被失效
## 移除需求
### 需求:记住我
(已弃用,改为使用 2FA。用户应在每次会话时重新认证。)增量部分
| 部分 | 含义 | 归档时发生什么 |
|---|---|---|
## 新增需求 | 新行为 | 追加到主规范 |
## 修改需求 | 变更的行为 | 替换现有需求 |
## 移除需求 | 已弃用的行为 | 从主规范中删除 |
为何使用增量规范而非完整规范
清晰性。 增量规范精确显示了正在发生的变化。阅读完整规范时,你必须在脑中将其与当前版本进行对比。
避免冲突。 两个变更可以触及同一个规范文件而不冲突,只要它们修改的是不同的需求。
审查效率。 审查者看到的是变更,而非未变的上下文。专注于重要的事情。
适合棕地开发。 大部分工作都是修改现有行为。增量规范使修改成为一等公民,而非事后考虑。
模式
模式为工作流定义了工件类型及其依赖关系。
模式如何工作
yaml
# openspec/schemas/spec-driven/schema.yaml
name: spec-driven
artifacts:
- id: proposal
generates: proposal.md
requires: [] # 无依赖,可首先创建
- id: specs
generates: specs/**/*.md
requires: [proposal] # 创建前需要提案
- id: design
generates: design.md
requires: [proposal] # 可与规范并行创建
- id: tasks
generates: tasks.md
requires: [specs, design] # 需要规范和设计两者工件形成一个依赖图:
提案
(根节点)
│
┌─────────────┴─────────────┐
│ │
▼ ▼
规范 设计
(需要: (需要:
提案) 提案)
│ │
└─────────────┬─────────────┘
│
▼
任务
(需要:
规范, 设计)依赖是使能器,而非关卡。 它们显示了可以创建什么,而不是你接下来必须创建什么。如果不需要,可以跳过设计。你可以在设计之前或之后创建规范——两者都只依赖于提案。
内置模式
spec-driven (默认)
规范驱动开发的标准工作流:
提案 → 规范 → 设计 → 任务 → 实现适用于:大多数功能开发,希望在实现前就规范达成一致。
自定义模式
为你的团队工作流创建自定义模式:
bash
# 从头创建
openspec schema init research-first
# 或者分支一个现有模式
openspec schema fork spec-driven research-first自定义模式示例:
yaml
# 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] # 跳过规范/设计,直接进入任务有关创建和使用自定义模式的完整详情,请参阅自定义。
归档
归档通过将增量规范合并到主规范中并保留变更历史来完成一次变更。
归档时发生什么
归档前:
openspec/
├── specs/
│ └── auth/
│ └── spec.md ◄────────────────┐
└── changes/ │
└── add-2fa/ │
├── proposal.md │
├── design.md │ 合并
├── tasks.md │
└── specs/ │
└── auth/ │
└── spec.md ─────────┘
归档后:
openspec/
├── specs/
│ └── auth/
│ └── spec.md # 现在包含 2FA 需求
└── changes/
└── archive/
└── 2025-01-24-add-2fa/ # 为历史保留
├── proposal.md
├── design.md
├── tasks.md
└── specs/
└── auth/
└── spec.md归档过程
合并增量规范。 每个增量规范部分(新增/修改/移除)都会应用到相应的主规范。
移至归档。 变更文件夹移至
changes/archive/,并添加日期前缀以便按时间顺序排列。保留上下文。 所有工件在归档中保持完整。你始终可以回顾以了解变更的原因。
为何归档很重要
干净的状态。 活跃变更 (changes/) 仅显示进行中的工作。已完成的工作移出视野。
审计跟踪。 归档保留了每次变更的完整上下文——不仅仅是变更了什么,还有解释原因的提案、解释方法的设计以及显示已完成工作的任务。
规范演进。 随着变更被归档,规范有机地增长。每个归档合并其增量规范,随着时间的推移构建出全面的规范。
各部分如何协同工作
┌──────────────────────────────────────────────────────────────────────────────┐
│ OPENSPEC 流程 │
│ │
│ ┌────────────────┐ │
│ │ 1. 开始 │ /opsx:propose (核心) 或 /opsx:new (扩展) │
│ │ 变更 │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 2. 创建 │ /opsx:ff 或 /opsx:continue (扩展工作流) │
│ │ 工件 │ 创建 提案 → 规范 → 设计 → 任务 │
│ │ │ (基于模式依赖关系) │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 3. 实现 │ /opsx:apply │
│ │ 任务 │ 处理任务,完成后勾选 │
│ │ │◄──── 根据所学更新工件 │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 4. 验证 │ /opsx:verify (可选) │
│ │ 工作 │ 检查实现是否符合规范 │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │
│ │ 5. 归档 │────►│ 增量规范合并到主规范中 │ │
│ │ 变更 │ │ 变更文件夹移至 archive/ │ │
│ └────────────────┘ │ 规范现在是更新后的真实来源 │ │
│ └──────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘良性循环:
- 规范描述当前行为
- 变更提出修改建议(作为增量规范)
- 实现使变更成为现实
- 归档将增量规范合并到规范中
- 规范现在描述新的行为
- 下一个变更基于更新后的规范构建
术语表
| 术语 | 定义 |
|---|---|
| 工件 | 变更中的文档(提案、设计、任务或增量规范) |
| 归档 | 完成变更并将其增量合并到主规范的过程 |
| 变更 | 对系统的拟议修改,以包含工件的文件夹形式打包 |
| 增量规范 | 描述相对于当前规范的变更(新增/修改/删除)的规范 |
| 领域 | 规范的逻辑分组(例如 auth/、payments/) |
| 需求 | 系统必须具备的特定行为 |
| 场景 | 需求的具体示例,通常采用 Given/When/Then 格式 |
| 模式 | 工件类型及其依赖关系的定义 |
| 规范 | 描述系统行为的规范,包含需求和场景 |
| 事实来源 | openspec/specs/ 目录,包含当前已达成共识的行为 |