speckit-archive-feature
Archive the current feature directory under specs/archive/YYYY-MM-DD-{slug}/, update CHANGES.md, and close associated GitHub issues.
SKILL.md.specify/extensions/archive/.specify-dev/agent-commands/claude/speckit-archive-feature/SKILL.md
GitHubArchive Current Feature
Move the completed feature planning folder from specs/{slug}/ to specs/archive/YYYY-MM-DD-{slug}/ using git mv, update (or create) CHANGES.md, and close any GitHub issues recorded as source_issue in .specify/feature.json.
Behavior
- Parse arguments. Detect a leading
--force/-fflag. Treat the next positional as the feature slug. - Resolve the feature directory from the current git branch (
specs/<branch>), or from the argument if provided. Refuse if the path is already underspecs/archive/. - Verify the feature is ready to archive (tasks.md exists and contains no unchecked
[ ]items). If unchecked tasks remain, the script exits with status2and the list on stderr — see Interactive confirmation below. When--forcewas passed up front, log the count and proceed without prompting. - Derive archive date
YYYY-MM-DDfrom today. - Append a
CHANGES.mdentry with the feature title (fromspec.mdH1) and a short summary. CreateCHANGES.mdin Keep-a-Changelog style if absent. git mv specs/{slug} specs/archive/{date}-{slug}(creating the parent if needed).- If
ghis available and.specify/feature.jsonhassource_issue, rungh issue close <N> -c "Archived in specs/archive/{date}-{slug}/".
The archive can run as part of the feature's PR — the PR does not have to be merged first. Tasks completion is the real readiness signal; PR merge state is enforced by the platform, not by this script.
Execution
- Bash:
.specify/extensions/archive/scripts/bash/archive-feature.sh [--force] [feature_slug]
When feature_slug is omitted, the script derives it from the current git branch. --force skips the unchecked-tasks gate; it does not bypass the "destination exists" or "already-archived" guards.
Interactive confirmation
Archiving with unfinished tasks loses signal — the right default is to finish them first. When the user did not pass --force and the script exits with status 2 (unchecked tasks):
- Show the unchecked-task list from the script's stderr to the user.
- Recommend completing the open tasks before archiving. If any are clearly small or already done in the code, offer to finish them now.
- Ask the user explicitly: "Force archive with N unfinished tasks anyway?" — present at least these options:
- Finish the tasks first (default — abort the archive and return to the feature).
- Force archive now (re-run the script with
--force).
- Only re-invoke the script with
--forceafter an explicit "yes / force" from the user. Any other response (including silence or ambiguity) aborts the archive.
If the user passed --force on the original invocation, skip the prompt entirely — they've already consented.
Changelog Conventions
The changelog update follows Keep a Changelog conventions (do-changelog style):
- Prefer
CHANGELOG.md, fall back toCHANGES.mdif it already exists. CreateCHANGELOG.mdin Keep a Changelog format if neither is present. - Inspect the existing format before writing — match heading depth and date format.
- Group entries by type: Added / Changed / Fixed / Removed / Security. Archive entries are written under
### Changed. - Lead with user-visible impact; keep bullets short and specific.
- Do not invent version numbers or release dates — use the archive date
YYYY-MM-DDas the section heading.
Graceful Degradation
- If
ghis missing or nosource_issueis recorded, the archive still proceeds; issue-close is skipped with a notice. - If
CHANGES.mdalready has a section for today's date, the entry is appended under it rather than duplicating the header. - If the destination path already exists, the script aborts without overwriting (even with
--force). - Unchecked tasks: script exits
2with the list on stderr. The command layer prompts the user to finish them first or confirm a forced archive — see Interactive confirmation. Passing--forceon the original invocation skips the prompt.