ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Halo 的 OpenSpec 变更修订工作流:openspec-update-change 如何保持规划工件一致性

Halo 的 OpenSpec 变更修订工作流:openspec-update-change 如何保持规划工件一致性 Halo 的 OpenSpec 变更修订工作流openspec-update-change 如何保持规划工件一致性【免费下载链接】haloHalo 是一款强大易用的开源建站工具从个人博客、知识库到企业官网、在线商城Halo 都能助您轻松实现一站式满足您的多样化建站需求。项目地址: https://gitcode.com/GitHub_Trending/ha/halo本文以 Halo 仓库中的 openspec-update-change 技能定义 为主体完整拆解该技能声明的六步修订流程、openspecCLI 的关键 JSON 字段schemaName、artifactPaths、existingOutputPaths等、逐项确认机制与护栏约束并结合仓库中真实的 OpenSpec 规划目录openspec/与已归档变更示例说明“修订计划而不触碰代码”这一工作流在 Halo 项目中如何落地。读完后你能掌握 OpenSpec 变更修订的完整操作步骤、各工件proposal / design / specs / tasks之间的协调关系以及它与 propose、apply、archive 等相邻技能的衔接点。技能定位只改规划工件绝不改代码.codex/skills/目录下存放了 Halo 为 Codex Agent 准备的六个 OpenSpec 技能每个技能是一个包含 YAML frontmatter 的SKILL.md文件openspec-explore探索模式只做思考与调研明确禁止写代码openspec-propose一步创建新变更并生成全部工件openspec-update-change修订既有变更的规划工件本文主题openspec-apply-change按 tasks 逐项实现代码openspec-sync-specs把变更下的 delta spec 同步回主 specopenspec-archive-change归档已完成变更。update-change 技能的核心一句话定位写在文档首段Revise a changes existing planning artifacts and keep them coherent. Never edit code. 修订一个变更的既有规划工件并保持它们彼此一致。绝不编辑代码。其 frontmatter 元数据完整如下体现了 Agent Skill 的声明式约定--- name: openspec-update-change description: Update an OpenSpec change by revising its existing planning artifacts and keeping them coherent with one another. Use when the user wants to revise a changes plan, fold new decisions into it, or reconcile its artifacts after an edit. Never edits code. allowed-tools: Bash(openspec:*) # 仅允许调用 openspec CLI license: MIT compatibility: Requires openspec CLI. metadata: author: openspec version: 1.0 generatedBy: 1.6.0 ---两个字段值得注意allowed-tools限定该技能只能执行openspec前缀的 Bash 命令配合文件读写能力修订工件description同时描述了“何时使用”用户想修订计划、把新决策折叠进计划、或编辑后重新对齐工件便于 Agent 路由时精准匹配。Store 选择机制多 OpenSpec 仓库场景下的作用域控制技能正文在步骤之前给出了Store selection通用规则六个技能中措辞一致“store”指一台机器上注册的独立 OpenSpec 仓库。若用户点名了某个 store或工作发生在 store 中先运行openspec store list --json发现已注册的 store id之后在所有“读写 specs 与 changes”的命令上追加--store id技能列出的适用命令为new change、status、instructions、list、show、validate、archive、doctor、context其他命令不接受该参数命令打印的提示中若已带该 flag后续跟进命令应保留它不指定 store 时命令作用于最近的本地openspec/根目录——这正是 Halo 仓库的场景openspec/config.yaml 所在的openspec/目录即为规划根。输入约定变更名从哪来技能对输入的处理规则是可显式指定变更名change name未指定时先尝试从对话上下文推断若含糊或存在歧义必须提示用户从可用变更中选择MUST prompt不得猜测。步骤一变更选择无变更名时执行openspec list --json获取按最近修改时间排序的可用变更列表然后用 AskUserQuestion 工具让用户选择。展示规则有明确的 UI 约束只呈现最近修改的3–4 个变更作为选项每个选项展示四项信息变更名、Schema取schema字段缺省则显示 spec-driven、状态如0/5 tasks、complete、no tasks、最近修改时间取lastModified字段最近修改的那个变更标记为(Recommended)——因为它最可能是用户想更新的严禁猜测或自动选择始终由用户拍板。这一约束与 openspec-archive-change 的选择逻辑呼应归档技能同样要求“Do NOT guess or auto-select a change”。步骤二用openspec status解析变更状态核心命令openspec status --change name --json返回的 JSON 中技能明确要求解析以下字段字段含义schemaName正在使用的工作流 schema例如spec-drivenartifacts工件数组每个带状态done/ready/blockedisComplete布尔值是否所有工件均已完成planningHome、changeRoot、artifactPaths、actionContext路径与作用域上下文其中路径上下文的用法有两条硬性要求不要假设仓库内路径工件 id 和路径来自当前激活的 schema必须使用 status 返回的planningHome/changeRoot/artifactPaths/actionContext而不是硬编码仓库局部路径不要对硬编码的工件名做分支判断自定义 schema 必须“原样可用”Custom schemas must work unchanged。最关键的一条规则是关于写盘目标的要编辑的文件是artifactPaths.id.existingOutputPaths——即磁盘上真实存在的具体文件glob 类工件如specs/**/*.md已经完成 glob 展开。不要写resolvedOutputPath对 glob 工件而言它仍然是 glob 模式本身而不是真实文件。Halo 仓库的实例正好印证这一点归档变更 2026-05-19-issue-5634-category-post-navigation 的工件布局为proposal.md、design.md、tasks.md三个常规文件外加specs/category-post-navigation/spec.md对应specs/**/*.md这类 glob 工件展开后的具体文件。修订时应当逐个指向这些已存在的文件而不是写回specs/**/*.md这个模式串。步骤三理解请求——“定向修订”还是“一致性审查”技能把用户输入区分为两类处理方式不同定向修订用户提出了具体改动例如“设计现在改用 X 了”这就是起始编辑点一致性审查coherence review用户只说“更新一下”/“让它保持一致”则读取全部既有工件两两对照检查矛盾contradictions、缺口gaps与重复duplication。这个二分法意味着同一技能既能执行明确的小手术也能做全文档体检后者的检查方向是双向的见步骤四。步骤四阅读与对齐Read and Reconcile这是整个流程的技术核心包含五条细则读全读被请求触及的工件也读该变更的其他既有工件应用编辑后反向核查所有其他工件方向任意修改后置工件如 tasks可能需要回过头修订前置工件如 design 或 proposal——构建顺序只是“有用的阅读顺序”不是“哪些工件可被修订”的约束记录一切把现在不一致、缺失或矛盾的地方全部记下来只改已存在的文件existingOutputPaths不创建尚不存在的工件也不在 glob 工件下发明新文件遇到这种情况记录下来并指向/opsx:continue去创建如果变更本已一致明说并零编辑——不做无意义的“润色式”写入。步骤五逐工件确认后再落盘每一处拟议修订都要先展示改什么、为什么改用户确认后才写盘用户拒绝某条修订则该工件保持原样不写入当某工件需要大幅重写时先取回该工件的规则与模板openspec instructions artifact-id --change name --json对照 openspec-propose 中对openspec instructions返回值的说明该 JSON 至少包含context项目背景、rules工件专属规则、template输出文件结构、instructionschema 特定指导、resolvedOutputPath与dependencies并且强调context与rules是对 Agent 的约束不得被复制进工件文件本身。Halo 的 openspec/config.yaml 正是这些规则的项目侧来源schema: spec-driven context: | Tech stack: Backend: Java 21, Gradle (Groovy DSL), Spring Boot 4.x, WebFlux/Reactor, R2DBC Frontend: Vue 3, TypeScript, Vite (vite-plus), pnpm workspaces, TailwindCSS ... rules: proposal: - Evaluate impact on existing plugin/theme APIs for compatibility - Database schema changes must include a migration strategy ... tasks: - Backend changes must pass ./gradlew spotlessCheck - Frontend changes must pass pnpm lint and pnpm typecheck - API changes require updating OpenAPI docs and regenerating api-client ...也就是说一次“大幅重写 tasks 工件”时openspec instructions tasks --change ...注入的 rules 会强制要求后端任务包含spotlessCheck通过项、API 变更需更新 OpenAPI 文档并重新生成 api-client——这解释了为什么 归档变更的 tasks.md 中能看到Run ./gradlew spotlessApply与check OpenAPI spec generation这类验收项。步骤六指引下一步只指引绝不代执行修订完成后技能要求按变更所处阶段给出且仅给出下一步建议明确标注 “guidance only - NEVER act on it”变更状态建议命令对应技能仍有缺失的工件/opsx:continue继续创建工件update-change 明确不得越权代劳变更已实现tasks 已勾掉/代码已应用/opsx:applyopenspec-apply-change——因为代码可能已不匹配修订后的计划apply 负责把 delta 带进代码全部完成且已实现/opsx:archiveopenspec-archive-change——将changeRoot移入archive/YYYY-MM-DD-name/“已实现再修订计划”是这条分支存在的意义所在plan 与 code 之间的偏差要靠 apply 去追平而不是在 update 阶段顺手改代码。输出契约化的输出格式技能规定每次调用结束后必须展示三件事哪些工件被修订了以及哪些拟议修订被用户拒绝哪些内容被推迟给/opsx:continue尚未创建的工件或文件变更当前处于什么位置、推荐的下一条命令是什么。这使每次修订会话都有可审计的收尾Agent 与人类都能据此判断后续动作。护栏Guardrails逐条解读原文档末尾的 Guardrails 是该技能的行为边界逐条对应到具体工程考量只碰规划工件绝不改实现代码若修订后的计划隐含代码变更停下并指向/opsx:apply——这划清了“计划面”与“实现面”的职责边界与 explore 技能“never write code”、apply 技能“只做代码”形成三段式分工使用openspec status报告的工件 id 与路径永不基于硬编码工件名分支——保证自定义 schema 可插拔只编辑existingOutputPaths里的具体文件永不写 glob 的resolvedOutputPath——防止把specs/**/*.md当文件名写出损坏产物不推进构建前沿build frontier不新建工件、不在 glob 工件下新建文件——那是/opsx:continue的职责。这实际上把一个“计划演进”的过程拆成了两个幂等的角色continue 只增update 只改每次写入前与用户确认——规划工件是决策记录误写成本高“Update vs. Start Fresh”启发式如果请求改变的是变更的**意图intent**而非细化refining建议用/opsx:new重新开一个变更而不是把新意图硬塞进旧计划。这条规则防止语义漂移被伪装成普通编辑。在 Halo 仓库中看真实工件长什么样结合openspec/changes/archive/下的归档变更可以看清 update-change 技能“修订对象”的实际形态。以 2026-05-19-issue-5634-category-post-navigation 为例其工件集合完整展示了 spec-driven schema 的三类文件proposal.mdWhat Why——为何文章页“上一篇/下一篇”需要按分类作用域导航对应 issue halo-dev/halo#5634以及变更点清单新增PostFinder.cursorByCategory、扩展GET /posts/{name}/navigation?scopecategory、无分类时返回空NavigationPostVo、既有cursor()行为不变design.mdHow——包含 Goals/Non-Goals、四条编号决策精确匹配主分类且不下钻子分类、新增方法而非修改cursor()、复用端点加查询参数而非新路径、不做控制台配置以及风险/权衡表tasks.md实施步骤——按 Finder 接口与实现、REST 端点、测试、验证四个小节编号全部以- [x]勾选收尾并包含./gradlew spotlessApply、./gradlew test等可执行验收项specs/category-post-navigation/spec.mddelta spec——以## ADDED Requirements### Requirement#### ScenarioWHEN/THEN 式描述新增行为契约例如“文章无分类时cursorByCategory返回空NavigationPostVo”。对照 update-change 的四步流程若此时有人提出“现在导航要支持子分类下钻”这种修订正确的动作是改 design.md 的 Decision 1该决策明确记录了“用户选择了精确匹配”再反向核查 delta spec 中 “Category scope uses exact match (no subcategory cascade)” 这条 Requirement 与 tasks 第 1.2 项是否需要同步调整——这正是步骤四“ANY direction”规则要覆盖的场景。而 delta spec 到主 spec 的合并openspec/specs/ 等 18 个 capability 目录则由 openspec-sync-specs 负责归档时的mv操作由 archive 技能执行update-change 一概不越权。小结一个“只改计划”的幂等修订闭环openspec-update-change 的设计可以概括为四个工程决策状态驱动而非假设驱动一切工件 id、路径、状态以openspec status --json的返回为准天然兼容任意自定义 schema读写分离只写existingOutputPaths中已存在的文件glob 模式永远只读创建新内容交给 continue人工确认门逐工件展示 diff 意图、拒绝即回退保证规划记录不被 Agent 悄悄改写意图变更熔断触及变更意图时建议/opsx:new重来避免旧计划与新目标混杂。在 Halo 这样的多模块单体仓库api、application、platform、ui中这种“计划先行、修订受控、实现与归档各司其职”的 OpenSpec 工作流使得从 proposal 的 What/Why 到 tasks 的勾选收尾 的每个阶段都有可追溯的文件载体而 update-change 技能正是保证这些载体在决策演进中始终自洽的那一环。【免费下载链接】haloHalo 是一款强大易用的开源建站工具从个人博客、知识库到企业官网、在线商城Halo 都能助您轻松实现一站式满足您的多样化建站需求。项目地址: https://gitcode.com/GitHub_Trending/ha/halo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表