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-relay-channels-host

v0.129.7

Published

Channels host connector for Agent Relay — bundles N lightweight egress adapters (ntfy, webhook, …) behind one agent-relay.connector.v1 channel connector. Core ships zero per-service transport.

Readme

agent-relay-channels-host

The channels host is a single agent-relay.connector.v1 connector (kind:"channel") that bundles N lightweight egress adapters for the long tail of trivial third-party integrations (ntfy, generic webhook, slack/discord-egress, …). It keeps Agent Relay core free of per-service transport code — core owns only the registry, routing, and the channel.v1 contract; the actual HTTP/push for each service lives in an adapter here.

Heavyweight, stateful, two-way integrations (Telegram-class) keep their own repo. This host is for one-way / egress-only and other ~30-line adapters.

Status: the host (#778) installs, registers as a channel connector, and is health-polled by the existing connector subsystem. ntfy (#774) is the first bundled adapter; it registers ntfy:default (outbound) only when NTFY_TOPIC is set, so an unconfigured install still registers zero channels cleanly.

Productionized (#794): published as part of the agent-relay lockstep release set and installed into ~/.agent-relay/runtime as a dependency of agent-relay-server. The relay auto-registers and auto-starts this connector on boot (src/connectors.tsensureChannelsHostConnector), so it survives deploys/restarts with no manual register/start. ntfy adapter config is persisted in the connector's config.json and migrated once from the legacy core channel-type/ntfy setting.

How it plugs into Agent Relay

The host reuses the existing connector lifecycle machinery (src/connectors.ts) — it is a client of that subsystem, not a reimplementation:

  • Register the connector: POST /api/connectors with the manifest (src/index.ts registerroutes/connectors.ts). The manifest declares the start/stop/restart/status/doctor commands the relay drives, and an aggregated configSchema.
  • Lifecycle: the relay spawns start (which detaches the long-running daemon), stop, restart, status, doctor with a 30s timeout and persists their JSON output as connector state. The 60s status poller keeps the dashboard honest.

The adapter interface

Adapters implement ChannelAdapter (src/adapter.ts). The host owns all relay plumbing, so an adapter never touches SSE, agent registration, or tokens:

| verb | owner | what it does | | --- | --- | --- | | registerChannel() | host | POST /api/agents with the integration token for each ChannelSpec: id provider:account, kind:"channel", meta.direction. Core derives the channel row + directionality from this. | | onOutboundMessage() | host | subscribe GET /api/events?for=<channelAgentId>; the relay fans out only message.new frames addressed to that agent. | | push() | adapter | the only transport an adapter writes — deliver one outbound message to the service. |

import type { ChannelAdapter } from "agent-relay-channels-host/adapter";

export const myAdapter: ChannelAdapter = {
  provider: "ntfy",
  displayName: "ntfy",
  configSchema: { properties: { NTFY_TOPIC: { type: "string" } }, required: ["NTFY_TOPIC"] },
  channels(ctx) {
    const topic = ctx.get("NTFY_TOPIC");
    return topic ? [{ account: "default", direction: "outbound", config: { topic } }] : [];
  },
  async push(message, channel, ctx) {
    const topic = channel.config?.topic as string;
    await fetch(`https://ntfy.sh/${topic}`, { method: "POST", body: message.body });
  },
};

Register it by appending to src/adapters/index.ts — no host or core changes:

export const adapters: ChannelAdapter[] = [ntfyAdapter, myAdapter];

See src/adapters/ntfy.ts for the reference implementation.

Each adapter's configSchema fragment is merged into the connector manifest's aggregated configSchema (src/manifest.ts); dashboard-managed settings flow back to the adapter through ctx.get(name) (precedence: process.env > connector config.json).

CLI

agent-relay-channels-host <start|stop|restart|status|doctor|register|manifest|daemon>
  • registerPOST /api/connectors with the aggregated manifest.
  • manifest — print the aggregated manifest as { manifest } JSON (no relay call). The relay's boot auto-register spawns this from the deployed binary, so the manifest's binary/commands resolve to the installed runtime path, never a repo-tree path.
  • start — detach the daemon, report {status, running, endpoint}.
  • status / doctor — JSON the relay persists as connector state.
  • daemon — internal long-running process (SSE subscriptions + push routing + status server).

Config

| key | default | purpose | | --- | --- | --- | | AGENT_RELAY_URL | http://127.0.0.1:4850 | relay base the host registers channels against | | AGENT_RELAY_TOKEN | — | integration/component token (agent:write); empty on a tokenless localhost relay | | CHANNELS_HOST_PORT | 4863 | daemon status HTTP server port |

Plus every bundled adapter's namespaced keys. ntfy:

| key | default | purpose | | --- | --- | --- | | NTFY_TOPIC | — | topic to publish to; empty disables the ntfy channel | | NTFY_SERVER_URL | https://ntfy.sh | ntfy server base URL | | NTFY_TOKEN | — | optional access token (sent as Bearer) | | NTFY_DEFAULT_PRIORITY | default | priority when the event omits one (minurgent) | | NTFY_DEFAULT_TAGS | — | comma-separated tags merged into every notification | | NTFY_DEFAULT_CLICK | — | default click-through URL | | NTFY_TIMEOUT_MS | 15000 | per-request timeout |