Architecture
core/ Rust library: the engine
src/scan.rs parallel walk, allocated sizes, hardlinks once, no symlinks, no volume crossing
src/rules.rs YAML rule loading, validation and glob matching
rules/macos.yaml the built-in rules
src/findings.rs expands rules against a home folder and sizes the matches
src/clean.rs plan → execute → verify, with re-checks before each action
src/journal.rs append-only journal and undo
src/paths.rs the hard denylist
src/system.rs Trash, running apps, free space, commands (behind a trait, faked in tests)
src/fda.rs Full Disk Access detection
src/snapshots.rs APFS local snapshots
src/index.rs SQLite scan history
cli/ `opendisk` command line on the same engine
app/ Tauri 2 desktop app
src-tauri/ Rust commands exposed to the UI (an explicit allowlist)
src/ React + TypeScript interface
demo/ demo data and backend stand-in for screenshots and UI work
docs/ this manual (VitePress)Why these choices
- Rust engine as a library. The scanner and cleaner are the parts that must be fast and correct, so they live in one tested crate used by both the app and the command line.
- Tauri instead of Electron. The heavy logic is Rust anyway; Tauri gives a ~10 MB app instead of ~150 MB, and its command allowlist limits what the interface can ask the engine to do.
- Declarative rules. Knowledge about what is safe to delete is data, reviewed and tested like code, not logic scattered through the program.
- Distributed outside the App Store. The App Store sandbox cannot get Full Disk Access.
Cleaning flow
findings::findexpands every rule's globs under the home folder, without following symlinks, resolves overlaps by priority and sizes each match (reusing the scan tree when there is one).clean::planvalidates the selection against the rules and the denylist, records a fingerprint (device, inode, type, modification time) of each path, chooses the action and lists blockers such as running apps.clean::executere-checks each item, acts (Trash, delete or the rule's command) or only reports in a dry run, writes the journal, and measures free space before and after withstatfs.
Not done yet
- A faster macOS listing with
getattrlistbulk(the walker uses portablereaddirfor now). - Deleting through directory file descriptors (
openat/unlinkat) to close the last check-then-act window. - Showing what grew since the last scan, from the scan history.
- Developer ID signing and notarization.
- Windows and Linux.