wtsweep
Classify and clean up git worktrees across a repo or a directory of repos. One
core, two frontends: an agent-friendly CLI (scan --json, remove) and an
interactive TUI (tui).
What it looks like
wtsweep tui ~/projects --size (verdicts are colored in the real terminal):
wtsweep ~/projects · 2.9 GB reclaimable [1-12/47]
verdict branch size age reasons
api-gateway
[x] safe AGP-412-rate-limit-headers 142MB 12d PR #318 merged, remote branch gone
[ ] review chore/bump-otel-sdk 88MB 3d not merged, no closed PR
core-tools
· locked main 0MB 1d primary worktree of the repo
[x] safe AGP-403-deterministic-scoring 151MB 41d branch merged into default branch, AGP-403: Done
▸ [x] safe GKCS-9176-release-fixup 1MB 6d PR #75 merged
[ ] unsafe hotfix/token-refresh 210MB 0d uncommitted changes, 2 unpushed commit(s)
[ ] safe kepler/agent-run-5cec… 34MB 9d branch merged into default branch, git-locked (needs --force to remove)
merge-mate
· locked develop 0MB 2d protected branch (develop)
[x] safe MM-142-conflict-eval-fixture 47MB 21d branch merged into default branch
3 selected · frees 341 MB
↑/↓ move · space select · a all-safe · f force:false · d delete · r rescan · q quit
The scan --json output feeds agents; see AGENTS.md.
Why
git worktree prune only removes entries whose directory is already gone. It
never tells you which live worktrees are safe to delete. wtsweep answers that
by crossing three signals and refusing to destroy local work.
Verdicts
| verdict |
meaning |
removable |
safe |
clean, pushed, and merged (or PR merged/closed) |
yes |
review |
clean and pushed but not merged |
yes, with intent |
unsafe |
uncommitted or unpushed work |
only with --force |
locked |
primary worktree or a protected branch |
never |
Signals: git (merged / dirty / unpushed / age), gh (PR state, opt-out
with --no-pr), Jira (ticket status, on by default but a no-op without a
token, skip with --no-jira; informational only, never the sole basis for
deletion).
Install
go install (needs Go):
go install github.com/alejandroSuch/wtsweep@latest
Prebuilt binaries: grab a tar.gz for your OS/arch from the
latest release
(linux/darwin, amd64/arm64, built by GoReleaser).
From source:
make install # go install . -> $(go env GOPATH)/bin (put it on PATH)
make build # ./wtsweep
Requires git; gh for PR state (uses your existing auth).
Usage
wtsweep scan [dir] [--json|--quiet] [--no-pr] [--no-jira] [--size] [--fetch] [--older-than 30d] [--verdict v]
wtsweep remove [path...] | --dir <dir> --verdict <v> [--dry-run] [--force] [--prune-branch] [--yes] [--json]
wtsweep tui [dir] (interactive, TTY only)
wtsweep config path|show|init
Examples:
# see what's reclaimable
wtsweep scan ~/projects --json
# list safe worktree paths for piping
wtsweep scan ~/projects --quiet --verdict safe
# preview then delete all safe worktrees under a dir
wtsweep remove --dir ~/projects --verdict safe --dry-run --json
wtsweep remove --dir ~/projects --verdict safe --yes --json
# delete specific worktrees (unsafe ones need --force)
wtsweep remove /path/to/wt --yes
Agents
The CLI is built for non-interactive use: --json to stdout, diagnostics and
structured errors to stderr, a stable exit-code contract, --dry-run before
mutations, and --yes to skip prompts. See AGENTS.md for the
contract and skills/worktree-clean for a
portable playbook any agent runner can follow.
See AGENTS.md.
Config & env
Precedence: flag > env > config file > default. File lives at
~/.config/wtsweep/config.json (XDG_CONFIG_HOME honored). Scaffold it with
wtsweep config init.
| setting |
env |
config key |
| default target |
WTSWEEP_TARGET |
target |
| skip PR lookups |
WTSWEEP_NO_PR |
no_pr |
| Jira enrichment |
WTSWEEP_JIRA |
jira |
| compute size |
WTSWEEP_SIZE |
size |
| fetch before scan |
WTSWEEP_FETCH |
fetch |
| prune merged branch |
WTSWEEP_PRUNE_BRANCH |
prune_branch |
| protected branches |
WTSWEEP_PROTECT |
protect_branches |
| disable update check |
WTSWEEP_NO_UPDATE_CHECK |
no_update_check |
| Jira base URL |
JIRA_BASE_URL |
jira_base_url |
| Jira email |
JIRA_EMAIL |
jira_email |
| Jira token |
JIRA_TOKEN |
jira_token (file is 0600) |
Set Jira credentials in the config file (wtsweep config init, then edit) or
via env. wtsweep config show reports the resolved values (token as a boolean).
Safety
- Never removes a worktree with uncommitted or unpushed work without
--force.
- Never removes the primary worktree or a protected branch (
main, master,
develop by default; configurable).
- A git-locked worktree needs
--force too; wtsweep won't clear the lock silently.
--dry-run and the TUI confirmation show exactly what will be removed first.
Update check
Interactive runs check GitHub for a newer release at most once a day (cached,
best-effort, never blocks) and print a one-line notice to stderr. It is skipped
for --json/--quiet, non-terminals, and dev builds. Disable with
WTSWEEP_NO_UPDATE_CHECK=1 or no_update_check in the config.
License
MIT © Alejandro Such