Add worktree handoff and status tools to the t3-code MCP server#3754
Add worktree handoff and status tools to the t3-code MCP server#3754nsxdavid wants to merge 9 commits into
Conversation
…andoff Adds a worktree toolkit to the t3-code MCP server so an agent can move its own thread into a new git worktree mid-conversation. The tool: - creates the worktree branch from a base ref (defaults to the branch currently checked out in the project workspace), optionally starting from the remote-tracking commit of that ref (defaults to the server's 'new worktrees start from origin' setting) - supports an optional explicit worktree path (defaults to the server-managed worktrees directory) - dispatches thread.meta.update so the provider session restarts inside the worktree at the next turn with the conversation preserved via the existing resumeCursor machinery - runs the project's configured setup script in the new worktree by default; setup failures are reported in the result instead of failing the handoff - fails cleanly when the thread is already attached to a worktree or the base ref cannot be resolved Introduces a 'worktree' MCP capability alongside 'preview' and new contracts (WorktreeHandoffInput/Result/Error).
…ror names Adds a read-only worktree_status tool reporting the calling thread's worktree binding (attached, worktreePath, branch), the project's main workspace root, and the server default for startFromOrigin, so agents can check whether a handoff is possible or already happened before calling worktree_handoff. Renames the shared error classes to be tool-neutral now that the toolkit has more than one tool: WorktreeHandoffUnavailableError -> WorktreeCapabilityUnavailableError, WorktreeHandoffThreadNotFoundError -> WorktreeThreadNotFoundError, WorktreeHandoffOperationError -> WorktreeOperationError. Handoff-specific errors keep their names.
- rename contracts module worktreeHandoff.ts to worktree.ts now that it also holds the status schemas - type the handoff handler input with the WorktreeHandoffInput contract instead of an inline structural type - give requireWorktreeCapability an Effect.fn trace span matching requireMcpCapability - drop a dead undefined check on thread.worktreePath (contract is NullOr) - use 'satisfies Partial<Service>' for test mocks instead of double casts, and tighten the createWorktree stub signature it flagged
… MCP layer Boots the real McpHttpServer.layer (layerHttp transport, auth middleware, session registry) over a test HTTP server, mints a credential, and asserts tools/list includes worktree_handoff and worktree_status alongside the preview tools.
An explicit empty Schema.Struct({}) serializes to JSON Schema
'anyOf: [object, array]', which is not a valid MCP tool inputSchema
(clients require a top-level object schema). Claude Code rejects the
entire t3-code MCP server when any tool schema is invalid, so the
broken worktree_status schema silently took the preview tools down
with it - the server stayed 'pending' and sessions saw zero tools.
Drop the explicit parameters so Tool.make defaults to Tool.EmptyParams,
which serializes to a top-level object schema, remove the now-unused
WorktreeStatusInput contract, and extend the registration test to
assert every listed tool has a top-level object inputSchema.
- correct the operation label on the settings read in the handoff path (resolveSettings, not resolveBaseRef) - assert typed failure tags unconditionally in handler tests via an expectTypedFailure helper so defects can no longer slip past the guarded assertions
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
One convention issue: WorktreeOperationError copies the underlying cause.message into a detail field and builds its message from it, instead of preserving the real failure as cause and deriving the message from structural attributes. The sibling previewAutomation.ts errors already follow the expected pattern (cause: Schema.Defect() plus bounded diagnostics). See inline comment.
Posted via Macroscope — Effect Service Conventions
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a7bf0f58f3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a7bf0f5. Configure here.
ApprovabilityVerdict: Needs human review Introduces new worktree handoff and status MCP tools that create git worktrees, rebind agent threads, and run setup scripts. New features with cross-cutting behavior affecting session management and filesystem operations warrant human review. You can customize Macroscope's approvability policy. Learn more. |
- WorktreeOperationError now preserves the underlying failure as cause (Schema.Defect) and derives its message from the operation alone, matching the previewAutomation error conventions, instead of copying the wrapped error's message into a detail field - worktree_handoff rejects relative paths: git would create them relative to the project workspace but the raw string would be stored as the thread's worktree binding and later used as the session cwd
There was a problem hiding this comment.
One finding on the new worktree handlers: WorktreeOperationError requires a cause, but the project-not-found path has no underlying failure and fabricates an Error only to satisfy that field.
Posted via Macroscope — Effect Service Conventions
…ting - serialize handoffs per thread with an in-flight guard so concurrent calls cannot both pass the attachment check and create two worktrees - remove the created worktree when the thread.meta.update dispatch fails so a failed handoff leaves nothing orphaned on disk - reject relative paths at the schema level (absolute POSIX, Windows drive, or UNC) in addition to the handler check, so the input contract matches its description
…tools WorktreeOperationError requires an underlying cause, and project-not-found has none; manufacturing an Error just to fill the field violated the error conventions. Add WorktreeProjectNotFoundError (threadId, projectId), symmetric with WorktreeThreadNotFoundError, and use it in both handlers.

What Changed
Closes #3753.
Adds two tools to the
t3-codeMCP server:worktree_handoffcreates a worktree and re-points the calling thread at it.branchis the only required argument; the rest are optional:baseRefdefaults to the branch checked out in the project workspacestartFromOrigindefaults to the existing "new worktrees start from origin" server settingpathdefaults to the managed worktrees directoryrunSetupScriptdefaults to trueworktree_statusreports the thread's current binding (attached or not, worktree path, branch, workspace root) so an agent can check before trying.No new machinery. The handler runs the same sequence as the thread-bootstrap path in
ws.ts:GitWorkflowService.createWorktree, athread.meta.updatedispatch, a status refresh, and the project setup script runner. The session restart with resume on cwd change picks the rest up on the next turn, and worktree cleanup on thread delete works unchanged since it keys offworktreePath. Aworktreecapability is added alongsidepreviewin the MCP credential.Deliberately not included: a detach/undo tool. The UI has no equivalent (worktree removal only happens on thread delete), and detaching raises lifecycle questions that seem worth their own discussion.
Why
See #3753: an agent can create a worktree from its shell, but the thread binding lives in T3 Code's orchestration state and nothing agent-reachable can update it, so agent-driven worktree setup dead-ends. The MCP server is the only channel T3 Code exposes to the agent, so this is the only place the capability can live.
Tested with unit tests over the handlers, an HTTP-level test that drives the production MCP layer end to end (auth, initialize, tools/list), and manually in a packaged Windows build: status, handoff from origin, session resume inside the worktree with conversation intact, and cleanup on thread delete.
Checklist
Note
Medium Risk
Agents can create worktrees and change thread metadata via git and orchestration; rollback and concurrency guards reduce orphan worktrees, but filesystem and git side effects remain meaningful.
Overview
Adds
worktree_handoffandworktree_statusto the t3-code MCP server so agents can bind a thread to a git worktree through orchestration instead of only creating worktrees in a shell.worktree_handoffcreates a worktree (optional origin-based base, absolute path, setup script), dispatchesthread.meta.updatewith branch andworktreePath, refreshes VCS status, and returns setup-script outcome. It rejects threads already on a worktree, invalid paths, and concurrent handoffs per thread; if metadata update fails, it force-removes the new worktree.worktree_statusis read-only: attachment state, paths, branch, workspace root, and the server default forstartFromOrigin.New MCP credentials include a
worktreecapability alongsidepreview; handlers use dedicatedrequireWorktreeCapabilitychecks. Shared Effect schemas and tagged errors live inpackages/contracts/worktree.ts. The HTTP MCP layer registers the worktree toolkit next to preview; handler and HTTPtools/listtests cover the flow.Reviewed by Cursor Bugbot for commit a33fb24. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add
worktree_handoffandworktree_statustools to the t3-code MCP servertools.ts:worktree_handofffor end-to-end git worktree creation with optional origin fetch, thread metadata update, rollback on failure, and optional setup script execution; andworktree_statusto query current worktree attachment state.handlers.tswith a per-thread in-flight serialization guard — concurrentworktree_handoffcalls for the same thread fail withWorktreeHandoffInvalidRequestError.packages/contracts/src/worktree.tsand wires theWorktreeToolkitinto the MCP server layer alongside the existing preview toolkit.worktreecapability; sessions without it receiveWorktreeCapabilityUnavailableErroron tool invocation.worktree_handoffmutates git state (creates a worktree, updates thread metadata) and only rolls back the worktree creation on metadata update failure — setup script failures are reported but do not roll back the worktree.Macroscope summarized a33fb24.