Skip to main content
Ops work is where « the agent ran a command » stops being acceptable and « the file says exactly which commands, and the runtime enforces it » starts to matter. This guide builds a Docker health report the audited way: two pinned docker reads, one local model, one kept artifact.

The whole workflow

Checked clean against nika 0.120.1 (9d554c84c · nika check exit 0 · permits declared · 0 hints). The run card below is a dated capture from 2026-07-08; re-run on your machine for a current journal:

Why the exec tasks are arrays

Write shell: "docker ps | grep Up" and nika check refuses to bless the boundary:
That refusal is the feature. A shell string can smuggle any program through a pipe; the argv array names exactly one program with exactly those arguments, so permits.exec: ["docker"] is a boundary the checker can actually prove. Transforms that would have lived in | grep | awk belong in extract: bindings and nika:jq instead.

What the audit says before a token is spent

Two things worth noticing:
  • The two docker reads run in parallel (wave 1) — the scheduler proved it from the with: bindings, nobody ordered it.
  • The cost line practices the honesty rule: a local model is unpriced compute, not « free » — the report says FLOOR and names why, it never rounds unknown to $0.

Run it

Captured verbatim (Apple-silicon laptop · Docker Desktop · a small local thinking model — the two-minute infer is the model, not the engine):
docker-health.md now holds the model’s prose, and the run left a hash-chained journal you can prove later:

When the daemon is down

The failure is part of the design. With Docker stopped, the same run fails honestly and early — the model is never called, nothing is spent, and the card hands over:

Take it further

  • Gate an action on the report — add an agent: task allowed only nika:done, or a when: gate on a structured diagnose output, and the workflow can act on unhealthy containers, still inside the declared boundary. See patterns.
  • Schedule it — the file is the artifact: cron or CI runs nika run; when journaling is enabled, inspect and verify the evidence the execution leaves behind.
  • Structured instead of prose — give diagnose a schema: and the report becomes typed data downstream tasks can branch on. See testing for pinning it with a golden.
The two exec tasks carry the repo’s exec ledger (the header comment): every surviving exec: names why no builtin or MCP tool covers it yet, and what would remove it. When a Docker MCP server enters your stack, invoke: replaces both reads and the ledger empties — that is the native-first law working as intended.