Skip to main content

Normalization Rules

Beacon normalizes OTLP attributes and hook payloads into the same event contract. The collector exporter looks for common runtime fields, while hook telemetry builds those fields directly from hook payloads.

Source mapping

OpenCode plugin mapping

OpenCode’s managed plugin maps chat.message to prompt.submitted; tool.execute.before to tool.invoked; and successful terminal tool events to command.executed, file.read, file.modified, mcp.tool_invoked, or tool.completed according to tool semantics. Terminal tool errors become tool.failed. Completed assistant message metadata supplies model, finish reason, runtime-reported cost, and canonical gen_ai.usage. Completed text and reasoning parts use gen_ai.output.messages; reasoning additionally uses agent.reasoning. Permission replies map once and always to approval.allowed, reject to approval.denied, and unknown states to approval.requested. Structured session.diff arrays emit file events only for entries containing a real path and change. Empty/cumulative duplicate diffs do not create pathless file.modified records.

OpenTelemetry GenAI fields

Beacon preserves OpenTelemetry GenAI semantic convention fields under the nested gen_ai object and also projects selected fields into Beacon’s common investigation fields. This keeps the raw GenAI context available without forcing downstream rules to parse runtime-specific attribute names.

Request and response metadata

Usage metadata

Usage also arrives as metric datapoints, not just span and log attributes. Claude Code’s claude_code.token.usage and claude_code.cost.usage and Codex’s codex.turn.token_usage are expanded per datapoint and mapped into the same gen_ai.usage fields by their token_type (for example Codex cached_input maps to cache_read.input_tokens and reasoning_output to reasoning.output_tokens; rollup types such as total are ignored). gen_ai.usage.cost_usd carries runtime-reported cost only and is never derived from a local pricing table. See How token attribution works for how these normalized fields aggregate into local reports.

Prompt and content handling

Prompt text can come from gen_ai.prompt, prompt, user_prompt, input.prompt, copilot_chat.user_request, or the first meaningful text value in gen_ai.input.messages. Empty input message arrays do not create prompt events by themselves. Beacon accepts empty content.retention values for compatibility with older records. Truncation can be represented by top-level field_truncated and, for event-specific content state, content.truncated.

Category inference

When a runtime omits event.category, Beacon infers it from event.action:

Unified telemetry schema

Return to the schema overview.

Schema fields

Review entities, optional context, and shared top-level fields.

Open Source Architecture

See where normalization fits in the local telemetry architecture.