Skip to main content
run.result() resolves once, with the engine’s account of how an admitted run ended. An admitted failure resolves: it does not throw. Read the status before you trust the outputs.
results.mts
With the quickstart’s hello.nika and a failing.nika whose only task is a failing assertion:
A try { await run.result() } catch {} alone never catches a failed workflow. A CI job or an app must read result.status, or call isNikaRunSucceeded(result), and treat anything but succeeded as its own failure. Otherwise a red run passes silently.

Statuses

isNikaRunSucceeded(result) is true only for succeeded. exitCode is the engine process’s exit code and exists only on the local transport; over HTTP read status. Statuses stay open to future engine words: keep a default branch.

Typed outputs

run<Outputs>() types result.outputs at compile time:
The generic validates nothing at runtime, and outputs stays optional even on success. The workflow’s outputs: block exports values; it does not validate them. Shape enforcement comes from infer.schema: (checked when the model answers) or a validator task such as nika:validate. A run that failed, or stopped on its budget (NIKA-1704), resolves no outputs.

The settlement

result.settlement is the engine’s own record of the ending, built once, never derived from an exit code: result.receipt points at the run’s record for verification. Over HTTP, result.evidence would report a journal mirror the server lost; no released engine writes it yet.

Rejections are not results

run.result() rejects only for transport, protocol, configuration and compatibility problems, or a lost observation (NikaObservationInterrupted). None of those says the run failed: it may still be running. The errors page lists the three channels.

Events

Follow a run while it runs.

Errors

What throws, what resolves.

Receipts

Verify the record behind a result.

Spend caps

How maxCostUsd refuses or stops a run.