--resume re-executes the workflow,
skipping every task whose recorded work is still valid (ADR-099).
No daemon, no run store, no new artifact β the reader of a file you
already have.
Record, then resume
release-notes.nika.yaml
--json run is a recording (Traces & replay):
cache hit line in the render, a
task_cache_hit event in the new trace, and the summary counts skipped
vs live. A resumed run never pretends work happened silently.
A trace recorded by an engine version without resume keys is not an
error:
--resume prints a notice and runs everything live.The skip rule Β· two hashes, both must match
A task skips iff the trace holds its completed record and- the task definition hashes the same (the verb body,
with:,output:,retry:/on_error:,when:,for_each:β as now written), and - the resolved inputs hash the same (what its
${{ }}references actually resolved to β upstream outputs,vars,env).
--var β the tasks
that consume it re-run, and the mismatch cascades exactly as far as the
data flows β untouched sibling branches still skip:
infer: / agent: task that matches replays its recorded output β
that is the point: crash-resume without re-spending tokens. There are no
determinism rules, no replay constraints, no workflow versioning:
durability is the engineβs problem, never yours. A task that does not
match simply re-runs live, side effects included.
--from Β· force a re-run the hashes cannot see
Some changes are invisible to hashing: a rotated secret, external state,
an infer: output you want re-rolled. --from <task_id> forces that
task and its transitive downstream to re-run even on a match β
upstream tasks still cache-hit:
--var key.
The durable human gate Β· pause and answer
Anika:prompt task blocks on a human. Under a
non-interactive surface (--json Β· CI) with no usable default:, the
run does not hang and does not fail β it pauses durably: the trace
records a workflow_paused event with the prompt payload, and the
process exits with code 4.
gated-ship.nika.yaml
the workflow_paused event (one line of the trace Β· reformatted)
--answer (repeatable):
mode:. confirm wants a boolean
(--answer approve=true / =false β a refusal is a value, and the
when: gate downstream decides what happens with it). input takes a
string, choice one of the declared choices. Like --var, the value
parses as JSON when it parses.
Resumed without an answer, a --json run pauses again β idempotent,
exit 4 every time, so a poller can retry harmlessly. Resumed
interactively (a human at the terminal), the prompt simply asks.
Exit codes
| Exit | Meaning |
|---|---|
0 | Run completed |
1 | Run executed and a task failed unrecovered |
2 | Validation findings β the file never ran |
3 | Environment error (also: unknown --var / --from key) |
4 | Paused on a human gate β resume with --resume <trace> --answer <task>=<value> |
Related
- Concepts Β· Traces: the NDJSON recorder this rides β record, replay, share.
- Concepts Β· Workflows:
--varinputs (a changed input re-runs exactly the tasks that consume it). - Guides Β· Testing: the offline golden gate for the same files.