Documentation Index
Fetch the complete documentation index at: https://langwatch.ai/docs/llms.txt
Use this file to discover all available pages before exploring further.
Pairs with: AI Gateway → CLI Integrations. The
langwatch CLI is shared between Gateway and Governance, login/logout-device 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-device 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:
| Group | Tools | What’s pinned |
|---|---|---|
| Login state gating | claude | langwatch claude refuses to run when no session is active and prints the correct re-auth hint |
| Env-var injection | claude, codex, cursor, gemini, opencode | Wrapper exports the right base-URL + token vars per tool: ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN for claude; OPENAI_BASE_URL + OPENAI_API_KEY for codex; both pairs for cursor + opencode (multi-provider); GOOGLE_GENAI_API_BASE + GEMINI_API_KEY for gemini |
| Routing | claude, codex, opencode | Inbound HTTP request to the fake gateway carries Bearer = the personal Virtual Key minted at login |
| Budget pre-check | claude | Gateway 402 response surfaces as wrapper exit code 2 (“budget exhausted”); 200 passes through; 5xx surfaces as upstream-failure |
| Tool-not-found | claude | Wrapper exit code 127 + “binary not found” hint when the wrapped binary isn’t on PATH |
| Exit-code propagation | claude (0, 42), codex (1) | Wrapper returns the wrapped tool’s exit code byte-for-byte |
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:| Surface | Audience | Contract |
|---|---|---|
Web /governance admin oversight | Governance admin in a browser | tRPC: api.governance.setupState, api.activityMonitor.*, api.ingestionSources.* |
Web /settings/governance/ingestion-sources/:id detail | Per-source SRE | tRPC: api.activityMonitor.eventsForSource, api.activityMonitor.sourceHealthMetrics |
CLI governance status, ingest list/health/tail | Terminal-first SRE, on-call | REST: GET /api/auth/cli/governance/*, Bearer adapter that imports the same service classes the tRPC procedures use, byte-for-byte matching IO |
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.