computer-clean · v1.1.0 · 2026-08-12 · sha256 dcb889b439ae980e

computer-clean v1.1.0B

Immutable. This exact content is served forever at /api/v1/blob/dcb889b439ae980e.

---
name: computer-clean
description: "Audit and reclaim disk space on macOS. Discovers cache hogs, dev caches, dead app data, old Downloads, dup installers, and obsolete container/VM images. Use when user says 'clean disk', 'free up space', 'computer-clean', 'cleanup mac', 'disk full', or shows ≥85% disk usage."
category: utilities
keywords: [disk, cleanup, space, cache, mac, macos, prune, storage]
metadata:
  version: "1.1.0"
---

# Computer Clean - macOS Disk Cleanup

Goal: surface the largest reclaimable space on the user's Mac, classify by risk, **always confirm before destructive ops**, then execute.

## Operating principle

**Audit → Classify → Confirm → Execute → Verify.** Never skip the confirm step for 🟡/🔴 buckets. The 🟢 cache bucket can run after a single user "go".

The skill **discovers** what's actually on the user's machine - don't assume specific apps/caches exist. Run audit commands first, then classify what was found.

---

## Phase 1 - Audit (read-only)

Run these in parallel. Report top consumers per bucket.

```bash
# Volume stats
df -h /

# Home Library hot zones
du -sh ~/Library/Caches ~/Library/Logs ~/Library/Containers \
       ~/Library/Application\ Support ~/Downloads ~/.Trash 2>/dev/null

# Drill the heavy ones - top 15 each
du -sh ~/Library/Application\ Support/* 2>/dev/null | sort -rh | head -15
du -sh ~/Library/Caches/* 2>/dev/null | sort -rh | head -15
du -sh ~/Library/Containers/* 2>/dev/null | sort -rh | head -10
du -sh ~/Downloads/* 2>/dev/null | sort -rh | head -15

# Common dev caches outside Library (skip silently if missing)
du -sh ~/.npm ~/.yarn ~/.pnpm-store ~/Library/pnpm \
       ~/go/pkg ~/.cargo ~/.gradle ~/.m2 ~/.rustup \
       ~/.cache ~/.docker 2>/dev/null

# Drill ~/.cache children (uv, pip, puppeteer, pre-commit, etc.)
du -sh ~/.cache/* 2>/dev/null | sort -rh | head -15

# Xcode (developers only)
du -sh ~/Library/Developer/Xcode/{DerivedData,Archives,iOS\ DeviceSupport} 2>/dev/null
```

### Git worktree audit (developers)

Discover worktree roots read-only under existing development roots, then inspect each repository with `vd:worktree`:

```bash
for root in "$HOME/git" "$HOME/code" "$HOME/src" "$HOME/projects" \
           "$HOME/worktrees" "$HOME/Worktrees" "$HOME/repos" "$HOME/dev"; do
  [ -d "$root" ] || continue
  find "$root" -maxdepth 8 -type d \
    \( -name .worktrees -o -name worktrees \
       -o -path '*/.claude/worktrees' -o -path '*/.dmux/worktrees' \) \
    -print 2>/dev/null
done
```

Run `node "$HOME/skills/skills/worktree/scripts/worktree.cjs" clean` from each repository root. It is a dry run unless `--yes` is supplied, reports branch state and reclaimable size, and skips dirty worktrees unless `--force` is supplied.

## Phase 2 - Classify

Bucket discovered items by risk.

### 🟢 Safe (regenerable) - execute on single confirm

Standard regenerable caches. Apply only if path exists.

| Path / tool | Reclaim command |
|---|---|
| `~/.Trash/*` | `rm -rf ~/.Trash/* ~/.Trash/.[!.]*` |
| Homebrew | `brew cleanup -s --prune=all` |
| Go | `go clean -cache && go clean -modcache` (or `rm -rf ~/Library/Caches/go-build ~/go/pkg`) |
| npm | `npm cache clean --force` |
| pnpm | `pnpm store prune` |
| yarn | `yarn cache clean` |
| Cargo | `cargo cache --autoclean` (if `cargo-cache` installed) |
| Gradle | `rm -rf ~/.gradle/caches` |
| uv (Python) | `uv cache clean` (kill stuck `uv` first if locked, then `rm -rf ~/.cache/uv`) |
| pip | `pip cache purge` |
| Generic `~/.cache/<tool>` | `rm -rf` after confirming tool is regenerable (puppeteer, pre-commit, packer, etc.) |
| Old JetBrains caches (>1yr) | `rm -rf ~/Library/Caches/JetBrains/*<old-year>*` |
| App auto-updaters | `~/Library/Caches/*ShipIt*`, `~/Library/Caches/*.updater` |
| Xcode `DerivedData` | `rm -rf ~/Library/Developer/Xcode/DerivedData` (rebuilds on next compile) |

