Repository navigation
[Bug]: Worktrees T3 creates for Claude threads ignore Claude Code's WorktreeCreate / WorktreeRemove hooks
#24754
Replies: 1 comment
|
Two smaller asks that would cover most of this without T3 having to run Claude's hooks. Both came out of trying to work around it with 1.
make-sibling-worktrees feature-x # however the repo needs it
t3 thread start --worktree-path ../worktrees/feature-x/repo --branch feature-x . "…"Today only an agent already running in a T3 thread can do this, by calling 2. A provider-agnostic worktree command, as an alternative to running Claude's hooks If running the resolved Claude Why setup scripts can't stand in
|
Uh oh!
There was an error while loading. Please reload this page.
Before submitting
Area
apps/server
Steps to reproduce
WorktreeCreatehook in.claude/settings.json. Make it log its input, create the worktree (git worktree add …) and print the path. ASessionStarthook that logs too is useful for comparison.EnterWorktreetool. → TheWorktreeCreatehook runs, and Claude uses the path it returns.delegate_taskwithisolation: "worktree", or start a new thread in a new worktree from the UI. → TheWorktreeCreatehook is not called. T3 creates~/.t3/worktrees/<repo>/t3-<id>with plaingit worktree add. The child'sSessionStarthook does fire inside that worktree.Expected behavior
T3 Code uses Claude Code's login and configuration (
docs/user/providers-claude.md). So for Claude-backed threads, a worktree should be created and removed by the project's configured Claude CodeWorktreeCreate/WorktreeRemovehooks, as Claude Code does. Claude Code runs aWorktreeCreatehook instead ofgit worktree addand uses the path it prints. Today, the same thread gets different worktrees depending on whether Claude or T3 creates them.Actual behavior
T3 creates and removes worktrees itself, through
GitVcsDriver.createWorktree/removeWorktree(git worktree add/remove); storage cleanup and PR review checkouts do the same. The configured hooks never run for T3-made worktrees.runOnWorktreeCreatescripts don't solve this. They run after T3 has already created a plain git worktree at its own path, so they can't control where or how the checkout is made.Example of a hook this breaks: a repo that needs sibling repos checked out next to it. The code refers to
../shared-liband similar paths. TheWorktreeCreatehook creates the main worktree and matching worktrees of each sibling in a parallel directory, so the relative paths resolve, andWorktreeRemovetears all of them down together. A T3-made worktree under~/.t3/worktrees/<repo>/t3-<id>has no siblings beside it, so builds and tests in that thread fail, and nothing cleans up siblings on removal.Impact
Major degradation or frequent failure (for any repo that depends on these hooks: T3 worktree isolation and new-worktree threads are unusable there).
Version or commit
T3 Code 0.1.2 (CLI service); behavior read against main @ 453bf01
Environment
macOS 26.2 (Apple Silicon), T3 CLI service, Claude Code 2.1.308 (
claudeAgentprovider)Logs or stack traces
Hook log from the repro (one T3 thread; payloads trimmed):
01:00:58 SessionStart {"cwd":"/private/tmp/t3-hooktest/repo", ...} # parent thread starts 01:01:01 WorktreeCreate {"cwd":"/private/tmp/t3-hooktest/repo", ...} # Claude EnterWorktree → hook runs, its path is used 01:01:06 SessionStart {"cwd":"/Users/…/.t3/worktrees/repo/t3-8d562f36", ...} # delegate_task isolation:"worktree" → NO WorktreeCreate; T3 used git directlygit worktree listafterwards:Workaround
Avoid T3-made worktrees in these repos: ask Claude to use
EnterWorktreeor native subagent worktree isolation, which do run the hooks. This loses T3's worktree features (delegate_taskworktree isolation, new-worktree threads, automatic cleanup).Possible fix (suggestion only)
An opt-in per-project setting, for example
worktreeCreation: "git" | "claudeHooks", with the default unchanged. When enabled for a Claude-backed thread, T3 runs the resolvedWorktreeCreate/WorktreeRemovehooks (user, project and local settings, and enabled plugins) instead ofgit worktree add/remove. It binds the thread to the returned path and falls back to git when no hook is configured. Happy to discuss scope, or to move this to an Ideas discussion if you'd prefer, and to implement it if the direction is approved.All reactions