前一节我们说形态四的交付物可以就是 SPEC 文档。但真实的业务系统不会只有一份简简单单的 SPEC.md——系统会演进,需求会变更,团队会换人,SPEC 本身也需要管理。
这一节我们来讨论,怎么把 SPEC 从「一份文档」变成「一套工程化的体系」。
重点理解: - SPEC 为什么需要版本管理和变更跟踪? - OpenSpec 的三层结构是什么? - 「主 SPEC + 增量变更」的模式怎么解决一致性问题?
5.1 SPEC 不可能是一次性的文档
很多人对 SPEC 的想象停留在「写一份文档,丢给 Agent 就完事了」。但真实的业务系统是会变的:
- 你加了一个新字段,数据模型要更新
- 业务规则改了,判断标准要重写
如果 SPEC 只是一个随手写的 Markdown 文件,那它很快就会变成: - 改了新的忘了改旧的,前后矛盾 - 变更没有记录,不知道为什么改、谁改的 - 多个 Agent 读了不同版本的 SPEC,行为不一致 - 出了问题不知道是 SPEC 写错了还是 Agent 理解错了
换句话来说,SPEC 本身也需要工程化管理。 它需要版本控制、需要变更跟踪、需要验收机制、需要回滚能力。
这就是 OpenSpec 要解决的问题。
5.2 OpenSpec 是什么
OpenSpec 是一套 SPEC 驱动开发的开源框架,它的核心理念只有一句话:
所有变更都先写成 SPEC,验收通过了再执行。
它不是一个给你写文档的编辑器,也不是一个项目管理工具。它是一套让 Agent 严格按规矩做事的工作流。
用 OpenSpec 的话,你加一个新功能的流程是这样的:
1. 你说:我要加一个内容去重功能
↓
2. Agent 自动生成一份变更 SPEC,写清楚:
- 这次改什么
- 数据模型怎么变
- 业务规则怎么加
- 验收场景有哪些
↓
3. 你看了没问题,批准这个变更
↓
4. Agent 按 SPEC 执行修改
↓
5. 执行完了自动验收,通过了就合入主 SPEC
全程都有记录,每一步都可追溯,出了问题可以回滚到任意版本。
5.3 OpenSpec 的三层结构
OpenSpec 把 SPEC 体系分成了三层:
┌─────────────────────────────────────┐
│ 变更层 │
│ changes/add-dark-mode/SPEC.md │ ← 每次变更单独一份
├─────────────────────────────────────┤
│ 主规范层 │
│ specs/domain/SPEC.md │ ← 当前系统行为的权威基准
├─────────────────────────────────────┤
│ 锁定层 │
│ SPEC.lock.md │ ← 当前生效版本的快照
└─────────────────────────────────────┘
变更层:每次加功能、改规则,都新建一个变更目录,单独写 SPEC。不会直接改主规范,避免改坏了回不去。
主规范层:按业务领域组织的 SPEC 集合,是当前系统行为的「唯一真相源」。所有 Agent 干活都先读这里的 SPEC。
锁定层:每次变更验收通过后,生成一个 SPEC.lock.md 快照。Agent 执行时优先读 lock 文件,保证大家行为一致。
这个设计跟前端的 package.json + package-lock.json 很像:
- 主 SPEC = package.json(声明要什么)
- SPEC.lock.md = package-lock.json(锁定当前版本)
- 变更 SPEC = 每次装新包时的临时描述
5.4 「主 SPEC + 增量变更」模式
这是 OpenSpec 最核心的设计,也是它解决「SPEC 一致性问题」的关键。
传统改 SPEC 的方式,是直接在原来的文件里覆盖保存:
之前的版本没了,谁改的、为什么改、改了什么,全靠 Git 提交记录去查。Agent A 可能还在按旧版本执行,Agent B 已经读到新版本了,两者行为不一致。
OpenSpec 改 SPEC 的方式不同:
每次变更都新建一个独立的 SPEC 文件,写清楚「这次在什么基础上改、改了什么、为什么改、验收标准是什么」。你验收通过了,它才自动合入主 SPEC,同时更新 lock 文件。
好处很明显:
- 变更可追溯:每个改法都有完整记录,为什么改、谁批的、验收结果是什么,一目了然。
- 可回滚:改坏了,直接把这个变更标记为作废,主 SPEC 就能回退到之前的状态。
- 增量执行:Agent 不需要重读整个主 SPEC,只需要读本次变更的内容,就能知道该做什么。
- 版本一致:所有 Agent 都读同一个 lock 文件,不会出现版本分歧。
这跟代码的「Pull Request」模式本质上是一样的——只是把代码换成了 SPEC,把 CI 测试换成了 Agent 验收。
5.5 SDD:规范驱动开发是什么
在讲 SPEC 具体写什么之前,我们先把概念理清楚。
SDD 的全称是 Specification-Driven Development——规范驱动开发。它不是什么新东西,而是软件工程里一个很老的理念。
传统开发是「代码先行」——代码写出来了,才知道系统到底做什么:
先写代码,跑起来看看,不对再改。需求可能在脑子里,可能在 Jira 上,但代码才是唯一的真相源。
SDD 反过来,是「规范先行」:
先把系统该做什么、怎么做、怎么算对写清楚,写成精确的、可验证的规范。所有开发都围绕这份规范转。代码只是规范的实现,不是真相源。
SDD 的核心理念有三条:
第一,规范是唯一真相源 代码、测试、文档、都是从规范派生出来的。规范改了,所有东西跟着改。出了问题先查规范——要么是规范写错了,要么是实现不符合规范。
第二,规范必须可验证 每一条规范都必须能被检验。「系统要快」不是规范,「接口响应时间不超过 200ms」才是规范。「内容质量要高」不是规范,「原创度 ≥ 80% 且无明显常识错误」才是规范。
第三,所有变更都先改规范 不允许直接改代码。想加功能、改规则,先改规范,验收通过了,再改代码。
这个理念在传统开发里推广不开,因为太麻烦了——你写了规范还得写代码,相当于做两次工。但在 Agent 时代不一样了:规范写好了,Agent 会帮你生成代码、生成测试、执行操作。写规范这一次工,后面全省了。
所以 SDD 不是为 Agent 发明的,但 Agent 让 SDD 第一次真正变得实用。
5.6 一份合格的 SPEC 必须包含什么
OpenSpec 对 SPEC 的格式没有强制性规定——你可以用 Markdown,可以用 JSON,可以用 YAML,甚至可以用纯文本。但社区有约定俗成的结构,一份合格的主 SPEC 必须包含这 8 个要素:
| 要素 | 说明 | 要求 |
|---|---|---|
| 概述 | 一句话讲清楚这个规范是管什么的、给谁用的 | 必须 |
| 数据模型 | 精确到字段和约束:字段名、类型、是否必填、默认值、合法范围、关联关系 | 必须 |
| 业务规则 | 什么能做、什么不能做、什么条件下触发什么逻辑 | 必须 |
| 操作流程 | 核心场景的执行步骤、分支逻辑、异常处理 | 必须 |
| 判断标准 | 质量怎么评估、合格不合格怎么界定、各种阈值是多少 | 必须 |
| 验收场景 | 按「给定-当-那么」格式写的可验证场景 | 必须 |
| 边界条件 | 空值、超时、并发、极端数据等异常情况怎么处理 | 推荐 |
| 术语表 | 本领域专有名词的明确定义,避免 Agent 理解偏差 | 推荐 |
注意这里没有「技术选型」「架构设计」「实现方案」这些东西。SPEC 只描述「系统该是什么样」,不描述「怎么实现它」。
举个例子,这是一个「内容去重」模块的 SPEC 片段:
# 内容去重规范
## 概述
定义内容去重的判断标准、处理流程和输出格式。
## 数据模型
去重结果对象结构:
- id: string, 必填, 内容唯一标识
- similarity: float, 必填, 0-1 之间的相似度分数
- duplicate_with: string, 可选, 重复的目标内容 ID
- decision: enum, 必填, keep/discard/need_review 三选一
## 判断标准
- 相似度 ≥ 0.95:判定为完全重复,直接丢弃
- 相似度 0.8-0.95:疑似重复,标记为人工审核
- 相似度 < 0.8:判定为不重复,保留
- 标题完全一致但正文差异超过 30%:不判定为重复
## 验收场景
场景 1:完全重复的内容
- 给定:两篇内容相似度 0.97
- 当:执行去重
- 那么:保留时间较早的一篇,标记另一篇为丢弃
场景 2:边界值判断
- 给定:两篇内容相似度正好是 0.95
- 当:执行去重
- 那么:按完全重复处理
这就是一份合格的 SPEC。任何 Agent 读到它,不管是 Hermes 还是 GPT 还是 Cursor,都会做出同样的判断。
5.7 实际怎么用
初始化
在你的项目根目录执行:
openspec init
它会自动创建目录结构:
openspec/
├── specs/ # 主规范目录
├── changes/ # 变更目录
└── archive/ # 归档目录
同时生成一个 AGENTS.md 文件,告诉所有 AI 助手这个项目用 OpenSpec 管理。
提一个新变更
在 Claude Code 或 Cursor 里说:
/opsx:propose 加一个内容去重功能
Agent 会自动在 openspec/changes/add-content-dedup/ 下生成:
SPEC.md # 本次变更的完整描述
plan.md # 执行计划
verify.md # 验收清单
你看一下,没问题就批准:
/opsx:apply
Agent 就会按 SPEC 去执行,执行完了自动验收,通过了就合入主 SPEC,更新 lock 文件。
查看历史
所有做过的变更都在 openspec/archive/ 下面按时间归档,你想知道某个功能当初为什么这么设计,去翻对应的变更 SPEC 就行。
5.8 OpenSpec 和 Shell Engineering 的关系
讲到这里你应该看出来了:OpenSpec 就是 Shell Engineering 的工程化实现。
我们说 Shell Engineering 交付的是 SPEC,不是代码。但如果没有一套工程化的体系,SPEC 很快就会变成没人维护的死文档。
OpenSpec 补上了这一块: - 它告诉你 SPEC 该怎么组织 - 它告诉你变更该怎么提、怎么审、怎么验收 - 它告诉你怎么保证所有 Agent 读到的是同一个版本 - 它告诉你怎么回滚、怎么追溯历史
形态四的 Shell,配上 OpenSpec 的工作流,才是一套完整的、可落地的、可维护的方案。
5.9 本章结语
Shell Engineering 不是什么黑科技,也不是什么遥不可及的未来。它就是一种非常朴素的思路:
既然超级 Agent 已经这么强了,我们为什么还要自己写代码? 为什么不把业务规则写清楚,让 Agent 去干活?
从纯 Skill 的轻量形态,到 SPEC 驱动的工程化形态,本质上都是在回答同一个问题:怎么用最低的成本,让超级 Agent 帮你把业务做起来。
代码不是目的,能干活才是目的。
5.10 ■ 学点英语
| 中文 | English | 音标 | 说明 |
|---|---|---|---|
| 规格驱动开发 | Specification-Driven Development | /ˌspesɪfɪˈkeɪʃən ˈdrɪvən dɪˈveləpmənt/ | 先定义规格,再围绕规格实现和验证的开发方式 |
| 变更提案 | Change Proposal | /tʃeɪndʒ prəˈpoʊzl/ | 描述需求变更、影响范围和实施方案的文档 |
| 验收标准 | Acceptance Criteria | /əkˈseptəns kraɪˈtɪriə/ | 判断需求实现是否合格的可验证条件 |
| 版本一致性 | Version Consistency | /ˈvɜːrʒən kənˈsɪstənsi/ | 多个执行者读取同一规范版本的状态 |
| 边界条件 | Edge Case | /edʒ keɪs/ | 正常流程之外但必须处理的特殊情况 |
| 变更跟踪 | Change Tracking | /tʃeɪndʒ ˈtrækɪŋ/ | 记录需求或规范如何变化的机制 |