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.
Status: a proposal, emitted today
The attributes areexperimental and filed upstream as OpenTelemetry GenAI SemConv issue #180 (open, in discussion). The names are already emitted by the AIM reference backend, locked to that proposal.The nine attributes
Three groups: who the agent is, what is known about it, and what was decided.
Identity
- agent.id
- string, stable identifier for the agent instance, e.g. "agent-7f3a9c2e" or a DID.
- agent.public_key.algorithm
- string, the agent's identity key algorithm, e.g. "ed25519", "ml-dsa-65".
- agent.capability
- string, the capability being invoked, in the producer's namespace, e.g. "database.read".
Trust signals (producer-emitted)
- agent.trust_score
- double 0.0-1.0, the trust score at decision time. Producer-defined semantics; not normative.
- agent.drift_score
- double 0.0-1.0, behavioral drift from baseline at decision time.
- agent.scan_verdict
- string, latest scan verdict: clean | warnings | findings | critical | unknown.
Authorization decision
- 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).
- 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.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.
fga.authorize agent.id=agent-7f3a9c2e
│ agent.capability=database.read
│ agent.trust_score=0.62 agent.scan_verdict=clean
│ 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)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 risingagent.drift_score, and answer “why was this agent denied?” out of the box.If you know HTTP semantic conventions
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.