Skip to main content
Every successful task attempt records the workspace’s JJ change ID into _smithers_attempts.jj_pointer. The time-travel API replays a run to one of those points: it restores the filesystem from the captured pointer and discards the graph snapshots recorded after the attempt began, so the run’s timeline rolls back to that attempt. The public, facade-exported surface is two functions. revertToAttempt is the low-level VCS restore; timeTravel is the higher-level reset that can also reset the target node and its dependents so the engine re-runs them.
import { timeTravel, revertToAttempt } from "smithers-orchestrator";
import type {
  TimeTravelOptions,
  TimeTravelResult,
  RevertOptions,
  RevertResult,
} from "smithers-orchestrator";
Both take the run’s SmithersDb adapter as their first argument. Neither throws for a missing attempt or a missing pointer; they report failure on the returned success boolean. Inspect result.success rather than wrapping the call in try/catch.

timeTravel

Restore VCS to a previous attempt, then reset the target node (and optionally its dependents) back to pending so the engine re-runs from there. This is the entry point you want when you intend to resume the run: it cancels later attempts, deletes the affected output rows, discards frames recorded after the attempt started, and flips the run back to running.
function timeTravel(adapter: SmithersDb, opts: TimeTravelOptions): Promise<TimeTravelResult>;
adapter
SmithersDb
required
The database adapter for the run, as returned by the authoring factory’s db layer. See SmithersDb.
opts
TimeTravelOptions
required
TimeTravelResult
Promise<object>
const reset = await timeTravel(adapter, {
  runId: "RUN_ID",
  nodeId: "NODE_ID",
  attempt: 2,
  iteration: 0,
  resetDependents: true,
  restoreVcs: true,
});

if (!reset.success) throw new Error(reset.error);
// reset.resetNodes are now pending; resume the run to re-execute them.
Source timetravel.js · TimeTravelOptions.ts · Tests timetravel.e2e.test.jsx · See also Revert, revertToAttempt

revertToAttempt

Restore the working copy to an attempt’s JJ pointer and discard DB frames recorded after the attempt started. This is files-only: it does not reset nodes, cancel attempts, or change the run status, so it leaves the graph untouched. Use it when you only need the filesystem state of a past attempt. Unlike timeTravel, both iteration and attempt are required.
function revertToAttempt(adapter: SmithersDb, opts: RevertOptions): Promise<RevertResult>;
adapter
SmithersDb
required
The database adapter for the run. See SmithersDb.
opts
RevertOptions
required
RevertResult
Promise<object>
const result = await revertToAttempt(adapter, {
  runId: "RUN_ID",
  nodeId: "NODE_ID",
  attempt: 2,
  iteration: 0,
});

if (!result.success) throw new Error(result.error);
revertToAttempt and timeTravel need JJ in PATH and a JJ-initialized workspace, and the target attempt must have completed while JJ was available (otherwise no pointer was captured). See Revert for the requirements and the equivalent CLI command.
Source revert.js · RevertOptions.ts · Tests revert.test.js · See also Revert, timeTravel

CLI surface

The richer time-travel surface (fork, replay, rewind, snapshots, and timeline) is driven through the CLI and the rewind RPC, not as facade exports. Reach for those rather than importing non-exported functions from the package.
  • CLI overview for fork, replay, rewind, snapshots, and timeline.
  • Revert for the revert command that mirrors revertToAttempt.
  • rewind-run RPC to rewind a run over the gateway.
# Browse the timeline, then rewind to a checkpoint and resume.
bunx smithers-orchestrator timeline --run-id RUN_ID
bunx smithers-orchestrator rewind --run-id RUN_ID --node-id NODE_ID
Source time-travel/src · Tests time-travel/tests · See also CLI overview, Revert, rewind-run RPC