Your first cleanup
The interactive dashboard is the safest way to clean: you see every item before anything is removed, nothing is selected until you choose it, and every deletion is re-checked at the last moment. This walkthrough follows one complete cleanup, screen by screen. The projects, paths and sizes are illustrative.
Start the dashboard
Section titled “Start the dashboard”lu-cleanerlu-cleaner clean opens the same picker. Both need an interactive terminal (at least 40 × 10; 32 lines or more to see the details panel).
The usual filters pre-filter the dashboard, for example lu-cleaner -c artifacts,worktrees --older-than 30d. Nothing is preselected: the dashboard always opens with an empty selection, and you decide what to remove. To start with the recommended items already selected, opt in with lu-cleaner clean --smart.
1. Read the category overview
Section titled “1. Read the category overview”Scanners run in parallel and stream their results: categories appear and grow while the header shows scanning 5/8 providers. When the last scanner finishes, the status line tells you how to choose: nothing is selected yet.
🧹 lu-cleaner ✓ scan done in 21.4s · 339 items · 176 GB reclaimable 💾 ██████████████████████░░ 91% used · 43.0 GB free of 494 GB Categories · enter to open CATEGORY SIZE ITEMS SELECTED › [ ] 🌳 Worktrees 42.8 GB 31 items [ ] 📦 Project artifacts 36.4 GB 118 items [ ] 📱 iOS Simulators 24.1 GB 14 items [ ] 🔨 Xcode 18.6 GB 12 items [ ] 🤖 Android 14.3 GB 19 items [ ] 🧠 AI tools 12.9 GB 57 items [ ] 🟨 JS toolchain 17.2 GB 48 items [ ] 🧩 IDEs 3.10 GB 15 items [ ] 💻 System 6.40 GB 25 items Nothing is selected — space picks an item, a picks the recommended ones, d cleans the selection nothing selected │ delete permanently │ enter open ␣ select a smart d clean t trash / filter ? help q quit
| Element | Meaning |
|---|---|
| Header | Scan status, number of items listed, and the total that could be reclaimed. |
| 💾 line | Disk usage of the volume that holds your home folder, refreshed after each cleanup. |
| SIZE | What cleaning every item of the category would free. Report-only entries are not counted. |
| SELECTED | Size of the current selection in that category. Blank until you select something. |
[✓] [~] [ ] [·] |
Everything selected, part of it, nothing, or nothing cleanable (report-only entries). |
| Status line | The latest message (here, how to select), otherwise a description of the category under the cursor. |
| Footer | Selection count and size (nothing selected for now), the cleaning mode, and the main keys. |
The mode in the footer matters: delete permanently frees space immediately, 🗑 Trash mode (toggled with t) moves files and folders to ~/.Trash, frees nothing until you empty it and skips worktrees and commands (they cannot be undone), and ○ dry-run touches nothing.
Press s to sort the categories by size, and space to select a whole category at once (or, if something in it is already selected, to clear it). That bulk selection deliberately skips items of risk caution: you have to open the category and pick those one by one.
2. Open a category
Section titled “2. Open a category”Move to Project artifacts and press enter (or →):
🧹 lu-cleaner ✓ scan done in 21.4s · 339 items · 176 GB reclaimable 💾 ██████████████████████░░ 91% used · 43.0 GB free of 494 GB 📦 Project artifacts (118) · sort: size ↓ · ← back · tab next NAME LOCATION SIZE AGE RISK [ ] my-app › ios/build ~/dev/my-app/ios/build 2.10 GB 5h safe › [ ] shop-app › node_modules ~/dev/shop-app/node_modules 1.42 GB 3mo moderate stale [ ] my-app › node_modules ~/dev/my-app/node_modules 1.31 GB 2d moderate [ ] codex:my-app › node_modules …/worktrees/a1b2/my-app/node_modules 1.28 GB 5w moderate stale [ ] shop-app › android/app/build ~/dev/shop-app/android/app/build 1.20 GB 3mo safe stale [ ] shop-app › ios/Pods ~/dev/shop-app/ios/Pods 980 MB 3mo moderate stale [ ] my-app › ios/Pods ~/dev/my-app/ios/Pods 910 MB 2d moderate … ────────────────────────────────────────────────────────────────────────────────────────────────────────────── shop-app › node_modules · moderate · node_modules · artifacts · 48,210 files Path /Users/you/dev/shop-app/node_modules Method delete Age last used 3mo ago (2026-06-24) · stale Note Installed JS dependencies; reinstall with `yarn install` when you need the project again (minutes, network). Project ~/dev/shop-app Meta package_manager=yarn · project_type=react-native nothing selected │ delete permanently │ ␣ select a smart d clean s sort / filter ← back ? help q quit
Each row is one item: something lu-cleaner can remove as a unit (a node_modules folder, a worktree, a cache, a simulator…).
| Column | Meaning |
|---|---|
| NAME | project › path for project artifacts; the codex: prefix means the project lives in a Codex worktree. |
| LOCATION | Where it is on disk. |
| SIZE | Space allocated on disk. … means the item is still being measured. |
| AGE | Time since the item was last used. It turns yellow, with a stale tag, after 14 days (stale_after). |
| RISK | safe, moderate, caution or never. See Risk levels and smart select. |
| Tags | stale, ⚠ (a warning), and hints such as dirty, ↑2 (unpushed commits), locked, running, the tool and ⎇ branch for worktrees. |
Dimmed rows marked [·] are listed for information and cannot be selected. Press space on one to see why.
Use tab / shift+tab to jump to the next or previous category, ← to go back to the overview, / to filter by text and s to sort by size, age or name.
3. Select what to clean
Section titled “3. Select what to clean”Nothing is selected until you choose. There are two ways, and you can mix them:
- By hand. Move to a row and press
space. On the category overview,spaceselects a whole category (except its caution items). - With smart select. Press
a: lu-cleaner selects the recommended items of the current view, nothing more, and says how many in the status line. It is your explicit request, so you see what it picked before anything can be cleaned.
| Key | Effect |
|---|---|
space |
Select or unselect the item under the cursor. |
a |
Smart select the current view: recommended items on, everything else off. |
A |
Select every cleanable item of the view, caution items included. |
n |
Select nothing in the view. |
i |
Invert the selection in the view. |
Inside a category, "the view" is the current list, after any / filter. On the category overview, it is every visible item. The selection is kept when you move between categories.
Try it: in Project artifacts, press a.
📦 Project artifacts (118) · sort: size ↓ · ← back · tab next NAME LOCATION SIZE AGE RISK [ ] my-app › ios/build ~/dev/my-app/ios/build 2.10 GB 5h safe › [✓] shop-app › node_modules ~/dev/shop-app/node_modules 1.42 GB 3mo moderate stale [ ] my-app › node_modules ~/dev/my-app/node_modules 1.31 GB 2d moderate [✓] codex:my-app › node_modules …/worktrees/a1b2/my-app/node_modules 1.28 GB 5w moderate stale [✓] shop-app › android/app/build ~/dev/shop-app/android/app/build 1.20 GB 3mo safe stale [✓] shop-app › ios/Pods ~/dev/shop-app/ios/Pods 980 MB 3mo moderate stale [ ] my-app › ios/Pods ~/dev/my-app/ios/Pods 910 MB 2d moderate … Smart selection: 38 items (safe caches + moderate items unused for 2w) ✓ 38 selected · 9.20 GB │ delete permanently │ ␣ select a smart d clean s sort / filter ← back ? help q quit
Notice what smart select left out:
my-app › ios/buildwas used 5 hours ago. Smart select never picks the artifacts of a project used in the last 24 hours: you are probably working on it.my-app › node_modulesandmy-app › ios/Podsare moderate: rebuilding them costs time, so they are only recommended once unused for 14 days.
You can always adjust: space unselects a recommended item or selects one it left out. To carry on with the recommended items of every category, press ← to go back to the overview and press a there: the rest of this walkthrough cleans that selection (131 items, 69.0 GB).
When you select a caution item, the status line tells you what is at stake, for example ⚠ caution: my-app · spike/old-ui — 3 uncommitted changes.
Two kinds of items cannot be selected yet, and space tells you why:
- an item still being measured (
…in SIZE): its checks are not finished, select it once its size is shown; - an item that needs
--force, such as an orphaned worktree folder whose uncommitted work git can no longer see. Start lu-cleaner with--forceto delete it, or switch to Trash mode (t), which moves it to the Trash where you can still recover it.
4. Read the details
Section titled “4. Read the details”On a terminal of 32 lines or more, a details panel shows the item under the cursor (bottom of the screen above). enter toggles it: press it to show the panel on a smaller terminal, or to hide it on a large one.
| Line | What it tells you |
|---|---|
| First line | Name, risk, kind, scanner and number of files. |
| Path / Paths / Location | Exactly what will be removed. Group items (for example "Metro / Haste file maps (18)") list their first paths. |
| Method | delete, trash (Trash mode), command: … (the tool's own cleanup, such as xcrun simctl delete <UDID>), worktree (git worktree remove) or report. In Trash mode, worktrees and commands show skipped in Trash mode. |
| Blocked / Force | Shown for an item that needs --force, with the reason. |
| Reclaim | Shown when part of the data is shared with other files (hardlinks or APFS clones) and deleting frees less than the size. |
| Age | Date of last use, and whether the item is stale. |
| Warning | Why an item is risky or was not recommended. |
| Note | What the item is and how it comes back if you need it again. |
| Project, Meta | The owning project and scanner details (branch, package manager, API level…). |
Press o to reveal the item in Finder.
5. Clean and confirm
Section titled “5. Clean and confirm”Press d (or x). With nothing selected, d only reminds you to select something. Otherwise a confirmation shows what is about to happen, with the total:
╭──────────────────────────────────────────────────────────────────────────╮ │ Clean 131 items — 69.0 GB? │ │ │ │ safe 74 items 31.2 GB │ │ moderate 57 items 37.8 GB │ │ │ │ Method delete permanently — frees space now │ │ Commands xcrun simctl delete 5A1F0C2E-7B3D-4E8A-9C61-2F4B8D0E1A37 │ │ git worktree remove … │ │ Running Xcode — items guarded by them will be skipped │ │ Largest my-app · feature/login (2.40 GB), shop-app (2.30 GB), … │ │ │ │ y/enter confirm n/esc cancel │ ╰──────────────────────────────────────────────────────────────────────────╯
- Risk breakdown: how many items of each risk, and their size. Items inside another selected item are cleaned with it and counted once.
- Method: delete permanently, move to Trash, or dry-run.
- Skipped (Trash mode only): worktrees and command items, which cannot be moved to the Trash and would delete permanently. Press
tto switch back to delete mode if you want them. - Commands: the external commands that will run, such as
xcrun simctl delete <UDID>orgit worktree remove. - Running: some items refuse to be cleaned while an app uses them (Xcode for DerivedData, Simulator for simulators…). lu-cleaner checks those apps now; items guarded by a running app will be skipped, unless you started lu-cleaner with
--force. - Largest: the biggest items of the selection (on terminals of 24 lines or more).
- Hidden: selected items that the current
/filter hides. They are cleaned too.
Press y or enter to confirm, n or esc to cancel. You can also clean before the scan is over: the dialog then warns that sizes may be partial.
When the selection contains caution items
Section titled “When the selection contains caution items”If the selection holds at least one caution item, either selected or lying inside a selected item (cleaning the parent removes it too, and the dialog lists it), or an item cleaned only because of --force, the dialog turns red and a single key is no longer enough:
╭──────────────────────────────────────────────────────────────────────────╮ │ Clean 3 items — 7.90 GB? │ │ │ │ moderate 2 items 5.80 GB │ │ caution 1 item 2.10 GB │ │ │ │ Method delete permanently — frees space now │ │ Commands git worktree remove … │ │ │ │ ⚠ 1 caution item selected: may hold data you care about. │ │ Type yes to confirm: ▏ │ │ │ │ enter confirm esc cancel │ ╰──────────────────────────────────────────────────────────────────────────╯
Type yes and press enter, or esc to cancel. Caution items may hold something you cannot regenerate: uncommitted work in a worktree, agent sessions, application data. A one-key confirmation is easy to hit by reflex; typing a word makes you stop and read the list.
Confirming is not the last check. A worktree that is locked, has uncommitted or untracked changes, has commits on no branch or contains another repository is still refused at removal time unless you started lu-cleaner with --force. See Safety.
lu-cleaner worktrees: the merged Codex worktree is removed (its branch is kept); the Cursor worktree passes the typed confirmation but git refuses it at removal time, because it holds uncommitted changes.6. Follow the progress
Section titled “6. Follow the progress”🧹 lu-cleaner ✓ scan done in 21.4s · 339 items · 176 GB reclaimable 💾 ██████████████████████░░ 91% used · 43.0 GB free of 494 GB ⠹ Cleaning 131 items — 69.0 GB 12s ctrl+c cancels items ████████████████████████████████░░░░░░░░░░░░░░░░░░ 84/131 data ██████████████████████████████▏░░░░░░░░░░░░░░░░░░░ 41.6 GB / 69.0 GB freed 41.2 GB ✓ shop-app › node_modules 1.42 GB ~/dev/shop-app/node_modules ✓ shop-app › ios/Pods 980 MB ~/dev/shop-app/ios/Pods ↷ shop-app 2.30 GB skipped: Xcode is running — quit it first (or use --force) ✓ my-app · feature/login 2.40 GB git worktree removed (branch kept)
Path deletions run four at a time; commands and worktree removals run one after the other. Each finished item gets a line:
| Mark | Meaning |
|---|---|
✓ |
Done. |
↷ |
Skipped, with the reason: an app is running, a process works inside the folder, the path changed since the scan, the safety guard refused it… |
✗ |
Failed, with the error. |
○ |
Dry run: what would have been done. |
Press ctrl+c to cancel: the items in progress finish, the remaining ones are skipped as cancelled.
7. Read the summary
Section titled “7. Read the summary”╭──────────────────────────────────────────────────────────────╮ │ ✓ Cleaning finished in 38.2s │ │ 129 done · 2 skipped │ │ │ │ Estimated freed 65.4 GB │ │ Measured freed 64.8 GB (43.0 GB → 108 GB free) │ ╰──────────────────────────────────────────────────────────────╯ items ██████████████████████████████████████████████████ 131/131 data ██████████████████████████████████████████████████ 69.0 GB / 69.0 GB freed 65.4 GB press any key to return to the list ↷ shop-app 2.30 GB skipped: Xcode is running — quit it first (or use --force) ↷ codex:my-app › node_modules 1.28 GB skipped: in use: process 51234 runs a program or library from ~/.codex/… ✓ shop-app › node_modules 1.42 GB ~/dev/shop-app/node_modules …
Problems are listed first. Two numbers matter:
- Estimated freed adds up what each cleaned item was expected to free.
- Measured freed is the difference in free space on your home volume before and after the cleanup, as reported by the file system.
They are rarely identical, since other apps keep writing to disk. When the measured value is less than half the estimate, the summary suggests running lu-cleaner doctor (next section).
In Trash mode, what was moved to the Trash is never counted as freed: it gets its own line, Moved to Trash … (not freed yet), and a reminder to empty the Trash.
Press any key to return to the lists. Cleaned items disappear; skipped and failed items stay listed and selected. To retry them, quit the app that blocked them and press d again.
Every cleanup is recorded in the history (lu-cleaner history), and when you quit with q, the summary of the last one is printed in your terminal:
✓ 129 items cleaned · 65.4 GB freed (estimated) Disk free: 43.0 GB → 108 GB (64.8 GB measured) Skipped: 2 - codex:my-app › node_modules: in use: process 51234 runs a program or library from ~/.codex/worktrees/a1b2/my-app/node_modules - shop-app: Xcode is running — quit it first (or use --force)
If the space is not freed
Section titled “If the space is not freed”macOS does not always return deleted space right away. Here is what to check, in order:
-
Run the doctor. It lists APFS local snapshots, the size of the Trash and the running apps that block cleaning:
Terminal window lu-cleaner doctor -
Local snapshots (Time Machine) keep the blocks of deleted files until they expire, after about 24 hours.
doctorprints thetmutilcommands to thin or delete them. lu-cleaner never runs them for you. -
The Trash. If you cleaned in Trash mode (
t,--trashoruse_trash = true), nothing is freed until the Trash is emptied. The System category offers to empty it. -
Open files. A running process keeps deleted files allocated until it exits: Simulator, Xcode, Gradle daemons (
./gradlew --stop), Docker, an agent working in a worktree. Quit them. -
Other volumes. The measured value only covers the volume of your home folder. Items cleaned on an external drive free space there instead.
Why is my disk still full? covers each case in detail, including hardlinks, APFS clones, purgeable space and Docker's disk image.