Skip to content

Capabilities

Accountability

A run you can reconstruct: what it was allowed to do, what it cost, what it changed, and how to get back.

The session is a file

Every session is a .jsonl file — a header line, then one JSON line per entry, appended in order. Sessions are bucketed per working directory under ~/.arcturn/sessions/<hash>/, so resuming only ever offers you sessions from the same project root.

The structure is a tree, not a flat log: every entry carries a parentId, so appending after an older entry starts a new branch instead of overwriting what came after. Resuming from three turns ago and trying a different approach is an ordinary operation, and both branches stay walkable afterwards.

Checkpoints and /rewind

Before a write or edit touches a file for the first time in a turn, Arcturn records that file’s content — or its absence, if it did not exist yet. Snapshots are content-addressed blobs with an append-only manifest, and a snapshot failure is written to the manifest as an error record rather than blocking the call that triggered it.

/rewind picks a turn, restores the files that changed after it, and forks the conversation rather than deleting it — every branch you rewound past stays reachable by resuming its own leaf.

The limit, exactly: it covers write and edit. A shell command that mutates the tree is not checkpointed, so sed -i and rm are invisible to /rewind. The conversation side is genuinely non-destructive; the file side is a real disk mutation.

~/.arcturn/checkpoints/<sessionId>/
├── manifest.jsonl   append-only log of turn / file / error records
└── blobs/<sha256>   content-addressed file snapshots

A /rewind in an arcturn session: two files are restored to their pre-turn content and the conversation forks at turn 3, leaving both branches walkable.

Replay

arcturn replay <session> pulls the original prompts back out and re-runs them, one at a time, in order — against the same model or, with -m, another one. Progress goes to stderr and results are one JSON object per turn on stdout, carrying the prompt, final text, tool-call order and cost, so a replay pipes straight into a diff without cleanup.

Replay is live, which makes it the tool for cross-model comparison and regression testing against a real provider — not for reproducing a run byte for byte. A turn that errors is recorded and the next prompt still runs.

$ arcturn replay 019c4a2f --model openai/gpt-5.1
arcturn: replaying 6 prompts on GPT-5.1
arcturn: [1/6] rate-limit the login route
{"prompt":"rate-limit the login route","finalText":"Added a 5-req…","toolCalls":["read","edit"],"costUsd":0.0412}
arcturn: [2/6] add a test for the limiter
{"prompt":"add a test for the limiter","finalText":"Added auth.test…","toolCalls":["read","write"],"costUsd":0.0388}
arcturn: replay total $0.2317

Bisect

arcturn bisect binary-searches the same prompts for the turn where behaviour left a recorded cassette. Each probe replays against a freshly loaded copy of the cassette, so the run is hermetic: no provider, no network, and the underlying tool’s execute is never invoked at all.

A cassette is a JSONL recording of everything Arcturn does not control — LLM stream events and tool results, keyed by a content hash rather than by position. Cassettes are recorded through the SDK today; there is no CLI flag for it yet.

arcturn bisect <session> --cassette <file> [--model <id>] [--cwd <dir>]

Blame and provenance

arcturn blame <file> answers, per line, which turn wrote it and what evidence that turn was working from: files read, pages fetched, commands run — with anything that arrived from a fetch or an MCP server marked untrusted. Not who wrote a line, but which reasoning step did.

It is opt-in, because the recording costs disk: set "provenance": true in config to start capturing it.

Audit trail and cost

arcturn audit answers a different question than blame — not why a line is here, but what happened in this session and what approved it. Every completed tool call, every interactive permission decision and every hook verdict is recorded as the run happens, not reconstructed afterwards. It is off by default; enable it with "audit": true.

Cost accounting has no opt-in — it is always on, updated after every turn. /cost prints current spend; --max-cost and /cost limit set a ceiling that aborts the run the moment cumulative spend reaches it, at the next turn boundary. Sub-agent spend counts against the same ceiling, which is otherwise trivially easy to treat as free.

14:03:12  tool  bash  git status  ✓
14:03:20  perm  write  src/auth.ts  ask-allow
14:03:21  tool  write  src/auth.ts  ✓
14:03:44  perm  bash  rm -rf dist  ask-deny
14:04:02  hook  preToolUse  deny: no writes under infra/
14:04:19  tool  edit  src/auth.test.ts  ✗

4 tool calls, 1 denied, 1 hook veto

Every turn counts.

Start a session, watch every tool call ask first, then go back and read exactly what happened.

npm install -g arcturn