How oops works
Philosophy
macOS doesn’t ship with gparted or anything like it. When your disk fills up, you’re stuck clicking through Finder or running du -sh * one directory at a time. oops fixes that.
The design principles:
- Fast by default. Parallel scanning with rayon. Most directories render instantly.
- Honest sizes. Reports on-disk block usage, not apparent file sizes. A 1 TiB sparse Docker image that only uses 20 GiB of blocks shows as 20 GiB.
- Terminal-native. Colored output with proportional bars and tree drawing — all to stderr. Machine-readable output goes to stdout.
- Configurable. Built-in sweep rules ship by default; extend with your own via
~/.config/oops/config.toml. - APFS-aware. Handles macOS firmlinks correctly when scanning
/to avoid double-counting.
Architecture
oops is a Rust workspace with two crates:
crates/
├── oops-core/ # Library: scanning, volumes, config, rules, sweep engine
└── oops-cli/ # Binary: commands, UI rendering, terminal output
oops-core handles the heavy lifting:
scan_top_entries()— parallel scan of immediate children with aggregated sizesscan_tree()— recursive tree with sizes, used bymaplist_volumes()— portable volume detection viadf -Pksweep_directory()— rule-based matching engine for reclaimable spaceconfigmodule — XDG config loading, TOML parsingrulesmodule — built-in rules, user rule merging, template expansion
oops-cli handles presentation:
- Each command implements an
Optrait with typed errors and output - Shared rendering lives in a
ui/module (colors, output, tables, bars) - Per-command rendering lives in
commands/<cmd>/render.rs - A
command_enum!macro generates the dispatch enum from individual command structs
Key commands
| Command | Purpose |
|---|---|
oops map (default) |
Visual disk usage map — proportional bars, one line per entry |
oops sweep |
Find reclaimable space using configurable rules |
oops config |
Inspect/manage config and sweep rules |
oops free |
One-liner: how much space is left? |
oops vol |
Mounted filesystems with capacity bars |
On-disk sizing
Most disk usage tools report apparent size — what metadata.len() returns. For sparse files (like Docker.raw on macOS), the apparent size can be wildly larger than the actual disk blocks allocated.
oops uses stat.blocks * 512 — the same metric du reports by default. This gives you the real on-disk footprint.
A Docker.raw file might report 1 TiB apparent size but only consume 20 GiB of actual disk blocks. oops shows you the 20 GiB.
APFS handling
On macOS, oops map / redirects to /System/Volumes/Data and skips child mount points to avoid double-counting via APFS firmlinks. The volume context bar at the top shows the breakdown: scanned data, system/other, and free space.