feat(web): start a thread in an existing worktree#3798
Conversation
The workspace selector only offered "Current checkout" or "New worktree", so an existing worktree could only be reused indirectly (by picking its branch). This surfaces existing worktrees as first-class choices, so a fresh conversation can be started directly in a previous worktree. - BranchToolbar.logic: deriveExistingWorktreeOptions builds the list from the branch refs (each ref already carries its worktreePath from `git worktree list`), so t3code- AND externally-created worktrees (JetBrains/git/etc.) appear. Excludes the main checkout and the current worktree; deduped by path. - BranchToolbar: fetch refs for the project cwd (only while the selector is interactive) and bind a picked worktree to the thread — draft via setDraftThreadContext, server thread via updateThreadMetadata (stopping a running session first). No git op runs; the server adopts the existing worktree path as the thread cwd, mirroring the branch selector's reuse. - Selectors: add an "Existing worktrees" group to the desktop workspace Select and the mobile radio menu. No server/contract changes (reuses vcs.listRefs + existing worktreePath acceptance on thread create). Known limits: worktrees whose branch isn't in the first 100 refs, and detached-HEAD worktrees, are not listed. Verified end-to-end: an externally-created git worktree appears in the picker, selecting it binds the draft (branch + worktreePath), and the started conversation runs in that worktree (pwd confirmed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The workspace selector/label read only "Worktree" / "Current worktree" when a thread was attached to one, giving no hint of which worktree it was. Append the worktree's folder name, e.g. "Current worktree · t3code-4e609bb8" / "Worktree · t3code-4e609bb8". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. This PR introduces a new feature for starting threads in existing worktrees, which constitutes significant new user-facing capability. Additionally, there is an unresolved high-severity review comment identifying a potential bug where stale worktree path overrides may cause operations to target the wrong checkout. You can customize Macroscope's approvability policy. Learn more. |
When a started server thread selects an existing worktree, set the env-mode override to "worktree" optimistically, so a send that races the async metadata round-trip runs in the chosen worktree instead of the thread's prior local mode. (Macroscope review.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Selecting an existing worktree on a fresh server thread flipped env mode to worktree optimistically but left worktreePath null until the metadata round-trip resolved. A racing first send then saw worktree mode with no path and spawned a brand-new worktree, and the branch picker ran git in the main checkout instead of the chosen worktree. Mirror the existing branch override with a worktree-path override: - ChatView holds pendingServerThreadWorktreePath and uses the effective path in the send guard so no fresh worktree is created. - BranchToolbar sets it on select and reflects it in env-mode lock/labels. - BranchToolbarBranchSelector uses it for branchCwd. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit 440beaf4ae7a3a961e48096cadd32f8f9fdb7bf2)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
There are 3 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f7c4947. Configure here.
Two follow-ups to the optimistic worktree-path override:
- onEnvModeChange now clears pendingServerThreadWorktreePath when the user
switches to Current checkout or New worktree, so a stale override can't
keep branch git ops, the workspace lock/labels and the send guard pointed
at an abandoned worktree. onSelectExistingWorktree re-sets the path right
after its onEnvModeChange("worktree") call, so a genuine pick survives.
- The first-message send folds the picked branch + worktree path into the
already-awaited metadata round-trip, so the server binds the chosen
worktree before startThreadTurn instead of racing the fire-and-forget
update and starting the turn with a null path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit d5311185b86f4feb7e11a973ebc4b5f013fe1607)
deriveExistingWorktreeOptions compared worktreePath to the project cwd and active worktree with raw ===, while display normalizes separators and trailing slashes. If git worktree list and client state spell the same directory differently, the main checkout or active worktree could leak into the Existing worktrees list. Add an exported canonicalizeWorktreePath and compare/dedupe on it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit f44935c85856825431034d5c71b5830572203a8f)
setThreadBranch updated the branch override and thread metadata but left the parent's optimistic worktree-path override untouched. Picking a branch that retargets the main checkout (worktreePath === null) during the pre-persist window left a stale override, so branchCwd, resolveBranchSelectionTarget and the next send kept operating against the previously-picked worktree. Propagate the new worktree path to the parent override alongside the branch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit 34ef0df3335e4711a425ac38e41b00b4005c9828)

Closes #3796.
What changed
Adds an "Existing worktrees" group to the workspace selector so a thread can be started directly in a worktree that already exists (t3code-created or one made by JetBrains /
git worktree add), instead of only "Current checkout" / "New worktree".deriveExistingWorktreeOptionsbuilds the list from the branch refs — each ref already carriesworktreePathfromgit worktree list(vcs.listRefs) — excluding the main checkout and the current worktree, deduped by path.setDraftThreadContext, server thread viaupdateThreadMetadata(stopping a running session first). No git op runs — the server adopts the existing worktree path as the thread cwd, mirroring the branch selector's existingreuseExistingWorktreepath.Selectand the mobile radio menu.Current worktree · <name>) so you can tell which worktree a thread is in.Why
Worktrees could be created but not reattached to when starting a thread. This makes it practical to start a clean conversation while continuing to operate on a previous worktree.
Notes
vcs.listRefs+ existing acceptance of a pre-existingworktreePathon thread create).main; refiles the idea from Add open-worktree mode and reuse existing worktrees on send #1094 (closed for staleness, invited to resubmit).deriveExistingWorktreeOptionsand the label helpers.Before
After
Note
Medium Risk
Touches thread cwd binding, session stop, and first-send worktree creation races in the composer; mistakes could run turns in the wrong directory or spawn duplicate worktrees, though behavior reuses existing metadata adoption paths with no server changes.
Overview
Adds an Existing worktrees section to the workspace picker (desktop select and mobile menu) so threads can bind to worktrees already on disk—not only Current checkout or New worktree.
deriveExistingWorktreeOptionsbuilds that list from branch refs’worktreePath(fromgit worktree list), excluding the main checkout and active worktree, withcanonicalizeWorktreePathfor dedupe/exclusion across path spellings. Picking one sets branch +worktreePathvia draft context orupdateThreadMetadata(stopping a live session when needed), without creating a new worktree.Optimistic state in
ChatView,BranchToolbar, and the branch selector keeps labels,branchCwd, and first-send logic aligned before metadata lands: pending worktree path overrides avoid spawning a new worktree on a racing first message, and the first send can await metadata that includes the chosen path. Workspace labels now show the folder name (e.g.Current worktree · feature-a).Unit tests cover
deriveExistingWorktreeOptionsand updated label helpers.Reviewed by Cursor Bugbot for commit 78862d4. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add existing worktree selection to the branch toolbar for starting threads
VcsRef.worktreePath(excluding the main checkout and active worktree).updateThreadMetadata.canonicalizeWorktreePathin worktreeCleanup.ts to normalize paths (backslashes, trailing slashes) for deduplication and exclusion comparisons.ChatViewContentandBranchToolbarmust be cleared correctly on thread change and mode switches; mismatches could cause a send to target the wrong worktree.Macroscope summarized 78862d4.