# Cleanup Mac Storage

> Inspect macOS disk usage and safely reclaim space from development and app caches with explicit approval. Use for low disk space, large System Data, or targeted Mac cache cleanup, including inspection of Chrome profiles, Time Machine snapshots, and device backups.

- Skill: `natolambert/cleanup-mac-storage` (Agent Skill)
- Install (CLI): `npx skillmds@latest add natolambert/cleanup-mac-storage`
- Raw SKILL.md: https://api.skillmd.com/api/skills/natolambert/cleanup-mac-storage/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: natolambert (https://skillmd.com/u/natolambert)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/natolambert/cleanup-mac-storage

---


# Clean up Mac storage

Measure first, propose specific targets, clean only approved items, then measure
again. The commands below are a menu, not a script to run in full.

## Safety defaults

- Start read-only. Before deleting, show each exact path or tool-managed cache,
  its measured size, the destructive command, and what will be lost or downloaded
  again. Obtain explicit approval for those targets and impacts. A request to
  inspect storage or write cleanup instructions does not authorize deletion.
- Quit affected apps and stop model jobs, downloads, builds, and hooks before
  clearing their caches. Caches will be rebuilt or downloaded again; this costs
  time/bandwidth, can break offline workflows, and assumes the original content
  is still available. Preserve locally authored or irreplaceable files.
- Treat paths below as defaults, not proof of what is stored there. Check cache
  configuration and symlinks, inspect resolved paths, and use quoted, explicit
  targets. Never feed unchecked environment variables, globs, or discovery
  output directly to `rm -rf`. A directory named `Caches` can contain user state.
- Never blanket-delete `~/Library`, `~/.cache`, `~/Library/Caches`, Application
  Support, Chrome/Arc profiles, or MobileSync backups. Do not use `sudo rm`,
  disable macOS protections, or empty Trash as part of routine cache cleanup.
- Skip absent paths/tools; do not install or upgrade software just to inspect
  storage. Permission errors mean totals may be incomplete, not that a directory
  is empty. Report access limits; do not automatically elevate privileges.

## 1. Inspect storage

Use macOS/BSD `du` syntax. Start shallow and drill into large locations only.
Keep permission errors visible. `System Data` is a storage category, not a
directory to delete.

```bash
df -h "$HOME"
du -h -d 1 "$HOME/Library" | sort -h
du -h -d 1 "$HOME/.cache" | sort -h
du -h -d 1 "$HOME/Library/Caches" | sort -h
du -h -d 1 "$HOME/Library/Application Support" | sort -h

# Deeper inspection when needed:
du -h -d 2 "$HOME/Library" | sort -h | tail -40
du -h -d 2 "$HOME/.cache" | sort -h | tail -40
```

Make a short table of candidate, current size, contents, expected impact, and
proposed command. Do not reuse historical GB estimates or double-count parent
directories and their children. APFS snapshots, clones, and hard links can make
directory totals differ from space actually recoverable. If a cache resolves to
another volume, record `df -h` for that path too; deleting from an external disk
does not free internal storage.

## 2. Development caches

Resolve configured locations before measuring or removing anything:

| Cache | Location/configuration to check |
| --- | --- |
| Hugging Face | Usually `~/.cache/huggingface`; check `HF_HOME`, `XDG_CACHE_HOME`, `HF_HUB_CACHE`, `HF_DATASETS_CACHE`, `HF_XET_CACHE`, `HF_ASSETS_CACHE`, and legacy `TRANSFORMERS_CACHE` overrides. |
| uv | Use `uv cache dir`; respect `UV_CACHE_DIR` and uv configuration instead of assuming `~/.cache/uv`. |
| pre-commit | `PRE_COMMIT_HOME`, otherwise `${XDG_CACHE_HOME:-$HOME/.cache}/pre-commit`. |
| pip | Use the intended interpreter's `python3 -m pip cache dir` and `cache info`; respect `PIP_CACHE_DIR` and pip configuration. On macOS it is often `~/Library/Caches/pip`. |

Read only relevant path settings, not the entire environment or credential files.
Use the same environment/configuration for inspection and cleanup.

```bash
# Default-path examples; substitute resolved paths if configuration differs.
du -h -d 2 "$HOME/.cache/huggingface" | sort -h | tail -30
du -sh "$HOME/.cache/pre-commit"
uv cache dir
python3 -m pip cache dir
python3 -m pip cache info
```

