[BUG] Plugin `WorktreeCreate` hook still ignored for `claude --worktree` on 2.1.296 (#46664 closed as stale, never fixed)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
This is the same bug as [[BUG] Plugin-registered WorktreeCreate hooks in hooks/hooks.json are never dispatched — settings.json hooks for the same event fire normally (2.1.101)#46664](https://github.com/anthropics/claude-code/issues/46664) (reported on 2.1.101, confirmed on 2.1.145, closed as stale by the bot and now locked).
A WorktreeCreate hook defined in a plugin's hooks/hooks.json is still never invoked for claude --worktree <name>. Claude Code silently falls back to its default git worktree add (.claude/worktrees/<name>). The original report (#46664) covers this in detail; this issue adds what has changed since:
- Still reproduces on 2.1.296, roughly 190 releases after #46664.
- It's specific to startup
--worktree. The same plugin hook does fire for a subagent withisolation: worktree:
| Trigger | Hook defined in | WorktreeCreate fired? | Worktree used |
|---|---|---|---|
| claude --worktree probe | plugin | No | default .claude/worktrees/probe |
| claude --worktree probe | settings.json | Yes | hook's directory |
| subagent with isolation: worktree | plugin | Yes | hook's directory |
In the first row, the same plugin's SessionStart hook fires in the same session, so the plugin is loaded. Plugin WorktreeRemove is not affected either: with WorktreeCreate in settings.json and WorktreeRemove only in the plugin, the plugin's WorktreeRemove runs when an interactive --worktree session exits.
A likely cause (not confirmed): --worktree creates the worktree during startup, before plugin hooks are loaded, while subagent isolation runs after they're registered.
What Should Happen?
Per the hooks reference, WorktreeCreate fires "when a worktree is being created via --worktree, isolation: "worktree", or for a background session" and "replaces default git behavior." Per the plugin docs, plugin hooks "merge with your user and project hooks", with no events excluded. So a plugin's WorktreeCreate hook should run for claude --worktree, as it already does for subagents.
Error Messages/Logs
Steps to Reproduce
Save as repro.sh and run it from an empty directory. It uses a throwaway local marketplace. Make sure no WorktreeCreate hook is configured in your settings files.
#!/bin/bash
set -euo pipefail
ROOT=$(pwd)
LOG="$ROOT/fired.log"
# 1. Probe plugin: WorktreeCreate logs and creates a directory, SessionStart just logs.
mkdir -p mkt/.claude-plugin mkt/probe/.claude-plugin mkt/probe/hooks repo
cat > mkt/.claude-plugin/marketplace.json <<'EOF'
{"name":"probe-mkt","owner":{"name":"probe"},"plugins":[{"name":"probe","source":"./probe"}]}
EOF
cat > mkt/probe/.claude-plugin/plugin.json <<'EOF'
{"name":"probe","version":"0.0.1","description":"WorktreeCreate probe"}
EOF
cat > mkt/probe/hooks/hooks.json <<'EOF'
{"hooks":{
"WorktreeCreate":[{"hooks":[{"type":"command","command":"${CLAUDE_PLUGIN_ROOT}/hooks/create","timeout":30}]}],
"SessionStart":[{"hooks":[{"type":"command","command":"${CLAUDE_PLUGIN_ROOT}/hooks/session"}]}]}}
EOF
cat > mkt/probe/hooks/create <<EOF
#!/bin/bash
IN=\$(cat); echo "WorktreeCreate \$IN" >> "$LOG"
D="$ROOT/wts/\$(echo "\$IN" | jq -r .name)"; mkdir -p "\$D"; echo "\$D"
EOF
cat > mkt/probe/hooks/session <<EOF
#!/bin/bash
echo "SessionStart \$(cat)" >> "$LOG"
EOF
chmod +x mkt/probe/hooks/create mkt/probe/hooks/session
claude plugin marketplace add "$ROOT/mkt"
claude plugin install probe@probe-mkt
# 2. A git repo to run in.
git -C repo init -q && git -C repo -c user.email=a@b -c user.name=a commit -q --allow-empty -m init
cd repo
# 3. Startup --worktree: plugin WorktreeCreate is NOT invoked.
: > "$LOG"
claude --worktree probe -p "Reply with only the output of pwd." --allowedTools Bash < /dev/null
echo "== --worktree"; cut -c1-80 "$LOG" # only SessionStart
git worktree list # shows .claude/worktrees/probe (default git worktree)
# 4. Subagent isolation: plugin WorktreeCreate IS invoked.
mkdir -p .claude/agents
cat > .claude/agents/wt-probe.md <<'EOF'
---
name: wt-probe
description: Reports its working directory. Use when asked to run the worktree probe.
isolation: worktree
tools: Bash
---
Run `pwd` with the Bash tool and reply with only the output.
EOF
: > "$LOG"
claude -p "Use the wt-probe agent to run the worktree probe and report the directory." --allowedTools "Agent,Bash" < /dev/null
echo "== isolation: worktree"; cut -c1-80 "$LOG" # SessionStart + WorktreeCreate
ls "$ROOT/wts" # hook-created directory
Observed output (abridged):
== --worktree
SessionStart {"session_id":"…","cwd":"…/repo/.claude/worktrees/probe",…
…/repo/.claude/worktrees/probe fab6e8c [worktree-probe]
== isolation: worktree
SessionStart {"session_id":"…",…
WorktreeCreate {"session_id":"…","hook_event_name":"WorktreeCreate","name":"agent-…"}
agent-…
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.296
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_