rusty-broom 0.2.1

Reclaim disk space from build artifacts of projects you stopped working on
rusty-broom-0.2.1 is not a library.

rusty-broom

Actions Status Coverage badge dependency status Crates.io

Frees up disk space by clearing build artifacts from projects you haven't worked on in a long time: target, node_modules, .venv, build, Pods, and so on.

The primary metric is how recently the project was modified. The age is calculated based on the modification time of the project's own files. Artifacts, .git, and system/service directories are excluded from this calculation. This ensures that rebuilding the project or running git gc won't make an abandoned project appear "fresh," whereas editing source code or running git pull will.

The tool only deletes paths that Git itself considers ignored (git check-ignore). Committed dist/ or vendor/ directories will remain untouched, even if they are listed in the configuration file. Projects outside of a Git repository are labeled as no-git, and their artifacts are not verified—this is indicated in both the report and the user interface.

Installation

  • cargo binstall rusty-broom (install binary using cargo-binstall)
  • brew install oriontvv/tap/rusty-broom (for macos)
  • cargo install rusty-broom (build from sources)
  • or download latest build

Building

cargo build --release
./target/release/rusty-broom --help

CLI

# Scan what's inside ~/dev (default threshold is 30 days)
rusty-broom scan ~/dev

# Projects untouched for six months, broken down by artifacts
rusty-broom scan ~/dev --older-than 6mo --long

# Only large projects of specific types, sorted by age in ascending order
rusty-broom scan ~/dev -o 1y -m 500M -t rust -t node --sort age

# Machine-readable output
rusty-broom scan ~/dev --json | jq '.totals'

# Delete: first preview the plan, then confirm
rusty-broom clean ~/dev -o 1y --dry-run
rusty-broom clean ~/dev -o 1y            # Will prompt for confirmation
rusty-broom clean ~/dev -o 1y --yes      # Without prompting

# List all supported project types
rusty-broom types

Useful flags: --all (ignore age threshold), --query TEXT (filter by path), --nested (show nested projects/workspace members), --max-depth N, --no-git-check (bypass Git validation—use at your own risk).

Running clean without the --yes flag in a non-interactive environment will not delete anything and will exit with an error; explicit confirmation is required.

TUI

rusty-broom ~/dev          # Opens the interface when run without a subcommand
rusty-broom tui ~/dev -o 90d

Projects appear in the list as soon as they are found. Artifact sizes are calculated in the background by a worker pool and update progressively as they finish (uncalculated sizes are displayed with a tilde, e.g., ~4.2 GiB).

Key Action
j/k, ↑/↓ Move selection (g/G for top/bottom, PgUp/PgDn for page up/down)
space Toggle selection mark
a / A Mark all visible / Clear all marks
c, Enter Clean marked (or current) projects—with confirmation
o / O Increase/decrease the "untouched for longer than" threshold
s Cycle sorting order: size → age → path → type
/ Filter by path or type
v Toggle showing projects that have nothing to clean
r Rescan from scratch
? Show keybindings help
q, Esc Exit

Configuration

rusty-broom config init    # Create a user config from the built-in template
rusty-broom config path    # Show which config file is currently in use
rusty-broom config show    # Display the final evaluated configuration

Lookup order: --config FILE → ./.rusty-broom.toml → ~/.config/rusty-broom/config.toml (on macOS: ~/Library/Application Support/rusty-broom/config.toml) → built-in configuration.

Project types are configured as follows:

[settings]
older_than = "30d"
max_depth = 8
require_git_ignored = true

[[project_types]]
name = "rust"
markers = ["Cargo.toml"]      # Used to identify the project
artifacts = ["target"]        # Safe to delete

[[project_types]]
name = "python"
markers = ["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "poetry.lock"]
artifacts = [
    "**/__pycache__", ".venv", "venv", ".tox", ".nox",
    ".mypy_cache", ".pytest_cache", ".ruff_cache", ".ipynb_checkpoints",
    "build", "dist", "*.egg-info", "htmlcov",
]

markers and artifacts support wildcards (*, ?), nested paths (app/build.gradle), and glob patterns (**/__pycache__). By default, a single matching marker is enough; setting require_all_markers = true enforces all of them (which is how the unity type is configured). Defining a [[project_types]] block with an existing name overrides the built-in type, while a new name adds it. Setting enabled = false deactivates the type.

Out of the box, it supports rust, node, python, maven, gradle, sbt, dotnet, go, cmake, swift, cocoapods, elixir, dart, php, ruby, haskell, zig, terraform, unity, and latex (the latter is disabled by default).

Under the Hood

  • scan: Traverses root directories, determines project types, resolves artifact patterns, and dates the project.
  • engine: Comprises a scanner thread and a worker pool. It first filters paths via Git, then measures sizes, and finally handles deletion. All communication happens via channel events, ensuring the UI never freezes due to I/O operations, while the CLI simply processes the stream until completion.
  • clean: Deletion with safety guards. The target must reside within the project root; the root cannot be the user's home directory or too close to the file system root; symbolic links are deleted as links and are never traversed.

Size is calculated based on actually allocated blocks (st_blocks), matching the behavior of the du command.

Development

cargo test
cargo clippy --all-targets
bash scripts/fixture.sh   # Deploy test projects to \$TMPDIR for manual verification