Documentation · the CLI

Drive it from
your own
Claude
Code.

TableBI is a CLI your agent drives. Pipe every source into one trusted set of numbers (口径) and the lossless raw underneath; Ask in two altitudes; Pin a live dashboard that refreshes itself. Every command speaks --json. No LLM inside — your agent is the brain.

$0 inference Numbers are deterministic & traceable Pipe · Ask · Pin
~/clients/acme · zsh ● cli
$ tablebi install
✓ skill planted → ~/.claude/skills
$ tablebi context --json
口径 · sources · freshness · overview
$ tablebi metrics --metric roas \
--group-by channel --json
blended, cross-channel, trusted
01 · Quickstart

From zero to a live dashboard

Five moves: plant the skill, connect a source, rehydrate, ask in both altitudes, pin it live. Run them yourself, or just tell your agent what you want — once the skill is installed it knows the commands.

01 Install

Plant the skill

Drops a skill into Claude Code (~/.claude/skills) or Codex (~/.agents/skills) so the agent knows TableBI exists and when to reach for it. Binary on PATH ≠ agent knows it.

terminal
# teach your agent the CLI exists + how to drive it
tablebi install

# also plant it for Codex
tablebi install --codex
02 Pipe

Connect a source

A CSV is one shot. Live sources connect once via the web OAuth flow, then sync pulls them into facts — 口径-normalized, raw kept, refreshed on a schedule.

terminal
# one-shot: a Meta export, definitions unified on ingest
tablebi connect csv --file meta-ads.csv --platform meta_ads -w acme

# live: connect walks the OAuth flow, lists targets, then syncs
tablebi connect ga4 -w acme
tablebi sync ga4 --account 123456789 -w acme
03 Rehydrate

Start every session here

context returns the 口径 definitions, connected sources, freshness, a data overview, and the command cheatsheet — in one call. status shows what needs you.

terminal
# the live manifest: 口径 + sources + freshness + overview
tablebi context -w acme --json

# what's pending: reports due, stale / unsynced sources
tablebi context --json
04 Ask

Both altitudes

metrics for the trusted, cross-channel 口径 view; query --platform for a single platform's native fields at full granularity. Same data underneath.

terminal
# 口径 — unified, cross-channel, trusted
tablebi metrics --metric roas --group-by channel \
  --period last-week -w acme --json

# raw — native, single-platform, full granularity
tablebi ask -w acme --json \
  "SELECT campaign, SUM(clicks) AS clicks, SUM(impressions) AS impressions
   FROM meta_ads_raw GROUP BY campaign ORDER BY clicks DESC LIMIT 10"
05 Pin

Publish it live

dashboard publish hands back a hosted read-only URL. It stores the query (the spec), not a snapshot — so it refreshes itself every time the data does.

terminal
# publish a hosted, self-refreshing dashboard URL
tablebi dashboard publish dsh_7f2a… -w acme

→ https://acme.tablebi.com/d/dsh_7f2a…  # read-only, live

One workspace = one client/brand (default default). Most commands take -w <ws>. Every read command accepts --json — so your agent parses, never guesses.

02 · The contract

What TableBI does, and what your agent does

TableBI gives you trustworthy numbers — it does the data cleaning, the 口径 unification, and the freshness accounting — plus the lossless raw underneath. The reasoning runs on your own Claude Code. The line is clean, and it never blurs.

TableBI provides
  • Deterministic numbers: cleaning, 口径 unification, WoW math.
  • Lossless raw: every native record kept, queryable.
  • Trust metadata: freshness + the 口径 lineage on every number.
  • Managed connectors, sync, and a live dashboard URL.
Your Claude Code provides
  • The analysis: why it changed, what to do next.
  • Reading the JSON and reasoning over it.
  • Picking the altitude per question (口径 vs raw).
  • The brain. $0 inference — your key, your agent.