### 🟡 Git worktrees (project data) - confirm by cleanup mode

- Merged into the repository base: eligible for `clean merged` after a fresh dry run.
- Gone from the remote: eligible only for `clean all`; local-only commits may remain.
- Dirty worktrees: always skip; inspect and approve each path before any forced removal.
- Prunable Git metadata: report separately; it may reclaim no checkout space.

### 🟡 Review (user data, easy wins - confirm each)

- **Downloads**: `*.dmg`/`*.pkg`/`*.zip`/`*.rar`/`*.tar.gz` older than 30 days
- **Downloads**: duplicate installers matching `* (1).*`, `* (2).*`
- **Downloads**: stray data dumps (large CSVs, sample videos), abandoned project folders, leftover venvs
- **Apple Podcasts** episodes (auto-downloaded media, not subscriptions)
- **Mail attachments**: `~/Library/Mail/V*/MailData/Attachments` (re-downloadable from server)

### 🔴 Big-ticket (explicit per-item auth required)

- **Container engine VMs** - typically the largest single item. Confirm engine is unused (see Phase 4 migration check):
  - Docker Desktop: `~/Library/Containers/com.docker.docker/Data/vms`
  - OrbStack: `~/.orbstack/data`
  - Rancher Desktop: `~/Library/Application Support/rancher-desktop/lima`, `~/.rd`
  - Colima/Lima: `~/.colima`, `~/.lima`
  - Podman: `~/.local/share/containers`
- **Xcode** archives + simulators: `~/Library/Developer/Xcode/{Archives,iOS DeviceSupport,watchOS DeviceSupport}`, `~/Library/Developer/CoreSimulator`
- **Chat / messaging app data** (Slack, Teams, Discord, Zalo, WeChat, Telegram, Signal) - user-owned history
- **Browser profiles** (Chrome, Brave, Arc, Edge, Firefox, Safari, Vivaldi, etc.) - bookmarks/sessions/extensions live here
- **iOS device backups**: `~/Library/Application Support/MobileSync/Backup`
- **iCloud / Photos library**: `~/Pictures/Photos Library.photoslibrary`
- **Time Machine local snapshots**: `tmutil thinlocalsnapshots / 0 4`

## Phase 3 - Confirm

Present a single summary table (path · size · bucket) and ask:
1. Proceed with all 🟢? (default yes)
2. For 🟡: which to keep / delete?
3. For each 🔴: is the underlying app still in use? Run dependency checks (Phase 4) before approval.

For worktrees, accept these reusable approval aliases:

| User phrase | Action | Scope |
|---|---|---|
| `clean merged` or `clean merge` | `worktree.cjs clean --merged --yes` | Clean worktrees whose branches are merged into base |
| `clean all` | `worktree.cjs clean --yes` | Clean merged and stale/gone-from-remote worktrees; still skip dirty worktrees |

Always show the dry-run candidates and total size before applying either alias. Never infer approval for dirty paths from `clean all`.

## Phase 4 - Execute

### App-quit guard

Before deleting any app's data dir, quit the app cleanly:
```bash
osascript -e 'quit app "<App Name>"' 2>/dev/null; sleep 1
```

### Git worktree cleanup

Use `vd:worktree` commands from each repository root. Do not use `rm -rf` on a worktree. Refresh the dry run immediately before execution, pass `--yes` only after the matching approval alias, and never pass `--force` unless the user explicitly names the dirty worktree.

Before removing each candidate, check for active agent processes and open files:

```bash
ps -axo pid=,command= | rg -F "$WT" || true
lsof -nP +D "$WT" 2>/dev/null | head -50
```

