Obi Madu 的博客
返回所有文章
AI EngineeringAITips & Tricks

读懂 OpenSpec

用简单的语言讲清楚 OpenSpec 的 profiles、schemas、artifacts、config、skills 和 delta specs。

读懂 OpenSpec

我接触 OpenSpec 时,以为它就是几个命令加一些 Markdown。至少它早期给我留下的是这种印象。

然后我打开文档,看到了 profiles、schemas、artifacts、config 文件、archive 流程、OPSX,还有 delta specs。我花了比我想承认的更多的时间,在几个标签页之间来回切换,想把所有东西都装进脑子里。到底什么是 artifact?为什么 profiles schemas 都存在?如果两者都影响工作流,为什么都需要存在?

这就是我当时希望看到的解释,而不是那些标签页。

OpenSpec 是什么?

OpenSpec 是一个 spec-driven 的开发框架。它和你的代码一起住在仓库里,能和大多数编程 agent 一起工作:Claude Code、Cursor、Codex、GitHub Copilot、OpenCode 等等。用 npm install -g @fission-ai/openspec@latest 安装,它就给你的 agent 加上了规划命令。

思路很简单。在写代码之前,先描述你想做的改动。OpenSpec 会生成一份提案、一份设计文档、一份任务拆解,以及一个 spec delta,显示需求将如何变化。你审阅这份计划,打磨它,然后再去实现。改动完成后,spec delta 会被应用到你的 canonical specs 上,这样仓库里的需求就保持最新了。

最后这一步是它和 agent 自带 plan 模式的区别。plan 模式在 chat session 结束时就没了。OpenSpec 的 specs 作为活文档留在仓库里,提交到 git,可以在 PR 里审阅。

项目开源在 openspec.dev

简版

当我把 OpenSpec 归结为四个问题之后,它对我来说就变得容易多了:

概念它回答的问题
Profile我的 agent 可以用哪些工作流动作?
Schema存在哪些规划 artifact,以及什么依赖什么?
Config应该用哪些项目上下文和额外规则来塑造这些 artifact?
Skills我的 AI 工具如何执行每个工作流动作?

Artifact 是这个系统产出的东西:提案、specs、设计、任务,或你的 schema 定义的其他任何东西。

为什么这套术语感觉是分层的

当你看 OpenSpec 是怎么演化过来的,一些困惑就比较好理解了。

早期的工作流有意做得很小:

propose -> apply -> archive

提案这一步生成规划文档,agent 实现改动,archive 把结果折回项目的 specs 里。

之后 OPSX 让系统更灵活了。规划变成了一组离散的 artifact,通过依赖关系连接。你可以增量地创建它们,边做边修改,并自定义这个图,而不是接受一个写死的过程。

这种灵活性带来了更多动作:

new -> continue or ff -> apply -> verify -> archive

OpenSpec 1.2 然后引入了 profiles。重点不是再加一层规划抽象。Profile 控制安装哪些工作流 skills 和命令,让想要短路径的人不需要在 agent 的上下文里塞进每一个扩展命令。

当前的 core profile 给你快路径:

explore -> propose -> apply -> sync -> archive

扩展工作流在你想要更细控制时,暴露 newcontinueffverify 这些动作。

这段历史很重要。Profiles 和 schemas 看着像同一个想法的两代产品。其实不是,这种困惑是我浪费最多时间的地方。

Profiles vs. Schemas

这是我卡得最久的地方。我原以为 profiles 和 schemas 是两种相互竞争的、定义工作流的方式。

它们是正交的。

Profile 控制你可用的动作。Schema 控制这些动作所作用的规划结构。

这句话我在文档里读了三遍才理解,所以我这里要多花点篇幅。

Profile 选择控制项

Profile 不定义 proposal.mddesign.mdtasks.md。它决定 OpenSpec 给你的 AI 工具安装哪些工作流动作。

用 core profile 时,/opsx:propose 给你简单的体验:描述改动,一次性生成所有规划 artifact。

选择扩展后,你可以更有意识地操作:

  • /opsx:new 创建改动的脚手架。
  • /opsx:continue 创建下一个可用的 artifact。
  • /opsx:ff 创建所有能生成的规划 artifact。
  • /opsx:verify 在 archive 之前把实现和 artifact 进行对比。

所以我最初的简略说法接近正确,但不够准确。Profile 不说"全部生成"或"只生成一个"。Profile 让这些动作可用;你选哪个命令决定接下来发生什么。

Schema 定义规划图

Schema 回答另一个问题:这个改动应该包含什么?

默认的 spec-driven schema 包含提案、specs、设计和任务这些 artifact。它也描述它们的依赖。简化视图长这样:

              proposal
              /      \
           specs    design
              \      /
                tasks

这个图就是为什么 /opsx:continue 能判断哪个 artifact 已经就绪,哪个还被阻塞。OpenSpec 检查磁盘上有什么,并遵循 schema 的依赖规则。

自定义 schema 可以加一个研究或安全评审的 artifact:

research -> proposal -> specs -> security-review -> tasks

Profile 不需要改。同一个 continueff 动作可以遍历不同的 schema。

就在这一刻,profiles 和 schemas 在我脑子里终于分开了:profile 给你控制项;schema 给这些控制项提供作用对象。

