WorktreeRemove hook silently suppresses the /exit "keep or remove" picker

Resolved 💬 3 comments Opened May 8, 2026 by bvallelunga Closed May 12, 2026

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 /exit from a worktree session, Claude Code shows an interactive picker ("keep" / "remove").
  • WorktreeRemove hook 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 manually git worktree remove later).

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).
  • SessionEnd fires before the removal decision and cannot tell whether removal will happen.
  • No settings.json key controls the suppression.
  • No CLI subcommand or slash command invokes the picker programmatically.

Proposed solutions (any one would solve this)

  1. Don't suppress the picker when WorktreeRemove is 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.
  2. Add a WorktreeRemovePre hook that fires after the user confirms removal in the picker but before deletion, and let users opt into either or both.
  3. Add a settings flag like worktree.suppressExitPicker: false that preserves the picker even when a hook is registered.
  4. Add a payload field to WorktreeRemove indicating 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" }]
      }
    ]
  }
}
  1. claude from a worktree session, do some work, /exit.
  2. Expected: picker appears asking keep/remove.
  3. Actual: session exits silently; picker never shown.

Environment

  • Claude Code CLI (latest)
  • macOS

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