Skip to content
borlafuPublic

About

Safe disk cleanup CLI for macOS: dry-run first, reversible quarantine, honest APFS numbers. Rust, Apple Silicon.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Broza — safe disk cleanup CLI for macOS

Broza is an open-source command-line tool that analyzes your Mac's APFS storage, explains what "System Data" and purgeable space really are, and frees disk space (Xcode DerivedData, node_modules, Docker, caches, snapshots) with a dry-run first and a reversible quarantine. Built in Rust for Apple Silicon.

CI Release License: MIT Ko-fi

Website: borlafu.github.io/broza · Mac disk space guides

Why Broza

Every Mac owner eventually asks the same three questions when the disk fills up:

  • What do I have? Broza maps physical disks, APFS containers, volumes and their roles, and local snapshots.
  • What is each thing for? Broza explains every volume and folder in plain English.
  • What can I delete without breaking anything? Broza suggests cleanup by risk level and only acts after you confirm, moving items to a quarantine you can undo.

The name is Spanish: broza means brushwood or useless clutter. Pronounced BRO-zah.

Quick start

Install with Homebrew:

brew install borlafu/broza/broza

Or with the installer script from the latest release:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/borlafu/broza/releases/latest/download/broza-cli-installer.sh | sh

Or build from source with Cargo:

cargo install --locked --git https://github.com/borlafu/broza broza-cli

See what is using your disk:

broza scan

Get cleanup suggestions grouped by risk:

broza suggest

Preview a safe cleanup. This is a dry-run; nothing is deleted:

broza clean --risk green

Apply it. Items move to quarantine, and Broza asks for confirmation first:

broza clean --risk green --apply

Changed your mind? Everything stays restorable until the session expires (30 days by default):

broza quarantine list
broza restore --session cln_20260921103608_a1b2

Space is actually freed when a session expires or is purged. broza clean --apply expires past-due sessions on its way; broza quarantine expire does it on demand.

Example clean dry run:

Dry run: nothing was changed.

Would move to quarantine 5122 item(s), 21.6 GB in all:
   planned        3.0 GB  ~/Library/Caches/Google
   planned        2.3 GB  ~/Library/Caches/pnpm
   planned        1.9 GB  ~/Library/Caches/Homebrew
   … and 5119 more

Next step:
  broza clean --risk green --apply    (moves to quarantine; `broza restore` brings items back until they expire)

Example scan output:

Physical disk  disk0  —  APPLE SSD AP1024Z  (1.00 TB)
└─ APFS container  disk3  (994.7 GB)
   ├─ Used        812.4 GB  ████████████████░░░░  81.7%
   ├─ Free         98.1 GB
   └─ Purgeable    84.1 GB  ← estimate; macOS shows this as "available"

   Volumes in this container:
   ┌ Macintosh HD         System     11.3 GB   read-only, sealed
   ├ Macintosh HD - Data  Data      798.2 GB   ← your data
   ├ Preboot              Preboot     6.5 GB
   ├ Recovery             Recovery    1.2 GB
   └ VM                   VM          3.0 GB   swap

Largest consumers on Macintosh HD - Data:
  312.4 GB  ~/Library/Developer/Xcode/DerivedData/
   84.1 GB  ~/Library/Caches/
   61.7 GB  ~/Documents/

Ask what any volume, path or category actually is:

broza explain /System/Volumes/Data
broza explain cloud-synced --short

Why it is safe

Broza is designed so that a mistake cannot cost you data.

  • Dry-run by default. broza clean only simulates. Nothing changes without --apply.
  • Reversible by default. Deleted items go to a quarantine for 30 days. broza restore puts them back.
  • Irreversible deletion is deliberate. --purge requires typing the word PURGE. --yes does not skip it.
  • System volumes are untouchable. Broza never writes to the System, Preboot, Recovery, or VM volumes. There is no flag to change that.
  • Cloud files are only reported. Files already synced to iCloud Drive, Dropbox, OneDrive, or Google Drive are never deleted. Broza shows the provider's official steps instead.
  • Honest numbers. Purgeable space is shown separately from free space. Quarantined bytes are reported separately from bytes actually freed.
  • Scriptable. Every command has --json. No prompt appears without a terminal.

What it cleans

Category What it finds Risk Action
user-cache ~/Library/Caches, logs, incomplete downloads Safe quarantine
build-cache Xcode DerivedData and Archives, orphan node_modules, __pycache__, .gradle, target/, Docker disk image Safe / Review quarantine
ios-simulators Unused iOS simulator runtimes and devices Review quarantine
trash Trash on every volume Review empty
snapshots APFS local snapshots (Time Machine) Review delete by UUID (diskutil)
old-backups Old iPhone and iPad backups in MobileSync/Backup Review quarantine
unused-apps Apps not opened in over a year, plus leftovers of uninstalled apps Review / Info only quarantine
cloud-synced Files already stored in iCloud Drive, Dropbox, OneDrive, Google Drive Info only report
duplicates Identical files by content hash Review quarantine
large-old-files Large files not opened in a long time Review quarantine

