- Active changes apply requirement-level replacements when archiving. When two changes touch the same requirement, the second archive overwrites the first and silently drops scenarios (e.g., Windsurf vs. Kilo Code slash command updates).
- The archive workflow (
src/core/archive.ts:191andsrc/core/archive.ts:501) rebuilds main specs by replacing entire requirement blocks with the content contained in the change delta. The delta format (src/core/parsers/requirement-blocks.ts:113) has no notion of base versions or scenario-level operations. - The tooling cannot detect divergence between the change author’s starting point and the live spec, so parallel development corrupts the source of truth without warning.
- Change A (
add-windsurf-workflows) adds a Windsurf scenario underSlash Command Configuration. - Change B (
add-kilocode-workflows) adds a Kilo Code scenario to the same requirement, starting from the pre-Windsurf spec. - After Change A archives, the main spec contains both scenarios.
- When Change B archives,
buildUpdatedSpecsees aMODIFIEDblock forSlash Command Configurationand replaces the requirement with the four-scenario variant shipped in that change. Because that file never learned about Windsurf, the Windsurf scenario disappears. - There is no warning, diff, or conflict indicator—the archive completes successfully, and the source-of-truth spec now omits a shipped scenario.
- Replace-only semantics.
buildUpdatedSpecperforms hash-map substitution of requirement blocks and cannot merge or compare individual scenarios (src/core/archive.ts:455-src/core/archive.ts:526). - Missing base fingerprint. Changes do not persist the requirement content they were authored against, so the archive step cannot tell if the live spec diverged.
- Single-level granularity. The delta language only understands requirements. Even if we introduced scenario-level parsing, we would still lose sibling edits without an accompanying merge strategy.
- Lack of conflict UX. The CLI never forces contributors to reconcile parallel updates. There is no equivalent of
git merge,git rebase, or conflict markers.
- Preserve every approved scenario regardless of archive order.
- Detect and block speculative archives when the live spec diverges from the author’s base.
- Provide a deterministic, reviewable conflict resolution flow that mirrors source-control best practices.
- Keep the authoring experience ergonomic: deltas should remain human-editable markdown.
- Support incremental adoption so existing repositories can roll forward without breaking active work.
- Persist requirement fingerprints alongside each change.
- When scaffolding or validating a change, capture the current requirement body for every
MODIFIED/REMOVED/RENAMEDentry and write it tochanges/<id>/meta.json. - Store a stable hash (e.g., SHA-256) of the base requirement content and the raw text itself for later merges.
- When scaffolding or validating a change, capture the current requirement body for every
- Validate fingerprints during archive.
- Before
buildUpdatedSpecmutates specs, recompute the requirement hash from the live spec. - If the hash differs from the stored base, abort and instruct the user to rebase. This makes the destructive path impossible.
- Before
- Surface intent in CLI output.
- Show which requirements are stale, when they diverged, and which change last touched them.
- Document interim manual mitigation.
- Update
openspec/AGENTS.mdand docs so contributors know to rerunopenspec change sync(see Phase 1) whenever another change lands.
- Update
Outcome: We prevent data loss immediately while we work on a richer merge story.
- Introduce
openspec change sync <id>(orrebase).- Reads the stored base snapshot, the current spec, and the author’s delta.
- Performs a 3-way merge per requirement. A naive diff3 on markdown lines is acceptable initially because we already operate on requirement-sized chunks.
- If the merge is clean, rewrite the
MODIFIEDblock with the merged text and refresh the stored fingerprint. - On conflict, write conflict markers inside the change delta (similar to Git) and require the author to hand-edit before re-running validation.
- Enrich validator messages.
openspec validateshould flag unresolved conflict markers or fingerprint mismatches so errors appear early in the workflow.
- Optional: Offer a
--rewrite-scenarioshelper that merges bullet lists of scenarios to reduce manual editing noise.
Outcome: Contributors can safely reconcile their work with the latest spec before archiving, restoring true parallel development.
- Extend the delta language with scenario-level directives.
- Allow
## MODIFIED Requirements+## ADDED Scenarios/## MODIFIED Scenariossections nested under the requirement header. - Backed by stable scenario identifiers (explicit IDs or generated hashes) stored in
meta.json. This lets the system reason about individual scenarios.
- Allow
- Teach the parser to understand nested operations.
- Update
parseDeltaSpecto emit scenario-level operations in addition to requirement blocks. - Update
buildUpdatedSpec(or its replacement) to merge scenario lists, preserving order while inserting new entries in a deterministic fashion.
- Update
- Automate migration.
- Provide a one-time command that inspects each existing spec, injects scenario IDs, and rewrites in-flight change deltas into the richer format.
- Continue to rely on the Phase 1 rebase flow for conflicts when two changes edit the same scenario body or description.
Outcome: Most concurrent updates become commutative, drastically reducing the odds of human merges.
- Define stable requirement IDs.
- Embed
Requirement ID: <uuid>markers in specs so renames and moves are trackable. - This enables future features like cross-capability references and better diff visualizations.
- Embed
- Model spec edits as operations over an AST.
- Build an intermediate representation (IR) for requirements/scenarios/metadata.
- Use operational transforms or CRDT-like techniques to guarantee merge associativity.
- Integrate with Git directly.
- Offer optional
openspec branchscaffolding that aligns spec changes with Git branches, letting teams leverage Git’s conflict editor for the markdown IR.
- Offer optional
Outcome: OpenSpec graduates from replace-based updates to a resilient, intent-preserving spec management platform.
- Backfill metadata: add hashes for all active changes and the current main specs during the initial rollout.
- CLI UX: new commands (
change sync, enhancedarchive) require documentation, help text, and release notes. - Docs & AGENTS updates: reinforce the rebase workflow and explain conflict resolution to AI assistants.
- Testing: introduce fixtures covering divergent requirement fingerprints and merge resolution logic.
- Telemetry (optional): log fingerprint mismatches so we can see how often teams hit conflicts after the rollout.
- How should we order scenarios when multiple changes insert at different points? (Consider optional
positionmetadata or deterministic alphabetical fallbacks.) - What is the graceful failure mode if contributors delete the
meta.jsonfile? (CLI should recreate fingerprints on demand.) - Do we need to support offline authors who cannot easily re-run the sync command before archiving? (Potential
--accept-outdatedescape hatch for emergencies.) - How will archived historical changes be handled? We may need a migration script to embed fingerprints retroactively so re-validation succeeds.
- Prototype fingerprint capture during
openspec change validateand block archive on mismatches. - Ship
openspec change syncwith line-based diff3 merging and conflict markers. - Update contributor docs and AI instructions to mandate running
syncbefore archiving. - Plan the scenario-level delta extension and migration path as a follow-up RFC.