npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@agent-ops/claude-nats-channel

v0.8.0

Published

NATS channel bridge for Claude Code — exposes a Claude Code session as a discoverable, spec-compliant Synadia Agent Protocol agent on agents.prompt.<machine>.<project>.<session>.

Readme

NATS Channel for Claude Code

Connect Claude Code to NATS messaging as a spec-compliant Synadia Agent Protocol for NATS agent.

The MCP server registers an agents micro service, exposes a prompt endpoint at agents.prompt.<machine>.<project>.<session>, a status endpoint at agents.status.<machine>.<project>.<session> (replies with the same payload as a heartbeat), publishes heartbeats at agents.hb.<machine>.<project>.<session> (the verb is the abbreviation hb), and bridges prompt requests into the Claude Code session. Harness identity (claude-code) lives in the service metadata (agent key), not in the subject. 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 sure bun is on your PATH.
  • 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.<machine>.<project>.<session>, where <session> 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 (the <session> token in agents.prompt.<machine>.<project>.<session>) | | /nats-channel:configure session clear | Remove session name override, revert to CWD basename | | /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.<machine>.<project>.<session> "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.

Launching claude-code with the channel enabled

If you launch Claude Code via /plugin install (Quick Setup steps 1-3), the plugin marketplace pre-registers nats-channel as an approved channel and the inbound notification path "just works".

If you launch Claude Code directly with --mcp-config pointing at this server's config (e.g., in containerized / CI environments), you must also pass one of:

  • --channels <server-name> — production mode; requires claude.ai authentication and the channel name to be on your org's allowedChannelPlugins allowlist (managed settings).
  • --dangerously-load-development-channels <server-name> — local-dev mode; shows a one-time confirmation dialog at startup.

<server-name> is the key under mcpServers in your --mcp-config file (e.g., nats for the standard installation).

Without either flag, the channel's MCP notifications/claude/channel notifications are silently dropped by Claude Code's channel gate, and the model never starts a turn in response to an inbound NATS prompt — the channel still emits its §6.4 ack chunks, so callers see acks but no response, until they time out.

This requirement is enforced inside the claude-code binary at the tengu_mcp_channel_gate telemetry boundary; the MCP server's experimental.claude/channel capability handshake (declared in server.ts:586-589) is necessary but not sufficient.

v0.4 (A2A parity) advertisement

The channel advertises v0.4 capabilities via service metadata (sesh.protocol_version: "0.4", sesh.v04_capabilities: "messages,artifacts,cards") and registers these NATS micro endpoints, all keyed on the clean machine-rooted scheme (agents.<verb>.<machine>.<project>.<session>):

  • agents.prompt.<machine>.<project>.<session> — accepts an A2A Message envelope, drives Claude via the same MCP pipeline, and (when JetStream KV / Object Store buckets exist) durably appends Messages and publishes per-task stream events on agents.task.stream.*.
  • agents.card.<machine>.<session>.<name> — public L3 AgentCard partial.
  • agents.cardx.<machine>.<session>.<name> — auth-gated L3 AgentCard partial (the same payload — claude-nats-channel does not distinguish scope today; the shim re-applies access control upstream).

The clean v0.4 subject scheme is the only scheme: subjects are machine-rooted (agents.prompt.<machine>.<project>.<session>) and harness identity lives in service metadata (agent key), never in the subject.

KV/Object-Store wiring is best-effort: when buckets are not provisioned (e.g. running against demo.nats.io), the v2 handler still replies on the inbox; only the durable Message/Artifact writes are skipped, with a single startup log line per missing surface.

Protocol compliance

This plugin implements the Synadia Agent Protocol for NATS v0.3 end-to-end:

  • Registers as an agents NATS micro service (§3.1 - the bare subject-safe token).
  • Service metadata includes agent, owner, session, and protocol_version: "0.3" (§3.2).
  • prompt endpoint declares the server-negotiated max_payload (read from nc.info.max_payload at startup and formatted into the §2.1 \d+(B|KB|MB|GB) grammar — 1MB against a default nats-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 under max_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.<machine>.<project>.<session> (§8.1) every 5 s with the full §8.3 payload including instance_id (§8).
  • Relays Claude Code permission prompts as mid-stream query chunks (§7) when permissions.mode = query.

The caller-side SDK at client-sdk/typescript/ is the canonical counterpart.

Session names

The micro service prompt subject is agents.prompt.<machine>.<project>.<session> (clean v0.4 scheme; identity lives in metadata, not the subject). Heartbeats go to agents.hb.<machine>.<project>.<session> and the status endpoint replies on agents.status.<machine>.<project>.<session>.

The <project> token is the 40-char lowercase-hex SESH_PROJECT_ID pin when set (the canonical, collision-resistant project key; sesh up / sesh ≥ v0.6.0 inject it). When the pin is absent — e.g. launched outside sesh up — it falls back to the sanitized SESH_PROJECT slug. A pin set to a malformed value fails loudly at startup rather than silently misdelivering. The human-readable slug is display metadata; resolve a peer's subject via nats__resolve rather than hand-building it from the slug.

The <session> token resolves as:

  • Default: sanitized basename of the working directory (e.g., my-project)
  • Override: set NATS_SESSION_NAME env var, or use /nats-channel:configure session <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

Strict mode

NATS_CHANNEL_STRICT=1 makes the channel refuse to auto-suffix on (agent, owner, name) collision. By default (env var unset), a second instance trying to register the same triple as a live one auto-renames to <name>-2, <name>-3, etc. — useful for multiple parallel sessions, but problematic when a misconfiguration accidentally spawns a duplicate (the phantom is silent rather than loud).

Use strict mode when:

  • You're running claude-nats-channel in a containerized or unattended environment where a phantom duplicate registration should be a loud failure (exit code 2).
  • You've co-located claude-code with Oh My Pi, and OMP's mcp.discoveryMode: true may autoload claude's .mcp.json — strict mode catches the resulting double-spawn before the bus sees a phantom <name>-2 instance.

To opt back out (re-enable auto-suffixing), unset the env var or set NATS_CHANNEL_STRICT=0.

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.<machine>.<project>.<session>, 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",
  "sessionName": "my-session",
  "permissions": {
    "mode": "query"
  }
}

| Field | Default | Description | | --- | --- | --- | | context | (none - uses demo.nats.io) | NATS CLI context name | | sessionName | CWD basename | Override the session name | | permissions.mode | terminal | terminal or query (nats accepted as legacy alias for query) |

Environment variables

| Variable | Overrides | Default | | --- | --- | --- | | NATS_SESSION_NAME | Session name (the <session> token in agents.prompt.<machine>.<project>.<session>) | sanitized basename of $CLAUDE_CWD | | NATS_STATE_DIR | State directory location | ~/.claude/channels/nats | | NATS_CHANNEL_STRICT | When 1, refuse to auto-suffix on (agent, owner, name) collision (exit 2). See Strict mode. | unset (auto-suffix) | | SESH_ROLE | Free-form role token (^[a-z0-9_-]+$, 1–63 chars). Identifies the function this agent plays in the swarm — e.g. implementer, verifier, spy. Surfaced as metadata.role on the NATS Micro service and as role in sesh's session manifest. | worker | | SESH_CLASS | One of active or observer. Coordination-subject routing keys on this: active agents subscribe to workers.*, observer agents subscribe to spies.*. | active |