Record a run
nika run renders a live storyboard for humans and writes an execution
journal by default to .nika/traces/<timestamp>-<id>.ndjson. The
verdict line prints that path — the same file
nika compile hello hello.nika then nika run hello.nika writes.
Add --json and the same run also streams machine events on stdout, one
NDJSON line per event — the CI and agent surface (stdout stays pure
NDJSON; nothing else is printed there):
--resume, nika trace show|replay|verify and the editor read the
journal directly. With no path, show, replay, and verify read the
workspace’s latest journal and name it on stderr
(nika trace: reading <path> (the workspace latest)). Pass a path to
select another; nika trace ls lists the store. 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).
A refusal before execution or a queued cancellation can leave no journal.
Interruption can leave incomplete evidence. A job or receipt identity alone
does not prove that a trace exists or is sealed; nika trace verify reads
existing evidence and never seals it.
The journal keeps task outputs verbatim so a run can be replayed and
verified. Hash-chained is not confidential: .nika/traces/ inherits the
sensitivity of whatever the workflow read, and on a shared or CI machine
that directory is a second data-at-rest surface. Treat it like the files
the run opened. A redaction posture that still verifies is a larger
conversation; this page only names the consequence.
The event stream
A trace is the run’s lifecycle spine. Each line is one event with a unique id, a nanosecond timestamp, akind, and typed fields:
workflow_started, then onetask_scheduledper tasktask_startedwhen a task’s dependencies cleartask_completed(withduration_ms), ortask_failed, ortask_skipped(awhen:gate said no), ortask_cache_hit(a resumed run reused this task’s recorded work)workflow_completed, orworkflow_failed, orworkflow_paused(a human gate is waiting — the trace carries the prompt payload)
exec workflow). The
kinds are still the spine; do not treat the timestamps or ids as current
engine output:
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 tokens — absent 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 inspect a recorded run. With no path they read the workspace’s latest journal: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. Both are a
reading of the file — they do not walk the hash chain.
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 anagent: 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.
Change one byte, and verify says where. Each line of a run’s trace carries the sha256 of the line before it. nika trace verify reads the chain back intact; in a copy with one byte of line 4 changed, it stops at line 5 with BROKEN and exit code 2. A mock/echo rehearsal captured from the real CLI; the scan and the moving hashes are illustration.
verify walks the chain and then climbs a proof ladder, reporting the
highest tier honestly attained. That is the proof, distinct from
show / replay: those inspect the recorded events; this command
attests the sequence is intact. The tiers:
- CHAINED — the links hold; the sequence is intact (
verifyprintsOK — N events · chain intactand the head to compare). - 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 anchoris the opt-in network act that mints it). - REPLAYED — you passed a separately supplied fresh journal; verify compares it. The command never starts that second run.
traceVerify / nika trace verify verifies an existing seal. It
does not create one. A succeeded run can still be UNSEALED on a keyless
machine. An intact chain is not proof that a human read the output, that
an external API committed, or that the business goal was met.
Three refusals name themselves rather than hide in a tier: a broken
chain is BROKEN at line N, the first line whose recorded link no longer
matches; a seal with lines appended after it is TAMPERED (forgery, never
a crash); a sidecar that vouches for nothing is ANCHOR FORGED.
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
.ndjsonto 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.
Related
- Reference · CLI: every
nika runandnika traceflag, including--jsonand--output json(the typedoutputs: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.