Skip to content

v0.1.0 pre-releasereal public data: 18/20 checksreal-model smoke: 3/3 jobs, 0 wrong numbers139 test filesverifier on every report nightly regression: 30 generated businesses , latest results in section 3

Exhibit · a real report from the example run, verified

9 figures recomputed by the verifier, 1 quote checked against its file · 4 steps below

Report · coffee-roaster · April

Revenue went from $44,100N12 in 2026-03 to $36,200N11 in 2026-04 (a change of −$7,900N29, −17.9%N30). It stood at $37,000N17 in 2026-06.

By channel, “wholesale” fell $8,500N149, more than the whole drop; “retail” rose $600N151.

The hotel customer paused its standing order because of the new price list. D1

Recommended: offer wholesale accounts a volume-tier discount to win back paused standing orders, $3,995N350 to $7,191N351 over the next quarter.

verified: 101 numbers recomputed, 0 mismatched · 6 citations checked

Recorded from a real engine run. Any number opens how it was computed. Fact ledger
  1. 1/4 Revenue fell −17.9% how it was computed

    N30 I5 trend_break.v1 revenue 2026-04:change_pct

    −17.9% recomputed

    Function, in code

    pct_change(N11, N12)
    Inputs
    Input Fact Value
    N11 revenue_2026-04 $36,200
    N12 revenue_2026-03 $44,100

    In the fact ledger

  2. 2/4 April revenue, $36,200 the SQL and the sheet rows it read

    N11 revenue_2026-04

    $36,200 recomputed

    SQL, run in DuckDB

    WITH m1 AS (
      SELECT strftime("date", '%Y-%m') AS period, sum("amount") AS value
      FROM "t_t1"
      WHERE NOT _is_total
        AND "date" IS NOT NULL
        AND (("status" IS NULL) OR ("status" NOT IN ($1)))
        AND strftime("date", '%Y-%m') BETWEEN $2 AND $3
      GROUP BY ALL
    )
    SELECT period, value
    FROM m1
    ORDER BY period

    $1 = 'refunded' · $2 = '2026-04' · $3 = '2026-04'

    Cited rows · sales-2026.xlsx · 50 cited

    Rows of sales-2026.xlsx around the first cited row
    Row dateamountstatus
    3094 2026-03-3117.89refunded
    3095 (cited) 2026-04-0132.9paid
    3096 (cited) 2026-04-0120.98paid

    In the fact ledger

  3. 3/4 Wholesale: $8,500 the change split by channel

    N149 contribution.v1 revenue 2026-04 by channel:magnitude:wholesale

    $8,500 recomputed

    Function, in code

    abs(N144)
    Inputs
    Input Fact Value
    N144 contribution.v1 revenue 2026-04 by channel:delta:wholesale −$8,500

    In the fact ledger

  4. 4/4 The cause quoted from email-0412.eml, checked against the file

    D1 email · email-0412.eml

    Quoted from email-0412.eml · Standing order

    After the new price list we are pausing our standing order while we compare suppliers.

    quote checked against the source

    In the fact ledger

Fact ledger · every fact behind the exhibit

