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/omp-nats-channel

v0.8.0

Published

NATS channel bridge for Oh My Pi (OMP) — makes every OMP session a discoverable, spec-compliant Synadia Agent Protocol agent on NATS.

Downloads

1,613

Readme

@synadia-ai/nats-omp-channel

NATS channel extension for Oh My Pi (OMP). Every running OMP session becomes discoverable, addressable, and streamable over NATS — anyone with a Synadia Agent Protocol for NATS client (e.g. @synadia-ai/agents) can find your session, prompt it, and stream the reply back.

OMP registers under agent kind op to distinguish it from upstream pi. If you also run a vanilla pi, you'll see both side-by-side on the bus.

Protocol versions

This adapter advertises both v0.3 and v0.4 of the Synadia Agent Protocol on the same NATS micro service. v0.3 is the default discovery shape (metadata.protocol_version = "0.3"); v0.4 lives behind the sesh.* metadata namespace so legacy callers never see it:

  • metadata["sesh.protocol_version"] = "0.4"
  • metadata["sesh.v04_capabilities"] = "messages,artifacts,cards"

Callers (the sesh shim) publish prompts on agents.prompt.<machine>.<project>.<session>, receive streamed Message / statusUpdate events on agents.task.stream.<scope-kind>.<scope-id>.<task-id>, and fetch the OMP AgentCard from agents.card.<machine>.<session>.<name>. The clean v0.4 machine-rooted scheme is the only scheme; harness identity (oh-my-pi) lives in service metadata (the agent key), never in the subject.

Install

OMP doesn't have a plugin-install CLI today; wire the package in via config.yml:

# ~/.omp/agent/config.yml
extensions:
  - /absolute/path/to/omp-nats-channel

Install the package's own deps once:

cd /absolute/path/to/omp-nats-channel
bun install

Then start OMP normally:

omp

You should see Connected to NATS (<server>) as agents.prompt.<machine>.<project>.<session> on session start, and a footer status line ● nats://<machine>.<project>.<session> rendered above the editor.

Configure

Out of the box, no configuration is needed: OMP connects to demo.nats.io and derives the machine, project, and session tokens from its environment. Your session is reachable at:

agents.prompt.<machine>.<project>.<session>

For real deployments, point OMP at your own NATS via a context file. Two common setups:

Production with a NATS CLI context (already configured via nats context add):

// ~/.omp/agent/nats-channel.json
{
  "context": "prod"
}

Pin a stable session name (so callers can address the same logical session even if you cd around):

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

Restart OMP to pick up changes — or use the in-OMP commands below.

Configuration reference

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

| Field | Required | Default | Description | |-------|----------|---------|-------------| | context | no | — | Name of a NATS CLI context (file under ~/.config/nats/context/<name>.json). When unset, falls back to $NATS_URL, then the sesh hub at ~/.sesh/hub.nats.url if present, then the built-in demo.nats.io. | | sessionName | no | sanitized basename of CWD | The 5th subject token. Override to give your session a stable, addressable name. |

The owner token (4th) is always derived from $USER — there's no override for it. For multi-tenant isolation, use NATS accounts (server-side configuration).

Environment variables

Env vars override the config file:

| Variable | Sets | Notes | |----------|------|-------| | NATS_CONTEXT | context | Highest precedence. | | NATS_URL | raw URL (no auth context) | Used only when NATS_CONTEXT and config.context are both unset. | | SESH_SESSION | sessionName | Canonical sesh contract — set by sesh up --exec and orch-spawn SESH_* exports. Wins over NATS_SESSION_NAME. | | NATS_SESSION_NAME | sessionName | Legacy operator override; kept for back-compat. | | SESH_ROLE | metadata.role on the NATS Micro service registration | 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 and as role in sesh's session manifest. Default worker. | | SESH_CLASS | metadata.class on the NATS Micro service registration | One of active or observer. Coordination-subject routing keys on this: active agents subscribe to workers.*, observer agents subscribe to spies.*. Default active. |

Resolution order

  1. Built-in default — demo.nats.io, no auth
  2. Sesh hub URL — ~/.sesh/hub.nats.url if present
  3. $NATS_URL — raw URL fallback (only consulted when no context is set)
  4. config.context — wizard-set / hand-edited NATS CLI context
  5. $NATS_CONTEXT — wins over everything

For sessionName (first non-empty wins): $SESH_SESSION (canonical sesh contract — also resolved via .sesh/sessions/<label>.json state-walk when unset) → $NATS_SESSION_NAME (legacy operator override) → config.sessionName → sanitised CWD-basename.

In-OMP commands

Available inside a running OMP session:

| Command | What it does | |---------|--------------| | /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 |

/nats-configure writes the config file; restart OMP to apply. (Live reconnect on context switch is a deferral — see Limitations.)

Verify

# Find your session (and any other agents on the same NATS)
nats req '$SRV.INFO.agents' '' --replies=0 --timeout=2s

# Watch heartbeats — your session beats every ~5 s
nats sub 'agents.hb.*.*.*'

A successful $SRV.INFO.agents response for an OMP session looks like:

