| name | repo-hygiene |
| description | Periodic repository cleanup sweep (Tierward repo variant) - finds orphaned/merged git branches, orphaned worktrees and unregistered worktree directories, stale `.claude/session/*.md` files, stale `.claude/initiatives/*.md` files, and (target:full / target:reviews) orphaned documentation and stale `docs/reviews/` snapshots (archive-only moves, never deletion). Reports every finding with evidence, then executes only the branches/worktrees/session-files the user explicitly confirms via a single AskUserQuestion batch. Never deletes docs/*.md itself - those are always report-only, evidence-based, human-decided. Distinct from the Phase 8 cleanup gate (which tears down one specific block at closure) - this is the periodic sweep that catches what block-by-block cleanup misses. |
| user-invocable | true |
| model | sonnet |
| argument-hint | [target:full] |
| allowed-tools | Bash(bash .claude/skills/repo-hygiene/references/scan-branches-worktrees.sh), Bash(git branch:*), Bash(git worktree:*), Bash(git status:*), Bash(git log:*), Bash(git fetch:*), Bash(git rev-parse:*), Bash(git show:*), Bash(gh pr list:*), Bash(gh pr view:*), Bash(ls:*), Bash(wc:*), Bash(date:*), Bash(stat:*), Bash(find:*), Bash(rm .claude/session/*.md), Bash(rm .claude/initiatives/*.md), Bash(mkdir -p docs/reviews/archive), Bash(mv .claude/initiatives/*), Bash(mv docs/reviews/*), Bash(rm -rf .claude/worktrees/*), Read, Grep, Glob
|
Tierward repo variant - diverges deliberately from the scaffolded payload copy (packages/cli/templates/tier-{m,l}/...): adds the unregistered-worktree-dir scan, Step 2b (initiatives staleness), and the docs/reviews/ staleness pass. Do not sync this file back over the payload copies.
Runs in the main conversation, deliberately without context: fork. AskUserQuestion is unavailable to subagents/forked skill contexts, and this skill's confirm-then-execute design requires it mid-run. Do not add context: fork to this file.
Goal: search thoroughly, report every candidate with concrete evidence, execute only what the user explicitly confirms. Never guess-execute. Never touch docs/*.md regardless of confirmation.
Step 0 - Parse scope
$ARGUMENTS: default = quick scan (Steps 1, 2, 2b). target:full adds Step 3 (doc orphans + reviews staleness) - the slow, judgment-heavy pass. target:reviews runs ONLY the Step 3 reviews-staleness pass (skips the tracked-doc orphan sweep). State which mode is active before starting.
Always exclude .claude/worktrees/** from every Grep/Glob in Steps 2 and 3. Worktrees are full repo checkouts - without this exclusion every file inside every active worktree gets reported as a duplicate "root-level" finding.
Step 1 - Branch & worktree scan (mechanical, always runs)
Run the companion script:
bash .claude/skills/repo-hygiene/references/scan-branches-worktrees.sh
It is read-only and prints three sections:
SAFE_BRANCH_DELETE - bare branch names with no attached worktree, merged into every protected branch that exists on origin (see PROTECTED_BRANCHES at the top of the script), no open PR.
SAFE_WORKTREE_REMOVE - <branch>|<path> pairs, merged into all protected branches, clean working tree, no open PR. Lines prefixed KEEP| are explicitly excluded with a reason (uncommitted changes / not yet merged / open PR / gh check failed) - do not re-litigate these, the script already checked.
PRUNABLE_WORKTREE - paths registered in git worktree list whose actual directory no longer exists.
ORPHAN_WORKTREE_DIR - directories on disk under .claude/worktrees/ that are NOT registered in git worktree list (leftovers of a failed/manual removal + prune), with a content summary (files:N|newest:date). Git cannot report dirtiness for an unregistered dir, so these NEVER join the low-risk batch: each one gets its own separate confirmation in Step 5, after the content summary is shown, and is removed with rm -rf only on that explicit per-item confirm.
The classification is deliberately conservative (merged into ALL protected branches + clean + no open PR; a failed gh check reads as unknown, never as "no PR"). Trust it - do not loosen or tighten the criteria ad hoc.
Safety nets when executing in Step 6: always git branch -d (never -D - -d refuses on unmerged content, which is your backstop against a misclassification). Always git worktree remove without --force (refuses if dirty). If either refuses, STOP and report to the user - do not retry with the forced variant.
Step 2 - Session-file staleness check (judgment, always runs)
For every .claude/session/*.md (block-.md and fix-.md):
- Read the file. Note its mtime (
stat), its front matter, and any Status: line.
- Front matter
block_closed: true or fix_closed: true means the block was closed and the file was kept on purpose at the cleanup gate - classify as WEAK CANDIDATE ("archived by choice - delete only if no longer needed").
gh pr list --state merged --search "<slug derived from filename>" --limit 5 - does a merged PR confirm that block is closed?
- Check
git branch -a and git worktree list for a branch/worktree matching the file's block/branch name.
- Classify - evidence-based, never by mtime alone in either direction (a fresh in-progress block and a long-blocked-but-still-relevant investigation must both resolve to KEEP absent closure evidence):
- STRONG CANDIDATE: a merged PR confirms closure AND no matching branch/worktree exists anymore.
- WEAK CANDIDATE: closed-and-kept front matter (point 2), OR no merged PR references it AND the file's own status reads as finished/abandoned AND it is several days old. Report with lower confidence, explicit evidence.
- KEEP: recent activity, an in-progress/blocked-pending-external-action status, or a still-existing matching branch/worktree. When in doubt, KEEP.
Step 2b - Initiatives staleness check (Tierward repo only, judgment, always runs)
For every .claude/initiatives/*.md (gitignored, local - deletable like session files, with one hard exception):
roadmap-status.md is KEEP, always, non-negotiable. It is the single source of truth for roadmap state. Never list it as a candidate, regardless of any evidence.
- For each other file: read the header/status, note mtime and size, then cross-check closure evidence - does
roadmap-status.md mark the corresponding item(s) Done/Closed/Deferred-with-criteria? Do merged PRs confirm the plan was executed? Does a superseding doc exist?
- Classify STRONG / WEAK / KEEP with the same evidence discipline as Step 2 (never mtime alone; deferred-with-criteria plans are KEEP - they are the criteria's home).
- For large closed memos (>50KB), offer archive (
mkdir -p docs/reviews/archive && mv the file there) as the default proposal instead of deletion - they carry decision history worth keeping out of the working set but not destroying.
Step 3 - Documentation orphan sweep + reviews staleness (target:full; reviews pass alone via target:reviews)
Tracked-doc orphan findings are judgment-based, evidence-only, NEVER executable. The docs/reviews/ staleness pass below is the one exception with an action - and that action is archive-only, never deletion.
Scan docs/**/*.md, excluding the pipeline-fed canonical set (requirements.md, implementation-checklist.md, refactoring-backlog.md, sitemap.md, db-map.md, pipeline-standards.md, claudemd-standards.md, model-effort-policy.md, adr/, specs/, metrics/). For each remaining file, check inbound references - Grep across every other tracked doc, every SKILL.md, CLAUDE.md, and the .claude/rules/*.md files. A file with zero inbound references AND content suggesting a closed/superseded snapshot is reported as evidence-only.
Additionally (Tierward repo, also runs under target:reviews): scan docs/reviews/ (gitignored, local audit history), excluding docs/reviews/archive/ (the destination). For each dated snapshot dir/file:
- Mechanical KEEP first (non-negotiable): Grep for inbound references across
roadmap-status.md, every tracked doc, every SKILL.md, CLAUDE.md, and .claude/rules/*.md. Any hit → KEEP, regardless of age or absorption evidence (e.g. the roadmap "Source files for open items" table cites review synthesis files - those must stay where the pointer says).
- For the rest, classify by staleness - ALL THREE required, never one alone: (a) findings absorbed into
docs/refactoring-backlog.md or roadmap-status, (b) superseded by a more recent review of the same surface, (c) older than 30 days.
- Action semantics - archive-only: candidates are proposed as
mv docs/reviews/<item> docs/reviews/archive/ in the Step 5 batch. Deletion of anything under docs/reviews/ stays forbidden - this history exists nowhere else (gitignored, no git recovery); a move within the same tree is reversible by hand, a delete is not.
Hard rule: documentation is git-tracked content - a wrong call here is real, hard-to-reverse loss, a different risk class than a git branch or a local session file. Never include a doc-orphan finding in the Step 5 confirmation batch, never suggest a deletion command for it, regardless of how confident the evidence looks. State this limitation explicitly in the report so it doesn't read as an oversight.
Step 4 - Report
Present findings grouped by category, each with its evidence. For branches/worktrees/session files: include the exact command that would run. For doc orphans: evidence only, explicitly labeled "not included in execution - human judgment required."
Step 5 - Confirm (AskUserQuestion)
One batched question (or a small set): list the exact items proposed for deletion, grouped, with an option to execute all / execute a subset / cancel. Initiatives candidates state their proposed action per item (archive vs delete). ORPHAN_WORKTREE_DIR items are NEVER part of the batch: each gets its own dedicated confirmation, with the content summary restated. Reviews-staleness candidates enter the batch as MOVES only (mv into docs/reviews/archive/), clearly labeled as such. Do not include tracked-doc orphan findings in this gate - they were never candidates for execution.
Step 6 - Execute confirmed items only
- Branches:
git branch -d <name>
- Worktrees:
git worktree remove <path>
- Prunable worktree registrations:
git worktree prune
- Session files:
rm .claude/session/<file>.md - only for items the user explicitly confirmed, one at a time, never a bulk rm .claude/session/*.md.
- Initiatives:
rm .claude/initiatives/<file>.md (delete) or mkdir -p docs/reviews/archive && mv .claude/initiatives/<file>.md docs/reviews/archive/ (archive) - one at a time, per the action confirmed for that item. Never touch roadmap-status.md.
- Orphan worktree dirs:
rm -rf .claude/worktrees/<dir> - only after that item's own dedicated confirmation.
- Reviews snapshots:
mv docs/reviews/<item> docs/reviews/archive/ - one at a time, archive-only; never rm anything under docs/reviews/.
If any command refuses (unmerged branch, dirty worktree), stop and report - do not force.
Step 7 - Summary
One line per category: found / confirmed / executed / left for later (docs). If nothing was found in a category, say so plainly rather than omitting the section - a clean report is a valid, useful outcome.