Halo 开源项目中的 spec-driven 提案工作流:openspec-propose Skill 全解析
【免费下载链接】haloHalo 是一款强大易用的开源建站工具,从个人博客、知识库,到企业官网、在线商城,Halo 都能助您轻松实现,一站式满足您的多样化建站需求。项目地址: https://gitcode.com/GitHub_Trending/ha/halo
导读
在 Halo(api、application、ui 组成的前后端 monorepo)这类大型开源项目里,一次功能改动往往横跨后端 API、数据库迁移、前端组件与插件生态,需要“提案—设计—规格—任务”层层对齐。openspec-proposeSkill(定义于 .claude/skills/openspec-propose/SKILL.md)把这一过程压缩为一次对话:由 Agent 调用 OpenSpec CLI,一步创建proposal.md(做什么、为什么)、design.md(怎么设计)、tasks.md(怎么落地)等全部制品。读完本文,你将掌握这条“一句话需求 → kebab-case 变更名 → apply-ready 制品”的流水线的每个命令、产物结构与约束规则,并能对照 Halo 仓库中真实存档的变更记录理解其运行效果。
一、openspec-propose 是什么:一次提问,一份完整变更提案
该 Skill 的文件头(frontmatter)给出了它的精确角色定位:
name: openspec-propose——在 Agent 技能体系中的注册名;description——用户只需“快速描述想构建的内容”,即可一次拿到包含 design、specs、tasks 的完整提案;allowed-tools: Bash(openspec:*)——只允许通过 Bash 调用openspec前缀的 CLI 子命令;compatibility: Requires openspec CLI——使用前提是环境中安装并注册了 OpenSpec CLI;license: MIT、generatedBy: "1.6.0"——记录该 Skill 的来源与生成工具版本。
它承诺的产出是一个 "change"(变更),并自动生成三类制品文件:
proposal.md——what & why(改什么、为什么改);design.md——how(技术方案如何落地);tasks.md——implementation steps(可勾选执行的实现步骤)。
这三个文件名与 Halo 仓库归档区里真实存档一一对应。例如 openspec/changes/archive/2026-08-07-support-esm-ui-plugins/ 下的proposal.md、design.md、tasks.md就分别以 “## Why / ## What Changes / ## Capabilities”、“## Context / foundations” 和 “## 1. Shared Dependency Contract … - [x] 1.1 …” 的形态存在,是这份 Skill 在实际开发中被反复执行后留下的成品样本。
二、全程执行前:输入判定与 store 选择
2.1 输入与命名规范
Skill 要求用户的请求至少包含两样之一:一个kebab-case 变更名,或一句“想构建什么”的描述。若只有描述,Agent 需从中推导出 kebab-case 命名,例如 “add user authentication” 推导为add-user-auth。
Halo 归档区的变更目录名验证了这套命名与日期前缀并存的组织方式,如:
- openspec/changes/archive/2026-05-19-issue-5634-category-post-navigation/(关联 issue 编号)
- openspec/changes/archive/2026-08-03-refactor-editor-table/(一个变更下含多个 spec)
- openspec/changes/archive/2026-07-17-support-theme-message-fallback/
当输入完全没有指向时,Skill 给出硬性约束:不得在理解用户意图前继续推进,应使用开放式提问工具让用户描述要构建或修复的内容。
2.2 store 选择:单仓根目录与独立 store 两种模式
Skill 的前置逻辑区分两类操作目标:
- 无 store 模式:若未指定 store,所有命令作用于“最近的本地
openspec/根目录”。这正是 Halo 仓库的用法——仓库根目录下就是 openspec/,内含config.yaml、specs/、changes/三大部分。 - store 模式:若工作位于本机注册的独立 OpenSpec 仓库(store),应先执行
openspec store list --json发现已注册的 store id,再在读写 specs/changes 的命令后追加--store <id>。
关键细节:--store并非所有命令通用——只有new change、status、instructions、list、show、validate、archive、doctor、context这些读写类命令接受该参数,其余命令不带此标志。CLI 打印的提示信息已自带该 flag,后续跟进命令应保持沿用。
三、核心执行流:五步生成 apply-ready 制品
以下五步是 openspec-propose 的主流程,所有命令都应原样保留(必要时追加--store <id>)。
第 1 步:创建变更目录
openspec new change "<name>"CLI 会在其解析出的 planning home 下按.openspec.yaml创建一个脚手架变更目录。归档区内的每个变更目录都带有一个最小化的 .openspec.yaml,内容形如:
schema: spec-driven created: 2026-08-06它声明了该变更采用的 schema(Halo 全仓统一为spec-driven)与创建时间,是 CLI 判断制品依赖与校验规则的依据。
第 2 步:查询制品构建顺序
openspec status --change "<name>" --json解析返回的 JSON 需要重点读取以下字段:
applyRequires:开始实现前必须产出的制品 id 数组(例如["tasks"]);artifacts:全部制品及其状态、依赖关系;planningHome、changeRoot、artifactPaths、actionContext:路径与作用域上下文。Skill 特别强调用这些返回值替代自行假设的仓库本地路径。
第 3 步:按依赖顺序逐个创建制品
这一步应配合 TodoWrite 工具跟踪进度。循环规则是:优先处理没有未决依赖的制品;每处理一个ready状态的制品,先取指令:
openspec instructions <artifact-id> --change "<name>" --json返回的 instructions JSON 包含 7 类关键信息:
| 字段 | 含义与用法 |
|---|---|
context | 项目背景,是约束 Agent 行为的输入,禁止写入制品文件 |
rules | 制品专属规则,同样只作约束,禁止写入文件 |
template | 输出文件应遵循的结构骨架 |
instruction | 针对该制品类型的 schema 级写作指引 |
resolvedOutputPath | 制品应写入的解析后路径(或路径模式) |
dependencies | 需要先读的已完成制品,用于获取上下文 |
写作方法为:先读dependencies指向的成品文件,再以template为结构骨架、以instruction为内容指引,将文件写入resolvedOutputPath。每完成一个制品打印一行 “Created ” 作为进度汇报。
第 4 步:迭代直到 applyRequires 全部完成
每次创建完制品都重新执行openspec status --change "<name>" --json,检查artifacts数组里applyRequires中每个制品 id 的status是否都为"done"。全部为 done 即停止循环,此时变更处于 “apply-ready” 状态。
若某个制品因上下文不清需要用户输入,应使用 AskUserQuestion 澄清后再继续,不要带着歧义硬写。
第 5 步:展示最终状态并总结交接
openspec status --change "<name>"收尾阶段 Skill 要求 Agent 输出一份结构化总结:
- 变更名称与位置;
- 已创建制品清单及简述;
- 就绪声明:“All artifacts created! Ready for implementation.”;
- 交接提示:“Run
/opsx:applyor ask me to implement to start working on the tasks.”
这条交接链路在 Halo 的 Claude 命令生态中是闭环的:/opsx:propose 负责提案生成,apply、update、archive 等命令承接后续实现、修订与归档。
四、spec-driven schema 在 Halo 的真实落地:config.yaml 详解
Halo 在仓库根目录 openspec/config.yaml 声明了schema: spec-driven,并把共享上下文注入到所有 AI 提示词。这份配置决定了 openspec-propose 生成的每份制品必须遵守的工程事实,主要包括两块。
4.1 context:全局技术栈共识
文件注释点明其职责是“保持简洁”地给出 tech stack、conventions 与架构原则,更宽的编码标准进 AGENTS.md。Halo 的 context 可归纳为四组事实:
- 技术栈:后端 Java 21 + Gradle(Groovy DSL)+ Spring Boot 4.x + WebFlux/Reactor + R2DBC;前端 Vue 3 + TypeScript + Vite(vite-plus)+ pnpm workspaces + TailwindCSS;
- Monorepo 结构:
api、application、platform:application、platform:plugin、ui; - 架构要点:基于 PF4J 的插件化体系、可经 Extension Points 扩展、主题系统带模板渲染、API 以 SpringDoc / OpenAPI 记录;
- 协作约定:Conventional Commits(feat、fix、chore、docs、build、refactor、test、style)。
也就是说,任何由 openspec-propose 产出的提案都默认处于“WebFlux 响应式后端 + Vue 前端 + PF4J 插件架构”的约束语境中,context保证 AI 不会写出偏离该栈的设计。
4.2 rules:按制品类型细分的硬性约束
config.yaml 的rules按制品分开定义:
- proposal 规则:评估对现有插件/主题 API 的兼容性影响;数据库 schema 变更必须有迁移策略;安全相关变更须评估 auth/authorization 影响;UI 变更须考虑 i18n 支持。
- tasks 规则:后端改动须通过
./gradlew spotlessCheck;前端改动须通过pnpm lint与pnpm typecheck;API 变更要求更新 OpenAPI 文档并重新生成 api-client;新增依赖须做许可证兼容性检查。
以 Halo 归档中体量较大的 2026-08-07-support-esm-ui-plugins 为例,其proposal.md的 “What Changes” 明确给出 “Keep existing IIFE bundles … operational throughout Halo 2.x”“must remain additive for existing IIFE artifacts” 等兼容性承诺,design.md的 “Context” 直接盘点 “plugin/theme resource routes …Plugin.status…spec.requires” 等既有地基,tasks.md则以可勾选列表铺开 “Shared Dependency Contract / Host Shared Runtime / Provider Discovery and Backend Delivery” 等实施阶段——这正是 context/rules 约束落进真实产物的结果。同时该变更还产出两个规格文档:specs/ui-plugin-bundler-provider/spec.md与specs/ui-plugin-esm-runtime/spec.md(按 spec.md 的 “MODIFIED Requirements → Scenario: WHEN/THEN” 结构书写),说明规范(specs)也是 spec-driven schema 制品链的一部分,会被后续的openspec-sync-specs同步进仓库 openspec/specs/ 作为长期规格基线。
五、制品写作纪律:context/rules 是约束而非内容
这是 openspec-propose 反复强调的一条红线,值得单独成节:
- 每个制品都必须遵循
openspec instructions返回的instruction字段; - schema 决定了制品应包含什么,创建前必须先读依赖制品;
- 必须使用
template作为输出结构; - 绝对不要把
<context>、<rules>、<project_context>之类的块复制进制品文件——它们只约束“怎么写”,不构成文件内容。
违规的典型表现是:把配置里技术栈清单原样粘贴进 design.md,或把 rules 的检查项当作 proposal 的 “Why” 段落——前者造成信息冗余,后者则让“为什么改”被实现纪律淹没。
六、护栏(Guardrails)与流体工作流协同
Skill 在结尾给出四条必须遵守的护栏:
- 完整产出:创建 schema 的
apply.requires定义的全部实现必需制品,缺一不可; - 依赖先行:创建新制品前必须先读已完成依赖制品;
- 关键上下文不明才提问:若上下文严重不清可以问用户,但更倾向于做合理决策以保持推进节奏;
- 重名处理:若同名变更已存在,必须询问用户是继续该变更还是新建一个;
- 落盘确认:每个制品写完后校验文件确实存在,再进入下一个。
此外,openspec-propose 不是孤立的一次性流程。参考同目录下 openspec-apply-change/SKILL.md 可看到,Halo 采用 “actions on a change” 的流体工作流模型:实现进行到一半发现设计问题,可以直接建议更新提案制品,而不是僵化地锁死在“提案期/实现期”的相位里。这也解释了为何归档变更中能看到类似 2026-05-19-signup-agreement-pages 与 2026-05-12-signup-agreement-pages 这样同主题反复迭代的记录——提案、实现、修订可以在同一变更上循环打磨,直到产物稳定后再归档沉淀。
七、在 Halo 仓库中进一步探索
若想将本 Skill 对照真实代码与历史变更深入研读,推荐按以下顺序查看:
- openspec/config.yaml——spec-driven schema 的 context/rules 定义源;
- openspec/changes/archive/——数十份已归档变更,覆盖 ESM UI 插件、编辑器表格重构、菜单层级迁移、主题消息回退等真实功能;
- openspec/specs/——从变更中同步沉淀出的稳定规格基线;
- .claude/skills/ 与 .claude/commands/opsx/——完整技能/命令生态,包括 propose、apply、update、archive、explore、sync 六个环节;
- openspec/changes/archive/2026-08-07-support-esm-ui-plugins/——一份横跨 UI 构建、打包工具、后端资源发现与运行时加载的大型提案样本,可用于对照本 Skill 的每一条流程步骤。
总体而言,openspec-propose 的本质是把“AI 辅助提案”这一易失过程制度化:通过 CLI 的 schema 驱动、依赖排序与状态回查,让每一次功能设想都能稳定地产出结构一致、可直接进入实现阶段的制品;而 Halo 仓库本身,就是这个流程在高复杂度开源 monorepo 中反复运行后留下的一套真实档案。
【免费下载链接】haloHalo 是一款强大易用的开源建站工具,从个人博客、知识库,到企业官网、在线商城,Halo 都能助您轻松实现,一站式满足您的多样化建站需求。项目地址: https://gitcode.com/GitHub_Trending/ha/halo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考