skills/openspec-bulk-archive-change/SKILL.md
Archive multiple completed changes in a single operation.
This skill allows you to batch-archive changes, handling spec conflicts intelligently by checking the codebase to determine what's actually implemented.
Store selection: If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run openspec store list --json to discover registered store ids, then pass --store <id> on the commands that read or write specs and changes (new change, status, instructions, list, show, validate, archive, doctor, context, view). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local openspec/ root.
Input: None required (prompts for selection)
Steps
Get active changes
Run openspec list --json to get all active changes.
If no active changes exist, inform user and stop.
Prompt for change selection
Ask the user to choose changes (multi-select):
IMPORTANT: Do NOT auto-select. Always let the user choose.
Load current archive inputs once for the selected root before batch validation:
Choose one selected change from this root and run
openspec instructions archive --change "<selected-change>" --json with the
same selected-root flags. This lookup is advisory and optional: it only supplies
extra prompt inputs, so it must never block the batch. If it fails or returns
invalid JSON — for example on an older CLI that does not support this command
yet — continue the batch with no context and no operation guidance. Do not
report an error and do not stop.
A valid response may omit context and operationGuidance. Treat
context as a required prompt-level input across the batch: read and consider
it, and apply relevant project facts, conventions, and constraints. Treat
operationGuidance as optional additive advice: read and consider every
entry, and follow entries that are applicable and compatible with the built-in
batch workflow.
Keep both fields separate from conflict analysis, explicit user choices, resolved paths, CLI checks, and command contracts. If context conflicts with one of those controlling inputs, report the conflict and preserve the controlling value. If guidance is inapplicable or conflicts with a controlling input, do not follow it and explain why. Do not infer skipped prompts, replacement paths, or flags from either field, and do not copy their text verbatim into specs, changes, or summaries. These are prompt-level behavior contracts, not enforceable checks.
Batch validation - gather status for all selected changes
For each selected change, collect:
a. Artifact status - Run openspec status --change "<name>" --json
schemaName, artifacts, planningHome, changeRoot, artifactPaths, and actionContextdone vs other statesb. Task completion - Read artifactPaths.tasks.existingOutputPaths from status JSON
- [ ] (incomplete) vs - [x] (complete)c. Delta specs - Check artifactPaths.specs.existingOutputPaths from status JSON
### Requirement: <name>)specs entry is
missing or the list is empty, perform no spec sync or specs-instruction
lookup for that change; do not infer deltas from unrelated artifacts.specs artifact.Detect spec conflicts
Build a map of capability -> [changes that touch it]:
auth -> [change-a, change-b] <- CONFLICT (2+ changes)
api -> [change-c] <- OK (only 1 change)
A conflict exists when 2+ selected changes have delta specs for the same capability.
Resolve conflicts agentically
For each conflict, investigate the codebase:
a. Read the delta specs from each conflicting change to understand what each claims to add/modify
b. Search the codebase for implementation evidence:
c. Determine resolution:
d. Record resolution for each conflict:
Show consolidated status table
Display a table summarizing all changes:
| Change | Artifacts | Tasks | Specs | Conflicts | Status |
|---------------------|-----------|-------|---------|-----------|--------|
| schema-management | Done | 5/5 | 2 delta | None | Ready |
| project-config | Done | 3/3 | 1 delta | None | Ready |
| add-oauth | Done | 4/4 | 1 delta | auth (!) | Ready* |
| add-verify-skill | 1 left | 2/5 | None | None | Warn |
For conflicts, show the resolution:
* Conflict resolution:
- auth spec: Will apply add-oauth then add-jwt (both implemented, chronological order)
For incomplete changes, show warnings:
Warnings:
- add-verify-skill: 1 incomplete artifact, 3 incomplete tasks
Confirm batch operation
Ask the user a single confirmation question:
If there are incomplete changes, make clear they'll be archived with warnings.
Route on the answer by intent, not by exact label — you wrote these labels, so match what the user picked rather than the wording above:
Ready or Ready*, and record the rest as Skipped in step 8d. If a Ready* change's conflict partner is skipped, re-derive that conflict's resolution using only the changes being archived.Before step 8 writes the first main spec or moves any change, fetch every
required specs-rule snapshot for the confirmed batch. For each change that will
sync concrete artifactPaths.specs.existingOutputPaths, run
openspec instructions specs --change "<name>" --json exactly once with the
same selected-root flags. Obtain all snapshots before the first write or move.
If any lookup exits non-zero or returns invalid artifact-instruction JSON,
identify the affected change, report the error, and stop the whole batch before
any main-spec write or change move. Do not treat lookup failure as omitted
rules. A valid response without rules is the no-rules case.
Execute archive for each confirmed change
Before processing, carry the recorded decisions from step 5 (after any step 7 re-derivation) into two per-delta sets:
includedDeltas: all non-conflicting delta specs from confirmed changes plus conflict deltas selected for syncexcludedDeltas: conflict deltas from confirmed changes excluded because their implementation is missingProcess changes in the determined order (respecting conflict resolution):
a. Sync included delta specs:
openspec-sync-specs workflow inline (agent-driven intelligent merge) only for changes with entries in includedDeltas, passing only the included delta paths and explicitly instructing it to ignore that change's excludedDeltas. Wait for it to finish.changeRoot out from under a sync that is still reading it.b. Verify included delta specs before moving changeRoot:
includedDeltas against main spec at <planningHome.root>/openspec/specs/<capability>/spec.md (use the store-aware planningHome.root from step 3 status JSON, not a hardcoded repo path).excludedDeltas; they are intentionally left unsynced.changeRoot — do not archive that change. changeRoot remains intact.c. Perform the archive:
Target name: use the change name as-is when it already starts with a YYYY-MM-DD- prefix; otherwise prepend the current date as YYYY-MM-DD-<name> (same rule as openspec archive).
mkdir -p "<planningHome.changesDir>/archive"
mv "<changeRoot>" "<planningHome.changesDir>/archive/<target-name>"
d. Track outcome for each change:
excludedDeltas, report sync skipped with the change, capability, and recorded reason. This is distinct from skipping the archive.Display summary
Show final results:
## Bulk Archive Complete
Archived 3 changes:
- schema-management-cli -> archive/2026-01-19-schema-management-cli/
- project-config -> archive/2026-01-19-project-config/
- add-oauth -> archive/2026-01-19-add-oauth/
Skipped 1 change:
- add-verify-skill (user chose not to archive incomplete)
Spec sync summary:
- 4 delta specs synced to main specs
- 1 delta spec sync skipped (add-jwt/auth: implementation not found)
- 1 conflict resolved (auth: synced add-oauth, skipped add-jwt)
If any failures:
Failed 1 change:
- some-change: Archive directory already exists
Conflict Resolution Examples
Example 1: Only one implemented
Conflict: <planningHome.root>/openspec/specs/auth/spec.md touched by [add-oauth, add-jwt]
Checking add-oauth:
- Delta adds "OAuth Provider Integration" requirement
- Searching codebase... found src/auth/oauth.ts implementing OAuth flow
Checking add-jwt:
- Delta adds "JWT Token Handling" requirement
- Searching codebase... no JWT implementation found
Resolution: Only add-oauth is implemented. Will sync add-oauth specs only.
Example 2: Both implemented
Conflict: <planningHome.root>/openspec/specs/api/spec.md touched by [add-rest-api, add-graphql]
Checking add-rest-api (created 2026-01-10):
- Delta adds "REST Endpoints" requirement
- Searching codebase... found src/api/rest.ts
Checking add-graphql (created 2026-01-15):
- Delta adds "GraphQL Schema" requirement
- Searching codebase... found src/api/graphql.ts
Resolution: Both implemented. Will apply add-rest-api specs first,
then add-graphql specs (chronological order, newer takes precedence).
Output On Success
## Bulk Archive Complete
Archived N changes:
- <change-1> -> archive/<target-name-1>/
- <change-2> -> archive/<target-name-2>/
Spec sync summary:
- N delta specs synced to main specs
- No conflicts (or: M conflicts resolved)
Output On Partial Success
## Bulk Archive Complete (partial)
Archived N changes:
- <change-1> -> archive/<target-name-1>/
Skipped M changes:
- <change-2> (user chose not to archive incomplete)
Failed K changes:
- <change-3>: Archive directory already exists
Output When No Changes
## No Changes to Archive
No active changes found. Create a new change to get started.
Guardrails
YYYY-MM-DD- prefix is used as-is (never stack a second date)openspec-sync-specs workflow inline (agent-driven) for each change with included delta specsincludedDeltas and excludedDeltas decisions into execution; sync and verify only included deltassync skipped without treating the archive itself as skipped<planningHome.root>/openspec/specs/<capability>/spec.md before moving changeRootartifactPaths.specs.existingOutputPaths continue without spec sync