The pattern
A run deserves two documents, one on each side of the execution:1
Before — a reviewable contract
A static, diffable statement of what the run would do: the task
graph and its order, which models and secrets it needs, what it may
read, write and reach on the network, and an honest cost bound —
a ceiling when priceable, an explicit unknown when not (never a
silent
$0). A human can approve it in review; a machine can gate
on it in CI. Nothing has executed yet.2
During — bounded execution
The runtime enforces the contract instead of trusting the prose:
effects outside the declared boundary fail, spend past the bound
stops the run. The contract is load-bearing, not documentation.
3
After — a verifiable record
An append-only journal of what actually happened: every task’s
settle, output digest, spend and timing, each entry carrying a hash
of the previous one. Anyone holding the file can recompute the chain
and detect tampering — trust lives in the artifact, not in whoever
hands it over.
What a receipt answers
The minimal shape
Nothing about the record requires a platform. Newline-delimited JSON, one event per line, each line carrying the hash of the line before it:Nika as one implementation
Nika ships the pattern end to end, which is why this page lives here — but each half maps to a plain command you can inspect:- The contract is
nika check: the static audit that prints the plan, the cost bound, the secret flows and the permits boundary before a single token is spent, and exits non-zero when the file breaks its own contract. - The record is the flight recorder: every run
journals to
.nika/traces/as hash-chained NDJSON, and the run prints its chain head on close. - The re-proof is
nika trace verify— it recomputes the chain and either confirms the head or names the first altered link (the full trace verb family is in the CLI reference). It never starts a run and never proves the business result was correct. - The exit is
nika trace export: the journal projects to OTLP/JSON for Jaeger, Grafana or Langfuse — the receipt is portable, not a lock-in surface.
@supernovae-st/nika@0.120.2), the same split is
check() (the contract), run() then run.result() (execution), and
traceVerify() (the re-proof of existing evidence). A succeeded run
can still be unsealed on a keyless machine.
In CI, the same split powers Nika × GitHub Actions:
pull requests get the contract as a sticky comment, and nothing executes.