The relay's job: translate agent-to-agent activity into OTel spans, with no protocol changes visible to the agents themselves.
The persistence substrate is OTel spans. The wire format implemented today is A2A. The spec is shaped so other wire formats (and the Agent Channel coordination layer in channels-protocol.md, implemented in channels/) map onto the same span / session / graph shape. Agents never read raw spans. Drop the relay between two existing agent peers and they coordinate normally, except every exchange is now a queryable trace.
This is the v0.4 shape. See protocol-changelog.md for the v0 -> v0.4 evolution and protocol-validation.md for which v0 claims survived Phoenix validation.
Phoenix-only OTLP/HTTP for v1. The relay process exports directly to Phoenix's collector port. No Tempo, no separate OTel Collector, no fan-out. Pluggability is a one-line endpoint swap, documented but not shipped.
One TracerProvider per relay process. Agent identity rides on span attributes, not on the Resource.
session.id = sha256("<repo>:<issue>")[:16] for GitHub-issue-rooted channels. Deterministic, stable across reconnects, no collector-side coordination. Other transports (Slack thread, Linear ticket) get their own deterministic derivation. The relay never mints session IDs server-side.
One session groups many traces. Each trace is one agent's burst.
Phoenix's Agent Graph view consumes OpenInference's explicit graph attributes, not span links. The relay synthesizes them from the A2A peer relationship and attaches them to each root span:
graph.node.id- the acting agent's identity for graph rendering. Default:<agent_id>. Use<agent_id>:<task_id>for per-task nodes.graph.node.parent_id- the upstream agent in the handoff chain (set on B'sa2a.taskroot when triggered by A; unset on the originating burst).
Span links can still be emitted as a secondary signal for OTel-native consumers that read them (Tempo, Jaeger). They are not load-bearing for Phoenix and are informational only.
- protocol-worked-example.md and protocol-worked-example-task.md - A streams a task to B, B completes, A acks, span by span.
- protocol-conventions.md - the attribute and span-shape conventions, plus the out-of-protocol relay-management surface.
- protocol-tracing.md - the
tracing.bootstrap()entrypoint. - protocol-attributes.md - the canonical span attribute registry (generates
docs/generated/). - protocol-validation.md and protocol-changelog.md - Phoenix findings and version history.
The operator CLI talks A2A to a relay (send, stream, tasks-get, tasks-cancel, view) and inherits the audit + gate wrapper pattern. The relay itself ships only a serve mode.
- Protocol doc + harness updated and re-validated against Phoenix.
- Implement the relay around the verified shape.
- The operator CLI ships after the relay has a
servemode reachable on the homelab.
See harness.md for the full sequencing gate.