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:- One verb per task ·
infer,exec,invokeoragent. - snake_case task ids (CEL-safe) · kebab-case
workflow:. tasks.*crosses a boundary throughwith:orafter:only · the binding IS the edge, the body reads${{ with.<name> }}— the DAG has no invisible edges (NIKA-VAR-021otherwise, anddepends_on:is dead:NIKA-PARSE-024).when:is a${{ }}CEL boolean or the literaltrue/false·${{ inputs.count }}is not a condition;${{ inputs.count > 0 }}is; a bare string without${{ }}is rejected. It reads local namespaces only (the value authoritiesinputs·config·const·secrets, pluswith·item/index), post-gate; the always-pattern isafter: { x: terminal }, never awhen:trick.- The CEL function set is closed ·
size()· thehas()presence macro · thecontains/startsWith/endsWithstring tests · the?:conditional (cel-subset/0.1). Everything else — arithmetic, regex, transforms — lives in jq, not in${{ }}. nika:writeneedscontent:· a write without it writes nothing.nika:doneonly insideagent.tools· it is the loop sentinel, meaningless elsewhere.- Fan-outs get the leash ·
max_parallel+fail_fast: false+ per-iterationretry/timeout. - Native-first ·
invoke: nika:*→mcp:<server>/<tool>→exec:last. Anexec:a builtin covers earns anative-firsthint;nika check --native-strictfails on any that remain, and a survivingexec:gets an exec-ledger row (task · command · why · unlock) in the workflow header. - 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:andenv:are dead envelope fields (NIKA-VALUES-001/NIKA-VALUES-002) — classify by the role the value plays, never rename in bulk. - A body with effects carries
permits:· an absent block is zero authority, not a free pass: the check refuses withNIKA-AUTH-006before a token is spent, and the run refuses withNIKA-SEC-004. Write the block withnika 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.