Pairs with: AI Gateway → CLI Integrations. The
langwatch CLI is shared between Gateway and Governance, login and logout are gateway-side, ingest and governance status subcommands are governance-side, both behind the same device-flow OAuth.--json).
When to use
- “Did my OTLP push actually land?”:
langwatch ingest tail <sourceId>and watch events stream as you fire from the upstream platform. - “Why isn’t the source flipping to Active?”:
langwatch ingest health <sourceId>shows 24h, 7d, 30d counts plus the timestamp of the last successful event. - “Has anyone in this org started using governance yet?”:
langwatch governance statusmirrors the OR-of-flags that drives the MainMenu Govern entry promotion in the web app. - “I need machine output for a runbook step, SIEM script”: every command accepts
--jsonand is contract-stable against the equivalent tRPC procedure.
Prerequisites
~/.langwatch/config.json the rest of the governance CLI uses persists the Bearer access token. Token TTL is 1h with a long-lived refresh token; the CLI rotates transparently. langwatch logout server-revokes both.
The ingest and governance subcommands are always registered — langwatch --help lists them once the CLI is installed. Per-account governance entitlement is enforced server-side.
langwatch governance status
The org-level setup-state OR-of-flags. Mirrors api.governance.setupState exactly, same boolean shape that promotes the MainMenu Govern entry from hidden → visible once any 3 of 5 are true.
✓ is a flag the org already qualifies for; a · is one it does not. The bottom line (Governance active: yes/no) is the OR of the five, yes if any of them are on, no otherwise.
--json for machine output (exact contract match with the tRPC procedure):
jq for runbook predicates: langwatch governance status --json | jq -r '.setup.governanceActive'.
langwatch ingest list
The org’s IngestionSources, active by default. Pass --all to include archived rows.
- active (green), events received in the last 30d.
- awaiting_first_event (yellow), secret minted, source created, no events yet.
- archived (grey), soft-deleted, hidden by default.
--json returns the full row shape used by api.ingestionSources.list:
id is the same one you pass to ingest health and ingest tail.
langwatch ingest health <sourceId>
A one-shot snapshot: events received in the last 24h, 7d, 30d, plus the timestamp of the most recent successful event. Wraps api.activityMonitor.sourceHealthMetrics, the same query the per-source detail page’s metric strip uses.
--json:
events24h through jq and alert when it drops to zero on a source you expect traffic from.
langwatch ingest tail <sourceId>
Stream the most recent OCSF-normalised events for a source. Wraps api.activityMonitor.eventsForSource, the same query the per-source detail page renders, so the CLI tail and the web event list show identical data.
<eventTimestamp> <eventType> <action> → <target> $cost <input>/<output> tok. cost and tokens render only when present (gated on the cost-enrichment + token-count attributes the OTel normaliser picks up, gen_ai.usage.cost_usd, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens).
--follow
Polls every 3s for new events newest-first, deduplicating by eventId so re-replays don’t double-print:
Ctrl-C exits cleanly. The follow loop is robust to transient errors, control-plane 5xx prints a yellow warn and retries on the next tick rather than killing the stream.
--json
Each event prints as a single JSON line (NDJSON) so you can pipe to jq or save to a file:
ActivityEventDetailRow, same fields the per-source detail page consumes. Field names are kebab-friendly (eventTimestampIso, tokensInput, tokensOutput, costUsd).
Empty state
If a source exists but no events have landed yet (statusawaiting_first_event), tail prints a hint pointing at the upstream-platform setup rather than an empty list:
Error paths
These commands respect the same auth contract every other governance REST adapter uses; the CLI surfaces the underlying tRPC errors with human-readable wording:specs/ai-gateway/governance/cli-ingest-debug.feature (12 scenarios).
Error catalog
Thelangwatch login flow itself can fail before the device-flow handshake completes if the org isn’t configured for CLI sign-in. Each entry below names the error code returned by /api/auth/cli/personal-virtual-keys/approve, the human-readable hint shown to the developer, and the admin remediation.
409 no_default_routing_policy
Returned when the org has no default routing policy published. The CLI cannot bind the new Personal Virtual Key to a policy without a default, so it refuses to create the VK rather than creating an orphan.
- Sign in to the LangWatch web app as an org admin.
- Navigate to Settings → Routing Policies (
/settings/routing-policies). - Create at least one routing policy and toggle it to Default.
- Ask the developer to re-run
langwatch login --device.
specs/ai-gateway/governance/personal-keys.feature (sign-in scenarios).
CLI wrapper e2e coverage
The five wrapped tools (langwatch claude, langwatch codex, langwatch cursor, langwatch gemini, langwatch opencode) are exercised by a Node-only end-to-end suite at typescript-sdk/__tests__/e2e/cli/governance-wrapper.e2e.test.ts, fake control-plane Express + fake gateway Express + mocked tool binaries on PATH. No Docker, no live LLM, ~3-second total runtime; runs on every PR.
Per-tool assertions:
The behavioral pins live in
specs/ai-gateway/wrapper-e2e/{claude,codex,cursor,gemini,opencode}.feature; the concrete test-shape pin is specs/ai-governance/cli-wrappers/wrap-login-routing.feature.
How it fits
Three surfaces, one backend:
The REST endpoints reuse the existing
validateAccessToken() Bearer helper that’s been in production since the device-flow CLI shipped, so opening this surface doesn’t introduce a new auth path. Per-account governance entitlement is enforced at the endpoint layer.
For the bigger picture, five-tier integration ladder, persona-based routing, the daily-use vs admin-authoring split, see the control plane overview.