
Nats Channel
- 71 repo stars
- Updated July 23, 2026
- synadia-ai/synadia-agents
NATS channel plugin for Claude Code — bridges NATS messaging to Claude Code sessions
About
nats-channel is a Claude Code skill in the AI & Agent Building category. NATS channel plugin for Claude Code — bridges NATS messaging to Claude Code sessions
- nats-channel
- AI & Agent Building
- AI-coding skill
Nats Channel by the numbers
- Data as of Aug 5, 2026 (Skillselion catalog sync)
/plugin marketplace add synadia-ai/synadia-agents/plugin install nats-channel@synadia-pluginsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| repo stars | ★ 71 |
|---|---|
| Last updated | July 23, 2026 |
| Repository | synadia-ai/synadia-agents ↗ |
What it does
NATS channel plugin for Claude Code — bridges NATS messaging to Claude Code sessions
README.md
NATS Channel for Claude Code
Connect Claude Code to NATS messaging as a spec-compliant
Synadia Agent Protocol for NATS v0.3 agent
(verb-first subjects + status endpoint).
The MCP server registers an agents micro service, exposes a
prompt endpoint at agents.prompt.cc.<owner>.<name>, a status
endpoint at agents.status.cc.<owner>.<name> (replies with the same
payload as a heartbeat), publishes heartbeats at
agents.hb.cc.<owner>.<name> (the verb is the abbreviation hb,
§8.1 v0.3), and bridges prompt requests into the Claude Code session.
Replies stream back as typed JSON chunks
({"type":"response","data":"..."}) terminated by an empty headerless
message - the protocol's uniform end-of-stream signal.
Prerequisites
- Bun - the MCP server runs on Bun. Install with
curl -fsSL https://bun.sh/install | bash, and make surebunis on yourPATH. - NATS CLI - for managing contexts and testing.
- A NATS server to connect to (local or remote) - the plugin defaults to
demo.nats.io.
Quick Setup
1. Add the marketplace.
These are Claude Code commands - run claude to start a session first.
/plugin marketplace add synadia-ai/synadia-agents
2. Install the plugin.
/plugin install nats-channel@synadia-plugins
3. Launch with the channel flag.
claude --dangerously-load-development-channels plugin:nats-channel@synadia-plugins
By default, the server connects to demo.nats.io (no credentials required)
and registers a micro service on agents.prompt.cc.<owner>.<name>, where
<name> defaults to the working directory name.
4. (Optional) Configure the channel.
The /nats-channel:configure skill manages connection, session naming,
and permissions. All state lives in ~/.claude/channels/nats/config.json.
| Command | Description |
|---|---|
/nats-channel:configure |
Show current config, list available contexts, and offer to switch |
/nats-channel:configure list |
List available NATS CLI contexts |
/nats-channel:configure <context-name> |
Select a NATS CLI context to connect to |
/nats-channel:configure session <name> |
Override the session name (5th token in agents.prompt.cc.<owner>.<name>) |
/nats-channel:configure session clear |
Remove session name override, revert to CWD basename |
/nats-channel:configure owner <name> |
Override the owner (4th token in agents.prompt.cc.<owner>.<name>) |
/nats-channel:configure owner clear |
Remove owner override, revert to sanitized $USER |
/nats-channel:configure permissions terminal |
Prompt for permissions in the terminal (default) |
/nats-channel:configure permissions query |
Relay permission prompts as protocol query chunks |
/nats-channel:configure permissions clear |
Reset permissions to default |
/nats-channel:configure clear |
Remove all configuration |
To connect to your own NATS server, use a NATS CLI context. List your contexts
with nats context ls, then:
/nats-channel:configure <context-name>
This writes the selected context to ~/.claude/channels/nats/config.json.
The server reads connection details (URL, credentials) from
~/.config/nats/context/<name>.json.
5. Send a prompt.
With the @synadia-ai/agents
TypeScript SDK:
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 Claude")) {
if (msg.type === "response") process.stdout.write(msg.text);
}
await agents.close();
await nc.close();
Or directly via the NATS CLI (plain-text shorthand per spec §5.1):
nats req agents.prompt.cc.<owner>.<name> "Hello Claude" \
--replies=0 --reply-timeout=30s --timeout=90s
Claude's response streams back as typed JSON chunks on the reply subject; an empty headerless message signals completion.
Protocol compliance
This plugin implements the Synadia Agent Protocol for NATS v0.3 end-to-end:
- Registers as an
agentsNATS micro service (§3.1 - the bare subject-safe token). - Service metadata includes
agent,owner,session, andprotocol_version: "0.3"(§3.2). promptendpoint declares the server-negotiatedmax_payload(read fromnc.info.max_payloadat startup and formatted into the §2.1\d+(B|KB|MB|GB)grammar —1MBagainst a defaultnats-server, larger if the operator bumped--max_payload),attachments_ok: "true"(§2.1), and queue group"agents"(§3.3).- Accepts both plain-text shorthand and JSON envelopes with optional base64-encoded attachments (§5.1, §5.2, §5.3). Inbound attachments are staged to a per-request temp directory and exposed to Claude via file paths.
- Rejects malformed envelopes, empty payloads, oversize requests, and
invalid base64 with
Nats-Service-Error-Code: 400(§9). - Emits typed response chunks
{"type":"response","data":"..."}(§6.3) terminated by an empty headerless message (§6.5). Large responses are split into multiple UTF-8-safe chunks that each fit undermax_payload. - Publishes periodic
{"type":"status","data":"ack"}keep-alives (§6.4) every 30 s while a request is open, resetting the caller's 60-second inactivity timeout. - Publishes heartbeats at
agents.hb.cc.<owner>.<name>(§8.1 v0.3) every 5 s with the full §8.3 payload includinginstance_id(§8). - Relays Claude Code permission prompts as mid-stream
querychunks (§7) whenpermissions.mode = query.
The caller-side SDK at
client-sdk/typescript/ is the
canonical counterpart.
Session names
The micro service prompt subject is agents.prompt.cc.<owner>.<name> (v0.3 verb-first §2). Heartbeats go to agents.hb.cc.<owner>.<name> and the status endpoint replies on agents.status.cc.<owner>.<name>.
- Default: sanitized basename of the working directory (e.g.,
my-project) - Override: set
SYNADIA_CLAUDE_CODE_NAME(or the fleet-wideSYNADIA_NAME, or the legacyNATS_SESSION_NAME) env var, or use/nats-channel:configure session <name> - Owner: the 4th token defaults to the sanitized
$USER; override withSYNADIA_CLAUDE_CODE_OWNER(or the fleet-wideSYNADIA_OWNER), or/nats-channel:configure owner <name> - Multiple sessions: if the default name is already taken by another
claude-code instance owned by the same user, the plugin auto-appends
-2,-3, etc.
Discover running sessions via the protocol's discovery subjects:
nats req '$SRV.INFO.agents' '' --replies=0 --timeout=2s
nats req '$SRV.PING.agents' '' --replies=0 --timeout=2s
Or via the NATS Micro CLI:
nats micro ls
nats micro info agents
Tools exposed to the assistant
| Tool | Purpose |
|---|---|
reply |
Send a response over NATS. Takes request_id + text. The server wraps the text in a {"type":"response","data":...} chunk. Set done=false for intermediate replies; done=true (default) emits the empty-body terminator. |
Permissions
When Claude Code needs permission to run a tool, the plugin can either
prompt in the terminal (default) or relay the request as a protocol
query chunk on the active NATS stream. This is controlled by the
permissions config.
Terminal mode (default)
Permission prompts appear directly in the Claude Code terminal. No extra configuration needed.
Query mode
Permission requests are emitted as {"type":"query","data":{...}}
chunks on the active stream's reply subject (spec §7). The caller
replies on the query's dynamic _INBOX with yes/no, and the plugin
forwards the decision back to the harness.
/nats-channel:configure permissions query
To switch back to terminal mode:
/nats-channel:configure permissions terminal
The legacy value "nats" is still accepted as an alias for "query" so
old configs keep working. The older permissions.subject override field
has been removed - query chunks always use a fresh NATS inbox per
request.
If Claude asks for permission while no NATS request is active (for
example from direct terminal input), the plugin denies by default in
query mode; use permissions terminal instead if you want interactive
approval in that case.
Handling permission queries with the SDK
for await (const msg of await remote.prompt("rm -rf /tmp/stale")) {
if (msg.type === "query") {
await msg.reply("yes"); // or "no"
}
if (msg.type === "response") {
process.stdout.write(msg.text);
}
}
Or with the NATS CLI, by publishing to the reply_subject from the
query chunk:
nats pub _INBOX.Xj7k9Q2pA "yes"
If no reply is received within 2 minutes, the permission defaults to deny.
Access control
NATS server authentication and authorization handle access control. If a
user can connect and publish to agents.prompt.cc.<owner>.<name>, they can
interact with Claude. No additional pairing or allowlist is needed.
Anthropic auth
Set ANTHROPIC_API_KEY in your environment before launching claude.
Claude Code uses the env var in preference to any ~/.claude/
credentials, so logging out is unnecessary.
Bedrock / Vertex / Azure deployments work too — set the standard
provider env vars before launching claude and Claude Code will use
those instead.
Configuration
State lives in ~/.claude/channels/nats/:
| File | Purpose |
|---|---|
config.json |
Selected NATS context, session name override, and permission settings |
attachments/<request_id>/ |
Per-request staged attachments; auto-cleaned on reply completion |
NATS CLI contexts live in ~/.config/nats/context/<name>.json.
config.json
{
"context": "my-context",
"owner": "my-team",
"sessionName": "my-session",
"permissions": {
"mode": "query"
}
}
| Field | Default | Description |
|---|---|---|
context |
(none - uses demo.nats.io) | NATS CLI context name |
owner |
sanitized $USER |
Override the owner (4th subject token) |
sessionName |
CWD basename | Override the session name |
permissions.mode |
terminal |
terminal or query (nats accepted as legacy alias for query) |
Environment variables
Identity vars follow the SYNADIA_* convention shared across the agent
plugins: per-agent var > fleet-wide var > legacy alias / config file >
derived fallback.
| Variable | Overrides | Default |
|---|---|---|
SYNADIA_CLAUDE_CODE_OWNER, SYNADIA_OWNER |
Owner (4th token in agents.prompt.cc.<owner>.<name>); per-agent var wins, then fleet-wide, then config owner |
sanitized $USER |
SYNADIA_CLAUDE_CODE_NAME, SYNADIA_NAME |
Session name (5th token); per-agent var wins, then fleet-wide, then the legacy NATS_SESSION_NAME, then config sessionName |
sanitized basename of $CLAUDE_CWD |
NATS_SESSION_NAME |
Session name — legacy alias, still honored below the SYNADIA_* vars |
(unset — falls through to config sessionName, then the $CLAUDE_CWD basename) |
NATS_CONTEXT |
NATS CLI context to connect with (wins over config context) |
— |
NATS_URL |
Raw NATS URL; used when no context is set via env or config | demo.nats.io |
NATS_STATE_DIR |
State directory location | ~/.claude/channels/nats |
CLAUDE_CWD |
Working directory whose basename seeds the default session name | — |