OpenSpec 说的"Artifact"是什么意思

"Artifact"这个词让系统听起来比实际更抽象。

Artifact 是 schema 定义的产出。大多数是 Markdown 文件,或一组 Markdown 文件:

proposal.md
design.md
tasks.md
specs/<capability>/spec.md

没有在后台运行的特殊的 artifact 对象。OpenSpec 主要从文件系统推断状态:如果需要的产出存在,这个 artifact 就完成了,它的依赖项可能就可用。

这个词还是重要的,因为 schema 可以定义不止一种文件形态。比如 specs artifact 可以生成一个 delta specs 目录,而不是一个固定文件。但作为用户,有用的翻译是:

Artifact = 一次改动过程中产出的规划物。

用熟悉的话讲 Proposal、Specs、Design 和 Tasks

用普通的项目语言来理解这些,对我来说容易得多:

OpenSpec artifact熟悉的对应物主要问题
Proposal商业案例我们为什么做这个,范围是什么?
Specs需求系统必须做什么?
Design技术方案我们要怎么建?
Tasks实现清单还有哪些工作要完成?

当我不再把这些当作 OpenSpec 专属的发明,工作流就感觉熟悉了。它们就是任何一个体面团队本来就会产出的文档,只不过这里的工具知道这些文档。

Main Specs vs. Delta Specs

有一个区别我有一阵子没注意到:OpenSpec 处理两种规格。

openspec/specs/ 下的 specs 描述系统现在是怎么运作的。它们是按能力组织的、权威的事实源。

一个改动内部的 specs 只描述这个改动添加、修改或删除的内容。那些是 delta specs

openspec/specs/                 current system
openspec/changes/add-2fa/specs/ proposed difference

这就是为什么改动可以不重写整个规格就能被审阅。审阅者看到的是差异,不是另一份完整副本。

当改动被 sync 或 archive 时,这些 delta 会被应用到 canonical specs 上。添加的需求被追加,修改的需求替换之前版本,删除的需求被删除。

这就是 OpenSpec 说"把规格作为活文档保存"的意思。

config.yaml 实际上做什么

我原本以为 openspec/config.yaml 用来定义工作流。它不是。

它配置的是工作流周围的项目:

schema: spec-driven

context: |
  Stack: TypeScript, React, PostgreSQL
  Public APIs must remain backwards compatible

rules:
  proposal:
    - Include a rollback plan
  tasks:
    - Include tests for every requirement

这个文件有三个主要工作:

  1. 选择默认的 schema。
  2. 把项目上下文注入到每个 artifact 的指令里。
  3. 按 ID 把额外规则注入到特定的 artifact。

它不添加新的 artifact,也不改变它们的依赖。那属于 schema 的事。

这个区别给了一条有用的经验法则:

  • 如果你想改变存在哪些文件,改 schema。
  • 如果你想改变生成的文件应该考虑什么,改 config。

Schemas vs. Skills

我接下来错在这里。我以为 schema 也是所有 agent 行为应该放的地方。

Schema 可以包含生成其 artifact 的模板和指令,但它们不替代 skills。

Schema 描述规划模型:artifact ID、输出路径、模板和依赖。生成的 OpenSpec skills 教 AI 工具如何执行 propose、continue、apply、sync 和 archive 这些动作。

所以如果我在任务之前想要一个新的 security-review.md,那是 schema 的改动。

如果我想让我的编程 agent 在实现时遵循 TDD,那属于实现 skill 或项目指令。如果我只是想让每个生成的任务清单提到测试,config.yaml 里的一条 tasks 规则可能就够了。

这些是相关的事,但它们在不同层,把它们混在一起是我大多数困惑的来源。

Archive 能防止文档过期吗?

这是我最后一个放不下的问题。

Archive 做两件有用的事:把完成的改动移到历史里,并确保 delta specs 能被同步到 canonical specs 里。这避免了把多份相互竞争的需求版本散落在活跃的改动文件夹里。

Archive 做的是证明代码和规格匹配。

扩展的 /opsx:verify 动作检查实现和规划 artifact 之间的完整性、正确性和一致性。即便如此,这个过程仍然依赖评审和工程纪律。没有任何 archive 命令能让一个不准确的 spec 变成真的。

所以 OpenSpec 减少了一种文档漂移:被遗弃或相互竞争的需求文档。它本身并不弥合书面意图和实际软件之间的差距。那部分仍然在你。

终于在我脑子里成形的心智模型

这是我现在记在脑子里的版本:

Profile -> chooses the available workflow actions
Schema  -> defines the artifact dependency graph
Config  -> injects project context and artifact-specific rules
Skills  -> teach the agent how to perform those actions
Files   -> record the state of the change

或者一句话:

OpenSpec 安装一组 agent 动作,在一个 schema 定义的图上运行它们,用项目 config 塑造它们的输出,并把进度作为文件记录在你的仓库里。

当我这样看的时候,profile、schema 和 artifact 这些词就不再相互竞争了。每一个都有清晰的边界。

OpenSpec 最难的部分不是命令数量。而是那些熟悉的词在系统内部带有非常具体的含义,文档又不总是把这些边界讲清楚。如果你卡在术语上,你不是一个人,我花了一阵子,这篇文章大部分就是我走到这里所走的路。

延伸阅读