Skip to main content

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.
A small set of read-only commands for SREs, governance admins, and on-call engineers to answer “is data flowing?” without opening the web UI. They reuse the same backend the admin oversight dashboard and the per-source detail page already render, so what you see in the terminal and what you see in the browser are guaranteed identical (byte-for-byte on --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 status mirrors 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 --json and is contract-stable against the equivalent tRPC procedure.
These commands are not for end-user developers, they don’t proxy completions, debit budgets, or mutate state. For coding-CLI integration, see Coding CLI Integrations.

Prerequisites

# Authenticate via device-flow OAuth, opens your browser to /cli/auth
langwatch login --device
The same ~/.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.
$ langwatch governance status
Governance setup state
  · Personal VKs
  · Routing policies
  ✓ Ingestion sources
  ✓ Anomaly rules
  ✓ Recent activity (30d)

Governance active: yes
A 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):
$ langwatch governance status --json
{
  "setup": {
    "hasPersonalVKs": false,
    "hasRoutingPolicies": false,
    "hasIngestionSources": true,
    "hasAnomalyRules": true,
    "hasRecentActivity": true,
    "governanceActive": true
  }
}
Pipe to 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.
$ langwatch ingest list
NAME                        TYPE          STATUS  LAST EVENT
Dogfood OTel · alexis lane  otel_generic  active  46m ago
Status colouring:
  • 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:
$ langwatch ingest list --json
[
  {
    "id": "JxQztBgN90QeX12-afJ0C",
    "name": "Dogfood OTel · alexis lane",
    "sourceType": "otel_generic",
    "description": null,
    "status": "active",
    "lastEventAt": "2026-04-27T07:11:19.105Z",
    "createdAt": "2026-04-27T06:25:27.884Z",
    "archivedAt": null
  }
]
The 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.
$ langwatch ingest health JxQztBgN90QeX12-afJ0C
Dogfood OTel · alexis lane  (JxQztBgN90QeX12-afJ0C)
Status:        active
Events (24h):  1
Events (7d):   1
Events (30d):  1
Last event:    47m ago
--json:
$ langwatch ingest health JxQztBgN90QeX12-afJ0C --json
{
  "source": {
    "id": "JxQztBgN90QeX12-afJ0C",
    "name": "Dogfood OTel · alexis lane",
    "status": "active"
  },
  "health": {
    "events24h": 1,
    "events7d": 1,
    "events30d": 1,
    "lastSuccessIso": "2026-04-27T07:11:18.963Z"
  }
}
Useful for a Datadog, Grafana check: pipe 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.
$ langwatch ingest tail JxQztBgN90QeX12-afJ0C --limit 5
2026-04-27T07:11:18.963Z  api.call  chat_completion → claude-3-5-sonnet
Format per row: <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:
langwatch ingest tail JxQztBgN90QeX12-afJ0C --follow
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:
langwatch ingest tail $SRC --follow --json | jq 'select(.action == "chat_completion") | {ts: .eventTimestampIso, model: .target}'
The shape is the canonical 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 (status awaiting_first_event), tail prints a hint pointing at the upstream-platform setup rather than an empty list:
$ langwatch ingest tail brand-new-source-id
No events for this source yet. Once your upstream platform starts
sending OTel/audit logs to /api/ingest/* with the source's bearer
secret, events will land here.

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:
# No ~/.langwatch/config.json or no access_token persisted
$ langwatch governance status
Not logged in, run `langwatch login --device` first

# Source ID doesn't exist (or belongs to a different org)
$ langwatch ingest health does-not-exist
Error: IngestionSource not found

# Access token expired or revoked server-side
$ langwatch ingest list
Error: Session expired, re-run `langwatch login --device`
The 401-on-expired-session path also clears the cached token, so the next invocation lands on the “not logged in” branch and the user sees a clear next step. All three error paths are asserted in specs/ai-gateway/governance/cli-ingest-debug.feature (12 scenarios).

Error catalog

The langwatch 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.
$ langwatch login --device
… opening https://app.langwatch.ai/cli/auth?code=ABCD-EFGH …
Error: HTTP 409, no_default_routing_policy
       Your organization has no default routing policy published.
       Ask your admin to publish one at Settings → Routing Policies
       (/settings/routing-policies), then re-run `langwatch login`.
Admin remediation:
  1. Sign in to the LangWatch web app as an org admin.
  2. Navigate to Settings → Routing Policies (/settings/routing-policies).
  3. Create at least one routing policy and toggle it to Default.
  4. Ask the developer to re-run langwatch login --device.
The CLI does not fall back to a non-default policy; selection is explicit. See the admin prerequisites callout in the AI Governance overview for the rest of the org-bootstrap checklist. The 409 contract is asserted in 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:
GroupToolsWhat’s pinned
Login state gatingclaudelangwatch claude refuses to run when no session is active and prints the correct re-auth hint
Env-var injectionclaude, codex, cursor, gemini, opencodeWrapper 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
Routingclaude, codex, opencodeInbound HTTP request to the fake gateway carries Bearer = the personal Virtual Key minted at login
Budget pre-checkclaudeGateway 402 response surfaces as wrapper exit code 2 (“budget exhausted”); 200 passes through; 5xx surfaces as upstream-failure
Tool-not-foundclaudeWrapper exit code 127 + “binary not found” hint when the wrapped binary isn’t on PATH
Exit-code propagationclaude (0, 42), codex (1)Wrapper returns the wrapped tool’s exit code byte-for-byte
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:
SurfaceAudienceContract
Web /governance admin oversightGovernance admin in a browsertRPC: api.governance.setupState, api.activityMonitor.*, api.ingestionSources.*
Web /settings/governance/ingestion-sources/:id detailPer-source SREtRPC: api.activityMonitor.eventsForSource, api.activityMonitor.sourceHealthMetrics
CLI governance status, ingest list/health/tailTerminal-first SRE, on-callREST: GET /api/auth/cli/governance/*, Bearer adapter that imports the same service classes the tRPC procedures use, byte-for-byte matching IO
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.