On this page · 12 sections
- What "Development" actually means
- The attributes that carry real weight
- Why the cache attributes pay for the whole exercise
- Span names, kinds and sampling
- Prompts and completions: what changed
- The migration flag, and its one legal value
- A build order that survives the rename
- What is coming, and what is not verified
- India-specific considerations
- FAQ
- How eCorpIT can help
- References
Summary. As of 20 July 2026, not one gen_ai.* attribute in the OpenTelemetry GenAI semantic conventions has reached Stable. Every GenAI document carries the header **Status**: Development, and in OpenTelemetry's own maturity ladder Development sits below Alpha, with the definition stating that a component "SHOULD NOT be used in production" and "MAY be removed without prior notice." The only Stable attributes you will find on a GenAI span are error.type, server.address and server.port, and those are inherited from the core conventions, not written by the GenAI group. Two further facts most write-ups have missed: the conventions moved out of open-telemetry/semantic-conventions into a separate repository, open-telemetry/semantic-conventions-genai, leaving the old opentelemetry.io/docs/specs/semconv/gen-ai/ pages as redirect stubs; and that new repository has published no tagged release at all, shipping from main against schema gen-ai/1.42.0. The core conventions, by contrast, tagged v1.42.0 on 12 June 2026. OpenTelemetry published its own explainer, "Inside the LLM Call", on 14 May 2026.
None of that means you should wait. Token attributes are the cheapest cost-attribution tool you will get, and at Claude Opus 4.8 rates of $5 per million input tokens and $25 per million output tokens, a single mis-scoped agent loop is a line item somebody will ask you about. This is what to instrument now, and how to keep the migration cheap when the spec does settle.
What "Development" actually means
Read the maturity ladder before you read the attribute tables, because the label changes what you should promise your team.
OpenTelemetry's document status definitions place Development below Alpha. Alpha components are "ready to be used for limited non-critical production workloads". Development components carry stronger warnings: configuration "might break often depending on how things evolve", the component "SHOULD NOT be used in production", and it "MAY be removed without prior notice."
This matters because a great deal of secondary coverage says the opposite. Several vendor and community posts published in the first half of 2026 state that GenAI client spans exited experimental status early in the year. The specification does not support that. Every gen_ai.* attribute in the inference span table is badged Development, and the spans document says in plain text that the stabilisation work has not been scheduled: "This transition plan will be updated to include stable version before the GenAI conventions are marked as stable."
There is also a vocabulary trap. "Experimental" is not a rung on OpenTelemetry's current ladder at all. The ladder runs from no explicit status through Development, Alpha, Beta, Release Candidate, Stable, then Deprecated and Unmaintained. So a post telling you something "left Experimental" is describing a ladder that no longer exists.
| Question | What secondary coverage says | What the specification says |
|---|---|---|
| Are client spans stable? | Exited experimental in early 2026 | Development, every attribute badged Development |
| Are agent spans stable? | Experimental | Development |
| Where does the spec live? | opentelemetry.io/docs/specs/semconv/gen-ai/ | Moved to open-telemetry/semantic-conventions-genai |
| Latest GenAI release? | Implied to track core semconv | No releases published; ships from main |
| Is there a stable opt-in value? | Implied | Only gen_ai_latest_experimental exists |
The practical consequence: budget for a rename. Do not tell your team the schema is settled, and do not build a billing pipeline that reads a gen_ai.* attribute name directly out of a span without a mapping layer.
The attributes that carry real weight
A GenAI inference span has exactly two Required attributes.
gen_ai.operation.name, with well-known values includingchat,create_agent,embeddings,execute_toolandgenerate_content.
gen_ai.provider.name, with examplesopenai,gcp.gen_aiandgcp.vertex_ai.
Note what is absent. There is no gen_ai.system attribute in the current table. Provider identity now lives on gen_ai.provider.name, described in the spec as "a discriminator that identifies the GenAI telemetry format flavor specific to that provider". If your dashboards group by gen_ai.system, they are grouping by a field the current spec does not define.
Conditionally Required attributes include gen_ai.request.model, gen_ai.conversation.id, gen_ai.output.type (text, json, image), gen_ai.request.choice.count when it is not 1, gen_ai.request.seed, gen_ai.request.stream and gen_ai.request.top_k.
The Recommended set is where the operational value sits:
- Sampling controls:
gen_ai.request.temperature,gen_ai.request.top_p,gen_ai.request.max_tokens,gen_ai.request.frequency_penalty,gen_ai.request.presence_penalty,gen_ai.request.stop_sequences.
- Response identity:
gen_ai.response.id,gen_ai.response.model,gen_ai.response.finish_reasons(a string array, examples["stop"]and["stop", "length"]).
- Latency:
gen_ai.response.time_to_first_chunk, a double in seconds, set when the request was streaming.
- Cost:
gen_ai.usage.input_tokens,gen_ai.usage.output_tokens,gen_ai.usage.cache_creation.input_tokens,gen_ai.usage.cache_read.input_tokens, andgen_ai.usage.reasoning.output_tokenswhen applicable.
That last group is the one to wire up first, and the cache split is the reason.
Why the cache attributes pay for the whole exercise
Prompt caching changes unit economics enough that a token count without a cache breakdown tells you almost nothing about spend.
Anthropic's published pricing puts a cache read at 0.1x the base input rate. On Claude Opus 4.8, base input is $5 per million tokens, a 5-minute cache write is $6.25 per million, a 1-hour cache write is $10 per million, and a cache hit is $0.50 per million. Output is $25 per million. On Claude Sonnet 5 the introductory rate is $2 input and $10 output per million tokens through 31 August 2026, moving to $3 and $15 from 1 September 2026. Claude Haiku 4.5 is $1 and $5.
Now put those against the spec. A span that records only gen_ai.usage.input_tokens cannot distinguish a million uncached input tokens from a million cache reads, and on Opus 4.8 that is the difference between $5 and $0.50 for the same number. Ten times. gen_ai.usage.cache_read.input_tokens and gen_ai.usage.cache_creation.input_tokens exist precisely so your cost query can separate them.
| Line item on Claude Opus 4.8 | Rate per million tokens | Attribute that captures it |
|---|---|---|
| Base input | $5 | gen_ai.usage.input_tokens |
| 5-minute cache write | $6.25 | gen_ai.usage.cache_creation.input_tokens |
| 1-hour cache write | $10 | gen_ai.usage.cache_creation.input_tokens |
| Cache hit or refresh | $0.50 | gen_ai.usage.cache_read.input_tokens |
| Output | $25 | gen_ai.usage.output_tokens |
| Reasoning output | $25 | gen_ai.usage.reasoning.output_tokens |
The OpenTelemetry specification notes that gen_ai.usage.input_tokens "SHOULD include all types of input tokens, including cached tokens", which is the trap in one line: the totals overlap. If you sum input tokens and cache-read tokens and multiply by the base rate, you will overstate your bill and no one will trust the dashboard again.
Anthropic also documents a Batch API discount of 50% on both input and output, and a 1.1x multiplier for US-only inference through the inference_geo parameter. Neither has a gen_ai.* attribute. If you use them, that mapping lives in your own code, and it is worth writing down where.
Span names, kinds and sampling
Get these right at creation time or your sampler cannot see them.
The inference span name "SHOULD be {gen_ai.operation.name} {gen_ai.request.model}", with span kind CLIENT, or INTERNAL for a model running in-process. Embeddings use the same shape with gen_ai.operation.name set to embeddings. Agent spans have their own forms: create_agent {gen_ai.agent.name} and invoke_agent {gen_ai.agent.name} when the name is readily available, both CLIENT.
MCP spans follow {mcp.method.name} {target}, where target should match gen_ai.tool.name or gen_ai.prompt.name, falling back to just {mcp.method.name} when no low-cardinality target exists. The MCP document notes that populating gen_ai.operation.name alongside mcp.method.name "allows consumers to treat MCP tool calls spans similarly with other tool call types", which is the difference between one tool-latency panel and two. If you are also tracking the protocol itself, our MCP stateless spec migration guide covers what changed on the transport side.
The spec marks five attributes as sampling-relevant, meaning they "SHOULD be provided at span creation time": gen_ai.operation.name, gen_ai.provider.name, gen_ai.request.model, server.address and server.port. Set them late and a tail sampler keyed on model cannot do its job. This is the single most common instrumentation bug we see in review, and it is invisible until your sampling bill or your trace coverage looks wrong.
Prompts and completions: what changed
If you built against the 2025 shape of the conventions, this section is your migration.
The old per-role events and the gen_ai.content.prompt and gen_ai.content.completion attributes do not appear in the current events document. There are now exactly two GenAI events, both Development:
gen_ai.client.inference.operation.details, where the spec states "The event name MUST begen_ai.client.inference.operation.details" and describes it as opt-in, usable "to store input and output details independently from traces".
gen_ai.evaluation.result.
The primary path for content is now Opt-In span attributes: gen_ai.input.messages, gen_ai.output.messages, gen_ai.system_instructions and gen_ai.tool.definitions. These carry structured role and parts JSON, shaped like {"role": "user", "parts": [{"type": "text", "content": "..."}]}, with tool_call and tool_call_response part types for tool traffic.
The events document also warns that "Events are in-development and not yet available in some languages." Check your language SDK before you design around them.
Treat all four content attributes as a data-protection decision, not a telemetry one. Prompts and completions routinely contain personal data, and under India's Digital Personal Data Protection Act 2023 the personal data in a prompt is personal data wherever it lands. Shipping it to a third-party observability vendor by flipping an opt-in flag is a processing decision that belongs in your record, not in a config file nobody reviewed. Our DPDP Act engineering playbook covers what that record needs to contain.
The migration flag, and its one legal value
This is the part teams get wrong because the GenAI flag does not behave like the HTTP one.
The general mechanism, documented in OpenTelemetry's HTTP migration guide, introduces OTEL_SEMCONV_STABILITY_OPT_IN, accepting http to emit the stable conventions and stop emitting the old ones, or http/dup to emit both "allowing for a phased rollout". The same page scopes it clearly: the variable "is only intended to be used when migrating from an experimental semantic convention to its initial stable version."
For GenAI the spec defines the variable as a comma-separated list of category-specific values, and it defines exactly one:
# Emit the latest experimental GenAI conventions and stop emitting v1.36.0 or prior
export OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
# Combine with other categories as a comma-separated list
export OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental,http/dup
The spec's own words on the value: gen_ai_latest_experimental means "emit the latest experimental version of GenAI conventions (supported by the instrumentation) and do not emit the old one (v1.36.0 or prior)." Default behaviour, in its absence, is to keep emitting whatever the instrumentation emitted before, pinned at v1.36.0 or earlier.
There is no gen_ai/dup. There is no stable value. Both absences follow from the same fact: there is no stable version to migrate to, so there is nothing to dual-write against. Existing instrumentations are told they "SHOULD NOT change the version of the GenAI conventions that they emit by default", which is why upgrading your SDK may change nothing until you set the flag yourself.
A build order that survives the rename
Six steps, in the order that minimises rework.
1. Pin the schema you emit. Record gen-ai/1.42.0 in your service metadata and treat it as a version you own, not a detail the SDK picks. When the number moves, you want a diff, not a surprise.
2. Set the flag explicitly in every environment, even where the default is what you want. An explicit gen_ai_latest_experimental in your deployment manifest is documentation that survives a maintainer leaving.
3. Emit the five sampling-relevant attributes at span creation. gen_ai.operation.name, gen_ai.provider.name, gen_ai.request.model, server.address, server.port. Everything else can be set later on the span.
4. Wire the token attributes into a cost view before you wire anything into a latency view. Latency you will feel. Spend you will not, until the invoice. Include the cache split from the start, and remember input tokens already include cached tokens.
5. Put a mapping layer between attribute names and your dashboards. One file that maps gen_ai.usage.input_tokens to your internal metric name costs an hour now and saves the rename later. This is not over-engineering when the spec says attributes "MAY be removed without prior notice."
6. Keep content capture off by default and gate it behind an explicit, reviewed decision per environment. Then decide whether it goes on the span or into gen_ai.client.inference.operation.details, which exists so content can live apart from traces.
The judgement worth carrying: instrument for the questions you will be asked in a billing review, not the ones a demo dashboard makes pretty.
What is coming, and what is not verified
The GenAI repository's changelog lists work under Unreleased rather than in any tagged version: memory operation spans covering store lifecycle and record create, update, upsert, search and delete; a plan operation for agent planning and task decomposition; a gen_ai.workflow.duration metric; gen_ai.agent.name becoming sampling-relevant on create_agent and invoke_agent spans; document added to the modality enum; and opt-in gen_ai.tool.call.arguments and gen_ai.tool.call.result attributes on the MCP server span.
Two things worth flagging as unresolved rather than guessing at. First, the core conventions show a version conflict depending on where you look: the GitHub releases page lists v1.42.0 as latest, released 12 June 2026, while opentelemetry.io navigation reads 1.43.0. Both are real pages; the release date for 1.43.0 is not something we could confirm, so we are not publishing one. Second, whether gen_ai.system, gen_ai.content.prompt and gen_ai.content.completion were formally deprecated with a deprecation record, or simply dropped, is not stated on the pages we read. Their absence from the current tables is verified. Their disposal process is not.
Say which of those you know when you write your own internal runbook. An observability spec you half-remember is worse than one you looked up this morning.
India-specific considerations
Two points for teams building from India.
Prompt and completion capture is the sharp edge. The Digital Personal Data Protection Act 2023 sets a maximum penalty of ₹250 crore for failure to take reasonable security safeguards, and the DPDP Rules were notified on 14 November 2025. A trace backend holding raw prompts is a personal data store. The opt-in design of gen_ai.input.messages and gen_ai.output.messages is helpful here: the safe default is already the default, and turning it on should require the same review as adding any new processor.
On cost, the currency exposure runs the other way. Token pricing is quoted and billed in USD, so an Indian team's observability work is measured in rupees while the spend it controls moves with the dollar. That gap is the argument for wiring gen_ai.usage.* into a finance-readable view early rather than after the first quarter that surprises someone. Teams working through the wider picture may find our notes on inference cost for enterprise AI and on long context versus RAG cost and latency useful alongside this.
FAQ
How eCorpIT can help
eCorpIT builds and reviews observability for LLM and agent workloads, including the parts that are easy to postpone: cost attribution that separates cached from uncached tokens, sampling that still works when a model attribute arrives late, and a content-capture policy that a data protection reviewer will accept. Our senior engineering teams work against the current specification rather than a blog post about it, and leave behind a mapping layer so the next rename is cheap. If you want a review of what your agents are actually emitting today, get in touch.
References
Last updated: 20 July 2026.