Skip to content

Commit b7f5a42

Browse files
authored
feat: add /opsx:archive command for archiving completed changes (#451)
Add `/opsx:archive` slash command to complete the OPSX workflow lifecycle. This command archives completed changes in the experimental workflow with: - Change selection prompt (if not specified) - Artifact completion check using `openspec status --json` - Task completion check (parsing tasks.md for `- [ ]`) - Spec sync prompt (offers `/opsx:sync` before archiving if specs exist) - Archive to `openspec/changes/archive/YYYY-MM-DD-<name>/` - Clear output formatting for success, warnings, and errors This completes the OPSX command suite: - /opsx:new - Start a change - /opsx:continue - Create next artifact - /opsx:ff - Fast-forward all artifacts - /opsx:apply - Implement tasks - /opsx:sync - Sync delta specs - /opsx:archive - Archive completed change (NEW)
1 parent a5c10ed commit b7f5a42

File tree

7 files changed

+523
-1
lines changed

7 files changed

+523
-1
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-01-07
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
## Context
2+
3+
The experimental workflow (OPSX) provides a complete lifecycle for creating changes:
4+
- `/opsx:new` - Scaffold a new change with schema
5+
- `/opsx:continue` - Create next artifact
6+
- `/opsx:ff` - Fast-forward all artifacts
7+
- `/opsx:apply` - Implement tasks
8+
- `/opsx:sync` - Sync delta specs to main
9+
10+
The missing piece is archiving. The existing `openspec archive` command works but:
11+
1. Applies specs programmatically (not agent-driven)
12+
2. Doesn't use the artifact graph for completion checking
13+
3. Doesn't integrate with the OPSX workflow philosophy
14+
15+
## Goals / Non-Goals
16+
17+
**Goals:**
18+
- Add `/opsx:archive` skill to complete the OPSX workflow lifecycle
19+
- Use artifact graph for schema-aware completion checking
20+
- Integrate with `/opsx:sync` for agent-driven spec syncing
21+
- Preserve `.openspec.yaml` schema metadata in archive
22+
23+
**Non-Goals:**
24+
- Replacing the existing `openspec archive` CLI command
25+
- Changing how specs are applied in the CLI command
26+
- Modifying the artifact graph or schema system
27+
28+
## Decisions
29+
30+
### Decision 1: Skill-only implementation (no new CLI command)
31+
32+
The `/opsx:archive` will be a slash command/skill only, not a new CLI command.
33+
34+
**Rationale**: The existing `openspec archive` CLI command already handles the core archive functionality (moving to archive folder, date prefixing). The OPSX version just needs different pre-archive checks and optional sync prompting, which are agent behaviors better suited to a skill.
35+
36+
**Alternatives considered**:
37+
- Adding flags to `openspec archive` (e.g., `--experimental`) - Rejected: adds complexity to CLI, harder to maintain two code paths
38+
- New CLI command `openspec archive-experimental` - Rejected: unnecessary duplication, agent skills are the OPSX pattern
39+
40+
### Decision 2: Prompt for sync before archive
41+
42+
The skill will check for unsynced delta specs and prompt the user before archiving.
43+
44+
**Rationale**: The OPSX philosophy is agent-driven intelligent merging via `/opsx:sync`. Rather than programmatically applying specs like the regular archive command, we prompt the user to sync first if needed. This maintains workflow flexibility (user can decline and just archive).
45+
46+
**Flow**:
47+
1. Check if `specs/` directory exists in the change
48+
2. If yes, ask: "This change has delta specs. Would you like to sync them to main specs before archiving?"
49+
3. If user says yes, execute `/opsx:sync` logic
50+
4. Proceed with archive regardless of answer
51+
52+
### Decision 3: Use artifact graph for completion checking
53+
54+
The skill will use `openspec status --change "<name>" --json` to check artifact completion instead of just validating proposal.md and specs.
55+
56+
**Rationale**: The experimental workflow is schema-aware. Different schemas have different required artifacts. The artifact graph knows which artifacts are complete/incomplete for the current schema.
57+
58+
**Behavior**:
59+
- Show warning if any artifacts are not `done`
60+
- Don't block archive (user may have valid reasons to archive early)
61+
- List incomplete artifacts so user can make informed decision
62+
63+
### Decision 4: Reuse tasks.md completion check from regular archive
64+
65+
The skill will parse tasks.md and warn about incomplete tasks, same as regular archive.
66+
67+
**Rationale**: Task completion checking is valuable regardless of workflow. The logic is simple (count `- [ ]` vs `- [x]`) and doesn't need special OPSX handling.
68+
69+
### Decision 5: Move change to archive/ with date prefix
70+
71+
Same archive behavior as regular command: move to `openspec/changes/archive/YYYY-MM-DD-<name>/`.
72+
73+
**Rationale**: Consistency with existing archive convention. The `.openspec.yaml` file moves with the change, preserving schema metadata.
74+
75+
## Risks / Trade-offs
76+
77+
**Risk**: Users confused about when to use `/opsx:archive` vs `openspec archive`
78+
**Mitigation**: Documentation should clarify: use `/opsx:archive` if you've been using the OPSX workflow, use `openspec archive` otherwise. Both produce the same archived result.
79+
80+
**Risk**: Incomplete sync if user declines and has delta specs
81+
**Mitigation**: The prompt is informational; user has full control. They may want to archive without syncing (e.g., abandoned change). Log a note in output.
82+
83+
**Trade-off**: No programmatic spec application in OPSX archive
84+
**Accepted**: This is intentional. OPSX philosophy is agent-driven merging. If user wants programmatic application, use `openspec archive` instead.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## Why
2+
3+
The experimental workflow (OPSX) provides a schema-driven, artifact-by-artifact approach to creating changes with `/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:apply`, and `/opsx:sync`. However, there's no corresponding archive command to finalize and archive completed changes. Users must currently fall back to the regular `openspec archive` command, which doesn't integrate with the OPSX philosophy of agent-driven spec syncing and schema-aware artifact tracking.
4+
5+
## What Changes
6+
7+
- Add `/opsx:archive` slash command for archiving changes in the experimental workflow
8+
- Use artifact graph to check completion status (schema-aware) instead of just validating proposal + specs
9+
- Prompt for `/opsx:sync` before archiving instead of programmatically applying specs
10+
- Preserve `.openspec.yaml` schema metadata when moving to archive
11+
- Integrate with existing OPSX commands for a cohesive workflow
12+
13+
## Capabilities
14+
15+
### New Capabilities
16+
17+
- `opsx-archive-skill`: Slash command and skill for archiving completed changes in the experimental workflow. Checks artifact completion via artifact graph, verifies task completion, optionally syncs specs via `/opsx:sync`, and moves the change to `archive/YYYY-MM-DD-<name>/`.
18+
19+
### Modified Capabilities
20+
21+
(none - this is a new skill that doesn't modify existing specs)
22+
23+
## Impact
24+
25+
- New file: `.claude/commands/opsx/archive.md`
26+
- New skill definition (generated via `openspec artifact-experimental-setup`)
27+
- No changes to existing archive command or other OPSX commands
28+
- Completes the OPSX command suite for full lifecycle management
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
## ADDED Requirements
2+
3+
### Requirement: OPSX Archive Skill
4+
5+
The system SHALL provide an `/opsx:archive` skill that archives completed changes in the experimental workflow.
6+
7+
#### Scenario: Archive a change with all artifacts complete
8+
9+
- **WHEN** agent executes `/opsx:archive` with a change name
10+
- **AND** all artifacts in the schema are complete
11+
- **AND** all tasks are complete
12+
- **THEN** the agent moves the change to `openspec/changes/archive/YYYY-MM-DD-<name>/`
13+
- **AND** displays success message with archived location
14+
15+
#### Scenario: Change selection prompt
16+
17+
- **WHEN** agent executes `/opsx:archive` without specifying a change
18+
- **THEN** the agent prompts user to select from available changes
19+
- **AND** shows only active changes (excludes archive/)
20+
21+
### Requirement: Artifact Completion Check
22+
23+
The skill SHALL check artifact completion status using the artifact graph before archiving.
24+
25+
#### Scenario: Incomplete artifacts warning
26+
27+
- **WHEN** agent checks artifact status
28+
- **AND** one or more artifacts have status other than `done`
29+
- **THEN** display warning listing incomplete artifacts
30+
- **AND** prompt user for confirmation to continue
31+
- **AND** proceed if user confirms
32+
33+
#### Scenario: All artifacts complete
34+
35+
- **WHEN** agent checks artifact status
36+
- **AND** all artifacts have status `done`
37+
- **THEN** proceed without warning
38+
39+
### Requirement: Task Completion Check
40+
41+
The skill SHALL check task completion status from tasks.md before archiving.
42+
43+
#### Scenario: Incomplete tasks found
44+
45+
- **WHEN** agent reads tasks.md
46+
- **AND** incomplete tasks are found (marked with `- [ ]`)
47+
- **THEN** display warning showing count of incomplete tasks
48+
- **AND** prompt user for confirmation to continue
49+
- **AND** proceed if user confirms
50+
51+
#### Scenario: All tasks complete
52+
53+
- **WHEN** agent reads tasks.md
54+
- **AND** all tasks are complete (marked with `- [x]`)
55+
- **THEN** proceed without task-related warning
56+
57+
#### Scenario: No tasks file
58+
59+
- **WHEN** tasks.md does not exist
60+
- **THEN** proceed without task-related warning
61+
62+
### Requirement: Spec Sync Prompt
63+
64+
The skill SHALL prompt to sync delta specs before archiving if specs exist.
65+
66+
#### Scenario: Delta specs exist
67+
68+
- **WHEN** agent checks for delta specs
69+
- **AND** `specs/` directory exists in the change with spec files
70+
- **THEN** prompt user: "This change has delta specs. Would you like to sync them to main specs before archiving?"
71+
- **AND** if user confirms, execute `/opsx:sync` logic
72+
- **AND** proceed with archive regardless of sync choice
73+
74+
#### Scenario: No delta specs
75+
76+
- **WHEN** agent checks for delta specs
77+
- **AND** no `specs/` directory or no spec files exist
78+
- **THEN** proceed without sync prompt
79+
80+
### Requirement: Archive Process
81+
82+
The skill SHALL move the change to the archive folder with date prefix.
83+
84+
#### Scenario: Successful archive
85+
86+
- **WHEN** archiving a change
87+
- **THEN** create `archive/` directory if it doesn't exist
88+
- **AND** generate target name as `YYYY-MM-DD-<change-name>` using current date
89+
- **AND** move entire change directory to archive location
90+
- **AND** preserve `.openspec.yaml` file in archived change
91+
92+
#### Scenario: Archive already exists
93+
94+
- **WHEN** target archive directory already exists
95+
- **THEN** fail with error message
96+
- **AND** suggest renaming existing archive or using different date
97+
98+
### Requirement: Skill Output
99+
100+
The skill SHALL provide clear feedback about the archive operation.
101+
102+
#### Scenario: Archive complete with sync
103+
104+
- **WHEN** archive completes after syncing specs
105+
- **THEN** display summary:
106+
- Specs synced (from `/opsx:sync` output)
107+
- Change archived to location
108+
- Schema that was used
109+
110+
#### Scenario: Archive complete without sync
111+
112+
- **WHEN** archive completes without syncing specs
113+
- **THEN** display summary:
114+
- Note that specs were not synced (if applicable)
115+
- Change archived to location
116+
- Schema that was used
117+
118+
#### Scenario: Archive complete with warnings
119+
120+
- **WHEN** archive completes with incomplete artifacts or tasks
121+
- **THEN** include note about what was incomplete
122+
- **AND** suggest reviewing if archive was intentional
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## 1. Create Slash Command
2+
3+
- [x] 1.1 Create `.claude/commands/opsx/archive.md` with skill definition
4+
- [x] 1.2 Add YAML frontmatter (name, description, category, tags)
5+
- [x] 1.3 Implement change selection logic (prompt if not provided)
6+
- [x] 1.4 Implement artifact completion check using `openspec status --json`
7+
- [x] 1.5 Implement task completion check (parse tasks.md for `- [ ]`)
8+
- [x] 1.6 Implement spec sync prompt (check for specs/ directory, offer `/opsx:sync`)
9+
- [x] 1.7 Implement archive process (move to archive/YYYY-MM-DD-<name>/)
10+
- [x] 1.8 Add output formatting for success/warning cases
11+
12+
## 2. Regenerate Skills
13+
14+
- [x] 2.1 Run `openspec artifact-experimental-setup` to regenerate skills
15+
- [x] 2.2 Verify skill appears in `.claude/skills/` directory
16+
17+
## 3. Testing
18+
19+
- [x] 3.1 Test `/opsx:archive` with a complete change (all artifacts, all tasks done)
20+
- [x] 3.2 Test `/opsx:archive` with incomplete artifacts (verify warning shown)
21+
- [x] 3.3 Test `/opsx:archive` with incomplete tasks (verify warning shown)
22+
- [x] 3.4 Test `/opsx:archive` with delta specs (verify sync prompt shown)
23+
- [x] 3.5 Test `/opsx:archive` without change name (verify selection prompt)

src/commands/artifact-workflow.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
type SchemaInfo,
2929
} from '../core/artifact-graph/index.js';
3030
import { createChange, validateChangeName } from '../utils/change-utils.js';
31-
import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getFfChangeSkillTemplate, getSyncSpecsSkillTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate, getOpsxFfCommandTemplate, getOpsxSyncCommandTemplate } from '../core/templates/skill-templates.js';
31+
import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getFfChangeSkillTemplate, getSyncSpecsSkillTemplate, getArchiveChangeSkillTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate, getOpsxFfCommandTemplate, getOpsxSyncCommandTemplate, getOpsxArchiveCommandTemplate } from '../core/templates/skill-templates.js';
3232
import { FileSystemUtils } from '../utils/file-system.js';
3333

