Skip to content

[Bug]: Worktrees T3 creates for Claude threads ignore Claude Code's WorktreeCreate / WorktreeRemove hooks #24645

Closed

Description

@alexandercaley

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. In a git repo, add a project-level Claude Code WorktreeCreate hook in .claude/settings.json. Make it log its input, create the worktree (git worktree add …) and print the path. A SessionStart hook that logs too is useful for comparison.
  2. Add the repo as a T3 project and start a thread on a Claude provider instance.
  3. In the thread, have Claude create a worktree with its own EnterWorktree tool. → The WorktreeCreate hook runs, and Claude uses the path it returns.
  4. In the same thread, call delegate_task with isolation: "worktree", or start a new thread in a new worktree from the UI. → The WorktreeCreate hook is not called. T3 creates ~/.t3/worktrees/<repo>/t3-<id> with plain git worktree add. The child's SessionStart hook 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 Code WorktreeCreate / WorktreeRemove hooks, as Claude Code does. Claude Code runs a WorktreeCreate hook instead of git worktree add and 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.

runOnWorktreeCreate scripts 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-lib and similar paths. The WorktreeCreate hook creates the main worktree and matching worktrees of each sibling in a parallel directory, so the relative paths resolve, and WorktreeRemove tears 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 (claudeAgent provider)

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 directly

git worktree list afterwards:

/private/tmp/t3-hooktest/repo                    [master]
/private/tmp/t3-hooktest/wt-native               [wt-native]          # created by the hook
/Users/…/.t3/worktrees/repo/t3-8d562f36          [t3/reply-child-ok]  # created by T3, hook bypassed

Workaround

Avoid T3-made worktrees in these repos: ask Claude to use EnterWorktree or native subagent worktree isolation, which do run the hooks. This loses T3's worktree features (delegate_task worktree 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 resolved WorktreeCreate / WorktreeRemove hooks (user, project and local settings, and enabled plugins) instead of git 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.

Activity

  1. locked and limited conversation to collaborators on Oct 25, 2026
  2. converted this issue into a discussion #24754 on Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions