Mac Disk Reclaim
Two phases: discover (read-only) then interactive delete (confirm each, direct delete).
macOS only. The scanner never surfaces user data — Documents, Photos, Mail, Keychains, Containers app data, iCloud, the system volume are off-limits. It deletes nothing itself.
Phase 1 — Discover
python3 scripts/scan_reclaimable.py --json # --min-mb N raises the floor (default 200)
It does not rely on a fixed path list. It finds bloat by category, including the distributed kind a "largest folders" scan misses (each item moderate, sum huge):
build — node_modules / target / build / dist / .next / .venv / pycache across every project
cache — tool + Electron app caches (Cache / Code Cache / GPUCache under Application Support)
browser-cache — Chrome/Brave/Vivaldi/Firefox caches
agent — Claude/Codex conversation history & log DBs (permanent — review)
ai-models — ollama / Hugging Face weights (re-downloadable, large)
git-gc — bloated .git objects → git gc (repacks, loses nothing)
worktree — git worktrees whose branch is already merged → git worktree remove
dsstore — thousands of .DS_Store files
trash — ~/.Trash and per-volume .Trashes
Each finding carries size, risk (low/med), and a one-line consequence (desc): what regenerates vs what is lost for good. Also returns a snapshot_note for Time Machine local snapshots. Tell the user the total and the top items first.
Phase 2 — Interactive delete (largest first)
Each finding carries key and remembered (delete / skip / null). Choices persist in ~/.config/mac-disk-reclaim/decisions.json (never swept by this skill), so a later run only asks about new items.
First, split findings by remembered (and reconfirm):
remembered: "delete" and reconfirm: false — previously approved, safely
regenerates. Reclaim each (step 4) without re-asking; state count + total up front so the user can abort.
remembered: "delete" and reconfirm: true — approved before but lossy
(med-risk, or a --volumes prune). Always re-ask anyway; memory never auto-runs an irreversible command.
remembered: "skip" — previously declined. Do not touch, do not ask. Mention the
count only.
remembered: null — new. Ask interactively (below).
For each new item, in size order:
- Show:
size · category · path, the desc consequence, and the risk. For
risk: med (agent history, AI models) state plainly it does not come back.
- Ask: delete / skip / stop. Wait. Never batch.
- Persist the choice so the next run skips it:
``bash python3 scripts/decisions.py set "<key>" delete --path "<path>" --category "<category>" python3 scripts/decisions.py set "<key>" skip --path "<path>" --category "<category>" ``
- On
delete, reclaim it:
- method: cmd → run the item's cmd (the tool's own cleanup, e.g. git gc, git worktree remove, brew cleanup --prune=all, docker system prune -af --volumes, find ~ -name .DSStore -delete). - method: rm → delete through the guard (refuses danger paths): ``bash python3 scripts/safedelete.py "<path>" --yes `` Deletion is direct and permanent — not Trash. Confirm the user knows this once, up front.
- Report freed space, continue.
Finish by offering the snapshot_note command (sudo tmutil thinlocalsnapshots …).
Memory controls: --no-memory on the scan reviews everything fresh; decisions.py list shows saved choices; decisions.py forget <key> / --all clears them.
Swap
Swap cannot be flushed on a running Mac. /private/var/vm swapfiles are kernel-managed (encrypted on Apple Silicon); deleting them risks a panic. sudo purge frees inactive RAM, not swap. Only a reboot clears swap. Report this; never offer to touch it.
Notes
- The scan uses only
du/find (always present). For faster discovery the user can
brew install dust; for a turnkey cleaner, mac-cleanup-py — but neither does this skill's per-item-confirmed direct delete.
- Never delete anything the scanner did not surface; never hand a typed path to
safe_delete.py.
- If
safe_delete.py blocks a path, do not work around it.