> ## Documentation Index
> Fetch the complete documentation index at: https://smithers.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Time-travel API

> Programmatic entry points to roll a run back to a previous task attempt.

Every successful task attempt records the workspace's [JJ](https://jj-vcs.github.io/jj/)
commit ID into `_smithers_attempts.jj_pointer`. The time-travel API replays a run
to one of those points, restoring the filesystem from the captured pointer and
discarding graph snapshots recorded after the attempt began, rolling the run's
timeline back to it.

The public, facade-exported surface is two functions: `revertToAttempt`, the
low-level VCS restore, and `timeTravel`, the higher-level reset that can also
reset the target node and its dependents so the engine re-runs them.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
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. A missing
attempt or pointer returns `success: false`. Crossing an unresolved external
effect throws `TIME_TRAVEL_SIDE_EFFECT_BLOCKED` with the boundary report in
the error details.

## timeTravel

Restores VCS to a previous attempt, then resets the target node (and optionally
its dependents) to `pending` so the engine re-runs from there. Use this to resume
a run: it cancels later attempts, deletes their output rows, discards frames
recorded after the attempt started, and flips the run back to `running`.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
function timeTravel(adapter: SmithersDb, opts: TimeTravelOptions): Promise<TimeTravelResult>;
```

<ParamField path="adapter" type="SmithersDb" required>
  The database adapter for the run, as returned by the authoring factory's `db`
  layer. See [`SmithersDb`](/reference/types).
</ParamField>

<ParamField path="opts" type="TimeTravelOptions" required>
  <Expandable title="TimeTravelOptions">
    <ParamField path="runId" type="string" required>
      The run to roll back.
    </ParamField>

    <ParamField path="nodeId" type="string" required>
      The node whose attempt is the rollback target.
    </ParamField>

    <ParamField path="iteration" type="number" default="0">
      Loop iteration of the node. Defaults to `0` for non-looped nodes.
    </ParamField>

    <ParamField path="attempt" type="number">
      Attempt number to restore. Omit to use the latest recorded attempt.
    </ParamField>

    <ParamField path="resetDependents" type="boolean" default="true">
      Also resets every node that ran after the target (later iterations, attempts
      started after its start time, or ordered after it) to `pending`. Set `false`
      to reset only the target node.
    </ParamField>

    <ParamField path="restoreVcs" type="boolean" default="true">
      Restore the working copy from the attempt's JJ pointer before resetting
      nodes. Set `false` to reset DB state without touching the filesystem.
    </ParamField>

    <ParamField path="force" type="boolean" default="false">
      Cross unresolved external effects, record the crossing, and mark the run
      for attention.
    </ParamField>

    <ParamField path="noRevert" type="boolean" default="false">
      Skip registered compensation handlers. Skipped effects require `force`.
    </ParamField>

    <ParamField path="onProgress" type="(event: SmithersEvent) => void">
      Callback for `TimeTravelStarted` / `TimeTravelFinished` events. See
      [`SmithersEvent`](/reference/types).
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="TimeTravelResult" type="Promise<object>">
  <Expandable title="TimeTravelResult">
    <ResponseField name="success" type="boolean">
      `true` once the reset committed. `false` if the attempt or node was not
      found, or the VCS restore failed.
    </ResponseField>

    <ResponseField name="jjPointer" type="string">
      The JJ commit ID restored from, when one was recorded for the attempt.
    </ResponseField>

    <ResponseField name="vcsRestored" type="boolean">
      Whether the working copy was restored. `false` when `restoreVcs` was off
      or the attempt had no pointer.
    </ResponseField>

    <ResponseField name="resetNodes" type="string[]">
      The node ids flipped back to `pending`, deduplicated.
    </ResponseField>

    <ResponseField name="effectBoundary" type="EffectBoundaryReport">
      Unconditional report with `blocking`, `revertible`, and `warnings`
      arrays.
    </ResponseField>

    <ResponseField name="error" type="string">
      Failure reason. Present only when `success` is `false`.
    </ResponseField>
  </Expandable>
</ResponseField>

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
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`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/src/timetravel.js) · [`TimeTravelOptions.ts`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/src/TimeTravelOptions.ts) · **Tests** [`timetravel.e2e.test.jsx`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/tests/timetravel.e2e.test.jsx) · **See also** [Revert](/runtime/revert), [`revertToAttempt`](#reverttoattempt)

## revertToAttempt

Restores the working copy to an attempt's JJ pointer and discards DB frames
recorded after the attempt started. Files-only: it doesn't reset nodes, cancel
attempts, or change run status, leaving the graph untouched. Use it when you
need only the filesystem state of a past attempt. Unlike `timeTravel`, both
`iteration` and `attempt` are required.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
function revertToAttempt(adapter: SmithersDb, opts: RevertOptions): Promise<RevertResult>;
```

<ParamField path="adapter" type="SmithersDb" required>
  The database adapter for the run. See [`SmithersDb`](/reference/types).
</ParamField>

<ParamField path="opts" type="RevertOptions" required>
  <Expandable title="RevertOptions">
    <ParamField path="runId" type="string" required>
      The run to revert.
    </ParamField>

    <ParamField path="nodeId" type="string" required>
      The node whose attempt is the revert target.
    </ParamField>

    <ParamField path="iteration" type="number" required>
      Loop iteration of the node. Pass `0` for non-looped nodes.
    </ParamField>

    <ParamField path="attempt" type="number" required>
      Attempt number to restore.
    </ParamField>

    <ParamField path="force" type="boolean" default="false">
      Cross unresolved external effects and mark the run for attention.
    </ParamField>

    <ParamField path="noRevert" type="boolean" default="false">
      Skip registered compensation handlers. Skipped effects require `force`.
    </ParamField>

    <ParamField path="onProgress" type="(event: SmithersEvent) => void">
      Callback for `RevertStarted` / `RevertFinished` events. See
      [`SmithersEvent`](/reference/types).
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="RevertResult" type="Promise<object>">
  <Expandable title="RevertResult">
    <ResponseField name="success" type="boolean">
      `true` once the working copy was restored. `false` if the attempt was not
      found, had no recorded pointer, or the JJ restore failed.
    </ResponseField>

    <ResponseField name="jjPointer" type="string">
      The JJ commit ID restored from. Present on success and on a failed restore
      where a pointer existed.
    </ResponseField>

    <ResponseField name="error" type="string">
      Failure reason. Present only when `success` is `false`.
    </ResponseField>

    <ResponseField name="effectBoundary" type="EffectBoundaryReport">
      Unconditional report with `blocking`, `revertible`, and `warnings`
      arrays.
    </ResponseField>
  </Expandable>
</ResponseField>

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const result = await revertToAttempt(adapter, {
  runId: "RUN_ID",
  nodeId: "NODE_ID",
  attempt: 2,
  iteration: 0,
});

if (!result.success) throw new Error(result.error);
```

<Note>
  Both `revertToAttempt` and `timeTravel` need JJ on `PATH` and a JJ-initialized
  workspace; the target attempt must have completed while JJ was available
  (otherwise no pointer was captured). See [Revert](/runtime/revert) for the
  requirements and the equivalent CLI command.
</Note>

## External-effect boundary

Marked tool calls and Tasks are checked before history moves. Discard
operations compensate entries with a registered handler before changing VCS
or database history. Replays and running forks never compensate the parent
run. Every result carries:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type EffectBoundaryReport = {
  blocking: CrossedEffect[];
  revertible: CrossedEffect[];
  warnings: CrossedEffect[];
};
```

The guard treats `unknown` like `succeeded`. A process may stop after an
external API accepted a request but before Smithers recorded the response.
Pass `force: true` only when double execution or external drift is acceptable.

Git commits, ref changes, worktree writes, and `git push` are exempt. GitHub
API mutations are not.

**Source** [`revert.js`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/src/revert.js) · [`RevertOptions.ts`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/src/RevertOptions.ts) · **Tests** [`revert.test.js`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/tests/revert.test.js) · **See also** [Revert](/runtime/revert), [`timeTravel`](#timetravel)

## CLI surface

<Note>
  The richer time-travel surface (fork, replay, rewind, snapshots, and timeline)
  is driven through the CLI and the rewind RPC, not facade exports. Use those
  instead of importing non-exported functions from the package.

  * [CLI overview](/cli/overview) for `fork`, `replay`, `rewind`, `snapshots`, and `timeline`. See [Time-travel commands compared](/cli/overview#time-travel-commands-compared) to disambiguate `rewind`, `replay`, `timetravel`, and `revert`.
  * [Revert](/runtime/revert) for the `revert` command that mirrors `revertToAttempt`.
  * [`rewind-run` RPC](/rpc/rewind-run) to rewind a run over the gateway.
</Note>

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Browse the timeline, then rewind to a checkpoint and resume.
bunx smithers-orchestrator timeline RUN_ID
bunx smithers-orchestrator rewind RUN_ID FRAME_NO
```

**Source** [`time-travel/src`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/src) · **Tests** [`time-travel/tests`](https://github.com/smithersai/smithers/blob/main/packages/time-travel/tests) · **See also** [CLI overview](/cli/overview), [Revert](/runtime/revert), [`rewind-run` RPC](/rpc/rewind-run)
