# Clean Stale

> Find and delete stale worktrees, build artifacts, caches, and dead branches safely, with an inventory-first protocol and freed-space report. Use when asked to clean up, free disk space, remove stale worktrees or artifacts, when a repo or machine "is huge", or when leftover agent worktrees and generated test output accumulate.

- Skill: `marve10s/clean-stale` (Agent Skill)
- Install (CLI): `npx skillmds@latest add marve10s/clean-stale`
- Raw SKILL.md: https://api.skillmd.com/api/skills/marve10s/clean-stale/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: marve10s (https://skillmd.com/u/marve10s)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/marve10s/clean-stale

---


# Clean stale data

Inventory first, classify, then delete. Deletion without a prior inventory line is a bug. Report freed space per item and in total.

## Inventory

Run per repo (or per directory the user names):

```sh
git worktree list                                  # registered worktrees
git status --porcelain --ignored | head -50        # ignored bulk
du -sh <big hits from status> 2>/dev/null | sort -rh
git branch -vv | grep ': gone'                     # branches whose upstream vanished
git worktree prune --dry-run; git remote prune origin --dry-run
find . -maxdepth 3 -name node_modules -prune -o -type d -name ".claude" -print 2>/dev/null
```

Look especially for the recurring offenders: orphaned agent worktrees under `.claude/worktrees/` and `/private/tmp/<repo>-*`, generated test/scaffold output, `.smoke-output`-style ignored artifact dirs, committed generated reports.

## Classification

**Safe — delete without per-item approval, after the checks below pass:**

- Git-ignored build artifacts and caches (`dist`, `.turbo`, `coverage`, `playwright-report`, smoke output).
- Worktree directories NOT in `git worktree list`, once verified clean (below).
- Registered worktrees the user calls stale, once verified clean, via `git worktree remove` then `git worktree prune`.
- Local branches whose upstream is gone AND that hold no unique commits.
- `git worktree prune` and `git remote prune origin` (the non-dry runs).
- `node_modules` inside a directory already classified safe to delete.

**Confirm with the user first — list with sizes, wait for a yes:**

- Any tracked file (deletion is a commit; one-shot authorization rules apply).
- Branches or worktrees holding unique commits (`git log <ref> --not --remotes --oneline` non-empty) or uncommitted changes.
- Remote branch deletion, and anything not authored by the user.
- Caches that are expensive to rebuild (downloaded browsers, models, dependency stores shared across repos).
- Session transcripts, logs, and histories (`~/.codex/sessions`, `~/.claude/projects`) — these are the user's records.

**Never:**

- `.git` internals, git history rewrites, reflog expiry.
- Env files, credentials, keychains.
- Live application state dirs (`~/.<app>` userdata patterns) — real databases live there.
- Anything inside a worktree with a dirty `git status`, beyond that worktree's ignored artifacts.

## Worktree safety check

A worktree directory is safe to delete only when ALL hold:

```sh
git -C <dir> status --porcelain            # empty
git -C <dir> log --branches --not --remotes --oneline  # empty — no unpushed commits
git worktree list | grep -F <dir>          # empty — unregistered, or user confirmed removal
```

Any check fails → report the directory with the failing evidence instead of deleting.

Two verified gotchas:

- A stale clone's own remote-tracking refs freeze at clone time, so `git log --branches --not --remotes` run INSIDE it reports false "unpushed" commits. Resolve each branch SHA and test it against the PARENT repo's live remote instead: `git -C <parent> merge-base --is-ancestor <sha> origin/<main>`.
- A directory whose `.git` is a pointer file is a worktree of some other clone, not of the main repo. Deleting that owner clone first strands the worktree. Delete owner and its worktrees together, after salvaging.

For a dirty clone or worktree whose committed history is fully merged, salvage the uncommitted edits as a patch (`git -C <dir> diff > <name>.patch` into a directory outside the repo), verify the patch is non-empty, then the directory joins the safe class.

## Execution

- Delete sequentially with `rm -rf` on the verified path; no parallel deletion storms on a warm machine.
- After worktree deletions run `git worktree prune` in the parent repo.
- Machine-wide sweeps ("clean my machine") iterate the user's project directories, applying the same protocol per repo; also check the system temp dir for `<repo>-*` scratch checkouts.

## Report

One line per deleted item: path, size, class. One line per skipped item: path and the evidence that blocked it. End with total freed. Nothing else.