ID Value Fact Computed by Verified
N11 $36,200 revenue_2026-04 SQL in DuckDB recomputed
N12 $44,100 revenue_2026-03 SQL in DuckDB recomputed
N17 $37,000 revenue_2026-06 SQL in DuckDB recomputed
N29 −$7,900 I5 trend_break.v1 revenue 2026-04:change delta(N11, N12) recomputed
N30 −17.9% I5 trend_break.v1 revenue 2026-04:change_pct pct_change(N11, N12) recomputed
N110 $28,200 revenue[channel=retail]_2026-03 SQL in DuckDB recomputed
N111 $28,800 revenue[channel=retail]_2026-04 SQL in DuckDB recomputed
N112 $15,900 revenue[channel=wholesale]_2026-03 SQL in DuckDB recomputed
N113 $7,400 revenue[channel=wholesale]_2026-04 SQL in DuckDB recomputed
N115 $10,188.15 revenue[product=Filter blend 250g]_2026-03 SQL in DuckDB recomputed
N116 $9,551.53 revenue[product=Filter blend 250g]_2026-04 SQL in DuckDB recomputed
N117 $8,797.74 revenue[product=Drip bags x10]_2026-03 SQL in DuckDB recomputed
N118 $8,973.81 revenue[product=Drip bags x10]_2026-04 SQL in DuckDB recomputed
N119 $9,214.11 revenue[product=Espresso blend 250g]_2026-03 SQL in DuckDB recomputed
N120 $10,274.66 revenue[product=Espresso blend 250g]_2026-04 SQL in DuckDB recomputed
N121 $5,565.48 revenue[product=Filter blend 1kg]_2026-03 SQL in DuckDB recomputed
N122 $3,773.01 revenue[product=Filter blend 1kg]_2026-04 SQL in DuckDB recomputed
N123 $10,334.52 revenue[product=Espresso blend 1kg]_2026-03 SQL in DuckDB recomputed
N124 $3,626.99 revenue[product=Espresso blend 1kg]_2026-04 SQL in DuckDB recomputed
N144 −$8,500 contribution.v1 revenue 2026-04 by channel:delta:wholesale delta(N113, N112) recomputed
N145 $600 contribution.v1 revenue 2026-04 by channel:delta:retail delta(N111, N110) recomputed
N146 −$7,900 contribution.v1 revenue 2026-04 by channel:delta:total sum(N145, N144) recomputed
N149 $8,500 contribution.v1 revenue 2026-04 by channel:magnitude:wholesale abs(N144) recomputed
N150 1 contribution.v1 revenue 2026-04 by channel:exceeds:wholesale abs_exceeds(N144, N146) recomputed
N151 $600 contribution.v1 revenue 2026-04 by channel:magnitude:retail abs(N145) recomputed
N163 725 revenue__qty[product=Filter blend 250g]_2026-03 SQL in DuckDB recomputed
N164 657 revenue__qty[product=Filter blend 250g]_2026-04 SQL in DuckDB recomputed
N165 636 revenue__qty[product=Drip bags x10]_2026-03 SQL in DuckDB recomputed
N166 629 revenue__qty[product=Drip bags x10]_2026-04 SQL in DuckDB recomputed
N167 691 revenue__qty[product=Espresso blend 250g]_2026-03 SQL in DuckDB recomputed
N168 711 revenue__qty[product=Espresso blend 250g]_2026-04 SQL in DuckDB recomputed
N169 25 revenue__qty[product=Filter blend 1kg]_2026-03 SQL in DuckDB recomputed
N170 17 revenue__qty[product=Filter blend 1kg]_2026-04 SQL in DuckDB recomputed
N171 46 revenue__qty[product=Espresso blend 1kg]_2026-03 SQL in DuckDB recomputed
N172 17 revenue__qty[product=Espresso blend 1kg]_2026-04 SQL in DuckDB recomputed
N173 −$1,911.07 pvm.v1 revenue 2026-04 by product:pvm:volume pvm.v1(N115, N163, N116, N164, N117, N165, N118, N166, N119, N167, N120, N168, N121, N169, N122, N170, N123, N171, N124, N172) recomputed
N174 −$7,170.84 pvm.v1 revenue 2026-04 by product:pvm:mix pvm.v1(N115, N163, N116, N164, N117, N165, N118, N166, N119, N167, N120, N168, N121, N169, N122, N170, N123, N171, N124, N172) recomputed
N175 $1,181.91 pvm.v1 revenue 2026-04 by product:pvm:price pvm.v1(N115, N163, N116, N164, N117, N165, N118, N166, N119, N167, N120, N168, N121, N169, N122, N170, N123, N171, N124, N172) recomputed
N347 50.0% scenario impact.v1:recover_share:param_low scenario_param() recomputed
N348 90.0% scenario impact.v1:recover_share:param_high scenario_param() recomputed
N349 6.0% scenario impact.v1:recover_share:param_cost scenario_param() recomputed
N350 $3,995 scenario impact.v1:recover_share:impact_low impact.v1:recover_share(N144, N349, N347) recomputed
N351 $7,191 scenario impact.v1:recover_share:impact_high impact.v1:recover_share(N144, N349, N348) recomputed
D1 quote email · email-0412.eml After the new price list we are pausing our standing order while we compare suppliers. checked

The engine, opened up

A small factory for business questions.

11 stations, from your files to a checked report. The models work behind glass; every number is made by the database.

