AGPL-3.0-or-later · forever.

the skeleton register

gate-and-act

Your intent sounds like: watch X, act when Y 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
  • 2tools grantedthe minimum for the job
  • a548c0e5sha-pinnedre-hashed on every test run

the plan

derived from the file, never drawn by hand
checkinvoke
actinvoke

the file, whole

conformance-gated upstream on every spec push
gate-and-act.nika.yaml
# SPDX-License-Identifier: Apache-2.0# yaml-language-server: $schema=https://nika.sh/spec/v1/workflow.schema.json## TEMPLATE · gate-and-act · check a condition, act only when it holds.##   [check]────with · when(cond)────▶[act]#   nika:fetch                        nika:notify## The watcher. Read a number, stay silent unless it crosses a line. Most runs# do nothing at all — and "nothing happened" is a SUCCESS here, not a failure.# Often zero model calls, so it is cheap enough to run on a schedule.## Demonstrates ·#   - `when:` as a SKIP gate · routing, not failure · a skipped task is not an#     error and does not fail the run#   - flow vs capability · `egress:` sanctions the SEND, `permits.net.http`#     grants the REACH · an alert path needs BOTH (see `permits.net`)#   - `on_error: recover:` · the gate rehearses CLOSED, so the skeleton is#     green before the real source is wired## Needs · nothing to rehearse. To alert FOR REAL: ALERTS_WEBHOOK_URL in the#   environment and a live source in `const.source_url` — then delete the#   `on_error:` so a dead source is loud.## Run · nika run <file>          # offline rehearsal · the gate stays closednika: v1workflow:  id: gate-and-act-template     # SLOT: kebab-case workflow id  # SLOT: one honest sentence — `nika new` matches intents against these words  description: "watch a value · act only when the condition holds"const:  source_url: "https://api.example.com/v1/value"   # SLOT: what to watch  threshold: 100                    # SLOT: the trigger condition valuepermits:                            # the blast radius · default-deny once present  tools: ["nika:fetch", "nika:notify"]  net:    http:      - "api.example.com"           # SLOT: the watched host from const.source_url      - "hooks.slack.com"           # SLOT: the host ALERTS_WEBHOOK_URL points at.                                    #   `host_from_self` below means the host is not                                    #   knowable at check — it is judged at RUN against                                    #   this list, so an unnamed host fails mid-flight.secrets:  webhook:    source: env    key: ALERTS_WEBHOOK_URL         # SLOT: where the act lands    egress:      - to: "nika:notify"        host_from_self: true        # the secret value IS the destination URLtasks:  check:    invoke:      tool: "nika:fetch"      args:        url: "${{ const.source_url }}"        mode: jq        jq: "."    output:      value: ".value"               # SLOT: the jq path to the watched field    on_error:      # Offline rehearsal · a sample UNDER the threshold — the gate stays      # closed, the skeleton runs green before you wire the real source.      recover: { value: 42 }  act:    with:      value: ${{ tasks.check.value }}   # the binding IS the edge · check → act    # when: is a SKIP gate — routing, not failure (a skipped task is not an error)    when: ${{ with.value > const.threshold }}   # SLOT: the CEL condition    invoke:      tool: "nika:notify"           # SLOT: the action · notify / write / exec      args:        channel: webhook        target: "${{ secrets.webhook }}"        message: "Threshold crossed · ${{ with.value }}"   # SLOT        severity: warningoutputs:  value: ${{ tasks.check.value }}

sha256 a548c0e551f7efb5. The copy above re-hashes to its pin on every test run (a copy is re-provable, never trusted). Source: gate-and-act.nika.yaml in the spec pack · open it in the playground →

the patterns it locks

  • jq extraction
  • CEL skip-gate
  • often zero model calls

Scaffold it locally: nika new gate-and-act my-flow.nika.yaml. Try the shape in the playground, or walk the showcase for the same patterns on real work. Read the spec →