showcase · tier 2 · builders
Release radar
Reads your dependencies’ release feeds and diffs against last run, so only new ships reach you.
- 6tasksthe plan falls out of the bindings
- 3wavesparallel by construction
- 2verbs exercisedinvoke · infer
- T2the tierbuilders
The whole file
6 tasks · 3 wavesThe plan falls out of the bindings, nothing is scheduled by hand.
release-radar.nika.yamlsource
nika: v1workflow: id: release-radar description: "dependency release feed → diff vs last run → only the NEW ships"model: ollama/qwen3.5:4b # local · zero key · swap for any provider in the catalogconst: releases_feed: "https://github.com/tokio-rs/tokio/releases.atom" state_path: "out/release-radar.json"permits: tools: ["nika:fetch", "nika:jq", "nika:json_diff", "nika:read", "nika:write"] fs: # The state-file pattern touches exactly ONE path, on both sides: read # last run's state, write the next. `const.state_path` names it and a run # cannot move a const, so the same literal is the whole boundary — # `create_dirs:` makes out/ underneath it on the first run. read: ["out/release-radar.json"] write: ["out/release-radar.json"] net: http: ["github.com"] # the feed's host · net entries are exact names, never globstasks: # First run has no state file · recover to an empty list. no_state: invoke: tool: "nika:jq" args: { input: [], expression: "." } previous: invoke: tool: "nika:read" args: { path: "${{ const.state_path }}" } on_error: on_codes: [NIKA-BUILTIN-READ-001] # not-found ONLY · a permission error still fails loudly recover: ${{ tasks.no_state.output }} feed: invoke: tool: "nika:fetch" args: url: "${{ const.releases_feed }}" mode: feed output: entries: "[.items[] | {title, url, published}]" on_error: # No network → this sample stands in for the RAW feed response, so it # carries `items:` exactly as `mode: feed` returns it and the `output:` # jq above runs over it unchanged. Recovering the BINDING's shape # instead makes the jq throw NIKA-VAR-004 — the recovery must mirror the # response, never the binding. recover: items: - { title: "tokio 1.48.0", url: "https://github.com/tokio-rs/tokio/releases/tag/tokio-1.48.0", published: "2026-07-21T09:14:00Z" } - { title: "tokio 1.47.1", url: "https://github.com/tokio-rs/tokio/releases/tag/tokio-1.47.1", published: "2026-07-02T16:40:00Z" } fresh: with: previous: ${{ tasks.previous.output }} entries: ${{ tasks.feed.entries }} invoke: tool: "nika:json_diff" args: before: "${{ with.previous }}" after: "${{ with.entries }}" digest: with: fresh: ${{ tasks.fresh.output }} entries: ${{ tasks.feed.entries }} when: ${{ size(with.fresh) > 0 }} infer: max_tokens: 500 prompt: | New releases appeared on our dependency radar (RFC 6902 patch against last run) · ${{ with.fresh }} Full current feed · ${{ with.entries }} Write 3 bullets · what shipped · whether it looks breaking · what to check in our code. save_state: with: entries: ${{ tasks.feed.entries }} invoke: tool: "nika:write" args: path: "${{ const.state_path }}" content: "${{ with.entries }}" create_dirs: true overwrite: trueoutputs: new_entries: value: ${{ tasks.fresh.output }} description: "RFC 6902 ops · empty = nothing new since last run" # Untyped on purpose: `digest` is `when:`-gated, so on a quiet week it is # SKIPPED and this reads null. Exporting it is also what keeps those tokens # from being dead spend — an infer whose output nothing consumes is paid for # and thrown away, and `check` says so. briefing: ${{ tasks.digest.output }}nika inspect · engine 0.106.1 · vendored graph, never re-derived
6 declared edges · 3 waves · the plan falls out of the bindings