Sweep
Sweep finds what you can do without — build output, caches, and applications with what they left behind — and moves what you choose to the Trash. It is the only part of Starf that changes the file system, so it keeps the rules the rest of Starf keeps for processes:
- A size that could not be measured is not zero. A folder still being measured shows
…, one that could not be read shows—, and one with an unreadable corner shows≥before what could be counted. A total that includes any of these says "at least". - The interface never names a path to move. It names a candidate Sweep found, by id. Only what the last scan or listing offered can be moved.
- Everything is checked again the moment before it moves. The same file must still be at the same path, and it must still be what it was found to be.
Open it with the broom in the title bar. Clicking a metric tab returns to monitoring.
Nothing is deleted
Everything goes to the Trash through the same call Finder uses, so an item keeps its name when it can, is renamed when the Trash already holds that name, and Put Back in the Trash returns it. Straight after a sweep, Undo takes the whole sweep back out, for each item whose original place is still free.
The space comes back when you empty the Trash. Starf does not empty it: the Trash holds whatever else you put there, and emptying it would destroy that too.
Build output
Sweep looks in the folders listed under Looking in. The default is the project folders
that exist in your home folder — ~/Code, ~/Projects, ~/Developer and the like — not
the home folder itself, because walking Documents, Desktop or Downloads makes macOS ask for
permission. Add any folder with Add folder…; the path comes from the open panel.
Each kind is recognised by what its tool leaves behind, not by name alone:
| Kind | Recognised by |
|---|---|
| Cargo | a target/ holding a CACHEDIR.TAG with the Cache Directory Tagging signature, which Cargo writes. A folder merely called target is not one. |
| Node | node_modules, .next, .svelte-kit, .turbo or .parcel-cache beside a package.json |
| Build | dist or build beside a project manifest, and ignored by git. A committed build/ is source — Starf's own holds its release manifest — and is never offered. Outside a repository, nothing is known, so nothing is offered. |
| Xcode | each project's folder in ~/Library/Developer/Xcode/DerivedData |
The walk never follows a symlink, never leaves the disk a folder is on, and never looks
inside what it found, inside .git or another hidden folder, or inside a bundle.
Changed is the newest modification anywhere inside. What has not changed within the
chosen time — 30 days unless you pick another — is selected; everything newer is listed
but left for you to choose. A Cargo target/ that a build holds the lock on is refused at
the moment of moving, whatever was selected.
Caches
A fixed list of places tools keep what they downloaded or computed and will fetch or
compute again: npm, the pnpm store, Cargo's registry and git checkouts, Gradle, Go
modules, the Simulator, and each folder in ~/Library/Caches and ~/.cache. macOS's own
caches (com.apple.*) are not offered.
None is selected. They refill by themselves, but a refill can be a long download — a
model in ~/.cache/huggingface, a browser's whole cache — and that is yours to weigh.
Applications
Choose an app to see it, and what it left in the Library, measured. The app itself and every exact match are selected. Two traps shaped the rules:
- Vendors share prefixes. Arc is
company.thebrowser.Browserand Dia iscompany.thebrowser.dia. So nothing matches by prefix: an entry must be the app's bundle identifier, that identifier with.plist,.savedStateor.binarycookies, or the identifier followed by a dot and more — the app's own extensions, such ascom.lowtechguys.Clop.FinderOptimiser. An entry that is another installed app's longer identifier, or one of its extensions, belongs to that app. - Names overlap. Removing Conductor must not touch Elyra Conductor. A folder named after the app matches only when the name is the app's whole name, and only in Application Support, Caches and Logs, where apps name folders that way.
The Library folders searched are Application Support, Caches, Logs, Preferences (and
ByHost), Saved Application State, HTTPStorages, Cookies, WebKit, Containers, Group
Containers (as <team>.<identifier> or group.<identifier>), Application Scripts and
LaunchAgents.
Folders only named like the app — ~/.zeron, ~/.config/zeron — are listed as
likely and are not selected. Nothing says they are the app's; you know. When one holds
git repositories, Sweep says whether any has uncommitted changes, commits no remote has,
or a stash. A folder in your home folder without the dot is never offered: an app named
Code would otherwise offer ~/Code. Documents, the desktop and anything outside the
home folder are never searched.
Application Support can hold more than settings. For a browser it holds bookmarks and saved passwords; for an editor, sometimes its documents. Look before you move it.
Refused: anything in /System, anything with a com.apple. identifier, Starf itself,
and an app that is running — quit it first. The last is checked again at the moment of
moving.
Some Library folders are protected by macOS. A sandboxed app's container can refuse to move, and Sweep then says so for that item and moves the rest. Drag it to the Trash in Finder instead.
In a terminal
The same finders, measurements and checks, from the app's own binary:
alias starf=/Applications/Starf.app/Contents/MacOS/starf
starf sweep # where the window looks: what would move, and how much
starf sweep ~/Code -o 14 # build output in ~/Code unchanged for two weeks
starf sweep -k cargo --apply # move old Cargo targets to the Trash
starf sweep -k cache # the caches, listed
starf sweep --app Zeron # an app and what it left
starf sweep --app Zeron --include-likely --apply
starf sweep --json # the listing, with each candidate's size and age
| Option | |
|---|---|
-o, --older-than |
build output unchanged for this many days (the window's setting, 30); 0 for all |
-k, --kind |
any of cargo, node, build, xcode, cache; all but cache by default |
--app |
one application by name or bundle identifier, and what it left |
--include-likely |
with --app, also move the folders only named like it |
--apply |
move what is listed to the Trash |
--json |
the listing as JSON; with --apply, each item's outcome too |
Nothing moves without --apply. With it, exactly what the listing shows is moved,
each item checked again first; one that fails says why and does not stop the rest, and
the exit status is 1. An app that cannot be removed is still listed, with the reason.