Forking

Forking copies the ancestor graph up to a selected step and starts a new run from that fork point. The copied steps keep their original IDs because they are the same content-addressed records.

How Forking Works

Run.fork(from_step_id) resolves the step ref, walks ancestors root-first, builds a new graph containing those steps, sets refs.mainand refs.fork_point to the selected step, and records metadata.forked_from.

fork_example.py
1from opentine import Run, StepKind
2
3run = Run(id="original", model_info="claude-sonnet-4-20250514")
4
5search_step = run.add_step(StepKind.think, {"text": "Search for papers"})
6tool_step = run.add_step(
7    StepKind.tool,
8    {"name": "search", "arguments": {"query": "RLHF"}},
9    outputs={"results": ["paper_a"]},
10    parent_ids=[search_step.id],
11)
12summary_step = run.add_step(
13    StepKind.done,
14    {"text": "Summary..."},
15    outputs={"text": "Summary..."},
16    parent_ids=[tool_step.id],
17)
18bad = run.add_step(
19    StepKind.error,
20    {"text": "Fetch failed"},
21    error={"type": "HTTPError", "message": "404"},
22    parent_ids=[summary_step.id],
23)
24
25forked = run.fork(summary_step.id, new_run_id="retry-01")
26forked.save("retry-01.tine")

What the Fork Contains

The fork contains the selected step and its ancestors. Descendants after the fork point and unrelated sibling branches are excluded.

fork_result.py
print([step.short_id for step in forked.steps])
print(forked.status.value)              # "running"
print(forked.refs["main"] == summary_step.id) # True
print(forked.refs["fork_point"])        # full fork-point step ID
print(forked.metadata["forked_from"])   # original run ID

CLI Workflow

Step refs can be numeric traversal indexes, full IDs, or unique ID prefixes.

Terminal
tine show failed.tine
tine fork failed.tine --from-step 2 --save retry.tine
tine fork failed.tine --from-step 6d4a0b270a5f --save retry-by-prefix.tine
tine diff failed.tine retry.tine

Fork Into a Harness

The CLI can pass fork context into an external harness when you specify a harness and prompt. The harness run is still a new recorded graph.

Terminal
tine fork failed.tine \
  --from-step 2 \
  --harness codex \
  --prompt "Retry from this context with a narrower search." \
  --save retry_codex.tine

Continue With a Native Agent

For native opentine agents, use agent.resume_sync() or the async agent.resume() API to continue from a forked run.

native_resume.py
1from opentine import Agent, Run
2from opentine.models.anthropic import Anthropic
3
4source = Run.load("failed.tine")
5forked = source.fork("6d4a0b270a5f")
6
7agent = Agent(model=Anthropic("claude-sonnet-4-20250514"))
8resumed = agent.resume_sync(
9    forked,
10    prompt="Retry with a narrower source set and cite each claim.",
11)
12resumed.save("retry_completed.tine")

Cost and Provenance

Forking does not re-execute the retained steps. It gives you a precise provenance boundary: everything before the fork point is the same recorded work, and everything after it belongs to the new branch.