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

@shaoweiz/agenttown-pairing-server

v0.2.2

Published

AgentTown runtime pairing rendezvous server.

Readme

AgentTown Pairing Server

Small rendezvous and relay server for ClawPilot-style AgentTown pairing.

The preferred flow is relay mode: the runtime registers with this server, receives a short code, then keeps an outbound WebSocket open to the server. The AgentTown App redeems the code and sends runtime RPCs through this server. The user only types AT-XXXX-XXXX-XXXX; the App does not need direct access to 127.0.0.1 on the runtime machine.

The older descriptor rendezvous endpoints are still present for direct-network deployments.

API

  • GET /health
  • POST /api/runtime-pairings
    • Runtime observer registers { type, pairingCode, descriptor }.
    • If AGENTTOWN_PAIRING_TOKEN is set on the server, this endpoint requires Authorization: Bearer <token>.
  • POST /api/runtime-pairings/redeem
    • App sends { "pairingCode": "AT-XXXX-XXXX-XXXX" }.
    • Server returns { type, descriptor } once, then removes the code.
  • POST /api/relay/register
    • Runtime registers { type, runtimeType, displayName, machineId, capabilities }.
    • If AGENTTOWN_PAIRING_TOKEN is set on the server, this endpoint requires Authorization: Bearer <token>.
    • Server returns { gatewayId, relaySecret, accessCode, relayUrl }.
  • GET /relay/<gatewayId>?secret=<relaySecret>
    • Runtime opens this WebSocket and waits for commands.
  • POST /api/relay/redeem
    • App sends { "accessCode": "AT-XXXX-XXXX-XXXX" }.
    • Server returns { gatewayId, clientToken, relayUrl, connected }.
  • POST /api/relay/rpc
    • App sends { gatewayId, method, params } with Authorization: Bearer <clientToken>.
    • Server forwards the command to the connected runtime WebSocket.
  • GET /monitor
    • Browser monitor page for live server events.
  • GET /api/monitor/events
    • Returns recent sanitized monitor events.
  • GET /api/monitor/stream
    • Streams sanitized monitor events as Server-Sent Events.

Descriptors are validated before storage. They must be agenttown.runtime_pairing.v1, must not contain plaintext pairingCode, and must not contain token/password/apiKey/cookie/Bearer/SSH/private-key style secrets.

Monitor endpoints require the same bearer token as AGENTTOWN_PAIRING_TOKEN when a registration token is configured. If the server was intentionally started without a token, monitor API access is limited to loopback clients. Monitor output is sanitized: pairing codes, access codes, relay secrets, client tokens, bearer values, and credential-looking fields are masked.

Install On Linux

If published to npm:

sudo npm install -g @shaoweiz/agenttown-pairing-server

If npm is missing on OpenCloudOS/CentOS/RHEL:

dnf install -y nodejs npm

If the distro Node.js is older than 20:

curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
dnf install -y nodejs

Published Docker image:

docker pull ghcr.io/zsw12abc/agenttown-pairing-server:0.1.0

From this repository:

git clone https://github.com/zsw12abc/AgentTownPlugin.git
cd AgentTownPlugin/agenttown-pairing-server
sudo npm install -g .

Create a strong registration token:

PAIRING_TOKEN=$(openssl rand -hex 32)
echo "$PAIRING_TOKEN"

Install and start the systemd service:

sudo agenttown-pairing-server install \
  --public-url http://<server-public-ip>:8787 \
  --port 8787 \
  --register-token "$PAIRING_TOKEN"

Open TCP 8787 on both the server firewall and the cloud provider security group:

firewall-cmd --permanent --add-port=8787/tcp
firewall-cmd --reload

Manual start without systemd:

AGENTTOWN_PAIRING_TOKEN=<PASTE_TOKEN_HERE> \
AGENTTOWN_PAIRING_PUBLIC_URL=https://pair.example.com \
agenttown-pairing-server serve --host 0.0.0.0 --port 8787

Put Nginx/Caddy/Cloudflare in front of port 8787 and expose HTTPS at https://pair.example.com.

Check:

agenttown-pairing-server status
curl http://127.0.0.1:8787/health
curl http://<server-public-ip>:8787/health

Open the live monitor:

http://<server-public-ip>:8787/monitor

Paste AGENTTOWN_PAIRING_TOKEN into the page to watch plugin/App traffic in real time.

For production, prefer a domain with HTTPS, for example https://pair.example.com, reverse-proxied to http://127.0.0.1:8787.

Docker

From this repository:

git clone https://github.com/zsw12abc/AgentTownPlugin.git
cd AgentTownPlugin/agenttown-pairing-server
docker build -t shaoweiz/agenttown-pairing-server:0.1.0 .

Run with Docker:

docker volume create agenttown-pairing-data
docker run -d \
  --name agenttown-pairing-server \
  --restart unless-stopped \
  -p 8787:8787 \
  -e AGENTTOWN_PAIRING_PUBLIC_URL=https://pair.example.com \
  -e AGENTTOWN_PAIRING_TOKEN=<PASTE_TOKEN_HERE> \
  -v agenttown-pairing-data:/data \
  shaoweiz/agenttown-pairing-server:0.1.0

Or use Docker Compose:

export AGENTTOWN_PAIRING_TOKEN=<PASTE_TOKEN_HERE>
docker compose up -d --build

Check the server:

curl https://pair.example.com/health
docker logs agenttown-pairing-server

Docker upgrade from this repository:

cd AgentTownPlugin
git pull --ff-only
cd agenttown-pairing-server
docker compose up -d --build

Docker uninstall:

