Skip to main content
Agents are the primary authors of Nika. The language is built so that the path carries the quality, not the model: a small closed grammar ( verbs · namespaces · one expression surface), one canonical way per intention, and a validator whose errors prescribe their own fix.

The protocol

1

Route: one intent, one template

The templates are complete, valid skeletons (conformance-gated on every push). Match the outer shape of the job:
2

Instantiate: structure is copied, never invented

Copy the template, rename the workflow, fill every # SLOT: line. Creativity belongs only in prompts, jq expressions and paths. If the job needs a construct the template lacks, the coverage matrix names the canonical example that exercises it: read it, don’t guess.
3

Check: never ship unchecked

nika check workflow.nika.yaml (engine) or python conformance/runner.py validate <file> (spec oracle). Editors get the same truth live via the JSON Schema.
4

Repair: the error names its fix

Fix exactly what the code says, nothing else, then re-check:

The hard rules

These catch ~90% of LLM-written errors. The validator enforces all of them; knowing them just saves round-trips:
  1. One verb per task · infer, exec, invoke or agent.
  2. snake_case task ids (CEL-safe) · kebab-case workflow:.
  3. tasks.* crosses a boundary through with: or after: only · the binding IS the edge, the body reads ${{ with.<name> }} — the DAG has no invisible edges (NIKA-VAR-021 otherwise, and depends_on: is dead: NIKA-PARSE-024).
  4. when: is a ${{ }} CEL boolean or the literal true/false · ${{ inputs.count }} is not a condition; ${{ inputs.count > 0 }} is; a bare string without ${{ }} is rejected. It reads local namespaces only (the value authorities inputs · config · const · secrets, plus with · item/index), post-gate; the always-pattern is after: { x: terminal }, never a when: trick.
  5. The CEL function set is closed · size() · the has() presence macro · the contains/startsWith/endsWith string tests · the ?: conditional (cel-subset/0.1). Everything else — arithmetic, regex, transforms — lives in jq, not in ${{ }}.
  6. nika:write needs content: · a write without it writes nothing.
  7. nika:done only inside agent.tools · it is the loop sentinel, meaningless elsewhere.
  8. Fan-outs get the leash · max_parallel + fail_fast: false + per-iteration retry/timeout.
  9. Native-first · invoke: nika:* → mcp:<server>/<tool> → exec: last. An exec: a builtin covers earns a native-first hint; nika check --native-strict fails on any that remain, and a surviving exec: gets an exec-ledger row (task · command · why · unlock) in the workflow header.
  10. Every value lands under one of four authorities · inputs: (the caller supplies it) · config: (the deployment supplies it) · const: (the file owns it) · secrets: (a governed store). vars: and env: are dead envelope fields (NIKA-VALUES-001 / NIKA-VALUES-002) — classify by the role the value plays, never rename in bulk.
  11. A body with effects carries permits: · an absent block is zero authority, not a free pass: the check refuses with NIKA-AUTH-006 before a token is spent, and the run refuses with NIKA-SEC-004. Write the block with nika check --infer-permits, which prints the tightest one and is paste-ready.

After valid: the judgment layer

Validity is the floor. The twelve patterns are the ceiling: deterministic core, typed boundaries, the right gate (when = skip · assert = fail · prompt = human), sovereignty for sensitive data, budgets on agents, on_finally evidence. Every pattern links the canonical example that embodies it.

The templates

The skeletons, every decision point a slot, conformance-gated.

The twelve patterns

The judgment layer: why each locked choice is locked.