AGPL-3.0-or-later · forever.

[ INTENT AS CODE ]

Your agent writes the workflow. Nika reads it back.

The checked workflow language for AI: audited before a token is spent, every fix named (the typo, the unbounded cost, the permit wider than the code), with a verifiable receipt after every run. The runtime enforces the file as a contract: permits default-deny, the trace hash-chained, cost capped.

The checked workflow language for AI: audited before a token is spent, a receipt after every run. The file is a contract the runtime enforces.

See it runtry it in your browseror in VS Code / Cursor

v0.111.0macOS · LinuxAGPL-3.0

see it run

nika: daily-brief# local model · your notes never leavemodel: ollama/llama3.2:3b# the file IS the blast radiuspermits:  fs: { read: [ ./notes/* ], write: [ ./brief.md ] }  tools: [ "nika:read", "nika:write" ]tasks:  notes: { invoke: { tool: "nika:read", args: { path: ./notes/today.md } } }  inbox: { invoke: { tool: "nika:read", args: { path: ./notes/inbox.md } } }  calendar: { invoke: { tool: "nika:read", args: { path: ./notes/calendar.md } } }  triage:    with:      inbox: ${{ tasks.inbox.output }}    infer: { prompt: "Flag what is urgent: ${{ with.inbox }}", max_tokens: 300 }  agenda:    with:      calendar: ${{ tasks.calendar.output }}    infer: { prompt: "Plan the day around: ${{ with.calendar }}", max_tokens: 300 }  draft:    with:      notes: ${{ tasks.notes.output }}      triage: ${{ tasks.triage.output }}      agenda: ${{ tasks.agenda.output }}    infer:      prompt: "Write the morning brief. Notes: ${{ with.notes }} Urgent: ${{ with.triage }} Plan: ${{ with.agenda }}"      max_tokens: 500  save:    with:      draft: ${{ tasks.draft.output }}    invoke:      tool: "nika:write"      args: { path: ./brief.md, content: "${{ with.draft }}" }outputs:  brief: "${{ tasks.draft.output }}"
source

audited · 7 tasks · 4 waves · permits declarednika 0.111.0

nika check: audited · 7 tasks · 4 waves · permits declarednika 0.111.0

[ THE READING ]

01

The file, read back.

An agent’s draft, two keystrokes early. Step through what the checker saw before a token was spent, then the repair: applied by the engine itself, not by hand.

two keystrokes · 3 findings · zero tokens spent

error:CONFORMNIKA-DAG-002

unknown dependency: task judge depends on dif, which does not exist — did you mean diff?

begin snippet for pr-review.broken.nika.yaml at line 19, column 16

      changes: ${{ tasks.dif.output }}

helpnika explain NIKA-DAG-002

the first keystroke: a reference to a task that does not exist, and the checker names what you meant

01

Watch the file become the run.

nika: daily-brief# local model · your notes never leavemodel: ollama/llama3.2:3b# the file IS the blast radiuspermits:  fs: { read: [ ./notes/* ], write: [ ./brief.md ] }  tools: [ "nika:read", "nika:write" ]tasks:  notes: { invoke: { tool: "nika:read", args: { path: ./notes/today.md } } }  inbox: { invoke: { tool: "nika:read", args: { path: ./notes/inbox.md } } }  calendar: { invoke: { tool: "nika:read", args: { path: ./notes/calendar.md } } }  triage:    with:      inbox: ${{ tasks.inbox.output }}    infer: { prompt: "Flag what is urgent: ${{ with.inbox }}", max_tokens: 300 }  agenda:    with:      calendar: ${{ tasks.calendar.output }}    infer: { prompt: "Plan the day around: ${{ with.calendar }}", max_tokens: 300 }  draft:    with:      notes: ${{ tasks.notes.output }}      triage: ${{ tasks.triage.output }}      agenda: ${{ tasks.agenda.output }}    infer:      prompt: "Write the morning brief. Notes: ${{ with.notes }} Urgent: ${{ with.triage }} Plan: ${{ with.agenda }}"      max_tokens: 500  save:    with:      draft: ${{ tasks.draft.output }}    invoke:      tool: "nika:write"      args: { path: ./brief.md, content: "${{ with.draft }}" }outputs:  brief: "${{ tasks.draft.output }}"

