Skip to content

Releases

v1.23.1

Choose a tag to compare

@github-actions github-actions released this 05 Nov 10:27
88409da

Fixed

  • A Windows short-name alias can no longer reach .git. On NTFS volumes that keep
    8.3 short names, GIT~1\objects is the same directory as .git\objects, and the
    .git boundary only compared names. dev-prune now resolves every deletion target to its
    real location first and refuses any that lands inside .git, outside the repository, or
    anywhere other than the path that was named. Nothing was known to be hit by this; it was
    found in a security review and closed before anyone could be.

  • A symlinked or junctioned parent directory can no longer stand in for a prunable
    one.
    The link check only looked at the last path component. It now looks at where the
    whole path really leads, for built-in adapters and for prunable.directories alike.

  • A committed prunable declaration can no longer mark un-ignored files as disposable.
    A cloned repository could carry "rebuild": "echo not needed" for a directory holding
    your own untracked data. Declared directories now have to be ignored by Git and not
    tracked, or they are refused with the reason. If you declare one, add it to
    .gitignore first.

  • devp caches clear refuses cache paths it cannot vouch for. Cache locations come
    from environment variables such as CCACHE_DIR and GOMODCACHE. A value that points at
    a filesystem root, at your home directory (or a folder containing it), or at a link is
    now left alone and reported.

  • devp containers clear will not act on a remote daemon. An inherited
    DOCKER_HOST=ssh://... or tcp://... (or CONTAINER_HOST) used to make "free space on
    this machine" prune someone else's engine. The command now stops and says why. Unset the
    variable for that command to clear the local engine.

  • On Windows, a planted node.cmd in a repository is no longer picked up. cmd.exe
    looks in the current directory before PATH, and the pnpm and yarn shims call
    node by bare name. dev-prune now sets NoDefaultCurrentDirectoryInExePath for the
    commands it starts.

  • The bundled TLS stack is updated (rustls 0.23.46, rustls-webpki 0.103.16 and
    webpki-roots 1.0.11). That closes four rustls advisories and two certificate-trust
    advisories (RUSTSEC-2026-0381 and RUSTSEC-2026-0382) in the connection code behind
    devp update.

For contributors

  • The VS Code extension's icon-font tooling now resolves glob 14 and minimatch 11, so
    npm audit is clean for editors/vscode.
  • docs/SAFETY_INVARIANTS.md now says plainly that verification runs the package manager
    in the repository, and that only npm and bun are passed --ignore-scripts.

Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.23.1 / pipx install dev-prune==1.23.1
Rust, no compile cargo binstall dev-prune@1.23.1
Rust, from source cargo install dev-prune --version 1.23.1 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev-prune yourself, air-gapping it, or
pinning it into a container image.

Asset For
dev-prune-v1.23.1-windows-x64.zip Windows on Intel/AMD — almost every Windows PC
dev-prune-v1.23.1-windows-arm64.zip Windows on ARM — Surface Pro X, Snapdragon laptops, Windows in a Mac VM
dev-prune-v1.23.1-windows-x86.zip 32-bit Windows — locked-down corporate images, older industrial machines
dev-prune-v1.23.1-darwin-arm64.tar.gz Apple Silicon Macs — M1 and later
dev-prune-v1.23.1-darwin-x64.tar.gz Intel Macs — 2020 and earlier
dev-prune-v1.23.1-linux-x64.tar.gz Linux on Intel/AMD
dev-prune-v1.23.1-linux-arm64.tar.gz Linux on ARM — Raspberry Pi 4/5, Graviton, ARM CI runners

Both Linux builds are statically linked against musl, so they run on any
distribution including Alpine, with no glibc floor.

32-bit is published for Windows only. There is no 32-bit Linux, no 32-bit
macOS and no 32-bit ARM build on any platform; the install scripts refuse
rather than guess when they meet one.

There is no .vsix on this page. The VS Code extension has its own
version and its own release cadence, so it ships from its own tags:
the extension's releases.
Install it by name instead — VKrishna04.dev-prune, on the
VS Code Marketplace
and on Open VSX.

Windows: the binaries are not code-signed, and two separate features react
to that.

Windows protected your PC is SmartScreen, and it only challenges files
carrying a Mark of the Web — which your browser attaches to the download and
File Explorer copies onto everything it extracts. Clear the mark on the archive
before extracting and nothing inside it is ever marked:

Unblock-File .\dev-prune-v1.23.1-windows-x64.zip

The installers above already do this for you, on the archive and on both
installed copies.

A refusal with no dialog and no "run anyway" is something else: Smart App
Control, which blocks unsigned executables outright and never looks at the mark.
It is on by default on clean installs of Windows 11 22H2+ and always off on
upgraded ones, which is why the same release runs on one machine and not the
next. Unblock-File does not help, and neither does building from source.
The troubleshooting guide
covers what your options actually are.

Every archive ships a .sha256 sidecar. Check it before you trust it:

sha256sum -c dev-prune-v1.23.1-linux-x64.tar.gz.sha256
(Get-FileHash dev-prune-v1.23.1-windows-x64.zip).Hash -eq (Get-Content dev-prune-v1.23.1-windows-x64.zip.sha256).Split(' ')[0].ToUpper()

An archive's hash stops meaning anything the moment you unpack it, and the
unpacked files are the only ones your antivirus ever looks at. So each Windows
zip also ships a .zip.contents.sha256 listing the digest of every file inside
it — run this in the folder you extracted to, from Git Bash (sha256sum ships
with Git for Windows, and is what reads this format):

sha256sum -c dev-prune-v1.23.1-windows-x64.zip.contents.sha256

dev-prune.exe and devp.exe are one file under two names and share a digest
on purpose, so a scanner builds one reputation record instead of two.
devpw.exe — the console-free build the scheduled task runs — is compiled
separately and legitimately has a different one. devp trust prints the same
three digests for the copies already installed on your machine, so you can
compare them against this file without downloading anything again.

That sidecar proves the file was not altered in transit. It does not prove
where it came from — the same hand that swaps an archive swaps its sidecar.
Every archive on this page is also signed by GitHub's build provenance, which
binds it to this repository, this workflow and the commit it was built from:

gh attestation verify dev-prune-v1.23.1-linux-x64.tar.gz --repo Life-Experimentalist/dev-prune
gh attestation verify dev-prune-v1.23.1-windows-x64.zip --repo Life-Experimentalist/dev-prune

Full Changelog: v1.23.0...v1.23.1

v1.23.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 03:22
3559d3d

Added

  • pycache joins the Python group as a regular adapter (on by default): it deletes
    __pycache__ by name alone, since CPython owns that name unconditionally, and deletes
    .pytest_cache, .mypy_cache and .ruff_cache only when a CACHEDIR.TAG file inside
    proves the tool wrote it, per the cache directory tagging
    spec
    . It never touches .hypothesis (holds regression
    examples pytest cannot regenerate on its own), and never .tox or .nox (environments,
    not caches). Verification requires at least one .py file anywhere in the repository,
    so there is always something to regenerate the bytecode and tool caches from. That
    makes thirty-six adapters.

  • devp status reports a Tools line for the output graphify and understand-anything
    leave behind (graphify-out/ and .understand-anything/), because both can grow
    into gigabytes and neither has a lockfile to prove it is safe to delete: rebuilding
    either means re-running the tool's own extraction passes, LLM calls included. The
    interactive dashboard's header and the plain-table view both show the size next to
    everything else, and --json carries it as a tools array on each repository entry.
    It is report-only: never counted in the reclaimable total, and never a candidate for
    devp run.

  • devp status opens an inspector pane beside the table on terminals at least 110
    columns wide: the selected repository's per-directory sizes, root-commit identity,
    idle window, last prune, lifetime space saved and detected adapters, all in one
    place instead of behind devp doctor <path>. It also draws a sparkline of the
    repository's commits over the last 26 weeks and lists the five largest entries inside
    its bloat directories, both read in the background so moving the selection never waits
    on a large node_modules. A narrower terminal with at least 34 rows puts the pane
    below the table instead, and Tab hides and shows it.

  • devp scores (the same report as devp history --scores) ranks your all-time
    largest single-repository cleanups and largest whole passes, read from the same pass
    log devp history prints, with medals on the top three of each. --json emits it
    as a document with "command": "history --scores".

  • The registry heals itself. devp status, devp run and devp doctor now
    resolve registry entries whose directory is gone instead of warning about them
    forever. A repository
    that moved into a sibling Archive/-style directory, or anywhere else its root-commit
    identity proves it is the same repository, keeps its lifetime statistics under the new
    path. An entry for a deleted AI-agent worktree (.claude/worktrees/,
    .cursor/worktrees/ and kin) is dropped outright, because the session that creates
    one deletes it when it ends. Nothing is merged on a shared directory name alone, so
    an entry whose drive is merely unplugged stays put until the drive returns.

  • devp skill --prompt workspace (or --prompt agent) prints just that onboarding
    prompt, with no header or code fence around it, so you can pipe it or paste it
    without trimming. Add --copy and it goes straight to the clipboard instead.
    devp skill --rules-file <path> writes the same marked rules block --agent
    uses into any file you name inside the repository, for an editor --agent does not
    list or one that reads a renamed file; a re-run replaces the block and leaves the
    rest of the file alone. See devp skill in the CLI
    reference.

