Skip to main content
nika:image_generate treats images as workflow citizens: the same declared permits: boundary that gates file writes gates every save, real spend lands in the run ledger, and provenance is structural — in the manifest beside the asset and inside the PNG itself. One workflow renders through any of five image providers — local server first; the run meters $0.02 exactly; the asset lands sha256-named with a provenance manifest beside it

The five providers

Keys and the local URL are engine config, never workflow args: OPENAI_API_KEY / GEMINI_API_KEY / XAI_API_KEY (or NIKA_-prefixed), NIKA_IMAGE_LOCAL_URL (+ optional NIKA_IMAGE_LOCAL_API_KEY). Check what’s wired with nika doctor — it prints an image line naming the ready providers.

Sovereign quickstart (local server)

The engine forces response_format: b64_json (LocalAI defaults to URL mode), refuses url-only answers (result URLs are never fetched — that would reopen the SSRF surface the fixed-endpoint design closed), and gives local renders a 300s default timeout — CPU diffusion runs minutes, raise timeout_ms: up to 600000 when needed. SD-family servers honor a positive | negative prompt split written directly inside prompt:.

What lands on disk

The manifest carries the resolved request, per-image sha256 + dimensions, endpoint_host (which server actually rendered it), timing, warnings, cost_usd, and your metadata: fields — never a credential, by construction. The PNG itself carries a nika tEXt chunk (tool, engine version, provider, model, prompt, seed) — so provenance survives cp, the practice ComfyUI and InvokeAI standardized. Read it back with any PNG tool:

Content credentials (detect-and-preserve)

OpenAI and Google sign their API bytes with C2PA Content Credentials — and C2PA hashes the file’s byte ranges, so any pipeline that writes into a signed render converts valid credentials into « present but tampered ». Nika detects the signals first (PNG caBX · JPEG APP11 JUMBF · RIFF C2PA · MP3 GEOB): on signed payloads the nika tEXt embed stands down (their signed manifest outranks our informal chunk — a loud content_credentials_preserved: warning says so), and the output + manifest surface content_credentials: "c2pa" plus watermark_declared (SynthID is a provider fact — only the vendor can detect it). Detection labels only: the wire never says « verified ». With EU AI Act Article 50 in force from 2026-08-02, preserving machine-readable marks is part of an operator’s compliance surface — no other workflow engine even looks.

Honesty rules (what the warnings mean)

Every lossy mapping is a stable, visible warning — silent degradation is non-conformant per the spec:
  • count_shortfall: — the provider returned fewer than n: (Ollama’s compat route ignores n, moderation can filter variants).
  • size_conflict: · xai_size_class: · aspect_remapped: — your exact size was folded to the provider’s nearest class, loudly.
  • seed_unsupported: · quality_folded: · compression_ignored: — the knob doesn’t exist on that provider; the arg was dropped, visibly.
  • format_mismatch: — fires only when you explicitly asked for a format the provider didn’t honor; magic bytes name the real extension either way.

Real spend in the ledger

xAI bills images in cost ticks — the engine converts them exactly and the render’s cost rides the task line, the run total, and the manifest:
Any invoke tool reporting a top-level cost_usd in its structured output is metered the same way. Providers that don’t report exact cost show null — never an estimate dressed as truth.

Cookbook (each proven end-to-end against live APIs)

An LLM writes the brief, another provider renders it:
Fan out one hero across locales (concurrent, one output dir):
Let an agent decide the arguments (the model reads the tool definition):
Retry transient failures (a local server still loading its model):

Why this design (versus every other engine)

No other workflow engine permit-gates image saves, verifies returned bytes against declared MIME types, writes a provenance manifest with the resolved request, refuses to fetch result URLs, or ships a local-first provider — and none embed provenance in the file itself (that practice comes from the image-native world). The full comparison lives in the builtins reference.

Editing (mode: edit)

An input image plus an instruction — the same builtin, one arg away:
The rules mirror generation, inverted where reading demands it:
  • Reads are permit-gated. Every image:/images:/mask: path is enforced against permits.fs.read before a byte is read — the exact mirror of the save boundary. Edit reads what generate writes, so a generate→edit chain declares both read: and write:.
  • image: XOR images: — one source or many (capped per provider: openai 16 · gemini 14 · xai 3), 20 MB each, magic-byte sniffed.
  • A mask: is refused, never dropped, on providers that edit by instruction only (gemini/xai): a silently-ignored mask edits the wrong region. openai (and local inpaint) take pixel masks.
  • The provenance chain survives. The manifest carries mode: "edit" plus source_images: [{path, sha256, format}] — an edited asset records exactly what it derived from.
reference_images: (compose-from-references) and save: false remain reserved — refused loudly rather than pretended.