audited · 7 tasks · 4 waves · permits declarednika 0.111.0

[ 01 ]run together ×3

notesinvokenika:read✓ 2ms
inboxinvokenika:read✓ 0ms
calendarinvokenika:read✓ 0ms

[ 02 ]run together ×2

triageinferollama/llama3.2:3b✓ 4.5s
agendainferollama/llama3.2:3b✓ 10.3s

[ 03 ]then

draftinferollama/llama3.2:3b✓ 6.5s

[ 04 ]then

saveinvokenika:write✓ 0ms
daily-brief.nika.yaml
nika run daily-brief.nika.yaml
workflow daily-brief
scheduled 7 tasks · notes inbox calendar triage agenda draft save
notes invoke · nika:read
notes 2ms
inbox invoke · nika:read
inbox 0ms
calendar invoke · nika:read
calendar 0ms
triage infer · ollama/llama3.2:3b
triage 4.5s · 122 tok
agenda infer · ollama/llama3.2:3b
agenda 10.3s · 300 tok
draft infer · ollama/llama3.2:3b
draft 6.5s · 315 tok
save invoke · nika:write
save 0ms
run complete · exit 0 · 16.8s
exit 07 tasks ran16.8swrote brief.md$0.00localollama/llama3.2:3b
recorded · nothing staged

recorded from a real nika run · replayed by your scroll · nothing staged

01.1

Press play. It really ran.

The same file, executed by the engine with a local model on a real machine. What you watch is the recorded event stream.

daily-brief.nika.yaml
nika run daily-brief.nika.yaml
workflow daily-brief
scheduled 7 tasks · notes inbox calendar triage agenda draft save
notes invoke · nika:read
notes 2ms
inbox invoke · nika:read
inbox 0ms
calendar invoke · nika:read
calendar 0ms
triage infer · ollama/llama3.2:3b
triage 4.5s · 122 tok
agenda infer · ollama/llama3.2:3b
agenda 10.3s · 300 tok
draft infer · ollama/llama3.2:3b
draft 6.5s · 315 tok
save invoke · nika:write
save 0ms
run complete · exit 0 · 16.8s
exit 07 tasks ran16.8swrote brief.md$0.00 · ollama/llama3.2:3b

recorded from a real nika run · replayed at reading pace · nothing staged

01.2

One file. A plan you can read.

The engine derives the order from the wiring: a with: binding is a data edge, an after: entry a control edge. Steps with no edge between them run together. Nothing runs that is not written in the file.

[ 01 ]run together ×3

notesinvokenika:read 2ms
inboxinvokenika:read 0ms
calendarinvokenika:read 0ms

[ 02 ]run together ×2

triageinferollama/llama3.2:3b 4.5s
agendainferollama/llama3.2:3b 10.3s

[ 03 ]then

draftinferollama/llama3.2:3b 6.5s

[ 04 ]then

saveinvokenika:write 0ms

durations recorded from the real run · hover a step to trace its wires

[ THE BOUNDARY ]

02

What it's allowed to touch.

The permits: block is part of the file you review. It is the whole list. Everything not on it is denied by default, before it runs. The full reference · families, secrets, the always-on floor · lives at /boundary.

daily-brief.nika.yaml · lines 6–8
permits:  fs: { read: [ ./notes/* ], write: [ ./brief.md ] }  tools: [ "nika:read", "nika:write" ]

the same file as above · the permits block, verbatim

don't write it by hand:nika check --infer-permitsprints the tightest boundary the plan needs. Paste it in, loosen it yourself, or leave it strict.

  • fs:which files it may read and write
  • tools:which tools it may call

if a step reaches outside the list, say

write ~/.ssh/config   NIKA-SEC-004

effect outside the declared permits: capability boundary. Blocked before it runs, never logged after the fact. (An example: the recorded run above stayed in bounds, exit 0.)

the written law · numbered, public, reviewable

  • NEP-0003an absent permits: block declares zero authority
  • NEP-0004untrusted values re-gate under permits, at the effect
  • NEP-0005a child’s environment is composed, never inherited
  • NEP-0006a fetch of a code-bearing artifact is never innocent
  • NEP-0007the trace carries a permit witness · check and run agree
  • NEP-0008the egress proxy is the permit’s exact projection
  • NEP-0009a path grant names a path identity, re-judged at dispatch

the full set lives in the spec’s governance register · proposals, numbered and versioned, before they bind the engine

03

Chats evaporate. Files compound. The prompts you perfect, the steps an agent improvises: gone with the session. Nika turns that work into a file: readable, versioned, runnable.

daily-brief.nika.yamlsource
nika: daily-brief# local model · your notes never leavemodel: ollama/llama3.2:3b# the file IS the blast radiuspermits:  fs: { read: [ ./notes/* ], write: [ ./brief.md ] }  tools: [ "nika:read", "nika:write" ]tasks:  notes: { invoke: { tool: "nika:read", args: { path: ./notes/today.md } } }  inbox: { invoke: { tool: "nika:read", args: { path: ./notes/inbox.md } } }  calendar: { invoke: { tool: "nika:read", args: { path: ./notes/calendar.md } } }  triage:    with:      inbox: ${{ tasks.inbox.output }}    infer: { prompt: "Flag what is urgent: ${{ with.inbox }}", max_tokens: 300 }  agenda:    with:      calendar: ${{ tasks.calendar.output }}    infer: { prompt: "Plan the day around: ${{ with.calendar }}", max_tokens: 300 }  draft:    with:      notes: ${{ tasks.notes.output }}      triage: ${{ tasks.triage.output }}      agenda: ${{ tasks.agenda.output }}    infer:      prompt: "Write the morning brief. Notes: ${{ with.notes }} Urgent: ${{ with.triage }} Plan: ${{ with.agenda }}"      max_tokens: 500  save:    with:      draft: ${{ tasks.draft.output }}    invoke:      tool: "nika:write"      args: { path: ./brief.md, content: "${{ with.draft }}" }outputs:  brief: "${{ tasks.draft.output }}"

audited · 7 tasks · 4 waves · permits declarednika 0.111.0

the session ends · the file stays

Seeing the steps is not the same as enforcing them. Here is what each black box trades away.

Chat sessions

  • Great for exploring
  • Gone when the tab closes
  • Different answer every time

A file you keep

  • Runs again tomorrow
  • Same steps, same order
  • Diff it like code

Glue scripts

  • 200 lines of Python + retries
  • One person understands it
  • Breaks when an API changes

Four verbs

  • The YAML is the logic
  • Anyone can read it
  • Engine handles retries & order

Cloud automations

  • Runs on their servers
  • Per-seat, per-run pricing
  • Your data leaves the building

Your machine

  • One binary, runs local
  • Free, AGPL forever
  • Nothing leaves unless you say so

04

The run explains itself.

One file ran once: audited before it started, storyboarded while it ran, replayable after it ended. Every frame below is real output of the real binary, captured on a terminal against committed fixtures. Offline, on the mock model, for zero dollars. How the proof works · graph, receipt, conformance · lives at /proof.

recorded from a real nika run · replayed at reading pace · nothing staged
Terminal capture of nika check on the signature workflow: the audit ladder passes with a cost floor warning and one permits hint, rc=0.
the pre-flight ladder: plan · cost · secrets · types · tools · args · schema · permits, then one hint. rc=0.

05

What an agent can do. Declared, not hidden.

Four verbs are the only native execution models. Every action explicit and typed, never improvised from a hidden prompt. Everything callable is a tool under invoke, and tools are allow-listed. Everything about ordering is the plan: which tasks wait on which. No fifth verb, ever.

5.3invoke

Use a tool. Fetch a page, write a file, call GitHub. Every tool explicit.

5.3.1 builtins5.3.2 extract modes5.3.3 MCP servers

use-a-tool.nika.yamlsource
# the invoke verb alone · one tool call under the two-part grantnika: use-a-toolpermits:  tools: ["nika:fetch"]  net: { http: ["nika.sh"] }tasks:  page:    invoke:      tool: "nika:fetch"      args: { url: "https://nika.sh" }

5.4agent

Delegate. An autonomous loop, on a leash you can read.

5.4.1 tool allow-list5.4.2 max turns5.4.3 the human gate

delegate.nika.yamlsource
# the agent verb alone · goal + tool whitelist, loop boundednika: delegatemodel: ollama/llama3.2:3bpermits:  tools: ["nika:read", "nika:fetch"]  net: { http: ["nika.sh"] }  fs:    read: ["./docs/*"]tasks:  audit:    agent:      prompt: "Find every dead link in ./docs"      tools: [ "nika:read", "nika:fetch" ]      max_tokens_total: 8192outputs:  report: ${{ tasks.audit.output }}

infer ◇ · exec ▷ · invoke ◆ · agent ✦   ·  the whole operation space, declared in one file

06

What an agent can be permitted to use.

The language stays four verbs. The standard library does the rest: 28 builtins, 17 model providers, and any of your agent tools (MCP servers) your editor already uses. All reached the same way: invoke:, and none of it runs unless the file's permits: allows it.

0128builtin tools · nothing to install
0217model providers · 5 local, 11 cloud, 1 mock
039extract modes on fetch
04MCPnativeyour agent tools (MCP) · any server, via the same verb
BuiltinsThe everyday tools. All called with invoke:.28 tools · 4 families

Files· 5

read· read a filewrite· save a fileedit· patch a fileglob· find filesgrep· search text

Data· 9

jq· transform JSONconvert· between formatsvalidate· check a schemajson_diff· what changedjson_merge_patch· merge JSONcompose· chain toolshash· fingerprint datauuid· fresh iddate· now · parse · format

Web· 1

fetch· get a page · 9 extract modes

Flow· 13

assert· check a conditiondone· end the loopwait· pauseemit· send an eventlog· say somethingnotify· ping a humanprompt· ask a humaninspect· debug a valuechart· see the docsdecide· see the docsimage_fx· see the docsimage_generate· see the docstts_generate· see the docs
ProvidersPick per task or per file. provider: ollama runs offline.17 total

Local runtimes· 5 · no cloud needed

OllamaLM Studiollama.cppLocalAIvLLM

Cloud · open-weight first· 11

MistralAnthropicOpenAIGeminiDeepSeekxAIGroqOpenRouterhuggingfacenvidiamoonshot

Test· 1

mock· deterministic · zero keys · CI-runnable
Extract modesHow fetch turns a page into typed output.9 modes
articlefeedjqlinksmarkdownmetadataselectorsitemaptext
MCPAny of your agent tools (MCP servers), reached as mcp:.native · unbounded
mcp:· the server your editor already usesstdiohttpdefault-deny· tools whitelisted in the file

every count derives from the spec's canon.yaml · never hand-typed

08

Not another agent framework. The layer underneath.

Frameworks and assistants help an agent decide and act. Nika is orthogonal: it makes what the agent does reviewable and enforceable the layer between the model wants to act and the system lets it act.

FrameworksLangGraph, n8n: they help you wire and orchestrate the steps.
Nika makes the wired steps a reviewable, enforceable file, not glue code.
AssistantsCursor, Claude Code: they help an agent decide and act in the moment.
Nika turns that intent into a plan you review and the runtime enforces.
Protocols & toolsYour agent tools (MCP servers) expose capabilities an agent can call.
Nika runs them through invoke: allow-listed, permission-bound, traced.

Run a Nika plan from any of them. It's a portable file, not a platform.

09

Real files you'd write.

Anything you'd ask an AI to do more than once belongs in a file. Every workflow below is real, projected from nika-spec, audited before it runs: plan, cost, secrets. Pick your métier, open a card, read the exact YAML that runs it.

Ship faster. Let the boring parts run themselves.

standup-digest.nika.yamlwalkthrough ↗
todayinvokenika:datehistoryexecgit
digestinfer
saveinvokenika:write
yamlsource
nika: standup-digestmodel: ollama/qwen3.5:4b   # local · zero key · swap for groq/llama-3.3-70b (a fast one-liner job)permits:  exec: ["git"]              # the ONE program this workflow may run  tools: ["nika:date", "nika:write"]  fs: { write: ["out/standup-note.md"] }tasks:  # No deps between these two → the engine runs them in parallel.  today:    invoke:      tool: "nika:date"      args: { op: now }  history:    exec:      command: ["git", "log", "--since=yesterday", "--oneline", "--no-merges"]  digest:    with:      today: ${{ tasks.today.output }}      history: ${{ tasks.history.output }}    infer:      max_tokens: 400          # a standup note is short · the ceiling says so      prompt: |        Date · ${{ with.today }}        Commits since yesterday ·        ${{ with.history }}        Write my standup note · 3 bullets · done / doing / blocked.        Plain words · no fluff. If there are no commits, say so in one line.  save:    with:      digest: ${{ tasks.digest.output }}    invoke:      tool: "nika:write"      args:        path: out/standup-note.md        create_dirs: true        content: "${{ with.digest }}"outputs:  note: ${{ tasks.digest.output }}

audited · 4 tasks · 3 waves · permits declarednika 0.111.0

Every morning: the note is already written. You glance, you tweak one word, you go.

27 workflows · four tiers · nika-spec/examples the plan, the typed answers and the tools, all checked before it runs

09

The file becomes a canvas. Open any .nika.yaml in VS Code or Cursor: prompts sit on the cards, a run lights the graph wave by wave, and every canvas edit lands back in the file. This miniature works: press ▶ mock.

release-notes.nika.yaml · canvashover a card; its lineage stays lit

$0.00 ceiling · local model · audited before it runs

release-notes.nika.yaml

nika: release-notes
model: ollama/qwen3.5:4b

tasks:
  fetch_commits:
    invoke:
      tool: "nika:fetch"
      args:
        url: "https://api.github.com/repos/acme/app/commits?since=v1.4.0"

  write_notes:
    with:
      commits: ${{ tasks.fetch_commits.output }}
    infer:
      max_tokens: 800
      prompt: "Write the release notes from ${{ with.commits }}: grouped, human, no hype."

  hero_image:
    after:
      fetch_commits: success
    invoke:
      tool: "nika:image_generate"
      args:
        provider: local
        prompt: "A minimal banner for the v1.5 release"
        aspect_ratio: "16:9"
        output_dir: "media/"

  publish:
    after:
      write_notes: success
      hero_image: success
    exec:
      command: ["gh", "release", "create", "v1.5.0", "--notes-file", "notes.md"]
  • The engine's judgment, as you type. Diagnostics, completions and hovers come from nika check and the schema: codes, fixes and positions are the binary's, not the extension's. Even this demo file passes the real nika check, exit 0.
  • Run, replay, scrub. The run streams onto the graph live; any recorded run replays with a time-travel scrubber.
  • Audited before a token is spent. Cost ceiling, permits boundary and secret flows are static facts on the cards. Read them before you press Run.

11

Shipping in the open.

A workflow language earns trust by moving, and by not breaking what you wrote. Here is the recent ship log: the spec opened, the verbs locked: and the engine shipped, one brew install away.

  1. release

    v0.111.0 · the authoring loop closes

    The checker now distinguishes a legal file from one ready to spend: paid_ready goes quiet only when no paid-run hint remains, compiled means the law was proven, and next names the first repair. nika:inspect is live from the first task and follows the run after every wave, so a workflow can read its DAG, records, spend and threads. nika:compose stays inside an agent loop after nika:done, where the model can draft, read the whole check verdict and revise without making check execute the draft. The arm lock now survives the shot, and the paid extract wave repairs structured hashing, string schemas, scalar anyOf coercion and resumed for_each item fields.

  2. release

    v0.109.2 · the nine-key envelope ships

    The envelope is nine keys: nika: is the mark and the name, never a version marker. Values come from three authorities (inputs · const · secrets). The first two 0.109 tags died at the release gates before any asset landed; this is the one a visitor can install. Linux builders now install bubblewrap so a permits: file is judged confined, the same way macOS already was.

  3. release

    v0.108.0 · the access layer

    The access layer arrives, and the check stops trusting what it cannot read. From this tag, model: picks the intelligence and access picks the path: the admission-time resolver is a pure function with a strict sovereign order (local · mock · harness · oauth · api), enumeration order can never change the outcome, and every dropped candidate carries its witness: the dimension, the layer, the teaching line. --access pins the path at the launch gates, before a token is spent: unsatisfied refuses, never substitutes. The ACP harness class lands with its mock agent in a quarantined workspace, proving the wire with no vendor in the loop. And the security fix that taught the train its lesson: a shell-string exec with no permits passed check green. The verifiable argv door refused while the unverifiable shell door stood open, the exact inversion of a security gate. The exec capability is now required whatever the spelling, and the runtime deferral owns dynamic values, never the door itself.

  4. release

    v0.107.2 · the adversarial pass

    An adversary was set on 0.107.1’s six boundaries with one instruction, break it. Three of six claims fell, and hunting what the first repairs still let through found four more · every fix proven on the binary before the code was touched, each carrying the mutation that makes it fail. Two doors were open: a permit could name a system root by shouting it (/ROOT/x* passed where /root/./x* refused: macOS folds case, so the comparison does now, and the Linux side can only ever refuse a path that does not exist), and a secret redacted in the trace was printed on stdout (outputs: rides RunOutcome past the event lane · the map is scrubbed at any depth now). Three guards judged less than they claimed: the dangerous-environment floor is proven entry by entry (forty names, both halves pinned), a tainted nika:notify target is judged whatever channel carries it, and the run guard speaks only about runs (an unreadable payload no longer blocks ls). And one law had two implementations: the MCP spawn now composes its child environment through the same function as the exec runner · the copy was equivalent, and equivalence was exactly what nothing guaranteed.

Full changelog

12

The control is the proof.

No logos to borrow, no quotes to dress up. Just what the engine guarantees: review before it acts · enforced permissions · hash-chained trace · priced before it spends · crash-resume without a server · portable off any platform: verifiable in the open spec and the one binary you install.

9.14verbs · every action explicit, declared not hidden
9.228builtin tools · allow-listed, nothing to install
9.317/5 localmodel providers · any model, cloud or fully offline
9.41Rust binary · zero daemons, zero background services
Review before it acts.
The agent writes its plan as a file first: every step, tool and permission. A human reads it before a single action runs.
Enforced permissions.
The file's permits: block is the blast radius: files, hosts, programs, tools. The runtime denies anything outside it (5 local providers mean PII never has to leave).
Replayable trace.
Every run leaves a hash-chained NDJSON trace: every task, and every agent tool call, in the same chain · nika trace verify walks it and names the first broken link. Same file, same steps, same order: run it again and diff it like code.
Portable off any platform.
One binary, 17 model providers, AGPL-3.0 forever. The file outlives the vendor. It still runs the day the company that made it is gone.
Priced before it spends.
nika check prints the plan’s cost floor before a token is spent, and --max-cost-usd is a hard ceiling: a plan whose floor exceeds it never starts.
Crash-resume without a server.
The trace a run already writes is the checkpoint · --resume is a reader of a file, not a client of a run-store: no supervisor, no database. Two hashes decide skip-or-rerun, recorded work replays instead of re-calling the model, and a cache hit is never silent.

A README is documentation. Nika is an executable contract.

every number derives from the spec's canon.yaml · verifiable, never hand-typed · every repo file declares its provenance in estate.yaml · authored or generated, hashed

13

Get started.

One binary, one file, one command. Install it, write a plan, run it, and watch it print the plan, check the permits, and stay within bounds.

  1. Install

    One Rust binary. Homebrew on macOS, or the install script anywhere.

    brew install supernovae-st/tap/nika
    curl -LsSf https://nika.sh/install.sh | sh

    Installed? See a workflow work before anything else · offline, zero keys, nothing written:

    nika try 01-hello
  2. Write a file

    A plan is plain YAML: the steps, the verbs, the wiring. This is the same file the page just ran, opened at its first step.

    daily-brief.nika.yaml · excerptsource
    nika: daily-brief# local model · your notes never leavemodel: ollama/llama3.2:3bpermits:  fs: { read: [ ./notes/* ], write: [ ./brief.md ] }  tools: [ "nika:read", "nika:write" ]  notes: { invoke: { tool: "nika:read", args: { path: ./notes/today.md } } }

    audited · 7 tasks · 4 waves · permits declarednika 0.111.0

    real lines, sliced from the file above · read-only

  3. Run it

    Point the binary at the file. It prints the plan, checks the permits, and runs within bounds. Every step traced and replayable.

    nika run daily-brief.nika.yaml

runs everywhere · same file, same result

6.0.4 In your terminal

One Rust binary. The command is the button: click it, paste it, run.

6.0.6 With your agent

nika init writes AGENTS.md · nika wire claude|cursor adds the read-only oracle (nika_check · nika_explain).

WORKS WITH YOUR STACK

Claude Code · Codex · Cursor · VS Code · Hermes · OpenCode · Zed · GitHub Actions · MCP

nika init teaches whatever agent you run. the full integrations map

Learn it in 5 minutes

14

Questions, answered straight.

The real objections, and honest answers. No overclaiming, no dunking on the tools you already use.

  • I already see the agent’s steps in Cursor or a README. Why Nika?

    Seeing the steps is not the same as enforcing the procedure. A README is documentation; a Nika file is an executable contract: versionable, replayable, permission-bound, auditable, and portable off any platform. You do not just read what it intends to do; the runtime holds it to exactly that.

  • Isn’t this just YAML, or another workflow engine?

    The syntax is plain YAML, but the point is not the syntax. The point is the reviewable, enforced plan. The 4 verbs (infer · exec · invoke · agent) are native execution models, each one explicit and typed, with a permits: block the runtime enforces before anything runs. The file is the control surface, not the formatting.

  • Why not LangGraph, n8n, or MCP (agent tools)?

    They live at a different layer. Frameworks help you orchestrate and assistants help an agent act; MCP exposes tools to call. Nika is the contract-and-control layer underneath: it makes the plan reviewable and enforceable, and it runs their tools through invoke, allow-listed and traced. It complements them rather than replacing them.

  • Does my data leave my machine?

    Local-first, any model: fully local, or any API. Run a local model and nothing leaves at all. Every plan declares its network egress in its permits: block, and it is default-deny: omit the hosts and the workflow physically cannot reach the network. The file states exactly what can leave, and the runtime enforces it. 5 of the 17 providers are local.

  • Is it production-ready? What’s the license?

    Honest answer: Nika is early. Real semver toward a 1.0 launch, currently at v0.111.0, shipping in the open. It is one Rust binary you can install and run today. The engine is AGPL-3.0-or-later; the spec is Apache-2.0. We would rather you trust the spec and the binary than a maturity claim we have not earned yet.

the noise becomes the file.

14

Put your agents on a leash you can read.

Install the binary, write the plan as a file, review what it's allowed to touch, run it. Same file, same result, enforced on your machine. Tomorrow, and the day the vendor is gone.

brew install supernovae-st/tap/nika

Do you repeat an AI task every week, in ChatGPT, Claude, Cursor, Codex, or scripts? Send it. We convert the best ones into runnable .nika.yaml examples, credited to you.

Send a workflow