Skip to content

OTel Configuration by Harness

Each agent harness configures OpenTelemetry differently based on the agent CLI's telemetry implementation. The local OTLP collector accepts all signals (metrics, logs, traces) regardless of harness -- the differences are in what the agent exports and what env vars control it.

For the full telemetry architecture (collector, trace completeness, MLflow pipeline), see OTEL Architecture.

Claude Code

Claude Code has its own telemetry system that exports via the standard OTLP protocol.

Variable Value Purpose
CLAUDE_CODE_ENABLE_TELEMETRY 1 Master switch for telemetry export
OTEL_METRICS_EXPORTER otlp Export metrics (token counts, cost)
OTEL_LOGS_EXPORTER otlp Export log events (API requests, tool decisions)
OTEL_TRACES_EXPORTER otlp Export trace spans (tool calls, LLM requests)
OTEL_EXPORTER_OTLP_PROTOCOL http/json OTLP wire format
OTEL_EXPORTER_OTLP_ENDPOINT http://...:{port} Collector address
OTEL_BSP_SCHEDULE_DELAY 1000 Flush spans every 1s. Reduces span loss on container crash vs the default 5s.
OTEL_METRIC_EXPORT_INTERVAL 10000 Export metrics every 10s. Controls Claude Code's OTel metrics SDK export frequency.
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA 1 Rich span hierarchy with tool nesting and subagent spans
OTEL_LOG_USER_PROMPTS 1 Include user prompt text in spans
OTEL_LOG_TOOL_DETAILS 1 Include tool input parameters in spans
OTEL_LOG_TOOL_CONTENT 1 Include tool output/results in spans
TRACEPARENT 00-{trace_id}-{span_id}-01 W3C Trace Context. If the agent's OTEL SDK respects it, spans parent under the orchestrator's root span.

OpenCode

OpenCode uses the Vercel AI SDK's OpenTelemetry integration. OTel must be enabled in opencode.json (experimental.openTelemetry: true) in addition to the env vars — the harness writes this config automatically via write_sandbox_config().

Variable Value Purpose
OTEL_EXPORTER_OTLP_ENDPOINT http://...:{port} Collector address
OTEL_EXPORTER_OTLP_PROTOCOL http/json OTLP wire format
OTEL_BSP_SCHEDULE_DELAY 0 Flush spans immediately. Required because OpenCode calls process.exit() which kills the Node.js process before the OTel batch span processor can drain its queue. Without this, spans are lost.
TRACEPARENT 00-{trace_id}-{span_id}-01 W3C Trace Context. Same as Claude Code.

Not set:

  • CLAUDE_CODE_ENABLE_TELEMETRY — Claude-specific, not used by OpenCode
  • OTEL_METRICS_EXPORTER / OTEL_LOGS_EXPORTER — OpenCode doesn't export metrics or logs via OTel. Cost and token data come from JSON stdout events (step_finish type), not from the OTel pipeline.
  • OTEL_METRIC_EXPORT_INTERVAL — no OTel metrics to export
  • OTEL_LOG_USER_PROMPTS / OTEL_LOG_TOOL_* — Claude-specific flags

Codex

Codex configures OTel through its [otel] configuration rather than standard OTel environment variables. For each run, the Codex harness passes -c overrides for three OTLP/HTTP JSON exporters:

Signal Endpoint
Logs http://...:{port}/v1/logs
Metrics http://...:{port}/v1/metrics
Traces http://...:{port}/v1/traces
Variable Value Purpose
TRACEPARENT 00-{trace_id}-{span_id}-01 W3C Trace Context. Codex parents its exec root span under it, so its spans join the agentic-ci root trace. Spans Codex spawns without context propagation (auth, code_mode.broker.invoke_tool) still start their own traces.

The log stream includes API requests, response events with token counts, tool decisions/results, and redacted prompt metadata. User prompt content remains disabled by default. The metrics stream includes Codex API, streaming, and tool counters and duration histograms. Exporters flush when Codex shuts down.

Codex reports token usage rather than dollar cost. agentic-ci estimates USD cost from a generated snapshot of LiteLLM's OpenAI model-price map, including cache and priority/flex service-tier rates. make update-cost-map resolves LiteLLM main to an immutable commit SHA, fetches the map from that revision, and records the SHA alongside the generated pricing data. Set AGENTIC_CI_LITELLM_COST_MAP to a path containing a LiteLLM-format JSON map to override the bundled snapshot. Token usage is still shown when a model has no known price; the cost table omits that model.

The endpoint host is backend-specific: loopback for local and host-networked Podman runs, and host.openshell.internal for OpenShell.

Sandbox config

The opencode.json config is written by write_sandbox_config() and mounted into the container by the backend:

  • Podman: mounted as a read-only volume via sandbox_config_mounts()
  • OpenShell: uploaded and moved into place via _upload_sandbox_config()

Claude Code and Codex do not require a mounted sandbox config for OTel. Claude Code uses environment variables; Codex receives per-run CLI config overrides.