Numbers come from the CLI, never from the model — so they're reproducible and traceable. Every --json payload carries a trust block: freshness per source, and the lineage (each metric's formula) to cite when you explain a result.

03 · Pipe · connect

Connect once, kept synced

CSV is one-shot. Live connectors are authorized once via the web OAuth flow, then synced into facts on a schedule — incremental by default, --full to re-pull. Set the per-source target on the first sync; it persists after.

connect & sync
# list connectable accounts — provider =
# gsc | ga4 | google_ads | meta_ads | csv
tablebi connect google_ads -w acme

# pick the target when an account has more than one
tablebi sync google_ads --account 1234567890 -w acme      # Google Ads
tablebi sync gsc --site "sc-domain:acme.com" -w acme      # Search Console
tablebi connect csv --file spend.csv --platform tiktok_ads -w acme

# incremental by default; --days widens the backfill window
tablebi sync gsc --site "sc-domain:acme.com" --days 90 -w acme

Data lags are real and TableBI accounts for them: Search Console finalizes ~2–3 days late; Meta re-attributes conversions over a trailing ~7-day window (sync re-pulls it automatically). Don't report "today/yesterday" as complete — check freshness first. Google Ads needs GOOGLE_ADS_DEVELOPER_TOKEN in the environment.

04 · How your agent learns the data

It interrogates the data before it queries

An agent only knows what's in its context — and capabilities and data detail live in the CLI, not in this page, so they never drift. The loop, cheapest first: rehydrate with context, then interrogate the warehouse with schema, values, sample. Output is always bounded — safe to read into context.

tablebi context

Rehydrate

口径, connected sources, freshness, data overview, command cheatsheet — one call.

tablebi schema

See the fields

Dimensions + metrics (口径) with a present flag, plus nativeFields per platform. --stats adds counts.

tablebi values

See the values

The distinct values a dimension takes (bounded top-N by volume), so filters hit real data. --search to find one.

tablebi sample

See the shape

A few real rows at full grain, so the agent reads the actual value shapes before it writes a query.

# which fields does Search Console actually expose?
$ tablebi schema -w acme --json
present: query, page, device · not campaign
# what campaigns can I filter on?
$ tablebi values --dimension campaign -w acme --json

This is the discovery layer under Pipe → Ask → Pin. Because the CLI is its own source of truth — context, --help and schema are generated from the code and your live warehouse — the agent reads current capabilities, not a doc that rots.

05 · Ask · two altitudes

Trusted numbers. Full granularity. Both.

Two altitudes over the same files. Your agent moves between them in one breath: 口径 for the cross-channel story, raw when it needs a platform's own metric. Nothing is thrown away at ingest — you never trade trust for power.

口径 · unified · cross-channel · trusted

One set of numbers
you can trust.

One definition of cost, conversions, ROAS — reconciled across every platform. The number you quote the client.

$ tablebi metrics --metric roas \
--group-by channel --period last-week \
-w acme --json
$ tablebi metrics --metric roas --period 2026-01-01:2026-01-31 -w acme --json
Blended ROAS · by channelall sources
Prospecting4.6×
Retargeting3.9×
Brand Search0.9×
raw · native · single-platform · lossless

The platform's own
fields, intact.

Every native column the platform reports. Full granularity — and not raw SQL: it's a structured, single-platform, 口径-safe surface.

$ tablebi sample -w acme --json
→ native fields: Video views, Profile visits…
$ tablebi ask -w acme --json \
--select "Video views,Profile visits" \
--group-by "Ad name" -w acme --json
Meta Ads · by campaign · nativesingle source
Ad nameVideo views
Hook A154,900
Hook B126,500
Altitude Answers Command
口径 · unified Overall? Blended ROAS? Cross-channel compare? metrics · report · dashboard
raw · native This platform's own metric, at full granularity? query --platform --select

Cross-platform blending always goes through metrics, never raw. Dimensions: date · platform · account · campaign · adGroup · ad · channel · country · query · page · device (query/page/device = Search Console / organic). Periods: auto · last-7-days · last-14-days · last-30-days · last-month · all · YYYY-MM-DD:YYYY-MM-DD.

06 · Pin · publish

Pin a dashboard that refreshes itself

A pinned dashboard is a spec — declarative widgets — not a snapshot. Publishing hands back a hosted, read-only URL; the engine re-runs the query every time the data moves, so the link is always live. You build and edit it from Claude Code by editing the spec.

publish & edit the spec
# publish → a hosted, self-refreshing read-only URL
tablebi dashboard publish dsh_7f2a… -w acme

# inspect the current dashboard payload
tablebi dashboard show dsh_7f2a… -w acme --json

# build/edit: read the spec → edit JSON → save it back
tablebi dashboard spec dsh_7f2a… -w acme --json > /tmp/spec.json
tablebi dashboard set-spec dsh_7f2a… --file /tmp/spec.json --confirm -w acme

Widgets are { id, type: kpis|timeseries|breakdown, title, metrics?, dimension?, limit? }. Convenience commands: dashboard add-widget, remove-widget, reset --template ecommerce|saas|agency|seo. Changing the spec changes the 口径, so it's gated — without --confirm, set-spec only previews the change. The web UI renders whatever spec is saved; the entry point stays the agent, not a GUI.

07 · Connectors

Sources, kept connected

Connectors handle auth, incremental fetch and an encrypted credential vault, so each source stays live and refreshed — not imported once and forgotten. CSV is one-shot; the rest connect once via OAuth, then sync.

Source Provider Connect via First-sync target
CSV / exportFile--platform
Google Analytics 4ga4OAuth--account
Google Search ConsolegscOAuth--site
Google Adsgoogle_adsOAuth + dev token--account
Meta Ads betameta_adsOAuth--account
CSV uploadcsvfile--file --platform
Google Sheets · TikTok Adson the roadmapnot shipped

Sheets map row 1 as headers into the 口径 like a CSV (--range "Sheet1!A:Z", default = first tab). Google Ads MCC routing uses GOOGLE_ADS_LOGIN_CUSTOMER_ID. New sources implement one interface — auth plus incremental fetch — and inherit 口径 normalization for free.

08 · Bring your own agent

Claude Code or Codex. Your brain, your key.

TableBI ships the data and the deterministic engine; the reasoning runs on your own agent. The CLI is the primary surface — CLI-native agents are great at running commands and need no setup. tablebi install plants the skill so the agent learns the commands, the 口径, and the workflows.

Claude Code

Skill lands in ~/.claude/skills. Your agent reads context first, then drives the CLI in plain English — no prompt-engineering.

Codex

Skill lands in ~/.agents/skills (with an AGENTS.md). Same CLI, same 口径, same --json contract.

We host no LLM. Inference is $0 and numbers are deterministic & traceable — they come from the CLI, not a model. An MCP entrance is on the roadmap for hosts that can't run commands; today the CLI is the only surface.

09 · Architecture

A deterministic engine. No LLM inside.

"What happened" is plain, explainable computation — connectors pull raw data, normalization unifies the definitions, metrics derive once, and the same numbers feed metrics, query, the dashboard spec and the report alike. That's why a number is the same no matter how you ask for it.

01

Facts

Per-tenant Parquet on object storage (Tigris/S3) + a DuckDB pod for the full history — both altitudes (口径 + raw) live here.

02

Metadata

Postgres holds workspaces, sources, dashboard specs and encrypted credentials — small, transactional, nothing heavy.

03

Engine

One shared service layer derives every metric once — deterministic, traceable, $0 inference. The CLI and web are thin shells over it.

Give your Claude Code
a data backend.

Install the skill, connect your sources, ask in two altitudes, pin a live dashboard. Your key, your agent, your numbers.

$0 inference Your agent is the brain Pipe · Ask · Pin