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

@m64/nats-pi-channel

v0.4.1

Published

NATS Agent Protocol channel for PI Agent. Makes every PI session a discoverable, spec-compliant agent on NATS.

Readme

@synadia/nats-pi-channel

Currently published on npm as @m64/nats-pi-channel; moving to @synadia/nats-pi-channel once Synadia publishing access lands. Install commands below use the current name.

NATS channel for PI Agent, implementing the NATS Agent Protocol v0.2.0.

Every PI session becomes a discoverable, addressable, streaming agent on NATS. Callers using any SDK that speaks the protocol - e.g. @synadia/agents - can enumerate running PI sessions, prompt them, and stream responses back.

Sibling implementations (same wire protocol): claude-code, openclaw.

How it works

On session start the extension:

  1. Connects to NATS using a configured context (or demo.nats.io by default).
  2. Registers a NATS micro service named agents with spec metadata (agent, owner, session, protocol_version).
  3. Adds a prompt endpoint at agents.pi.<owner>.<session> advertising max_payload: 1MB and attachments_ok: true.
  4. Begins publishing heartbeats on agents.pi.<owner>.<session>.heartbeat every 30 s.
  5. On each inbound prompt: decodes any attached files to ~/.pi/agent/attachments/<session>/<uuid>/<filename>, prepends their absolute paths to the prompt text, emits a status: ack chunk, injects the augmented prompt into PI via pi.sendUserMessage(), streams text_delta events back as typed {type:"response",data} chunks, and closes with the spec-mandated empty-body no-headers terminator.
  6. Malformed envelopes, oversized payloads, invalid base64, and unsafe filenames are rejected at the wire with Nats-Service-Error-Code: 400. Staging failures (disk full, permission denied) return 500.

Multiple PI sessions on the same host register as distinct instances of the same service, each with a unique prompt endpoint subject - nats micro info agents aggregates across all of them.

Install

# From npm (once published)
pi install npm:@m64/nats-pi-channel

# From a local clone during development
pi install /absolute/path/to/nats-pi-channel

Then start PI normally:

pi

You should see Connected to NATS (<server>) as agents.pi.<you>.<session> and a footer status NATS: agents.pi.<you>.<session>.

Configure

Config lives at ~/.pi/agent/nats-channel.json:

{
  "context": "my-nats-context",
  "sessionName": "my-session"
}

| Field | Required | Default | Description | |-------|----------|---------|-------------| | context | no | demo.nats.io | NATS CLI context name in ~/.config/nats/context/ | | sessionName | no | sanitized basename of CWD | Overrides the 4th subject token |

Environment variables take precedence over the file:

  • NATS_CONTEXT - select a NATS CLI context
  • NATS_SESSION_NAME - override the session name

In-PI commands

  • /nats-status - show current subject, service, instance id, protocol version, pending/queued counts
  • /nats-configure - print current config
  • /nats-configure <context> - switch NATS context
  • /nats-configure session <name> - override session name
  • /nats-configure session clear - revert to CWD basename

Changes take effect after restarting PI.

Tenant isolation

The spec reserves the subject structure for protocol use; there is no org segment. For multi-tenant isolation, use NATS accounts and subject permissions (spec §10.1). Within an account, collisions between two PI sessions on the same owner + session auto-suffix -2, -3, …

Subject hierarchy

agents.pi.<owner>.<session>             # prompt endpoint (spec §2, §5)
agents.pi.<owner>.<session>.heartbeat   # liveness beacon (spec §8)
  • pi is both metadata.agent and its subject abbreviation (Appendix C).
  • owner: sanitized $USER.
  • session: sanitized basename of CWD, overridable.

Talking to a running PI session

Any caller speaking the protocol - a spec-compliant SDK or the nats CLI - can:

# Enumerate all compliant agents (includes Claude Code, OpenClaw, etc.)
nats req '$SRV.INFO.agents' '' --replies=0 --timeout=2s

# Send a plain-text prompt
nats req agents.pi.<owner>.<session> "What files are in the current directory?" --wait-for-empty --timeout 120s

