A deterministic core, four thin outlets
Everything runs through one engine, @tablebi/core. There is no LLM inside it: "what happened" is plain, explainable computation. Connectors pull raw data, normalization unifies the definitions, metrics derive once, and the same numbers feed the narrative, the dashboard spec, and the report.
Pull raw rows from each source.
Map dirty fields to one model.
CTR, CPA, ROAS — defined once.
WoW shifts, top movers, the move.
Branded report, email or Slack.
The outlets — CLI, MCP, HTTP, Web — are thin shells over one shared service layer, so a number is computed the same way no matter how you ask for it.
From a CSV to a weekly report in four commands
Install the workspace, connect a source, and produce a deterministic report — no LLM required.
# install & build
pnpm install
pnpm build
# connect a Meta export — definitions unified automatically
tablebi connect csv --file meta-ads.csv --platform meta_ads
# a deterministic weekly report (WoW shifts + top movers), white-label
tablebi report --template ecommerce --period last-week --brand "Acme DTC"
# quick, deterministic question
tablebi metrics --metric roas --group-by campaign --period last-week
Every read command accepts --json so an agent can parse it. Add tablebi mcp to expose the same engine to Claude Code or Codex as a plugin.
Why the number is defensible
Each platform spells the same idea differently — Meta's "amount spent" is cost, "purchases" are conversions, "purchase value" is revenue. Normalization maps every dirty field to one fact model through synonym mapping and unit/date cleaning. Derived metrics — CTR, CPC, CPM, CVR, CPA, ROAS, AOV — are defined in exactly one place and reused by the CLI, MCP, web and SQL alike.
One fact model
A single daily-grain row: dimensions + base metrics + currency.
One definition
Derived metrics computed in a single function — no drift between outlets.
Zero inference
"What happened" never touches a model. Reliable, explainable, free.
Sources, kept connected
A connector framework handles auth, incremental fetch and an encrypted credential vault, so each source is kept live and refreshed on a schedule — not imported once and forgotten.
| Source | Auth | Status |
|---|---|---|
| CSV / Sheets export | File | Live |
| Google Analytics 4 | OAuth | Live |
| Google Search Console | OAuth | Live |
| Google Ads | OAuth + dev token | In progress |
| Meta Ads | OAuth | In progress |
Credentials are encrypted at rest (pgcrypto). OAuth handles state, exchange and refresh. New sources implement one interface — auth plus incremental fetch — and inherit normalization for free.
Your Claude Code is the brain
TableBI ships the data and the deterministic engine; the reasoning runs on your own agent. The CLI is the primary integration surface — CLI-native agents are great at running commands and need no MCP setup. A bundled skill teaches the agent the metric definitions and the common workflows.
Read with --json
metrics, dashboard show, report and sources all return structured JSON the agent parses directly.
Rewrite the dashboard
The dashboard is a declarative spec. The agent edits the spec via the CLI and the view changes — the engine fills in the data.
MCP is the fallback for the rare case the CLI can't express something. The narrative split is deliberate: deterministic "what happened" ships in the auto-report; "why / what to do" is produced by your agent reading the JSON.
Monday morning, under your brand
One shared scheduler loops over every workspace, checks who is due by weekday and timezone, renders the branded report and delivers it by email or Slack. No process-per-client; no manual send.
# brand, recipients, schedule per workspace
tablebi delivery set --workspace acme \
--brand "Acme DTC" --to founder@acme.com --weekday mon
# send now (dry-run writes to an outbox file)
tablebi send --workspace acme
With no mail credentials the report is written to the workspace outbox; set SMTP_URL and it sends for real. A daily scheduled machine hits /api/cron/send and the app decides who actually goes out.
Deploy it for the price of a coffee
The control-plane app scales to zero when idle; only a small Postgres stays on. Batch work — pulls, weekly sends, backups — runs as scheduled machines billed by the second. Expected ~$5–15/mo on Fly.io, with LLM cost at $0 because the brain is your own agent.