news 2026/9/29 3:50:57

OpenSpec实战:规范驱动开发如何用CLI管好需求与代码同步

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenSpec实战:规范驱动开发如何用CLI管好需求与代码同步

1. 为什么是 OpenSpec:规范驱动开发要解决的实际痛点

1.1 从一次真实“文档翻车”说起

前阵子我们团队接了一个中型 Web 项目,需求散落在飞书文档、Confluence、微信群聊天记录里。开发到第二周,产品经理口头确认的一个“小改动”被谁忘掉了,测试阶段才发现功能行为和验收标准对不上。更麻烦的是,AI 编码助手成了日常开发的一部分之后,新问题出现了:它很擅长“脑补”需求,你让它实现一个列表筛选,它把排序、分页、空态全帮你做了,看起来很勤奋,可这些不是你要的。

我当时的反应是:缺的不是更严格的代码评审,而是一个能让需求和代码之间建立强制映射的机制。后来接触到了 OpenSpec,它的思路很直接:把规范文件直接放进代码仓库里,用 CLI 工具管理规范的创建、变更、校验和快照,让需求、任务、实现之间不再是三张皮,而是同一份被 Git 跟踪着的活文档。

这篇博文我会做两件事:先从源码和仓库结构层面拆解 OpenSpec 这个项目,再把分析结果落成一个可执行的网站开发方案。无论你是想引入规范驱动开发,还是想为自己的开源项目搭建官网和文档站,都可以直接参考这套思路。

1.2 规范驱动开发,到底驱动的是什么

传统流程里,需求文档通常躺在文档系统里,代码在 Git 仓库里,两者唯一的联系方式是“人肉记忆”。一旦文档更新不及时,或者需求被口头变更,代码就悄悄偏离了预期。OpenSpec 解决这个问题的核心动作是:把需求变成仓库里的 Markdown 文件,并且给每一条需求一个稳定的 ID 和验收标准,代码提交时这些文件必须保持同步。

从概念层面看,OpenSpec 主要引出了几个角色:

  • Proposal(提案):一个待实施的功能变更或修复,相当于传统流程里的“需求变更单”。它有自己的名称、背景说明、目标。
  • Requirement(需求项):提案内部拆成的最小可验收单元,每条都有明确的验收标准,是后续校验的基本单位。
  • Task(任务):把需求项映射为具体的开发任务,每个任务对应代码侧的一组文件或模块改动。
  • Snapshot(快照):某个时间点所有需求项和实现状态的存档,方便回滚、审计和追踪进度。

这套命名听起来很朴素,但它解决了一个实际问题:需求变更不再是聊天记录里的几句话,而是仓库里的一次提交。谁改的、什么时候改的、改了什么,全部有迹可循。

1.3 和传统方案对比:为什么没选 RFC、ADR 或 BDD

接触过架构设计的人可能会问:我们有 RFC、ADR、BDD,为什么还需要 OpenSpec?我的对比体会是:

方案擅长解决的问题局限性
RFC重大技术方案的讨论与决策偏评审流程,事后没人维护
ADR记录架构决策及理由只记录“为什么”,不约束“做什么”
BDD用可执行用例驱动实现需要编写和维护测试代码,门槛高
OpenSpec需求、任务、实现三者强制同步生态还年轻,适合有纪律的小团队

RFC 和 ADR 本质上是对“决策过程”的管理,写完存进 docs 目录就结束了;BDD 是很强的约束,但它把重心放在可执行的测试用例上,业务人员参与成本高。OpenSpec 正好卡在中间:它用轻量的 Markdown 作为规范载体,不强制你写代码测试,但通过 CLI 的校验逻辑确保需求项和任务必须完整映射。这对“AI 辅助编程 + 小型产品团队”的场景尤其合适。

2. 仓库源码解剖:OpenSpec 的 CLI 架构与核心模块

2.1 技术栈与仓库的第一印象

