Command lineSafety and deletion
Safety and deletion
What census reads, what it can delete, how it asks, and the checks every item passes before it is deleted.
Deleting is permanent
Only these commands delete:
| Command | Deletes |
|---|---|
clean | The safe tier of a fresh scan, or the safe items you name |
review | The items you choose in its terminal menu |
apply | The paths in a selection file, if census listed them |
uninstall | An app and the data named after it |
optimize | The safe tier, then the quick maintenance tasks run |
empty-trash | What is in the Trashes you own |
maintain doesn’t delete your files, but its tasks change your Mac: rebuilding caches, restarting Finder, deleting local Time Machine snapshots. It asks before it runs any of them.
Safe, review and keep
Every finding has a safety tier, from the rule that recognized it.
| Tier | What it means | What happens to it |
|---|---|---|
safe | Rebuilds itself: caches, build output, logs, and AI agents’ old versions. | clean deletes it when it isn’t in use. |
review | May cost time or bandwidth to get back, or may hold something worth keeping: installers, Cargo target folders, some app caches. | Waits in a review set until a person picks it. |
keep | Shown with its size, never offered: AI agents’ history, the Go module cache, conda package caches, simulator devices, Docker’s disk image. | Never deleted. |
# Only what clean would delete
census findings --safety safe
# What waits for you
census findings --safety review
How each command asks
In a terminal, every command that deletes shows what it will delete and asks first. Without a terminal (a script, an agent, or census serve) there is no one to ask, so you pass a flag that says you already agreed. Without that flag the command fails with confirmation_required (exit code 1) and deletes nothing.
| Command | In a terminal | Without asking |
|---|---|---|
clean | Lists the items and asks [y/N] | --safe |
review | Delete which? (1,3-5 · Enter for none), then Type delete | Use review --json and apply |
apply | The selection file is your choice, so it doesn’t ask | No flag needed |
uninstall | Lists what goes and asks [y/N] | --yes |
optimize | Shows the items and tasks, and asks once | --yes |
empty-trash | Permanently delete 1,218 items (8.5 GB)? [y/N] | --yes |
maintain TASK | Asks [y/N] | --yes |
empty-trash --json without --yes only lists what is in the Trash. It never deletes.
What every item is checked against
All deletion goes through one executor. It works from a fresh scan, never from a list it was handed: clean, apply, uninstall and optimize rescan first, and an item is deleted only if the fresh scan still finds it under the same rule. Then, for each item:
- Outside the scan’s scope: refused.
- Protected folders: refused. The root folders (
/,/Users,/Applications,/Library,/System,/private), your home folder,~/Libraryand its standard folders,~/Documents,~/Desktop,~/Downloads,~/Pictures,~/Moviesand~/Musicare never deleted, and neither is a folder that contains one. The files inside them can be. - Synced folders: refused. iCloud Drive (except its Trash, when you empty it),
~/Library/CloudStorage, Dropbox and OneDrive. Cloud placeholders are refused too, except in a Trash you empty, because deleting one can delete the file from the cloud. - The System volume and SIP-protected items: refused.
- Links: never followed. A symbolic link anywhere on the path skips the item.
- Changed since the scan: skipped. A file must have the same identity, size and modification time; a folder, the same identity.
- In use: skipped. See below.
- Nested findings: a
revieworkeepfinding inside asafeone stays, with the folders that lead to it. - Never forced: census never runs
chmodorchflags. A locked file or a permission error is reported, not overridden.
Two more rules apply to every run: census refuses to delete as root (run_as_root), and only one cleanup runs at a time (cleanup_running).
Items in use
An item is skipped as in_use, and stays for review, when:
- a program you’re running has a file open inside it;
- a program is running from inside it, such as a dev server from
node_modulesor an agent’s current version; - the app or tool it belongs to is running, such as Xcode for
DerivedDataorcargofor the Cargo caches; - a launcher points to it, such as
~/.local/bin/claudeto the Claude Code version it starts.
Quit the app or tool, then run the command again.
The audit log
Every run that deletes writes an audit log to ~/Library/Application Support/census/audit/, one NDJSON file per run. Before each item it writes a started line, and after it the result, with the path, bytes and reason. The JSON result names the file in results.audit:
{
"audit": {
"display": "/Users/me/Library/Application Support/census/audit/clean-1790950000000.ndjson",
"lossy": false
}
}
If the audit can’t be written, census stops before the next item (audit_unavailable).
Item outcomes
Every item in a cleanup result has an outcome.result:
| Result | Meaning | Reasons |
|---|---|---|
deleted | Gone. bytes is the space it took. | — |
partial | Some of it was deleted, some couldn’t be. | — |
skipped | Left alone this time. | missing, changed_since_scan, not_listed, in_use, cancelled, audit_unavailable, no_other_copy |
failed | Nothing could be deleted. Carries errno and error. | — |
refused | Never attempted. | invalid_path, outside_scope, protected, own_data, synced, system_volume, sip, mount_point, not_deletable, root |
Skipped items are normal and still exit 0. Any failed or partial item makes the exit code 4 (partial_cleanup).