OpenA2A/specs
OTelDraft / proposalDraft; filed upstream as open-telemetry/semantic-conventions-genai#291 (pull request opened 2026-06-15, not merged)

OTel Semantic Conventions for Agent Identity

Nine proposed OpenTelemetry attributes under gen_ai.agent.* that put agent identity and trust signals into standard traces, metrics and logs; the repository also defines fga.* attributes for authorization outcomes.

The question it answers

“How do you observe an agent's authorization decisions?”

If you know one thing already

It’s like HTTP semantic conventions (http.method, http.status_code).

Why it exists

The web became observable once everyone agreed to log the same fields: every tracing tool understands http.method and http.status_code without being told. Agent authorization has no such vocabulary yet. This proposal adds one, nine OpenTelemetry attributesthat put an agent's identity, trust signals and authorization outcome into standard traces, metrics and logs.

Note

Status: a proposal, emitted today

The attributes are experimental and filed upstream as OpenTelemetry GenAI SemConv pull request #291 (open, not merged), from issue #180. The AIM reference backend emits these signals today under the earlier names (agent.trust_score and similar); its move to the gen_ai.agent.* names is tracked.

The nine attributes

All nine live under gen_ai.agent.*, the namespace the OpenTelemetry GenAI conventions reserve for agents, in two groups: who the agent is, and what is known about it. Each trust signal is paired with a method token so a consumer can tell a changed scoring method from a changed agent.

Identity

gen_ai.agent.id
string, stable identifier for the agent instance, e.g. "agent-7f3a9c2e" or a DID.
gen_ai.agent.public_key.algorithm
string, the agent's identity key algorithm, e.g. "ed25519", "ml-dsa-65". A verifier that does not recognize the identifier should refuse to verify (fail closed).
gen_ai.agent.capability
string, the capability being invoked, in the producer's namespace, e.g. "database.read".

Trust signals (producer-emitted, each with a method token)

gen_ai.agent.trust.score
double 0.0-1.0, the trust score at decision time. Producer-defined semantics; not normative.
gen_ai.agent.trust.method
string, opaque producer-scoped token for the method and version that produced the trust score, e.g. "trust-model@2.3.1". Compared for equality only.
gen_ai.agent.drift.score
double 0.0-1.0, behavioral drift from baseline at decision time.
gen_ai.agent.drift.method
string, opaque producer-scoped token for the method and version that produced the drift score, e.g. "embedding-cosine@1.4".
gen_ai.agent.scan.verdict
string, latest scan verdict: clean | warnings | findings | critical | unknown.
gen_ai.agent.scan.method
string, opaque producer-scoped token for the scanner and version that produced the verdict, e.g. "scanner@1.2.0".

The authorization decision: fga.*, repository-defined

Three more attributes carry the decision path. They are defined in the repository's registry/fga.yaml, not in pull request #291: where they sit (alongside gen_ai.agent.*, under gen_ai.agent.fga.*, or elsewhere) is pending the working-group decision asked for in issue #180, so they are kept unscoped and deferred from the filing.

fga.step
string, which authorization step produced this span: capability_check | attribute_check | context_check | chain_check | intent_check.
fga.outcome
string, ALLOW | DENY | DENY_INTENT | DENY_CONTEXT | DENY_CHAIN | DENY_ATTRIBUTE | ERROR.
fga.denied_by
string, when the outcome is a DENY, which step denied it (one of the fga.step values).
registry/fga.yaml (verbatim)yaml
groups:
  - id: registry.fga
    type: attribute_group
    display_name: Fine-Grained Authorization Attributes
    brief: >
      Decision-path attributes for fine-grained authorization spans. The namespace placement of
      these attributes (alongside gen_ai.agent.*, under gen_ai.agent.fga.*, or elsewhere) is
      pending the working-group decision asked for in
      open-telemetry/semantic-conventions-genai#180, so they are kept unscoped here and deferred
      from #291.
    attributes:
      - id: fga.step
        type: string
        stability: experimental
        brief: The fine-grained authorization step that produced this span.
        examples:
          - "capability_check"
          - "attribute_check"
          - "context_check"
          - "chain_check"
          - "intent_check"
      - id: fga.outcome
        type: string
        stability: experimental
        brief: The decision outcome.
        examples:
          - "ALLOW"
          - "DENY"
          - "DENY_INTENT"
          - "DENY_CONTEXT"
          - "DENY_CHAIN"
          - "DENY_ATTRIBUTE"
          - "ERROR"
      - id: fga.denied_by
        type: string
        stability: experimental
        brief: >
          Which step denied, when fga.outcome starts with DENY. Matches one of
          the fga.step enum values.
        examples:
          - "capability_check"
          - "attribute_check"
          - "intent_check"

What it looks like in a trace

The attributes map directly onto AIM's 5-step authorization: one parent span, fga.authorize, with a child span per check. A denied request is instantly explainable, the trace shows exactly which step said no.

An authorization trace (illustrative)text
fga.authorize            gen_ai.agent.id=agent-7f3a9c2e
│                        gen_ai.agent.capability=database.read
│                        gen_ai.agent.trust.score=0.62  gen_ai.agent.trust.method=trust-model@2.3.1
│                        gen_ai.agent.scan.verdict=clean  gen_ai.agent.scan.method=scanner@1.2.0
│                        fga.outcome=DENY_CONTEXT  fga.denied_by=context_check
├─ fga.capability_check  fga.step=capability_check  fga.outcome=ALLOW
├─ fga.attribute_check   fga.step=attribute_check   fga.outcome=ALLOW
├─ fga.context_check     fga.step=context_check     fga.outcome=DENY   ← here
├─ fga.chain_check       (skipped)
└─ fga.intent_check      (skipped)
Key idea

What it enables

Without conventions, every team invents its own field names and no dashboard can correlate across vendors. With them, any OpenTelemetry backend, Tempo, Prometheus, Grafana, Loki, can chart denial rates, alert on rising gen_ai.agent.drift.score, and answer “why was this agent denied?” out of the box.

If you know HTTP semantic conventions

HTTP SemConv (the web)
Agent SemConv
http.request.method
→
gen_ai.agent.capabilitywhat is being attempted
client identity / TLS
→
gen_ai.agent.id + public_key.algorithmwho is attempting it
http.response.status_code
→
fga.outcomeALLOW / DENY / ERROR
error detail
→
fga.denied_bywhich step refused
Standard, vendor-neutral telemetry fields, for agent authorization instead of HTTP requests.

How it applies to agents

  • It turns authorization from a black box into a queryable, chartable signal across any OTel stack.
  • The fga.* attributes are the observability face of AAP's enforcement and AIM's 5-step engine.
  • Because it's proposed upstream, the goal is that agent telemetry becomes legible to every observability tool, not just OpenA2A's.