打开 OpenSpec 仓库,第一感觉是干净。项目主体用 TypeScript 编写,跑在 Node.js 运行时上,通过 npm 分发 CLI 工具。整个仓库不是单体大泥球,而是按“CLI 入口 + 核心模型 + 命令实现 + 测试夹具”的方式组织,这对一个尚在早期阶段的开发工具来说是比较理性的选择。

顶层目录结构大致是这样:

OpenSpec/ ├── src/ │ ├── cli/ # 命令解析与各子命令入口 │ ├── commands/ # 具体命令实现 │ ├── models/ # Proposal、Requirement、Task 等类型定义 │ ├── services/ # 文件扫描、校验、快照等核心服务 │ └── utils/ # 通用工具 ├── tests/ │ ├── fixtures/ # 测试用的示例仓库结构 │ └── unit/ # 单元测试 ├── docs/ ├── package.json └── tsconfig.json

如果你准备给这个仓库写代码或者做二次开发,建议先从models和services入手,因为整个工具的运转逻辑都围绕这两层:模型负责“规范长什么样”,服务负责“怎么解析、校验、生成快照”。

2.2 核心模块拆解:命令层、模型层、校验层

命令层是所有用户接触的第一个窗口。OpenSpec 的 CLI 采用了一套典型的“子命令 + 参数”模式,比如初始化、创建提案、生成计划、校验、创建快照等操作都有对应命令。命令层本身做得很薄,它只负责收参数、调服务、打印输出,真正复杂的逻辑在下层。

模型层定义的是规范文件的数据结构。每条 Proposal 包含元信息和一组 Requirement,每个 Requirement 又关联 Task。我在读源码时注意到,模型层不是简单的“字典结构”,而是有明确的必填字段和可选字段约束,比如需求项必须有稳定的标识符和验收标准描述。这保证了后续校验服务能基于统一的结构做判断。

校验服务是整个仓库里技术含量最高的部分。它做的事情是:扫描仓库里的规范目录,检查提案下的需求项是否都映射到了任务,检查任务状态是否和代码改动对应,检查是否存在遗留的无效引用。说白了,它就是把“文档和代码同步”这个模糊目标翻译成了一系列可自动化检查的规则。

举个具体例子:如果工程师只改了代码,没有在对应任务中更新实现状态,校验服务会直接报错,CI 就会挂掉。这种“硬约束”比任何 Code Review 提醒都有效——因为它是流程层面的强制门槛。

2.3 一次提案从创建到快照的完整流转

结合源码里的调用链,我理出了一段很典型的提案生命周期,看清它之后,你基本就掌握了这个工具的设计哲学:

  1. init初始化仓库,生成openspec/目录骨架。
  2. 创建一个 Proposal 时,CLI 会在openspec/proposals/下生成一个目录,里面预置了提案说明的模板。
  3. plan命令读取提案内容,把它拆解成若干个 Requirement 和 Task,并生成对应的 Markdown 文件。
  4. 开发人员逐项完成任务,每完成一项就把对应任务的状态从todo改成done。
  5. 完成一轮后,CLI 生成 Snapshot,记录所有需求项的当前状态。这个快照会留下完整的审计轨迹。
  6. validate命令检查整个仓库的规范文件和实现状态是否一致,CI 里通常会跑这一步。

从源码角度看,这里面最巧妙的设计是“快照”机制。它没有引入数据库,而是靠 Git 仓库里的文件版本来实现时间线。每次快照实际上是一次标准化的提交,所以任何时刻你都能回看项目在某个阶段的需求全貌。

3. 从零跑通一个提案:OpenSpec 命令实操与常见坑

3.1 安装与初始化

OpenSpec 作为 npm 包分发,安装方式很常规。如果你的环境里已经有 Node.js,直接全局安装或者用npx调用都可以。我是用全局安装的:

npm install -g openspec openspec --version

