CLI

Install and use the definite CLI to operate and exercise an on-prem deployment.

The definite CLI is a single static binary with two layers:

  • Admin / cluster opsinit, upgrade, status, doctor, logs, bootstrap, export-helm. Talks to kubectl and helm against your cluster. These are covered in Agent setup and the per-cloud guides (AWS, GCP, Azure).
  • API clientdefinite run …. Talks to the deployed API over HTTPS using a bearer token. This page is mostly about that layer: querying the lakehouse, loading files, kicking off Fi, managing data apps, and so on.

Installation

The CLI ships as a single static binary. The fastest install is the public installer script — it detects your OS + arch, downloads the matching release, verifies its SHA256, and drops the binary into ~/.local/bin/definite.

curl -fsSL https://storage.googleapis.com/definite-public/definite-onprem/install.sh | sh
definite version

Supports macOS (Intel + Apple Silicon) and Linux (x86_64 + arm64). Override the defaults with env vars:

# Pin a specific version
DEFINITE_VERSION=v0.0.18 curl -fsSL .../install.sh | sh

# Install somewhere other than ~/.local/bin
DEFINITE_BIN_DIR=/usr/local/bin curl -fsSL .../install.sh | sudo sh

Run via Docker (Windows, CI, air-gapped)

If you'd rather not install natively — Windows hosts, ephemeral CI runners, or an environment where you don't want a ~/.local/bin mutation — the same binary is available as a public container image. The tag matches your deployment's API version.

docker run --rm \
  -e DEFINITE_API_URL -e DEFINITE_TOKEN \
  us-central1-docker.pkg.dev/definite-quack-spike/definite-onprem/cli:0.0.18 \
  run query "SELECT 1"

To make it feel like a local install, alias it and mount ~/.definite so definite login (below) persists across runs:

alias definite='docker run --rm -i \
  -v ~/.definite:/root/.definite \
  -e DEFINITE_API_URL -e DEFINITE_TOKEN \
  us-central1-docker.pkg.dev/definite-quack-spike/definite-onprem/cli:0.0.18'

Pin to your deployment's exact tag

To track whatever version the cluster is currently on:

TAG=$(helm get values definite -n definite | awk '/^  tag:/ {print $2; exit}')
DEFINITE_VERSION=v$TAG curl -fsSL \
  https://storage.googleapis.com/definite-public/definite-onprem/install.sh | sh

Authenticate

The API client uses bearer-token auth. Sessions are opaque ~43-character tokens with a ~14-day TTL.

The recommended flow is definite login, which prompts for credentials and writes the session token to ~/.definite/credentials.json (mode 0600). Every subsequent definite run … call picks it up automatically — no flags or env vars needed.

definite login https://your-deployment.example.com
# Email: you@example.com
# Password: ********
# ✓ logged in as you@example.com — credentials saved to ~/.definite/credentials.json

A bare hostname is assumed to be https://; pass an explicit http://… for a TLS-disabled deployment. Other useful forms:

# Non-interactive (CI, scripts) — read the password from stdin
echo "$DEFINITE_PASSWORD" | definite login your-deployment.example.com \
  --email you@example.com --password-stdin

Verify you're logged in:

definite run query "SELECT 1"

Without definite login (env-var fallback)

When you can't (or don't want to) write a credentials file — ephemeral containers, sandboxes, one-off scripts — definite run also honors DEFINITE_API_URL + DEFINITE_TOKEN. Mint a token by calling /api/v1/auth/login directly:

Mint a token
curl -sS -X POST "https://your-deployment.example.com/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "..."}'

The response looks like:

{
  "token": "eyJhbGciOi...",
  "expires_at": "2026-06-10T18:42:11Z"
}
Export it
export DEFINITE_API_URL=https://your-deployment.example.com
export DEFINITE_TOKEN=<paste token>

Explicit --api-url / --token flags on a definite run invocation override both env vars and the stored credentials file.

Verify
curl -sS -H "Authorization: Bearer $DEFINITE_TOKEN" \
  "$DEFINITE_API_URL/api/v1/auth/me"

A 200 with your user record means the token is good. A 401 means it expired or never validated — log in (or mint) again.


Commands

Every definite run subcommand respects DEFINITE_API_URL and DEFINITE_TOKEN. For an exhaustive list of flags, run:

definite run <subcommand> --help

run query

Execute SQL against the lakehouse.

# Inline SQL
definite run query "SELECT 1 AS one, 'hello' AS greeting"

# From a file
definite run query -f path/to/q.sql

# JSON output for jq
definite run query --format json "SELECT now()" | jq

--format defaults to table on a TTY and json when stdout is piped. csv is also valid.

run load

Upload a local file. Two modes:

# Mode 1: just upload to Drive (object storage)
definite run load ./mydata.csv

# Mode 2: upload AND register as a lakehouse table
definite run load ./sales.csv --table analytics.sales --mode replace
definite run load ./more.parquet --table analytics.sales --mode append

When --table is set, --mode is required: either replace (drop and recreate) or append (insert into the existing table). Format auto-detects from the extension (.csv, .parquet, .json, .ndjson, .jsonl) and is overridable with --file-format.

run drive get

Fetch a file back from Drive. Accepts either a full gs://…/drive/<id>/<name> URL or just the bare file id.

definite run drive get gs://your-bucket/drive/abc123/sales.csv
definite run drive get abc123

run app

Manage data apps.

definite run app list
definite run app upload <slug> ./index.html ./app.json
definite run app delete <slug>
definite run app scaffold

run fi

Kick off the Fi agent in a new or existing thread.

# Start a new thread
definite run fi "summarize the orders table" --title "ad-hoc"

# Continue an existing thread
definite run fi "follow-up question" --thread-id <id>

run automation

Trigger a manual run of an automation pipeline by id.

definite run automation run <pipeline-id>

run integration

List, inspect, and test saved integrations. Secrets are never echoed back — inspect shows config shape only.

definite run integration list
definite run integration inspect <id>
definite run integration test <id>

run agent

Manage autonomous agents (long-running, scheduled, or event-driven Fi runners).

definite run agent list
definite run agent show <id>

run script

Manage reusable Python automation scripts.

definite run script list
definite run script run <id>

run maintenance

Run DuckLake table maintenance (compaction, vacuum, expire-snapshots).

definite run maintenance compact <schema>.<table>
definite run maintenance vacuum <schema>.<table>

run event-source

Manage browser-safe event ingest sources.

definite run event-source list
definite run event-source show <id>

run permission

Manage app roles, sharing, and data-access roles.

definite run permission list
definite run permission grant <role> <subject>

Output formats and scripting

Most subcommands take --format table|json|csv. The default depends on context:

  • On a TTY (interactive shell): table.
  • Piped or redirected stdout (CI, scripts, agent sandboxes): json.

That flip means you can pipe straight into jq without specifying --format json every time:

definite run query "SELECT id, total FROM orders LIMIT 5" | jq '.[].total'

Troubleshooting

invalid or expired token from /auth/me

Tokens expire after ~14 days. Run definite login <host> again — the new token overwrites the stored one. If you're on the env-var fallback, re-mint and re-export DEFINITE_TOKEN.

cargo warnings about ~/.cargo/registry/index/.../.cache permissions

Harmless. Only relevant if you ever build the CLI from source on a machine with a partially-shared ~/.cargo. The shipped binary doesn't touch ~/.cargo at runtime.

Connection refused / DNS failure

Sanity-check $DEFINITE_API_URL resolves and is reachable from where you're running the CLI. If your deployment is on private DNS, run the CLI from inside the VPC (a bastion, or a one-off kubectl run pod).


Next

  • Agent setup — let Claude Code, Cursor, or Windsurf drive a fresh install using the admin side of the CLI.
  • AWS install guide — provision with Terraform, install with definite init.