On this page

Record the work.
Keep the reason.

Turnal is a local flight recorder for Claude Code and Codex. It captures each agent turn as an append-only event trail and a pair of hidden Git checkpoints, so you can reconstruct what happened, find the prompt behind a line, test an earlier state, or safely return to it.

Start in five minutes · Understand the model

GuaranteeWhat it means
Local recordingRecording data stays in .turnal/.
Separate historyYour workspace Git history remains independent.
Recoverable by designRollback saves the current workspace first.

Installation

Install Turnal globally with npm. The package selects a prebuilt binary for macOS, Linux, or Windows on x64 and arm64. On an unsupported platform it can fall back to a local Go build. Isolated turnal fork execution requires Linux, macOS, or Windows; elsewhere it fails closed rather than running an uncontained child.

npm install -g @aadijo/turnal

Requirements

  • Node.js 18 or newer
  • Git available on PATH
  • Go only when a prebuilt binary is unavailable

Verify the installation:

turnal version
turnal --help

Turnal preserves the installed release channel during upgrades. Use turnal upgrade --check to check without installing, or select --stable or --nightly explicitly when switching channels.


Quickstart

Initialize Turnal at the directory you consider the workspace root. The --agent all selection prepares every supported agent integration.

npm install -g @aadijo/turnal
cd path/to/your/project
turnal init --agent all
turnal status

# Use Claude Code or Codex normally, then inspect the recording.
turnal sessions
turnal log --transcript

Trust the workspace hooks before using your agent. For Codex, launch the Codex CLI in this workspace first and approve the Turnal hooks there before using Codex through another surface, such as the desktop app; those surfaces may not show the hook-trust prompt. For Claude Code, trust the workspace when prompted; no separate hook approval is needed.

  1. Initialize storage. Turnal creates or attaches .turnal/, ensures workspace Git exists by default, and adds the store to .gitignore.
  2. Install agent hooks. Existing non-Turnal hooks are preserved. Invalid supported config files are moved aside with a .backup suffix before replacement.
  3. Work normally. The provider launches as usual; Turnal records hook events and snapshots in the background.

Give the agent Turnal workflows

Turnal’s source repository includes three project-scoped skills. The npm CLI does not copy them into another repository, so place the desired folders under <project>/.agents/skills/ as part of that project’s agent setup. Compatible agents can select them from their descriptions or you can invoke them explicitly:

  • $turnal-inspect-history checks recorded work before implementation when a request may have been tried before, revisits existing code, or depends on missing prior intent. It recovers what the user asked for, what earlier agents attempted, what changed, and whether checks passed.
  • $turnal-fork-history previews fork readiness, reruns a recorded task from its historical pre-turn workspace, and compares or selects isolated attempts.
  • $turnal-restore-history resolves checkpoint arguments, previews rollback, and performs an explicitly requested restore or interrupted-rollback recovery safely.
$turnal-inspect-history Check whether this request has been tried before and recover the earlier user intent before implementing it.
$turnal-fork-history Rerun <session>:<turn> in isolation and compare the result with the existing attempts.
$turnal-restore-history Preview restoring the workspace to before <session>:<turn>; do not apply it yet.

Check health before relying on recovery. Run turnal status after setup. It validates identities, hidden Git, durable refs, configuration, hook wiring, and unfinished merge or rollback journals. A non-zero exit status means the workspace needs attention.


Mental model

Turnal separates the meaning of an agent run from the bytes in the workspace. One store contains three cooperating layers, each with a deliberately different job.

LayerPurposeDurability
Event streamsAppend-only, hash-chained JSONL records preserve prompts, replies, tools, errors, checkpoints, and adapter metadata.Durable; explains why
Hidden GitA bare repository stores byte-exact synthetic commits for pre- and post-turn workspace snapshots.Durable; preserves what
SQLite indexAn FTS5 index makes history searchable and is derived from durable logs and checkpoint refs.Disposable; accelerates queries

A session follows the provider session ID. A turn normally begins with a user prompt and becomes complete only after Turnal has both a pre checkpoint and a post checkpoint. Tool activity can start a turn when a prompt event is unavailable.

The index is a cache, not the record. Normal activity does not continuously rebuild full-text search. Run turnal reindex before searching and after recording new work. If the SQLite database is missing or damaged, rebuild it from the durable layers.