初始化一个新仓库时,在项目根目录执行:

openspec init

它会生成openspec/目录,里面会预置好 proposals、requirements、tasks、snapshots 等子目录。这里要注意:这些目录是空的时,很多命令会因为找不到规范文件而直接报错。这不是 bug,而是 OpenSpec 故意做的一种“空状态保护”,避免让无效数据混进流程。

3.2 创建你的第一个提案

假设我们要给一个网站加“夜间模式”功能,按 OpenSpec 的流程来走一遍:

openspec proposal create "dark-mode-support"

执行后,CLI 会在openspec/proposals/dark-mode-support/下生成一个提案说明文件。你需要编辑它,填写背景、目标、范围等信息。然后是拆解环节:

openspec plan dark-mode-support

这个命令会读取提案内容,自动在你的openspec/目录下生成一批 Requirement 和 Task 文件。以“夜间模式”为例,它可能会拆出:主题切换开关、CSS 变量映射、系统偏好读取、用户偏好持久化这几个需求项,每一项都有对应的验收标准。

接下来是开发环节:逐个完成任务。执行:

openspec task start dark-mode-support -- requirement "theme-toggle"

任务完成后,把它标记为完成状态。再执行:

openspec snapshot create openspec validate

如果一切正常,validate 会输出通过信息,表示规范文件和代码实现处于同步状态,这时你才能在 CI 里放心合并分支。

3.3 常用命令速查表

命令作用使用场景
openspec init初始化规范目录新项目首次接入
openspec proposal create <name>创建工作提案开始新功能或修复
openspec plan <proposal>生成需求项和任务清单提案评审通过后
openspec task start <proposal>开始一项任务开发前
openspec snapshot create创建变更快照阶段性完成时
openspec validate校验规范与实现一致性提交前和 CI 中

3.4 实际使用中踩过的几个坑

第一,提案名称的命名要谨慎。名称会直接成为目录名并在所有命令里被引用,一旦中间带空格或者特殊字符,命令解析容易出问题。我的建议是统一用短横线或驼峰,保持机器可读。

第二,快照不要撒芝麻一样频繁创建。快照本身是一份存档,过于高频会让仓库的提交历史变得很碎,后续回溯时反而看不清阶段节点。我个人习惯是一轮功能开发完成后,集中打一次快照。

第三,校验服务对目录大小写敏感。在 macOS 上默认文件系统大小写不敏感,但 Linux CI 环境大小写敏感,如果创建提案时使用了大写字母,等到 Linux 跑 validate 就很容易报“找不到目录”。这类问题在本地很难复现,最省事的做法是:团队约定全部使用小写命名。

第四,AI 编码助手接入时,上下文不要盲目拉满。OpenSpec 的定位之一就是给 AI 提供规范上下文,但如果把整个openspec/目录全塞给模型,不仅 token 开销大,模型反而容易被不相关的需求项干扰。只提取当前任务关联的那份提案和需求文件,效果会好很多。

4. 网站落地开发方案:从仓库分析结果到站点完整规划

4.1 站点的定位:它到底要去解决什么问题

分析完 OpenSpec 仓库之后,落地一个网站就顺理成章了。这个网站承担两个角色:第一是面向潜在用户的“门面”,介绍项目是什么、能做什么、为什么值得用;第二是面向使用者的“文档中心”,承载安装教程、命令参考、最佳实践。

很多人做工具官网时容易犯一个毛病:功能列表和文档堆在一起,新用户进来根本不知道先看哪块。我规划的信息架构刻意做了分层:

  • 首页:回答“这是什么、解决什么问题、适合谁”,用三到五个核心场景带出价值。
  • 快速开始:五分钟跑通一个提案,让新用户先获得成就感。
  • 文档:按使用阶段组织,分别是安装、初始化、提案、计划、任务、快照、校验、AI 集成。
  • 案例与生态:展示真实团队的工作流模板,降低决策门槛。

