[BUG] WorktreeRemove never fires for a subagent worktree created by a WorktreeCreate hook
Preflight Checklist
- [x] I have searched existing issues. This was reported as #50398 and #28363, both closed as stale without a fix and now locked.
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
With WorktreeCreate and WorktreeRemove command hooks configured, a subagent with isolation: worktree runs in the worktree the WorktreeCreate hook created, but WorktreeRemove is never called, neither when the subagent finishes nor on /exit. The worktree stays on disk even when the subagent changed nothing, so every isolated subagent leaves an orphaned worktree.
For comparison, without the hooks Claude Code removes the clean subagent worktree itself.
What Should Happen?
The hooks reference lists "a subagent with isolation: "worktree" finishes" among the WorktreeRemove triggers, and per #74708 WorktreeRemove runs for worktrees a WorktreeCreate hook created. WorktreeRemove should be called when the subagent finishes.
Error Messages/Logs
None. The script prints:
--- hook events received:
WorktreeCreate
--- worktrees left behind:
.../repo 9a7b107 [main]
.../repo/.claude/worktrees/agent-a05ede0a40d4dcb7d 9a7b107 [wt-agent-a05ede0a40d4dcb7d]
--- status of the subagent worktree:
## wt-agent-a05ede0a40d4dcb7d
Steps to Reproduce
Investigated and reproduced with an empty CLAUDE_CONFIG_DIR (no user hooks, plugins or CLAUDE.md) by Claude Code 2.1.288 using Opus 5.5.
CLAUDE_CONFIG_DIR=/path/to/repro-config bash worktree-remove-not-called-for-subagent.sh
When the agent has reported its working directory, /exit. The script registers the hooks in that configuration's settings.json, then prints the hook events received, the worktrees left behind, and the status of the subagent worktree.
<details>
<summary>worktree-remove-not-called-for-subagent.sh</summary>
#!/usr/bin/env bash
# Repro: WorktreeRemove never fires for a hook-created subagent worktree.
set -o errexit -o nounset -o pipefail
: "${CLAUDE_CONFIG_DIR:?Set CLAUDE_CONFIG_DIR to a configuration kept for reproductions}"
# Create a git repo
dir="$(mktemp -d)"
cd "${dir}"
git init -q -b main repo
git -C repo commit -q --allow-empty -m init
# Create hook: log every event, create a git worktree, remove it on WorktreeRemove
cat > hook.sh <<'EOF'
#!/usr/bin/env bash
input="$(cat)"
echo "${input}" >> "$(dirname "$0")/hook.log"
root="$(git -C "$(jq -r .cwd <<< "${input}")" rev-parse --show-toplevel)"
case "$(jq -r .hook_event_name <<< "${input}")" in
WorktreeCreate)
path="${root}/.claude/worktrees/$(jq -r .name <<< "${input}")"
git -C "${root}" worktree add -q -b "wt-$(jq -r .name <<< "${input}")" "${path}" >&2
echo "${path}" ;;
WorktreeRemove)
git -C "${root}" worktree remove "$(jq -r .worktree_path <<< "${input}")" >&2 ;;
esac
EOF
chmod +x hook.sh
# Register the hook in the user settings of the repro configuration
cat > "${CLAUDE_CONFIG_DIR}/settings.json" <<EOF
{ "hooks": {
"WorktreeCreate": [{ "hooks": [{ "type": "command", "command": "${dir}/hook.sh" }] }],
"WorktreeRemove": [{ "hooks": [{ "type": "command", "command": "${dir}/hook.sh" }] }] } }
EOF
# Create subagent
mkdir -p repo/.claude/agents
cat > repo/.claude/agents/iso.md <<'EOF'
---
name: iso
description: Reports its working directory.
isolation: worktree
tools: Bash
---
Run `pwd` with Bash and report the output. Do not create or modify any files.
EOF
# Run Claude Code: when the agent has reported, /exit
cd repo
claude --version
claude "Use the iso agent to report its working directory, then report what it said."
# Results
echo "--- hook events received:"
jq -r .hook_event_name "${dir}/hook.log"
echo "--- worktrees left behind:"
git worktree list
echo "--- status of the subagent worktree:"
git -C "$(git worktree list --porcelain | awk '/^worktree .*agent-/ {print $2}')" status --short --branch
</details>
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know. #50398 reported the same behaviour on 2.1.114.
Claude Code Version
2.1.288
Platform
Anthropic API
Operating System
macOS 14.8.9 (arm64)
Additional Information
#82097 looks related: removing a hook-created worktree from agent view fails because no starting commit is recorded for it.