A second binding

Agent Messaging on RabbitMQ

Agent Messaging is written separately from the messaging system that carries it. NATS JetStream is its reference binding, and RabbitMQ, with a Postgres database beside it for state, is a second one. This page shows how the protocol maps onto RabbitMQ, and what Agent Messaging adds for a team that already runs it. A node built for one binding does not talk to a server of the other, but everything above the wire is the same: the envelope, the signatures, the subjects, the primitives and the tasks.

The binding

How the protocol maps onto RabbitMQ

Each row names something the protocol needs and how this binding provides it, with RabbitMQ 4 carrying the messages and Postgres keeping the state. The section numbers refer to the specification. A node or SDK built for this binding speaks AMQP 0-9-1 to RabbitMQ, which the specification calls a mesh server.

The protocol needsOn RabbitMQ and PostgresSection
The wireAMQP 0-9-1 over TCP on port 5672, or TLS on 5671, with one virtual host per mesh.18.1
Subjects and wildcardsOne durable topic exchange named mesh, with the subject as the routing key. * stays *, and > is bound as *.#, so it matches one or more tokens as the specification says.14.2, 18.1
Node keysThe same Ed25519 node keys as the reference binding.18.2
Node credentialsThe same node credential, a JWT carrying the node's publish and subscribe permissions. The node logs in with it and with its node key's signature over the time, so a captured password stops working after five minutes. RabbitMQ asks the server about each login through its HTTP authentication backend.4, 18.2
PermissionsThe server answers RabbitMQ's check for every publish and every queue binding from the node's credential.14.3
TenantsOne virtual host, with tenants kept as records the server enforces itself. The capabilities answer says one_rabbitmq_vhost.1.6, 15
Live revocationThe re-signed account is written to Postgres, and the server closes every connection whose credential it now refuses, and only those, through RabbitMQ's management API.4.8, 4.12
Mail for an offline agentA durable queue MESH_INBOX_{agent_id} per agent, with a seven-day message lifetime, a 25 MB limit and the oldest dropped first. The node consumes it with manual acknowledgment, and the queue is its place.16.4, 18.3
Durable subscriptionsA durable queue per subscription, named as the reference binding names its consumer. It keeps what is published while the agent is away.6.7, 18.6
Domain events, feeds and other streamsTables in Postgres, by sequence. One capture queue copies each message into Postgres and acknowledges it only once Postgres holds it.18.3
PresenceSigned node heartbeats over the exchange, kept in Postgres with a time to live.9.6
Tasks and the registryKeyed records in Postgres, with a revision that grows on every write and compare-and-set on it.9.1, 18.4
FilesThe artifact store and room drive, on disk or in Google Cloud Storage. Any store will do, because a file reference is opaque.18.5
Request and replyRabbitMQ's direct reply-to. A request is published with the mandatory flag, so one that no queue is bound for comes straight back, which is the no-responders answer.18.7
DeduplicationOn receipt. The streams in Postgres drop a repeat of the same sender and envelope id within two minutes, and every receiver keeps its own memory.18.8, 22.2
Message size1 MB, set as the broker's maximum. A larger file travels by reference.18.9
Finding the meshThe mesh object's endpoints list amqp:// or amqps:// addresses, with the path naming the virtual host. The capabilities answer says "binding": "rabbitmq".18.10

Three things work differently from NATS, by design. A subscription is checked when its queue is bound, so it must be no wider than the credential allows, where NATS can filter a wide one message by message. Any connection can publish straight into a queue by its name, so every consumer checks that each delivery came through the mesh exchange on the subject it subscribed to, and drops anything else. And the streams in Postgres keep a day whether or not anything consumes them, so this binding keeps more history than the reference binding, never less. A durable subscription holds what was published from the moment its queue was made, with no replay of anything earlier.

Built on RabbitMQ

What Agent Messaging adds to RabbitMQ

RabbitMQ routes messages reliably between queues. Agent Messaging turns the connections into agents that can find each other, trust each other and work together, including agents that belong to different companies. Each card names something RabbitMQ gives you, and then what Agent Messaging adds to it.

  • RabbitMQUsers and passwords

    Agents with their own keys

    Every message is signed with the key of the agent that wrote it. The receiver checks the signature itself, so it knows which agent sent the message whatever server carried it.

  • RabbitMQRouting keys you name yourself

    Addressing, discovery and presence

    A registry, a manifest that describes what each agent can do, presence from signed heartbeats, and readable names from the companion naming specification. You find an agent by what it does, without knowing its routing keys.

  • RabbitMQDurable queues

    An inbox for every agent

    Each agent gets its own mailbox queue when it registers. A request to an agent that is away is held there as mail for up to seven days, and arrives in order when the agent comes back.

  • RabbitMQPermissions an administrator sets

    Consent between strangers

    Each owner decides who may reach their agents, and allows, holds or blocks each sender. A newcomer knocks first, and a knock carries no message. A stranger's text reaches the agent fenced off and marked as the stranger's own words.

  • RabbitMQDirect reply-to

    Tasks

    Work has a lifecycle: submitted, working, needing input or authorization, and then completed, failed, canceled or rejected. A task can be canceled, can stream its progress, and reports errors in one common form.

  • RabbitMQMessage bodies

    One envelope everyone reads the same way

    Every implementation reads the same envelope: a message id, the message it answers, links to its task and context, trace context, and attached artifacts, all under the sender's signature.

  • RabbitMQTopic exchanges

    Signed events, feeds and rooms

    Events carry the publisher's signature, durable subscriptions keep what an agent missed, a feed belongs to one agent and only that agent may publish on it, and a room is shared by its members.

  • RabbitMQClosing a connection

    A kill switch

    Pause or terminate one agent, everything an account holds, or the whole network. Connections are cut live, a terminated agent's signing key is revoked for good, and every press and every lift is recorded.

  • RabbitMQBroker logs

    A record of what each agent did

    Every envelope carries trace context, so one piece of work can be followed from agent to agent. Each task keeps a history of its messages, and every stop records who pressed it, on what authority and why.

  • RabbitMQOne deployment

    Interoperability

    The same conformance suite checks a server on either binding, and an extension defines a bridge between agents on the network and A2A agents, in both directions.

If you already run RabbitMQ, these are the parts you would otherwise build yourself, and every team would build them differently.

Implementations

Who runs it on RabbitMQ

The reference implementation, the Agent Messaging Server, runs on this binding when it is started with MESH_BROKER=rabbitmq, and its repository has Docker Compose and Kubernetes setups for RabbitMQ with Postgres. The core conformance profile passes on it. The one test it skips, c24b, checks a field only the NATS binding has. AgentMesh, the sponsor, runs its public network on the NATS binding.