-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat: add /opsx:sync command for syncing delta specs to main specs #450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-01-06 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| ## Context | ||
|
|
||
| Currently, delta specs are only applied to main specs when running `openspec archive`. This bundles two concerns: | ||
| 1. Applying spec changes (delta → main) | ||
| 2. Archiving the change (move to archive folder) | ||
|
|
||
| Users want flexibility to apply specs earlier, especially when iterating. The archive command already contains the reconciliation logic in `buildUpdatedSpec()`. | ||
|
|
||
| ## Goals / Non-Goals | ||
|
|
||
| **Goals:** | ||
| - Decouple spec application from archiving | ||
| - Provide `/opsx:specs` skill for agents to apply specs on demand | ||
| - Add `openspec specs apply` CLI command for direct invocation | ||
| - Keep operation idempotent (safe to run multiple times) | ||
|
|
||
| **Non-Goals:** | ||
| - Tracking whether specs have been applied (no state) | ||
| - Changing archive behavior (it will continue to apply specs) | ||
| - Supporting partial application (all deltas apply together) | ||
|
|
||
| ## Decisions | ||
|
|
||
| ### 1. Reuse existing reconciliation logic | ||
|
|
||
| **Decision**: Extract `buildUpdatedSpec()` logic from `ArchiveCommand` into a shared module. | ||
|
|
||
| **Rationale**: The archive command already implements delta parsing and application. Rather than duplicate, we extract and reuse. | ||
|
|
||
| **Alternatives considered**: | ||
| - Duplicate logic in new command (rejected: maintenance burden) | ||
| - Have specs apply call archive with flags (rejected: coupling) | ||
|
|
||
| ### 2. No state tracking | ||
|
|
||
| **Decision**: Don't track whether specs have been applied. Each invocation reads delta and main specs, reconciles. | ||
|
|
||
| **Rationale**: | ||
| - Idempotent operations don't need state | ||
| - Avoids sync issues between flag and reality | ||
| - Simpler implementation and mental model | ||
|
|
||
| **Alternatives considered**: | ||
| - Track `specsApplied: true` in `.openspec.yaml` (rejected: unnecessary complexity) | ||
| - Store snapshot of applied deltas (rejected: over-engineering) | ||
|
|
||
| ### 3. Agent-driven for skill, CLI for direct use | ||
|
|
||
| **Decision**: | ||
| - Skill (`/opsx:specs`) instructs agent to use CLI command | ||
| - CLI command (`openspec specs apply`) does the actual work | ||
|
|
||
| **Rationale**: Consistent with other opsx skills. CLI provides the capability, skill provides the agent workflow. | ||
|
|
||
| ### 4. Archive behavior unchanged | ||
|
|
||
| **Decision**: Archive continues to apply specs as part of its flow. If specs are already reconciled, the operation is a no-op. | ||
|
|
||
| **Rationale**: Backward compatibility. Users who don't use `/opsx:specs` get the same experience. | ||
|
|
||
| ## Risks / Trade-offs | ||
|
|
||
| **[Risk] Multiple changes modify same spec** | ||
| → Last to apply wins. Same as today with archive. Users should coordinate or use sequential archives. | ||
|
|
||
| **[Risk] User applies specs then continues editing deltas** | ||
| → Running `/opsx:specs` again reconciles. Idempotent design handles this. | ||
|
|
||
| **[Trade-off] No undo mechanism** | ||
| → Users can `git checkout` main specs if needed. Explicit undo command is out of scope. | ||
|
|
||
| ## Implementation Approach | ||
|
|
||
| 1. Extract spec application logic from `ArchiveCommand.buildUpdatedSpec()` into `src/core/specs-apply.ts` | ||
| 2. Create `openspec specs apply` command that uses extracted logic | ||
| 3. Add skill template for `/opsx:specs` in `skill-templates.ts` | ||
| 4. Register skill in managed skills |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| ## Why | ||
|
|
||
| Spec application is currently bundled with archive - users must run `openspec archive` to apply delta specs to main specs. This couples two distinct concerns (applying specs vs. archiving the change) and forces users to wait until they're "done" to see main specs updated. Users want the flexibility to apply specs earlier in the workflow while iterating. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - Add `/opsx:specs` skill that applies delta specs to main specs as a standalone action | ||
| - The operation is idempotent - safe to run multiple times, agent reconciles main specs to match deltas | ||
| - Archive continues to work as today (applies specs if not already reconciled, then moves to archive) | ||
| - No new state tracking - the agent reads delta and main specs, reconciles on each run | ||
|
|
||
| **Workflow becomes:** | ||
| ``` | ||
| /opsx:new → /opsx:continue → /opsx:apply → archive | ||
| │ | ||
| └── /opsx:specs (optional, anytime) | ||
| ``` | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### New Capabilities | ||
| - `specs-apply-skill`: Skill template for `/opsx:specs` command that reconciles main specs with delta specs | ||
|
|
||
| ### Modified Capabilities | ||
| - `cli-artifact-workflow`: Add `openspec specs apply --change <name>` CLI command to support the skill | ||
|
|
||
| ## Impact | ||
|
|
||
| - **Skills**: New `openspec-specs-apply` skill in `skill-templates.ts` | ||
| - **CLI**: New `specs apply` subcommand in artifact workflow commands | ||
| - **Archive**: No changes needed - already does reconciliation, will continue to work | ||
| - **Agent workflow**: Users gain flexibility to apply specs before archive | ||
29 changes: 29 additions & 0 deletions
29
openspec/changes/add-specs-apply-command/specs/cli-artifact-workflow/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Specs Apply Command | ||
| The system SHALL provide a `specs apply` subcommand for applying delta specs to main specs. | ||
|
|
||
| #### Scenario: Apply specs for a change | ||
| - **WHEN** user runs `openspec specs apply --change <name>` | ||
| - **THEN** the system applies delta specs from the change to main specs | ||
| - **AND** displays a summary of changes made | ||
|
|
||
| #### Scenario: JSON output | ||
| - **WHEN** user runs `openspec specs apply --change <name> --json` | ||
| - **THEN** the system outputs JSON with: | ||
| - `changeName`: the change being applied | ||
| - `capabilities`: array of affected capabilities with counts | ||
| - `totals`: aggregate counts of added/modified/removed/renamed | ||
|
|
||
| #### Scenario: Missing change parameter | ||
| - **WHEN** user runs `openspec specs apply` without `--change` | ||
| - **THEN** the system displays an error with list of available changes | ||
|
|
||
| #### Scenario: Change has no delta specs | ||
| - **WHEN** user runs `openspec specs apply --change <name>` | ||
| - **AND** the change has no `specs/` directory or no delta spec files | ||
| - **THEN** the system displays "No delta specs found for change <name>" | ||
|
|
||
| #### Scenario: Dry run mode | ||
| - **WHEN** user runs `openspec specs apply --change <name> --dry-run` | ||
| - **THEN** the system shows what would be changed without writing files |
67 changes: 67 additions & 0 deletions
67
openspec/changes/add-specs-apply-command/specs/specs-apply-skill/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Specs Apply Skill | ||
| The system SHALL provide an `/opsx:specs` skill that applies delta specs from a change to the main specs. | ||
|
|
||
| #### Scenario: Apply delta specs to main specs | ||
| - **WHEN** agent executes `/opsx:specs` with a change name | ||
| - **THEN** the agent reads delta specs from `openspec/changes/<name>/specs/` | ||
| - **AND** reads corresponding main specs from `openspec/specs/` | ||
| - **AND** reconciles main specs to match what the deltas describe | ||
|
|
||
| #### Scenario: Idempotent operation | ||
| - **WHEN** agent executes `/opsx:specs` multiple times on the same change | ||
| - **THEN** the result is the same as running it once | ||
| - **AND** no duplicate requirements are created | ||
|
|
||
| #### Scenario: Change selection prompt | ||
| - **WHEN** agent executes `/opsx:specs` without specifying a change | ||
| - **THEN** the agent prompts user to select from available changes | ||
| - **AND** shows changes that have delta specs | ||
|
|
||
| ### Requirement: Delta Reconciliation Logic | ||
| The agent SHALL reconcile main specs with delta specs using the delta operation headers. | ||
|
|
||
| #### Scenario: ADDED requirements | ||
| - **WHEN** delta contains `## ADDED Requirements` with a requirement | ||
| - **AND** the requirement does not exist in main spec | ||
| - **THEN** add the requirement to main spec | ||
|
|
||
| #### Scenario: ADDED requirement already exists | ||
| - **WHEN** delta contains `## ADDED Requirements` with a requirement | ||
| - **AND** a requirement with the same name already exists in main spec | ||
| - **THEN** update the existing requirement to match the delta version | ||
|
|
||
| #### Scenario: MODIFIED requirements | ||
| - **WHEN** delta contains `## MODIFIED Requirements` with a requirement | ||
| - **AND** the requirement exists in main spec | ||
| - **THEN** replace the requirement in main spec with the delta version | ||
|
|
||
| #### Scenario: REMOVED requirements | ||
| - **WHEN** delta contains `## REMOVED Requirements` with a requirement name | ||
| - **AND** the requirement exists in main spec | ||
| - **THEN** remove the requirement from main spec | ||
|
|
||
| #### Scenario: RENAMED requirements | ||
| - **WHEN** delta contains `## RENAMED Requirements` with FROM:/TO: format | ||
| - **AND** the FROM requirement exists in main spec | ||
| - **THEN** rename the requirement to the TO name | ||
|
|
||
| #### Scenario: New capability spec | ||
| - **WHEN** delta spec exists for a capability not in main specs | ||
| - **THEN** create new main spec file at `openspec/specs/<capability>/spec.md` | ||
|
|
||
| ### Requirement: Skill Output | ||
| The skill SHALL provide clear feedback on what was applied. | ||
|
|
||
| #### Scenario: Show applied changes | ||
| - **WHEN** reconciliation completes successfully | ||
| - **THEN** display summary of changes per capability: | ||
| - Number of requirements added | ||
| - Number of requirements modified | ||
| - Number of requirements removed | ||
| - Number of requirements renamed | ||
|
|
||
| #### Scenario: No changes needed | ||
| - **WHEN** main specs already match delta specs | ||
| - **THEN** display "Specs already in sync - no changes needed" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| ## Tasks | ||
|
|
||
| ### Core Implementation | ||
|
|
||
| - [x] Extract spec application logic from `ArchiveCommand` into `src/core/specs-apply.ts` | ||
| - Move `buildUpdatedSpec()`, `findSpecUpdates()`, `writeUpdatedSpec()` to shared module | ||
| - Keep `ArchiveCommand` importing from the new module | ||
| - Ensure all validation logic is preserved | ||
|
|
||
| - [x] ~~Create `openspec specs apply` CLI command~~ → Changed to agent-driven approach | ||
| - Removed CLI command - skill is now agent-driven | ||
| - Agent reads delta specs and directly edits main specs | ||
| - Allows intelligent merging (add scenarios without copying entire requirements) | ||
|
|
||
| ### Skill Template | ||
|
|
||
| - [x] Add `getSpecsApplySkillTemplate()` function in `src/core/templates/skill-templates.ts` | ||
| - Skill name: `openspec-specs-apply` | ||
| - Description: Apply delta specs to main specs | ||
| - **Agent-driven**: Instructions for agent to read deltas and edit main specs directly | ||
|
|
||
| - [x] Add `/opsx:specs` slash command template in `skill-templates.ts` | ||
| - Mirror the skill template for slash command format | ||
| - **Agent-driven**: No CLI command, agent does the merge | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Registration | ||
|
|
||
| - [x] Register skill in managed skills (via `artifact-experimental-setup`) | ||
| - Add to skill list with appropriate metadata | ||
| - Ensure it appears in setup output | ||
|
|
||
| ### Design Decision | ||
|
|
||
| **Why agent-driven instead of CLI-driven?** | ||
|
|
||
| The programmatic merge operates at requirement-level granularity: | ||
| - MODIFIED requires copying ALL scenarios, not just the changed ones | ||
| - If agent forgets a scenario, it gets deleted | ||
| - Delta specs become bloated with copied content | ||
|
|
||
| Agent-driven approach: | ||
| - Agent can apply partial updates (add a scenario without copying others) | ||
| - Delta represents *intent*, not wholesale replacement | ||
| - More flexible and natural editing workflow | ||
| - Archive still uses programmatic merge (for finalized changes) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| # specs-sync-skill Specification | ||
|
|
||
| ## Purpose | ||
| Defines the agent skill for syncing delta specs from changes to main specs. | ||
|
|
||
| ## Requirements | ||
|
|
||
| ### Requirement: Specs Sync Skill | ||
| The system SHALL provide an `/opsx:sync` skill that syncs delta specs from a change to the main specs. | ||
|
|
||
| #### Scenario: Sync delta specs to main specs | ||
| - **WHEN** agent executes `/opsx:sync` with a change name | ||
| - **THEN** the agent reads delta specs from `openspec/changes/<name>/specs/` | ||
| - **AND** reads corresponding main specs from `openspec/specs/` | ||
| - **AND** reconciles main specs to match what the deltas describe | ||
|
|
||
| #### Scenario: Idempotent operation | ||
| - **WHEN** agent executes `/opsx:sync` multiple times on the same change | ||
| - **THEN** the result is the same as running it once | ||
| - **AND** no duplicate requirements are created | ||
|
|
||
| #### Scenario: Change selection prompt | ||
| - **WHEN** agent executes `/opsx:sync` without specifying a change | ||
| - **THEN** the agent prompts user to select from available changes | ||
| - **AND** shows changes that have delta specs | ||
|
|
||
| ### Requirement: Delta Reconciliation Logic | ||
| The agent SHALL reconcile main specs with delta specs using the delta operation headers. | ||
|
|
||
| #### Scenario: ADDED requirements | ||
| - **WHEN** delta contains `## ADDED Requirements` with a requirement | ||
| - **AND** the requirement does not exist in main spec | ||
| - **THEN** add the requirement to main spec | ||
|
|
||
| #### Scenario: ADDED requirement already exists | ||
| - **WHEN** delta contains `## ADDED Requirements` with a requirement | ||
| - **AND** a requirement with the same name already exists in main spec | ||
| - **THEN** update the existing requirement to match the delta version | ||
|
|
||
| #### Scenario: MODIFIED requirements | ||
| - **WHEN** delta contains `## MODIFIED Requirements` with a requirement | ||
| - **AND** the requirement exists in main spec | ||
| - **THEN** replace the requirement in main spec with the delta version | ||
|
|
||
| #### Scenario: REMOVED requirements | ||
| - **WHEN** delta contains `## REMOVED Requirements` with a requirement name | ||
| - **AND** the requirement exists in main spec | ||
| - **THEN** remove the requirement from main spec | ||
|
|
||
| #### Scenario: RENAMED requirements | ||
| - **WHEN** delta contains `## RENAMED Requirements` with FROM:/TO: format | ||
| - **AND** the FROM requirement exists in main spec | ||
| - **THEN** rename the requirement to the TO name | ||
|
|
||
| #### Scenario: New capability spec | ||
| - **WHEN** delta spec exists for a capability not in main specs | ||
| - **THEN** create new main spec file at `openspec/specs/<capability>/spec.md` | ||
|
|
||
| ### Requirement: Skill Output | ||
| The skill SHALL provide clear feedback on what was applied. | ||
|
|
||
| #### Scenario: Show applied changes | ||
| - **WHEN** reconciliation completes successfully | ||
| - **THEN** display summary of changes per capability: | ||
| - Number of requirements added | ||
| - Number of requirements modified | ||
| - Number of requirements removed | ||
| - Number of requirements renamed | ||
|
|
||
| #### Scenario: No changes needed | ||
| - **WHEN** main specs already match delta specs | ||
| - **THEN** display "Specs already in sync - no changes needed" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.