The engine drawn as a factory line: 11 stations on a conveyor from the doors to the report, the job's database file in front and the model room behind glass. Every station is described in "Every station, as a list" below.

How to read the machine

Files in on the left, a checked report out on the right

Metrics, Explain, Decide and Verify sit behind glass: they call a model, and no model is allowed to write a number. Every number is computed by the database, then computed again by the verifier.

The long tank in front is the job's database file, where every station saves its work; the room at the back holds the models.

Scroll to move down the line, or explore the machine yourself.

Every station, as a list

The stations, in the order a job runs them

  1. Station 00 · Doors

    Your files go in

    Where you hand over your files. A terminal command, an HTTP API, an MCP server for AI assistants and a Telegram bot: whichever you use, the same job starts.

    No model: plain code.

    Input folder
    examples/coffee-roaster
    Files handed over
    4

    Learn: Ingestion & profiling

  2. Station 01 · Ingest

    Read the files

    Opens every file and finds the real tables in it. Titles, totals and several tables on one sheet are told apart; documents and emails are cut into sections. Every row remembers its file and row number.

    No model: plain code.

    Files read
    4
    Tables found
    3
    Document sections
    9

    Learn: Ingestion & profiling

  3. Station 02 · Profile

    Understand the columns

    Works out what each column means. Dates, money and its currency, customers; it flags problems such as duplicates or refunds, and screens cell text for instructions aimed at a model.

    No model: plain code.

    Data-quality issues
    3

    Learn: Ingestion & profiling · Security

  4. Station 03 · Metrics · METRICS_DRAFT

    Agree what to measure

    Decides what to measure, and lets you approve it. A model proposes each definition; code checks every column it names and compiles it to SQL, and you confirm or edit it before anything is measured.

    Calls a model: the planner.

    revenue
    sum of amount, per month
    Status
    assumed

    Learn: Metric layer

  5. Station 04 · Analysis · MEASURE · DETECT · DECOMPOSE

    Calculate the numbers

    Every number is made here, by the database, not by a model. SQL computes each figure, tests a change against its own noise and splits it by who caused it. Each number is stored as a fact with an id, its query and the rows it read.

    No model: plain code.

    Revenue, 2026-03
    $44,100 N12
    Revenue, 2026-04
    $36,200 N11
    Change
    −$7,900 N29 −17.9% N30
    By channel: wholesale
    −$8,500 N144 108% N147

    Learn: Analysis

  6. Station 05 · Index docs · INDEX_DOCS

    Make documents searchable

    Makes your documents and emails searchable. Passages keep their exact source text, page and position. Text addressed to a model is screened and locked away first.

    No model: plain code.

    Sections indexed
    9
    D1
    email-0412.eml
    D7
    price-list.pdf

    Learn: Retrieval · Security

  7. Station 06 · Web lane · WEB_CONTEXT

    Look things up online

    Optional: outside context, such as an industry benchmark. Before any search leaves your computer, customer names and amounts are removed from it; fetched pages are read only by the quarantined extractor.

    No model: plain code.

    W1
    coffee-benchmarks.example
    Gap to the benchmark
    1.4 pp N270
    Source
    offline web fixture (coffeeWeb)

    Learn: Web lane · Security

  8. Station 07 · Explain

    Find out why

    A model looks for why things changed. It sees the list of facts with their ids, never the raw data, and works through a few fixed tools. It writes {{N…}} placeholders, never a number.

    Calls a model: the planner and extractor.

    Cause found in
    D1 · email-0412.eml
    Graded
    document supported

    Learn: The planner (agent) · Security

  9. Station 08 · Decide

    Suggest what to do

    A model suggests what to do next. What each action could be worth is a range computed by code, with the metric and the date that will show whether it worked.

    Calls a model: the planner.

    Top action
    Offer wholesale accounts a volume-tier discount to win back paused standing orders
    Impact, next quarter
    $3,995 N350 $7,191 N351
    Checked later by
    revenue >= $44,100 by 2026-09-30

    Learn: The planner (agent)

  10. Station 09 · Verify

    Check everything

    Nothing reaches you until it passes. Its checks recompute every number from its SQL, find every quote in its file and drop or reword any claim they can't prove. A small judge model only confirms that a quote supports its claim.

    Calls a model: the judge.

    Numbers recomputed
    101 · 0 mismatched
    Citations checked
    6
    Claims dropped · reworded
    2 · 2

    Learn: The verifier (V1–V8)

  11. Station 10 · Render

    Write the report

    Builds the final report. Each placeholder is filled with its checked fact; in the report, any number opens how it was computed.

    No model: plain code.

    Headline
    Revenue fell after March, driven by wholesale (a change of −$7,900).

    Learn: Report & fact IDs

