WorktreeRemove hook never fires when a worktree is removed at session exit

Open 💬 2 comments Opened Jul 6, 2026 by jacob-carlborg-apoex

Environment

  • Claude Code 2.1.201 (native installer, latest at time of writing)
  • macOS 26.5 (reproduced identically regardless of exit path)

Description

The hooks reference documents that WorktreeRemove "fires when a worktree is being removed, either at session exit or when a subagent finishes." In 2.1.201 the hook is never invoked at session exit — neither when an unchanged worktree is removed automatically, nor when the user answers the remove/keep prompt for a changed worktree with "remove".

The worktree's branch is also left behind in both cases, although the worktrees doc says removal deletes the branch ("the worktree and its branch are removed automatically").

Since WorktreeRemove output is only visible in debug mode, this fails silently: any external resources a WorktreeCreate hook provisions (databases, containers, ports) leak on every worktree session.

Steps to reproduce

  1. In a git repo, add to .claude/settings.json:
{
  "hooks": {
    "WorktreeRemove": [
      { "hooks": [{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/remove-worktree.sh" }] }
    ]
  }
}
  1. Create the hook script (chmod +x):
#!/bin/sh
cat >> /tmp/worktree-remove-hook.log
echo "fired at $(date)" >> /tmp/worktree-remove-hook.log
  1. Run claude --worktree test, then exit the session (/exit).
  2. Claude Code prints Worktree removed (no changes) and the worktree directory is gone.
  3. /tmp/worktree-remove-hook.log was never created. Repeating with a modified file in the worktree and choosing "remove" at the exit prompt gives the same result.

Expected

The WorktreeRemove hook runs with {"hook_event_name": "WorktreeRemove", "worktree_path": ...} on stdin before/when the worktree is removed, and the worktree's branch is deleted, as documented.

Actual

The worktree directory is removed and deregistered, the hook never runs, and the branch remains.

Notes

  • Other hooks fire normally in the same session (WorktreeCreate runs at startup; the Stop hook runs at exit — visible in the exit output), so this isn't a hooks-config problem.
  • The WorktreeRemove event schema and executor exist in the CLI bundle (the string WorktreeRemove hook failed [...] is present), so it appears the executor simply isn't called from the session-exit cleanup path.
  • Possibly related docs mismatch: in 2.1.201 the WorktreeCreate stdin payload contains only name (plus common fields), while the docs describe worktree_path, branch, and detached.

View original on GitHub ↗

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