diff --git a/openspec/changes/opsx-archive-command/.openspec.yaml b/openspec/changes/opsx-archive-command/.openspec.yaml new file mode 100644 index 000000000..75b7b3e31 --- /dev/null +++ b/openspec/changes/opsx-archive-command/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-01-07 diff --git a/openspec/changes/opsx-archive-command/design.md b/openspec/changes/opsx-archive-command/design.md new file mode 100644 index 000000000..7e01aea7c --- /dev/null +++ b/openspec/changes/opsx-archive-command/design.md @@ -0,0 +1,84 @@ +## Context + +The experimental workflow (OPSX) provides a complete lifecycle for creating changes: +- `/opsx:new` - Scaffold a new change with schema +- `/opsx:continue` - Create next artifact +- `/opsx:ff` - Fast-forward all artifacts +- `/opsx:apply` - Implement tasks +- `/opsx:sync` - Sync delta specs to main + +The missing piece is archiving. The existing `openspec archive` command works but: +1. Applies specs programmatically (not agent-driven) +2. Doesn't use the artifact graph for completion checking +3. Doesn't integrate with the OPSX workflow philosophy + +## Goals / Non-Goals + +**Goals:** +- Add `/opsx:archive` skill to complete the OPSX workflow lifecycle +- Use artifact graph for schema-aware completion checking +- Integrate with `/opsx:sync` for agent-driven spec syncing +- Preserve `.openspec.yaml` schema metadata in archive + +**Non-Goals:** +- Replacing the existing `openspec archive` CLI command +- Changing how specs are applied in the CLI command +- Modifying the artifact graph or schema system + +## Decisions + +### Decision 1: Skill-only implementation (no new CLI command) + +The `/opsx:archive` will be a slash command/skill only, not a new CLI command. + +**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. + +**Alternatives considered**: +- Adding flags to `openspec archive` (e.g., `--experimental`) - Rejected: adds complexity to CLI, harder to maintain two code paths +- New CLI command `openspec archive-experimental` - Rejected: unnecessary duplication, agent skills are the OPSX pattern + +### Decision 2: Prompt for sync before archive + +The skill will check for unsynced delta specs and prompt the user before archiving. + +**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). + +**Flow**: +1. Check if `specs/` directory exists in the change +2. If yes, ask: "This change has delta specs. Would you like to sync them to main specs before archiving?" +3. If user says yes, execute `/opsx:sync` logic +4. Proceed with archive regardless of answer + +### Decision 3: Use artifact graph for completion checking + +The skill will use `openspec status --change "" --json` to check artifact completion instead of just validating proposal.md and specs. + +**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. + +**Behavior**: +- Show warning if any artifacts are not `done` +- Don't block archive (user may have valid reasons to archive early) +- List incomplete artifacts so user can make informed decision + +### Decision 4: Reuse tasks.md completion check from regular archive + +The skill will parse tasks.md and warn about incomplete tasks, same as regular archive. + +**Rationale**: Task completion checking is valuable regardless of workflow. The logic is simple (count `- [ ]` vs `- [x]`) and doesn't need special OPSX handling. + +### Decision 5: Move change to archive/ with date prefix + +Same archive behavior as regular command: move to `openspec/changes/archive/YYYY-MM-DD-/`. + +**Rationale**: Consistency with existing archive convention. The `.openspec.yaml` file moves with the change, preserving schema metadata. + +## Risks / Trade-offs + +**Risk**: Users confused about when to use `/opsx:archive` vs `openspec archive` +→ **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. + +**Risk**: Incomplete sync if user declines and has delta specs +→ **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. + +**Trade-off**: No programmatic spec application in OPSX archive +→ **Accepted**: This is intentional. OPSX philosophy is agent-driven merging. If user wants programmatic application, use `openspec archive` instead. diff --git a/openspec/changes/opsx-archive-command/proposal.md b/openspec/changes/opsx-archive-command/proposal.md new file mode 100644 index 000000000..263faaee2 --- /dev/null +++ b/openspec/changes/opsx-archive-command/proposal.md @@ -0,0 +1,28 @@ +## Why + +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. + +## What Changes + +- Add `/opsx:archive` slash command for archiving changes in the experimental workflow +- Use artifact graph to check completion status (schema-aware) instead of just validating proposal + specs +- Prompt for `/opsx:sync` before archiving instead of programmatically applying specs +- Preserve `.openspec.yaml` schema metadata when moving to archive +- Integrate with existing OPSX commands for a cohesive workflow + +## Capabilities + +### New Capabilities + +- `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-/`. + +### Modified Capabilities + +(none - this is a new skill that doesn't modify existing specs) + +## Impact + +- New file: `.claude/commands/opsx/archive.md` +- New skill definition (generated via `openspec artifact-experimental-setup`) +- No changes to existing archive command or other OPSX commands +- Completes the OPSX command suite for full lifecycle management diff --git a/openspec/changes/opsx-archive-command/specs/opsx-archive-skill/spec.md b/openspec/changes/opsx-archive-command/specs/opsx-archive-skill/spec.md new file mode 100644 index 000000000..59891c6e5 --- /dev/null +++ b/openspec/changes/opsx-archive-command/specs/opsx-archive-skill/spec.md @@ -0,0 +1,122 @@ +## ADDED Requirements + +### Requirement: OPSX Archive Skill + +The system SHALL provide an `/opsx:archive` skill that archives completed changes in the experimental workflow. + +#### Scenario: Archive a change with all artifacts complete + +- **WHEN** agent executes `/opsx:archive` with a change name +- **AND** all artifacts in the schema are complete +- **AND** all tasks are complete +- **THEN** the agent moves the change to `openspec/changes/archive/YYYY-MM-DD-/` +- **AND** displays success message with archived location + +#### Scenario: Change selection prompt + +- **WHEN** agent executes `/opsx:archive` without specifying a change +- **THEN** the agent prompts user to select from available changes +- **AND** shows only active changes (excludes archive/) + +### Requirement: Artifact Completion Check + +The skill SHALL check artifact completion status using the artifact graph before archiving. + +#### Scenario: Incomplete artifacts warning + +- **WHEN** agent checks artifact status +- **AND** one or more artifacts have status other than `done` +- **THEN** display warning listing incomplete artifacts +- **AND** prompt user for confirmation to continue +- **AND** proceed if user confirms + +#### Scenario: All artifacts complete + +- **WHEN** agent checks artifact status +- **AND** all artifacts have status `done` +- **THEN** proceed without warning + +### Requirement: Task Completion Check + +The skill SHALL check task completion status from tasks.md before archiving. + +#### Scenario: Incomplete tasks found + +- **WHEN** agent reads tasks.md +- **AND** incomplete tasks are found (marked with `- [ ]`) +- **THEN** display warning showing count of incomplete tasks +- **AND** prompt user for confirmation to continue +- **AND** proceed if user confirms + +#### Scenario: All tasks complete + +- **WHEN** agent reads tasks.md +- **AND** all tasks are complete (marked with `- [x]`) +- **THEN** proceed without task-related warning + +#### Scenario: No tasks file + +- **WHEN** tasks.md does not exist +- **THEN** proceed without task-related warning + +### Requirement: Spec Sync Prompt + +The skill SHALL prompt to sync delta specs before archiving if specs exist. + +#### Scenario: Delta specs exist + +- **WHEN** agent checks for delta specs +- **AND** `specs/` directory exists in the change with spec files +- **THEN** prompt user: "This change has delta specs. Would you like to sync them to main specs before archiving?" +- **AND** if user confirms, execute `/opsx:sync` logic +- **AND** proceed with archive regardless of sync choice + +#### Scenario: No delta specs + +- **WHEN** agent checks for delta specs +- **AND** no `specs/` directory or no spec files exist +- **THEN** proceed without sync prompt + +### Requirement: Archive Process + +The skill SHALL move the change to the archive folder with date prefix. + +#### Scenario: Successful archive + +- **WHEN** archiving a change +- **THEN** create `archive/` directory if it doesn't exist +- **AND** generate target name as `YYYY-MM-DD-` using current date +- **AND** move entire change directory to archive location +- **AND** preserve `.openspec.yaml` file in archived change + +#### Scenario: Archive already exists + +- **WHEN** target archive directory already exists +- **THEN** fail with error message +- **AND** suggest renaming existing archive or using different date + +### Requirement: Skill Output + +The skill SHALL provide clear feedback about the archive operation. + +#### Scenario: Archive complete with sync + +- **WHEN** archive completes after syncing specs +- **THEN** display summary: + - Specs synced (from `/opsx:sync` output) + - Change archived to location + - Schema that was used + +#### Scenario: Archive complete without sync + +- **WHEN** archive completes without syncing specs +- **THEN** display summary: + - Note that specs were not synced (if applicable) + - Change archived to location + - Schema that was used + +#### Scenario: Archive complete with warnings + +- **WHEN** archive completes with incomplete artifacts or tasks +- **THEN** include note about what was incomplete +- **AND** suggest reviewing if archive was intentional diff --git a/openspec/changes/opsx-archive-command/tasks.md b/openspec/changes/opsx-archive-command/tasks.md new file mode 100644 index 000000000..2b1582ab5 --- /dev/null +++ b/openspec/changes/opsx-archive-command/tasks.md @@ -0,0 +1,23 @@ +## 1. Create Slash Command + +- [x] 1.1 Create `.claude/commands/opsx/archive.md` with skill definition +- [x] 1.2 Add YAML frontmatter (name, description, category, tags) +- [x] 1.3 Implement change selection logic (prompt if not provided) +- [x] 1.4 Implement artifact completion check using `openspec status --json` +- [x] 1.5 Implement task completion check (parse tasks.md for `- [ ]`) +- [x] 1.6 Implement spec sync prompt (check for specs/ directory, offer `/opsx:sync`) +- [x] 1.7 Implement archive process (move to archive/YYYY-MM-DD-/) +- [x] 1.8 Add output formatting for success/warning cases + +## 2. Regenerate Skills + +- [x] 2.1 Run `openspec artifact-experimental-setup` to regenerate skills +- [x] 2.2 Verify skill appears in `.claude/skills/` directory + +## 3. Testing + +- [x] 3.1 Test `/opsx:archive` with a complete change (all artifacts, all tasks done) +- [x] 3.2 Test `/opsx:archive` with incomplete artifacts (verify warning shown) +- [x] 3.3 Test `/opsx:archive` with incomplete tasks (verify warning shown) +- [x] 3.4 Test `/opsx:archive` with delta specs (verify sync prompt shown) +- [x] 3.5 Test `/opsx:archive` without change name (verify selection prompt) diff --git a/src/commands/artifact-workflow.ts b/src/commands/artifact-workflow.ts index f9f046fb6..d97913691 100644 --- a/src/commands/artifact-workflow.ts +++ b/src/commands/artifact-workflow.ts @@ -28,7 +28,7 @@ import { type SchemaInfo, } from '../core/artifact-graph/index.js'; import { createChange, validateChangeName } from '../utils/change-utils.js'; -import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getFfChangeSkillTemplate, getSyncSpecsSkillTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate, getOpsxFfCommandTemplate, getOpsxSyncCommandTemplate } from '../core/templates/skill-templates.js'; +import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getFfChangeSkillTemplate, getSyncSpecsSkillTemplate, getArchiveChangeSkillTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate, getOpsxFfCommandTemplate, getOpsxSyncCommandTemplate, getOpsxArchiveCommandTemplate } from '../core/templates/skill-templates.js'; import { FileSystemUtils } from '../utils/file-system.js'; // ----------------------------------------------------------------------------- @@ -798,6 +798,7 @@ async function artifactExperimentalSetupCommand(): Promise { const applyChangeSkill = getApplyChangeSkillTemplate(); const ffChangeSkill = getFfChangeSkillTemplate(); const syncSpecsSkill = getSyncSpecsSkillTemplate(); + const archiveChangeSkill = getArchiveChangeSkillTemplate(); // Get command templates const newCommand = getOpsxNewCommandTemplate(); @@ -805,6 +806,7 @@ async function artifactExperimentalSetupCommand(): Promise { const applyCommand = getOpsxApplyCommandTemplate(); const ffCommand = getOpsxFfCommandTemplate(); const syncCommand = getOpsxSyncCommandTemplate(); + const archiveCommand = getOpsxArchiveCommandTemplate(); // Create skill directories and SKILL.md files const skills = [ @@ -813,6 +815,7 @@ async function artifactExperimentalSetupCommand(): Promise { { template: applyChangeSkill, dirName: 'openspec-apply-change' }, { template: ffChangeSkill, dirName: 'openspec-ff-change' }, { template: syncSpecsSkill, dirName: 'openspec-sync-specs' }, + { template: archiveChangeSkill, dirName: 'openspec-archive-change' }, ]; const createdSkillFiles: string[] = []; @@ -842,6 +845,7 @@ ${template.instructions} { template: applyCommand, fileName: 'apply.md' }, { template: ffCommand, fileName: 'ff.md' }, { template: syncCommand, fileName: 'sync.md' }, + { template: archiveCommand, fileName: 'archive.md' }, ]; const createdCommandFiles: string[] = []; @@ -899,6 +903,7 @@ ${template.content} console.log(' • /opsx:apply - Implement tasks'); console.log(' • /opsx:ff - Fast-forward: create all artifacts at once'); console.log(' • /opsx:sync - Sync delta specs to main specs'); + console.log(' • /opsx:archive - Archive a completed change'); console.log(); console.log(chalk.yellow('💡 This is an experimental feature.')); console.log(' Feedback welcome at: https://github.com/Fission-AI/OpenSpec/issues'); diff --git a/src/core/templates/skill-templates.ts b/src/core/templates/skill-templates.ts index 4050532c3..d076f13c4 100644 --- a/src/core/templates/skill-templates.ts +++ b/src/core/templates/skill-templates.ts @@ -1050,6 +1050,112 @@ After completing all artifacts, summarize: }; } +/** + * Template for openspec-archive-change skill + * For archiving completed changes in the experimental workflow + */ +export function getArchiveChangeSkillTemplate(): SkillTemplate { + return { + name: 'openspec-archive-change', + description: 'Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.', + instructions: `Archive a completed change in the experimental workflow. + +**Input**: Optionally specify a change name. If omitted, MUST prompt for available changes. + +**Steps** + +1. **If no change name provided, prompt for selection** + + Run \`openspec list --json\` to get available changes. Use the **AskUserQuestion tool** to let the user select. + + Show only active changes (not already archived). + Include the schema used for each change if available. + + **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose. + +2. **Check artifact completion status** + + Run \`openspec status --change "" --json\` to check artifact completion. + + Parse the JSON to understand: + - \`schemaName\`: The workflow being used + - \`artifacts\`: List of artifacts with their status (\`done\` or other) + + **If any artifacts are not \`done\`:** + - Display warning listing incomplete artifacts + - Use **AskUserQuestion tool** to confirm user wants to proceed + - Proceed if user confirms + +3. **Check task completion status** + + Read the tasks file (typically \`tasks.md\`) to check for incomplete tasks. + + Count tasks marked with \`- [ ]\` (incomplete) vs \`- [x]\` (complete). + + **If incomplete tasks found:** + - Display warning showing count of incomplete tasks + - Use **AskUserQuestion tool** to confirm user wants to proceed + - Proceed if user confirms + + **If no tasks file exists:** Proceed without task-related warning. + +4. **Check for delta specs and prompt for sync** + + Check if \`specs/\` directory exists in the change with spec files. + + **If delta specs exist:** + - Prompt: "This change has delta specs. Would you like to sync them to main specs before archiving?" + - If user confirms, execute /opsx:sync logic (use the openspec-sync-specs skill) + - Proceed with archive regardless of sync choice + +5. **Perform the archive** + + Create the archive directory if it doesn't exist: + \`\`\`bash + mkdir -p openspec/changes/archive + \`\`\` + + Generate target name using current date: \`YYYY-MM-DD-\` + + **Check if target already exists:** + - If yes: Fail with error, suggest renaming existing archive or using different date + - If no: Move the change directory to archive + + \`\`\`bash + mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + \`\`\` + +6. **Display summary** + + Show archive completion summary including: + - Change name + - Schema that was used + - Archive location + - Whether specs were synced (if applicable) + - Note about any warnings (incomplete artifacts/tasks) + +**Output On Success** + +\`\`\` +## Archive Complete + +**Change:** +**Schema:** +**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ + +All artifacts complete. All tasks complete. +\`\`\` + +**Guardrails** +- Always prompt for change selection if not provided +- Use artifact graph (openspec status --json) for completion checking +- Don't block archive on warnings - just inform and confirm +- Preserve .openspec.yaml when moving to archive (it moves with the directory) +- Show clear summary of what happened +- If sync is requested, use openspec-sync-specs approach (agent-driven)` + }; +} + /** * Template for /opsx:sync slash command */ @@ -1188,3 +1294,155 @@ Main specs are now updated. The change remains active - archive when implementat - The operation should be idempotent - running twice should give same result` }; } + +/** + * Template for /opsx:archive slash command + */ +export function getOpsxArchiveCommandTemplate(): CommandTemplate { + return { + name: 'OPSX: Archive', + description: 'Archive a completed change in the experimental workflow', + category: 'Workflow', + tags: ['workflow', 'archive', 'experimental'], + content: `Archive a completed change in the experimental workflow. + +**Input**: Optionally specify \`--change \` after \`/opsx:archive\`. If omitted, MUST prompt for available changes. + +**Steps** + +1. **If no change name provided, prompt for selection** + + Run \`openspec list --json\` to get available changes. Use the **AskUserQuestion tool** to let the user select. + + Show only active changes (not already archived). + Include the schema used for each change if available. + + **IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose. + +2. **Check artifact completion status** + + Run \`openspec status --change "" --json\` to check artifact completion. + + Parse the JSON to understand: + - \`schemaName\`: The workflow being used + - \`artifacts\`: List of artifacts with their status (\`done\` or other) + + **If any artifacts are not \`done\`:** + - Display warning listing incomplete artifacts + - Prompt user for confirmation to continue + - Proceed if user confirms + +3. **Check task completion status** + + Read the tasks file (typically \`tasks.md\`) to check for incomplete tasks. + + Count tasks marked with \`- [ ]\` (incomplete) vs \`- [x]\` (complete). + + **If incomplete tasks found:** + - Display warning showing count of incomplete tasks + - Prompt user for confirmation to continue + - Proceed if user confirms + + **If no tasks file exists:** Proceed without task-related warning. + +4. **Check for delta specs and prompt for sync** + + Check if \`specs/\` directory exists in the change with spec files. + + **If delta specs exist:** + - Prompt: "This change has delta specs. Would you like to sync them to main specs before archiving?" + - If user confirms, execute \`/opsx:sync\` logic + - Proceed with archive regardless of sync choice + +5. **Perform the archive** + + Create the archive directory if it doesn't exist: + \`\`\`bash + mkdir -p openspec/changes/archive + \`\`\` + + Generate target name using current date: \`YYYY-MM-DD-\` + + **Check if target already exists:** + - If yes: Fail with error, suggest renaming existing archive or using different date + - If no: Move the change directory to archive + + \`\`\`bash + mv openspec/changes/ openspec/changes/archive/YYYY-MM-DD- + \`\`\` + +6. **Display summary** + + Show archive completion summary including: + - Change name + - Schema that was used + - Archive location + - Whether specs were synced (if applicable) + - Note about any warnings (incomplete artifacts/tasks) + +**Output On Success** + +\`\`\` +## Archive Complete + +**Change:** +**Schema:** +**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ + +All artifacts complete. All tasks complete. +\`\`\` + +**Output On Success With Sync** + +\`\`\` +## Archive Complete + +**Change:** +**Schema:** +**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ + +Specs synced to main before archiving. +\`\`\` + +**Output On Success With Warnings** + +\`\`\` +## Archive Complete (with warnings) + +**Change:** +**Schema:** +**Archived to:** openspec/changes/archive/YYYY-MM-DD-/ + +**Warnings:** +- Archived with 2 incomplete artifacts +- Archived with 3 incomplete tasks +- Delta specs were not synced + +Review the archive if this was not intentional. +\`\`\` + +**Output On Error (Archive Exists)** + +\`\`\` +## Archive Failed + +**Change:** +**Target:** openspec/changes/archive/YYYY-MM-DD-/ + +Target archive directory already exists. + +**Options:** +1. Rename the existing archive +2. Delete the existing archive if it's a duplicate +3. Wait until a different date to archive +\`\`\` + +**Guardrails** +- Always prompt for change selection if not provided +- Use artifact graph (openspec status --json) for completion checking +- Don't block archive on warnings - just inform and confirm +- Preserve .openspec.yaml when moving to archive (it moves with the directory) +- Show clear summary of what happened +- If sync is requested, use /opsx:sync approach (agent-driven)` + }; +}