Beside the line

  • Beside the line · Workspace · job.duckdb

    The job's database file

    One DuckDB file per job, where every station saves its work. Tables, facts, document passages, claims and checks live in it, and each stage is checkpointed there, so a job that stops resumes where it was.

    No model: plain code.

    Events recorded
    31

    Learn: Report & fact IDs

  • Beside the line · Model room · planner · extractor · judge

    The AI models

    Where the models work, each with one narrow job, behind glass. The planner drafts definitions, causes and actions; the extractor alone reads untrusted text; the judge checks quotes. They run on free endpoints or your own machine.

    The models themselves.

    In this run
    scripted planner (coffeePlanner), no LLM

    Learn: Model router & free providers · Security

§1 How it works

What one run produced, stop by stop.

The files it read, the SQL it ran, the figures and the checks, from the same run.

One real run · examples/coffee-roaster · scripted planner, no LLM

01 Files INGEST

File Kind Read as
email-0412.eml email headers and body
ops-notes.docx document text, by section and page
price-list.pdf document text, by section and page
sales-2026.xlsx table sheets, split into table regions

02 Profile PROFILE

Tables
3
Document sections
9
Data-quality issues
3

Every column gets a role and a type before anything is measured; the issues go into the report.

03 Metric METRICS_DRAFT

revenue = sum of amount, per month · USD · assumed

Drafted in plain words and YAML, confirmed or assumed, then compiled to SQL:

SELECT strftime("date", '%Y-%m') AS period, sum("amount") AS value
FROM "t_t1"

04 SQL MEASURE · DETECT · DECOMPOSE

Revenue, 2026-03 $44,100 N12
Revenue, 2026-04 $36,200 N11
Change −$7,900 N29
Change, percent −17.9% N30
By channel: wholesale −$8,500 N144
Wholesale's share of the change 108% N147

05 Evidence INDEX_DOCS · WEB_CONTEXT · EXPLAIN · DECIDE

  • After the new price list we are pausing our standing order while we compare suppliers. D1 email-0412.eml · Purchasing, Hotel Group · Standing order · document supported
  • Wholesale prices increase 12% from 15 March 2026. D7 price-list.pdf · p.2 · correlated
  • Specialty coffee roasters typically see refunds of 1–2% of sales. W1 external · coffee-benchmarks.example · a benchmark page from this run's offline web fixture, compared with the run's own numbers, never in place of them

06 Verify VERIFY

  • V1 placeholders ran 19 times · pass
  • V2 recompute ran 101 times · pass
  • V3 re-derive ran 3 times · pass
  • V4 definitions ran 18 times · pass
  • V5 citations ran 73 times · pass
  • V6 causal ran 18 times · 2 caught
  • V7 grounding ran 2 times · pass
  • V8 external ran 18 times · pass

101 numbers recomputed, 0 mismatched · 6 citations checked · 2 claims dropped, 2 downgraded

07 Report RENDER

Revenue fell after March, driven by wholesale (a change of −$7,900).

#1 action of 2 · medium confidence Offer wholesale accounts a volume-tier discount to win back paused standing orders: +$3,995 N350 to +$7,191 N351 , next quarter.

Checked later against: revenue >= $44,100 by 2026-09-30

§2 Why it's different

Built so you don't have to take its word for it.

