| Internet-Draft | AAC OTel Extension | October 2026 |
| Palanisamy & Mih | Expires 5 April 2027 | [Page] |
This document defines org.agentactioncapsule.otel, a namespaced payload
extension for the Agent Action Capsule profile. The extension carries
OpenTelemetry trace and span context alongside a sealed agent-action record so
that the Capsule and the observability spans describing the same action can be
joined after the fact. It maps the OpenTelemetry Generative AI semantic
conventions onto Capsule fields where a mapping is well defined and states
which OpenTelemetry values MUST NOT enter a Capsule at all. The extension does
not alter Capsule verification: a verifier that does not implement it treats
the block as informational.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 5 April 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Agent runtimes emit OpenTelemetry spans for tool calls, model invocations, and handoffs. The Agent Action Capsule profile [I-D.mih-scitt-agent-action-capsule] seals the corresponding record at the effect boundary, and a Class 1 verifier validates it before it is accepted as evidence. This extension makes the join explicit: the Capsule carries the trace and span identifiers associated with the action, and the span can carry the Capsule's derived identifier as an attribute. This extension MUST NOT change the base Class 1 or Class 2 verification model. A verifier that does not implement the extension MUST treat the block as informational and MUST ignore it for verification purposes.¶
Two constraints matter. First, this extension MUST NOT alter the Producer
Envelope or the base profile's verification semantics. The protected header of a
Capsule remains closed by the base profile
([I-D.mih-scitt-agent-action-capsule], Section "Extensibility"), and all
fields defined here live in the Capsule payload under a namespaced key.
Second, this extension MUST treat OpenTelemetry identifiers as correlation
handles into systems that may hold end-user data. The base profile's admission
tiers apply to each field. In particular, trace_id and span_id are
clear-safe only when they are non-identifying within the producer's scope. A
trace ID is a lookup key into logs, APM backends, and gateway records that may
hold user data. This profile therefore defines a strict allow-list and an
explicit digest-only alternative rather than treating an opaque identifier as
harmless by default.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
Capsule, Producer Envelope, derived identifier, capsule_id, and the
data-admission tiers (clear-safe, digest-only, never-enters) are used as
defined in [I-D.mih-scitt-agent-action-capsule]. Trace ID, span ID, trace
flags, and tracestate are used as defined in [W3C.TraceContext].¶
This document is written against revision -05 of the base profile. It
addresses the observability gap between a sealed Capsule and the active
OpenTelemetry trace and span without changing the Class 1 or Class 2
verification model of [I-D.mih-scitt-agent-action-capsule]. In particular, trace and span identifiers are correlation handles, not
harmless opaque values; they therefore require explicit allow-listing and
digest-only handling when they may reveal or index user-bearing data. This
extension MUST NOT introduce a new mandatory identity claim: identity is
represented in the base model as operator/developer context rather than an
agent_id field. The extension remains payload-only and MUST NOT impose a
mandatory transport or OAuth dependency. Any transaction-token guidance is
informative and SHOULD-oriented so that the base profile remains transport-
neutral.¶
org.agentactioncapsule.otel Block
A Capsule MAY carry a top-level payload member named
org.agentactioncapsule.otel. The member name is reverse-DNS namespaced.
[I-D.mih-scitt-agent-action-capsule]'s Section "Namespacing convention"
currently states this rule only for three producer-local vocabularies
(constraint id/check_type, compliance.framework_tags, and
assurance.sources[].kind); it does not yet generalize the bare-name/
namespaced-name split to top-level payload members; revision -05 left that
section unchanged. This document adopts the same convention for its own
member — bare names reserved for values the base profile seeds, new members
namespaced — and the authors request that -06 generalize the rule explicitly.¶
Where the block lives. Until the base profile admits namespaced top-level
members explicitly, the one payload container the base profile already
treats as extensible is model_attestation.compute_attestation (see
draft-palanisamy-scitt-aac-runtime). The reference emitter therefore
places this block at
model_attestation.compute_attestation["org.agentactioncapsule.otel"]
today (see Section 8), with field names, tiers, and shape exactly as defined
here. A producer MAY place the block at either path. A verifier that
implements this extension MUST recognize the block at either path and MUST
treat the two placements identically; only the JSON path differs.¶
The block participates in the derived identifier like every other payload
member: it is canonicalized under JCS [RFC8785] and covered by capsule_id.
A verifier that does not implement this extension MUST ignore the block for
verification purposes and MUST NOT fail a Capsule because it is present.¶
| Field | Type | Req | Tier | Meaning |
|---|---|---|---|---|
| trace_id | string (32 lowercase hex) | REQUIRED | clear-safe, conditional (see Section 6) | The W3C trace ID of the span that observed the action. |
| span_id | string (16 lowercase hex) | REQUIRED | clear-safe, conditional | The W3C span ID of that span. |
| parent_span_id | string (16 lowercase hex) | OPTIONAL | clear-safe, conditional | Parent of span_id, when known to the producer. |
| trace_flags | string (2 lowercase hex) | OPTIONAL | clear-safe | W3C trace flags as sampled by the producer. |
| tracestate_digest | string (64 lowercase hex) | OPTIONAL | digest-only | SHA-256 over the tracestate header value as received. tracestate MUST NOT be carried in clear (vendor entries may carry identifiers). |
| span_name | string | OPTIONAL | clear-safe, conditional | The span's name, only when it is a fixed operation name and never user-derived. |
| resource | object | OPTIONAL | see Section 3.1 | A closed subset of OpenTelemetry resource attributes. |
| semconv | object | OPTIONAL | see Section 3.2 | GenAI semantic-convention attributes admitted by this document, plus semconv.source = the conventions repository and commit or release the names are drawn from. |
Additional members under org.agentactioncapsule.otel MUST be namespaced (URI or reverse-DNS
prefix). A verifier MUST ignore members it does not recognize.¶
Only the following resource attributes MAY appear under resource, and
only when their values are deployment constants rather than per-user or
per-session values:¶
| Attribute | Tier | Note |
|---|---|---|
| service.name | clear-safe | Deployment-assigned. |
| service.version | clear-safe | |
| service.namespace | clear-safe | |
| deployment.environment.name | clear-safe | |
| telemetry.sdk.name / telemetry.sdk.version | clear-safe |
service.instance.id, host.name, host.id, container.id, and any
attribute that identifies a machine or process instance are digest-only at
most and SHOULD be omitted: they are stable identifiers with small effective
entropy in most fleets, and the base profile's warning that hashing is not
anonymization applies.¶
The OpenTelemetry GenAI conventions [OTEL-GENAI] now live in their own
repository (open-telemetry/semantic-conventions-genai; the pages in the
main semantic-conventions repository redirect there as of v1.44.0). They
are not yet stable, so semconv.source MUST name the repository and the
commit or release the attribute names were taken from; this revision was
written against commit 8c1b98a.¶
Where a Capsule already carries the same fact, this extension does not
duplicate it; where the convention carries a fact the Capsule lacks, the
attribute MAY be admitted under semconv at the tier shown. Attributes not
listed are not admitted until a revision classifies them (allow-list stance).¶
| GenAI attribute | Disposition; note / Capsule counterpart |
|---|---|
| gen_ai.provider.name | clear-safe; (replaces the retired gen_ai.system) model_attestation.provider when present; do not carry in both |
| gen_ai.request.model / gen_ai.response.model | clear-safe; model_attestation.model_id (RECOMMENDED there); do not carry in both |
| gen_ai.operation.name | clear-safe; chat, execute_tool, invoke_agent, invoke_workflow, … — informs action_type mapping only |
| gen_ai.agent.id / gen_ai.agent.name / gen_ai.agent.version | clear-safe; corresponds to the Capsule's developer; carry only if it adds a version the Capsule lacks |
| gen_ai.workflow.name | clear-safe, conditional; fixed workflow names only; never user-derived |
| gen_ai.tool.name / gen_ai.tool.type | clear-safe; tool identity, not arguments |
| gen_ai.tool.call.id | clear-safe, conditional; joinable by the producer to the effect record; carry only if non-identifying |
| gen_ai.usage.input_tokens / output_tokens / reasoning.output_tokens / cache_*.input_tokens | clear-safe; counts are not content |
| gen_ai.request.temperature, top_p, top_k, max_tokens, seed, stop_sequences, reasoning.level, choice.count | clear-safe; decoding parameters; model_attestation.decoding when present |
| gen_ai.response.finish_reasons / gen_ai.response.status / gen_ai.output.type | clear-safe |
| gen_ai.response.id / gen_ai.request.previous_response.id | digest-only; provider-assigned ids are correlation handles into provider logs |
| gen_ai.data_source.id / gen_ai.memory.store.id | clear-safe, conditional; only when a deployment constant naming a store, never a per-user store |
| gen_ai.prompt.name / gen_ai.prompt.version | clear-safe, conditional; small value spaces; if a deployment treats prompt identity as sensitive, digest with a tenant-private salt — an unsalted digest of a small vocabulary is dictionary-recoverable |
| gen_ai.input.messages / gen_ai.output.messages / gen_ai.system_instructions | never-enters; content; the Capsule commits content by digest through its effect record only |
| gen_ai.tool.call.arguments / gen_ai.tool.call.result / gen_ai.tool.definitions | never-enters; content |
| gen_ai.memory.records / gen_ai.memory.query.text / gen_ai.retrieval.query.text / gen_ai.retrieval.documents | never-enters; content |
gen_ai.prompt.variable.* (incl. gen_ai.prompt.variable.user_name) |
never-enters; template variables carry user data by construction |
gen_ai.conversation.id, mcp.session.id, session_id, enduser., user.
|
never-enters; end-user or session identity; excluded, not digested |
| gen_ai.evaluation.* (name, result, score.*, explanation) | out of scope; judgments about a run belong to the reasoning/judging extension, not to a correlation block; a Capsule's own verdict is in the base profile's disposition |
| gen_ai.client.* / gen_ai.server.* metrics, mcp.*.session.duration | out of scope; metrics are not per-action facts |
This extension is a correlation profile for a Capsule, not a general observability ingestion format and not an evidence-exchange protocol. A local evidence store MAY index the relationship between a Capsule and OpenTelemetry records without placing all OpenTelemetry metadata in the Capsule. Likewise, an evidence bundle MAY carry or selectively disclose the correlated OpenTelemetry record under its own authorization and disclosure rules.¶
The presence of this block therefore says only that the Capsule producer bound a correlation handle to the Capsule. It does not establish that every relevant span was captured, that the span is independent of the Capsule producer, or that the span's semantic interpretation is correct.¶
A Capsule MAY be produced after the fact from spans already exported to an
observability backend, for example when an operator onboards an existing
deployment by replaying its telemetry. Such a Capsule MUST carry the base
profile's provenance_mode block with mode: "backfilled"
([I-D.mih-scitt-agent-action-capsule], Section "Provenance mode and backfilled records"), and
the source_ref of that block SHOULD identify the exported span record the
Capsule was derived from. The fields of org.agentactioncapsule.otel are
then taken from the exported span rather than from a live context, and the
same tiers and allow-list apply.¶
The base profile caps the time rung of a backfilled Capsule at what its
provenance_mode supports. A backfilled Capsule that cites a span therefore
records that the span existed when the replay ran; it does not record that
the Capsule was sealed when the span was emitted. Verifiers and coverage
reports MUST present replayed and contemporaneous Capsules separately.¶
A producer that emits both a span and a Capsule for one action SHOULD set
the span attribute aac.capsule_id to the Capsule's derived identifier once
sealed, so that observability tooling can locate the sealed record from the
trace. The attribute name is proposed for registration in the OpenTelemetry
semantic-conventions registry.¶
The span attribute is advisory. A verifier MUST recompute capsule_id from
the Capsule; a span attribute that disagrees with the recomputed value is a
defect in the span, not in the Capsule.¶
This extension defines no verification behavior beyond the base profile's Class 1 and Class 2 verifier checks (Sections 6 and 8.2 of [I-D.mih-scitt-agent-action-capsule]). Specifically:¶
The presence, absence, or content of org.agentactioncapsule.otel does not change the
verdict of Class 1 or Class 2 verification as established by the sealed
Capsule and the verifier's acceptance checks.¶
A verifier MAY use trace_id and span_id to locate corroborating spans
but MUST NOT treat the existence of a span as evidence that the recorded
action occurred; spans are self-reported by the same producer. A coverage
or assurance report MUST NOT count a same-producer span as independent
corroboration of the Capsule it correlates with.¶
Hex fields MUST be validated for length and case when present; a malformed value renders the block informational-only and SHOULD be reported.¶
The base profile's data-admission tiers govern every field in this block. This section states what the tiers mean for OpenTelemetry values because the intuition that an opaque identifier is harmless does not hold here.¶
Trace and span identifiers are correlation handles. A trace ID is clear-safe only when it is non-identifying on its own: it names an execution, not a person. But a trace ID is also a lookup key into every system that indexed the same trace — request logs, APM backends, gateway access logs — and some of those systems hold end-user data. Committing a trace ID in clear into a record that may later be disclosed to a third party therefore gives that party a key into systems the disclosure never covered. Producers MUST classify trace and span IDs as clear-safe only when the observability systems they index do not themselves hold end-user identity, or when disclosure of the Capsule is confined to parties that already hold access to those systems. Otherwise the IDs MUST be carried as digests, or a pairwise correlation identifier MUST be used instead.¶
What the block's fields must never be. Regardless of tier, no field of
org.agentactioncapsule.otel MAY carry: prompt or completion content; message bodies; tool
arguments or results; end-user identifiers or session identifiers, in clear or
as a digest; OpenTelemetry baggage entries [OTEL-BAGGAGE]; tracestate in
clear; or resource attributes that identify a natural person or a single
device. Hashing is not anonymization for low-entropy values (base profile,
"Data-Admission Tiers"); the digest-only tier is for content that must be
provable later, not for identifiers that must be hidden.¶
Allow-list stance. Adapters implementing this extension SHOULD admit only the attributes enumerated in this document and default-deny all others, per the base profile's adapter allow-list pattern. New GenAI attributes added by later convention versions are not admitted until a revision of this document classifies them.¶
The block is covered by the Capsule signature, the derived identifier, and the
verifier acceptance path used to seal and accept the Capsule. It MUST NOT be
altered without detection. It adds no authority: a span is the producer's own
telemetry, and the join it enables is between two records from one party.
Corroboration from a second party is provided by the base profile's
assurance.cross_party_rung mechanism (Section 5.4.1 of
[I-D.mih-scitt-agent-action-capsule]), not by this extension.¶
This section records the status of known implementations of this extension at the time of posting, per [RFC7942]. It is to be removed before publication as an RFC.¶
capsule-emit (Apache-2.0, Python): ships an OpenTelemetry SDK
SpanExporter that seals effect spans as Capsules and writes this block.
It applies the allow-list in Section 3.2 as default-deny and carries
trace_id, span_id, parent_span_id, and span_name as SHA-256 digests
unless a deployment opts into clear values, taking the conservative branch
of Section 6 by default. It places the block under
model_attestation.compute_attestation as described in the block section.
The exporter is accompanied by a leak test that runs the real block builder
against a deliberately poisoned allow-list to show the leak, then against
the real table to show none.¶
This is a tier-2 (per-profile) extension in the sense of
[I-D.mih-agent-accountability-conformance]: it defines its own semantics
and must-fail cases on top of the tier-1 binding conformance that
[I-D.mih-sokolov-scitt-payload-binding] (CPB) defines for every AAC
payload member. This document is not itself a binding-layer artifact and
does not register a type in the CPB Artifact Type Registry; that registry
governs the type field of typed digest references (for example, an
attestation_refs entry in the runtime extension), a different and
narrower thing than a named payload extension like this one.¶
As of this writing, the registry structure for tier-2 (per-profile) conformance artifacts is explicitly not yet specified — [I-D.mih-agent-accountability-conformance] states plainly that this is "TBD in a future revision." This document therefore cannot cite a settled registration procedure for itself, and does not assert one. What it does provide now, so that registration is a formality once the tier-2 registry exists rather than a rewrite, is the two-sided conformance-vector set that document's discipline (Section 5) requires of any record profile: positive vectors with pinned values, and must-fail vectors that a conformant implementation MUST refuse rather than merely mismatch.¶
Positive vector (MUST be accepted, and MUST reproduce the same capsule_id
under JCS [RFC8785] canonicalization as any other payload member):¶
{
"org.agentactioncapsule.otel": {
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"trace_flags": "01",
"resource": { "service.name": "support-agent" },
"semconv": {
"source": "open-telemetry/semantic-conventions-genai@8c1b98a",
"gen_ai.provider.name": "local",
"gen_ai.operation.name": "execute_tool"
}
}
}
¶
MUST-FAIL vectors (a conformant implementation MUST reject the field, or MUST treat the block as informational-only per Section 3 and Section 6):¶
// (a) malformed trace_id: 31 hex characters, and mixed case.
{ "org.agentactioncapsule.otel": {
"trace_id": "4BF92F3577b34da6a3ce929d0e0e473",
"span_id": "00f067aa0ba902b7" } }
// (b) tracestate carried in clear; MUST be a digest or absent.
{ "org.agentactioncapsule.otel": {
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"tracestate": "congo=t61rcWkgMzE" } }
// (c) semconv member outside the allow-list in {{semconv}}.
{ "org.agentactioncapsule.otel": {
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"semconv": { "gen_ai.input.messages":
[{"role": "user", "content": "…"}] } } }
¶
This document has no IANA actions. The org.agentactioncapsule.otel member
name is a namespaced payload member per Section 3 and is not IANA-governed.
Registration of this document as a conforming tier-2 profile awaits the
registry work noted in Section 9; this document requests no IANA
action for it. Registration of the aac.capsule_id span attribute is
requested of the OpenTelemetry semantic-conventions registry, not IANA.¶
{
"spec_version": "draft-mih-scitt-agent-action-capsule-05",
"format_version": "4",
"canonicalization_id": "jcs",
"capsule_id": "…",
"action_id": "act-7f3e…",
"action_type": "decide",
"operator": "example-tenant",
"developer": "support-agent@2.3.1",
"timestamp": "2026-09-04T18:02:11Z",
"org.agentactioncapsule.otel": {
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"trace_flags": "01",
"resource": { "service.name": "support-agent",
"service.version": "2.3.1" },
"semconv": {
"source": "open-telemetry/semantic-conventions-genai@8c1b98a",
"gen_ai.provider.name": "local",
"gen_ai.operation.name": "execute_tool",
"gen_ai.usage.input_tokens": 412,
"gen_ai.usage.output_tokens": 88
}
}
}
¶
The authors thank the maintainers of the OpenTelemetry GenAI semantic conventions, whose attribute vocabulary this document admits by reference, and the contributors to the capsule-emit OpenTelemetry exporter, whose implementation shaped the digest-only defaults in Section 6.¶