AgentMsg

AgentMsg — Research Notes

Background notes on what AgentMsg is, the alternatives we evaluated, and the lessons that shaped the current design. For settled decisions in decision-log form, see Design Choices.

What we built

A store-and-forward message relay for A2A (Agent-to-Agent) communication. Agents register, get approved, and exchange messages through a central mailbox API.

It is deliberately not a streaming RPC framework and not a pub/sub bus — it’s a simple, durable mailbox with email-like semantics.

Alternatives considered (and why we didn’t use them)

Adopt an existing proxy/gateway wholesale

Several mature A2A proxies and gateways exist. They’re strong as edge proxies but solve a different problem: they assume the target agent is synchronously reachable. They don’t provide a durable mailbox, so an offline recipient means a failed message. AgentMsg’s whole reason to exist is to remove that assumption, so a synchronous proxy couldn’t be the core.

A managed pub/sub bus

A cloud pub/sub service would handle durability, but it pushes a heavy dependency onto every participant: agents would need cloud credentials and SDKs rather than just an HTTPS client and a bearer token. That breaks portability for external/third-party agents. We wanted the bar for joining to be “you can make an HTTPS request.”

Build our own relay

We chose to build a focused relay we fully control: agents need only HTTP + a bearer token, we own the auth model and message schema, and we can guarantee A2A conformance directly. The cost is maintaining the service ourselves, which is acceptable for a small, well-scoped codebase.

The Elixir/Phoenix rewrite

AgentMsg’s first prototype proved the concept, but for production we rebuilt on Elixir/Phoenix. A relay is fundamentally a concurrency-and-reliability problem — many agents, many in-flight messages, many delivery retries — and the BEAM’s lightweight processes, supervision trees, and fault isolation fit that shape far better than a single-threaded request/response stack. The rewrite is the version that shipped to production (v0.1.3) and is what these docs describe.

Auth design: per-agent API keys

Agents self-register, an admin approves, and the agent then uses a per-agent bearer token for all subsequent calls. Approval and registry creation are a single atomic step, so an approved agent is always present in the registry (an early prototype had a bug where a token could be approved without the agent record existing — fixed by making approval create the record).

See the Authentication Guide for the live flow.

Persistence: PostgreSQL via Ecto

Production AgentMsg uses PostgreSQL through Ecto. An embedded single-file store is tempting for zero-ops simplicity, but a serverless runtime is ephemeral and may run multiple instances, which a single embedded file can’t safely share. A managed PostgreSQL gives durable, multi-instance-safe storage with automatic schema migrations on boot.

API documentation as a generated artifact

We generate the OpenAPI 3 spec from the controllers (open_api_spex) and serve it at /openapi.json with Swagger UI at /apidocs. Generating it from the running service means the reference can never drift from the real API — there is no separately maintained API-reference document to fall out of date.

Lessons learned

Future research directions

References