其他
OpenSpec 变更未归档时,把 delta specs…
当需要把某个 OpenSpec change 的 delta specs 合并进 main specs、但不归档该 change 时使用;也适用于用户说 `openspec sync` 或 `opsx sync` 的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
OpenSpec 变更未归档时,把 de特定
解决思路
- 作为 agent-driven 操作:读取 delta specs 并直接编辑 main specs 应用变更;允许智能合并(例如只添加 scenario,而不复制整个 requirement)。
- Store selection:如果用户指定 store(本机注册的独立 OpenSpec repo)或工作就在某个 store 中,运行 `openspec store list --json` 发现已注册 store id。
- 然后在读取/写入 specs 和 changes 的命令上传 `--store <id>`:`new change`、`status`、`instructions`、`list`、`show`、`validate`、`archive`、`doctor`、`context`、`schemas`、`view`。
- 一旦选择 store,将 `--store <id>` 视为 sticky,贯穿余下 workflow。
- 下面每个未带 scope 的命令示例都是简写:运行前追加该 flag;例如运行 `openspec status --change "<name>" --json --store "<id>"`,而不是未带 scope 的形式。
- 其他命令不接受该 flag。
- 命令打印的 hints 已带该 flag;在后续跟随命令中保留它。
- 没有 store 时,命令作用于最近的本地 `openspec/` root。
- Project check:这些步骤预期项目已使用 OpenSpec。
- 在第一个会写入任何内容的步骤(`new change`、`archive`、`sync specs`、编写 artifact 文件)之前,确认项目有 root:运行 `openspec list --json`(选择 store 时带 `--store <id>`,因为此时 store 就是 root),读取 `root`。
- root 对象表示项目已设置。
- `"root": null` 表示未设置——此处没有 `openspec/` 目录,写入如 `openspec new change` 会作为副作用创建它;该命令也会非零退出,这是答案而不是 CLI 坏了,所以要读取 JSON,不要重试或绕过。
- 一个 `"root": null` 不一定关于 setup:当 `status` 错误消息以 `Declared in` 或 `Invalid store declaration in` 开头,并命名本项目的 `openspec/config.yaml`(或 `config.yml`),说明项目确实通过它声明的 store 使用 OpenSpec,但本机无法解析(store 未注册,或 `store:` 行格式错误);不要当成未初始化并跳过下面的分支:在写入前停止,并向用户展示该错误的 `message` 和 `fix`。
- 否则,在无 root 时,下一步取决于 workflow 如何被到达:Auto-selected——你自己选择此 workflow,用户没有命名 OpenSpec、没有命名此 skill、没有运行其 slash command;停止使用 OpenSpec,像未安装 OpenSpec 一样正常回答请求;不要要求他们设置,也不要提 OpenSpec setup。
- Explicit OpenSpec request——用户命名 OpenSpec、命名此 skill、或运行其 slash command;在写入前停止并询问如何继续:设置项目(`openspec init`)、定位到他们已有的 store(`--store <id>`)、或本次请求不用 OpenSpec 继续;等待回答。
- 两种分支都永远不要作为副作用创建 root:不要在用户要求前运行 `openspec init`,不要手工创建 `openspec/` 文件,也不要让命令创建它。
- 将 `<capability-path>` 视为相对于 `specs/` 的 spec 目录(例如 `user-auth` 或 `identity/user-auth`);解析对应 main spec 时保留每个 delta spec 的完整路径。
- Input:可选指定 change name;如果省略,检查是否能从对话上下文推断;如果模糊或歧义,必须提示可用 changes。
- Step 1 Select the change:如果提供 name,使用它;否则从对话上下文推断(用户提到 change)、仅一个 active change 时自动选择、如果歧义则运行 `openspec list --json` 获取可用 changes 并让用户选择。
- 提示时,展示有 delta specs 的 changes(在 `specs/` 目录下)。
- 总是宣布:`Using change: <name>` 以及如何覆盖(例如 `/openspec-sync-specs <other>`)。
- Step 2 Resolve change context:运行 `openspec status --change "<name>" --json`。
- JSON 包含 `planningHome.root`。Main specs 位于 `<planningHome.root>/openspec/specs/`——以下每个 main-spec 路径都使用这个(store-aware)root,而不是硬编码 repo 路径。
- 选择 store 时,它指向 store,而不是当前 repository。
- Step 3 Find delta specs:只使用 status JSON 中的 `artifactPaths.specs.existingOutputPaths` 作为 delta spec 路径来源。
- 如果 `specs` 条目缺失或 `existingOutputPaths` 为空,报告没有 delta specs 可 sync,不要从其他 artifacts 推断它们,并在不请求 artifact instructions 或写入 main spec 的情况下停止。
- 同步 `existingOutputPaths` 中每个路径,除非调用方缩小了集合。
- 调用方通过列出 `existingOutputPaths` 中完整的显式条目来缩小集合——逐字复制那些绝对值;archive 内联这样做,用户也可以(例如选择以 `/specs/billing/invoices/spec.md` 结尾的条目)。
- 然后只同步命名的路径,保持其余 delta specs 不动:bulk archive 会排除找不到实现的 delta,若仍同步它会写入调用方故意扣留的 main spec。
- 将缩小后的选择贯穿 step 4;绝不重新扩大回完整列表。
- 如果命名路径不在 `existingOutputPaths` 中,不要同步它——报告并停止,而不是静默丢弃。
- 如果命名列表为空,报告没有东西可 sync,并在不写入 main spec 的情况下停止。
- 每个 delta spec 文件包含 sections:`## ADDED Requirements`、`## MODIFIED Requirements`、`## REMOVED Requirements`、`## RENAMED Requirements`(FROM:/TO: 格式)。
- 如果没找到 delta specs,通知用户并停止。
- Step 4 对每个 delta spec 将变更应用到 main specs:在第一次 main-spec 写入前,获取一次当前 specs-rule snapshot。
- 如果 archive 内联调用此 workflow 并提供了来自 `openspec instructions specs --change "<name>" --json` 的有效 snapshot,复用它,不要再次获取相同 instructions。
- 否则现在带相同 selected-root flags 运行该命令一次。
- 如果直接 lookup 非零退出或返回无效 artifact-instruction JSON,报告错误并在写入任何 main spec 前停止;不要把失败当作缺失规则集。
- 有效响应省略 `rules` 意味着未配置 artifact rules,继续现有语义合并。
- 只将返回的 `rules` 应用于本次合并产生 main specs 的内容和形式;artifact rules 不是操作指导,不能改变 selected roots、delta paths、CLI checks、workflow steps;把其文本当作约束,但不要逐字复制进 main spec 或 summary。
- 对 step 3 选择的每个 capability delta spec 路径——完整 `existingOutputPaths` 列表,或调用方提供时的缩小子集(这些可能属于选中的 store,而不是 repo)。
- a. 读取 delta spec 以理解意图变更。
- b. 读取 main spec:`<planningHome.root>/openspec/specs/<capability-path>/spec.md`(可能尚不存在)。
- 如果尚不存在(新 capability),匹配 `openspec archive` 行为:只能应用 ADDED requirements——step d 用它们创建 spec。
- MODIFIED 和 RENAMED 没有 requirement 可操作,因此停止该 capability 的 sync,并报告其 main spec 不存在且新 spec 只允许 ADDED;绝不要发明缺失的 requirement。
- REMOVED 没有东西可移除——跳过并警告。
- c. 智能应用变更:ADDED Requirements:如果 main spec 中不存在该 requirement → 添加它。
- ADDED Requirements:如果该 requirement 已存在 → 更新它以匹配(视为隐式 MODIFIED)。
- MODIFIED Requirements:在 main spec 中找到该 requirement。
- MODIFIED Requirements:应用变更——可以是:添加 main spec 尚无的新 scenarios;修改现有 scenarios;更改 requirement description。
- MODIFIED Requirements:保留 delta 未提及的 scenarios/content。
- REMOVED Requirements:从 main spec 移除整个 requirement block。
- REMOVED/retiring capability:仅当以下全部成立时,删除整个 `spec.md`——并且当目录中不再有其他内容时删除目录。
- 条件 1:本次运行移除 requirements 后没有留下 requirement blocks。
- 条件 2:spec 其余部分格式良好(仍有 `## Purpose`)。
- 条件 3:main spec 在本次 sync 前不是已经为空——如果你什么都没移除,就什么都不要改。
- 条件 4:整个文件中每个其他非空行都能归为 title、Purpose、Requirements header、或 canonical requirement 的 statement、scenarios、或 fenced examples。
- 条件 5:change 的 `.openspec.yaml` 声明 `retire_capabilities: true`。
- 条件 6:`spec.md` 解析在真实 specs root 内(不要跟随 capability-directory symlink 去删除外部文件)。
- 如果移除所选 requirements 会留下没有 requirement blocks,且任何 retirement 条件不满足,不要修改 main spec;停止该 capability 的 sync,报告阻塞条件,并告诉用户如何解决。
- 绝不写入或留下空的 `## Requirements` section。
- 当只缺 marker 时,也要说出来——这是用户可添加以让 retirement 通过的一件事。
- 删除文件也会删除其 `## Purpose`;任何其他 section 都会阻止 retirement。报告 retirement 时点名 Purpose。仅当 spec 位于调用方 checkout 中时,包含可粘贴的 `git checkout`;否则给出 checkout 范围的恢复指导。
- RENAMED Requirements:找到 FROM requirement,重命名为 TO。
- delta 中的 `## Purpose`:main spec 已有一个且它是权威的——不要动它(这是 `openspec archive` 的行为;它警告并继续)。
- d. Create new main spec 如果 capability 尚不存在:仅当 delta 有 ADDED requirements 可放入,且 step b 中没有 MODIFIED 或 RENAMED requirements 阻塞该 capability 时才创建;否则不创建任何东西,保持 specs 目录不变。
- 对于 REMOVED-only delta,如果 change 的 `.openspec.yaml` 声明 `retire_capabilities: true`,报告它已 retired,并继续而不重建 spec。
- 没有该 marker 时,报告 sync 被阻塞:`openspec archive` 会以 `Spec must have at least one requirement` 拒绝它。
- 空 delta 没有可 sync 的操作;也报告为 blocked。
- 绝不写入空的 `## Requirements` section。
- 创建 `<planningHome.root>/openspec/specs/<capability-path>/spec.md`。
- 添加 Purpose section:当 delta 有 `## Purpose` body 时逐字复制(这是 archive 的行为);没有时才写简短 TBD placeholder。
- 添加 Requirements section,包含 ADDED requirements。
- 遵循 Main Spec Format Reference。
- Step 5 Validate updated main specs:使用之前相同的 selected-root flags 运行 `openspec validate --specs`。
- 如果 validation 失败,报告问题,不要声称 sync 成功。
- Step 6 Show summary:应用所有变更后,总结哪些 capabilities 被更新。
- 总结做了哪些变更(requirements added/modified/removed/renamed)。
- 总结任何新 main spec 仍留下 TBD Purpose placeholder,使其现在被写入而不是滞留。
- 总结任何被 retired 的 capability,点名被删除的 `spec.md`、其 Purpose,以及可粘贴的 `git checkout` 或 checkout 范围的恢复指导。
- Delta Spec Format Reference:识别 delta 中 `# Spec Delta`、`## Purpose`(仅在引入全新 capability 的 delta 上,用于 seed 新 main spec)、`## ADDED Requirements`、`## MODIFIED Requirements`、`## REMOVED Requirements`、`## RENAMED Requirements` 的结构。
- Main Spec Format Reference:main specs 是 delta 合并进入的目标;它们绝不能包含 delta operation headers(`## ADDED/MODIFIED/REMOVED/RENAMED Requirements`);sync 后每个 requirement 位于单个 `## Requirements` section 下。
- Main Spec Format Reference 结构:`# <capability> Specification`、`## Purpose`(简短描述 capability 做什么及为何存在)、`## Requirements`,其下 requirement 和 scenario。
- Key Principle Intelligent Merging:与程序化合并不同,要合并而不是覆盖。
- MODIFIED block 携带整个 requirement——body 加上每个在变更后存活的 scenario;`openspec validate` 和 `openspec archive` 都拒绝丢弃 main spec 仍有的 scenario 的 MODIFIED。
- 保持 delta 未提及的任何内容,并维持 main spec 现有顺序。
- 使用判断力合理合并变更。
- Output On Success:成功后输出 `## Specs Synced: <change-name>`,列出 updated main specs。
- 输出中按 capability 列出 Added requirement、Modified requirement(如 added 1 scenario)、Created new spec file 等。
- 输出中说明 main specs 现在已更新,change 仍 active——实现完成后 archive。
- Guardrails:在变更前读取 delta 和 main specs。
- Guardrails:保留 delta 未提及的现有内容。
- Guardrails:绝不要原样把 delta 文件复制进 main spec——合并其内容,使 main spec 保持 Main Spec Format Reference 结构,无 delta operation headers。
- Guardrails:如果有不清楚之处,请求澄清。
- Guardrails:边做边展示正在变更什么。
- Guardrails:操作应幂等——运行两次应得到相同结果。
- Guardrails:只使用 `artifactPaths.specs.existingOutputPaths`;绝不要从不相关 artifacts 推断 delta specs。
- Guardrails:遵守调用方提供的 `existingOutputPaths` 子集;绝不要重新扩大回完整列表。
- Guardrails:直接 sync 时只获取一次 specs instructions,或在内联时复用 archive 提供的 snapshot。
- Guardrails:在 specs-instruction 响应非零或 JSON 无效时,每次 main-spec 写入前停止。
- Guardrails:Artifact rules 只约束被写入的 specs,绝不复制进输出文件。
适用边界 · 注意事项
- 项目未使用 OpenSpec,且用户没有明确要求 OpenSpec、本 skill 或其 slash command 时,不要启动本流程,按普通请求回答。
- 没有 delta specs,或调用方提供的路径不在 `artifactPaths.specs.existingOutputPaths` 中,或命名列表为空时,不要写入 main specs,报告并停止。
- 缺少 openspec CLI,或项目声明的 store 无法解析时,不要写入;先展示错误的 `message` 和 `fix` 并停止。