[BUG] WorktreeRemove hook never fires on worktree removal (claude --worktree exit → remove)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet (closest is #36205, but it states this path should work — see Additional Information)
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
A WorktreeRemove command hook configured in ~/.claude/settings.json never runs when a worktree created with claude --worktree <name> is removed via the interactive session-exit "remove" prompt. The worktree is deleted correctly, but the WorktreeRemove event is never dispatched, so the hook command never executes.
The hook config is valid and loaded — I verified this two ways in the same session:
- A
PostToolUsecontrol hook in the same settings file fires normally. - A
--debugtrace shows the worktree being removed with noWorktreeRemovedispatch.
Reproduced from a brand-new terminal (fresh claude process), so this is not a mid-session config-reload issue.
What Should Happen?
Per the worktrees and hooks docs, removing a worktree should fire the WorktreeRemove hook (with worktree_path on stdin) so per-worktree cleanup — e.g. dropping a scoped dev database, removing a virtualenv, releasing ports — can run.
Error Messages/Logs
# 1) The synchronous PostToolUse hook DOES register and fire — right after a Bash
# tool call, Claude processes the hook's (non-JSON) output:
[INFO] [Stall] tool_dispatch_end tool=Bash toolUseId=... outcome=ok
[DEBUG] Hook output does not start with {, treating as plain text # <- PostToolUse hook ran
# 2) The worktree is removed cleanly, but NO hook output is processed here —
# the WorktreeRemove event is never dispatched:
[DEBUG] Removed linked worktree at: .../.claude/worktrees/probe
[DEBUG] Deleted worktree branch: worktree-probe
[DEBUG] Linked worktree cleaned up completely
# Result: post-tool-use.log has a line (hooks live); worktree-remove.log never created.
Please don't be misled by the two 0 hooks debug lines — I checked, and neither refers to the synchronous settings-hook dispatch table:
Registered 0 hooks from 0 plugins— the plugin hook registry (I have no plugins).Hooks: Found 0 total hooks in registry— always emitted alongsidecheckForNewResponses returning 0 responses, i.e. the async-hook response poll (no async hooks here).
The synchronous PostToolUse hook from the same settings file demonstrably fires (the Hook output does not start with { line above is Claude handling its output), so settings hooks load and dispatch fine. WorktreeRemove specifically is never dispatched on removal.
Steps to Reproduce
- Add this to
~/.claude/settings.json(thePostToolUsehook is a control, to prove hooks load):
``json``
{
"hooks": {
"PostToolUse": [
{ "matcher": "Bash", "hooks": [
{ "type": "command", "command": "echo \"PostToolUse fired $(date)\" >> ~/.claude/post-tool-use.log" } ] }
],
"WorktreeRemove": [
{ "hooks": [
{ "type": "command", "command": "echo \"WorktreeRemove fired $(date)\" >> ~/.claude/worktree-remove.log" } ] }
]
}
}
- Ensure
~/.claude/post-tool-use.logand~/.claude/worktree-remove.logdo not exist. - In a new terminal:
claude --worktree probe - Inside the session, run any bash command (e.g.
echo hi). - Exit the session (Ctrl-D or
/exit) and choose remove at the keep/remove prompt. cat ~/.claude/post-tool-use.log ~/.claude/worktree-remove.log
Result: post-tool-use.log contains a line (hooks are live this session); worktree-remove.log is empty (WorktreeRemove never fired). git worktree list confirms the worktree was removed.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
(unknown — not bisected)
Claude Code Version
2.1.214 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
iTerm2
Additional Information
- Related but distinct — #36205. That issue states the
claude --worktreeCLI path does invoke these hooks, and only the in-sessionEnterWorktree/ExitWorktreetool path ignores them. On 2.1.214 the CLI exit-remove path does not fireWorktreeRemove— so this is either a regression or an uncovered path. (I can also confirm theExitWorktreetool path fails, matching #36205.) - Other issues in the same hook-dispatch cluster: #39281 (
--worktree --tmux), #37611 (WorktreeCreatedisables the cleanup prompt), #29716 / #57209 (Claude Desktop), #27276 (docs don't cover these events). - Impact: per-worktree cleanup (scoped dev database, virtualenv, ports) can't be automated on removal; teardown has to be run manually before deleting the worktree.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