Spec Coding 解决了一个核心问题:在让 AI 写代码之前,先把规格写清楚。但它还有一个遗留问题——规格本身没有统一的格式。每个人写的 Spec 长相各异,AI 能读懂,但不同格式给 AI 的"信号密度"差异很大,也无法在工具之间共享和复用。
OpenSpec 是对这个问题的回答:一种面向 AI 工具设计的、标准化的机器可读规格格式。
为什么需要标准化
现有的规格标准如 OpenAPI、JSON Schema 并不是为 AI 消费设计的。它们的目的是文档化和验证,而不是指导生成。OpenAPI 描述的是一个 API 已经长什么样,而 OpenSpec 描述的是一个功能应该长什么样——包含约束、边界条件、验收标准和明确的不在范围内的部分。
OpenSpec 的文档结构
一个 OpenSpec 文档是一个 YAML 文件,包含以下顶层字段:
openspec: "1.0"
info:
title: User Login
description: 用户通过邮箱 + 密码登录,获取访问 token
version: "1.0.0"
author: benson
constraints:
- id: C001
description: 密码使用 argon2id 哈希存储,不得使用 MD5 或 SHA1
- id: C002
description: JWT 存储在 httpOnly Cookie,不得出现在响应 body 中
- id: C003
description: 连续失败 5 次后锁定账户 15 分钟
interface:
inputs:
- name: email
type: string
format: email
required: true
- name: password
type: string
minLength: 8
required: true
outputs:
success:
status: 200
schema:
user:
id: string
email: string
name: string
errors:
- status: 401
condition: 凭据错误或账户不存在
schema:
error: "Invalid credentials"
- status: 429
condition: 账户已锁定
schema:
error: "Account locked"
retryAfter: number
acceptance_criteria:
- id: AC001
description: 正确凭据可以登录并在响应中设置 httpOnly Cookie
testable: true
- id: AC002
description: 错误凭据返回 401,响应内容不区分"账户不存在"和"密码错误"
testable: true
- id: AC003
description: 第 5 次失败后返回 429,retryAfter 为 900(秒)
testable: true
- id: AC004
description: 登录成功后,该账户的失败计数归零
testable: true
out_of_scope:
- OAuth / 第三方登录
- 多因素认证(MFA)
- 记住我(Remember Me)功能
tech_stack:
language: typescript
framework: nextjs
database: postgresql
orm: prisma每个字段都有明确的语义,AI 工具在解析时无需做任何猜测。
AI 工具如何消费 OpenSpec
AI 编码助手在接收到 OpenSpec 文件后会经历三个阶段:
结构解析
工具将 YAML 解析为内部数据结构,提取关键信息:
interface ParsedSpec {
constraints: Constraint[] // 硬性限制,不可违反
interface: InterfaceDefinition // 输入输出的类型约束
acceptanceCriteria: AC[] // 验收条件,直接对应测试用例
outOfScope: string[] // 排除范围,防止过度实现
techStack: TechStack // 技术选型,决定生成代码的风格
}约束注入
解析结果被转化为结构化的 System Prompt 注入 LLM 上下文。constraints 被标注为最高优先级,out_of_scope 被明确列为禁止实现,防止模型"顺手"多做:
[CONSTRAINTS - MUST NOT VIOLATE]
- C001: Use argon2id for password hashing. MD5 and SHA1 are forbidden.
- C002: JWT must be set via httpOnly Cookie only.
- C003: Lock account for 900 seconds after 5 consecutive failures.
[INTERFACE CONTRACT]
Input: { email: string(email), password: string(min:8) }
Output: 200 → { user: {id, email, name} } + Set-Cookie header
401 → { error: "Invalid credentials" }
429 → { error: "Account locked", retryAfter: number }
[OUT OF SCOPE - DO NOT IMPLEMENT]
- OAuth / third-party login, MFA, Remember Me
[TECH STACK]
TypeScript + Next.js App Router + Prisma + PostgreSQL验收测试生成
acceptance_criteria 字段直接被转化为测试骨架,每个 testable: true 的条目对应一个 test 块:
// 由 OpenSpec AC001~AC004 自动生成
describe('POST /auth/login', () => {
test('AC001: 正确凭据设置 httpOnly Cookie', async () => {
const res = await request(app).post('/auth/login')
.send({ email: 'user@example.com', password: 'correct-password' })
expect(res.status).toBe(200)
expect(res.headers['set-cookie']).toEqual(
expect.arrayContaining([expect.stringContaining('HttpOnly')])
)
})
test('AC002: 错误凭据返回统一错误信息', async () => {
const res = await request(app).post('/auth/login')
.send({ email: 'user@example.com', password: 'wrong-password' })
expect(res.status).toBe(401)
expect(res.body.error).toBe('Invalid credentials')
})
test('AC003: 连续失败 5 次后锁定账户', async () => {
for (let i = 0; i < 5; i++) {
await request(app).post('/auth/login')
.send({ email: 'user@example.com', password: 'wrong' })
}
const res = await request(app).post('/auth/login')
.send({ email: 'user@example.com', password: 'wrong' })
expect(res.status).toBe(429)
expect(res.body.retryAfter).toBe(900)
})
test('AC004: 登录成功后失败计数归零', async () => {
// ...
})
})这个过程不需要 AI 猜测应该测什么——测什么完全由 Spec 决定。
OpenSpec 与 Agentic Loop
OpenSpec 和 Agentic Loop 的结合是自然的。一个 AI Agent 在拿到 OpenSpec 文件后可以自主执行:
读取 OpenSpec
│
▼
生成实现代码(遵循 constraints + interface)
│
▼
生成测试代码(基于 acceptance_criteria)
│
▼
运行测试
│
├── 全部通过 ──> 输出完成信号,loop 结束
│
└── 存在失败 ──> 分析失败原因,修改实现代码,重新运行测试OpenSpec 在这里扮演了"事实来源"的角色——Agent 在每轮循环中都可以回头对照 Spec 检查自己的实现是否偏离了约束。
安装与使用
OpenSpec 提供了官方的 CLI 工具,将整个 spec-driven 工作流封装为一组命令。
安装
pnpm add -g @fission-ai/openspec@latest初始化项目
cd your-project
openspec init这会在项目里生成 openspec/ 目录和对应的 AI 指令文件。
核心工作流
第一步:探索阶段(可选)
/opsx:explore
AI 会读取代码,分析现有架构,帮你权衡方案。
第二步:创建 Spec 提案
/opsx:propose add-dark-mode
AI 自动在 openspec/changes/add-dark-mode/ 目录下生成四份文件:
openspec/changes/add-dark-mode/
├── proposal.md # 做什么、为什么做
├── specs/ # 需求与验收场景
├── design.md # 技术方案
└── tasks.md # 实现清单
审查并修改这些文件,确认规格正确后再进入实现。
第三步:按 Spec 实现
/opsx:apply
AI 按 tasks.md 中的清单逐条实现,每完成一项打勾。
第四步:归档
/opsx:archive
变更记录被移入 openspec/changes/archive/,保留完整的决策历史。
OpenSpec 官方建议搭配高推理能力模型使用,推荐使用 Opus 4.7 或同等水平的模型。每次开始
/opsx:apply前最好清空 context window,避免历史对话噪音干扰 AI 对 Spec 的理解。
总结
OpenSpec 的本质是给 Spec Coding 加上一层协议。自然语言 Spec 依赖 AI 的理解能力,不同写法给模型的信号强度不同,也难以在工具之间复用。OpenSpec 通过标准化的 YAML 结构将约束、接口、验收标准和范围边界分离到独立字段,让 AI 工具能精确消费每一类信息。
从 Vibe Coding 到 Spec Coding,再到 OpenSpec,本质上是同一件事的三个层次:把对 AI 的输入从"随意"变成"有结构",从"有结构"变成"可标准化"。