Skip to main content
The language stays verbs. Everything else is a tool, and the standard library ships builtins under the nika:* namespace, engine-native (no MCP round-trip, no subprocess), all invoked the same way:
The tables below name every builtin so you know what exists offline. For the argument contract of any one of them, ask your installed binary rather than a page that can drift:
Canonical source: nika-spec/stdlib/builtins-v0.1.md, the Apache-2.0 language spec. The set was curated by the Rams “less but better” sweep (ADR-086/087/088): one super-powerful builtin with mode args beats five single-purpose ones.

Overview

Builtins

tools · 6 categories

Extract modes

on nika:fetch

Namespace

nika:* · engine-native

Core (6)

The workflow-control family: speak, signal, guard, ask, finish, pause.

File (5)

Data (9)

jq is THE data language: map, filter, reshape, merge. The other eight cover what jq genuinely cannot do: diff, validate, delete-on-null merge, format conversion, generation, time, hashing, adjudication.

The decision bundle

One builtin in that table earns its own section. nika:decide is the only builtin whose semantics live outside the engine: the rubric is a portable JSON artifact you own and version, and the engine is a reference implementation of it, never its prison. Teaching shapes: nika try 14-decide-publish (offline, zero keys) and nika compile classify-and-route --json (incomplete until its questions are answered; a destination writes only when Ready).

The two args

Both args are required. A wrong arg shape is NIKA-BUILTIN-DECIDE-001, the arg plane every builtin shares. permits.tools must list nika:decide.

The bundle, as the kernel reads it

A bundle is ONE JSON document with six mandatory regions. A missing region refuses before anything is scored. The three transform kinds, exactly: A rule term and a threshold:
  • evidence must name a declared evidence_schema key, and that key must not be an identity: true key.
  • transform must name a declared transform.
  • weight_bp is an integer basis point: 8735 is 87.35%. One term contributes transform(value) * weight_bp / 10000, floor division.
  • monotonicity is increases · decreases · none (the default).
  • recommend_gte_bp is an integer basis point too, and its dimension must be a declared dimension.
The threshold ladder is read in order, and it reads intervals, never a point estimate: inf ≥ gate recommends (robust dominance) · sup < gate falls through to the next threshold · a straddle defers as incomparable with the available evidence · no threshold admitted defers. governance.never_automatic lists outcomes that may never ride out automatically. Every entry must be in the closed outcome enum (recommend · defer · human_required · opted_out · overridden), and it is applied last, over whatever outcome emerged: a bundle that lists recommend turns its own recommendations into human_required. Fixtures carry a class from a closed set: positive · negative · ambiguous · contradictory · adversarial. At least one contradictory fixture is mandatory: a bundle that cannot prove its Conflict handling is unpublishable.

What the kernel enforces

The bundle is validated in full before it scores anything, and both refusals are deterministic: same inputs, same refusal, never a partial receipt. NIKA-DECIDE-001 · the bundle breaks its own laws:
  • Fixed-point integrity. Every weight, threshold and transform bound is a real JSON integer. A float refuses, and so does 3.0, which is a float in both evaluators.
  • Closed rules. A term may only read a declared evidence_schema key, and only through a declared transform.
  • Identity counterfactual invariance. An identity: true key feeding a technical dimension refuses. The same case under a different author, tenure or tier yields the same technical decision, structurally.
  • A contradictory fixture is mandatory.
  • Declared monotonicity is property-checked, on the bundle’s own positive / negative / ambiguous fixtures: for every fixture pair that differs on exactly one monotone key, all else equal, that dimension’s score must move the declared way. It does not, and the bundle is refused at publication. The law is tested, not prose.
  • Shape laws: the six regions, the manifest strings, transform kinds in the closed set, min ≤ max, edges[n] with values[n+1] and edges sorted, fixture classes in the closed set.
NIKA-DECIDE-002 · the snapshot does not satisfy the schema:
  • an undeclared evidence key (the schema is the closed surface);
  • a value that does not fit the key’s declared type;
  • a source outside the key’s declared sources;
  • an integrity below the declared floor, on the lattice untrusted ⊑ observed ⊑ verified ⊑ authoritative.
Every item is judged, including a duplicate key, which is two claims. A missing required key is not an error: it lands in snapshot.missing and drives defer, because abstention is a safety property.
nika check does not evaluate the bundle. The bundle laws above are the kernel’s, and they fire when the task runs. A workflow carrying a bundle with no contradictory fixture, a float weight or a violated monotonicity audits clean and refuses at run time with NIKA-DECIDE-001. Prove a bundle by running it against its cases: see Testing · Proving a rule against cases.

What it does not enforce today

Stated plainly, so you do not buy a guarantee that is not there:
  • A fixture’s class is a label, not an asserted outcome. Nothing evaluates a positive fixture and checks that it recommends. Relabel a passing fixture negative and the bundle still publishes. The classes carry exactly two mechanical duties: at least one contradictory must exist, and the positive / negative / ambiguous set is the corpus the monotonicity check runs over. Everything else a class implies is yours to prove, one case file at a time.
  • manifest.digest is copied into the receipt verbatim, never recomputed and never verified against the bundle’s bytes.
  • manifest.valid_until is not read. Expiry is not enforced by the kernel.
  • governance.human_required_triggers, override and appeal are carried, not read. Only never_automatic changes an outcome today.
  • The snapshot’s observed_at, confidentiality and quality (freshness · completeness · independence_group) are carried, not scored. The ttl and the independence-group contribution cap are not applied by the kernel today.

The receipt

The success value is the whole receipt, and the explanation IS the formula:
A dimension is a vector component, never a universal scalar score. Declare change_risk and evidence_quality separately and route on each, rather than averaging them into one number nobody can appeal.

Where the lane goes

There is no lane field in the receipt: the routing decision is the outcome, and mapping an outcome to a queue is one nika:jq away.
The semantics belong to the bundle. A stdlib-Python reference interpreter (conformance/decision_core.py in the spec) is the conformance oracle: for every bundle fixture, the engine’s receipt must be byte-equal canonical JSON against it. That proof, not a claim on this page, is what makes a bundle portable.

Network (2)

Engines MUST ship SSRF defense on nika:fetch: private-network and cloud-metadata targets are rejected unless explicitly configured, and self-signed TLS is rejected by default.

Introspection (2)

Media (4)

API keys are engine-configured, never workflow args: OPENAI_API_KEY / GEMINI_API_KEY / XAI_API_KEY (or the NIKA_-prefixed variants) and the local server’s NIKA_IMAGE_LOCAL_URL (+ optional NIKA_IMAGE_LOCAL_API_KEY) are read once at the engine’s composition root. The provider endpoints are engine-fixed constants — permits.net.http does not govern them (exactly like infer:); permits.tools and permits.fs do.

Design rules the set obeys

  • One super-powerful builtin, multi-mode args: fetch+extract, jq, convert, wait, date, inspect all follow the same pattern. No per-direction or per-shape builtin slots.
  • jq subsumes: anything that is a pure JSON transform is a jq expression, not a builtin. A builtin earns its slot only by doing what jq cannot.
  • Additive forever: new builtins may join in stdlib v0.x; existing arg shapes never break (a grammar change ships with its nika check --fix migration).

See also

Full stdlib spec

Per-builtin args, error codes (NIKA-BUILTIN-*), trust classes, and what jq subsumed out of v0.1.

Verbs

How invoke: dispatches nika:* builtins vs MCP tools.

MCP catalog

External tools: the MCP server registry Nika knows by id.

Bindings

Templating that pipes output from one invoke: to the next.