Repository navigation
After /opsx-archive executes successfully, sync is not executed. #799
Description

Activity
Also noticed that the main spec file is not updating: after each
archivecommand execution an agent mentioned that /spec is empty and no action required.
Looks related to changes in the latest release.If I understand correctly, I also have this problem, at least for changes that create new specs that aren't already in the specs folder.
It happened to me with both version 1.1.1 and 1.2.0. I had to manually instruct to copy over the spec.
OpenSpec on OpenCode + GPT 4.1
Reacted by svaiteIf I understand correctly, I also have this problem, at least for changes that create new specs that aren't already in the specs folder.
It happened to me with both version 1.1.1 and 1.2.0. I had to manually instruct to copy over the spec.
OpenSpec on OpenCode + GPT 4.1
Same behavior on Ubuntu 25 throught Opencode
Same for me. Has it been confirmed as a BUG? any quick fix/workaround?
is some file is holding by other editors?
In my case it was caused by old models (like gpt 4.1) which are not working well with openspec scripts and instructions. More advanced models are capable to do this pretty well. Also, models are being confused sometimes by the outputs of CLI commands like "no matching specs".
is some file is holding by other editors?
I do not think so.
In my case it was caused by old models (like gpt 4.1) which are not working well with openspec scripts and instructions. More advanced models are capable to do this pretty well. Also, models are being confused sometimes by the outputs of CLI commands like "no matching specs".
Then is there any explict approach to make it always ok?
Additionly, how can I make the workflow did not jump to next phase automatically, and let me to explict do it with skill/command call?
Experiment. The workflow is defined in .md files - add some extra instructions like "you MUST sync delta specs" etc - just explain the problem to AI and ask for prompt correction.
Does the init command not copy the opsx command and skills?
@gonefish No, it copied.
- added 7 commits that reference this issue
on Jun 29, 2026 - added a commit that references this issue
on Jun 29, 2026 Verified as resolved on current
main; this is ready to close. The archive workflow now makes a requested sync synchronous, verifies the resulting main specs, and refuses to archive if the sync did not actually land.Proof:
- The merged fix is fix(templates): don't archive a change before its spec sync finishes #1394 (
fix(templates): don't archive a change before its spec sync finishes): fix(templates): don't archive a change before its spec sync finishes #1394 - Current archive instructions require the sync to run inline and finish before the change is moved:
OpenSpec/src/core/templates/workflows/archive-change.ts
Lines 107 to 119 in 45cca5d
- "Sync now" or "Sync anyway" — sync, then verify (below) - Anything else — ask again rather than archiving Before a selected sync writes any main spec, run \`openspec instructions specs --change "<name>" --json\` once with the same selected-root flags. Require a zero exit status and valid artifact-instruction JSON. If the lookup fails or returns invalid JSON, report the error and stop before writing any main spec or moving the change. A valid response with omitted \`rules\` is the no-rules case. Apply returned \`rules\` only to the content and form of main specs produced by this merge; do not use them as archive guidance, change CLI behavior, or copy the rule text into any output file. Then run the \`openspec-sync-specs\` workflow inline (agent-driven intelligent merge) for change '<name>', passing the delta spec analysis and the fetched specs-rule snapshot from above, and wait for it to finish. The inline sync must reuse that snapshot without fetching \`specs\` instructions again. Do not delegate it to a background task — step 5 would move \`changeRoot\` out from under a sync that is still reading it, leaving the change archived and the main specs never updated. If your agent can only run it by delegation, delegate synchronously and wait for the result. - They then recompare every delta capability against the main specs and explicitly stop without archiving on any failure or mismatch:
OpenSpec/src/core/templates/workflows/archive-change.ts
Lines 120 to 130 in 45cca5d
Then re-run the comparison from the top of this step against every capability that has a delta spec in \`artifactPaths.specs.existingOutputPaths\` — not only the ones the sync reports it touched. A successful sync leaves nothing left to apply, so each capability must now read as already synced: - ADDED requirements present - MODIFIED requirements carrying the scenario and description changes named in the delta, with their other scenarios intact - REMOVED requirements gone - RENAMED requirements present under the new name and absent under the old one If the sync failed, or any capability does not match, report what differs and stop — do not archive. Nothing has moved and \`changeRoot\` is intact, so the user can fix the mismatch or re-run the sync and start the archive again. 5. **Perform the archive** - Regression coverage pins both the single-change and bulk-archive ordering/verification contracts:
OpenSpec/test/core/templates/skill-templates-parity.test.ts
Lines 223 to 275 in 45cca5d
it('gates the archive on a completed spec sync (#1393)', () => { const generatedSkill = generateSkillContent(getArchiveChangeSkillTemplate(), 'PARITY-BASELINE'); const commandContent = getOpsxArchiveCommandTemplate().content; // The single archive skill references openspec-sync-specs; opsx command references /opsx:sync. expect(generatedSkill, 'skill').toContain('run the `openspec-sync-specs` workflow inline'); expect(commandContent, 'opsx command').toContain('run the `/opsx:sync` workflow inline'); const variants: Array<[string, string]> = [ ['skill', generatedSkill], ['opsx command', commandContent], ]; for (const [variant, content] of variants) { expect(content, variant).toContain('Do not delegate it to a background task'); expect(content, variant).toContain('Never archive while a spec sync is still in flight'); // Verification must follow delta semantics. expect(content, variant).toContain('MODIFIED requirements carrying the scenario and description changes'); expect(content, variant).toContain('REMOVED requirements gone'); expect(content, variant).toContain('RENAMED requirements present under the new name and absent under the old one'); // Verification is bound to the delta specs on disk, not to whatever the sync reports it touched. expect(content, variant).toContain('not only the ones the sync reports it touched'); // Main spec paths are store-root aware expect(content, variant).toContain('<planningHome.root>/openspec/specs/<capability>/spec.md'); } }); it('gates bulk archive on inline synchronous spec sync and verification before moving change root', () => { const generatedSkill = generateSkillContent(getBulkArchiveChangeSkillTemplate(), 'PARITY-BASELINE'); const commandContent = getOpsxBulkArchiveCommandTemplate().content; // The bulk archive skill references openspec-sync-specs; opsx command references /opsx:sync. expect(generatedSkill, 'bulk skill').toContain('run the `openspec-sync-specs` workflow inline'); expect(commandContent, 'bulk opsx command').toContain('run the `/opsx:sync` workflow inline'); const variants: Array<[string, string]> = [ ['bulk skill', generatedSkill], ['bulk opsx command', commandContent], ]; for (const [variant, content] of variants) { expect(content, variant).toContain('Do not delegate to a background task'); expect(content, variant).toContain('Never archive a change while a spec sync is still in flight'); expect(content, variant).toContain('Verify included delta specs before moving changeRoot'); // Verification must follow delta semantics. expect(content, variant).toContain('MODIFIED requirements carrying scenario and description changes'); expect(content, variant).toContain('REMOVED requirements gone'); expect(content, variant).toContain('RENAMED requirements present under the new name and absent under the old one'); - I generated a fresh Claude/core installation from
main(45cca5db) and confirmed those synchronous-sync and post-sync-verification guardrails are present in the emittedopenspec-archive-change/SKILL.md. The focused init/profile/template/adapter suite passed all 1,167 tests.
The explicit “Archive without syncing” choice remains intentional; this fix covers the reported failure mode where a sync is selected/expected but archive completes before it is executed. The separate greenfield-main-spec discussion in #1222/#1264 remains open and is not being collapsed into this closure.
Thank you to everyone who supplied model/tool/version details; those reports are what made the missing synchronization barrier clear.
- The merged fix is fix(templates): don't archive a change before its spec sync finishes #1394 (