Skip to content
Sigilbase

Claude Code, Cowork and Codex CLI#

A customer who wants a tamper-evident record of what an AI coding agent did in their estate sets a few environment variables, or an admin sets them once in managed settings, and writes no code. Each event the agent exports becomes one sealed ledger event on a telemetry-class stream. The receiver itself, the mapping and the limits are on OpenTelemetry log receiver; this page is the sources.

Before you start#

  1. Create a stream and choose the Telemetry class. The agent telemetry template pre-fills it.
  2. On the stream's page, create a telemetry key. It is shown once, with the snippet below already filled in.
  3. Decide the privacy flags before the first batch. Retention is forever and redaction is deliberate, declared and permanent, so what arrives is kept.

Claude Code#

Set these in the shell that runs Claude Code:

export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
export OTEL_EXPORTER_OTLP_ENDPOINT=https://app.sigilbase.io/api/v1/otlp
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <telemetry key>"
export OTEL_METRICS_EXPORTER=none

Claude Code appends /v1/logs to the endpoint itself. http/protobuf is accepted in place of http/json.

Managed settings#

To enforce the export across a fleet rather than rely on each developer opting in, put the same variables under env in the managed settings file, which developers cannot override: /Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux, C:\ProgramData\ClaudeCode\managed-settings.json on Windows.

{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "http/json",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "https://app.sigilbase.io/api/v1/otlp",
    "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer <telemetry key>",
    "OTEL_METRICS_EXPORTER": "none"
  }
}

Managed settings make a missing export harder to produce by accident. They do not make it impossible, and the ledger cannot see a gap: see the end of this page.

Privacy flags#

From Claude Code's own documentation:

  • Content is off by default. Prompts, assistant responses and tool inputs arrive redacted unless OTEL_LOG_USER_PROMPTS, OTEL_LOG_ASSISTANT_RESPONSES or OTEL_LOG_TOOL_DETAILS are set. Sigilbase stores what arrives; it does not add or remove content.
  • OTEL_LOG_TOOL_DETAILS=1 adds tool parameters, Bash commands, full error messages and, for a successful git commit, the commit SHA and branch. This is the flag most customers will want: it is what ties an agent action to a change in the codebase.
  • OTEL_LOG_RAW_API_BODIES is discouraged for a Sigilbase stream. Retention is forever and redaction is permanent, so full API bodies belong in a store with a retention policy, not here. A raw body can also exceed the 32 KiB per-event limit, in which case that record is rejected and the rest of the batch stored.

Timing#

Export is batched, every five seconds by default. occurred_at on the event is the agent's own clock (event.timestamp); the receipt time is ours. The verifier reports both, and the ledger vouches for receipt.

Events you will see#

The action of each event is the event.name Claude Code sends, with its claude_code. prefix. From the Claude Code event reference at the time of writing:

Event What it evidences
claude_code.user_prompt A prompt was submitted; its length always, its text only with OTEL_LOG_USER_PROMPTS.
claude_code.tool_decision The agent chose to use a tool, and whether the user allowed it.
claude_code.tool_result A tool finished: which, whether it succeeded, how long it took, and with tool details the parameters, the command, and a commit's SHA and branch.
claude_code.api_request A model request: model, tokens, cost and duration.
claude_code.api_error A model request failed, with the status and the attempt.
claude_code.api_refusal The model declined a request.
claude_code.permission_mode_changed The permission mode changed, which governs what the agent may do without asking.
claude_code.hook_registered, claude_code.hook_execution_start, claude_code.hook_execution_complete A hook was configured and ran, with its outcome.
claude_code.skill_activated A skill was loaded into the session.
claude_code.subagent_completed A delegated subagent finished.
claude_code.mcp_server_connection An MCP server connected or failed to.
claude_code.plugin_loaded A plugin was loaded.
claude_code.compaction The conversation was summarised to make room.

The full attribute list for each event is in the Claude Code monitoring reference; it is not restated here. Every attribute travels verbatim in the event payload under otlp.attributes.

Cowork#

Cowork, Cowork in the cloud and the Office agents export through the Agent SDK with the same event schema as Claude Code. An admin sets the export once for the organisation (Team and Enterprise), putting the telemetry key in the OTLP headers field as Authorization=Bearer <telemetry key>; the resource service.name is cowork.

Two things differ from Claude Code. On first-party deployments the metadata always carries user.email and workspace.host_paths. And the otlpContentCapture device key is not set by default, which means prompt text, response text and tool inputs are exported unless the admin sets it to []. Because Sigilbase retention is forever and redaction is permanent and declared, decide the content key before pointing the endpoint at Sigilbase. The metadata-only setting is:

{ "otlpContentCapture": [] }

Codex CLI#

Codex CLI configures OpenTelemetry in config.toml. The endpoint must be the full logs URL, protocol is json or binary, the key goes in headers as x-api-key, and log_user_prompt defaults to false.

[otel]
environment = "prod"
log_user_prompt = false
exporter = { otlp-http = { endpoint = "https://app.sigilbase.io/otlp/v1/logs", protocol = "json", headers = { "x-api-key" = "<telemetry key>" } } }

Codex sends conversation.id rather than session.id and no sequence counter, so its events map to resource session:<conversation.id> and take the content-hash form of the idempotency key. Its event names carry the codex. prefix: codex.conversation_starts, codex.user_prompt, codex.tool_decision, codex.tool_result, codex.api_request, codex.sse_event and others. The resource service.name is codex_cli_rs.

Any OpenTelemetry collector#

A collector that forwards logs over OTLP/HTTP works with any of the three header forms. Whatever attributes it forwards travel verbatim; the envelope is derived from the attributes named on the receiver page, and unknown sources map through the fallbacks and are stored.

What a telemetry stream proves#

  • That each record was received by Sigilbase at the stated time, from a holder of the stream's telemetry key, and has not been modified, deleted or reordered since.
  • The order in which records were received, and the order the source claimed through its own sequence numbers.

What it does not prove#

  • That the source emitted every event it could have. Telemetry is produced by a client on the user's machine. A client with export disabled, misconfigured or offline produces no records, and the ledger cannot see the gap. Managed settings make this harder to do by accident; they do not make it impossible.
  • That the content of a record is true. Sigilbase stores what the client sent.
  • The source's claimed time. Sigilbase vouches for receipt time only, and export is batched, so the two differ by seconds in normal operation.