AGPL-3.0-or-later · forever.

showcase · tier 3 · research

Competitor radar

Maps their sitemap, reads the freshest pages in parallel with retry, then digests one brief.

Monday 8am, everything they shipped last week is on your desk, with what it signals. · conformance-gated in nika-spec ↗ · re-proven at every push

The whole file

5 tasks · 5 waves · the plan falls out of the bindings, nothing is scheduled by hand.

t3-competitor-radar.nika.yamlsource
nika: v1workflow:  id: competitor-radar  description: "Sitemap → parallel page reads → one competitive brief + ping"model: ollama/qwen3.5:4b   # local · zero key · swap for anthropic/claude-sonnet-4-6vars:  competitor_sitemap: "https://competitor.example.com/sitemap.xml"secrets:  team_webhook:    source: env    key: TEAM_WEBHOOK_URL    egress:                       # sanction the one send · the secret IS the URL      - to: "nika:notify"        host_from_self: truetasks:  map:    invoke:      tool: "nika:fetch"      args:        url: "${{ vars.competitor_sitemap }}"        mode: sitemap    output:      recent: ".[:8] | map(.loc)"     # sitemap = the root array of {loc, …} · cap at 8, keep the URLs  pages:    with:      map_recent: ${{ tasks.map.recent }}    for_each: ${{ with.map_recent }}    max_parallel: 4                    # be polite · 4 fetches in flight max    fail_fast: false                   # one dead page must not kill the radar    on_error:      recover: null                    # a dead page yields null at its index · the radar lives    timeout: "30s"    retry:      max_attempts: 3      backoff_strategy: exponential      jitter: true    invoke:      tool: "nika:fetch"      args:        url: "${{ item }}"        mode: article  digest:    with:      pages: ${{ tasks.pages.output }}    infer:      prompt: |        These are the pages a competitor published recently ·        ${{ with.pages }}        Write the Monday brief · what they shipped · what it signals ·        what we should watch. One page, plain words.  save:    with:      digest: ${{ tasks.digest.output }}    invoke:      tool: "nika:write"      args:        path: "./radar/competitor-brief.md"        content: "${{ with.digest }}"        create_dirs: true  ping:    after:      save: succeeded    invoke:      tool: "nika:notify"      args:        channel: webhook        target: "${{ secrets.team_webhook }}"        message: "Competitor radar is ready · ./radar/competitor-brief.md"        severity: infooutputs:  brief: ${{ tasks.digest.output }}

nika inspect · engine 0.105.0 · vendored graph, never re-derived

4 declared edges · 5 waves · the plan falls out of the bindings