the skeleton register
human-gated-ship
Your intent sounds like: anything irreversible (deploy · send · publish) 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
- 4patterns lockedarrive correct, stay correct
- 3tools grantedthe minimum for the job
- 3a9bbde8sha-pinnedre-hashed on every test run
the plan
derived from the file, never drawn by handcheck_aexeccheck_bexec
gatesinvoke
humaninvoke
actexec
recordinvoke
the file, whole
conformance-gated upstream on every spec pushhuman-gated-ship.nika.yaml
# SPDX-License-Identifier: Apache-2.0# yaml-language-server: $schema=https://nika.sh/spec/v1/workflow.schema.json## TEMPLATE · human-gated-ship · gates in parallel → a human signs → ship · evidence always lands.## [check_a]─┐ ┌──▶[act]──▶[record]# [check_b]─┴─▶[gates]──▶[human ⏸]──yes──┘ exec nika:notify (always)# exec ×2 assert nika:prompt## Anything you cannot take back — a deploy, a send, a publish. The machine# proves the preconditions in parallel, an assert refuses to even ASK when a# gate is red, the human decides once with the full picture, and the evidence# lands whether the answer was yes, no, or the ship blew up.## Demonstrates ·# - `nika:assert` before the question · never ask a human to rubber-stamp a# red board# - `after: <task>: success` · a STATE edge (ordering, no data) vs `with:` (a# value edge) — two different kinds of arrow# - `after: <task>: terminal` · the always-runs pattern · evidence on success,# failure OR refusal# - fail-closed defaults · unattended, the answer is NO## Needs · nothing to rehearse. To ship FOR REAL: TEAM_WEBHOOK_URL in the# environment, real commands in the three `exec:` slots — then delete the# `on_error:` on `record` so a lost audit trail is loud.## Run · nika run <file> # unattended · gates run, the answer defaults to NO# Headless, `default: false` answers for you — delete that line and the# run PAUSES instead (exit 4 · durable, not a failure) and prints its# own resume line ·# nika run <file> --resume <trace> --answer human=true · or falsenika: v1workflow: id: human-gated-ship-template # SLOT: kebab-case workflow id # SLOT: one honest sentence — `nika new` matches intents against these words description: "verify in parallel · human GO · act · record"permits: # SLOT: the blast radius · default-deny once present exec: ["echo"] # SLOT: ONLY the programs the gates + act run (argv form) tools: ["nika:assert", "nika:prompt", "nika:notify"] # `host_from_self` below sanctions the FLOW (the secret may BE the URL) — it # does not grant the capability to reach anyone. The host stays unknown at # check, so it is judged at RUN against this list: name the webhook host here # or the record is refused mid-run, after the ship already happened. net: { http: ["hooks.slack.com"] } # SLOT: the webhook host · nothing else may leavesecrets: webhook: source: env key: TEAM_WEBHOOK_URL # SLOT: where the record lands egress: - to: "nika:notify" host_from_self: true # the secret value IS the destination URLpolicy: # NEP-0014 · the gate runs under a NAMED endorsement mode endorsement: solotasks: # ── the verification wave · all checks run in parallel ── check_a: exec: command: ["echo", "ok"] # SLOT: gate 1 (argv form · injection-safe) capture: structured check_b: exec: command: ["echo", "ok"] # SLOT: gate 2 capture: structured gates: with: all_green: ${{ tasks.check_a.output.exit_code == 0 && tasks.check_b.output.exit_code == 0 }} # two value edges · one boundary expression invoke: tool: "nika:assert" args: condition: "${{ with.all_green }}" message: "A gate is RED: refusing to proceed" # SLOT human: after: gates: success # state, no data · no question until the board is green invoke: # On a terminal this ASKS. Headless, it answers with `default:` below — # the run completes, it does not pause (measured · act settles skipped). # The durable pause belongs to a prompt with NO default: headless it # PAUSES (exit 4 · not a failure) and prints its own resume line: # nika run <file> --resume <trace> --answer human=true · or false tool: "nika:prompt" args: message: "All gates GREEN. Proceed?" # SLOT: the decision, fully informed # Fail CLOSED. The unattended answer to "should I do the irreversible # thing" is no — `default: true` would hand CI a rubber stamp. default: false act: with: go: ${{ tasks.human.output }} # the answer crosses as a value edge when: ${{ with.go == true }} exec: command: ["echo", "shipped"] # SLOT: the irreversible action (argv · program must be in permits.exec) # default capture · a failing ship fails LOUDLY (NIKA-EXEC-001): # never `capture: structured` on the irreversible step (exit codes # would become data and a red ship would read as success) record: after: act: terminal # the always-pattern · runs on success, failure, OR refusal with: acted: ${{ tasks.act.status }} # observe the outcome · same pass-set as the after edge invoke: tool: "nika:notify" args: channel: webhook target: "${{ secrets.webhook }}" message: "Run finished · act=${{ with.acted }}" # SLOT · success | failure | skipped severity: info on_error: # Rehearsal only. With TEAM_WEBHOOK_URL unset the reference cannot resolve # and this task fails NIKA-VAR-001 (measured) — which would make the # skeleton red on a machine that has no webhook. Recovering keeps the # scaffold runnable; DELETE this block for real use, because a ship whose # audit trail silently vanished is exactly what this task exists to prevent. recover: "REHEARSAL · no webhook configured · nothing was sent"outputs: acted: ${{ tasks.act.status }}sha256 3a9bbde8086cbe41…. The copy above re-hashes to its pin on every test run (a copy is re-provable, never trusted). Source: human-gated-ship.nika.yaml in the spec pack · open it in the playground →
the patterns it locks
- parallel gates
- assert
- `nika:prompt` GO
- `on_finally` record
cross-references
Scaffold it locally: nika new human-gated-ship my-flow.nika.yaml. Try the shape in the playground, or walk the showcase for the same patterns on real work. Read the spec →