4.2 技术选型:为什么我推荐 Astro 而不是 Next.js 或 VitePress

技术选型往往决定后续维护成本。对于一个“内容为主、交互为辅”的工具官网,常见的候选有这么几个:

框架优势劣势适合场景
VitePress基于 Vite,启动快,文档体验好定制页面难度较高纯文档站
Astro内容优先,支持 MD/MDX,组件灵活,默认零 JS复杂交互需要引入前端框架官网 + 文档站混合
Next.js生态成熟,交互能力强对内容站偏重,构建成本高高交互 Web 应用

我给 OpenSpec 这类工具网站推荐 Astro,核心原因是它能把“文档”和“官网营销页”放在同一个项目里,用 Markdown 直接管理内容,同时又能在需要交互的地方嵌入 React/Vue 组件。构建产物是纯静态页面,部署成本几乎为零,移动端性能和 SEO 都比 SPA 方案好一截。

4.3 站点目录结构与内容规划

按 Astro 的惯例,我会把站点组织成下面这样:

site/ ├── src/ │ ├── pages/ │ │ ├── index.astro │ │ ├── docs/ │ │ │ ├── getting-started.md │ │ │ ├── cli-commands.md │ │ │ └── best-practices.md │ │ └── showcase/ │ ├── components/ │ │ ├── Header.astro │ │ ├── CodeBlock.astro │ │ └── DocSidebar.astro │ └── layouts/ │ └── BaseLayout.astro ├── public/ │ ├── favicon.svg │ └── og-image.png └── astro.config.mjs

内容规划上,我建议在项目初期就把“文档与规范同步”这个机制定下来。具体做法是:每个文档页面的 frontmatter 里声明它关联的 Proposal 或 Requirement ID,构建时做一次链接检查。如果文档里引用了不存在的需求项,或者某个需求项已经变更但文档没有同步,CI 直接报警。这其实是用 OpenSpec 自己的理念来做网站维护——内容也是代码,规范变更和内容变更必须同一次提交里出现。

4.4 把网站开发本身跑成一个 OpenSpec 提案

更有意思的是,这个网站的开发过程完全可以跑在 OpenSpec 工作流里。我们内部就把“站点上线”定义成了一个提案,拆出来的需求项覆盖了设计系统、首页文案、文档迁移、SEO 基础、部署流水线等。

每个需求项都有验收标准。比如“SEO 基础”这一项,验收标准是:每个页面有唯一的 title 和 description,生成sitemap.xml,核心页面的 Lighthouse 性能评分不低于某个阈值。开发人员在完成这些需求时,任务状态的更新过程本身就成了项目进度看板。评审提案时,团队只用翻一遍openspec/目录,就能知道网站开发到了哪一步、哪些验收标准还没满足。

这种“工具 + 自身实践”的循环很有意思:你在用 OpenSpec 建网站,而网站本身又在演示 OpenSpec 该怎么用。网站上那些最佳实践的内容,就是从我们自己的提案历史里提炼出来的,不是空话。

4.5 组件方案与样式组织

网站虽然是内容为主,但不能显得廉价。Astro 的岛屿架构让这件事变得轻松:全局的 Header、Footer、侧边栏都可以做成纯静态组件,只有“终端安装命令的复制按钮”“版本切换下拉框”这类小交互才需要挂一点 JavaScript。

样式层面我没有引入重型 UI 框架,而是用 CSS 变量定义了一套基础令牌:颜色、间距、圆角、字体。这套变量直接对应 OpenSpec 规范目录里的设计令牌,两个仓库共用同一套命名。这样当品牌色想调整时,只需要改规范目录里的源文件,再同步到站点样式变量,不会有代码里散落一堆魔数的问题。

主题方面,网站从第一天就支持明暗双主题,这也是我们自己提案里的第一个需求项,算是用 dogfooding 的方式验证了规范驱动开发在“前端功能”上的可行性。

