claude-code - 💡(How to fix) Fix WorktreeRemove hook silently suppresses the /exit "keep or remove" picker

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

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.

Root Cause

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.

Fix Action

Fix / Workaround

Confirmation that no workaround exists

Code Example

// .claude/settings.json
{
  "hooks": {
    "WorktreeRemove": [
      {
        "matcher": "*",
        "hooks": [{ "type": "command", "command": "echo teardown ran" }]
      }
    ]
  }
}
RAW_BUFFERClick to expand / collapse

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

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING