Stop new threads inheriting checkout/branch from viewed thread#4411
Conversation
"New thread" (cmd+n / cmd+shift+o, sidebar buttons, command palette) copied the viewed thread's branch, worktree, and env mode into the new draft, bypassing the configured defaults (new worktree from origin main). Remove the implicit carry-over everywhere: only the project is inherited from context; workspace context always comes from settings. Stored drafts resurrected without explicit options also reset their env context so stale "current checkout" drafts stop resurfacing. What still carries over is the working mode: model selection (including reasoning effort / context window options), permission mode, and interaction mode. Deliberate branch reuse gets explicit affordances instead: - "Previous worktree (<branch>)" entry in the composer workspace selector points a draft at the project's most recently active worktree. - "New thread on <branch>" in the sidebar thread context menu (v1+v2) seeds a draft with that thread's branch/worktree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe PR adds explicit previous-worktree reuse, changes new-thread creation to avoid implicit workspace-context propagation, adds branch-based sidebar actions, and carries model/runtime state into new or resurrected drafts. ChangesThread context and worktree selection
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
…pace options Review: the model/permissions/interaction-mode carry only ran in the no-options branch of the stored-draft reuse path, so "New thread on <branch>" (which passes explicit workspace options) reopened stale drafts with their old model and permission mode. Restructure the branch so explicit workspace options and the defaults-reset share one write that always includes the carried working mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…selection Review: setModelSelection merges — a selection without options keeps the draft's existing options, so carrying a thread whose model has no options (default effort/context window) left the resurrected draft's stale option state in place. Add a replaceOptions flag for callers passing a complete snapshot and use it for the working-mode carry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fcae817. Configure here.
ApprovabilityVerdict: Needs human review This PR changes core thread creation behavior by stopping implicit branch/worktree inheritance and adding new UI affordances for explicit worktree selection. The scope of runtime behavior changes to user-facing workflow warrants human review. You can customize Macroscope's approvability policy. Learn more. |
…t members Review (high): setLogicalProjectDraftThreadId was called with only threadId after the setDraftThreadContext write. When projectRef targets a different physical member of the same logical project, createDraftThreadState treats the remap as a project change and wipes branch/worktreePath and forces envMode to "local", undoing both the defaults reset and "New thread on <branch>" seeding. Pass the same workspace context and carried working mode through the remap call. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
apps/web/src/hooks/useHandleNewThread.ts (1)
149-167: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor duplication of the explicit-option spread pattern.
The per-field conditional-spread idiom used to build the explicit-override object (Line 152-156) mirrors the same pattern already used verbatim at Line 213-217 and Line 224-227. Consider extracting a small
buildExplicitWorkspaceOptions(options)helper to avoid a third copy of this logic drifting out of sync if a new workspace field is added later.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/hooks/useHandleNewThread.ts` around lines 149 - 167, Extract the repeated conditional-spread construction into a shared buildExplicitWorkspaceOptions(options) helper, then use it in the workspaceContext logic and the existing equivalent blocks around the later occurrences. Preserve each field’s current option guards and values so all explicit workspace overrides remain consistent.apps/web/src/components/BranchToolbar.tsx (1)
176-182: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated
"previous-worktree"sentinel string.This literal is hardcoded here (twice) and also exported as
PREVIOUS_WORKTREE_SELECT_VALUEfromBranchToolbarEnvModeSelector.tsx. See consolidated comment for the shared fix across both files.Also applies to: 202-209
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/components/BranchToolbar.tsx` around lines 176 - 182, Replace the hardcoded "previous-worktree" sentinel checks in the BranchToolbar value-change handlers with the shared PREVIOUS_WORKTREE_SELECT_VALUE export from BranchToolbarEnvModeSelector.tsx, including both referenced handler locations, while preserving the existing callback and return behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/components/BranchToolbar.tsx`:
- Around line 259-277: Filter the result from useThreadShellsForProjectRefs
before passing it to resolvePreviousWorktreeSeed in the previousWorktreeSeed
useMemo, retaining only threads whose archivedAt is null. Keep the existing
canUsePreviousWorktree and activeWorktreePath behavior unchanged.
In `@apps/web/src/components/Sidebar.tsx`:
- Around line 2129-2140: The new-thread-on-branch branch in Sidebar.tsx must
handle rejected handleNewThread promises instead of discarding them. Wrap the
call using the same settlePromise pattern as createThreadForProjectMember and
surface failures with the existing toast/error feedback, while preserving the
current branch, worktreePath, envMode, and startFromOrigin arguments.
In `@apps/web/src/components/SidebarV2.tsx`:
- Around line 1604-1616: Update the "new-thread-on-branch" case in SidebarV2.tsx
to handle rejected promises from handleNewThreadRef.current and provide user
feedback using the same failure-handling pattern as the equivalent Sidebar.tsx
action and nearby mutation flows. Preserve the existing branch, worktreePath,
envMode, and startFromOrigin arguments.
---
Nitpick comments:
In `@apps/web/src/components/BranchToolbar.tsx`:
- Around line 176-182: Replace the hardcoded "previous-worktree" sentinel checks
in the BranchToolbar value-change handlers with the shared
PREVIOUS_WORKTREE_SELECT_VALUE export from BranchToolbarEnvModeSelector.tsx,
including both referenced handler locations, while preserving the existing
callback and return behavior.
In `@apps/web/src/hooks/useHandleNewThread.ts`:
- Around line 149-167: Extract the repeated conditional-spread construction into
a shared buildExplicitWorkspaceOptions(options) helper, then use it in the
workspaceContext logic and the existing equivalent blocks around the later
occurrences. Preserve each field’s current option guards and values so all
explicit workspace overrides remain consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 3b513d64-6ecc-45d8-9b12-fbc01957fae6
📒 Files selected for processing (13)
apps/web/src/components/BranchToolbar.logic.test.tsapps/web/src/components/BranchToolbar.logic.tsapps/web/src/components/BranchToolbar.tsxapps/web/src/components/BranchToolbarEnvModeSelector.tsxapps/web/src/components/CommandPalette.tsxapps/web/src/components/Sidebar.logic.test.tsapps/web/src/components/Sidebar.logic.tsapps/web/src/components/Sidebar.tsxapps/web/src/components/SidebarV2.tsxapps/web/src/hooks/useHandleNewThread.tsapps/web/src/lib/chatThreadActions.test.tsapps/web/src/lib/chatThreadActions.tsapps/web/src/routes/_chat.tsx
💤 Files with no reviewable changes (2)
- apps/web/src/components/Sidebar.logic.test.ts
- apps/web/src/components/Sidebar.logic.ts
| if (clicked === "new-thread-on-branch") { | ||
| // Explicit branch carry-over: reuse the thread's worktree when it | ||
| // has one, otherwise its branch on the local checkout. | ||
| void handleNewThread(scopeProjectRef(thread.environmentId, thread.projectId), { | ||
| branch: thread.branch, | ||
| worktreePath: thread.worktreePath, | ||
| envMode: thread.worktreePath ? "worktree" : "local", | ||
| startFromOrigin: false, | ||
| }); | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Missing failure handling for the new "New thread on <branch>" action.
void handleNewThread(...) here has no error path, unlike createThreadForProjectMember (lines 1881-1893) in this same file, which wraps the identical call in settlePromise and shows a toast on failure. A rejected promise here silently fails with no user feedback. See consolidated comment for the shared fix with SidebarV2.tsx.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/components/Sidebar.tsx` around lines 2129 - 2140, The
new-thread-on-branch branch in Sidebar.tsx must handle rejected handleNewThread
promises instead of discarding them. Wrap the call using the same settlePromise
pattern as createThreadForProjectMember and surface failures with the existing
toast/error feedback, while preserving the current branch, worktreePath,
envMode, and startFromOrigin arguments.
| case "new-thread-on-branch": | ||
| // Explicit branch carry-over: reuse the thread's worktree when it | ||
| // has one, otherwise its branch on the local checkout. | ||
| void handleNewThreadRef.current( | ||
| scopeProjectRef(thread.environmentId, thread.projectId), | ||
| { | ||
| branch: thread.branch, | ||
| worktreePath: thread.worktreePath, | ||
| envMode: thread.worktreePath ? "worktree" : "local", | ||
| startFromOrigin: false, | ||
| }, | ||
| ); | ||
| return; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Missing failure handling for the new "New thread on <branch>" action.
Same gap as Sidebar.tsx's equivalent action: void handleNewThreadRef.current(...) has no failure path or user feedback, unlike this file's other mutation flows. See consolidated comment.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/components/SidebarV2.tsx` around lines 1604 - 1616, Update the
"new-thread-on-branch" case in SidebarV2.tsx to handle rejected promises from
handleNewThreadRef.current and provide user feedback using the same
failure-handling pattern as the equivalent Sidebar.tsx action and nearby
mutation flows. Preserve the existing branch, worktreePath, envMode, and
startFromOrigin arguments.
… action Review: both sidebars discarded the handleNewThread promise for the new context-menu action, so a failed thread creation gave no user feedback. Wrap in settlePromise and show the same error toast the other new-thread flows use. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nch inheritance fix 22 upstream commits (pingdotgg#4274-pingdotgg#4411). No conflicts; no overlap with the fork's provider-usage feature or release pipeline.
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)
…otgg#4411) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 2f41c07)

What Changed
buildContextualThreadOptions,startNewThreadInProjectFromContext, and the v1 sidebar's seed-context machinery.Why
The new-thread defaults fix (#4276) only covered the no-options path. Every other entry point passed explicit options copied from the viewed thread, which silently bypassed the "always use new worktrees / default main / latest origin" preferences — new threads on remote boxes kept landing on "current checkout" and random branches. Carrying the workspace implicitly was the wrong default; carrying the working mode (model/effort/permissions) is what users actually want, and branch reuse is now an explicit, visible choice.
Review-bot findings addressed during review: working-mode carry now applies when explicit workspace options are passed; carried model selections replace stale draft options (
replaceOptions); draft remaps across logical-project members no longer wipe workspace context; previous-worktree ranking uses parsed timestamps and skips archived threads; context-menu failures surface a toast.UI Changes
Checklist
🤖 Generated with Claude Code