OpenSpec实现原理深度解析 **项目热度**截至 2026 年 7 月 18 日OpenSpec 官方 GitHub 仓库 Fission-AI/OpenSpec 已获得61k Stars是目前备受关注的 AI 规格驱动开发Spec-Driven DevelopmentSDD开源项目之一。**版本基线**本文所有概念、命令与实现细节均来自官方仓库 Fission-AI/OpenSpec 及其docs/官方文档、src/源码。OpenSpec 试图解决的并不是“AI 会不会写代码”。它要回答的是另一个更偏工程化的问题当需求、边界与取舍只存在于对话上下文里时团队怎样把它们稳定地沉淀为可审查、可继承、可验证的规格资产。全文分为九节按照“先建立整体认知再拆解实现机制最后回到设计取舍”的顺序展开。1. OpenSpec 是什么AI 编程最脆弱的一环不是模型写不出代码而是需求只活在聊天记录里。同一句“给现有系统增加通知功能”换个会话、换个人、换个模型得到的实现可能完全不同。需求、边界、取舍一旦只存在于对话上下文就无法被审查、被继承、被验证。OpenSpec 给出的解法是加一层轻量的规格spec指对系统行为与边界的书面化约定。在写任何代码之前人和 AI 先就“做什么”达成一致再把这份共识写成文件。它的官方定位是spec-driven developmentSDD规格驱动开发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.mddelta spec指相对当前主规格的增量规格本次变更相对主规格的增量用## ADDED / MODIFIED / REMOVED / RENAMED Requirements分区。这是 OpenSpec 支撑 brownfield 的关键第六章详解。changes//design.md技术方案与架构决策记录选了哪个方案、为什么不选其他、关键约束和数据流。changes//tasks.md实现清单用分组编号 checkbox- [ ] 1.1 .../opsx:apply会逐项勾选。changes//.openspec.yamlchange 的元数据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完成并归档一个 changeexpanded profile需openspec config profile开启命令作用/opsx:new只创建 change 骨架等待后续生成 artifact/opsx:continue按依赖顺序一次创建一个 artifact/opsx:fffast-forward一次性创建全部规划 artifact/opsx:verify校验实现与 artifact 是否一致/opsx:bulk-archive批量归档多个 change/opsx:onboard用真实代码库走一遍完整流程的教学向导同一份 intent多种落地形态。不同 AI 工具的命令语法不同Claude Code 用冒号式/opsx:proposeCursor / Windsurf / Copilot 用连字符式/opsx-proposeKimi、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.mdname: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 展开就是一张有向无环图DAGproposal / \ 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 exploreexplore.ts无产物的思考伙伴。它读代码库、比较多个方案、必要时画图帮你把模糊想法收敛成具体计划。整个过程不创建任何 artifact收敛后可转入/opsx:proposecore或/opsx:newexpanded。适用于需求不清、需要先调研的场景。5.2 propose / new continue ff规划产物的四种节奏这几个 skill 都在解决同一件事——生成规划 artifact区别是粒度和控制力proposepropose.ts一步到位从需求描述直接生成全部applyRequires所需的 artifact。机制见 4.1是最快的端到端路径。newnew-change.ts只创建 change 目录和.openspec.yaml骨架然后停下等你用 continue 或 ff 生成产物。continuecontinue-change.ts查依赖图一次只创建一个ready 的 artifact创建后展示接下来解锁了什么。适合想逐个 review 的复杂变更。ffff-change.tsfast-forward按依赖顺序一次性创建全部 artifact用 todo 跟踪进度直到所有apply-required完成。适合心里有数的中小变更。一句话new是起点continue是单步ff是连跑propose是new ff的一步式封装。5.3 applyapply-change.ts实现阶段。它读tasks.md识别未完成项逐个写代码、建文件、按需跑测试完成一项就把 checkbox 标成[x]。因为进度记录在tasks.md的 checkbox 里所以中断后能续跑也支持通过指定 change 名并行处理多个变更。5.4 verifyverify-change.ts校验阶段回答的不是测试过了吗而是实现和规格一致吗。它在三个维度检查来自docs/commands.md维度校验内容Completeness所有 task 完成、所有 requirement 有对应实现、scenario 被覆盖Correctness实现符合 spec 意图、边界情况被处理Coherencedesign 决策在代码中体现、命名与模式一致它会搜索代码库找实现证据把问题分为CRITICAL / WARNING / SUGGESTION三级。注意verify不阻断archive它只是把问题暴露出来供人判断warnings 不影响归档。5.5 syncsync-specs.ts把 change 的 delta spec 合并进主规格。它解析 delta 的 ADDED / MODIFIED / REMOVED 分区智能合并而非复制粘贴——能往已有 requirement 里追加 scenario 而不重复保留 delta 未提及的既有内容。sync 后 change 仍是 active未归档。多数情况下用户不用手动调它archive 会在需要时自动提示 sync。5.6 archive / bulk-archive收尾与沉淀archivearchive-change.ts检查 artifact 与 task 完成情况未完成会警告但不强制阻断按需 sync delta然后把 change 文件夹移到changes/archive/YYYY-MM-DD-/完整保留 proposal、design、tasks、specs 作为审计轨迹。归档的本质不是合并代码而是把这次变更的规格事实并入 source of truth——归档后这些 spec 就成了后续所有 AI 会话的项目上下文。bulk-archivebulk-archive-change.ts批量归档多个 change并处理跨 change 的规格冲突。冲突解决是 agentic 的——当两个 change 都改了specs/ui/时它会检查代码库里实际实现了什么再按创建时间顺序合并。6. Delta Specbrownfield 的关键设计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.tsdelta 与 spec 的解析在src/core/parsers/。为什么用 delta 而不是全量 spec官方给了四个理由Claritydelta 直接显示改了什么读全量 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产物之间的逻辑自洽是强制的。能跳过的只是可选环节比如designconcepts.md原话 “You can skip design if you don’t need it”以及路径顺序先写 specs 还是先写 design、能否并行。这些属于怎么走OpenSpec 认为不该管——强推固定顺序就退回瀑布模型了而瀑布正是 “iterative not waterfall” 要避开的。一句话OpenSpec 约束的是**“什么必须在什么之前具备”工程纪律而不是你必须按什么顺序操作**官僚流程它刻意只要前者。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/OpenSpecREADMEhttps://github.com/Fission-AI/OpenSpec/blob/main/README.md核心概念 Conceptshttps://github.com/Fission-AI/OpenSpec/blob/main/docs/concepts.md命令参考 Commandshttps://github.com/Fission-AI/OpenSpec/blob/main/docs/commands.md命令如何工作 How Commands Workhttps://github.com/Fission-AI/OpenSpec/blob/main/docs/how-commands-work.mdskill 指令模板源码目录https://github.com/Fission-AI/OpenSpec/tree/main/src/core/templates/workflowsproposeskill 源码https://github.com/Fission-AI/OpenSpec/blob/main/src/core/templates/workflows/propose.tsartifact 依赖图源码目录https://github.com/Fission-AI/OpenSpec/tree/main/src/core/artifact-graph各工具命令生成适配器源码目录https://github.com/Fission-AI/OpenSpec/tree/main/src/core/command-generation/adaptersdelta spec 合并源码https://github.com/Fission-AI/OpenSpec/blob/main/src/core/specs-apply.tsnpm 包https://www.npmjs.com/package/fission-ai/openspec