5. 部署流水线与上线后的维护策略

5.1 GitHub Actions 里的一次完整发布

网站采用静态构建,部署可以走 GitHub Actions。工作流的核心逻辑是:推送到 main 触发构建,构建前先跑一遍 OpenSpec 校验,校验通过再执行 Astro 构建,产物发布到 Pages 或对象存储。

参考的 workflow 核心片段是:

name: build-site on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci - run: openspec validate - run: npm run build - uses: actions/upload-pages-artifact@v3 with: path: dist

把openspec validate放在构建之前是有意的:如果规范文件与实现不同步,连构建机会都不给,直接在源头拦截住。这比“构建完才发现问题”少浪费很多时间。

5.2 预览环境与分支策略

静态站点的优势在预览环境上体现得很明显。Pull Request 触发时,工作流可以先构建出一个带临时域名的预览站点,让产品经理、内容编辑直接点链接看效果,不需要本地跑环境。

分支策略我建议保持简单:main分支是唯一发布源,功能分支统一走 PR 合入。每个 PR 的标题里带上提案编号,比如docs: update quickstart for proposal 0012,这样 Git 历史本身就带上了规范追踪的索引。

5.3 内容与规范同步的长期维护

网站上线只是开始,真正的挑战是内容维护。文档站最容易烂掉的地方就是:代码改了,文档没改。我这边做了三层防线:

  • 第一层,文档 frontmatter 里的需求 ID 引用检查,构建时自动跑,发现无效引用就报错。
  • 第二层,把“文档更新”作为功能提案的验收标准之一,功能没写文档就等于没完成。
  • 第三层,定期用快照对比历史规范,把阶段性变更直接同步成网站上的 Changelog 内容。

这三层防线里,第二层是最重要的,它意味着文档更新不是开发完成之后的额外工作,而是提案的一部分。比如某个需求项要求“修改 CLI 命令openspec validate的输出格式”,它对应的验收标准里就包含了“更新 cli-commands.md 中相应示例”。开发人员想完成任务,就必须同步改文档,否则校验过不去。

5.4 几个值得马上试试的扩展方向

仓库分析和网站建设都跑通之后,后续有几个方向我觉得非常值得投入:

第一,做一个 Showcase 页面,收集采用 OpenSpec 工作流的真实团队案例。第二,把“提案模板”做成可复用的 npm 包,让新团队可以直接从一组最佳实践的规范文件起步。第三,把网站的站内搜索接上全文索引,并在搜索结果里直接展示对应的 Proposal ID,方便用户从网站内容跳回规范原文。

最后分享一个我们团队内部的实际感受:真正让规范驱动开发跑起来的,不是命令行工具本身,而是“规范变更必须和代码变更走在同一次提交里”这条纪律。技术方案写得再华丽,只要哪一天有人绕过流程,信任链条就会断掉。与其设计复杂的权限系统,不如把校验写进 CI,让机器去守底线。这套网站落地方案的规划方式,本质上就是在复刻这种纪律——把内容、代码、规范三者焊在一起,谁也不能单独漂移。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 3:50:56

I2C多主机仲裁与时钟延展:从原理到实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 3:49:38

【YOLO系列】YOLO v5 网络结构图+代码:从 SPPF 到 ONNX 的配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 3:49:08

校园网安全巡检实战:日志留存、弱口令排查与终端抽查指南

简介&#xff1a;这份文档面向中小学、幼儿园、职校及其他教育单位的信息安全负责人与网络管理员&#xff0c;围绕教育系统网络与信息安全巡检的实际工作展开&#xff0c;帮助读者理清巡检流程、检查要点与整改方向。内容涵盖巡检计划安排、重要设备日志备份、数据备份方式核查…

作者头像 李华
网站建设 2026/9/29 3:47:39

GPT-5+Codex登陆Azure AI:TaoToken统一Key接入配置与验证指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华