Skip to main content
The CLI is intentionally dumb — Claude (or another agent) running in your terminal does the natural-language parsing and constructs structured upstack calls. No LLM ever runs server-side in Upstack.

Example session

> Claude, make me a dashboard with NC ROAS, MER, and Facebook CPM.

$ upstack measures --search "new customer roas"   # confirms core.new_customer_roas
$ upstack measures --search mer                   # core.new_customer_mer
$ upstack measures --search "facebook cpm"        # meta.cpm
$ upstack dashboard view build \
    --name "NC + Meta Pulse" \
    --measures core.new_customer_roas,core.new_customer_mer,meta.cpm
# → Created dashboard view 5f1e6a4f-... "NC + Meta Pulse" with 3 widget(s).
#   Open the dashboard app and select it from the view dropdown.
The agent picks measure ids using upstack measures, then issues a single build call. Same result as the API quickstart, in one structured command.

Filters: discover before you construct

When the user asks for a scoped query — “MER for new customers only”, “spend on Meta campaigns containing ‘spring’”, etc. — the agent should call upstack filters first to enumerate valid filter fields, operators, and contexts before guessing field ids:
> Claude, show me MER for new customers only, last 30 days.

$ upstack filters --search customer --detail   # → orders.customer_type, operators include `equals`/`in`
$ upstack query \
    --measures core.new_customer_mer \
    --granularity day \
    --date-start 2026-04-01 --date-end 2026-04-30 \
    --filter '{"and":[{"field":"orders.customer_type","op":"equals","value":"new_customer"}]}'
The field id (orders.customer_type), its supported operators, and the set of applicable contexts all come from the discovery endpoint — no hard-coding.

Why this works

  • Discovery is free. upstack measures and upstack filters require only analytics:read. An agent can introspect what’s available before constructing a request.
  • The CLI is structured input for the agent’s structured output. Flags are JSON-shaped (--measures m1,m2,m3, --from-file payload.json). No shell-quoting gymnastics for natural-language prompts.
  • Every command can be replayed. Pass --from-file to load a JSON body, then iterate via flags. The agent doesn’t need to remember state — it can re-issue.

What the agent should NOT do

  • Don’t ask the user for their API key over chat. Credentials are already in ~/.upstackrc; the CLI handles auth automatically.
  • Don’t hand-construct API request bodies in chat. Use the CLI as the structured interface — it’s already typed and validated.