Skip to main content
T1 starter · marketing / content: one task is the whole media pipeline. Generated images land on disk under a declared boundary — outputs carry paths and sha256 hashes, never image bytes.

The job

Every landing page, blog post and QR campaign needs an OG image, and someone ends up producing them one by one in a chat window. This workflow turns that into a step: creative brief in, rendered variants + a provenance manifest out, ready for the site build to pick up.

The shape

The file

og-images.nika.yaml

Why it reads like that

  • provider: mock first — it renders real, decodable PNGs offline, deterministically, with zero keys: the pipeline is testable in CI as-is. Production is a one-line flip to local (the sovereign path — your LocalAI/Ollama/sd.cpp server, NIKA_IMAGE_LOCAL_URL), gemini (GEMINI_API_KEY), openai (OPENAI_API_KEY) or xai (XAI_API_KEY); keys and the local URL are engine-configured, never workflow args.
  • permits.fs.write is the contract./assets/og/** is the ONLY place assets may land; a templated output_dir that escapes it fails NIKA-SEC-004 before any byte is written. nika check --infer-permits writes this block for you.
  • assets, not blobstasks.hero.output.images is a list of { path, filename, width, height, sha256, … } entries, and a *.manifest.json lands beside the files (request echo · hashes · usage · your metadata: fields). Base64 never rides outputs, logs or traces.
  • n: 2 for A/B — OpenAI renders n natively; Gemini runs n sequential calls (documented); mock renders n distinct deterministic variants.

Run it

Flip the provider line and re-run when you want real renders — the rest of the file does not change.