agent-metabase-experimental
v0.3.0
Published
Experimental agent-oriented CLI for driving a Metabase instance.
Maintainers
Readme
agent-metabase-experimental
Experimental. CLI for driving a Metabase instance.
agent-metabase is an agent-oriented command-line interface to the Metabase HTTP API. It's designed to be called by scripts, LLM agents, and CI jobs:
- JSON by default when stdout is piped; human-readable tables in a TTY.
- Deterministic — no interactive prompts. All inputs come from flags, files, or stdin.
- Scriptable — stdin/stdout chain cleanly with pipes, and
http/batchprovide escape hatches to any endpoint that doesn't have a dedicated command. - Two independent auth contexts — a
TARGETinstance you read and write against, and an optionalSOURCEinstance you mirror from.
Install
npm install -g agent-metabase-experimental
agent-metabase --versionRequires Bun ≥ 1.0. The installed binary is agent-metabase (not the package name).
Auth
The CLI talks to up to two independent Metabase instances:
- TARGET — what every command reads from and writes to by default.
- SOURCE — a separate instance (often production) you mirror from into a workspace. Used by
workspace download …,workspace list/get/create/update/delete,workspace provision/unprovision, andworkspace bootstrap. Credentials never cross-fall-back: a missing SOURCE cred hard-errors rather than silently reusing TARGET.
Create API keys at Admin → Settings → Authentication → API Keys.
Environment variables
Read from .env in the working directory or the shell environment:
| Variable | Alias | Role | Required for |
|-------------------------------|--------------------|-------------------------------------------|--------------|
| METABASE_URL | MB_URL | TARGET URL | all commands |
| METABASE_API_KEY | MB_API_KEY | TARGET API key | all commands |
| METABASE_SESSION | MB_SESSION | TARGET session (alternative to API key) | optional |
| METABASE_SOURCE_URL | MB_SOURCE_URL | SOURCE URL | workspace SOURCE commands |
| METABASE_SOURCE_API_KEY | MB_SOURCE_API_KEY| SOURCE API key | workspace SOURCE commands |
| METABASE_SOURCE_SESSION | MB_SOURCE_SESSION| SOURCE session (alternative to API key) | optional |
Example .env:
METABASE_URL="http://localhost:3000"
METABASE_API_KEY="mb_your_target_key"
METABASE_SOURCE_URL="https://prod.metabase.example.com"
METABASE_SOURCE_API_KEY="mb_source_read_only_key"Flag overrides
Every command accepts:
--url,--api-key— override TARGET creds--source-url,--source-api-key— override SOURCE creds (on SOURCE commands)
Resolution order: flags → environment variables → .env in the working directory. Missing TARGET creds fail with a clear error; missing SOURCE creds hard-error without falling back to TARGET.
Verify:
agent-metabase ping
# ok user=Alice <[email protected]> id=1 admin=trueOutput format
Every command supports:
--format [auto|json|text]— defaultauto.--json— shorthand for--format json.
In auto, output is JSON when stdout is piped and a human-readable table when it's a TTY (for list-style commands). Exit codes are consistent:
0— success1— API error (network, HTTP 4xx/5xx, validation, task failure, polling timeout)2— config or usage error (missing creds, bad flag)
Commands that accept a body or SQL (query, http, batch, license set) read from stdin when it isn't a TTY, so piping in files just works:
cat my-query.sql | agent-metabase query --db-id 2Command reference
Every group has --help:
agent-metabase --help
agent-metabase <group> --help
agent-metabase <group> <command> --helpConnectivity & discovery
agent-metabase ping # verify auth
agent-metabase search "revenue" --models card,dashboard --limit 20
agent-metabase activity recents --limit 10
agent-metabase activity popularCollections
agent-metabase collection list
agent-metabase collection get 42 # or 'root' / 'trash'
agent-metabase collection items 42 --models card,dashboard --pinned-state is_pinned
agent-metabase collection tree
agent-metabase collection create "New folder" --parent-id 42Alias: coll.
Cards (questions & models)
agent-metabase card list --f mine
agent-metabase card get 57
agent-metabase card query 57 --limit 20 # preview rows
agent-metabase card query 57 --format csv > export.csv # raw CSV
agent-metabase card query 57 --format xlsx > export.xlsx # raw XLSX
agent-metabase card query 57 --parameters '[{"type":"category","value":"A","target":["variable",["template-tag","c"]]}]'
agent-metabase card create --body '{"name":"x","dataset_query":{...},"display":"table","visualization_settings":{}}'
agent-metabase card archive 57card query supports --format rows|json|csv|xlsx. rows gives a table preview capped at --limit; json returns the full /api/dataset payload with metadata; csv/xlsx stream raw bytes to stdout.
Dashboards
agent-metabase dashboard list --f mine
agent-metabase dashboard get 12
agent-metabase dashboard items 12
agent-metabase dashboard create "Weekly metrics" --collection-id 42Alias: dash.
Databases, tables, fields
agent-metabase db list
agent-metabase db get 2 --include tables.fields
agent-metabase db metadata 2 # full schemas/tables/fields
agent-metabase db schemas 2
agent-metabase db schema-tables 2 public
agent-metabase db sync-schema 2 # trigger schema sync
agent-metabase db rescan-values 2 # rescan cached field values
agent-metabase table list --db-id 2
agent-metabase table get 101
agent-metabase table metadata 101 # fields + FKs
agent-metabase table fields 101
agent-metabase table update 101 --body '{"display_name":"Users"}'
agent-metabase field get 9001
agent-metabase field values 9001
agent-metabase field summary 9001
agent-metabase field update 9001 --body '{"description":"Customer tier"}'Alias: db for database.
Ad-hoc queries
# SQL via flag, file, stdin, or positional
agent-metabase query --db-id 2 --sql "SELECT count(*) FROM orders"
agent-metabase query --db-id 2 --file ./q.sql --format csv > out.csv
cat q.sql | agent-metabase query --db-id 2
# MBQL
agent-metabase query --db-id 2 --mbql '{"type":"query","query":{"source-table":101}}'
# Parameters + template tags (native only)
agent-metabase query --db-id 2 --sql "SELECT * FROM x WHERE y = {{y}}" \
--template-tags '{"y":{"id":"t","name":"y","display-name":"y","type":"text"}}' \
--parameters '[{"type":"category","value":"foo","target":["variable",["template-tag","y"]]}]'--format rows|json|csv|xlsx; --limit caps the rows preview (default 100).
Transforms
agent-metabase transform list
agent-metabase transform get 3
agent-metabase transform run 3 # auto-polls until done
agent-metabase transform run 3 --no-wait # fire and return
agent-metabase transform runs --limit 20 --transform-id 3
agent-metabase transform get-run <run-id>
agent-metabase transform cancel 3transform run polls every 2s (configurable with --interval) up to --timeout ms (default 10 min). Exits non-zero on failed or timeout.
Alias: tx.
Segments, snippets, documents
agent-metabase segment list
agent-metabase segment get 5
agent-metabase snippet list
agent-metabase snippet get 8
agent-metabase document list
agent-metabase document get 17 # alias: docSettings
agent-metabase setting list # admin-only
agent-metabase setting get remote-sync-branch
agent-metabase setting set remote-sync-branch '"main"' # value is parsed as JSON when possibleIf --value parses as JSON it's sent as that value; otherwise it's sent as a raw string.
Users & activity
agent-metabase user current
agent-metabase user list --include-deactivated
agent-metabase user get 3
agent-metabase activity recents --limit 10
agent-metabase activity popularRemote sync
Drives the EE /api/ee/remote-sync endpoints that tie a Metabase instance to a git branch.
agent-metabase sync status # rollup: dirty state, current task, branch
agent-metabase sync is-dirty
agent-metabase sync has-remote-changes
agent-metabase sync dirty # list dirty objects
agent-metabase sync import --branch main # repo → Metabase (auto-polls)
agent-metabase sync import --branch main --force # discard dirty changes (LOSSY)
agent-metabase sync export -m "update dashboards" # Metabase → repo (auto-polls)
agent-metabase sync stash --new-branch wip # export to a new branch
agent-metabase sync current-task
agent-metabase sync cancel-task
agent-metabase sync wait --timeout 300000 # poll an in-flight task
agent-metabase sync branches
agent-metabase sync create-branch feat/xsync import/sync export poll every 2s until the task leaves running. Exits non-zero if the final status is errored, conflict, or timed-out.
Escape hatches: raw HTTP and batched calls
Use these for endpoints that don't have a dedicated command.
agent-metabase http /api/card/57 # GET (default)
agent-metabase http /api/card -X POST --body '{...}'
agent-metabase http /api/card/57 -X PUT --file patch.json
agent-metabase http /api/search -q '{"q":"revenue","models":["card"]}'
agent-metabase http /api/card/57.csv --raw # print response as raw text
cat body.json | agent-metabase http /api/card -X POSTbatch runs many calls in one invocation, sharing auth and base URL:
cat <<EOF | agent-metabase batch
[
{ "method": "GET", "path": "/api/card/57", "id": "card" },
{ "method": "GET", "path": "/api/card/58", "id": "other" },
{ "method": "POST", "path": "/api/card/57/query", "body": {}, "id": "rows" }
]
EOF
agent-metabase batch --file steps.json --parallel # fan out
agent-metabase batch --file steps.json --bail # stop on first error (sequential only)Each step yields {id?, ok, status, data?, error?}. batch exits non-zero if any step fails.
Provisioning a local Metabase from a source
workspace commands let you stand up a local Metabase jar preloaded with metadata, cached field values, and config from a source instance. There are two modes: end-to-end bootstrap and per-step.
End-to-end
The easiest path. Requires an EE source instance with Workspaces enabled and an absolute path to a metabase.jar.
agent-metabase workspace bootstrap my-workspace \
--jar "$PWD/metabase.jar" \
--databases '[{"database_id":2,"input_schemas":["raw_github"]}]' \
--source-url https://prod.example.com --source-api-key mb_source_key
# open http://localhost:3000This will, in order:
- Create the workspace on the source (or reuse it with
--reuse-existing). - Provision every attached database, polling until
:provisioned. - Scaffold
./my-workspace/withagent-metabase.yaml,.env,.gitignore. - Download
metadata.json,field-values.json,config.ymlinto that dir. - Write a
.envthat points TARGET athttp://localhost:<port>using the API key from the config bundle, and preserves your SOURCE creds. - Run a license preflight against the metastore (skip with
--skip-license). - Launch the jar detached, then poll
/api/healthuntil ready.
Per-step
If you want explicit control:
agent-metabase workspace init ./my-workspace --jar "$PWD/metabase.jar"
cd ./my-workspace
# edit .env with TARGET + SOURCE credentials (see auth table above)
agent-metabase workspace create "my-workspace" \
--databases '[{"database_id":2,"input_schemas":["raw_github"]}]'
agent-metabase workspace provision <id> --wait
agent-metabase workspace download all --id <id>
# writes metadata.json, config.yml, field-values.json at the workspace root
agent-metabase workspace instance start
# open http://localhost:3000workspace instance start spawns the jar with MB_TABLE_METADATA_PATH, MB_FIELD_VALUES_PATH, MB_CONFIG_FILE_PATH, and MB_DB_FILE pointed at the downloaded files, so the instance seeds from source on first boot. Use --skip-metadata, --skip-field-values, or --skip-config to omit any one.
Operating the child jar
agent-metabase workspace instance status # not-started | starting | ready | exited
agent-metabase workspace instance logs -n 200 # tail the jar log
agent-metabase workspace instance stop # SIGTERM via pid file
agent-metabase workspace instance current # which workspace is this jar running?
agent-metabase workspace instance remappings # schema input → output mapLocal CLI state lives under the workspace root:
agent-metabase.yaml # CLI config
.env # creds & ports
metadata.json # MB_TABLE_METADATA_PATH
field-values.json # MB_FIELD_VALUES_PATH
config.yml # MB_CONFIG_FILE_PATH
<prefix>-metabase.db.mv.db # MB_DB_FILE (H2)
.metabase-instance.pid # jar PID
.metabase-instance.log # jar stdout/stderrInspect what the jar will see:
agent-metabase workspace config show
agent-metabase workspace config pathsManaging workspaces on the source
agent-metabase workspace list
agent-metabase workspace get <id>
agent-metabase workspace status <id> # per-database provisioning state
agent-metabase workspace update <id> --name "new name"
agent-metabase workspace unprovision <id> --wait # must be :unprovisioned before delete
agent-metabase workspace delete <id>provision/unprovision are async; pass --wait to poll every 3s (up to --timeout, default 10 min) until every database reaches the target state.
Alias: ws.
License token
EE features that the child jar needs (Workspaces, config-text-file, etc.) require a license token. The license group stores it with user-only (0o600) permissions in ~/.agent-metabase/license.json and injects it into the child jar as MB_PREMIUM_EMBEDDING_TOKEN — the token value never appears in arguments, flags, or output.
# Set (token from stdin only — avoids shell history)
echo "$MY_TOKEN" | agent-metabase license set
agent-metabase license status # is a token stored?
agent-metabase license status --check # also validate against metastore
agent-metabase license apply # apply to already-running TARGET
agent-metabase license clear # remove stored tokenlicense status --check returns plan, features, and expiry without ever printing the token value. workspace instance start runs a preflight against the metastore before spawning the jar and errors if required features are missing; use --skip-preflight or --skip-license to bypass.
license apply is only needed for Metabase instances you didn't launch through workspace instance start — when you did, the token was already injected via env var.
More
- Full command list:
agent-metabase --help - Source & issues: https://github.com/metabase/agent-metabase
- License: Apache 2.0
