A weekly client report, generated end to end
Internal build — fictional outdoor-gear store data
A working automation, built and run by Veldway: one JSON file of store data becomes a finished weekly client report — computed metrics, a model-drafted narrative labeled with its source, an HTML page, and an email body — in one command.
Internal build. Built by Veldway and exercised on fictional sample data to prove the pattern. It is not a client project, and no client data was involved.
The problem
The weekly client email is real work: pull the numbers, compare them to last week, find the story, write it up, format it, send it. It eats an hour per client per week, it slips when things get busy, and the quality depends on who assembles it. The numbers already live in the systems — the assembly is the only manual part.
Requirements
- Every figure in the report must trace to the input data — the model is never the source of a number
- A report is produced even when no model is reachable, and the words' source is named honestly either way
- Nothing sends by accident: dry-run by default, and sending refuses to run unless fully configured
- Bad input fails loudly: missing fields, duplicate order ids, and negative totals are rejected with messages that say exactly what is wrong
The solution
Numbers and words are strictly separated. A pure-arithmetic metrics stage computes revenue, orders, average order value, week-over-week deltas, top products, and flags from validated input. A narrative stage then writes 3–5 plain-English sentences through a provider chain — Claude's API when a key is set, a local Ollama model when a server answers, and a deterministic template when neither is available — and the report footer names which source actually produced the words. The output is a clean HTML page and a text email body with identical content.
Architecture
A three-stage pipeline: validated input → computed metrics → rendered report. The narrative step is the only model call, and it is engineered like any production integration: every network read is bounded by a wall-clock deadline and a size cap, retryable failures get three attempts with backoff, and any provider problem routes to the next provider rather than failing the run. The prompt explicitly forbids numbers that are not in the metrics JSON.
Challenges & resolutions
A trickling or oversized API response could hang the run or exhaust memory, because a socket timeout resets on every byte received.
Resolution — Response bodies are read in bounded chunks against a total wall-clock deadline and a hard size cap, so a misbehaving provider degrades to the next path exactly like an outage would.
A malformed OLLAMA_HOST environment value crashed the server probe instead of reading as 'no server running'.
Resolution — Found by our own audit of the build: the probe now normalises the value and treats every failure class as absence, pinned by tests — a configuration typo can never take down report generation.
A small local model sometimes prefixed its answer with filler and once volunteered advice the prompt had forbidden.
Resolution — The prompt pins the output format, the deterministic fallback is always available, and the footer names which engine wrote the words — so the human reviewing the report knows exactly what they are reading.
Why this build exists
Before Veldway pitches an automation pattern to anyone, we build it and run it ourselves. This is the first of two internal builds behind our AI Automation service — chosen because the weekly client update is the single most universal piece of recurring agency work.
Honesty notes
"Acme Outdoor Supply" is fictional and the data file says so in its first line. The narrative in the committed sample was drafted by a local llama3.2 via Ollama, and the report footer says exactly that. In client work, the input stage is replaced by a connector to the real source — Shopify Admin API, GA4, or a warehouse export — and a human reviews the report before it goes out.
The full source, test suite, and sample outputs are public at github.com/veldway/internal-builds.
What the build does
- Runs live on a local llama3.2 with no API key and no vendor account — the committed sample output is labeled with its source
- 23 automated tests pin the provider chain, the failure routing, the bounded reads, and the input validation
- Identical input produces identical filenames, and the offline mode produces byte-identical files
- In the committed live sample, every figure traces to the input orders: revenue 2,292.40, up 8.9% week-over-week, top product at 1,156.00
Have a similar problem?
Describe the problem in plain language — broken, slow, manual, or missing. We'll tell you whether and how we can help.
- 01We reply within one business day
- 02A short call to understand the problem
- 03A written scope and fixed quote — no obligation