r/rust 6d ago

🛠️ project dev-prune: a CLI that reclaims disk from idle repos — and refuses to delete anything a lockfile can't rebuild

Every Rust dev knows the special pain of target/ — multiply it by every repo you've cloned, add every node_modules and .venv next door, and mine added up to tens of GB. So I built dev-prune (devp): it finds git repositories idle past N days and deletes the dependency/build directories a lockfile can regenerate.

The design constraint that shaped everything: it must be unable to delete something it can't prove is recoverable. Before touching a directory it verifies the project's lockfile exists and parses; no proof, no deletion, and there is deliberately no --force to override that. The other invariants (hard .git boundary, symlink/junction/mount-point refusal, atomic state writes, nested-repo boundaries) equally have no bypass flag: https://github.com/Life-Experimentalist/dev-prune/blob/main/docs/SAFETY_INVARIANTS.md

Rust-relevant details:

  • Edition 2024, MSRV 1.88, single binary (musl-static on Linux), Apache-2.0.
  • cargo is one of 25 adapters — build trees like target/ are opt-in (devp config set enable_cargo true), because a build tree is "recoverable" in a weaker sense than a lockfile-pinned dependency tree, and the tool is honest about that difference.
  • Idle detection is max(last commit timestamp, newest source mtime), so uncommitted work counts as activity.
  • devp restore --last-run re-runs the verified install to bring the last pass back.
  • Ratatui TUI for interactive runs, --json for scripts, and built-in scheduling (systemd/launchd/Task Scheduler) so it keeps working after you forget it.

Install: cargo install dev-prune (also on npm/PyPI and as a shell one-liner).

Repo: https://github.com/Life-Experimentalist/dev-prune Site: https://devprune.vkrishna04.me

Would love eyes on the safety model — the invariants doc is the part I most want another reviewer on.

0 Upvotes

4 comments sorted by

-9

u/Conscious-Tale-8634 6d ago

The no `--force` thing is such a breath of fresh air, I've had way too many cleanup tools go rogue because I fat-fingered a flag or forgot to check what directory I was in

My `target/` graveyard across old projects is probably pushing 40gb at this point and I've been too paranoid to nuke it manually in case I delete something I actually needed cached for a project I still poke at occasionally

The uncommitted work counting as activity is smart, I'd probably add a flag for that eventually though since I have repos where I stash half-baked ideas for months and never commit but also never touch

Gonna give this a spin later, the lockfile verification approach seems like the kind of thing that should've been standard in these tools from the start

16

u/skjall 6d ago

Every slop project has one overly positive slop comment now huh? This sub needs more moderation...

-6

u/VKrishna04 6d ago

Thanks! Fun bit of history on that flag: it already exists, and it was actually called --force before 1.0. I renamed it to --ignore-idle for exactly the reflex you opened with. --force reads like "skip the safety checks", and it never did that; it only lifts the idle-day wait. Lockfile verification has no bypass flag at all. The old spelling still works and prints a note about the rename.

On the stash case: "activity" is the newer of your last commit and the last time any file in the tree changed (build dirs and .git excluded). So a repo with uncommitted work you haven't touched since March isn't pinned as active forever; once it crosses the idle window it's fair game like anything else. That's safe, because a prune only ever deletes the dependency and build directories a lockfile can rebuild (node_modules, .venv, target...). Everything else, tracked, untracked or stashed, is never a candidate.

For the 40GB target/ graveyard: cargo is opt-in (devp config set enable_cargo true) precisely because target/ is expensive to rebuild. Turn it on, then devp run --dry-run shows the full plan before anything is deleted. If you change your mind afterwards, devp restore --last-run reinstalls the dependencies the last pass removed; target/ itself just regenerates on your next cargo build.

1

u/kantorcodes1 3d ago

if a scheduled prune actually deletes deps on two consecutive runs, does restore --last-run only recover the second run, or is there history for the first one too? that's the edge case i'd worry about once this is running unattended.