If either command finds a process, stop and ask the user to close it. Do not kill agent processes automatically.

### Container engine migration (generic)

If user is decommissioning one engine in favor of another, **verify migration first**:

```bash
docker context ls                          # which engine is active (asterisk)
which docker                               # current binary
ls -la "$(which docker)"                   # follow symlink chain
/usr/bin/which -a docker                   # all docker binaries on PATH
kubectl config get-contexts                # k8s contexts that may be orphaned
grep -nE 'rancher|orbstack|colima|docker' ~/.zshrc ~/.zprofile ~/.bashrc ~/.bash_profile ~/.config/fish/config.fish 2>/dev/null
```

After confirmation, the removal pattern is:
1. Quit the app (`osascript -e 'quit app "..."'`).
2. `rm -rf` the app's `Application Support` data dir + dotfile dir under `$HOME` (e.g., `~/.rd`, `~/.colima`).
3. `rm -rf` its `Caches`, `Logs`, and `Preferences/<bundle-id>.*`.
4. `kubectl config delete-context/cluster/user <name>` for orphaned k8s contexts.
5. `rm -rf /Applications/<App>.app`.
6. Remind user to remove any `PATH` entries from shell rc files if grep found matches.

### Downloads sweep

```bash
# Duplicates created by re-downloads
find ~/Downloads -maxdepth 1 -type f \( -name '* (1).*' -o -name '* (2).*' -o -name '* (3).*' \) -delete

# Old installer payloads (>30d)
find ~/Downloads -maxdepth 3 -type f \
  \( -name '*.dmg' -o -name '*.pkg' -o -name '*.zip' -o -name '*.rar' -o -name '*.tar.gz' -o -name '*.tgz' \) \
  -mtime +30 -print -delete
```

### Apple Podcasts media purge

```bash
osascript -e 'quit app "Podcasts"' 2>/dev/null; sleep 1
find ~/Library/Group\ Containers/*.groups.com.apple.podcasts \
     ~/Library/Containers/com.apple.podcasts \
     -type f \( -name '*.mp3' -o -name '*.m4a' -o -name '*.mp4' \) -delete 2>/dev/null
```

### Files older than N months

Always **preview first** with `find … -print` before adding `-delete`. Show total size before deleting. Skip if <100MB total unless user insists. **Never** blanket-delete `~/Documents`, `~/Pictures`, `~/Movies`, or iCloud-synced paths.

## Phase 5 - Verify

```bash
df -h /                             # confirm space freed
node "$HOME/skills/skills/worktree/scripts/worktree.cjs" clean --merged 2>/dev/null
docker context show 2>/dev/null     # if container engines were touched
docker version --format '{{.Server.Version}}' 2>/dev/null
```

Report: GB freed, before/after free space, residual >5GB items the user declined (so they can revisit later).

---

## Hard rules

1. **Discover, don't assume.** Inspect the machine first - don't pre-supply paths that may not exist. Skip silently when paths are absent.
2. **Never** delete `~/Documents`, `~/Pictures`, `~/Movies`, iCloud Drive, or anything under `~/git`/`~/code`/`~/src`/`~/projects` without explicit per-path approval.
3. **Never** delete an app's `Application Support` while the app is running - quit it first.
4. **Never** wipe browser profiles. Bookmarks, sessions, history, extensions, saved passwords live there.
5. **Never** use `sudo` to bypass file locks. If a tool's cache is locked (e.g., `uv`, `pnpm`), kill the stuck process first.
6. **Container engines:** before deleting one engine's VM, verify the user has migrated to another via `docker context ls`, `kubectl config get-contexts`, and shell rc grep. State the migration target explicitly to the user.
7. **Surface skipped items** at the end so user can decide later - don't silently leave reclaimable space on the table.
8. **Adapt to what's there.** macOS evolves; new caches appear (LLM tool caches, Playwright/Cypress, Hugging Face, Ollama models). Apply the regenerable-cache heuristic: if it's recreated automatically on next use, it's 🟢.

## When to suggest `vd:computer-clean` proactively

End the message with a one-line offer when you notice:
- `df -h` capacity ≥ 85%
- Build/test failures with "no space left on device"
- User mentions "slow Mac", "running out of space", "can't update macOS", "Time Machine full"

Never auto-execute without confirmation.