Skip to content
Back to skills

Worktree Janitor

ASecurity

Sweep .claude/worktrees/ across every repo in the workspace — list each worktree's branch, dirtiness, age, and merge state; remove the safe ones, flag the rest. Use when the user says "/worktree-janitor", "clean up worktrees", or a checkout fails with "already used by worktree".

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 10, 2026
ai-agentsgobashgit

Security analysis

A100/100

Scanned October 10, 2026

npx -y skills add amntoppo/MasterDeck-Terminal --skill worktree-janitor --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Worktree Janitor?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Worktree Janitor
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/amntoppo-worktree-janitor/badge)](https://www.skillsdirectory.com/skills/amntoppo-worktree-janitor)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: worktree-janitor
description: Sweep .claude/worktrees/ across every repo in the workspace — list each worktree's branch, dirtiness, age, and merge state; remove the safe ones, flag the rest. Use when the user says "/worktree-janitor", "clean up worktrees", or a checkout fails with "already used by worktree".
---

# worktree-janitor — sweep stale Claude worktrees

Goal: reclaim disk and unblock branch checkouts by removing worktrees that are safe to
remove, while never deleting work. Report-then-delete, not delete-then-apologize.

## Steps

### 1. Inventory

Find every repo with worktrees under the configured workspace (`workspace` in
`~/.claude/master/config.json`) — the workspace root itself, if it is a repo, plus the
repos directly inside it:

```bash
ws=$(~/.claude/skills/master/master config get workspace)
# A workspace that is itself a repo sits next to its sibling repos: sweep the folder around it.
root="$ws"; [ -e "$ws/.git" ] && root=$(dirname "$ws")
for r in "$root"/*/.git "$root"/.git; do
  [ -e "$r" ] || continue
  repo=$(dirname "$r")
  [ -d "$repo/.claude/worktrees" ] && echo "== $repo" && git -C "$repo" worktree list
done
```

For each worktree collect, via `git -C <wt>`:
- **branch** (`branch --show-current`; empty = detached HEAD)
- **dirty?** (`status --porcelain` non-empty, untracked included)
- **age** (last commit date, `log -1 --format=%cr`)
- **merged?** (`git -C <repo> branch --merged <default-branch>` contains it, or
  `gh pr list --head <branch> --state merged` shows its PR merged)
- **pushed?** (`git -C <repo> ls-remote --heads origin <branch>` non-empty)

### 2. Classify

| Class | Criteria | Action |
|---|---|---|
| **SAFE** | clean AND (branch merged into default, or detached with no unique commits) | remove |
| **PUSHED** | clean, unmerged, but branch exists on origin | remove worktree, branch survives locally + remotely — say so |
| **DIRTY** | uncommitted changes | never auto-remove — list files, offer kill-worktree-style rescue (stash → remove → checkout in main repo) |
| **UNPUSHED** | clean but has commits on no remote and not merged | flag with commit list; remove only on explicit per-item approval |

Detached-HEAD worktrees (e.g. random-named session leftovers): check
`git log --oneline <sha> --not --branches` — empty means every commit is reachable
from a branch → SAFE; non-empty means orphaned commits → UNPUSHED class.

### 3. Report first

Print the classification table (repo, worktree, branch, class, reason) BEFORE
removing anything. Then:

```bash
git -C <repo> worktree remove <path>      # SAFE + PUSHED rows
git -C <repo> worktree prune
```

Never `worktree remove --force` on a DIRTY row without the user naming it explicitly.
Never delete branches — this skill removes worktree *directories* only; branch
cleanup is a separate ask.

### 4. Summary

Removed / kept / needs-decision counts per repo, disk freed if easily available
(`du -sh` before/after is optional, skip if slow), and the exact command for any
row left for the user.

## Rules

- A worktree currently in use by a live Claude session may refuse removal or break
  that session — if a removal errors with "is locked" or the user says a session is
  active there, skip it.
- The workspace root repo (if the workspace folder is itself a git repo) gets swept too,
  not just the repos inside it.
- One-shot skill: no monitor, no schedule. For recurring hygiene, wrap it in a
  `/loop` or a scheduled routine explicitly.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…