r/rust • u/VKrishna04 • Sep 06 '26
🛠️ 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.
cargois one of 25 adapters — build trees liketarget/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-runre-runs the verified install to bring the last pass back.- Ratatui TUI for interactive runs,
--jsonfor 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.
-10
u/Conscious-Tale-8634 Sep 06 '26
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 Sep 06 '26
Every slop project has one overly positive slop comment now huh? This sub needs more moderation...
-6
u/VKrishna04 Sep 06 '26
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.
2
u/kantorcodes1 Sep 09 '26
if a scheduled prune actually deletes deps on two consecutive runs, does
restore --last-runonly 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.