> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nika.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# YAML syntax reference

> Full .nika.yaml schema. Every field, type, and validation rule.

<Warning>
  The machine-readable schema is at
  [https://nika.sh/schema/workflow.json](https://nika.sh/schema/workflow.json).
  Point your editor at it for live validation — see [editor setup](/getting-started/editors).
</Warning>

## Top level

```yaml the envelope · a skeleton, not a runnable file theme={"system"}
nika: v1                     # required · language + contract version (single marker)
workflow: <identifier>       # required · kebab-case · unique within file
description: <string>        # optional · human-readable

model: <provider>/<name>     # optional · default model for infer/agent tasks

vars: { ... }                # optional · inputs (typed or untyped) · ${{ vars.* }}
env: { ... }                 # optional · non-sensitive config · ${{ env.* }}
secrets: { ... }             # optional · vault/env/file references · ${{ secrets.* }}

tasks: [ ... ]               # required · non-empty

outputs: { ... }             # optional · the workflow's return value
```

## A task

```yaml theme={"system"}
- id: <identifier>           # required, unique within workflow (snake_case)

  depends_on: [<id>, ...]    # optional DAG edge
  when: <expression>         # optional gate · ${{ }} CEL boolean OR literal true/false
  for_each: <expression>     # optional fan-out (an array)
  max_parallel: <int>        # optional · cap concurrent iterations
  fail_fast: <bool>          # optional · default true · false = collect errors
  timeout: "<duration>"      # optional · quoted Go-duration · per-iteration on for_each
  retry: { ... }             # optional retry policy (max_attempts · backoff · on_codes)
  on_error: { ... }          # optional recovery · recover/skip/fail_workflow + on_codes
  with: { ... }              # optional task-scoped variables
  output: { <name>: <jq> }   # optional named jq bindings over the raw output
  on_finally: [ ... ]        # optional cleanup steps · run if the task STARTED

  # exactly one verb block:
  infer: { ... }
  exec: { ... }
  invoke: { ... }
  agent: { ... }
```

The full per-field semantics live in the spec:
[03 · DAG shape](https://github.com/supernovae-st/nika-spec/blob/main/spec/03-dag.md).

## Verbs

See individual pages:

* [`infer`](/concepts/verbs#infer) — LLM call
* [`exec`](/concepts/verbs#exec) — shell commands
* [`invoke`](/concepts/verbs#invoke) — built-in or MCP tool (HTTP fetch is `invoke: nika:fetch`)
* [`agent`](/concepts/verbs#agent) — tool-calling loop

## Full schema

The canonical JSON Schema is at
[https://nika.sh/schema/workflow.json](https://nika.sh/schema/workflow.json).
It's 100% machine-authoritative. This doc is a readable summary.

## Contract version policy

`nika: v1` is a **single version marker** — `v1` is the only value for the
entire lifetime of the v1 contract. Minor additions (a new optional field, a
new builtin) are **additive** and never change it (no `@minor` bumps, no
`nika migrate` for them). A future `nika: v2` would be a deliberate
breaking-change generation with its own spec — and since the `v1` envelope
is frozen, effectively never.
