C# and NATS.io for agentic AI orchestration Synadia released an open-source Agent Protocol for NATS on May 25, 2026, giving AI agents a shared discovery, conversation and liveness contract on the NATS messaging fabric. Agents register as NATS micro services under the service name "agents" and answer pings at $SRV.PING.agents, while prompts go to subjects matching agents.prompt.{agent}.{owner}.{name} and responses stream back as typed JSON {type, data} chunks. The protocol is a contract rather than a framework or runtime, so callers can find and talk to agents built on any stack without a registry or coordinator process. Back to Blog https://nats.io/blog What's old is new: A NATS-native protocol for AI agents Andrew Connolly — May 25, 2026 Agent systems are becoming distributed systems, and NATS already solves many of the communication problems those systems are rediscovering. NATS has long been a natural fit for distributed, heterogeneous systems. No matter where your devices run, what languages your services use, or how ephemeral your clients are, it gives them a simple way to find and talk to one another. It also easily bridges different cloud vendors, geographies, runtimes, or hardware—with an integrated security model that naturally extends everywhere NATS does. These traits make NATS an obvious choice for multi-agent architectures. Set aside the AI language, and agents have many of the same needs as microservices : - Discover peers and their capabilities - Exchange messages across boundaries - Handle long-running requests without blocking - Notice when peers come and go Plus, as orgs race to ship products and services enabled by agents or build internal agentic workflows , they aren’t building on one unified agent stack . They’re mixing models, clouds, runtimes, private data, and physical environments that no layer of their stack can fully understand or control. At production scale, agentic systems are distributed systems in a trench coat. And most teams are stuck gluing them together with HTTP or shoehorning everything into a vendor’s gateway or mesh. The open source Synadia Agent Protocol for NATS https://github.com/synadia-ai/synadia-agent-sdk-docs lets agents of any kind be addressed on a single fabric. This new protocol on top of NATS isn’t an agent framework, or a runtime, or a product of any kind. It’s a contract that says: If an agent does these few specific things, anything else on the same NATS system can find it and talk to it without knowing what framework you built the agent with . The payoff is that callers don’t need to care whether an agent is a Python script, a hosted model wrapper, a CLI session, or a long-running service. They discover capabilities, send a prompt, receive a typed stream, and observe liveness the same way every time. When all your agents speak NATS fluently, you can build the surfaces that work across them — monitor, audit, orchestrate, whatever your architecture needs. The protocol itself has three responsibilities: discovery, conversation, and liveness. Discovery An agent registers as a NATS micro service with the service name agents . Its metadata describes itself — what kind of agent it is, who owns it, what protocol version it implements, optionally what session it belongs to. A caller that wants to know which agents are reachable sends a standard micro service ping at $SRV.PING.agents or asks for full info at $SRV.INFO.agents , and every running agent that matches the caller’s permissions answers. No registry. No service catalog. No coordinator process you have to keep alive. The thing NATS already does for every other micro service on the cluster is the thing it does for agents too. Discovery returns full endpoint records: the subject to publish prompts to, capability metadata like maximum payload size and whether attachments are accepted, and the queue group the agent has joined. Callers read these from $SRV.INFO rather than constructing them from identity, which means an agent can move subjects without breaking its callers. Conversation Once a caller has an endpoint subject, prompting is one NATS request. The default subject pattern is agents.prompt.{agent}.{owner}.{name} — verb-first, so every endpoint type owns its own slot in the hierarchy and a wildcard like agents.prompt. cleanly partitions all prompt traffic from everything else. The agent answers by streaming typed JSON chunks back to the caller’s reply inbox. Each chunk is {type, data} : - response chunks carry content a string or an object with text and optional attachments . - status chunks carry lifecycle signals. The protocol mandates exactly one ack status chunk as the very first message on the reply subject, before any latency-inducing work, so the caller knows the request was received and its inactivity timer can be reset. - query chunks let the agent pause and ask the caller a mid-stream question — a permission prompt, a clarification, a menu selection — supplying a fresh reply subject for the answer. The response stream stays open. Every stream — successful or errored — ends with the same signal: a zero-byte message carrying no headers. Errors arrive as a NATS micro service error-headered message Nats-Service-Error-Code , Nats-Service-Error immediately before the terminator, with an optional JSON body for structured detail. That’s the entire conversation: typed chunks in publication order, ack first, terminator last. Liveness Every agent publishes a small heartbeat on agents.hb.{agent}.{owner}.{name} at a configurable cadence 30 seconds by default . The payload carries the agent’s identity, its per-instance instance id , a UTC timestamp, and the cadence itself. The heartbeat subject is the one subject the protocol fixes instead of letting agents override it , so a caller can subscribe to agents.hb. . . and watch every agent on the cluster come up, stay up, and go offline — without ever polling. An instance is considered offline after three missed beats. For point-in-time liveness, every agent also exposes a status request/reply endpoint that returns the same payload shape as a heartbeat, freshly built on demand. A caller that just connected can bootstrap its liveness tracker without waiting up to a full interval for the next beat. The details, in one place What the protocol actually pins down, beyond the three jobs: - Subject hierarchy — agents.{verb}.{agent}.{owner}.{name} . Verbs: prompt , hb , status , attachments reserved for future chunked upload . Tokens follow standard NATS subject naming. - Service registration — micro service name = "agents" ; required metadata: agent , owner , protocol version , plus session when session-aware. - Queue group — the prompt and status endpoints both register with queue group "agents" , which load-balances across same-identity instances without per-deployment coordination. - Discovery subjects — exactly two are stable: $SRV.PING.agents and $SRV.INFO.agents .{instance id} . Callers MUST read endpoint subjects from $SRV.INFO , not construct them. - Endpoint capability metadata — the prompt endpoint declares max payload e.g. "1MB" and attachments ok boolean . Callers enforce both locally before publishing. - Request envelope — either plain UTF-8 text shorthand for {"prompt":