From disk-cleanup
Scan internal fixed drives for space hogs, junk, and stale files, then permanently delete ONLY what the user explicitly confirms. Use whenever the user wants to free up space, clean up their disk, find what's eating storage, remove junk/temp/cache files, clear old downloads or installers, find large or unused files, deal with a full or nearly-full C: drive, or asks 'why is my disk full' / 'what's taking up space'. Windows / PowerShell only. Trigger keywords: disk space, free up space, clean up, junk files, space hogs, storage full, large files, old files, clear cache, delete temp.
How this skill is triggered — by the user, by Claude, or both
Slash command
/disk-cleanup:disk-cleanupThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A safe, two-phase disk janitor for **internal fixed drives only** (Windows / PowerShell).
A safe, two-phase disk janitor for internal fixed drives only (Windows / PowerShell). Phase one scans and reports; phase two deletes — but only items the user explicitly confirms, defaulting to the Recycle Bin. Two PowerShell helpers do the heavy lifting; this file is the workflow you (the model) follow around them.
The scanner is folder-first: it reports the highest-value folders (Downloads first) as soon as each one finishes, so the user sees results streaming in rather than waiting for a single big dump. You render those folder cards live in the conversation — the JSON the scripts write is just how the two halves talk to each other, not a report file for the user to open.
The scripts already enforce the safety rules independently (fixed-drive check, hard-exclude zones, re-validation at delete time). Your job is to drive them, render the folder cards as they land, and never delete anything without a clear confirmation.
The helpers live in the scripts/ folder next to this SKILL.md. When this skill
loads, the harness shows you its location as Base directory for this skill: <path>.
In every command below, replace <SKILL_DIR> with that base directory. (When installed
as a plugin this is also ${CLAUDE_PLUGIN_ROOT}/skills/disk-cleanup.) Never hardcode a
user-specific path like C:\Users\Someone\....
scripts/scan.ps1 — read-only scanner. Writes a JSON report. Never modifies anything.scripts/delete.ps1 — safe deleter. Acts ONLY on the exact -Paths you pass, re-validates each, defaults to Recycle Bin.Run both through the PowerShell tool with this exact pattern (the -ExecutionPolicy Bypass guarantees the script runs regardless of the machine's execution policy):
powershell -NoProfile -ExecutionPolicy Bypass -File "<SKILL_DIR>\scripts\scan.ps1" -OutJson "$env:TEMP\disk_scan.json"
/disk-cleanup # scan the default roots on internal fixed drives
/disk-cleanup D:\ # scan a specific drive/path (must be a fixed drive)
/disk-cleanup C:\Users\Me\Downloads # scan one folder
Default scan (when no path is given) processes only the places that hold reclaimable
space, as ordered folder units, highest-value first: Downloads → Desktop → Documents
→ AppData\Local caches → Windows Temp → Recycle Bin → game install roots → Other user
files (the rest of the profile: Pictures, Videos, OneDrive, loose project folders).
Game install roots (Steam steamapps\common, Epic) surface unused games as uninstall
candidates. Browser/package caches are folded into the AppData\Local caches unit. It
deliberately does not deep-walk all of Program Files / Windows / ProgramData — those
are huge, slow, and hard-excluded from deletion anyway. To scan one of those, pass it
explicitly as a path (each -Paths target becomes its own folder card, in order).
-Paths. Otherwise omit -Paths to use the defaults.<SKILL_DIR>):
powershell -NoProfile -ExecutionPolicy Bypass -File "<SKILL_DIR>\scripts\scan.ps1" -OutJson "$env:TEMP\disk_scan.json"
Useful flags: -Paths "<path>" for an explicit target · -StaleMonths N (default 6)
· -BigTop N top items per section · -NoCache to force a fresh scan (it caches
per-folder results between runs so repeat scans are near-instant).[scan] ...). The JSON has a top-level
phase field that moves through "sample" → "scanning" → "done":
sample (lands in ~1–2s): every folder with a fast size estimate and zero
items. Read it immediately and render the map (see Phase 2) so the user sees
scope right away.scanning: folders gain their real items one at a time, Downloads first.done: every folder complete; ids (B1/J1/S1…) are final. Do selection from this.$env:TEMP\disk_scan.json) with the Read tool: once shortly after
launch for the sample map, and again when the background run finishes. (For a snappy
feel you may read once more mid-run to stream a folder or two, but never present the
numbered selection list until phase is done — ids are only stable then.)If aborted is true (the target resolved to a removable / external / network
drive, or no valid root): STOP. Show the reason and ask the user how to proceed.
Do not scan anything else.
Render the results directly in the conversation as they arrive. No saved report file — the user reads the cards here. Keep it scannable, no walls of text.
phase: sample)As soon as the sample lands, show a one-glance map so the user sees where space is going:
## 🧹 Disk Cleanup — scanning…
Reclaimable space lives in these folders (estimating, full results streaming in):
| Folder | Size |
|--------|------|
| 📁 Downloads | █████░░░░░ 1.0 GB |
| 🧩 AppData\Local caches | ██░░░░░░░░ 412 MB |
| ♻️ Windows Temp | ████████░░ 2.2 GB |
| 🎮 Game install roots | ███████░░░ 1.5 GB |
(~ prefix or "approx" is fine for folders where approx is true.)
phase: scanning / done)Walk report.folders in order and render one card per folder as a small table.
Downloads comes first. For each card show the folder's subtotalHuman (total size) and
reclaimableHuman (junk+stale found), then its items (already highest-impact first).
Columns: # | Item | Size | Last used | Age | Risk. Use each item's id (B1, J1, S1…)
as #. Add a size bar relative to the largest item in that card — roughly one █
per 10%, e.g. ████████░░. Shorten long paths in the middle with …, keep the filename
and a recognizable parent. Mark fromCache: true folders with a small "(cached)" note.
### 📁 Downloads — 1.0 GB · 0.7 GB reclaimable
| # | Item | Size | Last used | Age | Risk |
|---|------|------|-----------|-----|------|
| J3 | …\Downloads\setup_old.msi | ████████░░ 520 MB | 2024-11-02 | >1y | safe |
| B4 | …\Downloads\old-vm.iso | █████░░░░░ 9.1 GB | 2024-11-02 | >1y | review |
Use the item's risk field to guide the user: safe = clear without worry,
review = look first, protected = a hard-exclude zone — never offer it for
deletion (the deleter will refuse it anyway). Group/colour by risk if helpful.
Two extra flags ride on each item and change how you treat it:
personal: true — irreplaceable user data (photos, documents, videos, music,
by location or extension). Mark it visibly (e.g. a 🔒 or "personal" tag). These are
legitimately deletable, but only item by item with the user looking — they must
never be swept up by a bulk/one-click option (see Phase 3).cloud: true — lives in a OneDrive/Dropbox/Drive folder. Deleting it removes it
from the cloud and every other synced device, so the Recycle Bin does not make
it recoverable. Flag this loudly and treat it like personal data: individual selection
and an explicit heads-up only.Items with needsAdmin: true (the Windows Temp container) are clearable but only in an
elevated session — non-admin runs will skip most of it as access-denied. Surface this
when you show it: e.g. "Windows Temp — 2.2 GB (run Claude/PowerShell as admin to clear it
fully)". Don't drop it from the reclaimable total; just set the expectation.
For kind: app items (games/programs in the Game install roots card), the JSON carries
appName and uninstall. Render these as uninstall candidates, not delete candidates
— show the uninstall command/path. Never offer to delete an install folder directly.
Once phase is done, output ✅ scan complete and move to selection.
Ask the user what to remove with an interactive picker (the AskUserQuestion
tool) rather than making them type ids into prose. Offer concrete, mutually sensible
options derived from what the scan actually found.
The golden rule for bulk options: a one-click choice may only contain items that are
fully recoverable or fully regenerable. That means every item in a bundle must be
risk: safe AND personal: false AND cloud: false. Personal/cloud items are never
recoverable enough to risk on a single click (a large personal file can even skip the
Recycle Bin entirely — see the thresholds below), so they only ever go in individually.
Good presets (only offer the ones the scan actually populated):
J* — caches, temp, old installers, regenerable build dirs,
Recycle Bin). All risk: safe, none personal/cloud. The safe default to recommend.J* plus the S* items where personal:false and
cloud:false — old installers, archives, build leftovers). Explicitly excludes
personal media/documents and anything cloud-synced.personal:true
or cloud:true item can be chosen, and only when the user names it specifically.Set multiSelect: true so the user can combine folders/categories. Always keep the
typed free-form fallback working: if they answer "Let me pick" (or just type), parse
replies like "all junk", "J1, J3, S2", "everything in Downloads", or
"none". Tell them the default is the Recycle Bin (recoverable).
Parse the selection into a concrete list of ids, then map those ids back to their
full paths from the JSON. Rules:
J* item. "all stale" → every S* where personal:false and
cloud:false; if that phrase would have swept in personal/cloud items, list those
separately and make the user opt into each one. "all big" is unusual — confirm
individually; big items are often things they want to keep.personal:true or cloud:true
item solely when the user names it by id or by an unambiguous description. Never let a
category word ("all stale", "everything in Documents") pull one in silently.Recycle Bin — handle it with the
-EmptyRecycleBin switch rather than -Paths.kind: app install folders. If the user wants a game/app
gone, give them the uninstall command to run and ask them to confirm uninstalling
— do not pass the folder to delete.ps1.risk: protected — these are hard-exclude zones and
are not selectable, even if the user names them. Say why; the deleter refuses them too.Before deleting, check the totals. STOP and ask for explicit extra confirmation when:
personal:true or cloud:true item. List each one by
name and have the user re-confirm it specifically. For cloud items, spell out that the
delete propagates to every synced device and the Recycle Bin won't bring it back..sys/.dll, AppData\Roaming, anything off a fixed drive). Refuse those
items and tell the user why — even if they ask indirectly. The deleter will refuse
them too, but call it out up front.Echo back exactly what will be removed and the total space to reclaim:
About to move these **7 items (14.3 GB)** to the Recycle Bin:
- J1 Recycle Bin (12.0 GB)
- J4 …\Temp (1.8 GB)
- S3 …\Downloads\setup_old.msi (0.5 GB)
Reply **yes** to proceed, or tell me what to change.
Require a clear typed yes before running anything. Output ✅ selection confirmed.
Default is the Recycle Bin (recoverable).
Pass the selected paths through a file, not inline. powershell.exe -File … -Paths "a","b" does not split on the comma — it binds the whole thing as a single string,
which silently turns a multi-item delete into a no-op. So write the confirmed paths to a
temp file (one per line, UTF-8) and hand the deleter -PathsFile. This also avoids
command-line length limits when the user clears a few hundred items. Use the Write tool
to create $env:TEMP\disk_delete_paths.txt with one path per line, then run (replace
<SKILL_DIR>):
powershell -NoProfile -ExecutionPolicy Bypass -File "<SKILL_DIR>\scripts\delete.ps1" -OutJson "$env:TEMP\disk_delete.json" -PathsFile "$env:TEMP\disk_delete_paths.txt"
For a single path, inline -Paths "C:\one\file.iso" is fine (no comma, no quirk).
Add -EmptyRecycleBin if the user selected the Recycle Bin item (it needs no path).
Only if the user explicitly asks to permanently delete (e.g. "delete permanently",
"don't use the recycle bin"). This is irreversible, so require a second explicit
confirmation specifically for permanence, then add -Permanent:
⚠️ Permanent deletion can't be undone — these won't go to the Recycle Bin. Type permanently delete to confirm.
Never default to -Permanent. Never combine "first time the user said yes" with
permanence — permanence needs its own confirmation for that batch.
Read the result JSON and report honestly:
✅ Cleanup done. Freed **{freedHuman}**.
- Removed: {counts.deleted} items ({mode})
- Skipped: {counts.skipped} (list each with its reason)
- Errors: {counts.errors} (list each)
Pass along anything the deleter skipped (e.g. protected paths) so the user sees what
was refused and why. Output ✅ deletion complete.
.sys/.dll/.drv
system files, anything under AppData\Roaming, drive roots, and any path off a
fixed drive. For installed apps/games, surface the uninstaller — don't rm the
folder.If anything is ambiguous or irreversible, stop and ask rather than guess.
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub ammarshaffy24/disk-cleanup --plugin disk-cleanup