Safe git worktree cleanup for Claude Code and other coding agents.
Coding agents are very good at creating worktrees and very bad at deleting them. After a few weeks of agent-assisted work there are dozens scattered across your machine, quietly holding tens of gigabytes, and no quick way to tell which are merged, which still hold unpushed commits, and which are in use right now.
Asking an agent to sort that out means asking a language model to assemble
git worktree remove --force and git branch -D from whatever it can infer.
One wrong flag deletes work that exists nowhere else.
Bonsai moves that decision out of the model. It finds agent worktrees across
your repositories, classifies each one as safe, review, or protected, and
removes only the safe ones — no matter how the agent asks.
- Finds agent worktrees across every repository on your laptop
- Classifies each worktree as
safe,review, orprotected - Reports reclaimable disk space before anything is deleted
- Protects dirty, unpushed, locked, current, in-use, and open-PR worktrees
- Gives agents structured JSON and a short-lived plan/apply workflow
- Can preserve every approved removal for
bonsai undo
Install the binary:
go install github.com/sauravpanda/bonsai@latestThen install the bundled Claude Code plugin:
/plugin marketplace add sauravpanda/bonsai
/plugin install bonsai@bonsai-tools
Ask Claude to clean up your worktrees naturally, or run:
/bonsai:cleanup
Claude will scan the usual development directories, explain what Bonsai will remove and preserve, ask for approval, and apply the exact approved plan. The plugin enables recovery, so the latest removed worktree can be restored with:
bonsai undoAny agent that can run a shell and read JSON can use the same safe protocol:
# 1. Create a recoverable, machine-readable cleanup plan.
bonsai prune --global --keep-history --json
# 2. Let the agent explain the plan and ask you to approve it.
# 3. Apply only that exact plan after approval.
bonsai prune --apply <plan-id> --yes --json
# 4. Restore the newest removal if you change your mind.
bonsai undo --jsonThis works well with Codex, Cursor, OpenCode, Aider, shell-based agents, and custom automation. Plans expire after 15 minutes and are revalidated before anything is deleted. If a worktree changes after planning, apply stops before removing it.
A good agent instruction is:
Use Bonsai's JSON plan/apply workflow to find safe worktrees globally. Enable keep-history, explain every safe, review, and protected result, ask before applying the plan, and never run raw Git deletion commands.
git clone https://github.com/sauravpanda/bonsai
cd bonsai
make installRequirements:
- Go 1.25+
- Optional: GitHub CLI for PR status and PR creation
bonsai new feat/search
bonsai list
bonsai push --pr
bonsai clean --keep-history
bonsai undoTypical flow:
- Create a worktree for a task.
- See all active worktrees in one place.
- Push and open a PR when the work is ready.
- Clean up merged or stale worktrees without guesswork.
- Undo a recoverable removal when needed.
See every worktree with branch, age, last commit, ahead/behind status, and PR state.
bonsai list
bonsai list --no-pr
bonsai list --offlineExample output:
# PATH BRANCH AGE LAST COMMIT +/- PR
──────────────────────────────────────────────────────────────────────────────────────────────────────
~/projects/myapp main 2h chore: bump deps +0/-0 -
1 .claude/worktrees/feat-auth feat/auth 3d add OAuth flow +4/-0 open
2 .claude/worktrees/fix-payments fix/payments 21d fix stripe webhook +0/-0 merged
3 .claude/worktrees/feat-dashboard feat/dashboard 8d WIP: new dashboard +2/-0 none
Create a new worktree and branch from the configured base branch.
bonsai new feat/search
bonsai new fix/login --base develop
bonsai new spike/idea --openPush a worktree branch, optionally create a PR, and optionally remove the worktree afterward.
bonsai push
bonsai push feat/search
bonsai push --pr
bonsai push --web
bonsai push --pr --remove
bonsai push --pr --remove --yes
bonsai push --pr --remove --keep-history--remove asks before deleting the worktree. Add --yes only when that
removal has already been approved in an automated workflow.
Open an interactive picker for merged, stale, or otherwise removable worktrees.
Commands are repository-local by default. Add --global to discover Git
repositories under common development roots and manage their linked worktrees
in one view.
bonsai clean
bonsai clean --all
bonsai clean --global --all
bonsai clean --global --claude
bonsai clean --global --claude --keep-history
bonsai clean --stale 7
bonsai clean --forcePicker keys: up/down or j/k move, space toggles the highlighted row,
a selects all safe rows, n clears the selection, and enter opens a final
review screen. Confirm deletion there with y or return with n/esc.
Classify merged or inactive worktrees as safe, review, or protected. Automatic cleanup only removes safe worktrees and their local branches.
bonsai prune
bonsai prune --dry-run
bonsai prune --claude
bonsai prune --global --claude --dry-run
bonsai prune --global --claude --json
bonsai prune --global --claude --keep-history --json
bonsai prune --global --root ~/workspace --dry-run
bonsai prune --apply <plan-id> --yes
bonsai prune -y # safe worktrees only--json saves a plan for 15 minutes. Applying the plan rechecks every local
fingerprint first and aborts before deletion if any worktree changed.
--keep-history is stored in the plan, so apply preserves each removed
worktree for recovery.
Every plan reports reclaimable_bytes, so an agent can tell you how much disk
space the cleanup frees before you approve it. Applying returns the matching
reclaimed_bytes.
Global scans are bounded to existing common development directories:
~/Github, ~/GitHub, ~/Projects, ~/Developer, ~/Code, and ~/src.
Use repeatable --root flags to choose other locations. Repository-local
.bonsai.toml settings are honored independently during a global scan.
Remove worktrees by the numbers shown in bonsai list.
bonsai rm 2
bonsai rm 1 3 5
bonsai rm --dry-run 2
bonsai rm --force 2
bonsai rm --keep-history 2Add --keep-history to clean, prune, rm, or push --remove to make the
removal recoverable. Bonsai records the branch and commit, staged and unstaged
binary patches, and non-ignored untracked files.
bonsai undo # restore the newest removal
bonsai trash list # show all recoverable removals
bonsai trash list --json
bonsai trash restore <id> # IDs may be shortened to a unique prefix
bonsai trash empty --yes # permanently delete all recovery dataRecovery entries live under ~/.bonsai/trash and expire after 30 days by
default. Ignored files, such as dependency directories and build output, are
not archived. Bonsai refuses to restore over an existing path or a branch that
has moved to a different commit.
bonsai switch # interactive picker that prints a cd command
bonsai status # dashboard view of working tree state
bonsai stats # summary across all worktrees
bonsai sync # rebase or merge all worktrees from base
bonsai open 2 # open a worktree in your editor
bonsai snapshot # archive a worktree before deleting it
bonsai doctor # detect broken or orphaned worktreesFor scripts, CI, and coding agents, the dashboard commands provide structured output on stdout without spinner or progress text:
bonsai list --json
bonsai status --json
bonsai stats --json
bonsai sync --dry-run --jsonsync --json reports each non-main worktree as synced, skipped, or
failed, with a reason or error when applicable.
- Classifies candidates as
safe,review, orprotected - Protects staged, modified, untracked, unpushed, locked, current, and open-PR worktrees
- Never lets
--yesor plan/apply delete review or protected worktrees - Revalidates saved plans before making any changes
- Supports opt-in recovery with
--keep-history,undo, andtrash restore - Deletes local branches only for worktrees proven recoverable; never deletes remote branches
- Supports
--dry-runon destructive flows - Gracefully works without GitHub auth
- Uses the
ghCLI instead of managing GitHub tokens directly
Global config lives at ~/.config/bonsai/config.toml.
stale_threshold_days = 14
default_remote = "origin"
default_base = "main"
ticket_pattern = "([A-Z]+-\\d+)"
trash_retention_days = 30Per-repo overrides are supported with .bonsai.toml at the repo root.
Validate both config layers and print the merged effective values:
bonsai config check
bonsai config check --jsonThe check reports the exact source and line for invalid TOML or values, and warns when it finds unknown keys. Syntax, type, and value errors return a non-zero exit code; unknown-key warnings do not.
If gh is installed and authenticated, bonsai can:
- show PR status in
bonsai list - detect merged branches for cleanup
- open PRs from
bonsai push --pr
Setup:
gh auth loginWithout gh, bonsai still works and falls back to local Git safety checks.
Bonsai automatically disables ANSI colors when stdout is redirected or piped.
Set NO_COLOR to any non-empty value or pass the global --no-color flag to
force plain output in a terminal:
NO_COLOR=1 bonsai list
bonsai --no-color statusMIT