All notable changes to cargo-reclaim will be documented in this file.
Format follows Keep a Changelog. cargo-reclaim uses Semantic Versioning.
- Background triggers are now an array — configure any number of independent
[[background.trigger]]blocks, each with its own cadence, limiter, policy, and disruptiveness. A trigger with no limiter is periodic; one with a limiter fires only when breached. (Replaces the single[background.periodic]/[background.trigger]tables.) - Per-trigger
whole_targetoverride (defaults to[policy].whole_target). Unattendeddeletestill requires theaggressivepolicy andallow_unattended_whole_target_delete = true. - Per-trigger disruptiveness toward active builds:
interrupt_active_build = true— delete in-use artifacts and whole targets even while a build runs (the build fails when its files vanish). Off by default; a normal trigger protects active builds entirely.kill_active_builds = true— before cleaning, terminate thecargo/rustcprocesses building targets under the configroots(SIGTERM, a 5-second grace, then SIGKILL), so the disk fill stops and there is no active build left to protect. Only build processes insiderootsare ever signalled, and never cargo-reclaim itself. This makes an emergencyonly_when_disk_free_below/whole_target = "delete"trigger able to stop a runaway build and reset its target instead of letting the disk reach 100%.
- The single-table
[background.periodic]/[background.trigger]form (0.3–0.4) is replaced by the[[background.trigger]]array. The deprecated flatmode/check_everyform still normalizes into one trigger. - Config parsing is now strict: an unknown or misspelled key in any config table is rejected with an actionable error at load time instead of being silently ignored. A wrong key can no longer leave a trigger mis-limited or a setting quietly unset.
- A
[[background.trigger]]limiter written asonly_when_disk_free_below(the documented spelling, matching the flat[background]form and the README) was silently ignored, because the array parser only accepted a different key name. The limiter therefore read as empty, so a disk-gatedsweep/emergency trigger fired on every cadence regardless of free space — killing builds and cargo-cleaning targets when the disk was nowhere near the threshold. The disk-free limiter key is nowonly_when_disk_free_beloweverywhere, and unknown keys fail loudly (see above), so this class of silent misconfiguration cannot recur. - Active-build protection no longer depends solely on the point-in-time process scan, which could be sampled in a gap between
rustcinvocations (or miss a build driver such ascargo-nextestit does not recognize) and letStaleDeps/StaleIncrementalartifacts be deleted mid-build — deleting a live--all-featuresfeature-variant the running build still links, which cargo will not rebuild while its fingerprint DB considers it fresh, breaking the build. A build writes into its target continuously, so the target's newest artifact mtime is now used as a race-free signal: while any artifact in a target was written within[planner].recent_write_keep_window, the whole target is protected — including the stale classes, whose own mtimes are old by definition and were previously guarded by the process scan alone. Reclaim still happens between builds, and a disruptiveinterrupt_active_build/kill_active_buildstrigger still opts out.
- New
sweeppolicy: cargo-sweep-style reclamation of cold final binaries (final_executable,final_rlib,final_library,final_wasm) once they are older than a sweep age threshold, on top of the balanced removable set. It never deletes whole targets, docs, packages, or unknown files, and — like every policy — reclaims nothing from a target with an active build. Configure the age gate with[planner].sweep_older_than(default 24h). - Per-trigger policy override: a
[background.periodic]or[background.trigger]block may set its ownpolicy(e.g.policy = "sweep"), so a disk-pressure trigger can reclaim more aggressively than the routine cadence while still satisfying the unattended high-policy gate.
- Active builds remain fully protected: while any
cargo/rustcprocess is touching a target, cargo-reclaim reclaims nothing from it (it cannot distinguish a superseded hash variant from a live feature-variant the linker needs without cargo's fingerprint DB). Age-based reclaim happens between builds, where cargo re-plans and rebuilds anything removed.
- Split the
[background]watcher into independent, composable trigger blocks:[background.periodic](fires on a timer) and[background.trigger](fires on a poll). Configure either or both, so a routine cadence and a responsive disk-pressure gate can run at once — the latter can trim the instant free space crosses a threshold instead of waiting for the next periodic pass. - Introduced the limiter concept, orthogonal to the trigger: each block may carry
only_when_disk_free_below,min_free_disk, ormax_target_size. With no limiter a fired run always cleans; with a limiter it cleans only when a threshold is breached. Disk limiters use a cheap free-space check;max_target_sizescans target sizes. - Surfaced non-fatal config deprecation notices through
ReclaimConfig::deprecations, printed as warnings by the scheduler commands.
modeis no longer a[background]key; how a run is triggered is now expressed by the presence of theperiodic/triggerblocks. Policy and budget config still govern what a run removes and how much.
- The flat
[background]keysmode,check_every,only_when_disk_free_below, andmin_free_diskare still accepted and normalized into the new blocks (with a warning), and will be removed in 0.4.mode = "periodic"maps to a[background.periodic]block;mode = "threshold"maps to a[background.trigger]block that inherits[policy].max_target_sizeas a limiter.
- Kept the background inventory from aborting a run when a concurrent
cargo builddeletes an artifact (for example adeps/*.rcgu.oobject file) between directory enumeration and the snapshot's stat; the vanished path is now skipped like the stale-deps and stale-incremental passes already did, instead of failing the run.
0.2.2 - 2026-07-07
- Rejected a
plan --jsondry-run report (or an unrecognized file) passed toapply --plan,edit-plan --plan, orcargo-home apply --planwith an actionable error that points at--save-plan, instead of a raw serialization error about a missingidfield (#1). - Discovered a shared
CARGO_TARGET_DIRorbuild.target-dirthat lives on a different filesystem than the project root without requiring--cross-filesystems; the flag now governs incidental traversal only, not explicitly configured output locations (#2). - Recognized a cargo target directory by its
.rustc_info.jsonmarker regardless of directory name, so a shared target directory named e.g.cargo-targetis listed and cleanable; the genericCACHEDIR.TAGmarker still requires the conventionaltargetname (#2).
- Explained empty
listresults, distinguishing "no Rust project found under the scanned roots" from "Rust projects found, but no cleanable target directories," in both terminal and JSON output.
0.2.1 - 2026-07-05
- Summarized foreground cleanup/apply terminal output by default and wrote complete per-run JSON reports under the cargo-reclaim state directory.
0.2.0 - 2026-07-05
- Made
cargo-reclaim <roots...>the primary cleanup assistant entrypoint, with smart trim as the default cleanup mode for active projects. - Made
cargo-reclaim list <roots...>the read-only target inventory surface and removed the old publictargetscommand surface. - Moved explicit whole-target deletion to the cleanup assistant path with
--target <path> --delete-target --yes, keeping whole-target cleanup separate from default smart trim. - Updated CLI help, JSON inventory output, README examples, and release preparation metadata around the 0.2.0 command model.
- Real terminal assistant coverage for selector, mode, confirmation, cancellation, page-skipping flags, and non-TTY guard behavior.
- Deterministic CLI integration test isolation from live cargo/rustc process scans.
- Improved target inventory sizing throughput and stale plan-test stability before the 0.2.0 release.
0.1.1 - 2026-07-04
- Support Cargo subcommand invocation through
cargo reclaim ...by accepting Cargo's leadingreclaimshim argument before normal command parsing.
0.1.0 - 2026-07-03
First release of cargo-reclaim: safe Cargo artifact cleanup for real Rust workstations.
- Read-only scan and plan workflows for Cargo target directories.
- Persisted cleanup plans with expiration and apply-time revalidation.
- Policy modes:
observe,conservative,balanced,aggressive, andcustom. - Ignore, skip, recent-write, keep-size, and rustc/toolchain preservation controls.
- Cargo target discovery from project roots, Cargo configuration, and target-root evidence.
- Interactive target directory discovery and selected whole-target cleanup through
cargo-reclaim targetsandcargo-reclaim targets clean. - Partial cleanup classes for incremental artifacts, fingerprints, build-script caches, dep-info files, temporary files, object metadata, stale fingerprint-group intermediates, stale hashed
depsvariants, old deps outputs guarded by recent-write windows, and stale incremental sessions or unit variants. - Protected classes for whole targets, docs, packages, timings, final binaries, final libraries, final
.rlib, final.wasm, and unknown artifacts.
- Cargo home cache reporting.
- Cargo home cleanup plans and saved-plan apply.
- Config-driven scheduler execution.
- Resident scheduler service support with platform preview/install/uninstall flows for Linux
systemd-user, macOSlaunchd, and Windows Task Scheduler. - Active
cargo/rustcprocess detection on Linux through procfs and on macOS/Windows through a native process-table provider. - Threshold background cleanup with per-target size ceilings, target size goals, absolute free-space triggers, and durable service state.
- Durable scheduler run logs and state directories.
- Read-only Cargo config recommendations.
- Cargo config preview and explicit apply flow.
- Saved plan editing with list, selector, and interactive modes.
- JSON output for automation-friendly scan, plan, scheduler, target, and Cargo home workflows.
- Deep directory measurement for CLI, scheduler, and background service planning, so cleanup budgets and reported sizes reflect real directory contents.
- Scheduler service status that keeps
runningwhen PID liveness cannot be inspected from the current environment instead of falsely reporting a stale service.
- Destructive flows require explicit confirmation with
--yes. - Saved apply flows revalidate path kind, size, modification time, and symlink state before deletion.
- Whole-target deletion remains separate from partial artifact trimming and requires explicit selected target cleanup or whole-target policy configuration.