关于 openspec-bulk-archive-change
用于将多个已完成的 OpenSpec 变更批量归档的技能。它检查任务与产物状态、检测规格路径冲突,并依据代码实现证据决定规格同步方式;变更由用户选择并确认。
主要功能
- 01批量归档所选变更
- 02检查产物与任务进度
- 03检测增量规格路径冲突
- 04依据代码证据解决冲突
- 05检查归档目标是否重名
适用场景
- 01一次归档多个已完成变更
- 02归档前检查未完成工作
- 03处理规格路径重叠的变更
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ fission-ai/ openspec --skill openspec-bulk-archive-change安装后在 Claude Code 中输入/openspec-bulk-archive-change确认已加载。
详细介绍
一次性归档多个已完成的变更。
此技能可批量归档变更,并通过检查代码库来判断实际实现情况,从而智能处理规格冲突。
存储库选择: 如果用户指定了存储库(存储库是指在此计算机上注册的独立 OpenSpec 仓库),或相关工作位于其中,请运行 openspec store list --json,查找已注册的存储库 ID,然后在读取或写入规格和变更的命令(new change、status、instructions、list、show、validate、archive、doctor、context、schemas、view)中传入 --store <id>。选定后,在整个工作流的其余部分都将 --store <id> 视为固定参数。以下未指定存储库的示例命令均为简写:运行前请追加此参数。例如,运行 openspec status --change "<name>" --json --store "<id>",而不是下方所示的未指定存储库版本。其他命令不接受此参数。命令输出的提示中已包含该参数;后续操作时请保留该参数。如果未指定存储库,命令会对最近的本地 openspec/ 根目录执行操作。
项目检查: 以下步骤要求项目已在使用 OpenSpec。在第一个会写入内容的步骤(new change、archive、sync specs 或编写构件文件)之前,请确认项目已有根目录:运行 openspec list --json(如果已选定存储库,则传入 --store <id>,因为此时存储库就是根目录),并读取 root。如果返回根对象,说明项目已完成设置。"root": null 表示项目尚未设置——此处没有 openspec/ 目录,执行 openspec new change 等写入操作会将其作为副作用创建。此命令还会以非零状态码退出,这就是结果,并不代表 CLI 出错;请读取 JSON,不要重试或绕过问题。
一个 "root": null 结果不一定表示项目尚未设置:如果 status 的错误消息以 Declared in 或 Invalid store declaration in 开头,并指出此项目的 openspec/config.yaml(或 config.yml),则表示项目通过其声明的存储库使用 OpenSpec,但此计算机无法解析该存储库(该存储库尚未注册,或 store: 行格式错误)。不要将项目视为尚未初始化,也不要继续执行下方分支:停止写入,并向用户展示错误中的 message 和 fix。
如果没有根目录,接下来的操作取决于此工作流的触发方式:
- 自动选择:你自行选择了此工作流,用户没有提及 OpenSpec、此技能,也没有运行其斜杠命令。停止使用 OpenSpec,并像未安装 OpenSpec 一样正常回应用户请求。不要询问用户是否要进行设置,也不要提及 OpenSpec 设置。
- 用户明确请求使用 OpenSpec:用户提及了 OpenSpec、此技能,或运行了其斜杠命令。停止写入,并询问用户如何继续:设置此项目(
openspec init)、指定他们已有的存储库(--store <id>),或在本次请求中不使用 OpenSpec 继续。等待用户回答。
在这两种情况下,都绝不能将创建根目录作为副作用:用户未要求前不要运行 openspec init,不要手动创建 openspec/ 文件,也不要让命令创建它。
<capability-path> 是相对于 specs/ 的规格目录(例如 user-auth 或 identity/user-auth)。解析其主规格时,请保留每个差异规格中的完整路径。
输入:无(提示用户选择)
步骤
-
获取活动变更
运行
openspec list --json获取所有活动变更。如果没有活动变更,请告知用户并停止。
-
提示用户选择变更
让用户选择变更(可多选):
- 显示列表输出中的每个变更名称和任务状态
- 提供“所有变更”选项
- 允许选择任意数量(可以只选 1 个,通常会选 2 个或更多)
重要:不要自动选择。始终让用户自行选择。
在批量验证前,为所选根目录一次性加载当前归档输入: 从此根目录中选择一个已选变更,并使用相同的已选根目录标志运行
openspec instructions archive --change "<selected-change>" --json。 此查询仅供参考,且为可选操作:它只提供额外的提示词输入,因此绝不能阻止批处理。如果查询失败或返回无效 JSON——例如使用尚不支持此命令的旧版 CLI——则继续批处理,不提供上下文或操作指南。不要报告错误,也不要停止。有效响应可以省略
context和operationGuidance。将context视为整个批次必需的提示词级输入:阅读并考虑它,并应用相关的项目事实、约定和约束。将operationGuidance视为可选的补充建议:阅读并考虑其中的每一条,并遵循适用且与内置批处理工作流兼容的条目。将这两个字段与冲突分析、明确的用户选择、已解析路径、CLI 检查和命令约定分开处理。如果上下文与这些控制性输入冲突,请报告冲突并保留控制性输入的值。如果指南不适用或与控制性输入冲突,则不要遵循,并说明原因。不要根据任一字段推断跳过的提示词、替代路径或标志,也不要将其中的文本原样复制到规格、变更或摘要中。这些是提示词级行为约定,而非可强制执行的检查。
-
批处理验证 - 收集所有已选变更的状态
使用相同的已选根目录标志运行一次
openspec list --json,以获取任务进度。如果查询失败、返回无效 JSON、遗漏任何已选变更、包含重复的已选变更,或返回无效计数,请报告问题,并在同步或归档此批次之前停止。对每项已选变更,收集:
a. 工件状态 - 运行
openspec status --change "<name>" --json- 解析
schemaName、artifacts、planningHome、changeRoot、artifactPaths和actionContext - 记录哪些工件状态为
done,哪些为其他状态
b. 任务完成情况 - 从列表响应中查找
name与此变更完全匹配的changes条目- 要求
totalTasks和completedTasks均为非负整数,且completedTasks <= totalTasks - 未完成任务数 =
totalTasks - completedTasks - CLI 会解析架构所跟踪的任务文件,包括自定义工件名称、输出路径和 glob 模式
- 不要根据工件状态、工件 ID
tasks或缺少顶层tasks.md来推断任务是否完成 - CLI 仅将
x/X复选框标记计为已完成;其他标记仍视为未完成 - 如果
totalTasks为零,注明“No tasks”
c. 差异规格 - 检查状态 JSON 中的
artifactPaths.specs.existingOutputPaths- 列出已存在的能力规格
- 对每个规格,提取需求名称(匹配
### Requirement: <name>的行) - 将此列表视为唯一的差异规格来源。如果缺少
specs条目或该列表为空,则不对此变更执行规格同步或规格指令查询;不要从无关工件推断差异。 - 对每项变更分别进行独立评估,包括部分架构没有
specs工件的混合架构批次 d. 归档目标 — 计算每个变更的目标名称,并记录为该变更的<target-name> - 如果变更名称已以
YYYY-MM-DD-前缀开头,则原样使用;否则在前面加上当前日期,格式为YYYY-MM-DD-<name>(规则与openspec archive相同) - 检查
<planningHome.changesDir>/archive/<target-name>是否已存在 - 如果已存在,或其他选定变更解析出的目标名称相同,则将所有此类变更标记为
Blocked,并注明Archive directory already exists - 被阻止的变更绝不进行同步或移动:在第 6 步表格中将其显示为
Blocked,将其排除在冲突解决之外(仅使用其他变更解决冲突),并在第 8d 步中将其记录为 Failed - 在写入任何主规格之前进行此项检查,与
openspec archive的行为一致:如果同步后才发现冲突,就会导致主规格已被改写,但归档并未完成
- 解析
-
检测规格冲突
构建一个以
<capability-path>为键的映射,该路径是相对于specs/的精确路径:identity/user-auth -> [change-a, change-b] <- CONFLICT (2+ changes) billing/user-auth -> [change-c] <- OK (different full path)当 2 个或更多选定变更包含相同
<capability-path>的增量规格时,即存在冲突。 -
通过 Agent 方式解决冲突
对于每个冲突,调查代码库:
a. 阅读增量规格,了解每个冲突变更声称要添加或修改的内容
b. 搜索代码库以查找实现证据:
- 查找实现各增量规格中要求的代码
- 检查相关文件、函数或测试
c. 确定解决方案:
- 如果实际上只有一个变更已实现,则同步该变更的规格
- 如果两个变更都已实现,则按时间顺序应用(较早的先应用,较新的覆盖)
- 如果两个变更都未实现,则跳过规格同步并警告用户
d. 记录每个冲突的解决方案:
- 按变更和
<capability-path>记录每个增量规格的纳入或排除决定 - 记录要应用的已纳入增量规格及其应用顺序
- 记录因缺少实现而从同步中排除的增量规格
- 说明理由(在代码库中发现了什么)
-
显示汇总状态表
显示汇总所有变更的表格:
| Change | Artifacts | Tasks | Specs | Conflicts | Status | |---------------------|-----------|-------|---------|-----------|--------| | schema-management | Done | 5/5 | 2 delta | None | Ready | | project-config | Done | 3/3 | 1 delta | None | Ready | | add-oauth | Done | 4/4 | 1 delta | identity/user-auth (!) | Ready* | | add-verify-skill | 1 left | 2/5 | None | None | Warn |对于冲突,显示解决方案:
* Conflict resolution: - identity/user-auth spec: Will apply add-oauth then add-jwt (both implemented, chronological order)对于未完成的变更,显示警告:
Warnings: - add-verify-skill: 1 incomplete artifact, 3 incomplete tasks -
确认批量操作
向用户询问一个确认问题:
- “归档 N 个变更?”并根据状态提供选项
- 选项可能包括:
- “归档全部 N 个变更”
- “仅归档 N 个就绪变更(跳过未完成项)”
- “取消”
如果存在未完成的变更,请明确说明归档时会附带警告。
根据用户的意图处理回答,而不是要求标签完全匹配——这些标签是你写的, 因此应根据用户选择进行匹配,而不是拘泥于上述措辞:
- “取消”——停止,不要归档。报告未归档任何内容,并跳过剩余步骤。
- 归档全部选项——继续处理所有未被标记为
Blocked的选定变更 - 仅归档就绪项选项——仅处理第 6 步表格中标记为
Ready或Ready*的变更,并在第 8d 步中将其余变更记录为 Skipped;但Blocked变更除外,这些变更仍标记为 Failed,并注明Archive directory already exists。如果跳过某个Ready*变更的冲突伙伴,则仅使用要归档的变更重新推导该冲突的解决方案。 - 其他任何回答——重新询问,不要归档
在步骤 8 写入第一个主规范或移动任何变更之前,先为已确认批次获取所有必需的规范规则快照。对于每个将同步具体
artifactPaths.specs.existingOutputPaths的变更,使用相同的选定根目录标志,恰好运行一次openspec instructions specs --change "<name>" --json。在首次写入或移动之前获取所有快照。 如果任何查询以非零状态退出,或返回无效的 artifact-instruction JSON, 请指出受影响的变更,报告错误,并在任何主规范写入或变更移动之前停止整个批次。不要将查询失败视为没有规则。没有rules的有效响应表示无规则。
-
为每个已确认的变更执行归档
处理前,将步骤 5 中记录的决策(经过步骤 7 的任何重新推导后)归入两个按增量划分的集合:
includedDeltas:已确认变更中所有无冲突的增量规范,以及选定用于同步的冲突增量规范excludedDeltas:因缺少实现而从已确认变更中排除的冲突增量规范- 单个变更可以同时包含纳入和排除的增量规范。按增量保留决策;不要将其合并为按变更划分的同步标志。
按确定的顺序处理变更(遵循冲突解决顺序):
a. 同步纳入的增量规范:
- 仅对
includedDeltas中有条目的变更,内联运行openspec-sync-specs工作流(由 Agent 驱动的智能合并),仅传入纳入的增量路径,并明确指示其忽略该变更的excludedDeltas。等待其完成。 - 如果同步报告任何停止或阻塞条件,则视为同步失败。立即停止处理该变更。在继续处理下一个变更之前,将该变更的结果记为批次结果中的 Failed,并包含同步阻塞条件或错误。
- 不要执行同步后的内容比较,也不要移动其
changeRoot;保持变更原样。 - 对于冲突,按解决后的顺序应用。
- 将该变更获取的规范规则快照传入内联同步;内联同步必须复用该快照,不得再次获取指令。
- 仅将工件规则应用于该变更生成的主规范。它们不会改变冲突解决、归档行为或 CLI 契约,其文本也不会复制到输出文件中。
- 不要委派给后台任务——步骤 8c 会在仍有同步任务读取
changeRoot时将其移走。 - 如果某个变更没有纳入的增量规范,则不要为其运行同步工作流。
b. 移动
changeRoot前验证纳入的增量规范:- 仅对
includedDeltas中的增量规范重新进行比较,并与<planningHome.root>/openspec/specs/<capability-path>/spec.md中的主规范比对(使用步骤 3 状态 JSON 中感知存储位置的planningHome.root,不要使用硬编码的仓库路径)。 - 验证主规范已更新:
- 已添加的需求存在
- 已修改的需求包含增量规范中指定的场景和描述变更,且其他场景保持不变
- 已移除的需求不再存在——如果此次同步停用了某项能力(移除其最后一个需求,使
## Requirements为空),则应删除其主规范,而不是保留空文件。 - 已重命名的需求使用新名称,且旧名称已不存在
- 不要验证
excludedDeltas中的增量规范;它们有意保持未同步状态。 - 如果同步失败或任何能力未通过验证,则报告差异,并且失败或跳过移动该变更的
changeRoot——不要归档该变更。changeRoot保持原样。
c. 执行归档:
目标名称:使用步骤 3d 中为该变更记录的
<target-name>,不得更改。切勿在此处重新计算:跨越午夜运行的批次可能会在步骤 3 中检查一个日期,却移动到另一个日期。 检查目标是否已存在:- 移动前立即再次检查,即使步骤 3 已检查过:目标可能在批处理期间出现
- 如果已存在:将此变更记录为失败,错误为
Archive directory already exists,将changeRoot保留在原处,报告步骤 8a 已为其同步的任何主规格,并继续处理剩余变更 - 如果不存在:将
changeRoot移动到归档目录
mkdir -p "<planningHome.changesDir>/archive" mv "<changeRoot>" "<planningHome.changesDir>/archive/<target-name>"**确认移动时没有嵌套:**即使目标在检查后出现,
mv也会以 0 退出,并将变更移动到该目录内部。如果现在存在<planningHome.changesDir>/archive/<target-name>/<change-directory-name>(即changeRoot的最后一个路径段),则将该目录移回changeRoot,并将此变更记录为失败,错误为Archive directory already exists。绝不要将其报告为已归档。d. 跟踪每项变更的结果:
- 成功:已成功归档
- 失败:归档或规格验证期间出错(记录错误)
- 已跳过:用户选择不归档(如适用)
- 跳过同步:对于
excludedDeltas中的每个增量,报告同步已跳过,并注明变更、<capability-path>和记录的原因。这与跳过归档不同。
-
显示摘要
显示最终结果:
## Bulk Archive Complete Archived 3 changes: - schema-management-cli -> archive/2026-01-19-schema-management-cli/ - project-config -> archive/2026-01-19-project-config/ - add-oauth -> archive/2026-01-19-add-oauth/ Skipped 1 change: - add-verify-skill (user chose not to archive incomplete) Spec sync summary: - 4 delta specs synced to main specs - 1 delta spec sync skipped (add-jwt, identity/user-auth: implementation not found) - 1 conflict resolved (identity/user-auth: synced add-oauth, skipped add-jwt)如果存在失败:
Failed 1 change: - some-change: Archive directory already exists
冲突解决示例
示例 1:仅一个已实现
Conflict: <planningHome.root>/openspec/specs/auth/spec.md touched by [add-oauth, add-jwt]
Checking add-oauth:
- Delta adds "OAuth Provider Integration" requirement
- Searching codebase... found src/auth/oauth.ts implementing OAuth flow
Checking add-jwt:
- Delta adds "JWT Token Handling" requirement
- Searching codebase... no JWT implementation found
Resolution: Only add-oauth is implemented. Will sync add-oauth specs only.
示例 2:两者均已实现
Conflict: <planningHome.root>/openspec/specs/api/spec.md touched by [add-rest-api, add-graphql]
Checking add-rest-api (created 2026-01-10):
- Delta adds "REST Endpoints" requirement
- Searching codebase... found src/api/rest.ts
Checking add-graphql (created 2026-01-15):
- Delta adds "GraphQL Schema" requirement
- Searching codebase... found src/api/graphql.ts
Resolution: Both implemented. Will apply add-rest-api specs first,
then add-graphql specs (chronological order, newer takes precedence).
成功时的输出
## Bulk Archive Complete
Archived N changes:
- <change-1> -> archive/<target-name-1>/
- <change-2> -> archive/<target-name-2>/
Spec sync summary:
- N delta specs synced to main specs
- No conflicts (or: M conflicts resolved)
部分成功时的输出
## Bulk Archive Complete (partial)
Archived N changes:
- <change-1> -> archive/<target-name-1>/
Skipped M changes:
- <change-2> (user chose not to archive incomplete)
Failed K changes:
- <change-3>: Archive directory already exists
没有变更时的输出
## No Changes to Archive
No active changes found. Create a new change to get started.
护栏
- 允许任意数量的变更(1 个或更多均可,典型用例为 2 个或更多)
- 始终提示用户进行选择,不得自动选择
- 尽早检测规范冲突,并通过检查代码库解决
- 当两个变更都已实现时,按时间顺序应用规范
- 仅当缺少实现时才跳过规范同步(并警告用户)
- 确认前清晰展示每项变更的状态
- 整个批次只进行一次确认
- 用户取消确认后,绝不归档——取消的批次不会归档任何内容
- 跟踪并报告所有结果(成功/跳过/失败)
- 移至归档时保留 .openspec.yaml
- 归档目录目标使用当前日期,该日期在步骤 3d 中计算一次,并在移动时重复使用:YYYY-MM-DD-;如果名称已以
YYYY-MM-DD-前缀开头,则原样使用(绝不叠加第二个日期) - 如果归档目标已存在,则该变更失败,但继续处理其他变更
- 在步骤 3 中、首次写入主规范之前检查每个归档目标;目标已存在的变更绝不进行同步或移动
- 如果请求同步,则针对每个包含增量规范的变更,内联运行
openspec-sync-specs工作流(由 Agent 驱动) - 将每个增量规范的
includedDeltas和excludedDeltas决策带入执行流程;只同步和验证已包含的增量规范 - 将每个已排除的增量规范报告为
sync skipped,但不要因此将归档本身视为已跳过 - 规范同步仍在进行时,绝不归档变更——内联运行同步,并在移动
changeRoot前验证<planningHome.root>/openspec/specs/<capability-path>/spec.md中的主规范 - 对每个选定的根目录,只获取一次归档输入,然后再检查规范或移动文件
- 在批次首次写入或移动主规范之前,获取所有必需的规范规则快照
- 归档输入查找失败不会阻止批次;继续执行时不使用上下文或指导
- 规范说明查找失败时,原子性地停止整个批次
- 没有具体
artifactPaths.specs.existingOutputPaths的变更继续执行,不进行规范同步 - 在整个批次中应用相关运行时上下文,并报告冲突
- 操作指导仅供参考;考虑每一条建议,并解释拒绝采纳的理由
- 将运行时输入、冲突分析、CLI 推导值和制品规则分开处理
- 制品规则仅约束写入的规范
- 绝不将运行时输入或制品规则文本原样复制到输出文件