WorktreeRemove hook silently suppresses the /exit "keep or remove" picker
Summary
Registering any WorktreeRemove hook in .claude/settings.json unconditionally suppresses Claude Code's native interactive "keep or remove this worktree?" picker on /exit. There is no documented way to keep the picker AND run a teardown script only when the user confirms removal.
Current behavior
- No hook registered → on
/exitfrom a worktree session, Claude Code shows an interactive picker ("keep" / "remove"). WorktreeRemovehook registered → picker is silently suppressed; the session exits and the hook fires when removal actually happens (which, without the picker, often never does — users have to manuallygit worktree removelater).
Why this is a problem
Worktree teardown frequently involves more than just git worktree remove — for example, stopping per-worktree Supabase containers, killing orphan tunnels, and unbinding Doppler. The hook is the right place for that. But losing the interactive picker means the user no longer gets a friction-free way to confirm removal at exit time, so either:
- They keep the hook and rarely actually remove worktrees (resources leak), or
- They drop the hook and have no automated teardown when they do remove.
Confirmation that no workaround exists
Per the docs (https://code.claude.com/docs/en/hooks.md, https://code.claude.com/docs/en/worktrees.md):
- No pre-removal hook exists (no
WorktreeRemovePre). WorktreeRemove's payload does not indicate trigger source (picker vs external vs internal).SessionEndfires before the removal decision and cannot tell whether removal will happen.- No
settings.jsonkey controls the suppression. - No CLI subcommand or slash command invokes the picker programmatically.
Proposed solutions (any one would solve this)
- Don't suppress the picker when
WorktreeRemoveis registered. Treat the hook as a teardown handler that runs only after the user picks "remove." This matches the natural reading of "WorktreeRemove" as a removal-time event. - Add a
WorktreeRemovePrehook that fires after the user confirms removal in the picker but before deletion, and let users opt into either or both. - Add a settings flag like
worktree.suppressExitPicker: falsethat preserves the picker even when a hook is registered. - Add a payload field to
WorktreeRemoveindicating trigger source ("picker" | "external" | "internal"), so hook authors can branch on it.
Repro
// .claude/settings.json
{
"hooks": {
"WorktreeRemove": [
{
"matcher": "*",
"hooks": [{ "type": "command", "command": "echo teardown ran" }]
}
]
}
}
claudefrom a worktree session, do some work,/exit.- Expected: picker appears asking keep/remove.
- Actual: session exits silently; picker never shown.
Environment
- Claude Code CLI (latest)
- macOS
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