Capture boundaries

A normal turn has a before-and-after boundary. The prompt hook records context and creates the pre checkpoint; tool hooks add normalized activity; the stop hook records the result and creates the post checkpoint.

  1. Prompt: event and pre checkpoint
  2. Agent work: tools, replies, and errors
  3. Stop: event and post checkpoint

Included in snapshots

  • Regular files under the workspace root
  • Symbolic links, captured as links
  • Executable and non-executable file modes
  • Untracked files unless ignored or denied

Excluded and preserved

  • Any .git or .turnal path segment
  • Files ignored by workspace Git
  • Paths matching secrets.snapshot_deny_globs
  • Excluded files already present during restore

Turnal Git is not your project Git. Turnal works in Git and non-Git directories without initializing a project repository. Normal checkpoints and checkpoint-mode rollback do not write the project’s HEAD, index, branches, or refs. Full workspace-Git capture is a separate, opt-in mode and requires an existing Git worktree.


Agent integrations

Turnal currently supports Claude Code and Codex. Hook installation is additive: it removes or refreshes Turnal-owned commands while leaving unrelated hook commands in place.

Claude Code

Claude Code is configured in .claude/settings.json.

HookRecorded boundary
UserPromptSubmitPrompt and pre boundary
PostToolUseTool activity
StopReply and post boundary

Codex

Codex is configured in .codex/config.toml with hooks enabled.

HookRecorded boundary
SessionStartSession metadata
UserPromptSubmitPrompt and pre boundary
PostToolUseTool activity
StopReply and post boundary

Select integrations explicitly when needed:

# Configure only one adapter.
turnal init --agent claude
turnal init --agent codex

# Configure both explicitly.
turnal init --agent all

# Create storage without changing hook files.
turnal init --agent none --skip-hooks

Codex wrapper checkpoints

turnal run -- codex launches Codex with hooks enabled and adds independent wrapper-level pre/post checkpoints. If hooks emit no prompt, tool, or assistant payloads, the safety checkpoints still exist but the semantic transcript will be sparse. The wrapper currently supports Codex only.


History and turns

Start with sessions, then move from a timeline into a single turn or its exact file patch. Session listing is store-wide; history commands default to the current worktree.

turnal sessions
turnal log
turnal log --transcript --session claude-7f2a
turnal show claude-7f2a:2
turnal diff claude-7f2a:2
CommandPurpose
turnal sessionsLists provider, turn counts, activity range, latest prompt, tools, and head checkpoint for each recorded session.
turnal logBuilds the timeline from durable data by default. Use --all-worktrees for a shared-store view and --no-pager in scripts.
turnal showAccepts latest, a bare unambiguous turn number, SESSION:TURN, or SESSION:latest.
turnal diffCompares the selected turn’s pre and post hidden-Git checkpoints.

Normalized history and provider transcripts are different. --transcript on turnal log renders normalized Turnal events. turnal show --transcript can also read the provider’s own transcript from its captured path on demand. Turnal does not copy that provider transcript into its store.


Search covers normalized prompts, assistant replies, tool activity, file paths, and event text. Whitespace-separated query terms are combined with AND, so every term must match the indexed turn.

turnal reindex
turnal search "invoice duplicate"
turnal search "stripe" --session codex-b91e
turnal search "timeout" --all-worktrees --json

Search defaults to the current worktree and 20 results. Use --all-worktrees for attached or imported worktrees and --limit 0 for every result. Re-run turnal reindex whenever newer activity is absent from results.


Prompt-aware blame

Turnal replays completed checkpoint history and attributes each current line to the turn that last changed it. Rename tracking and moved-line origins preserve authorship better than a simple last-snapshot comparison.

turnal blame src/webhooks/stripe.ts
turnal blame src/webhooks/stripe.ts:24 --verbose
turnal blame src/webhooks/stripe.ts --session codex-b91e --json
  • Only complete turns with both pre and post checkpoints participate.
  • The latest completed post checkpoint is the file source; live, uncheckpointed edits are not included.
  • Binary files are not supported.
  • The optional blame cache is derived and can be rebuilt.

Rollback

Rollback changes the source workspace. Turnal first records the current workspace as a hidden safety snapshot, journals the operation, then restores the selected checkpoint. Preview target resolution and planned file changes with --dry-run.

