This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
devopscritical PriorityID: opentelemetry-genai-semantic-conventions-production-standard

OpenTelemetry GenAI Semantic Conventions for Heterogeneous LLM Observability

Enforces strict adherence to OpenTelemetry GenAI Semantic Conventions across all LLM inference call sites, agent frameworks, and streaming gateways. Guarantees uniform telemetry capture for token consumption, streaming Time-To-First-Token (TTFT), and agent execution traces to enable accurate cost accounting, auditability, and SLA attribution without leaking unmasked PII.

Prohibited Anti-Pattern: Fragmented Ad-Hoc Span Names, Proprietary Token Metric Keys, and Missing Streaming TTFT Telemetry

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: OpenTelemetry GenAI Semantic Conventions for Heterogeneous LLM Observability - Enforces strict adherence to OpenTelemetry GenAI Semantic Conventions across all LLM inference call sites, agent frameworks, and streaming gateways. Guarantees uniform telemetry capture for token consumption, streaming Time-To-First-Token (TTFT), and agent execution traces to enable accurate cost accounting, auditability, and SLA attribution without leaking unmasked PII.
globs: src/**/{llm,ai,agents,providers,inference,telemetry}/**/*.{ts,js,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/opentelemetry-genai-semantic-conventions-production-standard"
---

# OpenTelemetry GenAI Semantic Conventions for Heterogeneous LLM Observability

> **Severity**: CRITICAL | **Category**: devops
> **Anti-Pattern Warning**: Fragmented Ad-Hoc Span Names, Proprietary Token Metric Keys, and Missing Streaming TTFT Telemetry

## System Constraints
You are a Principal Software Architect and Observability Specialist enforcing the OpenTelemetry GenAI Semantic Conventions. All LLM provider invocations, agent steps, and model gateways MUST produce standardized client spans following OpenTelemetry specifications. Ensure span names follow `{gen_ai.operation.name} {gen_ai.request.model}`, attributes strictly use `gen_ai.*` namespaces, streaming TTFT is accurately captured as a metric or span event, token counts are exhaustively recorded from provider responses or verified fallback tokenizers, and prompt content is conditionally captured only under strict PII-sanitized debug configurations.

## Strict Guidelines
- Engineers MUST ALWAYS name LLM client spans using the format `{gen_ai.operation.name} {gen_ai.request.model}` (e.g., 'chat gpt-4o' or 'generate_content claude-3-5-sonnet') and set SpanKind to SpanKind.CLIENT.
- Engineers MUST ALWAYS set required base attributes: `gen_ai.system` (e.g., 'openai', 'anthropic', 'aws.bedrock'), `gen_ai.operation.name` ('chat', 'text_completion', 'embeddings'), and `gen_ai.request.model`.
- Engineers MUST ALWAYS record token usage attributes upon completion: `gen_ai.usage.input_tokens` and `gen_ai.usage.output_tokens`. If the provider supports cached tokens, capture `gen_ai.usage.cache_read_input_tokens` and `gen_ai.usage.cache_creation_input_tokens`.
- Engineers MUST measure and record streaming Time-To-First-Token (TTFT) on the arrival of the initial stream chunk, attaching the duration in milliseconds to `gen_ai.client.token.time_to_first_token` or emitting a dedicated `gen_ai.client.first_token` event.
- Engineers MUST NOT store raw unmasked prompt inputs or model outputs in span attributes unless explicitly enabled by privacy-compliant data redaction flags under `gen_ai.prompt` / `gen_ai.completion` events.
- Engineers MUST ALWAYS record `gen_ai.response.finish_reasons` as an array of strings (e.g., ['stop', 'tool_calls', 'length']) and appropriately set span status to `StatusCode.ERROR` on failed responses or provider timeouts.
- Services MUST link child agent tool calls or multi-turn reasoning steps to the parent GenAI span via standardized OpenTelemetry trace context propagation.

## Bad vs Good Implementations
### Ad-Hoc LLM Call with Missing Semantic Attributes and Untracked TTFT

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Uses non-standard span naming, default INTERNAL SpanKind instead of CLIENT, proprietary attribute names ('model_name', 'tokens_used'), stores raw prompt without PII guards, fails to measure streaming Time-To-First-Token (TTFT), and does not set standard span error status.
```typescript
import { trace } from '@opentelemetry/api';
import OpenAI from 'openai';

const tracer = trace.getTracer('llm-service');
const client = new OpenAI();

export async function streamChatBad(prompt: string): Promise<string> {
  // ANTI-PATTERN: Non-standard span name and default internal span kind
  return tracer.startActiveSpan('openai-request', async (span) => {
    try {
      // ANTI-PATTERN: Proprietary/fragmented attribute keys and raw prompt leakage
      span.setAttribute('prompt_text', prompt);
      span.setAttribute('model_name', 'gpt-4o');

      const stream = await client.chat.completions.create({
        model: 'gpt-4o',
        messages: [{ role: 'user', content: prompt }],
        stream: true,
      });

      let fullText = '';
      for await (const chunk of stream) {
        // ANTI-PATTERN: TTFT is completely ignored; cannot measure stream latency SLA
        const content = chunk.choices[0]?.delta?.content || '';
        fullText += content;
      }

      // ANTI-PATTERN: Tokens are unrecorded or guessed with non-standard names
      span.setAttribute('tokens_used', fullText.length / 4);
      span.end();
      return fullText;
    } catch (err: any) {
      span.recordException(err);
      span.end();
      throw err;
    }
  });
}
```

#### Production Standard (Correct)
> **Standard**: Adheres strictly to OpenTelemetry GenAI Semantic Conventions: assigns SpanKind.CLIENT, uses `{operation} {model}` naming, records standardized `gen_ai.usage.*` attributes, measures streaming TTFT on first chunk, records finish reasons as an array, and correctly sets SpanStatusCode.
```typescript
import { trace, SpanKind, SpanStatusCode } from '@opentelemetry/api';
import OpenAI from 'openai';

const tracer = trace.getTracer('genai-llm-service', '1.0.0');
const client = new OpenAI();

export async function streamChatGood(prompt: string): Promise<string> {
  const model = 'gpt-4o';
  const operationName = 'chat';

  // INVARIANT: Standardized span name and SpanKind.CLIENT
  return tracer.startActiveSpan(
    `${operationName} ${model}`,
    {
      kind: SpanKind.CLIENT,
      attributes: {
        'gen_ai.system': 'openai',
        'gen_ai.operation.name': operationName,
        'gen_ai.request.model': model,
        'gen_ai.request.temperature': 0.7,
      },
    },
    async (span) => {
      const startTime = performance.now();
      let firstTokenRecorded = false;
      let inputTokens = 0;
      let outputTokens = 0;
      let finishReason: string = 'stop';

      try {
        const stream = await client.chat.completions.create({
          model,
          messages: [{ role: 'user', content: prompt }],
          stream: true,
          stream_options: { include_usage: true },
        });

        let fullText = '';
        for await (const chunk of stream) {
          if (!firstTokenRecorded && chunk.choices[0]?.delta?.content) {
            const ttftMs = performance.now() - startTime;
            span.setAttribute('gen_ai.client.token.time_to_first_token', ttftMs);
            span.addEvent('gen_ai.client.first_token', { 'gen_ai.first_token_duration_ms': ttftMs });
            firstTokenRecorded = true;
          }

          const content = chunk.choices[0]?.delta?.content || '';
          fullText += content;

          if (chunk.choices[0]?.finish_reason) {
            finishReason = chunk.choices[0].finish_reason;
          }
          if (chunk.usage) {
            inputTokens = chunk.usage.prompt_tokens;
            outputTokens = chunk.usage.completion_tokens;
          }
        }

        // INVARIANT: Conformant GenAI Semantic Attributes for usage and lifecycle
        span.setAttribute('gen_ai.response.model', model);
        span.setAttribute('gen_ai.response.finish_reasons', [finishReason]);
        span.setAttribute('gen_ai.usage.input_tokens', inputTokens);
        span.setAttribute('gen_ai.usage.output_tokens', outputTokens);
        span.setStatus({ code: SpanStatusCode.OK });

        return fullText;
      } catch (error: any) {
        span.recordException(error);
        span.setStatus({
          code: SpanStatusCode.ERROR,
          message: error?.message || 'LLM execution failed',
        });
        throw error;
      } finally {
        span.end();
      }
    }
  );
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: OpenTelemetry GenAI Semantic Conventions for Heterogeneous LLM Observability

OpenTelemetry GenAI Semantic Conventions for Heterogeneous LLM Observability defines an industrial-grade behavioral standard for devops engineering. Enforces strict adherence to OpenTelemetry GenAI Semantic Conventions across all LLM inference call sites, agent frameworks, and streaming gateways. Guarantees uniform telemetry capture for token consumption, streaming Time-To-First-Token (TTFT), and agent execution traces to enable accurate cost accounting, auditability, and SLA attribution without leaking unmasked PII. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Fragmented Ad-Hoc Span Names, Proprietary Token Metric Keys, and Missing Streaming TTFT Telemetry Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftFragmented Ad-Hoc Span Names, Proprietary Token Metric Keys, and Missing Streaming TTFT TelemetryCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS name LLM client spans using the format `{gen_ai.operation.name} {gen_ai.request.model}` (e.g., 'chat gpt-4o' or 'generate_content claude-3-5-sonnet') and set SpanKind to SpanKind.CLIENT.

Engineers MUST ALWAYS name LLM client spans using the format `{gen_ai.operation.name} {gen_ai.request.model}` (e.g., 'chat gpt-4o' or 'generate_content claude-3-5-sonnet') and set SpanKind to SpanKind.CLIENT.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST ALWAYS set required base attributes

Engineers MUST ALWAYS set required base attributes: `gen_ai.system` (e.g., 'openai', 'anthropic', 'aws.bedrock'), `gen_ai.operation.name` ('chat', 'text_completion', 'embeddings'), and `gen_ai.request.model`.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST ALWAYS record token usage attributes upon completion

Engineers MUST ALWAYS record token usage attributes upon completion: `gen_ai.usage.input_tokens` and `gen_ai.usage.output_tokens`. If the provider supports cached tokens, capture `gen_ai.usage.cache_read_input_tokens` and `gen_ai.usage.cache_creation_input_tokens`.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Engineers MUST measure and record streaming Time-To-First-Token (TTFT) on the arrival of the initial stream chunk, attaching the duration in milliseconds to `gen_ai.client.token.time_to_first_token` or emitting a dedicated `gen_ai.client.first_token` event.

Engineers MUST measure and record streaming Time-To-First-Token (TTFT) on the arrival of the initial stream chunk, attaching the duration in milliseconds to `gen_ai.client.token.time_to_first_token` or emitting a dedicated `gen_ai.client.first_token` event.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Engineers MUST NOT store raw unmasked prompt inputs or model outputs in span attributes unless explicitly enabled by privacy-compliant data redaction flags under `gen_ai.prompt` / `gen_ai.completion` events.

Engineers MUST NOT store raw unmasked prompt inputs or model outputs in span attributes unless explicitly enabled by privacy-compliant data redaction flags under `gen_ai.prompt` / `gen_ai.completion` events.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Engineers MUST ALWAYS record `gen_ai.response.finish_reasons` as an array of strings (e.g., ['stop', 'tool_calls', 'length']) and appropriately set span status to `StatusCode.ERROR` on failed responses or provider timeouts.

Engineers MUST ALWAYS record `gen_ai.response.finish_reasons` as an array of strings (e.g., ['stop', 'tool_calls', 'length']) and appropriately set span status to `StatusCode.ERROR` on failed responses or provider timeouts.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
7

Services MUST link child agent tool calls or multi-turn reasoning steps to the parent GenAI span via standardized OpenTelemetry trace context propagation.

Services MUST link child agent tool calls or multi-turn reasoning steps to the parent GenAI span via standardized OpenTelemetry trace context propagation.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is OpenTelemetry GenAI Semantic Conventions for Heterogeneous LLM Observability critical for AI coding assistants?

Enforces strict adherence to OpenTelemetry GenAI Semantic Conventions across all LLM inference call sites, agent frameworks, and streaming gateways. Guarantees uniform telemetry capture for token consumption, streaming Time-To-First-Token (TTFT), and agent execution traces to enable accurate cost accounting, auditability, and SLA attribution without leaking unmasked PII. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Fragmented Ad-Hoc Span Names, Proprietary Token Metric Keys, and Missing Streaming TTFT Telemetry) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

OpenTelemetry