Fork
Branch a real thread from a saved point and try a different input, model or prompt, in a fresh sandbox.
A fork is a new branch of a thread that starts from a snapshot of an earlier point. The original branch is untouched. Use it to reproduce a production issue, try a fix, or compare two answers side by side.
Fork points
After a turn that used the sandbox, threads snapshots the sandbox's files. Those snapshots are the points you can fork from, and timeline() marks them with fork_point.
TypeScript snapshots after a turn that changed something (any tool call that isn't read-only). Python also snapshots after turns that only read from the sandbox. A thread without a sandbox has no fork points.
Fork and continue
Open the thread with the sandbox adapter to restore into, pick a point, fork, and run the child branch with the same agent.
const opened = await openThread(store, first.thread.id, { sandbox });
if (!opened.ok) throw new Error(opened.error.message);
const thread = opened.value;
const [point] = await thread.forkPoints();
if (point === undefined) throw new Error("no fork point yet");
const forked = await thread.fork(point);
if (!forked.ok) throw new Error(forked.error.message);
const child = forked.value;
const retry = await writer.run("Rewrite it in French.", { store, thread: child });
console.log(retry.status, child.branch !== thread.branch);fork returns a value, not an exception. Common failures:
| Code | Why |
|---|---|
sandbox_required | The thread was opened without a sandbox to restore into |
no_snapshot_boundary | The event you passed isn't a fork point on this branch |
snapshot_restore_failed | The sandbox adapter couldn't restore the snapshot, or its provider doesn't match the snapshot's |
forkPoints() returns an array in TypeScript. In Python, fork_points() returns Ok / Err like the other reads.
What a fork isolates
- Sandbox. The child gets its own sandbox, restored from the snapshot. Changes on the fork never reach the original sandbox.
- Log. The child shares history up to the fork point and records its own events after it. The parent branch never changes.
- Knowledge. By default the fork searches the knowledge base as it was at the fork point, so results are reproducible. Pass
knowledge: "current"to use today's documents instead.
await thread.fork(point, { knowledge: "current" });Continue the child with the same agent definition. A thread is pinned to the config it started with.
Replay without real side effects
Python only today.
A stub fork answers every external operation from what the original branch recorded after the fork point. Nothing goes live: a call the original never made fails the run with unmatched_external_op instead of reaching the outside world. Use it to replay a production turn against a changed prompt safely.
stubbed = await thread.fork(points.value[0], mode="stub")Stub mode needs a sandbox that blocks all network access. TypeScript accepts mode: "stub" and checks the sandbox, but runs on the child branch are not stubbed yet, so don't rely on it.