# Files changed · PR \#10558 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/10558/diffs)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

[feat\(mcp\): expose fork and merge-back commands](https://git.cafe/pingdotgg/t3code/pull/10558.md)

Version: 1

Head commit: e3e71c75fa04a4bdfc277c8eea3266686a56aa72

Base commit: b0152bc6413b878f786c6c2ef30770fde71e3bbc

Comparison base: b0152bc6413b878f786c6c2ef30770fde71e3bbc

Showing up to 20 entries from this revision. If the pull request changes, reopen the first page before continuing.

## apps/server/src/mcp/toolkits/thread/handlers.ts

Status: modified; +50; −1

```diff
@@ -1,7 +1,7 @@
 import {
   type CommandId,
   type RuntimeRequestId,
-  type ThreadId,
+  ThreadId,
   type OrchestrationV2ThreadProjection,
   type RunId,
   OrchestratorMcpFailure,
@@ -61,6 +61,55 @@
   return { ...context, request, item };
 });
 export const ThreadToolkitHandlersLive = ThreadToolkit.toLayer({
+  t3_thread_fork: (input) =>
+    Effect.gen(function* () {
+      const { threads, projection } = yield* readWritableThread();
+      const commandId = yield* newCommandId();
+      const targetThreadId = ThreadId.make(`${commandId}:fork`);
+      const result = yield* threads
+        .dispatch({
+          type: "thread.fork",
+          commandId,
+          sourceThreadId: projection.thread.id,
+          targetThreadId,
+          sourcePoint: input.sourcePoint,
+          ...(input.title === undefined ? {} : { title: input.title }),
+          createdBy: "agent",
+          creationSource: "mcp",
+        })
+        .pipe(Effect.mapError(unavailable));
+      return { sequence: result.sequence, targetThreadId };
+    }),
+  t3_thread_merge_back: (input) =>
+    Effect.gen(function* () {
+      const { threads, caller } = yield* readWritableThread(input.targetThreadId);
+      const result = yield* threads
+        .dispatch({
+          type: "thread.merge_back",
+          commandId: yield* newCommandId(),
+          sourceThreadId: caller.id,
+          targetThreadId: input.targetThreadId,
+          sourcePoint: input.sourcePoint,
+          createdBy: "agent",
+          creationSource: "mcp",
+        })
+        .pipe(Effect.mapError(unavailable));
+      return { sequence: result.sequence, targetThreadId: input.targetThreadId };
+    }),
+  t3_thread_transfers: (input) =>
+    Effect.gen(function* () {
+      const { projection } = yield* readThread(input.threadId);
+      return {
+        transfers: projection.contextTransfers.map(
+          ({ id, sourceThreadId, targetThreadId, status }) => ({
+            id,
+            sourceThreadId,
+            targetThreadId,
+            status,
+          }),
+        ),
+      };
+    }),
   t3_thread_configuration: (input) =>
     Effect.gen(function* () {
       const {
```

## apps/server/src/mcp/toolkits/thread/tools.ts

Status: modified; +45; −0

```diff
@@ -1,4 +1,7 @@
 import {
+  OrchestrationV2ThreadForkSourcePoint,
+  OrchestrationV2ContextTransfer,
+  TrimmedNonEmptyString,
   ModelSelection,
   RuntimeMode,
   ProviderInteractionMode,
@@ -174,7 +177,49 @@
   parameters: Schema.Struct({ modelSelection: ModelSelection }),
 }).annotate(Tool.Destructive, true);
 
+const transferResult = Schema.Struct({ sequence: NonNegativeInt, targetThreadId: ThreadId });
+export const ThreadForkTool = Tool.make("t3_thread_fork", {
+  ...commandTool,
+  description:
+    "Fork this thread from a stable run or checkpoint using the existing fork command. The fork inherits the source configuration. Acceptance does not mean a provider turn has completed.",
+  parameters: Schema.Struct({
+    sourcePoint: OrchestrationV2ThreadForkSourcePoint,
+    title: Schema.optional(TrimmedNonEmptyString),
+  }),
+  success: transferResult,
+}).annotate(Tool.Destructive, true);
+export const ThreadMergeBackTool = Tool.make("t3_thread_merge_back", {
+  ...commandTool,
+  description:
+    "Merge context from this thread back to a related thread in the same project. Existing lineage and transfer rules apply.",
+  parameters: Schema.Struct({
+    targetThreadId: ThreadId,
+    sourcePoint: OrchestrationV2ThreadForkSourcePoint,
+  }),
+  success: transferResult,
+}).annotate(Tool.Destructive, true);
+export const ThreadTransfersTool = Tool.make("t3_thread_transfers", {
+  ...commandTool,
+  description: "Read context transfer status for a thread in the calling project.",
+  parameters: Schema.Struct({ threadId: Schema.optional(ThreadId) }),
+  success: Schema.Struct({
+    transfers: Schema.Array(
+      Schema.Struct({
+        id: OrchestrationV2ContextTransfer.fields.id,
+        sourceThreadId: OrchestrationV2ContextTransfer.fields.sourceThreadId,
+        targetThreadId: OrchestrationV2ContextTransfer.fields.targetThreadId,
+        status: OrchestrationV2ContextTransfer.fields.status,
+      }),
+    ),
+  }),
+})
+  .annotate(Tool.Readonly, true)
+  .annotate(Tool.Destructive, false);
+
 export const ThreadToolkit = Toolkit.make(
+  ThreadForkTool,
+  ThreadMergeBackTool,
+  ThreadTransfersTool,
   ThreadConfigurationTool,
   ThreadConfigureTool,
   PendingRequestListTool,
```

## apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts

Status: modified; +1; −0

```diff
@@ -811,6 +811,7 @@
   "mcp__t3-code__t3_pending_request_list",
   "mcp__t3-code__t3_pending_request_read",
   "mcp__t3-code__t3_thread_configuration",
+  "mcp__t3-code__t3_thread_transfers",
   "mcp__t3-code__t3_queue_list",
   "mcp__t3-code__t3_queue_read",
 ];
```

## packages/shared/src/t3McpToolPresentation.ts

Status: modified; +3; −0

```diff
@@ -59,6 +59,9 @@
   t3_pending_request_respond: { displayName: "Answer pending questions" },
   t3_thread_configuration: { displayName: "Read thread configuration" },
   t3_thread_configure: { displayName: "Set thread model" },
+  t3_thread_fork: { displayName: "Fork this thread" },
+  t3_thread_merge_back: { displayName: "Merge thread context" },
+  t3_thread_transfers: { displayName: "Read thread transfers" },
   t3_thread_organize: { displayName: "Organize a thread" },
   t3_thread_update: { displayName: "Update T3 thread metadata" },
   t3_thread_send: { displayName: "Send to a T3 thread", summaryAction: "thread-send" },
```