Measure the exact directory returned by each tool with `du -sh` before proposing
cleanup. Check installed `--help` when command availability is uncertain.

### Hugging Face

`HF_HOME` also holds login tokens, including `token` and `stored_tokens`; do not
delete the whole root as routine cleanup. Preserve any configured `HF_TOKEN_PATH`
without reading its contents. Prefer the installed `hf cache` CLI
for Hub entries: inspect with supported `hf cache ls` / `hf cache prune --dry-run`,
then offer targeted `hf cache rm` or `hf cache prune` after approval, retaining
confirmation prompts. Hub commands do not necessarily clear processed datasets,
Xet, assets, or legacy diffusers caches.

When full eviction of an inspected cache is explicitly approved, these are
default-path alternatives. Select only approved lines, and confirm that no
locally saved models, datasets, or credentials are inside the selected target:

```bash
# DESTRUCTIVE: individually approved, verified cache directories only.
rm -rf -- "$HOME/.cache/huggingface/hub"
rm -rf -- "$HOME/.cache/huggingface/datasets"
rm -rf -- "$HOME/.cache/huggingface/diffusers"
rm -rf -- "$HOME/.cache/huggingface/xet"
rm -rf -- "$HOME/.cache/huggingface/assets"
```

See [Hugging Face cache management](https://huggingface.co/docs/huggingface_hub/guides/manage-cache)
and [cache/token locations](https://huggingface.co/docs/huggingface_hub/en/package_reference/environment_variables).

### uv, pre-commit, and pip

Use the owning tool for cleanup. For uv, never manually remove cache files:
its cache has internal structure and locking. Check for `UV_LINK_MODE=symlink`
or `link-mode = "symlink"` first; deleting referenced cache files can break those
environments. This warning applies to both `prune` and `clean`. Explain the need
to recreate affected environments before approval.

```bash
# DESTRUCTIVE: choose approved operations, not every line.
uv cache prune                 # Remove unused entries; prefer to full eviction.
uv cache clean                 # Alternative: clear the whole uv cache.
pre-commit gc                  # Remove unused cached hook repositories.
pre-commit clean               # Alternative: clear all cached hook environments.
python3 -m pip cache purge     # Remove this pip configuration's HTTP/wheel cache.
```

Hook environments and packages may need rebuilding/reinstalling. Check
[uv cache guidance](https://docs.astral.sh/uv/concepts/cache/),
[uv link-mode settings](https://docs.astral.sh/uv/reference/settings/#link-mode),
[pre-commit commands](https://pre-commit.com/), and
[pip cache commands](https://pip.pypa.io/en/stable/cli/pip_cache/) as needed.

## 3. Browser and app caches

Inspect the common candidates individually, with their apps closed before any
cleanup. Prefer an app's cache-only clearing control when available; do not select
cookies, passwords, history, site storage, or offline downloads implicitly.

```bash
du -h -d 2 "$HOME/Library/Caches/Arc" | sort -h | tail -30
du -h -d 2 "$HOME/Library/Caches/Google" | sort -h | tail -30
du -h -d 2 "$HOME/Library/Caches/com.spotify.client" | sort -h | tail -30
du -h -d 2 "$HOME/Library/Caches/ms-playwright" | sort -h | tail -30
```

Only if inspection confirms an entire target is disposable cache, offer these
individual deletions. If it mixes cache and user state, select verified cache
subdirectories instead. Leave Arc and Spotify Application Support untouched;
inspect Google Application Support separately as described below.

```bash
# DESTRUCTIVE: select only inspected, cache-only, approved targets.
rm -rf -- "$HOME/Library/Caches/Arc"
rm -rf -- "$HOME/Library/Caches/Google"
rm -rf -- "$HOME/Library/Caches/com.spotify.client"
```

For Spotify, prefer Settings > Storage > Clear cache; downloaded music is a
separate decision. See [Spotify storage guidance](https://support.spotify.com/us/article/storage-information/).

### Playwright

Respect `PLAYWRIGHT_BROWSERS_PATH` and project-local installations. Do not remove
the whole `ms-playwright` directory: [Playwright MCP persistent profiles](https://playwright.dev/mcp/configuration/user-profile)
can live there as `mcp-*-profile` and contain login/site data. Preserve those and
any custom user-data directories. Inspect browser binary directories separately.

Prefer an already-installed project's CLI, after checking its uninstall help and
confirming its removal scope preserves persistent profiles. If that scope is
unclear, do not run it; propose individually verified browser-binary directories
instead.

```bash
# DESTRUCTIVE: example for an existing Node project's Playwright installation.
./node_modules/.bin/playwright uninstall
```

For a Python project, use that environment's `python3 -m playwright uninstall`
instead. Do not download a CLI just to clean up or add `--all` without explicit
approval of its wider scope. Browser binaries must be reinstalled with the
project's Playwright version before tests can run again. See
[Playwright browser management](https://playwright.dev/docs/browsers).

## 4. Google Application Support and Chrome profiles

Do not delete `~/Library/Application Support/Google`, the Chrome directory,
`Default`, or a whole `Profile N`. These hold actual browsing state and extensions.
IndexedDB, Local Storage, Service Worker storage, and extensions are not routine
disposable caches. An unfamiliar profile is not evidence that it is abandoned.

```bash
du -h -d 2 "$HOME/Library/Application Support/Google" | sort -h | tail -40
# Example only: replace Profile 5 with the profile actually identified.
du -h -d 2 "$HOME/Library/Application Support/Google/Chrome/Profile 5" | sort -h | tail -40
```

Use Chrome's `chrome://version` to identify the active Profile Path, or map
default-location profile directories to names without dumping the full Local
State file or account emails:

```bash
python3 - <<'PY'
import json
from pathlib import Path

state = Path.home() / "Library/Application Support/Google/Chrome/Local State"
profiles = json.loads(state.read_text()).get("profile", {}).get("info_cache", {})
for directory, info in sorted(profiles.items()):
    print(f"{directory} -> {info.get('name', '(unnamed)')}")
PY
```

Inspect these two narrower candidates separately. The on-device model is a
downloaded component; removing it can interrupt AI features and Chrome may
download it again. The updater cache contains downloaded update packages. Quit
Chrome and wait for any updater activity to finish before approved deletion.

```bash
du -sh "$HOME/Library/Application Support/Google/Chrome/OptGuideOnDeviceModel"
du -sh "$HOME/Library/Application Support/Google/GoogleUpdater/crx_cache"
```

```bash
# DESTRUCTIVE: only these confirmed, approved component/cache directories.
rm -rf -- "$HOME/Library/Application Support/Google/Chrome/OptGuideOnDeviceModel"
rm -rf -- "$HOME/Library/Application Support/Google/GoogleUpdater/crx_cache"
```

Do not remove GoogleUpdater itself or disable updates. Model paths can change;
consult [Chrome model management](https://developer.chrome.com/docs/ai/understand-built-in-model-management)
if the observed layout differs.

## 5. Snapshots and device backups: inspect, do not clean by default

```bash
tmutil listlocalsnapshots /
du -h -d 1 "$HOME/Library/Application Support/MobileSync/Backup" | sort -h
```

- **Time Machine:** local snapshots are restore points, not ordinary caches.
  macOS normally reclaims them automatically and counts their space as available.
  Do not sum snapshot sizes with cache estimates. Leave them alone unless the
  user separately approves losing specific restore points; consult the installed
  `man tmutil` before proposing any removal. Do not bulk-delete or thin snapshots
  as part of routine cleanup. See [Apple's local snapshot guidance](https://support.apple.com/en-us/102154).
- **MobileSync:** these are real iPhone/iPad backups. Do not delete the Backup
  directory or arbitrary files inside a backup. If the user wants to remove an
  identified obsolete backup, prefer Finder > connected device > General > Manage
  Backups, preserving the only usable backup. Obtain separate approval for the
  selected backup. See [Apple's backup management instructions](https://support.apple.com/en-us/108809).

## 6. Verify and report

After approved cleanup, repeat `df -h` on each measured volume and `du -sh` for
remaining target directories. Report what actually succeeded, what was skipped,
before/after free space, and what must be downloaded or rebuilt. Do not claim
space was recovered merely because a command was proposed or a directory was
removed; APFS accounting and active apps can affect the measured change.

