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:
- id: read_config
  invoke:
    tool: "nika:read"
    args: { path: "./config.yaml" }
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 Β· 5 categories

Extract modes

on nika:fetch

Namespace

nika:* Β· engine-native

Core (6)

The workflow-control family: speak, signal, guard, ask, finish, pause.
BuiltinWhat it does
nika:logEmit a log entry (debug/info/warn/error) to the event stream β€” human-readable diagnostic.
nika:emitEmit a custom machine event (consumed by subscribers and the journal). log is for humans, emit is for machines.
nika:assertFail the task if a CEL ${{ }} condition is false β€” the fail-fast guard (when: is the skip-guard).
nika:promptInteractive human confirm β€” blocks until answered; engines may use default in CI.
nika:doneMark the current agent: loop complete and exit β€” valid only inside an agent tool whitelist.
nika:waitTemporal pause β€” relative duration: XOR absolute until: (ISO 8601), validated at parse time.
- id: gate
  invoke:
    tool: "nika:assert"
    args:
      condition: "${{ tasks.fetch_data.output.count > 0 }}"
      message: "Expected non-empty result"

File (5)

BuiltinWhat it does
nika:readRead a file β€” returns string content.
nika:writeWrite a file β€” returns the path; binary upstream values are written as-is.
nika:editIn-place find/replace β€” returns the modified path.
nika:globGlob match β€” returns an array of paths.
nika:grepRecursive grep β€” returns an array of { path, line, match }.

Data (8)

jq is THE data language β€” map, filter, reshape, merge. The other seven cover what jq genuinely cannot do: diff, validate, delete-on-null merge, format conversion, generation, time, hashing.
BuiltinWhat it does
nika:jqRun a jq expression β€” the single transform-and-extraction language, same jq as output: bindings.
nika:json_diffJSON diff β€” returns RFC 6902 JSON Patch (jq can’t diff).
nika:validateValidate data against a JSON Schema β€” format: json | yaml, returns { valid, errors }.
nika:json_merge_patchRFC 7396 merge patch β€” null deletes a key, the semantics jq’s * merge does not provide.
nika:convertUniversal format converter β€” json Β· yaml Β· toml Β· csv, from:/to: mode args.
nika:uuidGenerate a UUID β€” v7 default (timestamped/sortable, RFC 9562) or v4.
nika:dateTimestamp arithmetic β€” op-discriminated (now/add/subtract/format/parse/diff), timezone-aware, ISO 8601 out.
nika:hashContent hashing β€” default blake3, or sha256/sha512; md5/sha1 are not supported.
# recursive deep-merge of two task outputs β€” pure jq, no extra builtin
- id: merged
  invoke:
    tool: "nika:jq"
    args:
      input: ["${{ tasks.base.output }}", "${{ tasks.overlay.output }}"]
      expression: ".[0] * .[1]"

Network (2)

BuiltinWhat it does
nika:fetchHTTP request + content extraction β€” extract modes (article, markdown, links, feed, sitemap, selector, text, metadata, jq). Fetching a URL is calling a tool, not a verb.
nika:notifySend notifications β€” channel: enum (webhook/slack/email/discord/sms), one builtin not five.
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 (1)

BuiltinWhat it does
nika:inspectWorkflow introspection β€” one builtin, four view: modes: cost (running USD by task/provider), records (full execution record), dag_info (nodes/edges/waves), threads (engine pool state, advisory).
- id: budget_check
  invoke:
    tool: "nika:inspect"
    args: { view: cost }

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 (the language envelope nika: v1 is frozen).

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.