docker compose down
docker volume rm agenttown-pairing-data

The volume stores pending short-lived pairings. Removing it clears outstanding pairing codes.

Publish Releases

GitHub Actions can publish both npm and Docker when a version tag is pushed.

Required repository setup:

  • Add GitHub secret NPM_TOKEN with npm publish permission.
  • Ensure the npm package scope in package.json exists. The default is @shaoweiz/agenttown-pairing-server; change it if you publish under your own npm scope.
  • Enable GitHub Actions package write permission for this repository if it is not already enabled.

Release:

cd AgentTownPlugin/agenttown-pairing-server
npm version patch --no-git-tag-version
cd ..
git add agenttown-pairing-server/package.json
git commit -m "Release AgentTown observers v0.1.3"
git tag v0.1.3
git push origin main --tags

The workflow publishes:

  • npm: @shaoweiz/agenttown-pairing-server
  • npm: @shaoweiz/hermes-agenttown-observer
  • npm: @shaoweiz/openclaw-agenttown-observer
  • Docker: ghcr.io/<github-owner>/agenttown-pairing-server:<version>
  • GitHub Release assets:
    • hermes-agenttown-observer-<version>.tar.gz
    • openclaw-agenttown-observer-<version>.tar.gz
    • APP-ADAPTATION.md
    • CHANGELOG.md

You can also run the workflow manually from GitHub Actions with a version input, but the version must match agenttown-pairing-server/package.json.

Runtime Pairing With Relay

On the OpenClaw/Hermes runtime machine, set the same token for registration:

export AGENTTOWN_PAIRING_TOKEN=<PASTE_TOKEN_HERE>

Install OpenClaw observer from npm:

npm install -g @shaoweiz/openclaw-agenttown-observer
openclaw plugins install @shaoweiz/openclaw-agenttown-observer
openclaw plugins enable agenttown-observer
openclaw gateway restart

OpenClaw:

agenttown relay-pair --agenttown-url https://pair.example.com --endpoint http://127.0.0.1:18789 --code-only
agenttown relay --endpoint http://127.0.0.1:18789

Install Hermes observer from npm:

npm install -g @shaoweiz/hermes-agenttown-observer
agenttown-hermes-observer install --plugins-dir <Hermes plugins dir>
hermes plugins enable agenttown-observer
hermes gateway

Hermes direct descriptor mode is still available until the Hermes observer grows an outbound relay client:

agenttown pair --agenttown-url https://pair.example.com --endpoint <AgentTown能访问到的Hermes地址> --code-only

The command prints only:

AT-XXXX-XXXX-XXXX

The AgentTown App should ask the user only for that code. In OpenClaw relay mode, the App should redeem /api/relay/redeem and then call /api/relay/rpc; it should not try to fetch http://127.0.0.1:18789 from the App device.

Direct descriptor endpoint examples:

  • OpenClaw same machine or SSH tunnel: http://127.0.0.1:18789
  • Hermes same machine or SSH tunnel: http://127.0.0.1:8642
  • Remote runtime: use a LAN/VPN/Tailscale/SSH tunnel address reachable from the AgentTown App machine.

Do not expose Hermes/OpenClaw gateway directly to the public internet just for pairing.

Verify observer status:

agenttown status

App Redeem

Relay mode:

curl -s https://pair.example.com/api/relay/redeem \
  -H 'Content-Type: application/json' \
  -d '{"accessCode":"AT-XXXX-XXXX-XXXX"}'

Then call the runtime through the relay:

curl -s https://pair.example.com/api/relay/rpc \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <clientToken>' \
  -d '{"gatewayId":"<gatewayId>","method":"agenttown.status","params":{}}'

Direct descriptor mode:

curl -s https://pair.example.com/api/runtime-pairings/redeem \
  -H 'Content-Type: application/json' \
  -d '{"pairingCode":"AT-XXXX-XXXX-XXXX"}'

The server returns the sanitized descriptor once. The App should then probe the runtime observer status and confirm pairing.challengeId and pairing.codeHash.

Live Monitor

The pairing server keeps the latest 500 sanitized events in memory and streams new events to the monitor page.

Browser:

https://pair.example.com/monitor

History API:

curl -s https://pair.example.com/api/monitor/events \
  -H "Authorization: Bearer <AGENTTOWN_PAIRING_TOKEN>"

Realtime SSE stream:

curl -N https://pair.example.com/api/monitor/stream \
  -H "Authorization: Bearer <AGENTTOWN_PAIRING_TOKEN>"

Useful event types include:

  • relay.register.request
  • relay.register.created
  • relay.websocket.connected
  • relay.websocket.message
  • relay.redeem.request
  • relay.redeem.success
  • relay.rpc.request
  • relay.rpc.command_sent
  • relay.rpc.success
  • pairing.register.request
  • pairing.redeem.request

The monitor is for diagnosis. Do not treat it as an audit log; events are in memory and reset when the server restarts.

Upgrade

If installed from npm:

sudo agenttown-pairing-server upgrade

upgrade and update are aliases. Both run npm install -g @shaoweiz/agenttown-pairing-server and then restart the agenttown-pairing-server systemd service automatically:

sudo agenttown-pairing-server update

If installed from this repository before publishing, update the checkout and reinstall:

cd AgentTownPlugin
git pull --ff-only
cd agenttown-pairing-server
sudo npm install -g .
sudo systemctl restart agenttown-pairing-server

Uninstall

sudo agenttown-pairing-server uninstall
sudo npm uninstall -g @shaoweiz/agenttown-pairing-server

Status

agenttown-pairing-server status
curl https://pair.example.com/health
docker logs agenttown-pairing-server