AGPL-3.0-or-later · forever.

showcase · tier 2 · business

CSV chart report

convert types the spreadsheet, jq aggregates, chart renders a real image, write assembles the report. Zero model calls.

Paste the export, get the slide: same data, same bytes, works on a plane. · conformance-gated in nika-spec ↗ · re-proven at every push

  • 6tasksthe plan falls out of the bindings
  • 5wavesparallel by construction
  • 1verbs exercisedinvoke
  • T2the tierbusiness

The whole file

6 tasks · 5 waves

The plan falls out of the bindings, nothing is scheduled by hand.

csv-chart-report.nika.yamlsource
nika: v1workflow:  id: csv-chart-report  description: "CSV → aggregate → rendered bar chart + markdown report · offline · deterministic"const:  sales_csv: "examples/fixtures/sales.csv" # columns · region,revenue (revenue a plain number)permits:  exec: false  tools: ["nika:chart", "nika:convert", "nika:jq", "nika:read", "nika:write"]  fs:    # The one CSV this reads, named exactly. `data/**` would have granted a    # whole tree to a workflow that opens a single file.    read: ["examples/fixtures/sales.csv"]    # Two artifacts land here — the SVG and the report page. `**` because the    # chart and the report are written by two different builtins into the    # same tree, and both are covered by one honest entry.    write: ["out/**"]tasks:  raw:    invoke:      tool: "nika:read"      args: { path: "${{ const.sales_csv }}" }  rows:    with:      raw: ${{ tasks.raw.output }}    invoke:      tool: "nika:convert"      args:        input: "${{ with.raw }}"        from: csv        to: json        has_header: true  # Sum revenue per region · a deterministic reduce, no model.  by_region:    with:      rows: ${{ tasks.rows.output }}    invoke:      tool: "nika:jq"      args:        input: "${{ with.rows }}"        expression: 'group_by(.region) | map({ region: .[0].region, revenue: (map(.revenue | tonumber) | add) })'  # The picture · one SVG, its sha lands in the trace.  chart:    with:      by_region: ${{ tasks.by_region.output }}    invoke:      tool: "nika:chart"      args:        data: "${{ with.by_region }}"        semantics: { region: category, revenue: usd }        chart: { type: bar, x: region, y: revenue, title: "Revenue by region" }        out: out/revenue-by-region.svg  # The rows as MARKDOWN · a report renders lines, never a JSON blob  # (region names are user data — the esc guards a `|` in them).  rows_md:    with:      by_region: ${{ tasks.by_region.output }}    invoke:      tool: "nika:jq"      args:        input: "${{ with.by_region }}"        expression: >-          def esc: tostring | gsub("\\|"; "\\|") | gsub("\n"; " ");          map("| \(.region | esc) | \(.revenue) |") | join("\n")  # The page · the report references the picture beside it.  report:    with:      rows_md: ${{ tasks.rows_md.output }}    after:      chart: success    invoke:      tool: "nika:write"      args:        path: out/revenue-report.md        content: |          # Revenue by region          ![Revenue by region](revenue-by-region.svg)          | region | revenue |          | --- | --- |          ${{ with.rows_md }}          *Generated offline by [nika](https://nika.sh) · the chart's sha is in the run trace (`nika trace verify`).*outputs:  by_region:    value: ${{ tasks.by_region.output }}    description: "Per-region revenue totals · the chart + report render from this"

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

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