Query icon
OllamaCLI icon
DiscordIncomingWebhook icon
Schedule icon

Nightly Data Narrative with DuckDB and a Local Ollama Model

Chain a DuckDB query into a local Ollama model with Kestra. Metrics become a plain-English standup narrative, written on your own hardware every night.

Categories
AI

Dashboards show numbers; standups need sentences. This blueprint chains the two halves in one execution: io.kestra.plugin.jdbc.duckdb.Query computes the day's metrics and stores the result set in internal storage, and io.kestra.plugin.ollama.cli.OllamaCLI reads that exact file and writes a three-sentence plain-English narrative, biggest improvement, biggest decline, on your own hardware. Discord points the team at the artifact before the morning standup, and no metric ever visits a cloud LLM.

How it works

  1. daily_metrics (io.kestra.plugin.jdbc.duckdb.Query) runs against DuckDB's default in-memory database. The VALUES list is a stand-in; in real use the same SQL reads your warehouse file or attached storage. fetchType: STORE writes the full result set to internal storage and exposes it as {{ outputs.daily_metrics.uri }}.
  2. narrate (io.kestra.plugin.ollama.cli.OllamaCLI) maps that stored file into its working directory through inputFiles, inlines it into a narration prompt via $(cat metrics.ion), and redirects the model's answer to narrative.txt, which outputFiles uploads as an execution artifact.
  3. Because the narration reads the exact file the query produced, the narrative and the numbers can never drift apart within an execution.
  4. enableModelCaching: true persists the model between nightly runs, so narration starts immediately.
  5. notify posts a pointer to the artifact rather than interpolating model prose into JSON; the errors block covers both halves of the chain. A disabled-by-default Schedule trigger runs the chain at 06:30.

What you get

  • A numbers-to-narrative pipeline with zero API cost and zero data egress.
  • Consistency by construction: the narrative is generated from the stored result of this execution's query, not from a table that may have changed since.
  • Both artifacts preserved per execution, the metrics file and the narrative, so anyone can check the prose against the data.
  • A chain where each half swaps independently: point the SQL at real tables, or trade the model for a larger one, without touching the other task.

Who it's for

  • Data teams who want a morning summary in chat instead of a dashboard nobody opens before coffee.
  • Analytics engineers adding a narrative layer on top of existing DuckDB or warehouse queries.
  • Teams that like LLM-written digests but cannot send business metrics to hosted APIs.

Why orchestrate this with Kestra

The chain is the point: DuckDB does not schedule inference and Ollama does not run SQL. Kestra sequences them with typed file passing through internal storage, so the query result becomes the model's input file with one template expression, retries apply per task, and the execution history keeps the metrics, the narrative, and the notification together as one auditable unit per day.

Prerequisites

  • The default containerImage runs Ollama inside Docker, so the Kestra worker needs access to a Docker daemon. On self-hosted workers that already have Ollama installed locally, set the task's taskRunner to Process to use the local install directly.
  • No database server; DuckDB runs in-memory inside the task. For real data, point the query at a persistent DuckDB file or attached storage.
  • A Discord incoming webhook.

Secrets

  • DISCORD_WEBHOOK_URL: Discord incoming webhook URL.

Quick start

  1. Add the DISCORD_WEBHOOK_URL secret to your Kestra namespace.
  2. Execute the flow; Discord should link an execution whose narrative.txt calls out signups up and orders down.
  3. Replace the VALUES list with SQL over your real tables and set disabled: false on the nightly trigger.

How to extend

  • Feed the query from a real warehouse: open a persistent DuckDB file, or produce one upstream as shown in the dlt to DuckDB analytics chain blueprint.
  • Tune the narration prompt with audience and tone, an executive digest and an on-call handoff want different sentences from the same numbers.
  • Add a second narration task with a different model and compare artifacts before standardizing.
  • Send the pointer to Slack or email instead by swapping the notification task; the chain shape survives.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.