Skip to content

feat(threads): an agent can put a thread in a checkout another thread already has - #911

Merged
badcuban merged 2 commits into
mainfrom
feat/thread-start-existing-checkout
Nov 14, 2026
Merged

badcuban merged 2 commits into
mainfrom
feat/thread-start-existing-checkout

Conversation

@badcuban

Copy link
Copy Markdown
Collaborator

Closes #892.

The problem

An agent could only start a thread in a new worktree cut from its own commit. A reviewer started that way never saw the uncommitted work a coder thread had just finished, and pointing it at the coder's folder in the prompt left its real cwd and project instructions in the wrong place.

The fix

  • thread_start takes a per-thread checkout: self, or the id of a thread the caller started. It is a thread, never a path. The folder and branch are resolved when the agent asks and saved with the request, so a late approval or a restart lands in the same place. Setup finds the folder among the project's worktrees again and reads its branch then. No worktree or branch is made, and the setup script is not run.
  • thread_send takes a checkout that moves an idle child there before it reads the message. It reuses the events of the user's own checkout switch, so the session restarts in the new folder and keeps its conversation. A busy child, or one with background work still running, is refused.
  • thread_start takes a per-thread access that can only lower access.
  • A guest, not an owner. A thread in another thread's worktree records it as worktreeOrigin (migration 110, a new column only, no rows rewritten). A guest never renames the branch on its first turn, never offers the folder for removal, and always reverts selectively. A move is written on the thread as an activity, and a revert to before it is refused.
  • Refused while the owning thread is working (except self), for linked computers, and while the new setting is off.
  • Setting: "Threads can share a checkout" in Settings › Threads, off by default, read at every call and again at setup.
  • On screen: the approval card names whose checkout a thread shares and a lowered access level; the row under the message box reads "Shared worktree"; the sidebar hover card names whose worktree it is.

ChildThreadWorkspace gets no new union member, so an older client still decodes these requests: ChildThreadLaunch.checkout rides beside workspace: project_folder.

The outside-agent and assistant tools are unchanged. Design notes are in docs/design/child-threads.md ("An existing checkout").

Checked

  • vp fmt, vp lint, vp run typecheck
  • vp run test (full suite)
  • vp run '@threadlines/web#test:browser': one unrelated spec (ThemeShareDialog) failed in the full run and passed when run alone

Not checked

No provider has run in a shared checkout yet. The cwd reaches every driver through the shared session start, and Claude and OpenCode have explicit code for resuming after a checkout switch, but nothing was run live with Codex, Claude, OpenCode, Antigravity, Muse, Pi or the other ACP agents.

… already has

An agent could only start a thread in a new worktree cut from its own
commit, so a reviewer never saw the uncommitted work a coder thread had
just finished (#892).

- thread_start takes a per-thread `checkout` (`self` or the id of a thread
  the caller started) and a per-thread `access` that can only lower access.
  The folder and branch are resolved when asked and saved with the request;
  setup finds the folder among the project's worktrees again and reads its
  branch then. No worktree or branch is made and the setup script is not run.
- thread_send takes a `checkout` that moves an idle child there before it
  reads the message, with the events the user's own checkout switch uses, so
  it keeps its conversation. A busy child, or one with background work still
  running, is refused.
- A thread in another thread's worktree records it as `worktreeOrigin`
  (migration 110, a new column only). Such a guest never renames the branch,
  never offers the folder for removal, and always reverts selectively. A
  move is written on the thread, and a revert to before it is refused.
- Refused while the owning thread is working, for linked computers, and
  while the new setting "Threads can share a checkout" is off (the default).
- The approval card names whose checkout a thread shares and a lowered
  access level; the row under the message box reads "Shared worktree"; the
  sidebar hover card names whose worktree it is.
@vercel

vercel Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
threadlines Skipped Skipped Nov 14, 2026 7:27am UTC

Request Review

…o startup

The sidebar hover card and the row under the message box now read another
thread's title, and importing that hook from childThreads.ts dragged the
whole module into the startup code (about 6 KB raw, 2 KB gzip), which put
the startup size 563 B over its budget in CI. The hook moves to a file of
its own; childThreads.ts re-exports it.

This branch was previously deployed

1 inactive deployment
Preview — c1ed92a6 Deployed Nov 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Allow thread_start to use an existing working directory without creating a worktree

1 participant