Buildnuke finds and removes regenerable build artifacts under a development
root, replacing one-off rm -rf scripts with a safer two-step loop: scan
(read-only) writes a manifest, you review it, then nuke deletes only the
paths you approved.
Nothing is deleted that you haven't reviewed in manifest.txt first. And nuke
does not trust the manifest blindly — it re-runs the full safety cascade on every
path at delete time, so a stale or hand-edited manifest cannot trick it into
removing something protected, git-tracked, or runtime-critical. scan is
strictly read-only.
A directory is deleted only if it is all of: a known artifact/cache name (or a
marker-required output dir), not protected, not WordPress / a local site /
zz-untracked, not a /src/ package dir, and — inside a git repo —
git-ignored.
# 1. Scan (read-only). Defaults to /Users/tudor/00.DevCenter
./buildnuke.sh scan
# ...or point it at a different root:
./buildnuke.sh scan /path/to/dev/rootScan writes manifest.txt. Review it (see below): every live (non-#) line in
the nukable body is a delete candidate — delete a line, or prefix it with
#, to spare that path.
# 2. Delete the approved nukable paths
./buildnuke.sh nuke # prompts for confirmation
./buildnuke.sh nuke --yes # or -y — non-interactivenuke deletes under the root recorded in the manifest header (the same root the
scan used) and re-checks each path before removing it.
# buildnuke manifest — 2026-05-28 09:14 root=/Users/tudor/00.DevCenter
# NUKABLE: 12.4 GB / 38 dirs — nuke rm -rf's every non-# line in the body.
# PROTECTED: 3.1 GB / 6 dirs — protect.txt; never deleted.
# REVIEW: 0.8 GB / 4 dirs — ambiguous/runtime; clear by hand.
# LEFT ALONE: 9 dirs — git-tracked source / src-package dirs.
#
# ── projects/jabbascript-slop (4.20 GB, 2 dirs) ──
/Users/tudor/00.DevCenter/projects/jabbascript-slop/node_modules # 3.90 GB node_modules
/Users/tudor/00.DevCenter/projects/jabbascript-slop/.next # 312 MB .next
Every artifact lands in one of four tiers:
| Tier | What it is | In the manifest | nuke deletes? |
|---|---|---|---|
| NUKABLE | regenerable artifacts that passed every guard | live (non-#) body lines |
yes |
| PROTECTED | matched protect.txt |
commented, shown for footprint | no |
| REVIEW | ambiguous / runtime — WordPress, local sites, zz-untracked, marker-less output dirs |
commented | no |
| LEFT ALONE | git-tracked source or /src/ package dirs |
counted only (skipped.txt) |
no |
Protected and review tiers are written as commented sections so their disk footprint is visible without making them deletable. Text after the first tab on a line is a human-readable note.
CocoaPods note:
Pods/directories are nukable, and the manifest flags them. Reinstalling pods for an old project can fail — spare anyPodsdir that may need to be restored.
Create the protect list from the template:
cp protect.example.txt protect.txtOne entry per line:
AcreKit
/Users/tudor/00.DevCenter/workspace/metro
- A bare name is broad:
AcreKitprotects any path with anAcreKitsegment (e.g.acrekit-webandacrekit-mobile). - An absolute path protects exactly that directory and everything under it — use it to protect one specific repo rather than a whole family.
Protected paths still appear in the manifest (commented, with sizes). protect.txt
is git-ignored; protect.example.txt is committed.
WordPress installs, zz-untracked/, and Local-by-Flywheel-style sites (detected
by layout) are auto-routed to REVIEW — they don't need to be listed.
A directory is NUKABLE only if it survives all of these, in order:
- protect.txt — listed paths are PROTECTED, never deleted.
- zz-untracked/ — hand-curated downloads → REVIEW.
- WordPress — paths under
wp-admin,wp-content, orwp-includes→ REVIEW (runtime/deploy content, not build output). - Local dev sites — under
Local Sites, or any ancestor withapp/public+conf+logs→ REVIEW. Detected by layout, not name. - /src/ package dirs — a marker-required name under
/src/is a source/package dir → LEFT ALONE. - Sibling marker — an output name (
build,dist, …) with no sibling project marker → REVIEW. - git-ignore — inside a repo, a candidate must be git-ignored to be nukable; tracked dirs are never deleted.
Git-ignore status is supporting evidence, not permission on its own — guards 1–6 still veto.
Two classes of directory name are scanned. The canonical lists are the
ALWAYS, MARKER_REQUIRED, and MARKERS arrays at the top of buildnuke.sh — edit
them there, not here.
- Always treated as artifacts/caches — unambiguous names like
node_modules,.gradle,.kotlin,DerivedData,Pods,.next,__pycache__,.venv, and ~25 more. Still vetoable by the protection, runtime-site, and git-tracked guards. - Marker-required output names —
build,dist,out,target,coverage. Nukable only when the parent has a sibling project marker (package.json,Cargo.toml,go.mod,build.gradle(.kts),settings.gradle(.kts),pom.xml,build.sbt,CMakeLists.txt,Makefile,pyproject.toml,setup.py), because these names also occur as source/package dirs.
| File | Purpose | Git |
|---|---|---|
buildnuke.sh |
scanner + deleter | tracked |
protect.example.txt |
starter template for protect.txt |
tracked |
protect.txt |
local protection list | ignored |
manifest.txt |
latest scan results | ignored |
skipped.txt |
git-tracked source / /src/ package dirs left alone |
ignored |
A Bash script using standard Unix tools available on macOS and most Linux:
find, du, sort, awk, cut, date, rm. git is optional but
recommended — when present it provides the tracked-vs-ignored safety check.
Edit the ALWAYS / MARKER_REQUIRED / MARKERS lists in buildnuke.sh only when a new
tool or ecosystem introduces a regenerable directory name.
After changing the script:
bash -n buildnuke.sh # syntax check
./buildnuke.sh scan /tmp/some-test-root # exercise it on a throwaway root firstInspect the generated manifest before running nuke. For unit testing,
source buildnuke.sh exposes the helper functions (e.g. is_deletable) without
running anything.