# fix\(server\): a thread's branch and worktree follow the agent when it moves · PR \#15989 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/15989)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: open

Source repository: pingdotgg/t3code

Source branch: fix/v2-follow-worktree-drift

Target branch: main

Head commit: f5a80658991a671a53a8f330baa44c59f12cdfba

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/15989)

[Commits](https://git.cafe/pingdotgg/t3code/pull/15989/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/15989/diffs?format=markdown)

## Description

---

Unproven: live Claude and Codex behavior on this head. The actual-server runs in the linked evidence ran on 42590b7bf7, before the rebase and the follow-up fixes; this head is covered by tests only.

## Problem

A thread kept its original branch and worktree after its agent moved, so file requests and later turns could use the wrong checkout.

## Change

Reconcile the thread after capturing the old checkout and before a queued successor starts. Claude's root native EnterWorktree/ExitWorktree hook records the observed destination and the turn's requested source checkout. Follow only while that source still matches the thread's recorded checkout and both paths belong to the same Git repository. This allows a failed reusable turn's move to catch up after the next successful turn in the same live session, while ignoring an old observation after a project-root repoint. A fresh Claude query that opens at a different cwd than the last tracked move resets its tracked location and clears that move's provenance; reuse of the same live process preserves failed-turn catch-up. Preserve a selected project subdirectory and the provider's factual cwd. Returning to the selected root clears the thread's worktree and branch. Each checkpoint capture carries the provider session its run used, because a queued model change can restart the session and give the provider thread a new one before capture runs.

Instance-wide sessions such as Codex/OpenCode do not identify a thread's location and are excluded from location follow, even with only one binding. In-place branch reconciliation still works independently for all providers. Shared checkout adoption keeps location without claiming an owned branch; a checkout counts as shared when another thread in any project uses it or an active project's root is at or inside it (compared as stored paths, so a project opened through a symlink into the checkout is not detected). Path/branch/run guards reject stale writes; session preservation and run provenance stay server-only; explicit T3 handoffs still detach and revoke the old observation. First-turn branch naming rechecks Git before renaming.

## Scope and approval

Closes [#11078](https://github.com/pingdotgg/t3code/issues/11078). This follows [Julius’s accepted bug and fix direction](https://github.com/pingdotgg/t3code/issues/11078#issuecomment-5618769019): persist the moved checkout on the server while preserving shared-worktree and branch guards. The [maintainer takeover](https://github.com/pingdotgg/t3code/pull/15989#issuecomment-6264692844) keeps this to thread worktree/branch reconciliation. Final human review and approval remain pending.

Rebuilt from @shivamhwp's [#15989](https://github.com/pingdotgg/t3code/pull/15989). Removed duplicate tests, generic cwd hooks, the public session-preservation flag and redundant wiring. No planned-handoff continuation fix from [#15203](https://github.com/pingdotgg/t3code/pull/15203) is included. Rebased onto main on 2026-10-22 as one commit; two follow-up commits fix review findings.

## Verification

On the current head (headless Linux):

- `vp run check:changed` passes: format, lint, knip, typecheck of 29 packages, and 500 tests in 14 files.
- New queue variant: Exit(remove) followed by a queued message that changes the Claude model. Without the session-carrying fix the successor started in the removed worktree; it now starts at the project root.
- The shared-worktree guard test now covers a sibling thread in another project and a checkout holding another project's root (`W/src`); both fail without the fix.
- The run execution test checks that the checkpoint capture effect carries the finishing run's provider session.

Before the rebase, on 42590b7bf7 (historical, not rerun on this head):

- Ten suites: 658 original cases → 645, with all 637 baseline cases and 2,271 baseline assertion sites retained; PR additions 21 → eight. All 645 pass serially. Production controls reproduce the location/queue/sharing defects; the failed-Enter case executes real failure ingestion with no failed-run capture, then succeeds after the recovery fix. Failed-provider recovery was tested at the service/adapter boundary, not by forcing a live Claude failure.
- Server, contracts and provider-core typechecks, 19-file lint/format and whitespace checks pass. Four existing lint warnings remain. Earlier parallel runs hit an existing background-steering timeout; its cause is unresolved.
- Ten fresh dual whole-PR review rounds; both final reviewers returned no findings. Earlier rounds fixed queued ordering/provider identity, subdirectory normalization, explicit handoff precedence, multiplex-session cwd adoption, linked-root repoint and failed-turn recovery. The final round confirmed the fresh-query reset and shared detach-reason constant. The replacement-process control fails without the reset; both live reuse and replacement now pass, including a repeated native Enter into the same path.
- Actual server proof: 13 completed Claude turns covering queued Enter/branch/Exit(remove), subdirectory Enter/Exit(keep), file-read RPC from the moved checkout, resume after an actual server restart, and a project repoint to a linked checkout of the same repository. Durable metadata precedes queued execution. Actual Codex P1 → settle → P2 keeps the thread, file and checkpoint in P2 despite a sole shared-session binding reporting P1. All owned servers stopped. No UI rendering claim is made.

[Before/after evidence and exact limits](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/c7666245d120cac3/15989-evidence-r10.md).

Limits: native location follow currently covers Claude Git Enter/Exit only; other providers retain branch reconciliation. Legacy sessions without source provenance wait for a fresh native observation. Restarting the server after a failed move, before catch-up, loses that source provenance; recovery across that restart is not claimed. A reused session can still run in its old cwd after a project repoint; this change prevents that cwd from becoming persistent thread metadata. Failed Exit(remove) can leave a deleted requested source and require manual handoff. Branch adoption compares project roots by stored path, not resolved path, so a project opened through a symlink into the destination checkout does not block it. Concurrent cross-thread adoption, an external checkout between the final branch read and rename, a project repoint while the follow reads Git status, and the immediate account-overlay send window retain narrow races.

Automatic mid-turn MCP handoff continuation still hits main's planned-release failure and holds the queue; [#15203](https://github.com/pingdotgg/t3code/pull/15203) addresses that separately. A queued alternate Claude-instance switch selects the destination but its first query can fail with a duplicate native session ID, also reproduced by a root-only control in base-identical code. Those live flows are not claimed fixed. Live OpenCode, other providers/accounts, native client rendering, macOS, Windows, iOS, Android and Electron desktop remain for human verification. Human approval is required; unmerged.

Implementation: GPT-6.1 Sol through Codex in T3 Code. Tests: GPT-6 Astra through Codex. Adversarial reviews: Claude Opus 5.5 through Claude Code and GPT-6 Sol through Codex.

Rebase and follow-up fixes: Claude Opus 5.5 through Claude Code in T3 Code. Review: GPT-6.1 Sol through Codex.

Fixes #11078
GitCafe: https://git.cafe/pingdotgg/t3code/issues/11078

