一键导入
housekeep
Local repo maintenance — clean stale worktrees, remove dirt files, sync with main, update codegraph, prune branches, and verify repo health
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Local repo maintenance — clean stale worktrees, remove dirt files, sync with main, update codegraph, prune branches, and verify repo health
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Adopt extracted helpers — find dead symbols from forge, wire them into consumers, replace duplicated inline patterns, and gate on dead-symbol delta (Titan Paradigm Phase 4.5)
Adopt extracted helpers — find dead symbols from forge, wire them into consumers, replace duplicated inline patterns, and gate on dead-symbol delta (Titan Paradigm Phase 4.5)
Validate staged changes — codegraph checks + project lint/build/test, auto-rollback on failure, pass/fail commit gate (Titan Paradigm Phase 4)
Audit codebase files against the 4-pillar quality manifesto using RECON work batches, with batch processing and context budget management (Titan Paradigm Phase 2)
Map a codebase's dependency graph, identify hotspots, name logical domains, propose work batches, and produce a ranked priority queue for autonomous cleanup (Titan Paradigm Phase 1)
Check all open PRs, resolve conflicts, update branches, address Claude and Greptile review concerns, fix CI failures, and retrigger reviewers until clean
| name | housekeep |
| description | Local repo maintenance — clean stale worktrees, remove dirt files, sync with main, update codegraph, prune branches, and verify repo health |
| argument-hint | [--full | --dry-run | --skip-update] (default: full cleanup) |
| allowed-tools | Bash, Read, Write, Edit, Glob, Grep |
Clean up the local repo: remove stale worktrees, delete dirt/temp files, sync with main, update codegraph to latest, prune merged branches, and verify repo health. The "spring cleaning" routine.
$ARGUMENTS may contain:
--full — run all phases (default behavior)--dry-run — show what would be cleaned without actually doing it--skip-update — skip the codegraph npm update phasepackage.json with "name": "@optave/codegraph")$ARGUMENTS:
DRY_RUN=true if --dry-runSKIP_UPDATE=true if --skip-updategit branch --show-currentgit status --shortExit condition: repo identity confirmed (@optave/codegraph); DRY_RUN/SKIP_UPDATE are known; current branch and status recorded.
Always report disk usage first. Worktree bloat (per-worktree
node_modules/,target/,dist/) is the single largest source of disk waste in this repo — a fresh worktree withnpm install+ a Rust build is ~3GB. Even when no worktree is technically "stale" by branch criteria, the disk footprint must be surfaced so the user can decide what to keep.
Always print this, even on --dry-run. Use du -sk (kilobytes) so the pipeline is portable across BSD (macOS) and GNU (Linux) — sort -h is a GNU coreutils extension and is rejected by stock macOS sort.
# 2>/dev/null suppress: .claude/worktrees/ may not exist yet on a fresh repo — zero worktrees, not an error
du -sh .claude/worktrees 2>/dev/null
# Portable per-worktree sort: kilobytes through sort -n, then format back to human-readable.
du -sk .claude/worktrees/*/ 2>/dev/null | sort -n | awk '{
k=$1; $1=""; sub(/^ /, "");
if (k >= 1048576) printf "%.1fG\t%s\n", k/1048576, $0;
else if (k >= 1024) printf "%.1fM\t%s\n", k/1024, $0;
else printf "%dK\t%s\n", k, $0;
}'
If the total exceeds 5GB, raise it as a finding in the report regardless of whether any individual worktree is stale.
git worktree list
Cross-reference against .claude/worktrees/* on disk — directories there that aren't in git worktree list are orphaned (prunable). Worktrees in the list whose directory is missing are also prunable.
A worktree is stale if:
git worktree list (orphaned)origin/main AND the branch's last commit is more than 7 days old
(check: git log -1 --format=%ci <branch> — git worktree list does not expose creation timestamps).claude/worktrees/agent-<hex> AND has no uncommitted changes AND its branch has no commits ahead of origin/main (sub-agent worktrees are typically ephemeral and orphaned after the agent finishes)A worktree is bloated if it is not stale (so we can't just remove it) but contains regeneratable build artifacts taking significant disk space. Check each non-stale worktree for:
node_modules/ (typically ~1.8GB)target/ (Rust build cache, typically ~1.4GB)dist/ (compiled TS output).codegraph/graph.db* (rebuildable via codegraph build) — measure only the graph.db and graph.db-journal files, not the whole .codegraph/ directory, because cleanup in §1e only removes those files. Measuring the whole directory would overstate the freed space.For each worktree, sum the artifact sizes and emit a per-worktree subtotal so the 500MB threshold can be evaluated without manually regrouping flat output. Uses du -sk (kilobytes) with sort -n for portability — sort -h is GNU-only and breaks on stock macOS.
for wt in .claude/worktrees/*/; do
total_kb=0
breakdown=""
for sub in node_modules target dist; do
if [ -d "$wt$sub" ]; then
# 2>/dev/null suppress: the dir can vanish between the glob and this du (e.g. concurrent cleanup) — skip it, don't fail the scan
sz=$(du -sk "$wt$sub" 2>/dev/null | awk '{print $1}')
[ -n "$sz" ] && total_kb=$((total_kb + sz)) && breakdown="$breakdown $sub=${sz}K"
fi
done
# .codegraph: only measure the two files we will actually remove
for f in "$wt.codegraph/graph.db" "$wt.codegraph/graph.db-journal"; do
if [ -f "$f" ]; then
# 2>/dev/null suppress: same rationale as the node_modules/target/dist loop above — a vanished file mid-scan is skipped, not fatal
sz=$(du -sk "$f" 2>/dev/null | awk '{print $1}')
[ -n "$sz" ] && total_kb=$((total_kb + sz)) && breakdown="$breakdown $(basename "$f")=${sz}K"
fi
done
[ "$total_kb" -gt 0 ] && printf "%d\t%s\t%s\n" "$total_kb" "$wt" "$breakdown"
done | sort -n | awk -F'\t' '{
k=$1;
if (k >= 1048576) printf "%.1fG\t%s%s\n", k/1048576, $2, $3;
else if (k >= 1024) printf "%.1fM\t%s%s\n", k/1024, $2, $3;
else printf "%dK\t%s%s\n", k, $2, $3;
}'
Flag any worktree whose combined build artifact size exceeds 500MB (512000 kilobytes).
For orphaned directories (on disk but not in git worktree list):
Critical: orphaned directories may still contain uncommitted work. A worktree's git registration can be dropped (failed
git worktree add, manualgit worktree prune, etc.) while the user's source edits remain on disk.rm -rfon such a directory is permanent data loss.
Before offering removal, run git -C <path> status --short to check for uncommitted changes:
# NOTE: iterate with `while IFS= read -r dir`, never `for dir in $ORPHANED_DIRS` —
# the Bash tool in Claude Code runs under zsh, which does NOT word-split an
# unquoted multi-line variable the way bash does. `for dir in $ORPHANED_DIRS`
# would silently collapse every orphaned directory into a single iteration
# whose $dir is the whole newline-joined blob, breaking `git -C "$dir"` the
# moment more than one orphaned directory exists.
printf '%s\n' "$ORPHANED_DIRS" | while IFS= read -r dir; do
[ -z "$dir" ] && continue
if [ -d "$dir/.git" ] || [ -f "$dir/.git" ]; then
# 2>/dev/null suppress: best-effort only — a failed git check on a non-worktree directory is expected and harmless here
changes=$(git -C "$dir" status --short 2>/dev/null)
if [ -n "$changes" ]; then
echo "SKIP $dir — has uncommitted changes:"
echo "$changes" | sed 's/^/ /'
continue
fi
fi
# Safe to offer removal — confirm with user first
echo "ORPHANED (clean): $dir"
done
Only after confirming the directory is clean (no uncommitted changes) AND the user has explicitly approved removal, run rm -rf <path>. Then run git worktree prune to clear any dangling refs. Apply the same "Never force-remove a worktree with uncommitted changes" rule that protects stale worktrees in git worktree list — orphaned dirs get the same guardrail.
For prunable worktrees (in list but directory missing):
git worktree prune
For stale worktrees with merged branches:
--fullgit worktree remove "<path>"
git branch -d "<branch>" # only if fully merged
For bloated (non-stale) worktrees:
npm install / cargo build / codegraph buildrm -rf "<worktree>/node_modules"
rm -rf "<worktree>/target"
rm -rf "<worktree>/dist"
rm -f "<worktree>/.codegraph/graph.db" "<worktree>/.codegraph/graph.db-journal"
npm install / cargo clean inside the target worktree — it may be in use by another Claude Code sessionIf DRY_RUN: List everything that would be removed with sizes, don't do it.
Never force-remove a worktree with uncommitted changes. List it as "has uncommitted work" and skip — but still report its disk size so the user knows what it's costing. Never delete source files in a bloated worktree — only delete the four regeneratable artifact paths above.
Exit condition: worktree disk usage has been reported; every worktree is classified (orphaned / stale / bloated / active) with confirmed removals and artifact cleanups completed outside DRY_RUN.
Remove temporary and generated files that accumulate over time. There are two distinct categories of dirt that require different discovery commands:
.gitignore patterns — e.g. coverage/, .DS_Store, *.log, .codegraph/graph.db-journal): use git clean -fdX --dry-run to list them. git ls-files --others --exclude-standard silently omits these because --exclude-standard suppresses gitignored entries..gitignore — e.g. *.tmp.*, *.bak, *.orig): use git ls-files --others --exclude-standard to list them.Run both commands and union the results to get the full set of candidate dirt files.
Search for and remove files found by the two discovery commands above (never touch tracked files):
*.tmp.*, *.bak, *.orig files in the repo (but NOT in node_modules/).DS_Store files*.log files in repo root (not in node_modules/).codegraph/, .claude/, node_modules/)coverage/ directory (regenerated by npm run test:coverage).codegraph/graph.db-journal (SQLite WAL leftovers)Stale lock files (.codegraph/*.lock older than 1 hour): Before removing, first check if lsof is available (command -v lsof). If lsof is not installed (common in Docker/CI minimal containers where it exits 127), skip lock file removal entirely and print a warning: "lsof not available — skipping lock file cleanup (cannot verify no process holds the file)". When lsof IS available, use lsof "$f" to verify no process holds the file. If the file is held, skip it and warn — concurrent Claude Code sessions may hold legitimate long-lived locks.
# > /dev/null 2>&1: suppress command path on success and shell's "not found" on failure — the else branch reports the skip explicitly
if ! command -v lsof > /dev/null 2>&1; then
echo "lsof not available — skipping lock file cleanup (cannot verify no process holds the file)"
else
for f in .codegraph/*.lock; do
[ -f "$f" ] || continue
# 2>/dev/null suppress: BSD vs GNU stat take different flags — try GNU syntax first, fall back to BSD
age=$(( $(date +%s) - $(stat --format='%Y' "$f" 2>/dev/null || stat -f '%m' "$f" 2>/dev/null) ))
[ -z "$age" ] && continue
# > /dev/null 2>&1: suppress lsof's own output — only its exit code (held vs free) matters here
if [ "$age" -gt 3600 ] && ! lsof "$f" > /dev/null 2>&1; then
if [ "$DRY_RUN" = "true" ]; then
echo "[DRY RUN] Would remove stale lock: $f"
else
echo "Removing stale lock: $f"
rm "$f"
fi
elif [ "$age" -gt 3600 ]; then
echo "Lock file $f is old but still held by a process — ask user before removing"
fi
done
fi
Find untracked files (both gitignored and non-ignored) larger than 1MB. Use both discovery commands and union the paths:
# Non-ignored untracked files
git ls-files --others --exclude-standard | while read f; do
# 2>/dev/null suppress: BSD vs GNU stat take different flags — try GNU syntax first, fall back to BSD; a genuine failure just yields empty $size and is skipped below
size=$(stat --format='%s' "$f" 2>/dev/null || stat -f '%z' "$f" 2>/dev/null)
[ -z "$size" ] && continue
if [ "$size" -gt 1048576 ]; then echo "$f ($size bytes)"; fi
done
# Gitignored files (strip the leading "Would remove " prefix from dry-run output)
git clean -fdX --dry-run | sed 's/^Would remove //' | while read f; do
# Skip directory entries — stat returns inode size, not content size
[ -d "$f" ] && continue
# 2>/dev/null suppress: BSD vs GNU stat fallback, same rationale as above
size=$(stat --format='%s' "$f" 2>/dev/null || stat -f '%z' "$f" 2>/dev/null)
[ -z "$size" ] && continue
if [ "$size" -gt 1048576 ]; then echo "$f ($size bytes) [gitignored]"; fi
done
Flag these for user review — they might be accidentally untracked binaries.
If DRY_RUN: List all files that would be removed with their sizes.
Otherwise:
Never delete files that are tracked by git. Only clean untracked/ignored files.
Exit condition: known dirt patterns have been removed (or listed, under DRY_RUN); large untracked files have been flagged for the user, never deleted automatically.
git fetch origin
git log HEAD..origin/main --oneline
If main has new commits:
git pull --no-rebase origin maingit merge origin/main (never rebase — per project rules)List local branches that have diverged from their remote tracking branch:
git for-each-ref --format='%(refname:short) %(upstream:track)' refs/heads/
Flag any branches marked [ahead N, behind M] — these may need attention.
Exit condition: the local branch's relationship to origin/main has been reported; main has been pulled only if it was already checked out and new commits exist; diverged branches have been flagged, not acted on.
git branch --merged origin/main
Branches that are:
main itselfgit worktree list)git remote prune origin
This removes local refs to branches that no longer exist on the remote.
If DRY_RUN: List branches that would be deleted.
Otherwise: For each merged branch, ask the user for confirmation before deleting:
Delete merged branch '<branch>'? (y/n)
If confirmed, delete the branch:
git branch -d "<branch>" # safe delete, only if fully merged
Never use
git branch -D(force delete). If-dfails, the branch has unmerged work — skip it. Always confirm before deleting — consistent with worktree removal in Phase 1c.
Exit condition: every fully-merged, non-protected branch has had a confirmed delete decision (or been listed under DRY_RUN); stale remote-tracking refs have been pruned.
Skip if SKIP_UPDATE is set.
Source-repo guard: This phase is only meaningful when codegraph is installed as a dependency of a consumer project. Because the pre-flight confirms we are inside the codegraph source repo (
"name": "@optave/codegraph"), comparing the dev version to the published release and runningnpm installwould be a no-op — codegraph is not one of its own dependencies. Skip this entire phase when running inside the source repo and print:Codegraph: skipped (running inside source repo — update via git pull / branch sync instead)
Exit condition: either the phase was skipped (source-repo guard or SKIP_UPDATE) and that is printed, or codegraph's version status has been reported.
Quick health checks to catch issues:
npx codegraph stats
If the graph is stale (built from a different commit), rebuild:
npx codegraph build
npm ls --depth=0 2>&1 | grep -cE "missing|invalid|WARN"
If issues found: npm install to fix.
git fsck --no-dangling 2>&1 | head -20
Flag any errors (rare but important).
Exit condition: graph integrity, node-modules integrity, and git integrity have each produced a pass/fail result.
Print a summary to the console (no file needed — this is a local maintenance task):
=== Housekeeping Report ===
Worktrees: total .claude/worktrees/ size 57G (32 worktrees)
removed 2 stale (4.2G freed), 1 has uncommitted work (skipped)
cleaned build artifacts in 3 active worktrees (9.6G freed)
Dirt files: cleaned 5 temp files (12KB), 1 large untracked flagged
Branches: pruned 3 merged branches, 2 remote refs
Main sync: up to date (or: 4 commits behind — merge suggested)
Codegraph: v3.1.2 → v3.1.3 updated (or: already latest)
Graph: rebuilt (was stale) (or: fresh)
Node mods: OK (or: fixed 2 missing deps)
Git: OK
Status: CLEAN ✓
Always include the worktree total at the top of the Worktrees line, even when no worktrees were removed. This is the metric that surfaces hidden disk bloat — without it, multi-GB worktree accumulations go invisible to the user.
If DRY_RUN: prefix with [DRY RUN] and show what would happen without doing it.
Exit condition: the report above has been printed; nothing further runs after it.
/housekeep — full local cleanup: prune stale/bloated worktrees, remove regeneratable dirt, sync with main, prune merged branches, verify health./housekeep --dry-run — preview everything above with zero changes./housekeep --skip-update — run the cleanup phases but skip the codegraph-version-check phase.git branch -d, git worktree remove)node_modules/, target/, dist/, .codegraph/graph.db*). Never touch source files in a worktree you don't own--dry-run is sacred — it must NEVER modify anything, only report