# Undo the work performed by turn 2.
turnal rollback --to claude-7f2a:2:pre --dry-run
turnal rollback --to claude-7f2a:2:pre

# Restore the completed result of turn 2.
turnal rollback --to claude-7f2a:2:post
PhaseState restoredUse it when
:preBefore the agent workedYou want to undo the changes made during the selected turn.
:postAfter the agent finishedYou want the completed result. This is the default when the phase is omitted.

Targets can also be a chk_ checkpoint ID prefix or a hidden Git SHA prefix; prefixes must be long enough to resolve safely. For another attached worktree, add --from-worktree ID.

Excluded files survive restore. Checkpoint mode restores captured workspace files while preserving Git-ignored files, deny-glob matches, .git, and .turnal. The safety snapshot ref is printed after a successful rollback and in recovery-oriented errors.

Workspace-Git rollback

Enable git_sync.enabled before the turn when you need to capture and later restore project Git state: HEAD, index, staged and unstaged patches, and non-ignored untracked files. Then pass --workspace-git, or set rollback.mode = "workspace-git". A checkpoint captured before Git sync was enabled cannot be upgraded retroactively.


Replay worktrees

Replay materializes a checkpoint in an isolated directory, leaving the source workspace untouched. Use it to inspect an old state, step through a session, run tests, or compare a checkpoint with what exists now.

turnal replay checkout claude-7f2a:2:pre
turnal replay show
turnal replay next
turnal replay diff
turnal replay diff --workspace
turnal replay keep
turnal replay stop

A managed replay lives under .turnal/tmp/replay/worktrees. By default, turnal replay stop removes it. Run turnal replay keep first to preserve that directory, or provide an empty destination path to copy the current replay state elsewhere. A range such as SESSION:2..6 constrains navigation.

Replay navigation commands are prev, next, goto, show, diff, list, keep, stop, and remove.


Verification

turnal verify runs repository-defined checks against the live workspace or an isolated historical checkpoint. Historical verification materializes the captured state in a temporary worktree, runs the same commands there, and leaves the source workspace untouched.

[[verify]]
name = "unit-tests"
command = "go"
args = ["test", "./..."]
timeout = "2m"

[[verify]]
name = "race-detector"
command = "go"
args = ["test", "-race", "./..."]
timeout = "5m"
# Check the current workspace.
turnal verify

# Check the exact captured state after turn 4.
turnal verify claude-7f2a:4:post

Verifier definitions must come from the workspace .turnal/config.toml; user-level configuration cannot silently add repository commands. Historical files are fixed by the checkpoint, but commands still use the current machine’s toolchain, credentials, network, and external services. Human output summarizes every check, while --json emits the complete versioned report. A completed verification with failed checks exits with status 3.


Reproducibility and cases

Before attempting to rerun old work, turnal fork --dry-run reports what Turnal can reconstruct and what still depends on live context. The report covers the pre-turn workspace, instruction, recorded model and permissions, conversation context, toolchain, secrets, network, and configured evaluators.

turnal fork claude-7f2a:4 --dry-run
turnal fork claude-7f2a:4 --dry-run --json

The preflight is read-only and does not claim that a recorded turn is deterministic. When the report has a usable base, execute a supervised attempt by putting the runner after --:

# Reuse the captured instruction with Codex.
turnal fork claude-7f2a:4 -- codex exec

# Or use any runner; Turnal exports TURNAL_FORK_* provenance variables.
turnal fork claude-7f2a:4 -- sh -c 'my-runner "$TURNAL_FORK_INSTRUCTION"'

Turnal creates or reuses a Case, materializes its pre-turn checkpoint into an owner-only temporary directory, and runs the child there. The source workspace is never the child’s working directory, .git/ and .turnal/ are excluded, and inherited GIT_* variables are removed. The wrapper records pre/post checkpoints, command status, and results from the verifier contract frozen into the Case. The directory is removed by default; --keep preserves it.

Fork execution is supported on Linux, macOS, and Windows. Other source-build targets can inspect readiness with --dry-run, but execution fails before starting the requested command when whole-process-tree containment is unavailable.

Experimental cases turn that readiness report into an immutable record. A case preserves the source turn, task revision, starting checkpoint, repository verifier contract, known limitations, and links to any existing wrapper attempts associated with the source turn.