3434
// -----------------------------------------------------------------------------
@@ -798,13 +798,15 @@ async function artifactExperimentalSetupCommand(): Promise<void> {
798798
const applyChangeSkill = getApplyChangeSkillTemplate();
799799
const ffChangeSkill = getFfChangeSkillTemplate();
800800
const syncSpecsSkill = getSyncSpecsSkillTemplate();
801+
const archiveChangeSkill = getArchiveChangeSkillTemplate();
801802

802803
// Get command templates
803804
const newCommand = getOpsxNewCommandTemplate();
804805
const continueCommand = getOpsxContinueCommandTemplate();
805806
const applyCommand = getOpsxApplyCommandTemplate();
806807
const ffCommand = getOpsxFfCommandTemplate();
807808
const syncCommand = getOpsxSyncCommandTemplate();
809+
const archiveCommand = getOpsxArchiveCommandTemplate();
808810

809811
// Create skill directories and SKILL.md files
810812
const skills = [
@@ -813,6 +815,7 @@ async function artifactExperimentalSetupCommand(): Promise<void> {
813815
{ template: applyChangeSkill, dirName: 'openspec-apply-change' },
814816
{ template: ffChangeSkill, dirName: 'openspec-ff-change' },
815817
{ template: syncSpecsSkill, dirName: 'openspec-sync-specs' },
818+
{ template: archiveChangeSkill, dirName: 'openspec-archive-change' },
816819
];
817820

818821
const createdSkillFiles: string[] = [];
@@ -842,6 +845,7 @@ ${template.instructions}
842845
{ template: applyCommand, fileName: 'apply.md' },
843846
{ template: ffCommand, fileName: 'ff.md' },
844847
{ template: syncCommand, fileName: 'sync.md' },
848+
{ template: archiveCommand, fileName: 'archive.md' },
845849
];
846850

847851
const createdCommandFiles: string[] = [];
@@ -899,6 +903,7 @@ ${template.content}
899903
console.log(' • /opsx:apply - Implement tasks');
900904
console.log(' • /opsx:ff - Fast-forward: create all artifacts at once');
901905
console.log(' • /opsx:sync - Sync delta specs to main specs');
906+
console.log(' • /opsx:archive - Archive a completed change');
902907
console.log();
903908
console.log(chalk.yellow('💡 This is an experimental feature.'));
904909
console.log(' Feedback welcome at: https://github.com/Fission-AI/OpenSpec/issues');

0 commit comments

Comments
 (0)