Website and documentation: casoon.github.io/broom
cargo-broom finds Cargo build artifacts across one project or an entire directory
tree and removes regenerable data without turning a routine cleanup into a risky
filesystem operation.
The current 0.1.0 codebase is a safety-first alpha. Conservative target cleanup,
inspection, JSON reporting, and selective cache cleanup are available. Cargo
fingerprint pruning remains experimental and is disabled by default.
cargo clean works well for one known project. It does not answer which of dozens
of local projects occupy the most space, which targets have gone cold, or what a
scheduled cleanup would remove. cargo-broom adds recursive discovery, age and
size policies, dry runs, interactive selection, and machine-readable reports.
Install from a checkout:
git clone https://github.com/casoon/broom.git
cd broom
cargo install --path .Inspect first. Neither command modifies files:
cargo broom inspect ~/GitHub
cargo broom --dry-run ~/GitHubRun a confirmed cleanup after reviewing the dry run:
cargo broom --yes --keep-days 14 --keep-size 50MB ~/GitHubCalling cargo broom without --dry-run, --interactive, or --yes fails before
the project scan begins.
- Project cleanup requires
--interactiveor--yes; registry cleanup requires--yes. - Whole-target cleanup is limited to a standard local
<workspace>/target. - Shared targets, configured target overrides, symlinked targets, and targets outside the workspace are never removed wholesale.
- A fingerprint parser error skips fine cleanup for that project. It never falls back to deleting the complete target.
- Staleness is judged by
mtime, notatime.atimeis unreliable onnoatime/relatimemounts (common on CI runners and some macOS setups), where it is not updated on every read or only coarsely, so recently-scanned-but-unused artifacts look falsely "recent".mtimeis written on every actual Cargo build and does not have this problem. - A target directory currently locked by a running
cargoprocess is skipped entirely, at both cleanup levels, instead of racing the build. - Filesystem deletion errors are reported and produce a failing exit status.
- Fingerprint pruning requires the explicit
--experimental-fineopt-in. --trashmoves Level A targets to the OS trash/recycle bin instead of deleting them permanently.
All removed data is generated Cargo output. Deletion can still cause rebuilds, so
use --dry-run before enabling an automated job.
| Mode | Selection | What it removes |
|---|---|---|
| Default / Level A | Target is at least --keep-days old and, when supplied, at least --keep-size large |
Complete standard local target/ |
--coarse-only |
Same policy as Level A; fine operations are rejected | Complete standard local target/ |
--clean-incremental |
Targets not selected for Level A | target/*/incremental caches |
--clean-doc |
Targets not selected for Level A | Generated target/doc output |
--experimental-fine |
Targets not selected for Level A | Fingerprints and matching hashed artifacts selected by experimental age and duplicate heuristics |
--toolchains <LIST> |
Modifier for --experimental-fine |
Also prunes fingerprints built with a rustc other than the named toolchain(s) |
--installed |
Modifier for --experimental-fine |
Same, but keeps any currently rustup-installed toolchain instead of a specific list |
--fine-only |
Disables Level A | Only explicitly requested fine operations |
--trash |
Modifier for Level A, any policy above | Moves the target to the OS trash/recycle bin instead of deleting it permanently |
Examples:
# Conservative whole-target cleanup only
cargo broom --yes --coarse-only --keep-days 14 --keep-size 50MB ~/GitHub
# Same, but recoverable: goes to the trash instead of a permanent delete
cargo broom --yes --coarse-only --trash --keep-days 14 --keep-size 50MB ~/GitHub
# Level A for cold projects; incremental caches and docs for the rest
cargo broom --yes --clean-incremental --clean-doc ~/GitHub
# Review experimental fingerprint pruning
cargo broom --dry-run --experimental-fine ~/GitHub
# Also prune fingerprints from toolchains rustup no longer has installed
cargo broom --dry-run --experimental-fine --installed ~/GitHub
# Never remove a complete target
cargo broom --yes --fine-only --clean-incremental --clean-doc ~/GitHub--fine-only requires --experimental-fine, --clean-incremental, or
--clean-doc. --tests-only, --toolchains, and --installed require
--experimental-fine. Conflicting mode combinations are rejected by the CLI.
--experimental-fine validates each fingerprint entry against its own JSON file
(the rustc hash Cargo records there) rather than trusting the .fingerprint/
directory naming pattern alone; an entry with no parseable fingerprint JSON marks
the whole project unsupported for fine cleanup instead of guessing (see Safety
guarantees above).
cargo broom inspect [DIR]
cargo broom doctor [DIR]
cargo broom toolchains [DIR]
cargo broom budget [DIR] --limit 50GBinspectlists discovered targets and their disk usage without applying cleanup policies.doctorreports target overrides, unusually large targets, and target lock findings.toolchainsreports installed rustup toolchains that are not referenced by arust-toolchainfile belowDIR. It does not uninstall anything.budgetreports total target disk usage across all discovered projects and, with--limit, flags when that total exceeds the budget together with the largest contributors. This is a whole-tree budget, unlike--keep-size, which is a per-project Level A threshold. Analysis only; it never deletes anything.
project uses the same policy and safety gates as a recursive run:
cargo broom project ./my-crate --dry-run
cargo broom project ./my-crate --yes --coarse-only --keep-days 14cargo broom registry ~/GitHub --dry-run
cargo broom registry ~/GitHub --yesThe registry command scans Cargo.lock files below DIR and removes cached
.crate archives whose name and version are not referenced there. Projects outside
DIR are not considered. Cached archives can be downloaded again by Cargo, but a
dry run over the broadest relevant project root is recommended.
Use --interactive to select proposed targets before deletion:
cargo broom --interactive ~/GitHubUse JSON for scripts, reports, or scheduled dry runs:
cargo broom --dry-run --format json ~/GitHub
cargo broom inspect --format json ~/GitHub
cargo broom registry --dry-run --format json ~/GitHubErrors produce a non-zero exit status. JSON reports are written to stdout; process errors are written to stderr.
--history (or history = true in broom.toml) is an opt-in, off-by-default flag
that appends each target's resulting size to a rolling 14-day JSON Lines log at
~/.local/state/cargo-broom/history.jsonl, one line per target per run. Entries
older than 14 days are pruned automatically; dry runs are never recorded, since they
do not reach the sizes they report.
cargo broom --yes --history ~/GitHubOnce a target has at least one prior entry, the report gains a History metric
comparing the current size against that target's oldest still-retained entry —
answering "is this growing back despite regular cleanup?" instead of only showing
the current run's numbers. The same data is available under history_trend in
--format json output for scripting.
The first applicable configuration source is used in this order:
- the file passed through
--config; ./broom.toml;~/.config/cargo-broom/config.toml.
An explicit file is not merged with the local or global file. Scalar CLI values
take precedence; ignore and skip lists are combined. Invalid files and unknown
keys are errors instead of being silently ignored. ~ is expanded in root_path.
root_path = "~/GitHub"
keep_days = 14
keep_size_mb = 50
# Keep experimental pruning disabled for unattended runs.
experimental_fine = false
fine_only = false
coarse_only = false
trash = false
history = false
hidden = false
ignore = ["archived-repo"]
skip = ["node_modules"]Confirmation is intentionally not configurable. An unattended destructive run
must include --yes in the command itself.
Start by logging dry-run output for several runs:
cargo broom --dry-run --format json ~/GitHubAfter reviewing the policy, an explicit conservative command is suitable for cron or launchd:
cargo broom --yes --coarse-only --keep-days 14 --keep-size 50MB ~/GitHubThe included de.casoon.cargo-broom.plist is a machine-specific example. Adjust
its executable, root, and log paths before loading it.
cargo-broom targets a developer machine with many long-lived local checkouts,
cleaned up periodically by age and size. It is not a fit for a target/ directory
persisted across CI runs (e.g. via actions/cache): that cache grows for a
different reason — every dependency bump leaves behind fingerprints from the
previous Cargo.lock state — and calls for cache-key-based or content-addressed
invalidation instead of an age heuristic. For that case, prefer a tool built for it:
Swatinem/rust-cache— GitHub Action that keys the cache onCargo.lockplus toolchain version and prunes known-safe-to-drop paths (incremental/, final binaries) before saving. The default choice for GitHub Actions.sccachewith a remote backend (S3, GCS, or the GitHub Actions cache backend) — content-addressed compiler cache, so entries are looked up by input hash rather than file age; sidesteps staleness entirely.cargo-chef— for Docker-based pipelines, separates dependency compilation from application compilation into distinct, correctly invalidated Docker layers.- Registry-only caching — cache just
~/.cargo/registryand~/.cargo/gitand skiptarget/altogether. Simpler, and often enough when CI runners are fast and dependency compilation dominates build time.
The project requires Rust 1.89 or newer (for std::fs::File::try_lock, used to detect
an in-progress build before cleaning its target directory).
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets
cargo packageCI runs formatting, Clippy, and tests on Linux, macOS, and Windows. The package uses
the published runemark dependency and does not require a sibling repository.
MIT
The rustc-version hashing in --toolchains/--installed (src/level_b.rs) is
ported from cargo-sweep (MIT), which
mirrors Cargo's own internal fingerprint hash.