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

# optional: also register the MCP server (default off)
tablebi install --mcp
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: list what you can connect, then sync it in
tablebi discover ga4 -w acme
tablebi sync --property-id 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 status --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 query --platform tiktok_ads \
  --select "Video views,Profile visits" \
  --group-by "Ad name" -w acme --json
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 -w acme

→ https://console.tablebi.com/d/acme  # 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 =
# ga4 | meta | gsc | google_ads | google_sheets
tablebi discover google_ads -w acme

# set the target on the first sync (persisted afterward)
tablebi sync --customer-id 1234567890 -w acme      # Google Ads
tablebi sync --site-url "sc-domain:acme.com" -w acme # Search Console
tablebi sync --spreadsheet-id <id> --range "Sheet1!A:Z" -w acme

# incremental by default; --full --since to backfill history
tablebi sync -w acme --full --since 2026-01-01

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 --platform search_console -w acme --json
present: query, page, device · not campaign
# what campaigns can I filter on?
$ tablebi values --dimension campaign --search brand -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 report --period last-week -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 schema --platform tiktok_ads -w acme
→ native fields: Video views, Profile visits…
$ tablebi query --platform tiktok_ads \
--select "Video views,Profile visits" \
--group-by "Ad name" -w acme --json
TikTok · by ad · 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 -w acme

# inspect the current dashboard payload
tablebi dashboard show --period auto -w acme --json

# build/edit: read the spec → edit JSON → save it back
tablebi dashboard spec --json > /tmp/spec.json
tablebi dashboard set-spec --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--property-id
Google Search ConsolegscOAuth--site-url
Google Adsgoogle_adsOAuth + dev token--customer-id
Meta AdsmetaOAuth--ad-account-id
Google Sheetsgoogle_sheetsOAuth--spreadsheet-id
TikTok Adstiktok_adsOAuthincremental

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. MCP exists only as a fallback for the rare case the CLI can't express something; register it with tablebi install --mcp. Otherwise, the CLI is the way.

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 meta + encrypted secrets and a hot recent window, so common reads stay fast.

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