# The first case creates its task identity.
turnal case create claude-7f2a:4

# Inspect the immutable case or its evolving task identity.
turnal case show case_...
turnal task show task_...

# Create a sibling case when the recorded instruction matches the task revision.
turnal case create codex-b91e:2 --task task_...

Compare completed attempts against their common immutable base, select one, and apply it only when the live workspace still matches that base:

turnal compare case_...
turnal compare case_... --patch attempt_...
turnal select case_... attempt_...
turnal apply case_... --dry-run
turnal apply case_...

Apply is exact-base only and does not attempt a three-way merge. A real apply uses the journaled rollback engine, captures a safety checkpoint before changing files, restores the selected attempt’s post-checkpoint, and records the application on the Case.


VS Code

The first-party VS Code extension keeps Turnal’s durable CLI model visible in the editor. It adds prompt-aware inline blame for the current line, session and recent-activity views, native single- and multi-file turn diffs, readable turn details, and rollback previews in VS Code’s Changes editor.

Editor rollback always performs a fresh dry run, warns about affected unsaved editors, and asks for confirmation before changing the workspace. It uses checkpoint mode and never moves the project’s Git HEAD or index. Recording, verification, replay, search, retention, and configuration remain CLI workflows.

Install the extension from the Visual Studio Marketplace.


Git worktrees

Linked Git worktrees can share the primary worktree’s physical .turnal store. Turnal records a distinct worktree identity on every stream and uses a user-state registry to find the shared store again.

# Usually discovery is automatic from a linked worktree.
turnal init

# Attach explicitly when discovery is unavailable.
turnal worktree attach --store /path/to/primary/.turnal
turnal worktree list
turnal worktree repair

The registry lives under TURNAL_STATE_DIR when set; otherwise Turnal uses the platform state directory, with XDG_STATE_HOME on XDG systems. History, search, and rollback remain current-worktree scoped unless you opt into their cross-worktree flags.

Copied stores need new identities. If you copy .turnal rather than attaching the same physical store, run turnal store rekey --confirm on the copy. This creates new store, worktree, and producer IDs; existing event records and commits are intentionally not rewritten.


Merge stores

turnal merge imports immutable event streams and private checkpoint refs from another store or a workspace containing one. The destination keeps a manifest of imported material and rebuilds its search index after a successful durable import.

turnal merge /path/to/other/workspace --dry-run
turnal merge /path/to/other/workspace

# Resume or discard an interrupted import.
turnal merge --recover
turnal merge --abort
  • Source and destination cannot have the same store ID.
  • Hidden-Git object formats must match.
  • Divergent immutable streams are rejected instead of silently reconciled.
  • A different repository ID requires --adopt-source-as-current-repo and should only be used for the same logical project.

Index failure does not erase a successful import. Imported event logs and refs are durable before reindexing. If the automatic index rebuild warns or fails, repair the cause and run turnal reindex manually.


Configuration

Configuration is layered from broad defaults to workspace-specific behavior. Later sources override earlier ones:

  1. Built-in defaults: safe, zero-config baseline
  2. User config: platform user config directory, or TURNAL_CONFIG
  3. Workspace config: .turnal/config.toml in the physical store
  4. Environment: TURNAL_HOOK_COMMAND overrides the hook command
  5. CLI flags: command-specific, highest precedence
version = 1

[init]
agent = "auto"
install_hooks = true

[run]
install_hooks = true
quiet = false
bypass_hook_trust = false

[hooks]
command = "turnal"

[bootstrap]
update_gitignore = true

[git_sync]
enabled = false

[rollback]
mode = "checkpoint"

[secrets]
store_prompts = true
store_tool_io = true
snapshot_deny_globs = [
  ".env",
  ".env.*",
  "**/.env",
  "**/.env.*",
  "**/credentials.*",
]

Configuration keys

KeyTypeDefaultDescription
versioninteger1Configuration schema version. Only version 1 is accepted.
init.agentenum"auto"Hook target: auto, claude, codex, all, or none.
init.install_hooksbooleantrueInstall or refresh agent hooks during turnal init.
run.install_hooksbooleantrueRefresh Codex hooks before turnal run launches Codex.
run.quietbooleanfalseSuppress Turnal wrapper status messages.
run.bypass_hook_trustbooleanfalsePass Codex the dangerous hook-trust bypass flag.
hooks.commandstring"turnal"Executable prefix written into Claude Code and Codex hooks.
bootstrap.update_gitignorebooleantrueEnsure .turnal/ appears in the workspace .gitignore.
git_sync.enabledbooleanfalseCapture HEAD, index, tracked patches, and untracked files alongside future checkpoints.
rollback.modeenum"checkpoint"Default rollback engine: checkpoint or workspace-git.
secrets.store_promptsbooleantrueStore normalized prompt and assistant text in Turnal logs.
secrets.store_tool_iobooleantrueStore tool inputs and outputs in Turnal logs.
secrets.snapshot_deny_globsstring arrayDefault secret globsPaths excluded from new snapshots and protected during restore.

Environment variables

VariablePurpose
TURNAL_CONFIGUse this config path instead of the OS user config path.
TURNAL_HOOK_COMMANDOverride hooks.command after file configuration is loaded.
TURNAL_STATE_DIRAbsolute directory for the cross-worktree store registry.
XDG_STATE_HOMEBase state directory when TURNAL_STATE_DIR is unset on XDG systems.
TURNAL_NO_UPDATE_CHECKDisable interactive npm update notices when set to a truthy value.
TURNAL_NPM_CACHEOverride the fallback binary cache used by the npm launcher.
PAGERPager for long turnal log output. Set it to cat or pass --no-pager to disable paging.
CLAUDE_CONFIG_DIRAllowed Claude transcript root used by turnal show --transcript.
CODEX_HOMEAllowed Codex transcript root used by turnal show --transcript.

Privacy and storage

Turnal does not upload recording data. Event logs, snapshots, and the search index stay in the local Turnal store. The npm launcher may contact npm for an interactive update notice unless TURNAL_NO_UPDATE_CHECK is set.

LayerContainsPolicy
Event streamsNormalized semantic events and raw adapter referencesDurable and hash-chained
Hidden GitCheckpoint commits and safety refsDurable and local
SQLiteFTS search and derived metadataDisposable and rebuildable
Provider transcriptClaude Code or Codex-owned conversation fileRead on demand and not copied

Recording policy

Prompts and tool I/O are stored by default. Set secrets.store_prompts = false or secrets.store_tool_io = false to redact those fields from new normalized events and structured raw hook payloads. This setting does not modify transcript files written by the provider itself.

Malformed raw payloads cannot be structurally redacted. When an adapter provides a non-JSON raw hook payload, Turnal preserves the opaque raw record because it cannot reliably identify individual prompt or tool fields inside it. Treat access to .turnal as access to development history, and set recording policy before starting sensitive work.

Snapshot deny globs

The default deny list excludes common environment and credential files. Add project-specific secrets before recording. Denied paths are excluded from new checkpoints and protected from deletion or replacement during checkpoint restore.

[secrets]
snapshot_deny_globs = [
  ".env",
  ".env.*",
  "**/.env",
  "**/.env.*",
  "**/credentials.*",
  "**/*.pem",
]

Transcript reads are limited to recognized Claude Code or Codex roots, such as CLAUDE_CONFIG_DIR and CODEX_HOME. They reject .git paths and enforce a 64 MiB file-size limit.


Retention and removal

Durable history and hidden-Git object bytes are removed in deliberate stages. Preview each stage before committing to it.

  1. Drop a session: turnal session drop ID --dry-run deletes its event log, stream metadata, temporary state, and related private refs.
  2. Prune refs: turnal retention prune --dry-run removes private refs no durable record, journal, active turn, or import manifest still needs.
  3. Collect objects: turnal maintenance gc --dry-run previews expiration of hidden reflogs and pruning of unreachable Git objects.

Garbage collection is the irreversible step. Dropping a session or pruning a ref does not immediately erase underlying Git objects. turnal maintenance gc performs immediate object pruning. Review the earlier dry runs and keep an external backup when the history may still matter.

Remove Turnal from a workspace

turnal destroy --dry-run --remove-hooks --agent all
turnal destroy --remove-hooks --agent all

Destroy removes Turnal metadata and, when requested, Turnal-owned agent hook commands. It does not delete workspace source files. Always inspect --dry-run first.


Command reference

These are Turnal’s primary public commands. Hook, checkpoint, and turn-plumbing commands are internal and intentionally omitted.

turnal init

Create or attach the Turnal store for the current directory and configure agent hooks.

turnal init [--agent auto|claude|codex|all|none] [--skip-hooks]
            [--git-sync] [--store PATH]
FlagDescription
--agent VALUESelect auto, claude, codex, all, or none. Default: auto.
--skip-hooksInitialize storage without changing agent hook configuration.
--git-syncCapture workspace Git state for future workspace-git rollbacks.
--store PATHUse or create an explicit physical .turnal store.

Run this from the directory that should become the workspace root. By default Turnal ensures workspace Git exists, adds .turnal/ to .gitignore, and installs detected hooks.

turnal status

Inspect storage, identities, hidden Git, hook health, integrity, and pending journals.

turnal status

Returns a non-zero status when the workspace needs attention.

turnal sessions

List recorded sessions, adapters, turn counts, activity, latest prompt, and head checkpoint.

turnal sessions [--json]

--json emits structured JSON instead of formatted text.

turnal log

Render checkpoint history across one or more agent sessions.

turnal log [--session ID] [--limit N] [--transcript] [--verbose]
           [--worktree ID | --all-worktrees] [--stream ID]
           [--index | --durable] [--no-pager]
FlagDescription
--session IDRestrict output to one provider session.
-n, --limit NMaximum turns per session; 0 shows all. Default: 0.
--transcriptShow normalized human, agent, and tool-call text.
--verboseShow full refs, checkpoint IDs, event counts, and per-file statistics.
--worktree IDSelect one attached worktree; current is the default.
--all-worktreesShow every attached worktree in the store.
--stream IDSelect one durable event stream.
--indexRead the disposable index when available; falls back to durable data.
--durableExplicitly read event logs and checkpoint refs, which is the default path.
--no-pagerWrite directly even when the output is taller than the terminal.

The alias turnal graph is equivalent to turnal log.

turnal show

Show normalized events and checkpoint metadata for one turn.

turnal show [latest|TURN|SESSION:TURN|SESSION:latest]
            [--raw] [--transcript] [--full] [--json]
FlagDescription
--rawInclude referenced raw adapter hook records.
--transcriptRead matching text from the provider transcript path.
--fullEnable both --raw and --transcript.
--jsonEmit the complete structured turn object.

No target means latest. A bare turn number works only when it is unambiguous across sessions in the current worktree.

turnal diff

Print the patch between the pre and post checkpoints of one turn.

turnal diff SESSION:TURN

Diffs come from hidden Git snapshots, not provider-reported file changes.

turnal blame

Attribute lines to the completed turn and prompt that last changed them.

turnal blame PATH[:LINE] [--session ID] [--verbose] [--json]
FlagDescription
--session IDRestrict replay history and the latest checkpoint to one session.
--verboseInclude prompt, tools, checkpoint ID, and origin metadata.
--jsonEmit structured blame results.

Only completed pre/post turn pairs participate. Uncheckpointed workspace edits are not considered, and binary files are not supported.

turnal reindex

Rebuild the disposable SQLite index from event logs and checkpoint refs.

turnal reindex [--quiet]

--quiet suppresses the rebuild summary.

Search indexed prompts, replies, tools, paths, and normalized event text.

turnal search QUERY [--session ID] [--all-worktrees]
              [-n N] [--json]
FlagDescription
--session IDRestrict results to one session.
--all-worktreesSearch attached and imported worktrees instead of only the current one.
-n, --limit NMaximum results; 0 shows all. Default: 20.
--jsonEmit structured ranked results.

Run turnal reindex after new activity. Every whitespace-separated query term must match.

turnal rollback

Restore the source workspace to a selected checkpoint with a safety snapshot.

turnal rollback --to SESSION:TURN[:pre|post] [--dry-run]
                [--workspace-git] [--from-worktree ID]
FlagDescription
--to TARGETSelect a turn checkpoint, chk_ checkpoint ID, or Git SHA prefix.
--dry-runResolve the target and print planned changes without writing.
--workspace-gitRestore captured HEAD, index, tracked changes, and untracked files.
--from-worktree IDSelect a cross-worktree checkpoint when the target is elsewhere or ambiguous.

Omitting the phase selects post. Use :pre to return to the state before that turn. Workspace-Git mode requires git_sync.enabled during the target capture.

turnal replay

Materialize checkpoints in an isolated directory without changing the source workspace.

turnal replay checkout SESSION[:TURN[:pre|post]] [--path PATH]
turnal replay checkout SESSION:START..END
turnal replay next | prev | goto TARGET | diff | show | keep | stop | list
Flag or commandDescription
--path PATHChoose the replay directory instead of the managed default.
--worktree PATHAlias for --path; the two flags cannot be combined.
replay diff --nextCompare the current checkpoint with the next checkpoint.
replay diff --workspaceCompare the current checkpoint with the live source workspace.
replay keep [PATH]Keep the managed replay directory or copy the current state to an empty path.
`replay remove [IDPATH]`

Stopping removes the managed directory unless turnal replay keep marked it to be preserved.

turnal save

Create an explicit checkpoint of the current captured workspace without committing to the project’s Git history.

turnal save [MESSAGE] [--json]

The optional message is descriptive metadata. The command prints the hidden Git commit that can be passed to turnal rollback --to. Manual saves do not contain workspace-Git sync state, so they always use checkpoint-mode rollback.

turnal verify

Run the repository verifier contract against the live workspace or an isolated historical checkpoint.

turnal verify [SESSION:TURN:pre|post] [--json]

With no target, checks run in the live workspace. Historical verification requires an explicit phase and never changes the source workspace. Failed checks exit with status 3; launch or infrastructure errors remain distinct in the report.

turnal fork

Inspect fork readiness or execute a supervised command from the historical pre-turn workspace.

turnal fork SESSION:TURN --dry-run [--json]
turnal fork SESSION:TURN|CASE_ID [--keep] [--no-replay-instruction]
            [--json] -- COMMAND [ARGS...]

--dry-run is read-only and distinguishes exact captured state from missing, live, or reauthorization-dependent context. Execution creates or reuses a Case, runs outside the source workspace, records a durable Attempt, and removes its temporary directory unless --keep is set. Bare codex and codex exec commands receive the captured instruction automatically; explicit command arguments are preserved.

turnal compare, turnal select, and turnal apply

Review attempts against their common Case base, record the chosen result, and restore it safely.

turnal compare CASE_ID [--patch ATTEMPT_ID] [--json]
turnal select CASE_ID ATTEMPT_ID [--json]
turnal apply CASE_ID [--attempt ATTEMPT_ID] [--dry-run] [--json]

Comparison reports command status, the frozen verifier outcome, aggregate additions and deletions, and per-file stats; --patch includes one full base-to-result patch. Selection is append-only and may be changed without altering attempts. Apply requires the live captured surface to equal the Case base, previews the restore with --dry-run, and creates a rollback safety checkpoint before an actual restore. Diverged workspaces are rejected because three-way application is not implemented.

turnal case and turnal task

Create and inspect experimental immutable cases derived from recorded turns.

turnal case create SESSION:TURN [--task TASK_ID] [--json]
turnal case show CASE_ID [--json]
turnal task show TASK_ID [--json]

Creating a case without --task creates a task identity and its initial revision. --task creates a sibling case only when the recorded instruction matches the task’s applicable revision. case show includes linked attempt status, verifier outcome, and the current selection; turnal fork is the command that launches the isolated runner.

turnal recovery

Inspect or resolve a rollback that was interrupted after its journal was written.

turnal recovery status
turnal recovery resume --yes
turnal recovery restore-safety --yes

resume reapplies the recorded target and finalizes the rollback. restore-safety abandons that target and restores the safety checkpoint captured before rollback began.

turnal run

Wrap a Codex process with independent pre/post safety checkpoints.

turnal run [--quiet] [--skip-hook-install]
           [--bypass-hook-trust] -- codex [CODEX_ARGS...]
FlagDescription
--quietSuppress wrapper status messages.
--skip-hook-installDo not update .codex/config.toml before launch.
--bypass-hook-trustPass --dangerously-bypass-hook-trust to Codex for this invocation.

The wrapper currently supports Codex only. Wrapper checkpoints still exist if hooks emit no prompt, tool, or assistant payloads.

turnal worktree

Inspect and repair the Git worktrees attached to one physical Turnal store.