Full details, flags, and the JSON contract are in the CLI specification.

Understanding your Mac's storage

APFS containers share space. A Mac's SSD holds one APFS container with several volumes (System, Data, Preboot, Recovery, VM). Free space belongs to the container, not to any single volume. That is why a "percentage full" per volume is misleading, and why Broza reasons at the container level.

Free is not the same as available. Finder reports "available" as free space plus purgeable space. Purgeable space is data macOS may delete on its own when it needs room, such as local snapshots and caches. An app asking the file system sees only the truly free part. Broza shows both numbers on separate lines and never adds purgeable to free.

What "System Data" contains. The large, opaque "System Data" bucket in System Settings is mostly APFS local snapshots, virtual memory swap, application caches, logs, and on newer Macs the Apple Intelligence models. Some of it is safe to remove, some shrinks after a reboot, and some should only be managed through Apple's own tools. broza explain tells you which is which.

Snapshots need tmutil. APFS local snapshots are copy-on-write images made by Time Machine and by system updates. They can take tens of gigabytes and must be managed with tmutil, never by deleting files by hand. Broza uses tmutil for this and never touches update snapshots.

Requirements

  • macOS 26 or 27 (Broza supports the two latest major versions).
  • Apple Silicon (M-series). Intel Macs are not supported.
  • No special permissions to enumerate disks or scan your home folder.
  • Full Disk Access is optional. It lets Broza scan protected areas such as Mail, Safari, and device backups. Without it, Broza scans what it can and tells you what it skipped: System Settings → Privacy & Security → Full Disk Access, then add your terminal (or the broza binary). Only a path you name that macOS refuses outright ends the command (exit 3).

Scripting and JSON

Every command supports --json. Output is a stable envelope:

{
  "schema_version": "1.1",
  "broza_version": "1.0.0",
  "generated_at": "2026-09-21T10:36:08Z",
  "command": "suggest",
  "host": { "macos_version": "26.1", "arch": "arm64" },
  "data": {},
  "warnings": [],
  "errors": []
}

Sizes are integers in bytes. Timestamps are ISO 8601 UTC. Consumers should ignore unknown fields.

Exit codes:

Code Meaning
0 Success, including "nothing to clean"
1 Unclassified error
2 Invalid arguments or flag combination
3 Permission denied (for example, missing Full Disk Access)
4 Volume, path, or quarantine item not found
5 Partial failure; see errors[]
6 Aborted by the user
7 Confirmation required but no terminal and no --yes
8 Unsupported macOS version or architecture
9 Cache corrupted; retry with --no-cache

Setting CI disables prompts, progress, and the support message. NO_COLOR disables color.

Contributing

Contributions are welcome. The project follows test-driven development, conventional commits, and a set of safety invariants that no pull request may weaken. Releases are built by cargo-dist from the committed Cargo.lock (cargo build --locked in CI) and ship a CycloneDX SBOM; code signing and notarization arrive with the Phase 2 app, which needs the same Developer ID. Human contributors: read the PRD, the CLI spec, and the implementation plan, which lists what is still open. AI coding agents: read AGENTS.md.

Support the project

Broza is free and will stay free. If it saved you space, you can leave a tip at ko-fi.com/borlafu. It is a donation, nothing is sold and nothing is unlocked.

Support Broza on Ko-fi

License

The Broza core and CLI are released under the MIT License. The planned Phase 2 desktop app will be proprietary, built on this same MIT core.

FAQ

Does Broza delete files permanently? Not by default. Items go to a quarantine for 30 days and can be restored with broza restore. Permanent deletion requires --purge and typing PURGE.

Why does Finder show more available space than Broza? Finder adds purgeable space to free space. Broza shows them separately because purgeable space is not guaranteed to be available to your apps right now.

Can Broza remove Time Machine local snapshots? Yes, through tmutil, and only after you confirm. macOS does not report per-snapshot sizes, so Broza lists them without a size estimate. Update snapshots are never proposed.

Is it safe to delete Xcode DerivedData? Yes. DerivedData contains build artifacts that Xcode regenerates on the next build. Broza marks it as a safe, green-risk item.

Does it work on Intel Macs? No. Broza targets Apple Silicon only.

Does Broza send any data anywhere? No. Broza has no telemetry and makes no network requests.

About

Safe disk cleanup CLI for macOS: dry-run first, reversible quarantine, honest APFS numbers. Rust, Apple Silicon.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages