Skip to content

[Feature] Default new sessions to an auto-generated worktree, instead of a per-session trip through the branch chip #4251

Description

@randypitcherii

Problem or use case

For anyone whose normal workflow is "every session gets its own worktree", the new-session composer makes that a repeated manual ritual. Starting an isolated session today costs, per session:

  1. Click the git-branch chip in the composer footer tray (data-testid="new-chat-landing-branch-chip", web/src/shell/NewChatDialog.tsx).
  2. Wait for the popover, then click the shuffle button (new-chat-landing-branch-generate) to fill a name — or type one yourself.
  3. Dismiss the popover and get back to the prompt box.

The machinery to skip all of that already exists. generateBranchName() (NewChatDialog.tsx ~L2897) mints worktree-<8 hex> names, and there is already an effect (~L2950) that calls it automatically when the picked project stores use_worktree: true — set per project in ProjectSettingsDialog.tsx (~L374). So auto-generation is a supported, tested behavior; it is just gated behind per-project configuration.

That leaves two gaps:

  • No global default. A user who wants worktree-per-session everywhere must flip use_worktree on every project individually, and gets nothing for sessions started outside a project (the plain landing composer, which is the fastest path in and the one the ⌘K palette's "New chat" action lands on).
  • The setting that would host this already exists and is empty-ish. Settings → Git ("Configure how Omnigent works with Git", pages/SettingsPage.tsx ~L969) currently holds exactly one control, DefaultBaseBranchControl — a preference that only matters once you are creating a new worktree. The base branch for new worktrees is globally configurable; whether to create one at all is not.

The cost is small per session and large in aggregate: it is 2–3 clicks on the single most frequent action in the product, and it is friction precisely on the safe choice (isolated worktree) versus the unsafe one (agent runs directly in the main work tree).

Proposed solution

Add a global "Start new sessions in a new worktree" preference, defaulting to off (no behavior change for existing users), and honor it in the composer wherever a project config doesn't already say otherwise.

Settings. A switch in the existing Git section, stored with the same localStorage-preference shape as the base branch (lib/baseBranchPreferences.tsreadDefaultBaseBranch / writeDefaultBaseBranch). Sits directly above DefaultBaseBranchControl, which reads as its natural sub-setting.

Composer. Extend the existing opt-in worktree effect (NewChatDialog.tsx ~L2950) so its trigger is prefillConfig?.useWorktree === true || readDefaultUseWorktree(). Every guard that effect already carries stays exactly as-is, and they are the reason this is a small change:

  • ref-guarded to fire at most once per settled workspace (worktreeSeededForRef);
  • only into an empty branch field (branchName !== "" || prefilledBranch !== "" bails), so a typed name or an existing-worktree prefill is never clobbered;
  • skipped for sandbox sessions and until the workspace is settled;
  • only when the git-ness probe resolves and the workspace is a real repo (hostWorktrees.some((w) => w.is_main)), so it is inert in a non-git directory.

Precedence. Project config wins over the global default in both directions — a project with use_worktree: true still auto-generates when the global default is off, and a project explicitly configured without it should not be overridden by the global on. That requires distinguishing "unset" from "off" in the project config, which today only ever stores an explicit true (ProjectSettingsDialog.tsx ~L191: "only an explicit ON is stored"). Simplest version that preserves the existing storage contract: treat absent as "inherit the global", and add an explicit off value only if someone asks for it.

Escape hatch stays. The generated name lands in the branch field, visible on the chip (worktreeLabel), and is fully editable — clearing it before send starts in the working directory as before. Nothing becomes unopt-outable per session.

Acceptance criteria

  • Settings → Git has a "Start new sessions in a new worktree" switch, off by default, persisted across reloads.
  • With it on, opening the new-session composer on a git working directory pre-fills a generated worktree-* branch name with no clicks, and the chip reflects it.
  • With it on, the pre-fill does not fire for: sandbox sessions, non-git working directories, a workspace that is already an existing worktree (branch prefill wins), or a branch name the user typed.
  • Changing the working directory to another git repo re-seeds a fresh name once (existing ref-guard behavior).
  • A project with use_worktree: true behaves as it does today regardless of the global setting.
  • Vitest coverage alongside the existing NewChatDialog.projectPrefill.test.tsx / NewChatDialog.flow.test.tsx cases.

Alternatives considered

  • Make auto-generation unconditional (no setting). Wrong default for anyone who deliberately runs in the main work tree, and it changes behavior silently for every existing user. It also creates real on-disk worktrees as a side effect of merely opening the composer.
  • Ship it as a per-project default only, and improve project onboarding instead. Doesn't help the plain landing composer or the palette's "New chat" — the fastest and most-used entry points, which have no project.
  • Keep it manual but reduce it to one click (a "New worktree" item on the chip, or auto-focus the branch input when the popover opens). Better than today, but it still scales with session count, and the generate button is already effectively that one click.
  • Generate the branch server-side at session create when no branch is given. Moves the policy into the API and hides it from the UI — the user could no longer see or edit the name before sending, and the chip would show "No worktree" while a worktree was in fact created.

Harness

Not applicable

Platform or device

Not platform-specific

Harness mode

Not applicable

Expected reach

A substantial user segment

Authentication type

Not authentication-related

Metadata

Metadata

Assignees

Labels

FeatureNew feature or requestP2-mediumPriority: bug with workaround, important feature requestcomp:web-uiComponent: web frontend (ap-web)help wantedExtra attention is neededtriagedIssue has been triaged by the bot

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions