Skip to main content
You ran a workflow an hour ago. It worked (or it didn’t), and now someone asks: what exactly happened? With most AI tooling the answer scrolled away. With Nika the run itself is a file: every event the engine emitted, one JSON line each, in order, with timestamps. Save it, share it, replay it. The run is evidence, not a memory. A real run, replayed: the plan lights task by task exactly as the recorded event stream says it happened.

Record a run

nika run renders a live storyboard for humans. Add --json and the same run streams machine events instead, one NDJSON line per event:
That single redirect is the whole recorder. The stream is designed for CI and agents (stdout stays pure NDJSON; nothing else is printed there), so capturing it live costs nothing. By convention, project traces live under .nika/traces/ next to the workflows they record; the CLI reads a trace from any path you give it. Since 0.94 the redirect is optional: every run writes its own journal to .nika/traces/<timestamp>-<id>.ndjson by default, and the verdict line prints the path. --resume, nika trace show|replay and the editor read it directly. Opt out per run with --no-trace-file, or globally with NIKA_NO_TRACE_FILE (nika try never journals — the mock rehearsal is not a workspace run).

The event stream

A trace is the run’s lifecycle spine. Each line is one event with a unique id, a nanosecond timestamp, a kind, and typed fields:
  • workflow_started, then one task_scheduled per task
  • task_started when a task’s dependencies clear
  • task_completed (with duration_ms), or task_failed, or task_skipped (a when: gate said no), or task_cache_hit (a resumed run reused this task’s recorded work)
  • workflow_completed, or workflow_failed, or workflow_paused (a human gate is waiting — the trace carries the prompt payload)
Here is a real capture, verbatim, from a two-task exec workflow:
The spine is not the whole vocabulary. Deeper kinds record retries (task_retrying), cancellation (task_cancelled, workflow_cancelled), money (cost_incurred), security checks (permit_checked), streaming (infer_chunk) and the agent loop (agent_tools_selected, agent_budget_checkpoint, and friends). The full event system, including the durability checkpoints that make runs resumable, is documented in Concepts · Events. Real spend also rides the spine: a priced task_completed carries a cost_usd field next to its tokensabsent for mock and local runs (unpriced is honestly absent, never a fake 0). Agent loops report the loop’s accumulated tool spend as tools_cost_usd.

Replay, never re-execute

Two commands read a trace back:
replay plays the recorded events through the same renderer that drew the original run: same storyboard, same timing, same verdict card. show skips the animation and prints the summary.
Replay = re-render, never re-execute. Replaying a trace calls no model, runs no command, touches no file. Zero tokens, zero effects. It is a projection of what already happened, safe to run on any machine, any number of times.

Tamper-evidence · every event, hash-chained

The trace is not just a log — it is a hash chain. Every event the engine emits carries a link over the one before it: task boundaries, each permit check, every tool call an agent: loop makes, the run seal at the end. Nothing the engine did is off the chain, and nothing can be edited, reordered, or dropped from the middle without breaking it.
verify walks the chain and then climbs a proof ladder, reporting the highest tier honestly attained:
  • CHAINED — the links hold; the sequence is intact.
  • SEALED — a signature over the whole chain verifies against a custody key (the run was signed).
  • ANCHORED — a detached sidecar verifies fully offline against a public transparency log entry + an RFC 3161 timestamp (nika trace anchor is the opt-in network act that mints it).
  • REPLAYED — a fresh run reproduces the recorded one.
Three refusals name themselves rather than hide in a tier: a broken chain is TAMPERED, lines appended after the seal are SEAL BURIED (forgery, never a crash), a sidecar that vouches for nothing is ANCHOR FORGED. This is the property no scrollback and no vendor dashboard gives you: the evidence proves itself, on your machine, without trusting the tool that wrote it.

Why this matters

  • The run is auditable. Which tasks ran, in what order, how long each took, what it cost, which permits were checked: it is all in the file, not in someone’s scrollback.
  • The run is verifiable. Every event is hash-chained and the whole chain verifies offline (nika trace verify) — tamper-evident by construction, not by trust.
  • The run is shareable. Attach the .ndjson to a PR or an issue. A reviewer replays it locally and sees exactly what you saw, without credentials and without re-running anything.
  • The demos are honest. The replays on nika.sh (“Press play. It really ran.”) are exactly these files: recorded runs played back through the same renderer, not screenshots and not mockups.
  • The run is resumable. The same file doubles as the checkpoint: nika run --resume <trace> skips completed work with visible cache hits and re-arms a paused human gate. See Resume a run.
  • Reference · CLI: every nika run and nika trace flag, including --json and --output json (the typed outputs: export, a different surface from the event stream).
  • Concepts · Events: the full event vocabulary and the durability model behind it.
  • Concepts · Workflows: how a file becomes the executed graph the trace records.