Skip to content

feat(web): start a thread in an existing worktree#3798

Open
Brechard wants to merge 7 commits into
pingdotgg:mainfrom
Brechard:pr/worktree-existing-picker
Open

feat(web): start a thread in an existing worktree#3798
Brechard wants to merge 7 commits into
pingdotgg:mainfrom
Brechard:pr/worktree-existing-picker

Conversation

@Brechard

@Brechard Brechard commented Jul 8, 2026

Copy link
Copy Markdown

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".

  • deriveExistingWorktreeOptions builds the list from the branch refs — each ref already carries worktreePath from git worktree list (vcs.listRefs) — excluding the main checkout and the current worktree, deduped by path.
  • Selecting one binds the thread to it: 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 existing reuseExistingWorktree path.
  • Added to both the desktop workspace Select and the mobile radio menu.
  • The active-worktree label now includes the folder name (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

  • Web-only; no server/contract changes (reuses vcs.listRefs + existing acceptance of a pre-existing worktreePath on thread create).
  • Rebased on current main; refiles the idea from Add open-worktree mode and reuse existing worktrees on send #1094 (closed for staleness, invited to resubmit).
  • +263 lines, incl. unit tests for deriveExistingWorktreeOptions and the label helpers.
  • Known limits: worktrees whose branch isn't in the first 100 refs, and detached-HEAD worktrees, aren't listed.

Before

pr3798-worktree-BEFORE-dropdown

After

pr3798-worktree-AFTER-dropdown

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.

deriveExistingWorktreeOptions builds that list from branch refs’ worktreePath (from git worktree list), excluding the main checkout and active worktree, with canonicalizeWorktreePath for dedupe/exclusion across path spellings. Picking one sets branch + worktreePath via draft context or updateThreadMetadata (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 deriveExistingWorktreeOptions and 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

  • Adds an 'Existing worktrees' group to both the desktop (BranchToolbarEnvModeSelector.tsx) and mobile (BranchToolbar.tsx) workspace selectors, listing worktrees derived from VcsRef.worktreePath (excluding the main checkout and active worktree).
  • Selecting an existing worktree optimistically updates env mode, workspace label, and branch picker context without waiting for server confirmation.
  • On first message send, the chosen worktree path is passed directly so no new worktree is created; for server threads, branch and worktreePath are persisted before the turn starts via updateThreadMetadata.
  • Adds canonicalizeWorktreePath in worktreeCleanup.ts to normalize paths (backslashes, trailing slashes) for deduplication and exclusion comparisons.
  • Risk: optimistic state in ChatViewContent and BranchToolbar must be cleared correctly on thread change and mode switches; mismatches could cause a send to target the wrong worktree.

Macroscope summarized 78862d4.

rodrigoB-CB and others added 2 commits July 8, 2026 13:30
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>
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8adaf0de-393a-4c4c-81b6-67b364ed3bd7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 8, 2026
Comment thread apps/web/src/components/BranchToolbar.tsx
Comment thread apps/web/src/components/BranchToolbar.logic.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: 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>
Comment thread apps/web/src/components/BranchToolbar.tsx
Comment thread apps/web/src/components/BranchToolbar.tsx
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)
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Fix All in Cursor

❌ 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.

Comment thread apps/web/src/components/ChatView.tsx
Comment thread apps/web/src/components/ChatView.tsx
rodrigoB-CB and others added 3 commits July 8, 2026 14:51
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Start a thread in an existing worktree (not only current / new)

2 participants