Synadia Agents
SDKs and ready-to-run agent plugins for the NATS Agent Protocol.
The NATS Agent Protocol lets any AI agent — Claude Code, OpenClaw, PI, Hermes, or your own — register itself as a NATS micro service named agents, and be discovered, prompted, and streamed from by any caller speaking the same wire format. This repo is the home of the official caller and host SDKs (TypeScript and Python — see SDKs below), plus pre-built channel plugins that put popular AI harnesses on NATS without writing code.
Get started — pick your path
| You want to… | Go to | Install |
|---|
| Put an existing AI agent on NATS (Claude Code, OpenClaw, PI, Hermes, DSPy ReAct) | agents/ — pick the agent | per-agent README |
| Build a caller that discovers and prompts agents | client-sdk/typescript/ · client-sdk/python/ | npm i @synadia-ai/agents · pip install synadia-ai-agents |
| Host a brand-new agent built from scratch | agent-sdk/typescript/ · agent-sdk/python/ | npm i @synadia-ai/agent-service · pip install synadia-ai-agent-service |
Agents
Pre-built channel plugins that put existing AI harnesses on NATS. Each registers as an agents micro service and serves the protocol's prompt, status, and hb endpoints out of the box.
Subjects follow a verb-first pattern: agents.{verb}.{token}.{owner}.{session} where verb is prompt, hb, or status.
SDKs
Two halves per language. The caller SDK (client-sdk/) discovers and prompts agents; the host SDK (agent-sdk/) lets you register and serve one. Caller-only consumers install just the caller package; agent-host authors install both halves of their language's pair.
Both languages stay in lockstep on the wire format, validated by a cross-SDK interop test (tests/test_interop_e2e.py) that runs the TS reference agent against the Python client.
Wire protocol at a glance
caller (SDK) ──▶ NATS ──▶ agent host
▲ │
└─── streamed chunks ───────┘
A request is plain UTF-8 text or a JSON envelope {"prompt": "...", "attachments": [{"filename": "...", "content": "<base64>"}]}. The agent streams typed JSON chunks on the reply subject — {"type":"response","data":"..."} for content, {"type":"status","data":"ack"} for keep-alive, {"type":"query","data":{...}} for mid-stream questions — and ends with an empty-body, no-headers terminator. Errors use the Nats-Service-Error-Code header (400 client, 500 server).
Discovery is standard NATS micro:
nats req '$SRV.INFO.agents' '' --replies=0 --timeout=2s
nats sub 'agents.hb.*.*.*'
Full spec: https://github.com/synadia-ai/nats-agent-sdk-docs.
Quickstart
Both snippets use TypeScript and bring their own NatsConnection — use @nats-io/transport-node for TCP or wsconnect from @nats-io/nats-core for WebSocket.
Caller side — discover and prompt an agent
Uses the caller SDK (client-sdk/typescript/ → @synadia-ai/agents).
import { connect } from "@nats-io/transport-node";
import { Agents } from "@synadia-ai/agents";
const nc = await connect({ servers: "nats://localhost:4222" });
const agents = new Agents({ nc });
const [agent] = await agents.discover();
for await (const msg of await agent!.prompt("hello")) {
if (msg.type === "response") process.stdout.write(msg.text);
}
await agents.close();
await nc.close();
Host side — serve an agent on NATS