**项目热度:**截至 2026 年 7 月 18 日,OpenSpec 官方 GitHub 仓库 Fission-AI/OpenSpec 已获得61k Stars,是目前备受关注的 AI 规格驱动开发(Spec-Driven Development,SDD)开源项目之一。
**版本基线:**本文所有概念、命令与实现细节均来自官方仓库 Fission-AI/OpenSpec 及其
docs/官方文档、src/源码。
OpenSpec 试图解决的并不是“AI 会不会写代码”。它要回答的是另一个更偏工程化的问题:当需求、边界与取舍只存在于对话上下文里时,团队怎样把它们稳定地沉淀为可审查、可继承、可验证的规格资产。
全文分为九节,按照“先建立整体认知,再拆解实现机制,最后回到设计取舍”的顺序展开。
1. OpenSpec 是什么
AI 编程最脆弱的一环,不是模型写不出代码,而是需求只活在聊天记录里。同一句“给现有系统增加通知功能”,换个会话、换个人、换个模型,得到的实现可能完全不同。需求、边界、取舍一旦只存在于对话上下文,就无法被审查、被继承、被验证。
OpenSpec 给出的解法,是加一层轻量的规格(spec,指对系统行为与边界的书面化约定)。在写任何代码之前,人和 AI 先就“做什么”达成一致,再把这份共识写成文件。它的官方定位是spec-driven development(SDD,规格驱动开发)for AI coding assistants。
1.1 四条设计哲学
它有四条设计哲学(来自官方 README 与concepts.md)。这四条不是口号,本文后面的实现细节几乎都是它们的落地,所以先讲透每条到底在反对什么、主张什么:
- 灵活,而非死板(fluid not rigid):传统规格流程会把你锁进固定阶段——先规划、再实现、后收尾,一步不能乱。OpenSpec 反对这种硬性阶段闸门,主张按当下最合理的顺序推进。这条哲学的实现落点,就是后面第四章的“依赖是 enabler,不是 gate”。依赖关系只告诉你“现在能做什么”,而不强制“必须先做什么”;因此流程既可以跳过某些环节,也可以并行推进。
- 迭代,而非瀑布(iterative not waterfall):需求会变,理解会加深,一开始看着对的方案,看到代码后可能就不成立了。OpenSpec 承认这种现实,允许你随时回头修改任何产物。这也是为什么
design.md、tasks.md都能在实现过程中回改,而不是一次定死。 - 简单,而非复杂(easy not complex):有些规格框架要大量前置配置、严格格式、繁重流程。OpenSpec 主张几秒钟初始化、最小仪式感。对应到实现上,就是第七章的"渐进严格":默认用最轻的 Lite spec,只有高风险变更才升级到 Full spec,不给小改动强加官僚流程。
- 存量场景优先(brownfield-first):大多数真实开发不是在白纸上从头搭建,而是在一个已经上线运行的系统上做改动。OpenSpec 优先服务这种存量场景,这直接催生了第六章的 delta spec——只描述"相对现状改了什么",而不是重写整份规格。
1.2 两个组件,分处两地
OpenSpec 由两个组件构成,运行在两个不同的地方,且始终协同工作。看懂这层关系,是理解后面所有实现细节的前提:
- CLI 引擎,跑在命令行里:一个叫
openspec的程序,负责初始化项目、解析change(一次待完成的需求变更)结构、校验、合并 delta、归档。它是所有工具通用的规则中枢,无论你用哪个 AI 助手,规则都一样。可以把它理解为整套系统的发动机。 - Slash 命令 / Skill,跑在 AI 对话框里:像
/opsx:propose这样的命令,你在聊天窗口输入,它指导 AI 按 OpenSpec 的流程干活。这里的 Skill 可以理解为一份可被宿主发现并按需加载的工作流说明。它是你操作这套系统的方向盘。
两者不是二选一,而是分工协作,连接点是openspec init:你在命令行运行它,它把对话框要用的 skill / 命令文件"安装"进你的 AI 工具。此后日常操作主要在聊天窗口完成。
它们在一次实际操作中如何串联?关键是中间还隔着一个执行者——AI。三者构成一条自上而下的链路:
你(在聊天框输入 /opsx:propose) │ ▼ ① Skill:聊天框里的入口 本体是一份写给 AI 的 markdown 指令,告诉 AI 该做什么 │ ▼ ② AI:按 skill 指令,执行 openspec CLI 命令 如 openspec new change / status --json / instructions --json │ ▼ ③ CLI 引擎:返回结构化数据 哪些 artifact 就绪、用什么模板、写到哪个路径 │ ▼ AI 据此写出 proposal.md / design.md / tasks.md 等文件所以准确地说,Skill 并不直接调用 CLI,真正发起调用的是“按 Skill 指令行事的 AI”。正因为隔着 AI 这层、且 Skill 只依赖 CLI 的稳定输出而非某个模型的内部行为,这套 Skill 才能跨模型、跨工具复用。这个分层是后面所有实现细节的根基,第四章会结合源码展开。
2. 目录与文件体系
OpenSpec 的全部状态都落在项目里的openspec/目录。先看整体结构,再逐个文件解释。
openspec/ ├── specs/ # source of truth:系统当前的行为 │ └── / │ └── spec.md ├── changes/ # 进行中的变更,每个 change 一个文件夹 │ ├── / │ │ ├── proposal.md # why & what │ │ ├── design.md # how(技术方案) │ │ ├── tasks.md # 实现清单 │ │ ├── .openspec.yaml # change 元数据 │ │ └── specs/ # delta spec(本次变更相对主规格的增量) │ │ └── / │ │ └── spec.md │ └── archive/ # 已归档的 change │ └── YYYY-MM-DD-/ └── schemas/ # workflow schema 定义(可自定义)这个结构里最关键的设计,是specs/和changes/的分离(官方concepts.md明确称之为 “The Big Picture”):
specs/是 source of truth,描述系统"现在"如何工作。changes/是提案,描述"想怎么改",在归档前不会污染主规格。
这种分离带来三个直接好处:多个 change 可以并行而互不冲突;change 在合并前可被独立 review;归档时增量干净地并入 source of truth。
逐个文件说明:
specs//spec.md(主规格):按领域(auth/、payments/等)组织。内部结构是## Purpose+ 若干### Requirement:+ 每个 requirement 下的#### Scenario:。requirement 用 RFC 2119 关键词(MUST/SHALL/SHOULD/MAY)表达强度,scenario 用 Given/When/Then 描述可验证的具体场景。官方强调:spec 是行为契约(behavior contract),不是实现计划——不写类名、函数名、库选型这些实现细节。changes//proposal.md:捕捉意图与范围,核心是 Why(为什么做)、Scope(边界,含 in scope / out of scope)、Approach(高层方向)。changes//specs//spec.md(delta spec,指相对当前主规格的增量规格):本次变更相对主规格的增量,用## ADDED / MODIFIED / REMOVED / RENAMED Requirements分区。这是 OpenSpec 支撑 brownfield 的关键,第六章详解。changes//design.md:技术方案与架构决策,记录选了哪个方案、为什么不选其他、关键约束和数据流。changes//tasks.md:实现清单,用分组编号 + checkbox(- [ ] 1.1 ...),/opsx:apply会逐项勾选。changes//.openspec.yaml:change 的元数据(schema 名、创建时间等)。注意:它是元数据,不是一个 draft→approved→archived 的阶段状态机——OpenSpec 并没有强制阶段闸门(对应 “fluid not rigid”)。
3. 命令与 Skill 的真实形态
OpenSpec 的官方命令是/opsx:*系列,分两套 profile(来自docs/commands.md)。
core profile(默认安装):
| 命令 | 作用 |
|---|---|
/opsx:explore | 动手前的"思考伙伴",读代码、比较方案,不产出任何文件 |
/opsx:propose | 一步创建 change 并生成全部规划产物 |
/opsx:apply | 按tasks.md实现,逐项勾选 |
/opsx:sync | 把 delta spec 合并进主规格(通常自动触发) |
/opsx:archive | 完成并归档一个 change |
expanded profile(需openspec config profile开启):
| 命令 | 作用 |
|---|---|
/opsx:new | 只创建 change 骨架,等待后续生成 artifact |
/opsx:continue | 按依赖顺序一次创建一个 artifact |
/opsx:ff | fast-forward,一次性创建全部规划 artifact |
/opsx:verify | 校验实现与 artifact 是否一致 |
/opsx:bulk-archive | 批量归档多个 change |
/opsx:onboard | 用真实代码库走一遍完整流程的教学向导 |
同一份 intent,多种落地形态。不同 AI 工具的命令语法不同:Claude Code 用冒号式/opsx:propose,Cursor / Windsurf / Copilot 用连字符式/opsx-propose,Kimi、Trae 等则以 skill 名义暴露(如/skill:openspec-propose)。intent 一致,写法因工具而异。
这些命令文件从哪来?运行openspec init或openspec update时,CLI 会为你选定的每个工具生成对应文件:skill 落在.claude/skills/openspec-*/SKILL.md这类位置,command 落在.claude/commands/opsx/*.md这类位置。skill 是新兴的跨工具标准(一个装满指令的文件夹,助手自动识别),command 是较旧的按工具定制的 slash command 文件。用户不需要关心用的是哪种,输入 slash 命令即可。
在源码里,这套生成机制对应两个目录:
src/core/templates/workflows/*.ts:每个命令的指令模板(skill 的正文内容)src/core/command-generation/adapters/*:各工具的适配器(把统一模板落成该工具认识的文件格式,仓库里能看到claude.ts、cursor.ts、windsurf.ts、codex.ts、gemini.ts等 20 多个)
这正是 OpenSpec 能支持 25+ 工具的原因:规则(CLI 引擎)只写一遍,方向盘(各工具 skill)由适配器批量生成。
4. 核心机制:Skill 是"指令 + CLI",引擎是 Artifact 依赖图
这是全文最核心的一章,回答两个问题:一个 skill 内部到底写了什么?它凭什么知道"下一步该创建哪个文件"?
4.1 一个 skill 内部长什么样
大多数人以为 skill 是一段程序。但读src/core/templates/workflows/propose.ts源码会发现,它其实是一份写给 AI 的自然语言指令,包在一个数据结构里:
exportfunctiongetOpsxProposeSkillTemplate():SkillTemplate{return{name:'openspec-propose',description:'Propose a new change with all artifacts generated in one step...',instructions:`... 一大段步骤化的自然语言指令 ...`,license:'MIT',compatibility:'Requires openspec CLI.',metadata:{author:'openspec',version:'1.0'},};}真正起作用的是instructions字段。它没有让 AI"凭感觉生成文件",而是把 AI 变成一个听命于 CLI 的执行器:每一步都先调openspecCLI,拿到结构化数据,再照着数据干活。以propose为例,指令编排的流程是:
- 明确需求:用户没说清就用 AskUserQuestion 追问,并把描述转成 kebab-case 的 change 名。
- 建骨架:
openspec new change "",生成 change 目录和.openspec.yaml。 - 问引擎"要做哪些文件、按什么顺序":
openspec status --change "" --json,拿到applyRequires(实现前必须完成的 artifact 清单)、artifacts(全部 artifact 及其状态和依赖)、以及changeRoot、artifactPaths等路径信息。 - 逐个生成 artifact:对每个"就绪"的 artifact,调
openspec instructions --change "" --json领取它的"作业要求"——template(文件结构)、instruction(写作指引)、resolvedOutputPath(写到哪)、dependencies(先读哪些已完成的文件)、context与rules(约束)。AI 先读依赖文件补上下文,再按template写出文件;每写完一个就重新查 status,直到applyRequires全部完成。 - 收尾:展示状态,提示运行
/opsx:apply。
这里有一个容易被忽略的巧思:context和rules只约束 AI 怎么写,不能出现在产物里。指令中反复强调 “constraints for YOU, not content for the file”、“Do NOT copy them into the file”。项目背景和规则会影响 AI 的判断,但不会污染 spec 本身,产物因此保持干净。
一句话总结这一节:skill 的实现 = 一份步骤化的 markdown 指令 + 对 CLI 的结构化调用。所有真正的逻辑——依赖怎么解析、路径怎么算、状态怎么判断——都在 CLI 里;skill 只负责把这些能力编排成一条 AI 能照着走的流水线。这正是 skill 能跨模型、跨工具复用的根本原因:它不赌某个模型的"聪明程度",只依赖 CLI 稳定的结构化输出。
4.2 引擎:Artifact 依赖图
上一节反复出现的openspec status --json,凭什么知道哪些文件"就绪"、哪些"还不能做"?答案是 OpenSpec 真正的引擎——artifact 依赖图(源码在src/core/artifact-graph/)。它描述了一个工作流有哪些 artifact、谁依赖谁,而这张图的具体定义方式,就是schema。
这张图并非硬编码在引擎代码里,而是由一份 schema 配置定义——引擎读 schema、照着搭图。换套 schema 就能换一套工作流,引擎代码一行不用动(这一点稍后展开)。默认的spec-drivenschema 如下(来自concepts.md):
name:spec-drivenartifacts:-id:proposalgenerates:proposal.mdrequires:[]# 无依赖,可最先创建-id:specsgenerates:specs/**/*.mdrequires:[proposal]-id:designgenerates:design.mdrequires:[proposal]# 与 specs 并列,都只依赖 proposal-id:tasksgenerates:tasks.mdrequires:[specs,design]# 需要 specs 和 design 都就绪这段 schema 展开就是一张有向无环图(DAG):
proposal / \ specs design \ / tasks引擎据此运转,分工很清晰:
resolver:拿这张图比对每个文件的当前状态,算出每个 artifact 是done(已完成)、ready(依赖齐了可以做)还是blocked(依赖没齐)。这就是status --json那份状态清单的来源。instruction-loader:当某个 artifact 要生成时,把它的template、rules、instruction等装配好,交给 skill(也就是 4.1 里openspec instructions返回的内容)。
理解整套设计的一句话(官方原文):依赖是 enabler,不是 gate。依赖只告诉你"现在能做什么",绝不强制"必须先做什么"。所以你可以跳过design直接写tasks之前的部分,也可以让specs和design任意先后甚至并行——它俩都只依赖proposal。这正是第一章"灵活而非死板"落到实现层的样子:图的作用是点亮下一步的可选项,而不是设卡拦人。
正因为流程是 schema 定义的,它就能被替换。想要不同的工作流,自定义 schema 即可:openspec schema init从零建,openspec schema fork spec-driven基于内置的改。比如定义一个"研究先行"的 schema,让research当根节点、proposal依赖它,整条流水线的形状就变了,而 skill 的代码一行都不用动。
5. 逐个 Skill 实现原理
有了第四章的框架,每个 skill 就好理解了:它们都是"markdown 指令 + 调用 CLI",区别只在编排的流程不同。每个 skill 对应src/core/templates/workflows/下的一个模板文件。
5.1 explore(explore.ts)
无产物的思考伙伴。它读代码库、比较多个方案、必要时画图,帮你把模糊想法收敛成具体计划。整个过程不创建任何 artifact,收敛后可转入/opsx:propose(core)或/opsx:new(expanded)。适用于需求不清、需要先调研的场景。
5.2 propose / new + continue + ff(规划产物的四种节奏)
这几个 skill 都在解决同一件事——生成规划 artifact,区别是粒度和控制力:
- propose(
propose.ts):一步到位,从需求描述直接生成全部applyRequires所需的 artifact。机制见 4.1,是最快的端到端路径。 - new(
new-change.ts):只创建 change 目录和.openspec.yaml骨架,然后停下,等你用 continue 或 ff 生成产物。 - continue(
continue-change.ts):查依赖图,一次只创建一个ready 的 artifact,创建后展示"接下来解锁了什么"。适合想逐个 review 的复杂变更。 - ff(
ff-change.ts):fast-forward,按依赖顺序一次性创建全部 artifact,用 todo 跟踪进度,直到所有apply-required完成。适合心里有数的中小变更。
一句话:new是起点,continue是单步,ff是连跑,propose是"new + ff"的一步式封装。
5.3 apply(apply-change.ts)
实现阶段。它读tasks.md,识别未完成项,逐个写代码、建文件、按需跑测试,完成一项就把 checkbox 标成[x]。因为进度记录在tasks.md的 checkbox 里,所以中断后能续跑,也支持通过指定 change 名并行处理多个变更。
5.4 verify(verify-change.ts)
校验阶段,回答的不是"测试过了吗",而是"实现和规格一致吗"。它在三个维度检查(来自docs/commands.md):
| 维度 | 校验内容 |
|---|---|
| Completeness | 所有 task 完成、所有 requirement 有对应实现、scenario 被覆盖 |
| Correctness | 实现符合 spec 意图、边界情况被处理 |
| Coherence | design 决策在代码中体现、命名与模式一致 |
它会搜索代码库找实现证据,把问题分为CRITICAL / WARNING / SUGGESTION三级。注意:verify不阻断archive,它只是把问题暴露出来供人判断(warnings 不影响归档)。
5.5 sync(sync-specs.ts)
把 change 的 delta spec 合并进主规格。它解析 delta 的 ADDED / MODIFIED / REMOVED 分区,智能合并而非复制粘贴——能往已有 requirement 里追加 scenario 而不重复,保留 delta 未提及的既有内容。sync 后 change 仍是 active(未归档)。多数情况下用户不用手动调它,archive 会在需要时自动提示 sync。
5.6 archive / bulk-archive(收尾与沉淀)
- archive(
archive-change.ts):检查 artifact 与 task 完成情况(未完成会警告但不强制阻断),按需 sync delta,然后把 change 文件夹移到changes/archive/YYYY-MM-DD-/,完整保留 proposal、design、tasks、specs 作为审计轨迹。归档的本质不是"合并代码",而是把这次变更的规格事实并入 source of truth——归档后这些 spec 就成了后续所有 AI 会话的项目上下文。 - bulk-archive(
bulk-archive-change.ts):批量归档多个 change,并处理跨 change 的规格冲突。冲突解决是 agentic 的——当两个 change 都改了specs/ui/时,它会检查代码库里实际实现了什么,再按创建时间顺序合并。
6. Delta Spec:brownfield 的关键设计
delta spec 是让 OpenSpec 适配存量代码库的核心概念。它描述的是"相对当前规格改了什么",而不是重述整份 spec。
格式上用四类分区(来自concepts.md):
## ADDED Requirements ### Requirement: Two-Factor Authentication The system MUST support TOTP-based two-factor authentication. #### Scenario: 2FA enrollment - GIVEN a user without 2FA enabled - WHEN the user enables 2FA in settings - THEN a QR code is displayed ... ## MODIFIED Requirements ### Requirement: Session Expiration The system MUST expire sessions after 15 minutes of inactivity. (Previously: 30 minutes) ## REMOVED Requirements ### Requirement: Remember Me (Deprecated in favor of 2FA.)归档时各分区的处理方式:
| 分区 | 含义 | archive 时的动作 |
|---|---|---|
## ADDED Requirements | 新增行为 | 追加到主规格 |
## MODIFIED Requirements | 变更行为 | 替换主规格里对应的 requirement |
## REMOVED Requirements | 废弃行为 | 从主规格删除 |
(此外还有RENAMED用于重命名。)合并逻辑在src/core/specs-apply.ts,delta 与 spec 的解析在src/core/parsers/。
为什么用 delta 而不是全量 spec,官方给了四个理由:
- Clarity:delta 直接显示改了什么,读全量 spec 得靠脑补 diff。
- 冲突规避:两个 change 只要改的是不同 requirement,就能同时改同一个 spec 文件而不冲突。
- Review 效率:reviewer 只看变更,不看未变的上下文。
- Brownfield 契合:真实工作大多是"改存量",delta 让"修改"成为一等公民。
7. 关键设计决策解析
以下每条都能在官方文档找到依据,帮助理解"为什么这样实现":
spec 是行为契约,不是实现计划。
concepts.md给了一个判断标准:如果实现可以改变而外部可见行为不变,那它就不该进 spec。类名、库选型、执行步骤属于design.md/tasks.md,不属于 spec。这保证 spec 长期稳定、可测试。依赖是 enabler 而非 phase gate。这是 “fluid not rigid” 的实现落点——依赖图用来点亮"可创建的下一步",而不是强制顺序。这也是 OpenSpec 与重量级、强阶段闸门的方案(如官方对比中提到的 Spec Kit)刻意拉开的差异。
这里容易产生一个疑问:OpenSpec 不就是想用工作流约束研发过程吗?允许随意跳过,岂不违背初衷?关键在于,它约束的是"结果",不是"路径"。
- 硬约束(真正的 gate)只有一条:写代码(
apply)之前,规格必须就绪。这条落在 schema 的applyRequires上——propose/ff会一直循环生成 artifact,直到applyRequires列表全部done才停,跳不过去。这守住了"先对齐再写码"的初衷。 - 结构约束由 DAG 保证:
tasks依赖specs和design,所以你无法在没有 specs 的情况下凭空生成 tasks,产物之间的逻辑自洽是强制的。 - 能"跳过"的只是可选环节:比如
design(concepts.md原话 “You can skip design if you don’t need it”),以及路径顺序(先写 specs 还是先写 design、能否并行)。这些属于"怎么走",OpenSpec 认为不该管——强推固定顺序就退回瀑布模型了,而瀑布正是 “iterative not waterfall” 要避开的。
一句话:OpenSpec 约束的是**“什么必须在什么之前具备”(工程纪律),而不是"你必须按什么顺序操作"**(官僚流程),它刻意只要前者。
- 硬约束(真正的 gate)只有一条:写代码(
specs 与 changes 目录分离。source of truth 与提案分开,换来并行、可 review、干净归档三个好处。
Progressive Rigor(渐进严格)。默认用 Lite spec(简短的行为优先要求 + 清晰范围 + 几条验收点),只有高风险变更(跨团队、API/契约变更、迁移、安全隐私)才升级到 Full spec。避免为小改动引入官僚流程。
context / rules 不写进产物。如 4.1 所述,项目背景和规则只作为 AI 的约束,不落入 spec 文件,保证产物纯净。
8. 结语
OpenSpec 的实现哲学可以浓缩成一句话:把规则沉淀进 CLI 引擎,把编排交给 skill 指令,把事实沉淀进 specs 目录。skill 之所以能跨模型、跨工具稳定复用,是因为它从不依赖某个模型的内部行为,只依赖 CLI 的结构化输出与 artifact 依赖图。真正让 AI 编程可预测的,不是更强的提示词,而是这层"人和 AI 动手前先对齐、动手后可沉淀"的轻量规格。
到这里,OpenSpec 的实现脉络可以收束为一条很清晰的主线:先用规格文件把需求事实固定下来,再用 CLI 引擎维护 artifact 依赖与生成顺序,最后让不同宿主中的 Skill 复用同一套结构化输出与工作流语义。它真正提供的,不是一组更复杂的命令,而是一种让 AI 编程结果能够沉淀为长期工程资产的最小规格层。
9. 参考链接(官方)
- 仓库主页:https://github.com/Fission-AI/OpenSpec
- README:https://github.com/Fission-AI/OpenSpec/blob/main/README.md
- 核心概念 Concepts:https://github.com/Fission-AI/OpenSpec/blob/main/docs/concepts.md
- 命令参考 Commands:https://github.com/Fission-AI/OpenSpec/blob/main/docs/commands.md
- 命令如何工作 How Commands Work:https://github.com/Fission-AI/OpenSpec/blob/main/docs/how-commands-work.md
- skill 指令模板源码目录:https://github.com/Fission-AI/OpenSpec/tree/main/src/core/templates/workflows
proposeskill 源码:https://github.com/Fission-AI/OpenSpec/blob/main/src/core/templates/workflows/propose.ts- artifact 依赖图源码目录:https://github.com/Fission-AI/OpenSpec/tree/main/src/core/artifact-graph
- 各工具命令生成适配器源码目录:https://github.com/Fission-AI/OpenSpec/tree/main/src/core/command-generation/adapters
- delta spec 合并源码:https://github.com/Fission-AI/OpenSpec/blob/main/src/core/specs-apply.ts
- npm 包:https://www.npmjs.com/package/@fission-ai/openspec