/cleanup
Repo/branch/file hygiene sweep — stray artifacts, doc drift, stale branches, worktrees, upstream sync, backup sprawl, duplicate build caches. Verifies before purging.
Command definition
cleanup.mddescription: Repo/branch/file hygiene sweep — stray artifacts, doc drift, stale branches, worktrees, upstream sync, backup sprawl, duplicate build caches. Verifies before purging.
allowed-tools: Bash, Read, Edit, Write
argument-hint: [dry-run|full] (default: full)
/cleanup — amux file cleanup & consolidation routine
A repeatable hygiene sweep for this repo and this box's `~/.amux` state. Built from a real cleanup session (2026-08-30) that found: a 37MB binary accidentally committed, a security-sensitive file (`CLAUDE.local.md`) pushed to a public fork, a live systemd script left untracked, a doc file independently drifting in **three** places, 6 stale branches, 2 worktrees for merged PRs, 17 accumulated backup-file generations, and — in a follow-up pass the same day — 5.9GB of pure disk waste: duplicate cargo `target/` dirs in every PR worktree (the shared-target config is gitignored, so worktrees never inherit it) plus stale manual binary backups nobody cleaned up. None of that was hypothetical — every category below is something that actually happened here, not a theoretical checklist.
**Golden rule, stated explicitly because it was tested and mattered:** verify before you purge. "Looks like a duplicate" and "confirmed byte-for-byte subset with a diff/comm check" are different claims — only act on the second. If a branch or file MIGHT hold unique value, flag it and stop; don't delete on a hunch. (The user's own framing: "old stuff can be purged but always double check.")
---
1. Tracked-file hygiene (repo)
# Find large tracked blobs that don't belong (compiled binaries, dumps)
git ls-files -z | xargs -0 du -b 2>/dev/null | sort -rn | head -20
# Cross-check: does anything live/running depend on a file that's
# UNTRACKED? (systemd ExecStart, cron, launchd plist — the audit trail
# must be real, ethos rule 6)
systemctl --user list-units --all 2>/dev/null | grep -oP '(?<=ExecStart=)\S+' 2>/dev/null
# or: systemctl --user cat <unit> | grep ExecStart
# then: git ls-files <that path> — empty means a fresh clone breaks
**Security check — do this every time, not just when something looks wrong:** grep tracked files for names that match your own "never commit this" conventions (`CLAUDE.local.md`, `*.env`, `*secrets*`, `*credentials*`, anything your `.gitignore` comments call out as sensitive) and confirm `.gitignore` actually covers them:
git ls-files | grep -iE 'local\.md$|\.env$|secret|credential|\.key$|\.pem$'
# for each hit, check: is it supposed to be here?
git check-ignore -v <path> # empty = NOT ignored, even if it should be
If something sensitive is tracked and already pushed: `git rm --cached` + add to `.gitignore` + commit stops it from being carried forward. That does **not** scrub it from history on a remote it already reached — flag that explicitly and let the human decide about a history rewrite (rewriting a shared/in-review branch is disruptive; not a unilateral call).
**After adding a gitignore entry, verify the COMMIT, not the working tree.** `git show HEAD:.gitignore | tail` — not `tail .gitignore`. Editing the file and reporting "added to .gitignore" without an explicit `git add .gitignore` is a real, repeatable mistake (happened twice in the same session here): the commit only contains what got staged, and a later `git reset --hard` silently drops the uncommitted rest with no error at all. `git status`'s summary line does not catch this when the same pass also has a staged deletion — check the actual diff that's about to be committed (`git diff --cached --stat`), not just that *something* is staged.
**If the human authorizes a history rewrite, scope it to exactly the affected commit range — do not process full history.** `git filter-repo` run without `--refs` restriction processes every reachable commit and can reassign NEW HASHES even to commits whose tree never changed (its default merge-simplification touches the whole graph) — this silently moves the branch's merge-base with `main`, and a locally-clean rewrite can still turn into spurious PR conflicts that have nothing to do with the actual fix. `git filter-branch --index-filter '...' -- <bad-commit>^..HEAD` (note the revision range after `--`) only touches commits in that range; everything before it, including the true shared ancestor with `main`, keeps its original hash. **Verify before pushing, every time:**
# merge-base must be IDENTICAL before and after the rewrite
git merge-base <old-ref> origin/main
git merge-base <rewritten-ref> origin/main
# and a real merge test should show 0 conflicts against the SAME origin/main
# snapshot the old branch was tested against (it may have moved since —
# check git log <old-merge-base>..origin/main for genuinely new, unrelated
# conflicts before blaming the rewrite for something upstream drift caused)
git merge-tree $(git merge-base <rewritten-ref> origin/main) <rewritten-ref> origin/main | grep -c '^<<<<<<<'
Tag the pre-rewrite tip locally (never pushed) before starting, so a wrong rewrite has a clean recovery path.
2. Doc/skill drift
The same fact living in more than one file is checked, not assumed — this codebase's own rule ("never a second copy of the same fact") applies to prose as much as code:
# Any obviously-paired doc files (same basename, different dirs)?
find . -iname "amux.md" -o -iname "README.md" 2>/dev/null | grep -v node_modules
diff <(cat copy1) <(cat copy2) # if near-identical, consolidate
# Is a user-level copy (~/.claude/commands/, ~/.claude/skills/) shadowing
# a project one for lanes whose CWD isn't this repo? Compare both:
diff ~/.claude/commands/<name>.md .claude/commands/<name>.md
**Fix at the root, not by re-syncing every time:** if two files are supposed to always match, make one a symlink to the other so drift is structurally impossible, not just corrected once. For a *repo* file with a *user-level* fallback (different lanes, different CWDs), there's no symlink across t
Read more
description: Repo/branch/file hygiene sweep — stray artifacts, doc drift, stale branches, worktrees, upstream sync, backup sprawl, duplicate build caches. Verifies before purging. allowed-tools: Bash, Read, Edit, Write argument-hint: [dry-run|full] (default: full)
/cleanup — amux file cleanup & consolidation routine
A repeatable hygiene sweep for this repo and this box's `~/.amux` state. Built from a real cleanup session (2026-08-30) that found: a 37MB binary accidentally committed, a security-sensitive file (`CLAUDE.local.md`) pushed to a public fork, a live systemd script left untracked, a doc file independently drifting in **three** places, 6 stale branches, 2 worktrees for merged PRs, 17 accumulated backup-file generations, and — in a follow-up pass the same day — 5.9GB of pure disk waste: duplicate cargo `target/` dirs in every PR worktree (the shared-target config is gitignored, so worktrees never inherit it) plus stale manual binary backups nobody cleaned up. None of that was hypothetical — every category below is something that actually happened here, not a theoretical checklist.
**Golden rule, stated explicitly because it was tested and mattered:** verify before you purge. "Looks like a duplicate" and "confirmed byte-for-byte subset with a diff/comm check" are different claims — only act on the second. If a branch or file MIGHT hold unique value, flag it and stop; don't delete on a hunch. (The user's own framing: "old stuff can be purged but always double check.")
---
1. Tracked-file hygiene (repo)
# Find large tracked blobs that don't belong (compiled binaries, dumps) git ls-files -z | xargs -0 du -b 2>/dev/null | sort -rn | head -20 # Cross-check: does anything live/running depend on a file that's # UNTRACKED? (systemd ExecStart, cron, launchd plist — the audit trail # must be real, ethos rule 6) systemctl --user list-units --all 2>/dev/null | grep -oP '(?<=ExecStart=)\S+' 2>/dev/null # or: systemctl --user cat <unit> | grep ExecStart # then: git ls-files <that path> — empty means a fresh clone breaks
**Security check — do this every time, not just when something looks wrong:** grep tracked files for names that match your own "never commit this" conventions (`CLAUDE.local.md`, `*.env`, `*secrets*`, `*credentials*`, anything your `.gitignore` comments call out as sensitive) and confirm `.gitignore` actually covers them:
git ls-files | grep -iE 'local\.md$|\.env$|secret|credential|\.key$|\.pem$' # for each hit, check: is it supposed to be here? git check-ignore -v <path> # empty = NOT ignored, even if it should be
If something sensitive is tracked and already pushed: `git rm --cached` + add to `.gitignore` + commit stops it from being carried forward. That does **not** scrub it from history on a remote it already reached — flag that explicitly and let the human decide about a history rewrite (rewriting a shared/in-review branch is disruptive; not a unilateral call).
**After adding a gitignore entry, verify the COMMIT, not the working tree.** `git show HEAD:.gitignore | tail` — not `tail .gitignore`. Editing the file and reporting "added to .gitignore" without an explicit `git add .gitignore` is a real, repeatable mistake (happened twice in the same session here): the commit only contains what got staged, and a later `git reset --hard` silently drops the uncommitted rest with no error at all. `git status`'s summary line does not catch this when the same pass also has a staged deletion — check the actual diff that's about to be committed (`git diff --cached --stat`), not just that *something* is staged.
**If the human authorizes a history rewrite, scope it to exactly the affected commit range — do not process full history.** `git filter-repo` run without `--refs` restriction processes every reachable commit and can reassign NEW HASHES even to commits whose tree never changed (its default merge-simplification touches the whole graph) — this silently moves the branch's merge-base with `main`, and a locally-clean rewrite can still turn into spurious PR conflicts that have nothing to do with the actual fix. `git filter-branch --index-filter '...' -- <bad-commit>^..HEAD` (note the revision range after `--`) only touches commits in that range; everything before it, including the true shared ancestor with `main`, keeps its original hash. **Verify before pushing, every time:**
# merge-base must be IDENTICAL before and after the rewrite git merge-base <old-ref> origin/main git merge-base <rewritten-ref> origin/main # and a real merge test should show 0 conflicts against the SAME origin/main # snapshot the old branch was tested against (it may have moved since — # check git log <old-merge-base>..origin/main for genuinely new, unrelated # conflicts before blaming the rewrite for something upstream drift caused) git merge-tree $(git merge-base <rewritten-ref> origin/main) <rewritten-ref> origin/main | grep -c '^<<<<<<<'
Tag the pre-rewrite tip locally (never pushed) before starting, so a wrong rewrite has a clean recovery path.
2. Doc/skill drift
The same fact living in more than one file is checked, not assumed — this codebase's own rule ("never a second copy of the same fact") applies to prose as much as code:
# Any obviously-paired doc files (same basename, different dirs)? find . -iname "amux.md" -o -iname "README.md" 2>/dev/null | grep -v node_modules diff <(cat copy1) <(cat copy2) # if near-identical, consolidate # Is a user-level copy (~/.claude/commands/, ~/.claude/skills/) shadowing # a project one for lanes whose CWD isn't this repo? Compare both: diff ~/.claude/commands/<name>.md .claude/commands/<name>.md
**Fix at the root, not by re-syncing every time:** if two files are supposed to always match, make one a symlink to the other so drift is structurally impossible, not just corrected once. For a *repo* file with a *user-level* fallback (different lanes, different CWDs), there's no symlink across t
The agent control plane: run Claude Code, Codex and Gemini CLI agents in parallel with a shared task board, schedules and usage-limit recovery. Native iPhone, iPad and Mac apps plus a web dashboard. Self-host (Rust + SQLite, Tailscale remote access) or use amux Cloud. MIT + Commons Clause.
Other commands on amux.
More commands from other plugins.
build
CommandImplement tasks incrementally — build, test, verify, commit. Add "auto" to run the whole plan in one approved pass.

