[BUG] WorktreeCreate / Remove hooks not called in Claude Desktop
Open 💬 24 comments Opened Mar 1, 2026 by clayallsopp
💡 Likely answer: A maintainer (amorriscode, contributor)
responded on this thread — see the highlighted reply below.
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?
- My project has WorktreeCreate and WorktreeRemove hooks setup that change where Git worktrees are managed
- When I create a worktree via Claude Desktop, it is still creating them in
<project>/.claude/worktrees, and not using the Hooks - I also have log files managed by my hooks, and their absence confirms they are not being called by Claude Desktop. The SessionStart hook seems to be called, but not the worktree ones.
What Should Happen?
- WorktreeCreate/Remove should be called by Claude Desktop.
Error Messages/Logs
Steps to Reproduce
- Check out https://github.com/clayallsopp/worktree-desktop-repro
- run
claude -w worktree-test - observe the worktree is created in
./custom-worktrees/worktree-test - observe log entry in
./logs - Open that repo in Claude Desktop
- Ask a question about the with worktree enabled
- Observe worktree created in
.claude/worktrees - Observe no new log entry in
./logs
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.52
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
24 Comments
Spent some time digging into this. Here's what I found:
What's happening: WorktreeCreate and WorktreeRemove hooks are only invoked by the Claude Code CLI (
claude -w), not by Claude Desktop. The SessionStart hook fires in both environments, confirming Desktop does process hooks — but the worktree-specific lifecycle hooks are skipped. This affects any project relying on custom worktree management via hooks when used through Claude Desktop.📊 _We found 5 similar cases in our knowledge base with the same pattern — this gives us high confidence in this analysis._
Hope this helps! Let me know if it doesn't match your case — happy to dig deeper. 🦞
---
<sub>🦞 Confucius Debug — community knowledge base for AI agent bugs. Free to search via MCP.</sub>
Reproducible on my end too. Happy to assist on debugging/testing if needed
Also reproducible on mine, I just did SessionStart cleanup hook to clean up old sessions when starting a new one instead
This is hindering parallel development on my team because only the App has preview integration and that's vital for what we're working on, but we can't run more than one at a time.
Workaround: use PreToolUse on Agent with worktree isolation to trigger your lifecycle hooks:
This works in Claude Desktop because PreToolUse/PostToolUse hooks fire normally — it's only the dedicated WorktreeCreate/WorktreeRemove events that are missing.
How does this let you move where the worktree is created?!
I am using
SessionStartinstead with a git-ignored file as marker:This also interferes with the use of jj. I have custom worktree hooks that create jj workspaces, which Claude Desktop completely ignores in Claude 1.2581.0 (f10398)
Still repros in the Desktop app. Worth flagging the doc contradiction too: the hooks reference says WorktreeCreate 'replaces Claude Code's default git worktree logic entirely', but the EnterWorktree tool description explicitly says it only delegates to the hook outside a git repo. One of the two docs is wrong, and this issue is the fallout.
Just confirmed that the redesigned desktop app released on 2026-04-14 still is not triggering WorktreeCreate when using worktrees in the Claude Code tab.
Please fix this.
Reproduces here as well, with an additional wrinkle: my project is a jj (Jujutsu) repo with a colocated
.git/. TheWorktreeCreatehook invokesjj workspace addto create a real jj workspace alongside the git checkout. CLIclaude --worktree <name>honors the hook correctly. Desktop's UI worktree toggle bypasses it and falls back togit worktree add, which silently "works" because of the colocated.git/— but the new worktree has no.jj/of its own, so anyjjcommands inside it walk up to the parent project's state and operate on the wrong workspace. This breaks any jj-aware tooling, slash commands, or skills inside the Desktop-created worktree.Worth calling out because in non-colocated jj-only repos this would fail loudly (no
.git/forgit worktree addto use). With colocated repos it fails silently, which is harder to debug. The hook should be honored regardless of whether.git/is present.Environment:
Claude 1.4758.0 (fb266c) 2026-04-24T20:22:30.000Z.claude/settings.jsonregistration verified working with CLIclaude --worktree <name>(createsclaude-<name>jj workspace as expected); Desktop UI toggle on the same project bypasses the hook entirely.Reproduction signal: from inside a Desktop-created worktree,
jj workspace listonly showsdefault,jj rootresolves to the parent project, andjj statusreports paths like../../../CLAUDE.md— i.e., jj is operating on the parent's working copy, not the worktree's.Sorry folks, hadn't seen this issue before. Fixing it up.
@amorriscode Sorry for the ping, any clue when the fix for the worktree-hooks from the Claude Desktop app can be released? (Then I know whether to work-around or wait a couple of days.) Thanks for the effort anyway 🙌
@ralphjsmit sorry, this one slipped from my plate. I'll have it in for Tuesday's release.
Thanks so much!
Still repros on Claude Desktop
1.9255.0(macOS).Earlier in this thread (May 21) @amorriscode said a fix was coming "in Tuesday's release" — that's now 6 days ago and the issue is still open. Public CLI releases v2.1.146 → v2.1.152 don't mention a Desktop dispatch fix in any changelog.
Fresh repro ~30 minutes ago:
~/Library/Application Support/Claude/git-worktrees.jsonat2026-05-27T09:56:28Z:``
`name: dreamy-matsumoto-769b26
branch: claude/dreamy-matsumoto-769b26
path: <repo>/.claude/worktrees/dreamy-matsumoto-769b26
claude/<codename>` convention.→ path / branch / name are all Desktop's hard-coded
WorktreeCreatehook (custom branch namingfeat/YYMMDD-<rest>, custom path layout) was not invoked —~/.claude/worktree-hook.logmtime didn't move; last entry is2026-05-24T21:46:01from a CLIclaude -winvocation.claude -w <name>still fires the hook correctly — bug is purely on the Desktop dispatch path, as originally filed.@amorriscode any update on landing the fix? Happy to test a build.
This seems to work for me locally - what doesn't work is an external plugin can't have it fire. For example, https://worktrunk.dev/ has its own WorktreeCreate - but via the plugin it wont work, even though a local WorktreeCreate / WorktreeRemove will.
@amorriscode Hi, was it fixed and released? Because I see this ticket is still open and I'm not sure if I can safely migrate from SessionStart hook.
For what it's worth: it's been working for me for a week or so. (Although the agent often tries to read files from the main worktree which is annoying in plan mode but it is tracked in a separate issue)
@etiennecrb Thanks for info. Yeah, I have exactly same issue! Do you have url of existing ticket for this?
This is still quite broken for me. To be clear, I'm using desktop SSH sessions.
Works: Session can spawn an agent in a new worktree and hooks will fire
Fails
This still constantly fires for me on the latest version
!image
Re-tested today on Claude Code 2.1.204 (macOS, Claude Desktop). Current status is split:
Session worktrees: still broken. When Claude Desktop creates (or reuses) a worktree for a session, it goes through its own pool mechanism and never calls the
WorktreeCreate/WorktreeRemovehooks.~/Library/Logs/Claude/main.logshows:and when no pooled worktree is available:
There is no
WorktreeCreatemention anywhere in the log, the worktree lands in the default.claude/worktrees/location, and none of the side effects of our hook (worktrunk-managed path, pre-start setup files) are present. The pool also explains why worktree directory names don't match the session branch - directories get re-leased and rebound to new branches.Agent tool with
isolation: "worktree"(in-session subagents): the hook IS called now. A subagent spawned with worktree isolation fails withWorktreeCreate hook failed: ...when the hook command errors, which proves invocation. So the gap appears specific to the Desktop app's session-level WorktreePool path, not to the hook plumbing in general.Setup for reference: hooks come from the worktrunk plugin (https://worktrunk.dev/claude-code/), which registers
WorktreeCreate/WorktreeRemovein itshooks.json; other plugin hooks (UserPromptSubmit,SessionEnd) fire fine in the same sessions.