turnal worktree list
turnal worktree attach --store PATH_TO_DOT_TURNAL
turnal worktree repair

list marks the current worktree and identifies the primary worktree. repair refreshes the worktree binding and user-state registry.

turnal merge

Import immutable event streams and private refs from another Turnal store.

turnal merge PATH [--dry-run] [--adopt-source-as-current-repo]
turnal merge --recover
turnal merge --abort
FlagDescription
--dry-runValidate and report the import without changing the destination.
--adopt-source-as-current-repoAssert that a differing repo ID represents the same logical project.
--recoverResume the single pending import journal.
--abortRemove staging data for the single pending import journal.

A successful merge rebuilds the destination index. Durable history remains imported if that rebuild fails.

turnal session drop

Delete one session event log, stream metadata, temporary state, and related private refs.

turnal session drop SESSION [--dry-run]

--dry-run reports the refs and files that would be deleted. Run turnal reindex afterward; object bytes remain until hidden Git garbage collection.

turnal retention prune

Delete private refs that no durable event, journal, active turn, or import manifest references.

turnal retention prune [--dry-run]

--dry-run lists the count without deleting refs.

turnal maintenance gc

Expire hidden-Git reflogs and immediately prune unreachable objects.

turnal maintenance gc [--dry-run]

--dry-run prints the garbage-collection policy without invoking Git. Run this only after reviewing session-drop and retention-prune results.

turnal store rekey

Give a copied .turnal store new store, worktree, and producer identities.

turnal store rekey --confirm

--confirm is required acknowledgement that this is a copied store. Existing events and checkpoint commits are not rewritten.

turnal destroy

Remove Turnal metadata and optionally uninstall Turnal-owned hook commands.

turnal destroy [--dry-run] [--remove-hooks]
               [--agent auto|claude|codex|all|none]
FlagDescription
--dry-runShow metadata and hook changes without deleting them.
--remove-hooksRemove Turnal commands from supported agent hook configs.
--agent VALUELimit hook removal to selected adapters. Default: auto.

Workspace source files are not deleted. Start with --dry-run.

turnal version

Print version, release channel, build commit, and install source.

turnal version [--json]

--json emits structured build metadata.

turnal upgrade

Check or install the newest release while preserving the current channel by default.

turnal upgrade [--check [--exit-code]] [--dry-run] [--json]
               [--stable | --nightly] [--yes]
FlagDescription
--checkCheck availability without installing.
--exit-codeWith --check, exit 3 when an update is available.
--dry-runShow the selected target and action without installing.
--stable, --nightlySwitch release channel.
--yesConfirm a channel switch or downgrade non-interactively.
--jsonEmit the upgrade plan as JSON.

The alias turnal update is equivalent to turnal upgrade.

turnal completion

Generate shell completion scripts.

turnal completion bash|zsh|fish|powershell

Troubleshooting

Run turnal status first. It is the fastest way to separate hook, store, identity, integrity, and unfinished-operation failures.

Search says the index is missing, or recent turns are absent

Run turnal reindex from the workspace. The SQLite database is intentionally disposable and normal recording does not rebuild it after every turn.

A linked worktree cannot find its Turnal store

From the linked worktree, run turnal worktree attach --store /path/to/primary/.turnal, then turnal worktree repair and turnal status.

A turn or checkpoint target is ambiguous

Use the explicit SESSION:TURN:PHASE form. For shared stores, add --from-worktree ID. Checkpoint and SHA prefixes must uniquely identify a target.

Workspace-Git rollback is unavailable

Git sync must have been enabled when the target was captured. Enable it with turnal init --git-sync or git_sync.enabled = true for future turns; use normal checkpoint rollback for older turns.

Provider transcript text cannot be loaded

The captured file must still exist under an allowed Claude Code or Codex config root, must not traverse a .git directory, and must be no larger than 64 MiB. Normalized Turnal events remain available without it.

An interrupted merge is reported

Inspect turnal status, then choose turnal merge --recover to resume the single pending journal or turnal merge --abort to remove its staging data.

Disk use remains after dropping a session

Run turnal reindex, preview turnal retention prune --dry-run, then preview and run turnal maintenance gc only when you are ready to irreversibly prune unreachable objects.

Still stuck? Include turnal version --json and the non-sensitive parts of turnal status in a GitHub issue.