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 mapschat.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 nestedgen_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 fromgen_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 omitsevent.category, Beacon infers it from event.action:
Related
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.

