Skip to content

open:sync messed up my spec.md files #911

Closed

Description

@HowardYan888

Hey folks,

I'm a bit confused about open:sync and hoping someone can shed some light.

I ran open:sync the other day, and now my spec.md files look different from what I expected. It's like they're not fully synced, or something got changed unexpectedly.

My main questions are:

Why did this happen? What usually causes spec.md to be different after open:sync? Is it something I'm doing wrong, or is there a common scenario for this?
How do I fix it? If my spec.md is now weird, what's the best way to get it back to normal without losing my work? Are there any commands to help me see the differences or merge them?
How can I avoid this in the future? Any tips or best practices for using open:sync with Git (like when to commit, when to run sync) so this doesn't happen again?

Activity

  1. 21st-connector commented on Apr 3, 2026

    @21st-connector
    Contributor

    Task completed.

    I'll analyze this issue by exploring the codebase to understand how open:sync works and what could cause spec.md files to be modified unexpectedly.


    View full conversation

    Powered by 1Code

  2. 21st-connector commented on Apr 3, 2026

    @21st-connector
    Contributor

    Issue Triage: open:sync and spec.md behavior

    Thanks for reporting this. Here's a breakdown of what's happening and how to address each of your questions.


    Why did this happen?

    /opsx:sync merges delta specs (from openspec/changes/<change-name>/specs/*/spec.md) into your main specs (at openspec/specs/*/spec.md). The key behavior that likely surprised you:

    • MODIFIED operations replace entire requirement blocks — they don't do a fine-grained merge. If your delta spec has a ## MODIFIED Requirements section, the entire requirement body in the main spec gets replaced with the delta version (src/core/specs-apply.ts:272-286).
    • Ordering may change — after sync, requirements are recomposed in a specific order (RENAMED first, then REMOVED, MODIFIED, ADDED), which can rearrange the output compared to what you had before.
    • No conflict detection for parallel changes — if you had multiple changes touching the same spec, the second sync silently overwrites what the first one wrote. This is a known limitation with planned improvements.

    Common scenarios that cause unexpected results:

    Scenario What happens
    Delta has MODIFIED section Entire requirement block is replaced, not merged
    Multiple changes target the same spec Later sync overwrites earlier one
    Delta was written against an older version of the spec New content from other changes can be lost

    How to fix it

    1. Check what changed — use git diff on your openspec/specs/ directory to see exactly what sync modified:

      git diff openspec/specs/
      
    2. Revert if needed — if you committed before syncing, you can restore the previous version:

      git checkout HEAD -- openspec/specs/
      
    3. Re-sync selectively — after reverting, you can run /opsx:sync <change-name> targeting a specific change, then review the diff before committing.

    4. Validate specs — run /opsx:status to check if your specs are still structurally valid.


    How to avoid this in the future

    Per the command documentation:

    • Commit before syncing — always commit (or stash) your current state so you can revert if the merge isn't what you expect.
    • You often don't need to call sync directly — the archive command prompts for sync if needed. Most users never need to run /opsx:sync manually (docs/commands.md:388).
    • Review the diff after sync — run git diff immediately after sync to verify the changes look correct before committing.
    • One change at a time for the same spec — if two changes target the same spec, archive the first before syncing the second. Parallel changes to the same spec are a known source of silent overwrites.
    • Use sync for preview — sync is useful when you want to preview what the merge looks like before archiving (docs/commands.md:432).

    Related issues

    Relevant code and docs

    Resource Path
    Sync merge logic src/core/specs-apply.ts
    Delta spec parsing src/core/parsers/requirement-blocks.ts
    /opsx:sync command docs docs/commands.md#L386-L440
    Delta specs concept docs/concepts.md#L346-L405
    Parallel merge plan (known limitations) openspec-parallel-merge-plan.md
    Sync workflow template src/core/templates/workflows/sync-specs.ts
  3. TabishB commented on Apr 7, 2026

    @TabishB
    Contributor

    How do I fix it? If my spec.md is now weird, what's the best way to get it back to normal without losing my work? Are there any commands to help me see the differences or merge them?

    You don't need special commands! The beauty of LLM's is you can just ask the model to go and fix it, you can literally prompt it to say "hey can you check if this is now wrong, if so what would the fix be?"

    Why did this happen? What usually causes spec.md to be different after open:sync? Is it something I'm doing wrong, or is there a common scenario for this?

    I would need more details here. Can you maybe retrieve the agent session to give more info?

    sync looks at your current change proposal and tries to sync it to the source of truth specs manually.

    But hard to say without a proper agent trace.

  4. nagoodman commented on May 12, 2026

    @nagoodman

    I think I have your root cause. Hit this in our project after using /opsx:archive (which calls the same openspec-sync-specs skill under the hood) since Feb 2026.

    Ran openspec validate --specs against our repo's state immediately after every archive commit:

    Archive commit Passing / Failing
    First archive (Feb 2026) 0 / 5
    Subsequent archives ~23 / ~22 (consistent)
    After manual cleanup of all specs 47 / 0

    Every main spec touched by sync-specs has failed validation since day one. The files weren't being "messed up" by some intermittent bug — the skill produces invalid output on every run, and there's no validation step in the archive workflow to catch it.

    Two specific defects in openspec-sync-specs (dist/core/templates/workflows/sync-specs.js) account for nearly all failures:

    1. Delta header leaks through. Delta specs use ## ADDED Requirements; main specs require ## Requirements. The skill instructions tell the agent to "apply changes intelligently" but never say to rewrite the header when writing into a main spec. The format reference and example output (lines 73–124, 248–262) show the delta header verbatim with no normalization. Result: ## ADDED Requirements ends up in your main spec.md and the validator rejects it.

    2. ## Purpose is only added on the "new spec" branch. Step 3d says to add Purpose when creating a brand-new main spec, but the much more common "main spec already exists, append new requirements" path never mentions Purpose. So existing specs that get touched lose/never gain a Purpose section.

    And openspec-archive-change has no validation step, so the broken output ships silently. Adding openspec validate --specs to the end of the archive workflow would have caught this on the very first run.

    How to recover your specs:

    openspec validate --specs

    That will list every main spec that's currently invalid, with the specific defect. In our repo it took one commit to hand-fix: change ## ADDED Requirements → ## Requirements, add a ## Purpose section if missing, and replace any non-RFC2119 wording (lowercase must, requires, by default is) with SHALL/MUST/SHOULD.

    To avoid this in the future: run openspec validate --specs after every /opsx:sync or /opsx:archive, and revert + hand-merge if it fails. Until the upstream skill templates are fixed, there's no way to make the agent-driven sync produce valid output reliably.

    Related canonical issue: #863 (covers the underlying "archive skill doesn't invoke openspec archive CLI, re-implements it manually without validation" architecture problem). #656 is the original ask.

  5. clay-good commented on Aug 5, 2026

    @clay-good
    Collaborator

    The concrete cause here — the sync skill leaving delta operation headers (## ADDED Requirements) in your main specs and dropping the ## Purpose section, producing invalid spec.md files — is fixed on main. The openspec-sync-specs workflow now normalizes deltas into a single ## Requirements section, carries the delta's ## Purpose over verbatim, and runs openspec validate --specs at the end so bad output is caught immediately (src/core/templates/workflows/sync-specs.ts; #1402, #1431, #1500).

    To recover an already-affected spec: run openspec validate --specs to see each defect, then either git checkout HEAD -- openspec/specs/ and re-sync, or hand-fix the flagged headers/Purpose. Closing as resolved on current versions — please reopen if a fresh sync still corrupts a spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-infoAwaiting more info from reporter

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions