openspec-sync-specs
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSync delta specs from a change to main specs.
This is an agent-driven operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
Store selection: If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run to discover registered store ids, then pass on the commands that read or write specs and changes (, , , , , , , , , , ). Once selected, treat as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run , not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local root.
openspec store list --json--store <id>new changestatusinstructionslistshowvalidatearchivedoctorcontextschemasview--store <id>openspec status --change "<name>" --json --store "<id>"openspec/<capability-path>specs/user-authidentity/user-authInput: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
Steps
-
Select the changeIf a name is provided, use it. Otherwise:
- Infer from conversation context if the user mentioned a change
- Auto-select if only one active change exists
- If ambiguous, run to get available changes and ask the user to select one
openspec list --json
When prompting, show changes that have delta specs (underdirectory).specs/Always announce: "Using change: <name>" and how to override (e.g.,)./openspec-sync-specs <other> -
Resolve change contextRun:bash
openspec status --change "<name>" --jsonThe JSON includes. Main specs live underplanningHome.root— use that (store-aware) root for every main-spec path below, not a hardcoded repo path. When a store is selected it points at the store, not the current repository.<planningHome.root>/openspec/specs/ -
Find delta specsUsefrom the status JSON as the only source of delta spec paths. If the
artifactPaths.specs.existingOutputPathsentry is missing orspecsis empty, report that there are no delta specs to sync, do not infer them from other artifacts, and stop without requesting artifact instructions or writing a main spec.existingOutputPathsSync every path inunless the caller narrowed the set. A caller narrows it by naming an explicit list of complete entries fromexistingOutputPaths— copy those absolute values verbatim. Archive does this inline, and a user can too (for example, by selecting the entry ending inexistingOutputPaths). Then sync only the named paths and leave the remaining delta specs untouched: bulk archive excludes a delta whose implementation it could not find, and syncing it anyway would write a main spec the caller deliberately withheld. Carry that narrowed selection through step 4; never widen it back to the full list. If a named path is not in/specs/billing/invoices/spec.md, do not sync it — report it and stop, rather than dropping it silently. If the named list is empty, report that there is nothing to sync and stop without writing a main spec.existingOutputPathsEach delta spec file contains sections like:- - New requirements to add
## ADDED Requirements - - Changes to existing requirements
## MODIFIED Requirements - - Requirements to remove
## REMOVED Requirements - - Requirements to rename (FROM:/TO: format)
## RENAMED Requirements
If no delta specs found, inform user and stop. -
For each delta spec, apply changes to main specsBefore the first main-spec write, obtain one current specs-rule snapshot:
- If archive invoked this workflow inline and supplied a valid snapshot from
, reuse it and do not fetch the same instructions again.
openspec instructions specs --change "<name>" --json - Otherwise run that command once now with the same selected-root flags.
- If the direct lookup exits non-zero or returns invalid artifact-instruction JSON, report the error and stop before writing any main spec. Do not treat the failure as an absent rule set.
- A valid response with omitted means no artifact rules are configured and the existing semantic merge continues.
rules
Apply returnedonly to the content and form of the main specs produced by this merge. Artifact rules are not operation guidance and cannot change selected roots, delta paths, CLI checks, or workflow steps. Use their text as constraints without copying it verbatim into a main spec or summary.rulesFor each capability delta spec path selected in step 3 — the fulllist, or the narrowed subset when a caller supplied one (these may belong to a selected store, not the repo):existingOutputPathsa. Read the delta spec to understand the intended changesb. Read the main spec at(may not exist yet)<planningHome.root>/openspec/specs/<capability-path>/spec.mdc. Apply changes intelligently:ADDED Requirements:- If requirement doesn't exist in main spec → add it
- If requirement already exists → update it to match (treat as implicit MODIFIED)
MODIFIED Requirements:- Find the requirement in main spec
- Apply the changes - this can be:
- Adding new scenarios the main spec does not have yet
- Modifying existing scenarios
- Changing the requirement description
- Preserve scenarios/content not mentioned in the delta
REMOVED Requirements:- Remove the entire requirement block from main spec
- Retiring the capability. Delete the whole - and the directory once nothing else is left in it - only when ALL of these hold:
spec.md- removing the requirements this run left no requirement blocks;
- the rest of the spec is well-formed (it still has a );
## Purpose - the main spec was not already empty before this sync - if you removed nothing, change nothing;
- every other nonblank line in the whole file is accounted for as the title, Purpose, Requirements header, or a canonical requirement's statement, scenarios, or fenced examples;
- the change's declares
.openspec.yaml;retire_capabilities: true - the resolves inside the real specs root (do not follow a capability-directory symlink to delete an external file). If removing the selected requirements would leave no requirement blocks and any retirement condition is not satisfied, do not modify the main spec. Stop the sync for that capability, report the blocking condition, and tell the user how to resolve it. Never write or leave an empty
spec.mdsection. When only the marker is missing, say that too - it is the one thing the user can add to make the retirement go through.## Requirements
- Deleting the file also deletes its ; any other section blocks retirement. Name Purpose when you report the retirement. Include a pasteable
## Purposeonly when the spec lived in the caller's checkout; otherwise give checkout-scoped recovery guidance.git checkout
RENAMED Requirements:- Find the FROM requirement, rename to TO
in the delta:## Purpose- The main spec already has one and it is authoritative - leave it alone
(this is what does; it warns and moves on)
openspec archive
d. Create new main spec if capability doesn't exist yet:- Create
<planningHome.root>/openspec/specs/<capability-path>/spec.md - Add Purpose section: copy the delta's body verbatim when it has one (this is what
## Purposedoes); only write a brief TBD placeholder when it does notopenspec archive - Add Requirements section with the ADDED requirements
- Follow the Main Spec Format Reference below
- If archive invoked this workflow inline and supplied a valid snapshot from
-
Validate updated main specsRunwith the same selected-root flags used earlier. If validation fails, report the problems and do not claim the sync succeeded.
openspec validate --specs -
Show summaryAfter applying all changes, summarize:
- Which capabilities were updated
- What changes were made (requirements added/modified/removed/renamed)
- Any new main spec left with a TBD Purpose placeholder, so it gets written now rather than lingering
- Any capability retired, naming the deleted , its Purpose, and either a pasteable
spec.mdor checkout-scoped recovery guidancegit checkout
Delta Spec Format Reference
markdown
undefined将变更中的delta specs同步至主规格。
这是一项Agent驱动的操作——你需要读取delta specs并直接编辑主规格以应用变更。这种方式支持智能合并(例如,无需复制整个需求即可添加场景)。
Store选择: 如果用户指定了某个store(store是指在本机注册的独立OpenSpec仓库),或者工作内容位于某个store中,请运行获取已注册的store ID,然后在读写规格和变更的命令(、、、、、、、、、、)中传入参数。一旦选定store,在后续工作流中参数将持续生效。下方所有未限定作用域的命令示例都是简写形式:运行前请追加该参数。例如,应运行,而非下方展示的未限定形式。其他命令不支持该参数。命令输出的提示信息已携带该参数,后续操作请保留。如果没有指定store,命令将作用于最近的本地根目录。
openspec store list --jsonnew changestatusinstructionslistshowvalidatearchivedoctorcontextschemasview--store <id>--store <id>openspec status --change "<name>" --json --store "<id>"openspec/<capability-path>specs/user-authidentity/user-auth输入: 可选择指定变更名称。如果未指定,需检查是否可从对话上下文中推断。如果表述模糊或存在歧义,必须提示用户选择可用的变更。
操作步骤
-
选择变更如果用户提供了变更名称,则直接使用。否则:
- 如果用户提到过某个变更,从对话上下文中推断
- 如果仅存在一个活跃变更,则自动选择
- 如果存在歧义,运行获取可用变更列表,并请用户选择一个
openspec list --json
提示用户时,请展示包含delta specs的变更(位于目录下)。specs/始终告知用户:"当前使用变更:<name>",并说明覆盖方式(例如)。/openspec-sync-specs <other> -
解析变更上下文运行:bash
openspec status --change "<name>" --json返回的JSON中包含。主规格存放在planningHome.root目录下——下方所有主规格路径都应使用这个(感知store的)根目录,而非硬编码的仓库路径。当选择了store时,该路径指向store,而非当前仓库。<planningHome.root>/openspec/specs/ -
查找delta specs仅使用status返回的JSON中的作为delta spec路径的唯一来源。如果
artifactPaths.specs.existingOutputPaths条目缺失或specs为空,需告知用户没有可同步的delta specs,不要从其他制品中推断,也无需请求制品指令或写入主规格,直接终止操作。existingOutputPaths除非调用方缩小了范围,否则需同步中的所有路径。调用方可通过指定existingOutputPaths中完整条目的明确列表来缩小范围——请原样复制这些绝对路径值。归档操作会内联执行此操作,用户也可以这样做(例如,选择以existingOutputPaths结尾的条目)。 此时仅同步指定的路径,其余delta specs保持不变:批量归档会排除找不到实现的delta spec,如果强行同步会写入调用方故意保留的主规格。请在步骤4中始终使用这个缩小后的选择范围,绝不要重新扩大到完整列表。如果指定的路径不在/specs/billing/invoices/spec.md中,不要同步它——需报告该问题并终止操作,而非静默忽略。如果指定的列表为空,需告知用户没有可同步的内容,无需写入主规格,直接终止。existingOutputPaths每个delta spec文件包含以下类似章节:- - 待新增的需求
## ADDED Requirements - - 对现有需求的变更
## MODIFIED Requirements - - 待删除的需求
## REMOVED Requirements - - 待重命名的需求(格式为FROM:/TO:)
## RENAMED Requirements
如果未找到delta specs,告知用户并终止操作。 -
针对每个delta spec,将变更应用到主规格在首次写入主规格之前,获取一份当前的规格规则快照:
- 如果归档操作内联调用了此工作流,并提供了来自的有效快照,请复用该快照,不要重复获取相同的指令。
openspec instructions specs --change "<name>" --json - 否则,使用之前选定的根目录参数运行一次该命令。
- 如果直接查找返回非零退出码,或返回的制品指令JSON无效,需报告错误,并在写入任何主规格之前终止操作。不要将该失败视为规则集不存在。
- 如果响应有效但省略了,表示未配置制品规则,继续执行现有的语义合并即可。
rules
返回的仅适用于本次合并生成的主规格的内容和形式。制品规则不是操作指南,不能更改选定的根目录、delta路径、CLI检查或工作流步骤。请将其文本作为约束使用,不要原样复制到主规格或摘要中。rules对于步骤3中选定的每个能力delta spec路径——即完整的列表,或调用方提供的缩小后的子集(这些路径可能属于选定的store,而非当前仓库):existingOutputPathsa. 读取delta spec,了解预期的变更内容b. 读取主规格,路径为(可能尚不存在)<planningHome.root>/openspec/specs/<capability-path>/spec.mdc. 智能应用变更:ADDED Requirements(新增需求):- 如果主规格中不存在该需求 → 新增
- 如果该需求已存在 → 更新使其匹配(视为隐式修改)
MODIFIED Requirements(修改需求):- 在主规格中找到对应需求
- 应用变更,变更类型可以是:
- 添加主规格中尚未存在的新场景
- 修改现有场景
- 更改需求描述
- 保留delta中未提及的场景/内容
REMOVED Requirements(删除需求):- 从主规格中删除整个需求块
- 停用该能力。仅当满足以下所有条件时,才删除整个文件——如果目录中没有其他内容,再删除目录:
spec.md- 本次运行删除需求后,没有剩余的需求块;
- 规格的其余部分格式正确(仍包含章节);
## Purpose - 本次同步前主规格并非空的——如果没有删除任何内容,就不要做任何更改;
- 文件中所有其他非空行都属于标题、Purpose、Requirements标题,或规范需求的陈述、场景、围栏代码块示例;
- 变更的中声明了
.openspec.yaml;retire_capabilities: true - 的解析路径位于真实的规格根目录内(不要跟随能力目录的符号链接删除外部文件)。 如果删除选定的需求后没有剩余需求块,但有任何停用条件不满足,则不要修改主规格。停止该能力的同步,报告阻碍条件,并告知用户如何解决。绝不要写入或留下空的
spec.md章节。如果只是缺少标记,也要说明——这是用户可以添加以使停用生效的内容。## Requirements
- 删除文件也会删除其章节;任何其他章节都会阻止停用。报告停用时请提及Purpose章节。仅当规格位于调用方的工作副本中时,才提供可直接粘贴的
## Purpose命令;否则提供基于工作副本范围的恢复指导。git checkout
RENAMED Requirements(重命名需求):- 找到FROM对应的需求,重命名为TO
delta中的章节:## Purpose- 主规格中已有该章节,且以主规格为准——不要修改它(这与的行为一致;它会发出警告并继续)。
openspec archive
d. 如果能力尚不存在,创建新的主规格:- 创建文件
<planningHome.root>/openspec/specs/<capability-path>/spec.md - 添加Purpose章节:如果delta中有章节,原样复制其内容(这与
## Purpose的行为一致);如果没有,则仅编写简短的TBD占位符openspec archive - 添加Requirements章节,包含所有新增需求
- 遵循下方的主规格格式参考
- 如果归档操作内联调用了此工作流,并提供了来自
-
验证更新后的主规格使用之前选定的根目录参数运行。如果验证失败,报告问题,不要声称同步成功。
openspec validate --specs -
展示摘要应用所有变更后,总结以下内容:
- 哪些能力得到了更新
- 做了哪些变更(新增/修改/删除/重命名的需求)
- 是否有新的主规格仍保留TBD Purpose占位符,以便用户立即编写而非搁置
- 是否有能力被停用,需说明删除的文件、其Purpose内容,以及可粘贴的
spec.md命令或基于工作副本范围的恢复指导git checkout
Delta Spec格式参考
markdown
undefinedPurpose
Purpose
Only on a delta that introduces a brand-new capability. Seeds the new main spec.
Only on a delta that introduces a brand-new capability. Seeds the new main spec.
ADDED Requirements
ADDED Requirements
Requirement: New Feature
Requirement: New Feature
The system SHALL do something new.
The system SHALL do something new.
Scenario: Basic case
Scenario: Basic case
- WHEN user does X
- THEN system does Y
- WHEN user does X
- THEN system does Y
MODIFIED Requirements
MODIFIED Requirements
Requirement: Existing Feature
Requirement: Existing Feature
The system SHALL keep doing the existing thing, now also handling A.
The system SHALL keep doing the existing thing, now also handling A.
Scenario: Scenario the main spec already has
Scenario: Scenario the main spec already has
- WHEN user does X
- THEN system does Y
- WHEN user does X
- THEN system does Y
Scenario: New scenario to add
Scenario: New scenario to add
- WHEN user does A
- THEN system does B
- WHEN user does A
- THEN system does B
REMOVED Requirements
REMOVED Requirements
Requirement: Deprecated Feature
Requirement: Deprecated Feature
RENAMED Requirements
RENAMED Requirements
- FROM:
### Requirement: Old Name - TO:
### Requirement: New Name
**Main Spec Format Reference**
Main specs are what the delta merges INTO. They must never contain delta operation headers (`## ADDED/MODIFIED/REMOVED/RENAMED Requirements`) - after syncing, every requirement lives under a single `## Requirements` section:
```markdown- FROM:
### Requirement: Old Name - TO:
### Requirement: New Name
**主规格格式参考**
主规格是delta合并的目标。它们绝不能包含delta操作标题(`## ADDED/MODIFIED/REMOVED/RENAMED Requirements`)——同步后,所有需求都应位于单个`## Requirements`章节下:
```markdown<capability> Specification
<capability> Specification
Purpose
Purpose
Short description of what this capability does and why it exists.
Short description of what this capability does and why it exists.
Requirements
Requirements
Requirement: New Feature
Requirement: New Feature
The system SHALL do something new.
The system SHALL do something new.
Scenario: Basic case
Scenario: Basic case
- WHEN user does X
- THEN system does Y
**Key Principle: Intelligent Merging**
Unlike programmatic merging, you merge rather than overwrite:
- A MODIFIED block carries the whole requirement - body plus every scenario that survives the change. `openspec validate` and `openspec archive` both reject one that drops a scenario the main spec still has.
- Keep anything the delta does not mention, in the main spec's existing order
- Use your judgment to merge changes sensibly
**Output On Success**
```markdown- WHEN user does X
- THEN system does Y
**核心原则:智能合并**
与程序化合并不同,你需要执行合并而非覆盖:
- MODIFIED块包含完整的需求——正文以及所有在变更后保留的场景。如果某个MODIFIED块丢失了主规格中仍存在的场景,`openspec validate`和`openspec archive`都会拒绝它。
- 保留delta中未提及的所有内容,保持主规格中的原有顺序
- 运用你的判断合理合并变更
**成功输出示例**
```markdownSpecs Synced: <change-name>
Specs Synced: <change-name>
Updated main specs:
<capability-1>:
- Added requirement: "New Feature"
- Modified requirement: "Existing Feature" (added 1 scenario)
<capability-2>:
- Created new spec file
- Added requirement: "Another Feature"
Main specs are now updated. The change remains active - archive when implementation is complete.
**Guardrails**
- Read both delta and main specs before making changes
- Preserve existing content not mentioned in delta
- Never copy a delta file into a main spec as-is - merge its content so the main spec keeps the Main Spec Format Reference structure, with no delta operation headers
- If something is unclear, ask for clarification
- Show what you're changing as you go
- The operation should be idempotent - running twice should give same result
- Use only `artifactPaths.specs.existingOutputPaths`; never infer delta specs from unrelated artifacts
- Honor a caller-supplied subset of `existingOutputPaths`; never widen it back to the full list
- Fetch specs instructions once for direct sync, or reuse the archive-supplied snapshot inline
- Stop before every main-spec write on a non-zero or invalid JSON specs-instruction response
- Artifact rules constrain only the specs being written and are never copied into output filesUpdated main specs:
<capability-1>:
- Added requirement: "New Feature"
- Modified requirement: "Existing Feature" (added 1 scenario)
<capability-2>:
- Created new spec file
- Added requirement: "Another Feature"
Main specs are now updated. The change remains active - archive when implementation is complete.
**防护规则**
- 做出变更前,同时读取delta spec和主规格
- 保留delta中未提及的现有内容
- 绝不要将delta文件原样复制到主规格中——合并其内容,使主规格保持《主规格格式参考》的结构,不包含任何delta操作标题
- 如果有不清楚的地方,询问澄清
- 操作过程中展示你正在更改的内容
- 操作应具有幂等性——运行两次应得到相同结果
- 仅使用`artifactPaths.specs.existingOutputPaths`;绝不要从不相关的制品中推断delta specs
- 遵守调用方提供的`existingOutputPaths`子集;绝不要重新扩大到完整列表
- 直接同步时仅获取一次规格指令,或内联复用归档提供的快照
- 如果规格指令响应的JSON无效或返回非零码,在写入任何主规格前终止
- 制品规则仅约束待写入的规格,绝不要复制到输出文件中