Changed

  • i in devp status asks before it changes anything. A small dialog names the
    repository and what will happen; y or Enter confirms and any other key backs out.
    A stray keypress used to rewrite .devprune.json on whichever row was highlighted.

  • devp update --install and the auto-update also replace the copies cargo put on
    PATH.
    The scheduled pass runs the managed copy, and a copy only ever replaced itself
    and the managed one, so devp typed from ~/.cargo/bin kept answering with the
    release that cargo binstall installed, however many scheduled passes had updated
    since. The dev-prune and devp files in cargo's bin directory now move forward with
    the managed copy, unless they are already the same release or newer (a cargo install --path . development build is never downgraded). Cargo's own record of the installed
    version is not touched, and the update says which command brings it forward.

  • devp doctor names the upgrade command for a stale copy, not only the uninstall
    one. A copy on an older release is usually one you still want, on the current
    release, and "remove with cargo uninstall dev-prune" pointed at deleting the binary
    you type. The line now reads, for example, "upgrade with cargo binstall dev-prune --force or remove with cargo uninstall dev-prune".

  • Windows binaries no longer need the Visual C++ runtime. They link the C runtime
    statically, so the release zip, the install script, Scoop, npm, PyPI and WinGet all
    run on a clean Windows install instead of failing to start with a missing
    VCRUNTIME140.dll. cargo install
    from crates.io still compiles against the dynamic runtime, which any machine with the
    MSVC toolchain already has.

Fixed

  • A pass that found nothing eligible to prune, or stopped early on a lockfile
    verification failure, skipped the auto-update check entirely, so an unattended
    machine whose repositories were all clean or all active could stay on an old release
    indefinitely. The check now runs at the end of every pass regardless of what the
    pass found, with one deliberate exception: a --json pass stays out of it, because
    that mode's stdout is a single machine-readable document and nothing else.

  • The windowless devpw.exe twin the Windows scheduled task runs is now refreshed
    when it is stale against the running binary, so an upgrade no longer leaves the
    scheduled task executing the previous version. And when the twin is missing and the
    console binary runs the task instead, it detaches from its console immediately,
    shortening the window flash.

  • DEV_PRUNE_NO_TUI now keeps every full-screen view closed, as documented. Only the
    config wizard read it, so devp status and the devp run selector still opened
    whenever both ends looked like a terminal, and an AI agent holding a pseudo-terminal
    landed in a keypress loop it had no way to leave. Set the variable and both print
    their plain output instead.

  • -y on devp trust --fix-ownership works in either position. devp -y trust --fix-ownership parsed the flag and then asked anyway, and devp trust --fix-ownership -y was a usage error.

  • devp restore --last-run puts a Go vendor/ directory back. Restore chose between
    go mod vendor and go mod download by checking whether vendor/ existed, but the
    prune had just deleted it, so a vendored repository always got go mod download,
    which exits successfully without recreating anything, and the pass reported
    "restored" over a directory that was still gone. It now rebuilds what the prune
    recorded, and reports a failure unless vendor/ exists afterwards.

  • Pressing i on a repository ignored through the older ignore.devprune.json marker
    took two presses to un-ignore it. The first wrote "ignore": true and deleted the
    marker, so the repository stayed ignored; it is now offered "stop ignoring" straight
    away, and confirming clears both.

  • In devp status, after sorting, filtering or searching, the highlighted row's path
    could keep the colour meant for an unhighlighted one while a different row got the
    white text meant for the highlight, which is unreadable on a light terminal theme.
    The highlight is now matched by its position on screen.

  • devp run --help lists deno and dotnet_build among the --only and --skip
    names, devp caches --help covers every manager the report sizes, and the sample
    output throughout the docs says MiB and GiB, which is what dev-prune prints.

  • When a .devprune.json cannot be read, devp run, devp doctor and devp config
    now suggest devp config project <PATH> --update to reset it. The hint used to say
    devp config <PATH> --update, which is a usage error, so following the advice printed
    only clap's complaint.

For contributors

  • devp uninstall and devp update now recognise a development build anywhere under
    target/, including target/<triple>/release and cargo-llvm-cov's
    target/llvm-cov-target/debug. Before, an uninstall run from one of those deleted the
    binary it was running from, so cargo llvm-cov failed the uninstall tests.

Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.23.0 / pipx install dev-prune==1.23.0
Rust, no compile cargo binstall dev-prune@1.23.0
Rust, from source cargo install dev-prune --version 1.23.0 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev...

Read more

v1.22.0

Choose a tag to compare

@github-actions github-actions released this 20 Sep 09:32

Added

  • Ten new adapters bring the total to thirty-five. pixi joins the regular set (on by
    default): a .pixi/ directory beside pixi.toml, pixi.lock or a pyproject.toml
    with a [tool.pixi] table is verified against pixi.lock read-only, because
    pixi lock --check can re-solve over the network and a verification must never do
    that. The other nine are opt-in like every build tree: Zig (.zig-cache/,
    zig-cache/ and zig-out/ beside a build.zig), Haskell Stack (.stack-work/),
    Haskell Cabal (dist-newstyle/; a lone .cabal file is never claimed), sbt
    (target/ and project/target/ beside build.sbt), and the imported-resource
    caches of Godot, Unity, Unreal, Defold and Cocos Creator. devp config set enable_zig true and friends switch them on, and every one is in the recommended
    set the config wizard offers. That makes thirty-five adapters, eighteen opt-in
    switches and forty-one settings; the whole opt-in class is walked through in
    docs/OPT_IN_BUILD_ADAPTERS.md.

  • devp caches clear docker --include-volumes (podman too): after the narrow
    reclaim, it lists the engine's unused volumes by name and takes one line of picks
    (numbers, ranges, all, or Enter for none), then runs one unforced volume rm <name> per pick. It is consent-gated end to end: it refuses --yes, --json and a
    piped stdin, and the pick list only arms within ten minutes of a completed volume
    dry run for that engine. Typed cold, the command becomes that dry run, and
    --include-volumes --dry-run ends by naming the command to type next. dev-prune
    still never runs volume prune or system prune --volumes anywhere, and the unit
    tests fail the build if any argv it assembles contains prune, --volumes or a
    force flag. nerdctl, finch and Apple's container get a usage error naming
    <engine> volume ls instead, because their volume listings cannot be sized safely.

  • A "Detected, but switched off" section at the end of a bulk dry run. When a
    dormant opt-in adapter would find bloat, devp run --dry-run now says so: how many
    repositories, and the exact devp config set enable_<name> true that would include
    them. The --json document carries the same facts under an additive
    recommendations key, and devp config set recommendations false silences the
    section once you have read it.

  • devp skill --detected and an editor detection report. Plain devp skill now
    ends by naming every editor and agent whose traces are on the machine or committed
    in the repository (home-directory footprints, VS Code-family extensions, rules
    files), and whether each one's rules are current, stale or missing. devp skill --detected then writes the right rules file for everything detected in one pass.
    Detection is pure existence checks; nothing is executed or fetched.

  • Exported rules files now carry three guardrails for the agents that read them: never
    delete a bloat directory by hand (use devp run, and devp restore to put back
    anything devp removed), never clear container volumes through a bulk engine prune,
    and never empty ~/.m2/repository uninvited.
    docs/IDE_INTEGRATION.md adds a copy-paste PreToolUse hook
    that turns the volume rule into a hard confirmation prompt in Claude Code.

