disk-cleanup
disk-cleanup
macOS disk space recovery — inventory, prune caches/dev junk, archive apps/SDKs to external drive. Trigger when the user asks to "clean up space", "free disk", "make room", or shows a near-full disk.
Unzip into your Claude skills directory (e.g. ~/.claude/skills/) or your project's .claude/skills/ to use it.
macOS disk-cleanup runbook
Goal: free space without losing data. Cache-class items are auto-deleted; user data is always confirmed.
1. Inventory (always start here)
df -h / # current free
du -sh ~/* 2>/dev/null | sort -h | tail -20
du -sh ~/Library/* 2>/dev/null | sort -h | tail -15
du -sh ~/Library/Application\ Support/* 2>/dev/null | sort -h | tail -15
du -sh ~/Library/Caches/* 2>/dev/null | sort -h | tail -15If APFS local snapshots may be holding space:
tmutil listlocalsnapshots /
diskutil apfs listSnapshots /Snapshots labelled com.apple.os.update-* are purged automatically under pressure.
2. Safe automatic deletions (no confirmation needed)
These all regenerate on next use:
# Browser caches (only if browser closed — check with `pgrep -l "Google Chrome|firefox"`)
rm -rf ~/Library/Caches/Google ~/Library/Caches/Firefox
# Build / dev tool caches
npm cache clean --force
pnpm store prune
rm -rf ~/Library/Caches/{go-build,CocoaPods,pip,pnpm,Homebrew,node-gyp,ms-playwright,ms-playwright-go}
# Apple system caches
rm -rf ~/Library/Caches/SiriTTS ~/Library/Caches/GeoServices
# Xcode (often biggest dev win)
rm -rf ~/Library/Developer/Xcode/DerivedData
rm -rf ~/Library/Developer/Xcode/iOS\ DeviceSupport
rm -rf ~/Library/Developer/CoreSimulator # iOS simulator data
# KEEP ~/Library/Developer/Xcode/Archives — release builds
# Wallpaper aerial videos (regenerate on demand)
rm -rf ~/Library/Application\ Support/com.apple.wallpaper/aerials
# Electron app caches (apps not running)
rm -f ~/Library/Application\ Support/Claude/state.vscdb.backup
rm -rf ~/Library/Application\ Support/Claude/vm_bundles # Claude Code sandbox VM image, ~10GB, re-downloads3. Confirmation required (data loss / re-auth risk)
Always ask before:
~/Library/Application Support/Notion/Partitions— re-login, loses offline content (1-2 GB)~/Library/Application Support/<app>/Partitions(other Electron apps) — same pattern~/.Trash— empty Trash only with explicit OK~/Library/Application Support/Cursorand similar — chat/session local statenode_modules— list with last-modified date, propose only dirs ≥60 days dormant- Uninstalled-app leftovers (digikam, GarageBand, Logic) — verify the app is truly gone
Dormancy check for node_modules:
find ~/Coding -name node_modules -type d -prune 2>/dev/null | while read d; do
parent=$(dirname "$d")
mtime=$(stat -f "%Sm" -t "%Y-%m-%d" "$parent")
size=$(du -sh "$d" | cut -f1)
echo "$mtime $size $parent"
done | sort4. Archiving large apps to external drive
Use ditto (preserves bundle metadata + code signature). Standard pattern:
ditto -c -k --sequesterRsrc --keepParent \
"/Applications/<App>.app" \
"/Volumes/LaCie/Applications-Archive/<App>.zip"
# Verify
unzip -tq "/Volumes/LaCie/Applications-Archive/<App>.zip" && echo OK
# Delete original (most apps need sudo)
sudo rm -rf "/Applications/<App>.app"A restore script is at /Volumes/LaCie/Applications-Archive/restore.sh — runs ditto -x -k and strips quarantine.
5. Moving an SDK to LaCie system-wide
For Flutter, Node, etc. — keep on external drive, available to all users:
sudo mv /path/to/sdk /Volumes/LaCie/Development/<sdk>
sudo chown -R root:wheel /Volumes/LaCie/Development/<sdk>
sudo chmod -R a+rX /Volumes/LaCie/Development/<sdk>
echo "/Volumes/LaCie/Development/<sdk>/bin" | sudo tee /etc/paths.d/<sdk>For tool caches that need to be writable (PUB_CACHE, npm prefix, etc.):
sudo mkdir -p /Volumes/LaCie/Development/.<cache>
sudo chmod 1777 /Volumes/LaCie/Development/.<cache> # sticky like /tmp
echo 'export <VAR>="/Volumes/LaCie/Development/.<cache>"' | sudo tee -a /etc/zshenv/etc/zshenv loads in every zsh session (login + non-login). /etc/paths.d/ is read by path_helper. Both system-wide.
6. Cleaning another user account
If another user account on the same Mac has space hogs, the agent's sandbox blocks cross-account writes even with sudo. Two approaches:
A — User provides one-liners themselves (recommended for app data):
Give them a sudo rm -rf … command targeting the other account.
B — Scoped NOPASSWD sudoers entry (for read-only inventory and safe cache cleanup):
sudo tee /etc/sudoers.d/claude-cleanup <<'EOF'
<user> ALL=(ALL) NOPASSWD: /usr/bin/du, /bin/ls, /bin/rm, /bin/cat
EOF
sudo chmod 440 /etc/sudoers.d/claude-cleanupThen sudo -n du …, sudo -n ls …, sudo -n rm -rf … work without password.
Even with this, the agent sandbox may still block app-data deletes on another user — caches/dev-junk usually pass. For app data, fall back to (A).
Remove the sudoers file when done:
sudo rm /etc/sudoers.d/claude-cleanup7. Pitfalls to avoid
- Cross-volume
mviscp+rm— sockets and special files won't copy; check stderr forsockets not copiedwarnings, normally fine to ignore. - APFS snapshots can hold deleted space briefly (
com.apple.os.update-*). They purge under pressure; don't force-delete. - SQLite over USB: never symlink an active SQLite DB (Cursor's
state.vscdb, etc.) to an external drive — risk of corruption on disconnect. Use snapshot-copy instead, or move only after the app has been uninstalled. - Don't touch
~/.claude/projects/— Claude Code session JSONL transcripts. du -shsilently truncates on permission-denied subdirs; for accurate size on another user's home, run viasudo.- **Hooks may interpret
Bash(sudo:)permission rule* as broadly granting sudo to the agent; combine with a narrowsudoers.dentry to bound real privilege.
8. Verifying the result
df -h /
diskutil info / | grep -iE "purg|free|avail" # confirms no snapshot phantom