{
  "type": "io.nats.micro.v1.info_response",
  "name": "agents",
  "id": "JC8O0IGAWI5APOHLAOA96N",
  "version": "0.4.0",
  "description": "OMP agent (my-session) in /home/me",
  "metadata": {
    "agent": "op",
    "owner": "me",
    "session": "my-session",
    "protocol_version": "0.3",
    "cwd": "/home/me"
  },
  "endpoints": [
    {
      "name": "prompt",
      "subject": "agents.prompt.m4.my-project.my-session",
      "queue_group": "agents",
      "metadata": { "max_payload": "8MB", "attachments_ok": "true" }
    },
    {
      "name": "status",
      "subject": "agents.status.m4.my-project.my-session",
      "queue_group": "agents"
    }
  ]
}

The cwd metadata field tells you which working directory each session was started from — useful when you've got several OMP windows open.

Talk to your session

From the CLI:

# Plain text prompt
nats req agents.prompt.<machine>.<project>.<session> "What files are here?" \
  --wait-for-empty --reply-timeout 30s --timeout 120s

# JSON envelope (caller SDKs use this form)
nats req agents.prompt.<machine>.<project>.<session> '{"prompt":"What files are here?"}' \
  --wait-for-empty --reply-timeout 30s --timeout 120s

--wait-for-empty is required: replies stream as multiple chunks and end with an empty terminator message.

--reply-timeout matters too. Its default is 300 ms — the maximum gap allowed between consecutive replies. The agent publishes an immediate {type:"status",data:"ack"} chunk on request receipt, but the LLM's first response chunk typically lands 1–2 s later, so the default fires before the first response and the CLI exits after just the ack. Setting --reply-timeout 30s gives the LLM enough warm-up time. SDK callers (requestMany with strategy:"sentinel") don't hit this — they wait the full maxWait regardless of inter-arrival gaps.

From TypeScript using @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({ filter: { agent: "op" } });

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();

Attachments

When a request envelope carries attachments, each file is decoded and staged at:

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

The absolute paths are prepended to the prompt text so OMP's model can open them with its file tools. Files staged earlier in a session stay on disk so follow-up turns can reference them; the whole <session>/ directory is removed on session shutdown.

Encode files with base64 -w0 <file> (Linux/macOS) or Buffer.from(bytes).toString("base64") in Node before embedding in the JSON envelope. Caller SDKs do this for you.

Caller-side limits (rejected with 400 if violated):

  • content must be standard-alphabet padded base64 — no URL-safe variant, no whitespace.
  • filename must be a plain basename. Path separators, .., absolute paths, and NUL bytes are rejected, not silently flattened.
  • The fully-encoded request must fit within the server-negotiated max_payload (1 MB on a default nats-server, more if the operator raised --max_payload).

Concurrency

Each OMP session processes one NATS request at a time. Additional requests queue until the session is idle. The local TUI input and inbound NATS prompts share the same agent — typing locally during a NATS-driven turn means that local output flows to the NATS reply alongside the remote prompt's response.

Multiple OMP sessions on the same host register as distinct service instances; nats micro info agents aggregates across all of them. If two sessions try to register on the same owner + session, the later one auto-suffixes -2, -3, … — pick a stable name with /nats-configure session <name> if you want addressability.

Multi-tenancy

The agent subject layout has no per-tenant slot. For real isolation between tenants or environments, use NATS accounts and subject permissions — that's a server-side configuration, not an extension one. Within a single account, sessions with distinct owner values (i.e. different $USERs) coexist cleanly.

Limitations

Deliberate deferrals:

  • No mid-stream queries. OMP doesn't initiate permission prompts or clarifications over this channel; the protocol's query chunk type is supported by callers but never emitted by the OMP side.
  • No live reconfigure. /nats-configure writes the config file; OMP must be restarted for the new context or session name to apply.
  • TUI bleed. Local typing during a NATS-driven turn flows to the NATS reply subject as part of the response.
  • No custom statusline segment. OMP's StatusLineSegmentId enum is fixed; the NATS indicator renders in the hook status row above the editor, not inline with the model/path/cost segments.

Troubleshooting

  • ○ nats://disconnected in footer — run /nats-status, then check the context file at ~/.config/nats/context/<context>.json and that the NATS server is reachable.
  • ◐ nats://reconnecting... — the connection dropped; the client restores it automatically.
  • My session got a -2 suffix — another OMP session was already registered on the same owner + session. Use /nats-configure session <name> to pick a different one.
  • nats req returns only the initial ack and exits — pass --reply-timeout 30s (default is 300 ms, shorter than the gap between the ack chunk and the LLM's first response). See the "Talk to your session" section above for the full command. --wait-for-empty alone isn't enough.
  • nats req hangs or returns nothing — pass --wait-for-empty. The protocol ends streams with an empty-body message, not a single response.
  • 400 attachment[N] has invalid base64 content — the caller emitted URL-safe base64 or unpadded output. Buffer.from(bytes).toString("base64") (Node) produces the right form.
  • 400 attachment[N] has unsafe filename — send the basename only ("report.pdf"), not a path ("./reports/report.pdf").
  • Stale attachments piling up under ~/.omp/agent/attachments/ — clean session shutdown removes the whole <session>/ tree, but a force-quit or crash leaves the per-request UUID directories on disk. Safe to rm -rf ~/.omp/agent/attachments/<session>/ between runs if you don't need to re-reference earlier attachments.

See also

License

Apache-2.0