Changed

  • The windowless Windows twin (devpw.exe) can no longer fall behind silently. The
    release publishes it as its own asset with a SHA-256 sidecar; devp update --install reconciles every twin alongside the main binary; devp doctor compares
    each twin's build stamp against the running version, names devp update --install
    as the fix, and exits 1 when the scheduled task is actually running a stale twin
    (a warning otherwise); devp doctor --fix performs the reconcile itself. The setup
    pass also self-heals once per version at an attended terminal. All of it stands
    down under DEV_PRUNE_OFFLINE, version_lock, and in development builds.

  • A worktree nested inside its own repository (the shape agent harnesses create under
    .claude/worktrees/) is no longer self-registered by the quiet Git hook or by
    status adoption. An explicit devp link still registers one when you mean it.

  • The no-longer-a-repository report now names both ways out in place (devp unlink <path> to drop the row, git init if the directory should be one again), and the
    nested-repository refusal explains why it exists (no lockfile of yours can vouch
    for someone else's git history) and points at the cache-relocation config for the
    common cause.

Fixed

  • devp restore in a Go repository rebuilds the recorded vendor/ directory again.
    It used to consult the directory the prune had already deleted to decide between
    go mod vendor and go mod download, so a pruned vendor tree came back as a
    module-cache download instead of the vendor/ the build was using.

  • devp trust --fix-ownership -y is honoured with the flag on either side of
    --fix-ownership. Previously one order asked anyway, which is what a script cannot
    answer.

  • DEV_PRUNE_NO_TUI=1 is honoured at every full-screen entry point, including the
    ones reached from inside another command, so agents driving a terminal never get a
    dashboard they cannot read.

  • The scheduled task's windowless twin, and a stray managed-binary alias, could be
    left running a stale release. Both are refreshed by comparing the new copy against
    the one already in place, and that comparison trusted two files with the same size
    and the same modified-time to also hold the same bytes, which is not guaranteed and
    occasionally false. A refresh that hit the coincidence quietly kept the old binary
    in place instead of replacing it. The comparison now always reads both files once
    their lengths match.

For contributors

  • crates.io publishing now uses Trusted Publishing: the release workflow exchanges a
    GitHub OIDC token for a 30-minute crates.io token at publish time, so the
    long-lived CARGO_REGISTRY_TOKEN secret is no longer read by the workflow.

  • Test fixtures create their repositories through git_in (an explicit -C on every
    invocation), so a test run started from inside a Git hook can never act on the
    repository that hosts the checkout.


Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.22.0 / pipx install dev-prune==1.22.0
Rust, no compile cargo binstall dev-prune@1.22.0
Rust, from source cargo install dev-prune --version 1.22.0 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev-prune yourself, air-gapping it, or
pinning it into a container image.

Asset For
dev-prune-v1.22.0-windows-x64.zip Windows on Intel/AMD — almost every Windows PC
dev-prune-v1.22.0-windows-arm64.zip Windows on ARM — Surface Pro X, Snapdragon laptops, Windows in a Mac VM
dev-prune-v1.22.0-windows-x86.zip 32-bit Windows — locked-down corporate images, older industrial machines
dev-prune-v1.22.0-darwin-arm64.tar.gz Apple Silicon Macs — M1 and later
dev-prune-v1.22.0-darwin-x64.tar.gz Intel Macs — 2020 and earlier
dev-prune-v1.22.0-linux-x64.tar.gz Linux on Intel/AMD
dev-prune-v1.22.0-linux-arm64.tar.gz Linux on ARM — Raspberry Pi 4/5, Graviton, ARM CI runners

Both Linux builds are statically linked against musl, so they run on any
distribution including Alpine, with no glibc floor.

32-bit is published for Windows only. There is no 32-bit Linux, no 32-bit
macOS and no 32-bit ARM build on any platform; the install scripts refuse
rather than guess when they meet one.

There is no .vsix on this page. The VS Code extension has its own
version and its own release cadence, so it ships from its own tags:
the extension's releases.
Install it by name instead — VKrishna04.dev-prune, on the
VS Code Marketplace
and on Open VSX.

Windows: the binaries are not code-signed, and two separate features react
to that.

Windows protected your PC is SmartScreen, and it only challenges files
carrying a Mark of the Web — which your browser attaches to the download and
File Explorer copies onto everything it extracts. Clear the mark on the archive
before extracting and nothing inside it is ever marked:

Unblock-File .\dev-prune-v1.22.0-windows-x64.zip

The installers above already do this for you, on the archive and on both
installed copies.

A refusal with no dialog and no "run anyway" is something else: Smart App
Control, which blocks unsigned executables outright and never looks at the mark.
It is on by default on clean installs of Windows 11 22H2+ and always off on
upgraded ones, which is why the same release runs on one machine and not the
next. Unblock-File does not help, and neither...

Read more

v1.21.0

Choose a tag to compare

@github-actions github-actions released this 06 Sep 19:12
e79bf0b

Added

  • devp caches clear npm,uv,pip empties exactly the caches you name. The target
    now takes a comma-separated list, a one-time whitelist with no configuration
    involved. The mirror image is devp caches clear all --except npm,uv: everything
    goes except the names given, for the day one cache is the only one worth keeping
    warm. --except only pairs with all (a list already says exactly what to clear),
    and a container engine never appears in either form: naming an engine alone remains
    the consent to touch it. Flags, exit codes and the maven rule are in
    the CLI reference.

Changed

  • A prunable declaration is now checked against the manifest its rebuild command
    would read, not just against your PATH.
    "rebuild": "npm run build" used to pass
    the moment npm was installed — even in a project whose package.json has no build
    script. dev-prune would call the directory recoverable, delete it, and the command
    meant to put it back would fail. It now reads the manifest and refuses instead:

    ! `site/dist` is declared prunable, rebuilt by `npm run build`, but `package.json`
      defines no `build` script — refusing to delete something that command cannot put
      back. Add a `build` script to `package.json`, or fix the command.
    

    Covered where a manifest in the tree can answer: npm/pnpm/yarn run <script>
    and the bare pnpm <script> / yarn <script> forms, honouring --prefix, -C,
    --dir and --cwd so npm --prefix docs run build reads docs/package.json;
    make <target> against the Makefile, honouring -C and -f; uv run <script>
    against [project.scripts] in pyproject.toml; and cargo <subcommand> for names
    that are neither cargo's own nor any installed cargo-<name> plugin.

    Two things this deliberately does not do. It never runs the rebuild command, or any
    part of it — every check is a read of a file already in the tree. And a command shape
    it cannot resolve is allowed through rather than guessed at: a shell pipeline, a
    target held in a variable, a tool with no manifest behind it, or a manifest that is
    absent or unparseable all fall back to the tool check alone, because a false refusal
    blocks a prune that was safe.

    One gotcha worth naming: [tool.uv.scripts] is not a table uv reads. A script
    declared only there does nothing, so uv run <that script> is refused, and the
    message says to move it to [project.scripts].

  • devp caches clear now ends with the reinstall command for browser bundles.
    Playwright, Puppeteer and Cypress binaries do not come back with the next
    npm install; they only return when their own installer runs. Clearing one of those
    caches now prints the command that brings it back (npx playwright install,
    npx puppeteer browsers install, npx cypress install) right where you cleared it,
    instead of leaving the next broken test run to say it later.

Fixed

  • A read-only file no longer stops the whole delete on Windows. go mod writes
    module directories read-only on purpose, and the odd npm package ships a read-only
    file too; a single one used to fail the prune with Access Denied partway through.
    dev-prune now clears the attribute the way rimraf does and retries. A delete that
    still fails after that is reported honestly, as before.
  • Dropping an ignore.devprune.json marker no longer resets the idle clock.
    Creating the marker is bookkeeping, not work, but its timestamp used to count as
    project activity: un-ignore a repository later and it looked freshly touched, waiting
    out idle_days all over again. The marker now sits beside .devprune.json and
    project.devprune.json in the activity walk's exclusion list.

Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.21.0 / pipx install dev-prune==1.21.0
Rust, no compile cargo binstall dev-prune@1.21.0
Rust, from source cargo install dev-prune --version 1.21.0 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev-prune yourself, air-gapping it, or
pinning it into a container image.

Asset For
dev-prune-v1.21.0-windows-x64.zip Windows on Intel/AMD — almost every Windows PC
dev-prune-v1.21.0-windows-arm64.zip Windows on ARM — Surface Pro X, Snapdragon laptops, Windows in a Mac VM
dev-prune-v1.21.0-windows-x86.zip 32-bit Windows — locked-down corporate images, older industrial machines
dev-prune-v1.21.0-darwin-arm64.tar.gz Apple Silicon Macs — M1 and later
dev-prune-v1.21.0-darwin-x64.tar.gz Intel Macs — 2020 and earlier
dev-prune-v1.21.0-linux-x64.tar.gz Linux on Intel/AMD
dev-prune-v1.21.0-linux-arm64.tar.gz Linux on ARM — Raspberry Pi 4/5, Graviton, ARM CI runners

Both Linux builds are statically linked against musl, so they run on any
distribution including Alpine, with no glibc floor.

32-bit is published for Windows only. There is no 32-bit Linux, no 32-bit
macOS and no 32-bit ARM build on any platform; the install scripts refuse
rather than guess when they meet one.

There is no .vsix on this page. The VS Code extension has its own
version and its own release cadence, so it ships from its own tags:
the extension's releases.
Install it by name instead — VKrishna04.dev-prune, on the
VS Code Marketplace
and on Open VSX.

Windows: the binaries are not code-signed, and two separate features react
to that.

Windows protected your PC is SmartScreen, and it only challenges files
carrying a Mark of the Web — which your browser attaches to the download and
File Explorer copies onto everything it extracts. Clear the mark on the archive
before extracting and nothing inside it is ever marked:

Unblock-File .\dev-prune-v1.21.0-windows-x64.zip

The installers above already do this for you, on the archive and on both
installed copies.

A refusal with no dialog and no "run anyway" is something else: Smart App
Control, which blocks unsigned executables outright and never looks at the mark.
It is on by default on clean installs of Windows 11 22H2+ and always off on
upgraded ones, which is why the same release runs on one machine and not the
next. Unblock-File does not help, and neither does building from source.
The troubleshooting guide
covers what your options actually are.

Every archive ships a .sha256 sidecar. Check it before you trust it:

sha256sum -c dev-prune-v1.21.0-linux-x64.tar.gz.sha256
(Get-FileHash dev-prune-v1.21.0-windows-x64.zip).Hash -eq (Get-Content dev-prune-v1.21.0-windows-x64.zip.sha256).Split(' ')[0].ToUpper()

An archive's hash stops meaning anything the moment you unpack it, and the
unpacked files are the only ones your antivirus ever looks at. So each Windows
zip also ships a .zip.contents.sha256 listing the digest of every file inside
it — run this in the folder you extracted to, from Git Bash (sha256sum ships
with Git for Windows, and is what reads this format):

sha256sum -c dev-prune-v1.21.0-windows-x64.zip.contents.sha256

dev-prune.exe and devp.exe are one file under two names and share a digest
on purpose, so a scanner builds one reputation record instead of two.
devpw.exe — the console-free build the scheduled task runs — is compiled
separately and legitimately has a different one. devp trust prints the same
three digests for the copies already installed on your machine, so you can
compare them against this file without downloading anything again.

That sidecar proves the file was not altered in transit. It does not prove
where it came from — the same hand that swaps an archive swaps its sidecar.
Every archive on this page is also signed by GitHub's build provenance, which
binds it to this repository, this workflow and the commit it was built from:

gh attestation verify dev-prune-v1.21.0-linux-x64.tar.gz --repo Life-Experimentalist/dev-prune
gh attestation verify dev-prune-v1.21.0-windows-x64.zip --repo Life-Experimentalist/dev-prune

Full Changelog: v1.20.0...v1.21.0

v1.20.0

Choose a tag to compare

@github-actions github-actions released this 04 Sep 14:26
08a8eac

Added

  • Adapter idle windows now show up in the report. A repository idle past
    idle_days whose target/ still waits on build_idle_days (or an
    adapter_idle_days entry) used to hold that adapter in silence — the node_modules
    row appeared, the target/ row simply didn't, and nothing said why. Now devp run
    prints one Not examined (adapter idle window: N days) line per held adapter,
    devp run --explain and devp doctor <repo> name the window and the
    devp --ignore-idle run override, and --json carries it as a new
    skipped_adapter_window status. One reading note for scripts: in
    devp status --json, a repository held only by such windows now reports the lowest
    unmet window as its idle_days — the threshold it is actually held to — rather
    than the configured setting.

Changed

  • A registered folder that lost its .git no longer fails every scheduled pass.
    Delete and re-clone a repository by hand, or git worktree prune a registered
    worktree, and the leftover entry used to count as a blocking error — exit 1 on
    every devp run until you went looking for why. It is now reported as what it is, a
    stale registry entry: the pass names the path, hints devp unlink <path>, exits
    0, and --json tags the row not_a_repo. If your automation alerts on devp run's
    exit code, note the change: this situation was exit 1 before 1.20.0 and is exit 0
    now. (devp unlink --missing deliberately does not clear these — the directory still
    exists; only its .git is gone.)
  • The scheduled prune no longer skips laptops on battery. The Windows task is now
    registered to start on battery power, keep running if the charger is pulled, and
    fire as soon as the machine wakes if it slept through the scheduled time
    (StartWhenAvailable). Existing installations are repaired in place: the next run
    of any devp command that checks the daemon rewrites the task's power settings
    without moving its schedule. A task dev-prune cannot rewrite is reported by
    devp doctor instead of silently left strict.
  • A failed update check retries the next day, not next week. When the release
    check cannot reach GitHub — captive portal, proxy, flaky hotel Wi-Fi — the failure
    used to consume the whole update_check_interval, so one bad morning meant a week
    of not hearing about a new release. A failed check is now retried after a day.

Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.20.0 / pipx install dev-prune==1.20.0
Rust, no compile cargo binstall dev-prune@1.20.0
Rust, from source cargo install dev-prune --version 1.20.0 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev-prune yourself, air-gapping it, or
pinning it into a container image.

Asset For
dev-prune-v1.20.0-windows-x64.zip Windows on Intel/AMD — almost every Windows PC
dev-prune-v1.20.0-windows-arm64.zip Windows on ARM — Surface Pro X, Snapdragon laptops, Windows in a Mac VM
dev-prune-v1.20.0-windows-x86.zip 32-bit Windows — locked-down corporate images, older industrial machines
dev-prune-v1.20.0-darwin-arm64.tar.gz Apple Silicon Macs — M1 and later
dev-prune-v1.20.0-darwin-x64.tar.gz Intel Macs — 2020 and earlier
dev-prune-v1.20.0-linux-x64.tar.gz Linux on Intel/AMD
dev-prune-v1.20.0-linux-arm64.tar.gz Linux on ARM — Raspberry Pi 4/5, Graviton, ARM CI runners

Both Linux builds are statically linked against musl, so they run on any
distribution including Alpine, with no glibc floor.

32-bit is published for Windows only. There is no 32-bit Linux, no 32-bit
macOS and no 32-bit ARM build on any platform; the install scripts refuse
rather than guess when they meet one.

There is no .vsix on this page. The VS Code extension has its own
version and its own release cadence, so it ships from its own tags:
the extension's releases.
Install it by name instead — VKrishna04.dev-prune, on the
VS Code Marketplace
and on Open VSX.

Windows: the binaries are not code-signed, and two separate features react
to that.

Windows protected your PC is SmartScreen, and it only challenges files
carrying a Mark of the Web — which your browser attaches to the download and
File Explorer copies onto everything it extracts. Clear the mark on the archive
before extracting and nothing inside it is ever marked:

Unblock-File .\dev-prune-v1.20.0-windows-x64.zip

The installers above already do this for you, on the archive and on both
installed copies.

A refusal with no dialog and no "run anyway" is something else: Smart App
Control, which blocks unsigned executables outright and never looks at the mark.
It is on by default on clean installs of Windows 11 22H2+ and always off on
upgraded ones, which is why the same release runs on one machine and not the
next. Unblock-File does not help, and neither does building from source.
The troubleshooting guide
covers what your options actually are.

Every archive ships a .sha256 sidecar. Check it before you trust it:

sha256sum -c dev-prune-v1.20.0-linux-x64.tar.gz.sha256
(Get-FileHash dev-prune-v1.20.0-windows-x64.zip).Hash -eq (Get-Content dev-prune-v1.20.0-windows-x64.zip.sha256).Split(' ')[0].ToUpper()

An archive's hash stops meaning anything the moment you unpack it, and the
unpacked files are the only ones your antivirus ever looks at. So each Windows
zip also ships a .zip.contents.sha256 listing the digest of every file inside
it — run this in the folder you extracted to, from Git Bash (sha256sum ships
with Git for Windows, and is what reads this format):

sha256sum -c dev-prune-v1.20.0-windows-x64.zip.contents.sha256

dev-prune.exe and devp.exe are one file under two names and share a digest
on purpose, so a scanner builds one reputation record instead of two.
devpw.exe — the console-free build the scheduled task runs — is compiled
separately and legitimately has a different one. devp trust prints the same
three digests for the copies already installed on your machine, so you can
compare them against this file without downloading anything again.

That sidecar proves the file was not altered in transit. It does not prove
where it came from — the same hand that swaps an archive swaps its sidecar.
Every archive on this page is also signed by GitHub's build provenance, which
binds it to this repository, this workflow and the commit it was built from:

gh attestation verify dev-prune-v1.20.0-linux-x64.tar.gz --repo Life-Experimentalist/dev-prune
gh attestation verify dev-prune-v1.20.0-windows-x64.zip --repo Life-Experimentalist/dev-prune

Full Changelog: v1.19.0...v1.20.0

v1.19.0

Choose a tag to compare

@github-actions github-actions released this 03 Sep 18:32
841fd5b

Added

  • devp update now asks before installing. When a newer release exists and you are
    at a terminal, the report ends with Install vX.Y.Z now? [y/N] — Enter leaves the
    binary alone, y runs the same download-verify-replace that --install always did.
    The global -y flag answers yes up front, and devp update --install still skips
    the report entirely. Run from a script or a pipe, nothing changes: the check never
    asks and never installs.

Fixed

  • The release check no longer reads api.github.com, whose sixty-requests-an-hour
    limit per unauthenticated address could turn devp update (and the passive
    update check) into a 403 that surfaced as "Could not reach the release API".
    The version now comes from the redirect Location of the release page at
    github.com/Life-Experimentalist/dev-prune/releases/latest, which has no such
    quota — and when the check does fail, the error now prints its full cause chain
    instead of a one-line summary.
  • The install pages taught commands that quietly did nothing on a machine that already
    had dev-prune — uv tool install dev-prune reports "already installed" and exits
    successfully having changed nothing, and npm, bun, pnpm and yarn share the trap. The
    README, the site and the docs now quote the spelling that both installs and updates:
    @latest where the manager re-resolves it, --force for pipx, --upgrade for pip.

For contributors

  • scripts/bump-version.sh now rewrites the three version strings in SECURITY.md
    (the supported-series table row and the two gh attestation verify example
    filenames), so a version bump no longer fails check-version.sh until SECURITY.md
    is edited by hand.

Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.19.0 / pipx install dev-prune==1.19.0
Rust, no compile cargo binstall dev-prune@1.19.0
Rust, from source cargo install dev-prune --version 1.19.0 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev-prune yourself, air-gapping it, or
pinning it into a container image.

Asset For
dev-prune-v1.19.0-windows-x64.zip Windows on Intel/AMD — almost every Windows PC
dev-prune-v1.19.0-windows-arm64.zip Windows on ARM — Surface Pro X, Snapdragon laptops, Windows in a Mac VM
dev-prune-v1.19.0-windows-x86.zip 32-bit Windows — locked-down corporate images, older industrial machines
dev-prune-v1.19.0-darwin-arm64.tar.gz Apple Silicon Macs — M1 and later
dev-prune-v1.19.0-darwin-x64.tar.gz Intel Macs — 2020 and earlier
dev-prune-v1.19.0-linux-x64.tar.gz Linux on Intel/AMD
dev-prune-v1.19.0-linux-arm64.tar.gz Linux on ARM — Raspberry Pi 4/5, Graviton, ARM CI runners

Both Linux builds are statically linked against musl, so they run on any
distribution including Alpine, with no glibc floor.

32-bit is published for Windows only. There is no 32-bit Linux, no 32-bit
macOS and no 32-bit ARM build on any platform; the install scripts refuse
rather than guess when they meet one.

There is no .vsix on this page. The VS Code extension has its own
version and its own release cadence, so it ships from its own tags:
the extension's releases.
Install it by name instead — VKrishna04.dev-prune, on the
VS Code Marketplace
and on Open VSX.

Windows: the binaries are not code-signed, and two separate features react
to that.

Windows protected your PC is SmartScreen, and it only challenges files
carrying a Mark of the Web — which your browser attaches to the download and
File Explorer copies onto everything it extracts. Clear the mark on the archive
before extracting and nothing inside it is ever marked:

Unblock-File .\dev-prune-v1.19.0-windows-x64.zip

The installers above already do this for you, on the archive and on both
installed copies.

A refusal with no dialog and no "run anyway" is something else: Smart App
Control, which blocks unsigned executables outright and never looks at the mark.
It is on by default on clean installs of Windows 11 22H2+ and always off on
upgraded ones, which is why the same release runs on one machine and not the
next. Unblock-File does not help, and neither does building from source.
The troubleshooting guide
covers what your options actually are.

Every archive ships a .sha256 sidecar. Check it before you trust it:

sha256sum -c dev-prune-v1.19.0-linux-x64.tar.gz.sha256
(Get-FileHash dev-prune-v1.19.0-windows-x64.zip).Hash -eq (Get-Content dev-prune-v1.19.0-windows-x64.zip.sha256).Split(' ')[0].ToUpper()

An archive's hash stops meaning anything the moment you unpack it, and the
unpacked files are the only ones your antivirus ever looks at. So each Windows
zip also ships a .zip.contents.sha256 listing the digest of every file inside
it — run this in the folder you extracted to, from Git Bash (sha256sum ships
with Git for Windows, and is what reads this format):

sha256sum -c dev-prune-v1.19.0-windows-x64.zip.contents.sha256

dev-prune.exe and devp.exe are one file under two names and share a digest
on purpose, so a scanner builds one reputation record instead of two.
devpw.exe — the console-free build the scheduled task runs — is compiled
separately and legitimately has a different one. devp trust prints the same
three digests for the copies already installed on your machine, so you can
compare them against this file without downloading anything again.

That sidecar proves the file was not altered in transit. It does not prove
where it came from — the same hand that swaps an archive swaps its sidecar.
Every archive on this page is also signed by GitHub's build provenance, which
binds it to this repository, this workflow and the commit it was built from:

gh attestation verify dev-prune-v1.19.0-linux-x64.tar.gz --repo Life-Experimentalist/dev-prune
gh attestation verify dev-prune-v1.19.0-windows-x64.zip --repo Life-Experimentalist/dev-prune

What's Changed

  • ci: bump softprops/action-gh-release from 3.0.2 to 3.0.3 in the actions-minor-and-patch group by @dependabot[bot] in #29
  • deps(site): bump @types/react-dom from 19.2.4 to 19.2.5 in /site in the site-minor-and-patch group by @dependabot[bot] in #28

New Contributors

Full Changelog: v1.18.0...v1.19.0

v1.18.0

Choose a tag to compare

@github-actions github-actions released this 02 Sep 11:19
514d198

Added

  • devp config set enable_dotnet_build true adds a twenty-fifth adapter: the .NET
    build output MSBuild writes. bin/ and obj/ are the most generic directory names a
    repository can hold, so the adapter demands proof before claiming either — NuGet's
    restore writes obj/project.assets.json recording exactly which project it restored,
    and only when that record names a project file in the same directory is obj/
    claimed, with bin/ going along only when it holds nothing but Debug/Release
    build output. A bin/ full of committed tools, or an obj/ someone made by hand, is
    never touched. Opt-in like every build-tree adapter and idle-gated by
    build_idle_days; the next dotnet build writes both directories again.

  • devp caches now sizes ccache and sccache, the compiler caches behind most C,
    C++ and Rust CI recipes — routinely several gigabytes that no row accounted for
    before. ccache is asked where its cache is (ccache --get-config cache_dir) and
    cleared with its own ccache --clear; sccache ships neither a path query nor a clear
    command, so its row uses the documented locations (SCCACHE_DIR respected) and
    devp caches clear sccache deletes the directory — after sccache --stop-server
    if the daemon is holding it open, which the report says on the row.

Changed

  • The first run now asks before installing anything. dev-prune used to put its
    integrations in place on the first command — a managed copy of the binary on
    PATH, Git hooks, and a scheduled task running devp run --yes — and open the
    settings walkthrough afterwards. Installing first and asking second is, from the
    outside, the exact shape of malware establishing persistence, and anti-virus
    classifiers flagged the 1.17.0 release executable for that behaviour. Now the
    walkthrough opens first, its opening screen lists exactly what finishing it will
    install, and nothing is installed until you finish it: accepting the recommended
    setup is still one key (a), everything it enables can still be switched off
    individually on the settings list, and quitting (q) installs nothing — durably,
    so no later upgrade installs it either. devp setup remains the standing way to say
    yes later, devp uninstall now clears the answer so a reinstall asks again, and
    machines upgrading from 1.17.0 or earlier are not re-asked — keeping the
    integrations the old flow installed already answered the question.

Fixed

  • devp config project <PATH> --team now writes the public schema URL into the
    committed project.devprune.json. It used to inherit the personal file's preference
    for the locally installed schema copy, which put a file:///C:/Users/<name>/... path
    — username included — into a file whose whole purpose is to be committed, and broke
    IntelliSense on every clone but the author's. If you created one before this release,
    replace its $schema value with
    https://devprune.vkrishna04.me/schemas/v1/devprune.schema.json.

  • A declared rebuild that starts with a shell builtin now says what to write
    instead.
    "rebuild": "cd docs && npm run build" was refused with "Install cd
    first" — advice that cannot be followed, because cd is not a program. The refusal
    now names the actual fix: put the tool first, as in npm --prefix docs run build.
    The check is also the same on every platform now; macOS ships a /usr/bin/cd shim
    that used to let such a declaration through there while Windows refused it.

For contributors

  • The release build now fails if a shipping binary contains dropper-bait strings —
    the PowerShell obfuscation flags, Defender-exclusion cmdlets and injection API names
    that the 1.15.0 hardening removed by hand. scripts/check-binary-hygiene.sh holds
    the list and runs over every staged executable (the Windows zips unpacked,
    devpw.exe included) before anything is published, so a dependency that smuggles
    one back in fails in CI instead of in front of seventy antivirus engines.

Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.18.0 / pipx install dev-prune==1.18.0
Rust, no compile cargo binstall dev-prune@1.18.0
Rust, from source cargo install dev-prune --version 1.18.0 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev-prune yourself, air-gapping it, or
pinning it into a container image.

Asset For
dev-prune-v1.18.0-windows-x64.zip Windows on Intel/AMD — almost every Windows PC
dev-prune-v1.18.0-windows-arm64.zip Windows on ARM — Surface Pro X, Snapdragon laptops, Windows in a Mac VM
dev-prune-v1.18.0-windows-x86.zip 32-bit Windows — locked-down corporate images, older industrial machines
dev-prune-v1.18.0-darwin-arm64.tar.gz Apple Silicon Macs — M1 and later
dev-prune-v1.18.0-darwin-x64.tar.gz Intel Macs — 2020 and earlier
dev-prune-v1.18.0-linux-x64.tar.gz Linux on Intel/AMD
dev-prune-v1.18.0-linux-arm64.tar.gz Linux on ARM — Raspberry Pi 4/5, Graviton, ARM CI runners

Both Linux builds are statically linked against musl, so they run on any
distribution including Alpine, with no glibc floor.

32-bit is published for Windows only. There is no 32-bit Linux, no 32-bit
macOS and no 32-bit ARM build on any platform; the install scripts refuse
rather than guess when they meet one.

There is no .vsix on this page. The VS Code extension has its own
version and its own release cadence, so it ships from its own tags:
the extension's releases.
Install it by name instead — VKrishna04.dev-prune, on the
VS Code Marketplace
and on Open VSX.

Windows: the binaries are not code-signed, and two separate features react
to that.

Windows protected your PC is SmartScreen, and it only challenges files
carrying a Mark of the Web — which your browser attaches to the download and
File Explorer copies onto everything it extracts. Clear the mark on the archive
before extracting and nothing inside it is ever marked:

Unblock-File .\dev-prune-v1.18.0-windows-x64.zip

The installers above already do this for you, on the archive and on both
installed copies.

A refusal with no dialog and no "run anyway" is something else: Smart App
Control, which blocks unsigned executables outright and never looks at the mark.
It is on by default on clean installs of Windows 11 22H2+ and always off on
upgraded ones, which is why the same release runs on one machine and not the
next. Unblock-File does not help, and neither does building from source.
The troubleshooting guide
covers what your options actually are.

Every archive ships a .sha256 sidecar. Check it before you trust it:

sha256sum -c dev-prune-v1.18.0-linux-x64.tar.gz.sha256
(Get-FileHash dev-prune-v1.18.0-windows-x64.zip).Hash -eq (Get-Content dev-prune-v1.18.0-windows-x64.zip.sha256).Split(' ')[0].ToUpper()

An archive's hash stops meaning anything the moment you unpack it, and the
unpacked files are the only ones your antivirus ever looks at. So each Windows
zip also ships a .zip.contents.sha256 listing the digest of every file inside
it — run this in the folder you extracted to, from Git Bash (sha256sum ships
with Git for Windows, and is what reads this format):

sha256sum -c dev-prune-v1.18.0-windows-x64.zip.contents.sha256

dev-prune.exe and devp.exe are one file under two names and share a digest
on purpose, so a scanner builds one reputation record instead of two.
devpw.exe — the console-free build the scheduled task runs — is compiled
separately and legitimately has a different one. devp trust prints the same
three digests for the copies already installed on your machine, so you can
compare them against this file without downloading anything again.

That sidecar proves the file was not altered in transit. It does not prove
where it came from — the same hand that swaps an archive swaps its sidecar.
Every archive on this page is also signed by GitHub's build provenance, which
binds it to this repository, this workflow and the commit it was built from:

gh attestation verify dev-prune-v1.18.0-linux-x64.tar.gz --repo Life-Experimentalist/dev-prune
gh attestation verify dev-prune-v1.18.0-windows-x64.zip --repo Life-Experimentalist/dev-prune

What's Changed

Read more

dev-prune VS Code extension v0.5.0

Choose a tag to compare

@github-actions github-actions released this 03 Sep 18:09
98e03cb
  • A stale “devp not found” now heals itself. The verdict was computed once,
    when the window opened — install the CLI a minute later (or have an antivirus
    quarantine give it back) and the warning stayed for the life of the window,
    and clicking it sent you to the install page for a CLI you already had. The
    extension now re-checks whenever the window regains focus while that warning
    is up, and a click re-probes first: the install page only opens when devp is
    still really missing.
  • A slow devp status no longer looks like a missing one. The status call
    walks every registered repository, and on a machine mid antivirus-scan it
    could outlive the old 15-second limit — the extension then hid its status bar
    item without a word. The limit is now 60 seconds, and reaching it shows
    “devp: not responding” with Refresh one click away, instead of nothing.
  • Prune This Repository is now a palette command. Pruning was reachable
    only through the status-bar QuickPick, and only while it showed a candidate;
    everything else the QuickPick offers already had a Command Palette twin. The
    new command runs devp run . in a visible terminal, same as the QuickPick
    entry — the CLI still decides whether this repository is safely prunable and
    says so in that terminal if not.

Install it from your editor rather than from this page: VKrishna04.dev-prune
on the VS Code Marketplace
and on Open VSX, which
is where VSCodium, Cursor, Windsurf and the other forks look.

The .vsix below is the same file both marketplaces are published from. Take
it if your editor cannot reach either registry:

code --install-extension dev-prune-vscode-0.5.0.vsix

(codium, cursor and windsurf accept the same flag.)

gh attestation verify dev-prune-vscode-0.5.0.vsix --repo Life-Experimentalist/dev-prune

The extension needs the devp CLI for everything except schema validation.
It is released separately — the latest release
is always the CLI, never this.

v1.17.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 20:37
979f06d

Added

  • devp caches clear docker (also podman, nerdctl, finch and Apple's
    container) runs the container prune commands the report has been printing since
    1.13.0, instead of asking you to go and type one in another window. Build cache, unused
    images, stopped containers — printed first, after a prompt, and counted on its own line
    in devp stats, so the 20 GiB you reclaimed on dev-prune's advice is space dev-prune
    can actually account for. --dry-run shows the commands and the estimate and touches
    nothing.

    It will not touch a volume, and there is no flag that makes it. No argument anywhere
    in its table contains the word, and a unit test fails the build if one appears. An image
    can be pulled again and a build cache rebuilt; what is inside a named volume is the only
    copy. docker volume prune stays a command it prints and you type — and the estimate
    has the engine's unused-volume figure taken out of it and named separately, rather than
    promising back space these commands cannot give.

    Nothing on a schedule reaches any of this: no daemon, no Git hook, no devp run, and
    not devp caches clear all either. Naming the engine is the consent.
    Reference

  • How a repository gets registered
    is every way a repository can land on a machine, and which of the three mechanisms
    catches it. A repository you unzipped, copied from another machine, restored from a
    backup or received over Dropbox never runs git, so no hook can ever fire for it —
    discovery is what covers those, and the table says so instead of leaving you to work it
    out. It also names the one case that still needs a hand, and what is skipped on purpose.

  • devp history answers the question devp stats raises. That report says ten passes
    freed 27.66 GiB; this one says pass #2 ran at 09:14 as devp run --daemon, took
    4.02 GiB out of two repositories, and names all three directories it deleted. Bare, it
    is one line per pass. devp history --pass 1 opens one in full: the exact command line,
    the version that ran it, and every directory removed with its package manager and size,
    grouped by repository.

    It records what started each pass, which nothing did before — manual if you typed
    devp run, scheduled if it was the background pass, dashboard if it was the [p]
    key in devp status. There are three ways to start a prune and those are all three, so
    "was that me or the daemon?" now has an answer rather than an inference.

    Long output has three exits rather than a truncation: detail is per-pass and opt-in, the
    directory list is capped at 200 entries only when it is going to a terminal (redirect
    or pipe it and nothing is elided), and devp history --export writes the whole document
    to your documents folder — or to exactly the path you name.

    Passes from before this release still appear, marked (totals only): their four numbers
    were always in the registry, and a history that started empty next to a devp stats
    reading "10 prune passes" would look like a bug rather than a gap. devp history --json
    carries detail: false on those, so a script can tell "deleted nothing" from "nobody
    wrote it down".
    Reference

  • devp caches now finds the stores that were quietly the largest things on the disk.
    Playwright and Puppeteer keep a whole browser build per version, Cypress an unpacked
    Electron application per version, and none of them ever removes the old one when the
    dependency moves — on the machine this was written on that was 2.9 GiB nothing had ever
    reported. The HuggingFace hub cache, the Electron download cache and electron-builder's
    own store are in the report for the same reason. Each gets the row every other cache
    gets: a size, the path, devp caches clear <name>, and the command that clears it.

    huggingface carries a warning the others do not, because it is the one row where
    "re-download it" is not a promise. A gated or now-private repository will not hand the
    weights back to the token that fetched them last month, a checkpoint from a deleted
    revision is gone, and the re-download is tens of gigabytes rather than tens of
    megabytes. It is cleared like anything else when you type it — with the path printed
    first, so you can look inside before you do.
    Reference

  • Six adapters that pruned projects with nothing to show for it now have a cache row.
    devp run has always cleaned a Bundler, pub, SwiftPM, Terraform, Poetry or PDM project;
    devp caches could not see the machine-wide store those projects were reinstalling
    from, so the report answered "where did my disk go" with a gap exactly where the answer
    was. Each is asked where its cache is rather than assumed — gem env gemdir,
    poetry config cache-dir, pdm config cache_dir — and each row names the one
    subdirectory that is genuinely a download cache. That last part is the whole care taken
    here: dart pub cache clean would also delete your globally activated executables and
    your git/ checkouts, and Poetry's cache directory holds virtualenvs/ beside
    artifacts/. dev-prune clears the archives and nothing else.
    Reference

  • A Deno adapter, the twenty-fourth. It detects on deno.lock and takes the
    node_modules a Deno project with npm dependencies materialises, sized the way bun's is
    because Deno hardlinks it out of DENO_DIR too. deno install puts it back, and
    devp caches clear deno empties the shared cache behind it.

    It takes vendor/ only when the Deno config asked for one. Go and Composer both use
    that name at a project root for something else entirely, and a repository carrying a
    deno.lock alongside either would otherwise have had its Composer dependencies deleted
    with deno install offered to put them back. The config is parsed rather than searched,
    so a "vendor": true somebody commented out in a deno.jsonc reads as what it is.
    Reference

  • finch and Apple's container join the container report and devp caches clear.
    finch is nerdctl inside a Lima VM and forwards system to it verbatim, so it reads and
    clears exactly as nerdctl does. Apple's engine is the odd one: its system df answers
    with a single object rather than a row per resource, it has no system prune, and its
    prune subcommands neither ask a question nor define a -f — so those steps run the
    moment they are typed, and devp caches containers container says so in as many words
    before it lists them. The confirmation is dev-prune's own, and it is still there.
    Reference

  • devp config set cache_max_gb default=10 caps every download cache at once,
    without you first having to learn which twenty-nine of them exist. Until now a ceiling
    had to name a manager, which meant the setting only ever covered the caches you had
    already thought about — and the one that has quietly passed 10 GiB is rarely one of
    those. A manager named outright still wins: default=10,npm=4 holds npm to four and
    everything else to ten. Setting a ceiling still deletes nothing; it decides what
    devp caches calls too big, and devp caches clear --over-cap all is still typed by
    hand.

    The first run now suggests it, alongside the adapters, and devp config recommended sets it. It is the first suggestion that is not a yes-or-no, so it is
    the first one that can already be satisfied by a different answer: any ceiling at all
    counts as taken. A machine with npm=4 set by hand is listed as Already set,
    never as outstanding, and devp config recommended leaves the number alone rather
    than replacing the map with its own.
    Reference

  • devp stats now says which package manager the space came from. The tool has
    twenty-four adapters and, until now, never told you which of them was earning its keep
    — the lifetime total was one number with nothing behind it. By package manager
    ranks them by what each has given back, with the directory count beside it, so "npm is
    the one costing me" stops being a hunch. It covers pruning only, and says so under
    itself: emptying a cache is not a prune pass, so these figures are not meant to add up
    to the lifetime total above them.

  • devp stats also shows how many passes you typed and how many ran unattended.
    How passes start splits the same reclaims across manual, scheduled and
    dashboard, each with its share. All three print even at zero, because a scheduled
    line reading zero passes is how you find out the daemon has never actually run — and
    when it does read zero, the report points you at devp status daemon. Both sections
    are summed from the prune log, so both are bounded by 1.17.0 and both say how many
    earlier passes they could not account for rather than quietly under-reporting.
    devp stats --json carries them as by_manager and by_trigger.
    Reference

Changed

  • Every binary in devp trust now shows the version it was built as, so the list
    answers the question people open it with. Three of those files are called some spelling
    of the same word, and until now the only thing telling them apart was a path and a
    digest — which meant "which of these is the old one" could only be answered by
    uninstalling something and seeing what broke. The newest is marked (latest release)
    when a releas...
Read more

v1.16.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 07:39
6e25cad

Added

  • devp caches --volume V: reports only the caches sitting on one drive, and the
    unfiltered report now ends with a By drive line splitting the total the same way.
    On a machine whose projects live on a second disk, "22 GiB of caches" is not the
    figure that decides anything — the two gigabytes on the drive that is full is, and
    until now you had to read twelve absolute paths to find it. --drive is the same
    flag; both take a drive (V:, V:\, or the bare letter V), a mount point
    (/mnt/data, /Volumes/Work), or any path on the one you mean, so --volume . is
    the drive you are standing on. In --json, every cache row gains a volume key so a
    consumer can group by drive without deriving a mount table from path.

    The narrowing happens last, after every verdict, so it changes what you see and never
    what a figure means: a cache_max_gb cap still weighs a manager's whole footprint
    wherever it is, and a cache no registered repository uses does not become unused just
    because the repositories that use it live on another drive. Container engines are left
    out of a filtered report entirely — an engine reports its disk from inside a VM image
    that has no path on this filesystem, so there is no honest drive to file it under, and
    the JSON document omits containers rather than emitting an empty list that would
    claim none are installed. devp caches docker still has that number.

    --volume with clear, docker or containers is a usage error rather than a flag
    that looks accepted and does nothing: the clear commands empty a manager wherever it
    is, and a clear that had silently ignored the drive you handed it would be the worst
    possible way to find that out.

  • a finishes the configurator in one keystroke. devp config wizard takes every
    remaining safe recommendation and jumps straight to the summary, which still needs its
    own Enter before anything is written. It applies exactly what holding Enter down
    would have applied — allow_manifest_rewrite is left off by both, because it can edit
    a file Git tracks and that stays a deliberate Space. Shift+Enter does the same
    thing on terminals that report the modifier; a is the spelling that works
    everywhere, so a is the one the footer names. The first screen now says so too:
    hold Enter and the whole setup configures itself.

  • devp trust now ends with every binary it owns and the SHA-256 of each, the one
    you are running marked and listed first, each with a VirusTotal lookup URL for that
    exact digest. When a scanner objects to dev-prune, the file it objected to is the one
    on your disk — not the asset on a release page — and until now there was no way to ask
    the tool which bytes those were. The digests are computed locally and the URLs are
    printed rather than fetched: nothing is uploaded anywhere, and a digest the service has
    never seen returns not found, which means unscanned rather than clean. On Windows
    dev-prune.exe and devp.exe share a digest on purpose — one file under two names, so
    a scanner builds one reputation record instead of two — and devpw.exe, the
    console-free build the scheduled task runs, is a separate build target that legitimately
    differs. devp trust --json carries the same facts under a new binaries array with
    sha256 as a field of its own, so a check can compare it against a published checksum
    without parsing a sentence.

  • Every Windows release now ships a .zip.contents.sha256 listing the digest of each
    file inside the archive, in sha256sum format — sha256sum -c in the folder you
    extracted to verifies all three at once. An archive's hash stops meaning anything the
    moment you unpack it, and the unpacked files are the only ones an antivirus ever looks
    at, so there was previously no published answer to "is the devpw.exe on my disk the
    one you built?". The same digests come out of devp trust, which is the side of the
    comparison you actually control.

Changed

  • The banner now says what the tool is. Under the art, two lines: every dependency
    directory on the machine in one command, and the promise that only what a lockfile can
    rebuild is ever deleted — with devp undo behind that. The screen every interactive
    command opens with said the name, the version and nothing else, so the first thing a
    new user saw answered neither "what does this do beyond node_modules" nor "what
    stops it deleting my work". The version now sits at the right edge under the art
    instead of trailing it, and PRUNE carries the weight DEV does not.

Fixed

  • The configurator no longer skips the settings above the cursor. After an upgrade
    added a setting, devp config wizard opened on that setting — halfway down the
    list. But the walk only moves downwards and leaves through the finish line at the
    bottom, so holding Enter from there never offered a single row above it. Anyone
    configuring the tool the way its own footer suggests was configuring a suffix of it.
    The cursor now starts at the top and the walk reaches everything; the new setting is
    still marked NEW when it comes around.

  • The AI skill now stays current on machines that turned auto-setup off. dev-prune
    exports SKILL.md — the file Claude Code and the other agents read to learn its flags
    — and rewrites it after every upgrade. That refresh rode along with the automatic
    setup pass, so turning setup off (devp config set auto_setup false, or
    DEV_PRUNE_NO_AUTO_SETUP) also froze the skill at whichever version installed it: the
    agent went on describing flags that had been removed two releases ago, confidently,
    because nothing told it otherwise. An upgrade now refreshes the copies that are
    already on disk regardless of that setting, and creates none that were not — a machine
    that never wanted an exported skill still does not get one. devp doctor continues to
    report a stale copy, and devp skill still rewrites it on demand.


Which download do I want?

Most people want none of them. The installers below verify the SHA-256
sidecar, put the binary somewhere already on PATH, and create the devp
alias — three things unzipping an archive does not do.

You are on Run this
Windows (PowerShell) iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex
Windows (Command Prompt) powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://devprune.vkrishna04.me/install.ps1 | iex"
macOS / Linux curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
Python tooling uv tool install dev-prune==1.16.0 / pipx install dev-prune==1.16.0
Rust, no compile cargo binstall dev-prune@1.16.0
Rust, from source cargo install dev-prune --version 1.16.0 (needs Rust 1.88+)

The PyPI packages contain these same binaries rather than downloading one
afterwards, so they work behind a registry mirror and offline. cargo install
is the only channel that compiles on your machine; cargo binstall reaches
for the archives on this page instead.

Full instructions: https://devprune.vkrishna04.me/#install

The assets, then

Take one only if you are packaging dev-prune yourself, air-gapping it, or
pinning it into a container image.

Asset For
dev-prune-v1.16.0-windows-x64.zip Windows on Intel/AMD — almost every Windows PC
dev-prune-v1.16.0-windows-arm64.zip Windows on ARM — Surface Pro X, Snapdragon laptops, Windows in a Mac VM
dev-prune-v1.16.0-windows-x86.zip 32-bit Windows — locked-down corporate images, older industrial machines
dev-prune-v1.16.0-darwin-arm64.tar.gz Apple Silicon Macs — M1 and later
dev-prune-v1.16.0-darwin-x64.tar.gz Intel Macs — 2020 and earlier
dev-prune-v1.16.0-linux-x64.tar.gz Linux on Intel/AMD
dev-prune-v1.16.0-linux-arm64.tar.gz Linux on ARM — Raspberry Pi 4/5, Graviton, ARM CI runners

Both Linux builds are statically linked against musl, so they run on any
distribution including Alpine, with no glibc floor.

32-bit is published for Windows only. There is no 32-bit Linux, no 32-bit
macOS and no 32-bit ARM build on any platform; the install scripts refuse
rather than guess when they meet one.

There is no .vsix on this page. The VS Code extension has its own
version and its own release cadence, so it ships from its own tags:
the extension's releases.
Install it by name instead — VKrishna04.dev-prune, on the
VS Code Marketplace
and on Open VSX.

Windows: the binaries are not code-signed, and two separate features react
to that.

Windows protected your PC is SmartScreen, and it only challenges files
carrying a Mark of the Web — which your browser attaches to the download and
File Explorer copies onto everything it extracts. Clear the mark on the archive
before extracting and nothing inside it is ever marked:

Unblock-File .\dev-prune-v1.16.0-windows-x64.zip

The installers above already do this for you, on the archive and on both
installed copies.

A refusal with no dialog and no "run anyway" is something else: Smart App
Control, which blocks unsigned executables outright and never looks at the mark.
It is on by default on clean installs of Windows 11 22H2+ and always off on
upgraded ones, which is why the same release runs on one machine and not the
next. Unblock-File does not help, and neither does building from source.
The troubleshooting guide
covers what your options actually are.

Every archive ships a .sha256 sidecar. Check it before you trust it:

sha256sum -c dev-prune-v1.16.0-linux-x64.tar.gz.sha256

...

Read more