mac-cleanup
Skill0 starsChanged 3 months agoMITView on GitHub
Use when someone asks to clean up their Mac, free disk space, find where storage went, remove unused apps, clear caches, or deduplicate Downloads. Measures first, then trashes in approved batches.
8 other projects use a version of this.
Adopted by
Most recently taken up by
- julianosirtori/skillstheir own version, first seen Nov 8, 2026
- jaywedgeworth22/BotFleettheir own version, first seen Nov 3, 2026
- Simple-With-Us/BotFleettheir own version, first seen Nov 3, 2026
- kevintraver/agent-skillstheir own version, first seen Nov 1, 2026
- awpthorp/mac-cleanuptheir own version, first seen Oct 25, 2026
- Tgoldi/claude-skillstheir own version, first seen Oct 13, 2026
Other versions8 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 8
- WiseWong6/wise-skills★ 10same name
- jaywedgeworth22/BotFleet★ 4same name
- Simple-With-Us/BotFleet★ 4same name
- kevintraver/agent-skills★ 1same name
- awpthorp/mac-cleanup★ 0same name
- FournineCS/claude-skills★ 0same name
- julianosirtori/skills★ 0same name
- Tgoldi/claude-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
9 rules. 0 are common, 6 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
6
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 43
Create ~/Cleanup-<YYYY-MM-DD>/ and write baseline.txt containing the output of the measurement pass below.
- Distinctive: line 89
Before proposing any deletion, show the user a table of where their space actually is.
- Distinctive: line 95
Run in ascending order of risk.
- Distinctive: line 122
Do this efficiently — never hash the whole disk:
- Very specific: line 151
When an app is approved for removal, take its satellites too — but list them first: ~/Library/Application Support/<name>, …
- Distinctive: line 201
After each batch: confirm every path in the manifest no longer resolves at its original location.
- Very specific: line 206
After Categories 4–6: launch the affected apps.
- Distinctive: line 237
When a user pushes back that the reclaimed total looks small, treat it as a signal the survey was wrong, not as a request to delete more.
- Distinctive: line 240
Prefer being wrong toward keeping.
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
What This Skill Does
Finds where disk space actually went on a Mac, then removes clutter in reviewed
batches. Nothing is deleted permanently — everything goes to ~/.Trash and stays
recoverable via Finder → Put Back until the user empties it themselves.
The skill is measurement-first. Most cleanup advice fails because the survey is wrong, not because the deletion is wrong. Half of this document is about not measuring badly.
$1 may narrow scope (downloads, apps, caches, dev). If empty, run all
categories.
Non-Negotiable Rules
- Trash only. Move files with Finder so Put Back is preserved:
osascript -e 'tell application "Finder" to delete POSIX file "/abs/path"'A rawmvto~/.Trashdestroys the Put Back record. Never userm. - Never empty the Trash. That is permanent deletion and it is the user's action, not yours. Say so explicitly when handing back.
- Never auto-accept a software licence. Many
.dmgfiles blockhdiutil attachbehind an SLA. Do not agree on the user's behalf — identify the file another way (see Category 1). - Per-category approval. Present each batch as a table of paths + sizes + why-flagged, with a total, and wait for a yes. One batch, one approval.
- Never touch
/System,/Library, anything needingsudo, Keychain, browser profiles, or iCloud/Dropbox-synced directories (a local delete propagates to their other devices). - User project directories are report-only. Source trees, git checkouts and
documents get listed with sizes and reasons. The user decides file by file.
The one exception, if they approve it:
node_modulesand build output, which a package manager regenerates.
Step 0 — Set Up the Audit Trail
Create ~/Cleanup-<YYYY-MM-DD>/ and write baseline.txt containing the output
of the measurement pass below. Every subsequent batch appends to manifest.md
in that directory: path, size, mtime, and the reason it was flagged. This is the
record the user needs to reverse a decision after the Trash is emptied.
Also record a KEPT section — things you flagged and then cleared. It is as valuable as the removal log, because it stops the next run re-investigating the same false positives.
Step 1 — Measure Correctly
Four traps, all of which produce a wrong survey:
du -sh ~/* silently skips every dotfolder. On a developer's machine the
dotfolders are usually the majority of the home directory. Always:
du -sh ~/* ~/.[!.]* 2>/dev/null | sort -rh | head -40/Applications is not under $HOME. Measure it separately, along with
/usr/local, /opt/homebrew, and /Library/Caches.
du overstates physical usage wherever APFS clones or hardlinks exist — very
common in node_modules and duplicated extension trees. It reports logical
bytes. Treat du totals as an upper bound and never quote them as "space you
will get back".
df is the only truth. Record before and after:
df -h /System/Volumes/Data
diskutil info / | grep -E "Free|Used"Report the real reclaimed number afterwards, including when it undershoots.
Also check for APFS local snapshots (tmutil listlocalsnapshots /) — they hold
space that du cannot see and that no file deletion will free.
Then drill down: from the top-level totals, recurse into the largest three or four directories until you can name the specific thing consuming the space. Stop descending when a directory is under ~2% of the total.
Step 2 — Present the Map
Before proposing any deletion, show the user a table of where their space actually is. This usually reframes the whole job — the clutter they asked about is often not where the space went. Get their reaction before proposing batches.
Categories
Run in ascending order of risk. Each is one approval.
Category 1 — Installers whose app is already installed
Lowest risk: the app is on disk, so the installer is redundant.
Match on bundle identifier, never filename. Filenames lie —
VSCode-darwin-universal.dmg → Visual Studio Code.app, googlechrome.dmg →
Google Chrome.app. Build an index of installed apps first, then match. For
.dmg files you cannot mount (SLA), read the download origin instead:
mdls -name kMDItemWhereFroms "$f"The origin URL names the vendor without agreeing to anything. See reference.md for the full matching pipeline.
Installers with no matching installed app are not duplicates — they belong in Category 3, because the question there is "do you want this app?"
Category 2 — Byte-identical duplicates
Two passes. Within Downloads first (the (1), (2) suffix families), then
across the filesystem to implement the general rule: if a file exists elsewhere
and also sits in Downloads, the Downloads copy goes.
Do this efficiently — never hash the whole disk:
- Hash every file in Downloads over 4 KB.
- Collect files elsewhere whose exact byte size matches one of those. Size comparison is cheap and eliminates almost everything.
- Hash only that shortlist. Confirm with SHA-256.
- Trash the Downloads copy. Never the copy that lives elsewhere.
Watch for versioned series. Files like report (1..7).zip with differing
sizes are successive versions, not duplicates. Present them separately and let
the user choose.
Category 3 — Unused applications
Three signals, because any one alone is wrong:
mdls -name kMDItemLastUsedDate— unreliable alone. A dozen apps sharing an identical timestamp to the second is a login or reindex batch event, not real use. Check for clustered identical times and discard them.mdls -name kMDItemUseCount— misses CLI and login-item launches. An app launched via a shim in/usr/local/binshows a near-zero count while being used daily. Check for such a shim before believing a low count.- Preference-plist mtime (
~/Library/Preferences/<bundleid>.plist) — the most honest of the three. An app written to yesterday is in use.
Also weigh what the app is for. Tools used in bursts (IDEs, CAD, video editors) look idle for months and are still wanted. Report the idle period and the app's total footprint; let the user judge.
When an app is approved for removal, take its satellites too — but list them
first: ~/Library/Application Support/<name>, ~/Library/Caches/<bundleid>,
~/Library/Preferences/<bundleid>.plist, ~/Library/Saved Application State/,
and any large SDK/toolchain directory the app owns (these are frequently far
larger than the app itself).
Category 4 — Orphaned support directories
~/Library/Application Support accumulates directories for uninstalled apps.
The folder-name heuristic produces false positives and this is the most
dangerous category. Real examples: Code is VS Code, Google is Chrome,
open-whispr is OpenWhispr — all installed, all active. Resolve every directory
to a running or installed app before flagging it, and check its mtime: a
directory written to today is not orphaned regardless of what it is called.
Present the list for confirmation. Never act on the name match alone.
Category 5 — Regenerable caches
Safe in the sense that they rebuild, at the cost of a slow next launch. Quit the owning app first, or it rewrites the directory mid-operation.
Typical: Homebrew (use brew cleanup -s --prune=all, not manual deletion),
~/Library/Caches/*, stale updater caches holding already-applied updates,
~/Library/Developer/Xcode/DerivedData, package-manager caches (~/.npm/_cacache,
~/.cache/uv, ~/.gradle, ~/.cargo/registry).
Tell the user what each cache costs to rebuild — a 4 GB npm cache is cheap to lose, a large VM or container image may be a long re-download.
Category 6 — Editor extensions and versioned installs
Frequently the single largest and least-obvious win. Editors keep every
installed version of an extension on disk while registering only the current
one. Compare the on-disk directory listing against the editor's own registry
(for VS Code: ~/.vscode/extensions/extensions.json) and treat unregistered
directories as stale. See reference.md for the exact comparison.
Same pattern applies to cached installer packages (.vsix, .crx, npm tarballs).
Category 7 — Documents and code (report only)
Produce a report, move nothing. Cover: node_modules and build-output trees with
sizes, git checkouts with no commits in 12+ months and a clean working tree,
large archived project directories, screenshot folders, and cross-directory
duplicates. Present findings and let the user decide.
Verification
After each batch: confirm every path in the manifest no longer resolves at its
original location. ~/.Trash may not be readable from the agent sandbox — verify
by source-absence rather than by listing the Trash, or read it via
osascript -e 'tell application "Finder" to get name of every item of trash'.
After Categories 4–6: launch the affected apps. Each should start normally. A
cache clear may make the first launch slow; nothing should error or lose
settings. Run brew doctor if Homebrew was touched.
At the end: re-run df -h, report actual reclaimed space against the manifest
total, and state plainly that emptying the Trash is the point of no return and
is theirs to do.
If Emptying the Trash Fails
Finder reports "the item X is in use". Diagnose before suggesting a restart:
lsof 2>/dev/null | grep "\.Trash"Zero hits means nothing holds it and the lock was transient — retrying usually
works. Beware the near-miss: a grep node_modules will match Electron apps'
own bundled copies inside /Applications, which look alarming and are
unrelated. Match on the .Trash path, not the basename.
lsof +D ~/.Trash is a hollow check — it cannot descend into a directory the
caller cannot read, and returns empty either way. Also check for drag-shelf
utilities holding a reference, and for mdworker indexing the freshly-moved
folder.
Notes
- Say early whether the disk is actually under pressure. If it is not, the goal is tidiness, and there is no reason to touch anything ambiguous — say that rather than maximising the number.
- When a user pushes back that the reclaimed total looks small, treat it as a signal the survey was wrong, not as a request to delete more. Re-measure with the Step 1 traps in mind.
- Prefer being wrong toward keeping. A false positive costs the user real data; a false negative costs some disk space on a disk that usually has plenty.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

