Skip to content

feat: non-blocking worktree creation with in-tab progress#4729

Open
tmchow wants to merge 1 commit into
stablyai:mainfrom
tmchow:tmchow/tmchow-worktree-creation-spinner
Open

feat: non-blocking worktree creation with in-tab progress#4729
tmchow wants to merge 1 commit into
stablyai:mainfrom
tmchow:tmchow/tmchow-worktree-creation-spinner

Conversation

@tmchow
Copy link
Copy Markdown
Contributor

@tmchow tmchow commented Jun 6, 2026

Summary

Creating a worktree no longer blocks you. The Create Worktree modal used to stay open with a spinning button until the entire create finished — base-ref git fetch + git worktree add, which runs 10–15s on heavy repos — so you sat staring at a frozen modal with nothing else you could do. Now the modal closes the instant you submit and the work continues in the background, where you can watch it, leave it, or cancel it.

A new in-tab panel shows live setup status as the worktree spins up, a row in the sidebar tracks each in-flight create, and when git finishes the workspace swaps straight to its terminal. You can switch to other worktrees while one is being created, and if creation fails the panel shows the error with a Retry.

Demo

Before (Left) vs After (Right)

CleanShot_2026-06-05_at_17.12.13-converted.mp4

Behavior

  • Submit → modal closes immediately; the new workspace shows a "Creating worktree…" panel stepping through Fetching base branchCreating worktree.
  • Navigate away mid-create → switching to another worktree works; the pending one keeps spinning in the sidebar and is one click away.
  • Cancel (✕ on the sidebar row, or Cancel in the panel) → abandons the in-progress UI. Git can't be interrupted, so a worktree already created on disk will still appear as a normal row — it just won't be auto-provisioned with a terminal/agent.
  • Failure → error + Retry in the panel, an error state on the sidebar row, and a toast if you've navigated away.
  • Remote/SSH targets (which don't report phase progress) show a single indeterminate spinner instead of a checklist that can't advance.

Design notes

  • Pending creations live in a separate store map, not a faked worktree row. Inventing a Worktree to get an early sidebar row would ripple through git-status, the tab model, session persistence, and PTY spawning. Keeping them separate means activeWorktreeId stays strictly real and the existing worktree lifecycle is untouched.
  • Connects an event that already existed. The main process already emitted createWorktree:progress with no listener; this wires it up and adds a per-create correlation id so concurrent creates each drive their own panel.
  • Scoped to composer quick-create. Other createWorktree callers (palette, automation dispatch, session fork) keep their synchronous behavior.
  • Flicker-free swap. On success, activation and clearing the pending entry happen in one synchronous commit, so the panel→terminal handoff lands in a single frame — no two-row flash, no empty terminal.

Testing

  • New unit tests for the pending-creation store actions (including the no-op progress guard that prevents re-renders on duplicate events) and panel-dismissal on worktree activation.
  • Full typecheck + lint clean; renderer suite green (2023 tests).
  • Reviewed across 10 code-review personas; the one behavioral finding — a cancelled create still provisioning a terminal/agent after git finished — is fixed.

Compound Engineering
Claude Code

The Create Worktree modal stayed open with a spinning button for the full
create IPC (base-ref git fetch + `git worktree add`, ~10-15s on heavy
repos) and only dismissed once it resolved, so the user stared at a frozen
modal with no way to work elsewhere.

Run creation in the background instead. On submit the modal closes
immediately and an in-tab "Creating worktree…" panel shows live setup
status, wiring the previously-unused `createWorktree:progress` main->renderer
event via a per-creation correlation id. A sidebar row tracks each
in-flight create, the user can navigate to other worktrees or cancel while
it runs, and on success it swaps to the real worktree + terminal in one
frame. Failure shows the error in the panel with retry; remote/runtime
targets (no progress events) show an indeterminate spinner.

Pending creations live in a separate store map rather than a faked Worktree
row, so git-status, the tab model, persistence, and PTY spawning are
untouched. Only the composer quick-create path changes; other createWorktree
callers keep their synchronous behavior.
Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — this PR makes worktree creation non-blocking: the modal closes immediately on submit and git fetch + git worktree add run in the background with an in-tab progress panel and sidebar strip.

  • PendingWorktreeCreation store map — separate from worktreesByRepo so activeWorktreeId stays strictly real; rides on a creationId correlation id for concurrent creates.
  • WorktreeCreationPanel — stepped checklist (fetching → creating) for local targets, indeterminate spinner for remote/runtime targets; error state with Retry/Dismiss.
  • PendingWorktreeCreationsStrip — sidebar row per in-flight creation, with cancel and error indicators; memoized on map reference to avoid re-renders from unrelated store updates.
  • worktree-creation-flow.ts — background orchestration: captures the composer's resolved state into a WorktreeCreationRequest, runs createWorktree in a fire-and-forget promise, and handles the race where the user dismissed mid-flight by checking the pending entry post-await.
  • setActiveWorktree now clears activePendingCreationId — navigating to any worktree dismisses the creation panel; removePendingWorktreeCreation only clears the active surface when it pointed at the removed entry, so dismissing a background creation doesn't yank the user.
  • WorktreeStartupPayload extracted from inline types — deduplicates the anonymous startup-object shape across activateAndRevealWorktree, ensureWorktreeHasInitialTerminal, and applyDefaultTerminalTabs.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@AmethystLiang AmethystLiang self-requested a review June 6, 2026 07:58
@nwparker
Copy link
Copy Markdown
Contributor

nwparker commented Jun 6, 2026

I think we're on the same wavelength. I was thinking about this.

I was wondering though maybe... maybe we can actually just immediatly open the worktree?

How?

  1. Open workspace immediatly
  2. In seperate pane or tab, run the commands in a terminal to clone things over etc

So in other words, we can make the process instant... just the file might now show up till a few seconds later

Interested to hear your thoughts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants