Skip to main content
The Moda CLI (@moda-ai/cli, installed as moda) queries your production trace data from the terminal, manages prompt versions, and syncs your harness. This page covers installation, authentication, profiles, output formats, and exit codes. The full command list is in the CLI reference, and agent/CI integration patterns are in Using the CLI from agents and CI.

Install

Requires Node.js 18 or later.

Authentication

The CLI uses two credentials for two different groups of commands: API keys (called ingestion keys in the dashboard) are tenant-bound: a key always operates on the tenant it was created for, and MODA_TENANT_ID cannot re-point it.

Log in (browser flow)

The command opens your browser to moda.dev, where you sign in; the CLI completes a PKCE exchange against a localhost callback (ports 8432–8435, first free port). If the browser cannot reach the CLI — for example when you run the CLI over SSH — paste the callback URL or the one-time code shown in the browser back into the terminal. The resulting CLI session lasts 30 days on a sliding window and renews in the background. Related commands:
  • moda auth status — reports session state; exits 4 when logged out. --online also probes the API.
  • moda auth whoami — shows the authenticated user and available tenants.
  • moda auth token — prints the raw session token (for scripting control-plane calls).
  • moda auth api-key — prints the saved moda_sk_ API key for $(moda auth api-key) and pipes.
  • moda auth logout — revokes the session server-side and clears local credentials, including the stored API key.
The session token authenticates control-plane commands only. Data commands require a moda_sk_ API key: set MODA_API_KEY, or mint one with moda init or moda provision. moda auth token output is not valid for the Data API.

API key resolution order

Data commands resolve the API key in this order:
  1. MODA_API_KEY environment variable
  2. The active profile’s stored key
  3. ~/.moda/config.json (api_key)

Headless provisioning: moda provision

moda provision mints (or reuses) a tenant API key without any interactive prompts and prints exactly one JSON document to stdout — nothing else. It is built for CI bootstrap scripts and agents:
Output
The field names are a stable contract. reused is true when an existing stored key passed a liveness check and no new key was created. Behavior to script around:
  • Provision requires an existing CLI session (moda auth login run previously on that machine) and never opens a browser. Without a session it fails with exit code 4 and instructions to log in first.
  • With access to multiple tenants, --tenant-id (or the MODA_TENANT_ID env var; the flag wins) is required. Without it, provision fails with exit code 5 and a machine-readable input_request that lists every tenant with its resume flags — it never prompts, even on an interactive terminal.
  • --label=TEXT names the key (default: machine hostname). --save also persists the key and tenant to ~/.moda/config.json; by default provision only prints, so headless callers own storage.
Provision’s stdout contains a live API key. Capture it into a secret store or variable; do not pipe it to logs.

Profiles and configuration

CLI state lives in ~/.moda/: config.json (API key, tenant ID, ingest URL), profiles.json, and per-profile secrets under ~/.moda/secrets/. Three profiles exist by default: prod (https://moda.dev, the default), staging, and local.
Select a profile per invocation with --profile=NAME or the MODA_PROFILE env var. Two env vars override URLs directly:
  • MODA_BASE_URL — the moda.dev host used for the Data API and control-plane calls.
  • MODA_INGEST_URL — the Ingestion API host.
A loopback MODA_BASE_URL (localhost, 127.0.0.1, ::1) is used only on a non-prod profile (local, staging, dev). On a prod profile the command fails with exit code 5 (input_required) before sending anything: the CLI never sends a prod profile’s key to a loopback server, and it does not send the request to production in its place. Re-run with --profile=local (or MODA_PROFILE=local) to use the local stack, or unset MODA_BASE_URL to use production. moda config show reports such a URL as refused, and moda auth status --online reports online.baseUrl, the URL every request uses.

Output formats

The CLI picks an output mode automatically, in this priority order:
  1. Explicit flags: --human (or --prose), --json, --agent, --agent --stream
  2. MODA_FORMAT env var: human | json | agent | agent-stream | ndjson
  3. Agent environment detection: a truthy CLAUDECODE, CURSOR, CI, or MODA_AGENT env var selects agent
  4. TTY detection: piped or redirected stdout selects agent; an interactive terminal selects human
The modes: This means a piped or CI invocation gets machine-parseable output with zero flags. These commands bypass envelopes in every mode because their stdout is meant to be captured directly: moda provision (one JSON credentials document), moda auth token / moda auth api-key (the bare credential), and moda tail (NDJSON — one JSON line per event, since a live tail is a stream rather than a single response).

The moda.agent.v1 envelope

In agent mode every command emits a single JSON envelope:
status is ok, degraded, or error; the command’s payload is always under data. The full field reference, the streaming event schema, and exit-code recipes are on Using the CLI from agents and CI. moda manifest --json and moda --json-schemas describe the protocol machine-readably.

Exit codes

Update check and telemetry

Both are on by default and both can be turned off:
  • Update check. At most once a day the CLI checks the npm registry for a newer @moda-ai/cli version and prints a notice to stderr on a terminal; agent envelopes carry it as meta.update. A failed check (offline, unreachable registry) also waits a day before the next try. In agent and JSON modes the check runs in a detached background process, so it never delays a command. Disable with --no-update-check (or --no_update_check) or MODA_CLI_UPDATE_CHECK=0. The check is automatically skipped in CI and when DO_NOT_TRACK=1 is set.
  • Usage telemetry. The CLI reports command name, the names of flags the command accepts (never values or arguments; any other --word is only counted), exit status, and duration. It is sent to the same base URL and with the same key the command uses, and not at all when --profile or MODA_PROFILE names a profile that does not exist. Events wait in a private local file (~/.moda/telemetry/, which never holds the API key) and are sent in batches by one background process once 20 have collected or the oldest is 30 seconds old (every run in CI). Disable with --no-telemetry (or --no_telemetry) for one run, or with MODA_CLI_TELEMETRY=0 or DO_NOT_TRACK=1, which also delete events still waiting to be sent.
  • Feedback tip. Successful commands print a one-line moda feedback tip (stderr on a TTY, meta.tip in envelopes). Hide the stderr line with MODA_CLI_TIPS=0.

Environment variables

Next steps