Skip to main content
A workflow’s permits: block lists what it may read, write, run and reach. It is default-deny engine policy: nothing in the SDK grants more, and the engine refuses a task that reaches past the boundary before anything starts.

A refused run

list-notes.nika runs ls but declares permits: {}, zero authority:
list-notes.nika
permits.mts
The finding names the repair. Replace permits: {} with exactly that grant, and the same calls succeed:
./node_modules/.bin/nika check list-notes.nika --infer-permits drafts the tightest block for a file. An absent permits: block is refused the same way (NIKA-AUTH-006): zero authority, with no boundary to judge against.

Read the boundary before you run

A local check() report carries the boundary the engine judged, so your application can apply its own policy before admitting a workflow, for example a reviewed allowlist of programs:
A report describes the bytes the engine read at that moment; run() re-admits the file’s current content. If the file can change between the two calls, gate its integrity, or capture a snapshot first. The SDK types these fields as unknown: narrow them as above.

What the engine enforces at run time

The check judges literal arguments. At run time the engine re-judges what the check could not know (computed paths, resolved programs, symlinks) and confines exec: children in the OS sandbox (Seatbelt on macOS, bubblewrap on Linux). A run that reaches past the boundary then fails with NIKA-SEC-004 as result data. Security describes every law, including the ones no permits: entry can open.

Security model

Permits, taint, the order law and the lethal trifecta.

Security boundary

The SDK’s own seams: argv, tokens, secrets.