# Or a JSON envelope
nats req agents.pi.<owner>.<session> '{"prompt":"What files are here?"}' --wait-for-empty --timeout 120s

With the TypeScript SDK:

import { connect } from "@nats-io/transport-node";
import { Agents } from "@synadia/agents";

const nc = await connect({ servers: "nats://localhost:4222" });
const agents = new Agents({ nc });

const [agent] = await agents.discover({ filter: { agent: "pi" } });

for await (const msg of await agent!.prompt("What files are here?")) {
  if (msg.type === "response") process.stdout.write(msg.text);
}

await agents.close();
await nc.close();

Wire protocol (summary)

Full spec: https://github.com/synadia-ai/nats-agent-sdk-docs. Quick reference:

  • Request: plain UTF-8 text OR JSON {"prompt":"…","attachments":[{"filename":"…","content":"<base64>"},…]}. Attachment content must be RFC 4648 §4 base64 (standard alphabet, padded, no URL-safe variant, no whitespace).
  • Response: one or more typed chunks on the reply subject:
    • {"type":"response","data":"<text>"} - content
    • {"type":"status","data":"ack"} - accepted / keep-alive
  • Terminator: empty body and no headers (spec §6.5).
  • Errors: Nats-Service-Error-Code header with 400/500, followed by the terminator.

Discovery

Any NATS Agent Protocol SDK will enumerate PI sessions automatically. Without an SDK:

# Micro service framework
nats micro list           # shows all agents instances
nats micro info agents

# Heartbeats - track liveness without polling
nats sub 'agents.*.*.*.heartbeat'

Concurrency

Each PI session processes one NATS request at a time. Additional requests queue until the agent is idle. The user's local TUI input and inbound NATS prompts share the same agent session.

Attachments

When a request envelope contains attachments, each file is decoded and staged on disk at:

~/.pi/agent/attachments/<session>/<uuid>/<filename>

The absolute paths are then prepended to the prompt as:

[Attachments available at the following absolute paths]
- /home/you/.pi/agent/attachments/myproj/abcd-…/vacation.jpg

<original prompt text>

PI's model sees the list in the user message and can open the files with its file tools. The entire <session> directory is removed on session_shutdown; within a session, attachments from earlier turns remain on disk so follow-up turns can still reference them.

Caller-side constraints (rejected at the wire with 400 if violated):

  • content must be strict RFC 4648 §4 base64 - standard alphabet, padded, no URL-safe, no whitespace.
  • filename must be a plain basename. Path separators (/, \), .., absolute paths, and NUL bytes are rejected rather than silently flattened.
  • Full encoded envelope must fit within max_payload (1 MB).

Spec §5.5 reserves a future attachments endpoint at agents.pi.<owner>.<session>.attachments for chunked large-file upload; that lands in protocol 0.2 and will coexist with inline attachments.

Limitations

Deliberate deferrals:

  • No mid-stream queries. PI doesn't currently initiate permission prompts or clarifications over this channel; the spec's query chunk type (§7) is supported by callers but never emitted.
  • No live reconfigure. /nats-configure writes the config file; restart PI to apply.
  • TUI bleed. If the user types locally during a NATS-driven turn, that output flows to the NATS reply subject alongside the prompt's response.

Troubleshooting

  • NATS: disconnected in footer. Check /nats-status, the context file at ~/.config/nats/context/<context>.json, and NATS server reachability.
  • NATS: reconnecting…. Connection dropped; restoring automatically.
  • My session got a -2 suffix. Another PI session on the same owner + session was already registered. Use /nats-configure session <name> to pick a different name.
  • nats req returns nothing or hangs. Pass --wait-for-empty; the protocol signals end-of-stream with an empty-body message, not a single response.
  • 400 attachment[N] has invalid base64 content. The SDK / client emitted URL-safe base64 or unpadded output. Switch to RFC 4648 §4 (standard alphabet, padded) - Node's Buffer.from(bytes).toString("base64") produces the correct form.
  • 400 attachment[N] has unsafe filename. Path separators, .., absolute paths, or NUL in filename. Send the basename only (e.g. "report.pdf", not "./reports/report.pdf").

License

MIT