the skeleton register
docker-report
Your intent sounds like: read a system's state (docker · kubectl · gh), explain it, keep the report One of 10 skeletons the pack ships, green as-is under nika check. Fill the # SLOT: lines, repair from the fix lines, re-check. Machines read the catalog; the binary lists them with nika new '?'.
- 10SLOT pointsthe only lines you edit
- 3patterns lockedarrive correct, stay correct
- 1tool grantedthe minimum for the job
- b17d9ca7sha-pinnedre-hashed on every test run
the plan
derived from the file, never drawn by handpsexecdfexec
diagnoseinfer
keepinvoke
the file, whole
conformance-gated upstream on every spec pushdocker-report.nika.yaml
# SPDX-License-Identifier: Apache-2.0# yaml-language-server: $schema=https://nika.sh/spec/v1/workflow.schema.json## TEMPLATE · docker-report · read real state via a pinned CLI → explain it → keep the report.## [ps]────┐# [df]────┴──▶[diagnose]────▶[keep]# exec ×2 infer nika:write## The "ask the machine what is actually true, then explain it" job. Two reads# run in parallel because nothing connects them, one model pass turns raw CLI# output into a report a human can act on, and the report is kept on disk. Swap# `docker` for `kubectl`, `gh`, `systemctl` — the shape does not change.## Demonstrates ·# - argv-ARRAY `exec:` · one program, exactly these arguments, no shell to# inject into · and `permits.exec` names the single program allowed# - implicit parallelism · `ps` and `df` share no edge, so the scheduler runs# them together · nobody writes "in parallel" anywhere# - `on_error: recover:` on an exec · the skeleton rehearses green on a host# with no Docker at all## Needs · nothing to rehearse. For a REAL report: a running Docker daemon —# then delete the two `on_error:` blocks so a broken daemon is loud.## Run · nika run <file> --model mock/echo # offline rehearsal · no daemonnika: v1workflow: id: docker-report-template # SLOT: kebab-case workflow id # SLOT: one honest sentence — `nika new` matches intents against these words description: "read the daemon's state · explain it · keep the report"# SLOT: local-first · `--model mock/echo` for the offline rehearsal. Measured# seat — `ollama/llama3.2:3b` answers this prose prompt in well under a minute.model: ollama/llama3.2:3bpermits: # the blast radius · default-deny once present exec: - "docker" # SLOT: the ONE program the reads may launch tools: - "nika:write" fs: write: - "./docker-health.md" # SLOT: where the report lands (must match `keep`)tasks: # The reads run IN PARALLEL (no edges between them) — the # scheduler proves it from the DAG, nobody orders it. ps: exec: # SLOT: argv ARRAY form — one program, exactly these arguments. The array # is why there is no shell here: no word-splitting, no globbing, nothing # to quote wrong. `permits.exec` above is the provable allowlist. command: ["docker", "ps", "--all", "--format", "{{.Names}}\t{{.Status}}\t{{.Image}}"] on_error: # Offline rehearsal · a host with no daemon answers with a literal that # LOOKS like the real thing, so `diagnose` reads the same shape either # way. Delete this once the daemon is really there. recover: "REHEARSAL\tno docker daemon on this host\tn/a" df: exec: command: ["docker", "system", "df"] # SLOT: the second read (drop the task if one suffices) on_error: recover: "REHEARSAL · disk usage unavailable without a daemon" diagnose: with: ps: ${{ tasks.ps.output }} df: ${{ tasks.df.output }} infer: max_tokens: 600 # SLOT: the spend ceiling for this call # SLOT: what should the model DO with the readings? Keep slot markers out # of the block below — everything indented under `prompt: |` is prompt # TEXT, and a stray comment line is sent to the model verbatim. prompt: | You are reading a Docker host's state. Containers (name·status·image): ${{ with.ps }} Disk usage: ${{ with.df }} Write a short health report: what is running, what exited, what looks unhealthy (restart loops · old exits), and whether disk usage needs attention. Plain prose, no preamble. keep: with: diagnose: ${{ tasks.diagnose.output }} invoke: tool: "nika:write" args: path: "./docker-health.md" # SLOT: same path as permits.fs.write content: "${{ with.diagnose }}"outputs: report: value: ${{ tasks.keep.output }} description: "Where the report landed — nika:write hands back the path it wrote"sha256 b17d9ca7da5a0177…. The copy above re-hashes to its pin on every test run (a copy is re-provable, never trusted). Source: docker-report.nika.yaml in the spec pack · open it in the playground →
the patterns it locks
- argv-array exec (provable allowlist)
- parallel reads
- one artifact
cross-references
Scaffold it locally: nika new docker-report my-flow.nika.yaml. Try the shape in the playground, or walk the showcase for the same patterns on real work. Read the spec →