Three rules the engine can't break.

  • 01 · Arithmetic

    The model never does arithmetic

    The model writes placeholders; every figure is a fact computed by SQL or a deterministic function, then recomputed.

    The model writes

    Revenue went from {{N12}} in 2026-03 to {{N11}} in 2026-04 (a change of {{N29}}, {{N30}}).

    You read

    Revenue went from $44,100N12 in 2026-03 to $36,200N11 in 2026-04 (a change of −$7,900N29, −17.9%N30).

    The pipeline
  • 02 · Definitions

    Definitions you confirm

    Each metric is drafted in plain words and YAML before anything is measured. You accept, edit or drop it.

    revenue: sum of amount, per month · assumed · compiles to

    SELECT strftime("date", '%Y-%m') AS period, sum("amount") AS value
    FROM "t_t1"
    The metric layer
  • 03 · Citations

    Every claim is cited

    Causes come from your documents, quoted exactly and checked against the source, and graded by how strong they are.

    After the new price list we are pausing our standing order while we compare suppliers. D1 email · email-0412.eml

    The verifier

§3 Results, as they are

Measured, with the caveats next to the numbers.

Real public data first; a run with jobs missing is labelled, not hidden.

Metric · bar Real public data 4 datasets, checked against SQL written separately 4/4 jobs · 2026-10-23 Free-tier model, smoke qwen/qwen3.8-27b on Groq, small-model mode 3/3 jobs · 2026-10-16 Nightly regression 30 generated businesses, same roles, over up to two nights 30/30 jobs · 2026-10-21 Offline baseline scripted heuristic, no LLM: checks the harness 30/30 jobs · 2026-10-21
Planted recall@5 bar ≥ 80% 18/20 checks against SQL written separately Scored by its own checks instead: real files have no planted events. 80.0% meets the bar 68.0% below bar 96.0% meets the bar
Distractor FP rate bar ≤ 10% 0.0% meets the bar 0.0% meets the bar 0.0% meets the bar
Driver accuracy bar ≥ 90% 100.0% meets the bar 100.0% meets the bar 100.0% meets the bar
Cause grade accuracy bar ≥ 80% 75.0% below bar 67.6% below bar 100.0% meets the bar
Citation precision bar ≥ 95% 100.0% meets the bar 100.0% meets the bar 100.0% meets the bar
Recommendation relevance bar ≥ 70% 66.7% below bar 30.0% below bar 100.0% meets the bar
Number mismatches bar 0 0 meets the bar 0 meets the bar 0 meets the bar

Real public data is checked against SQL written separately; a free-tier model then runs the smoke suite. The generated businesses with planted events are the nightly regression check, run over up to two nights within the free tier's quota; the latest published run is shown, labelled partial only if jobs are still unfinished after its second night. The offline baseline is a scripted heuristic tuned on the same datasets, so its scores are optimistic: it tests the engine and the harness, not model quality. All results (RESULTS.md) · How quality is measured

Sources: 4 result files
  • evals/results/2026-10-23-baseline-real.json
  • evals/results/2026-10-16-configured-small-smoke.json
  • evals/results/2026-10-21-configured-small-full.json
  • evals/results/2026-10-21-baseline-full.json

§4 Quickstart

Run it on the example, then on your files.

Install, pick a free model, analyze the example.

  1. Step 1 · Install

    git clone \
      https://github.com/gfirik/agentic-analytics
    cd agentic-analytics
    bun install
    bun run aa doctor

    Node 22 and Bun. doctor says what this machine has.

  2. Step 2 · Model

    # Ollama, or a free endpoint in .env
    cp .env.example .env

    Free and local only: Ollama or a free OpenAI-compatible endpoint. Running free

  3. Step 3 · Analyze

    bun run aa analyze \
      examples/coffee-roaster --open
    # no model yet? replay it offline
    AA_DEMO_MODEL=scripted \
      bun run aa analyze \
      examples/coffee-roaster \
      --yes --embedder hash

    The report opens with every number linked to its working.

Standalone binaries · Docker

No Node or Bun needed: attached to each tagged release, from v0.1.0 on, with a checksum file. Releases

  • aa-linux-x64
  • aa-linux-arm64
  • aa-macos-arm64
  • aa-windows-x64.exe
  • SHA256SUMS

docker compose up · API, viewer and MCP on http://127.0.0.1:8080

Four doors, one engine

  • CLI Analyze files, ask follow-ups, open the working behind any number. aa analyze ./exports --open
  • HTTP API Upload files, stream progress over SSE, fetch the report as JSON or HTML. aa serve
  • MCP Claude Desktop, Cursor or any MCP client analyzes files and quotes verified numbers. aa mcp
  • Telegram A demo bot: send files, get the summary and the report back. bun run --filter @agentic-analytics/telegram start