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

muxclaw

v2.0.0

Published

Multi-client AI coding agent router via Telegram/WhatsApp

Readme

MuxClaw

A lightweight Node.js system that maps Telegram/WhatsApp group chats to client projects and triggers an AI coding agent (Pi or OpenCode) to make code changes on demand.

Architecture

Telegram / WhatsApp
        |
+-------------------------------+
|  Layer 1: Router (stateless)  |  bot.ts + router.ts
|  Maps chatId -> project agent |
+---------------+---------------+
                |
+-------------------------------+  one per project, persistent
|  Layer 2: Chat Agent          |  chat-agent.ts (Anthropic SDK)
|  Owns conversation + tools.   |
|  chatModel (default: Haiku)   |
+---------------+---------------+
                | (when coding needed)
+-------------------------------+  ephemeral Docker container per job
|  Layer 3: Worker              |  docker.ts + pi.dockerfile
|  Pi or OpenCode runs inside.  |
|  workerModel (default: Sonnet)|
|  Only project dir mounted.    |
+-------------------------------+
                |
    Dev server (hot reload) + Cloudflare tunnel
                |
    client-a.yourdomain.com

Quick Start

1. Prerequisites

Install the following on your machine (local Mac/Linux or remote VM):

| Tool | Install | Purpose | |------|---------|---------| | Node.js >= 24 | nvm or nodejs.org | Runtime | | pnpm | npm install -g pnpm | Package manager | | Docker | docs.docker.com | Worker containers | | git | Pre-installed on most systems / sudo apt install git | Version control | | curl | Pre-installed on most systems / sudo apt install curl | Used by preview scripts | | GitHub CLI (gh) | brew install gh / sudo apt install gh | Auto-create project repos | | cloudflared | brew install cloudflared / cloudflare docs | Preview tunnels |

Optional:

| Tool | Install | Purpose | |------|---------|---------| | pm2 | npm install -g pm2 | Run router as always-on daemon (pnpm daemon:install) | | Claude CLI | claude.ai/download | Generate setup tokens (claude setup-token) for subscription auth |

Telegram bot setup

  1. Open Telegram and message @BotFather
  2. Send /newbot, follow prompts to name your bot
  3. Copy the bot token — set it as TELEGRAM_BOT_TOKEN in .env
  4. Disable privacy mode so the bot sees all group messages: send /setprivacy to BotFather, select your bot, choose Disable

Cloudflare account

Sign up at dash.cloudflare.com (free tier is enough). You need a Cloudflare account to:

  • Deploy projects to Workers (pnpm staging / pnpm deploy)
  • Use named tunnels for preview (optional — quick tunnels work without an account)

Wrangler auth (for deployment)

npx wrangler login                     # one-time, opens browser to authorize Cloudflare

On a headless VM, use an API token instead:

export CLOUDFLARE_API_TOKEN=<your-token>   # create at dash.cloudflare.com/profile/api-tokens

This is only needed when you deploy projects to Cloudflare Workers. You can skip this until step 8.

GitHub CLI auth

Local machine (GUI):

gh auth login                          # opens browser
gh auth refresh -h github.com -s workflow  # add workflow scope for CI/CD

Headless VM (no GUI):

gh auth login -h github.com -w        # prints a code, open URL on any device
gh auth refresh -h github.com -s workflow

Set git protocol to HTTPS (avoids SSH key setup):

gh auth setup-git                      # configures git to use gh token

Cloudflare tunnel auth (optional)

cloudflared tunnel login               # one-time, opens browser (or use device code on VM)

This stores ~/.cloudflared/cert.pem. Only needed if using named tunnels — quick tunnels (default) work without it.

2. Setup

./setup.sh

This installs dependencies, approves build scripts, adds your user to the docker group (if needed), builds Docker images, and creates .env from the template.

Note: If your user was just added to the docker group, you must log out and back in (or reboot) for the group to take effect. Then re-run ./setup.sh — it's idempotent.

3. Configure environment

Edit .env (created by setup.sh):

TELEGRAM_BOT_TOKEN=your_token_here

# Pick ONE auth method:
ANTHROPIC_API_KEY=           # pay-per-token
ANTHROPIC_OAUTH_TOKEN=       # Claude subscription (claude setup-token)

Option A — API key (pay-per-token): Get your key from console.anthropic.com/account/keys and set ANTHROPIC_API_KEY.

Option B — Setup token (Claude subscription): Requires the Claude CLI installed (see prerequisites). Run:

claude setup-token

Copy the token (starts with sk-ant-oat-) and set ANTHROPIC_OAUTH_TOKEN. This routes through your Claude subscription — no per-token billing.

4. Create a project

Option A: Scaffold a new Astro site (recommended for web projects)

pnpm create-project my-project --name "My Project"

This scaffolds an Astro + TailwindCSS + Cloudflare Workers project under projects/my-project/, installs dependencies, inits git, and registers it with the router. Each scaffolded project includes:

| Script | What | Use case | |--------|------|----------| | pnpm dev | Astro dev server (localhost) | Developer working locally | | pnpm preview | Dev server + Cloudflare tunnel | AI agent + client hot reload | | pnpm staging | Build + deploy to Workers staging | Client approval before go-live | | pnpm deploy | Build + deploy to Workers production | Production release |

Options: --dir <path>, --tunnel <name>, --worker, --chat-model, --worker-model

To configure preview, set TUNNEL_NAME in the project's .env (or pass --tunnel at creation time). Without a tunnel name, pnpm preview uses a quick tunnel with a random URL.

Option B: Register an existing project

pnpm add-project my-project /path/to/existing --name "My Project"

The project directory must be a git repo. If the project has a scripts/preview.sh, the router will use it for live preview sessions. Options: --repo, --worker, --chat-model, --worker-model

5. Start the bot

pnpm start       # production
pnpm run dev     # development (auto-restart)

Startup validates: Docker running, Docker images built, auth configured, Telegram token set (if needed).

6. Add a channel

Add the bot to a Telegram group (or WhatsApp), then @mention it once. The chat ID is logged to the console via [discovery]:

[discovery] Unknown chat: platform=telegram id=-1001234567890 title="My Group" type=supergroup

Copy the ID and attach it:

pnpm add-channel my-project telegram -1001234567890

Restart the bot to pick up the new channel. A project can have multiple channels:

pnpm add-channel my-project whatsapp [email protected]

7. Deploy (when ready)

Deploy from the router using deploy-project:

pnpm deploy-project my-project staging      # deploy to my-project-staging.workers.dev
pnpm deploy-project my-project production   # deploy to production

Or from the project directory directly:

cd projects/my-project
pnpm staging    # deploy to staging
pnpm deploy     # deploy to production

Requires wrangler auth — see Wrangler auth in prerequisites.

8. Enable WhatsApp (optional)

WhatsApp support uses Baileys (no official API / business account needed).

  1. Uncomment startWhatsApp() in src/bot.ts
  2. Start the router — a QR code appears in the terminal
  3. Scan the QR code with WhatsApp on your phone (Settings > Linked Devices > Link a Device)
  4. Auth state is saved in whatsapp-auth/ — you only need to scan once

Add WhatsApp channels the same way as Telegram:

pnpm add-channel my-project whatsapp [email protected]

The chat ID is logged to the console via [discovery] when someone messages a group the bot is in.

9. Run as daemon (optional)

To keep the router running after you close the terminal:

pnpm daemon:install     # start as background service (uses pm2)
pnpm daemon:logs        # view live logs
pnpm daemon:status      # check if running
pnpm daemon:uninstall   # stop and remove

Requires pm2 — install with npm install -g pm2.


Config

Defaults

All projects inherit from defaults. Projects only override what's different.

| Field | Default | Used by | |-------|---------|---------| | chatModel | claude-haiku-4-5-20251001 | Chat agent (Anthropic SDK) | | workerModel | anthropic/claude-sonnet-4-6 | Worker (Pi/OpenCode in Docker) | | worker | pi | Docker image + CLI |

Per-project overrides

| Field | Required | Description | |-------|----------|-------------| | project | Yes | Path to project directory (relative to repo root, e.g. projects/my-project) | | repo | No | Git repo URL — project is auto-cloned on first start if directory is missing | | channels | Yes | Array of { platform, chatId } | | name | No | Display name (defaults to slug) | | chatModel | No | Override chat model | | workerModel | No | Override worker model | | worker | No | pi or opencode |

Preview, tunnel, and deploy config live in the project itself (.env and wrangler.jsonc), not in the router.


Auth

| Method | Env var | Worker support | Use case | |--------|---------|---------------|----------| | Setup token | ANTHROPIC_OAUTH_TOKEN | Pi only | Claude subscription (personal/pilot) | | API key | ANTHROPIC_API_KEY | Pi + OpenCode | Pay-per-token (production) |

The chat agent (Layer 2) supports both methods via the Anthropic SDK.

Pi auto-detects setup tokens by prefix (sk-ant-oat) and routes them through OAuth bearer auth.


Workers

| Worker | Docker image | Auth | Model format | |--------|-------------|------|-------------| | Pi | client-agent-pi | API key + setup token | anthropic/claude-sonnet-4-6 | | OpenCode | client-agent-opencode | API key only | anthropic/claude-sonnet-4-6 |

Pi is the default — it supports Claude subscription auth, has LSP diagnostics, hash-anchored edits, and skills.


Client Usage

make the header dark blue
add a contact form to the homepage
what did you just change?
start the preview server
cancel
/clear

The bot receives all messages in registered channels and uses AI to decide which ones are directed at it. You can also @mention it or reply to its messages to guarantee a response. Send /clear or reset to start a fresh conversation.


Security

  • Each job runs in a fresh Docker container (--rm)
  • Only the project's folder is mounted — other projects are invisible
  • Memory: 2GB, CPU: 2 cores per container
  • Runs as non-root user (uid 1000)
  • Client messages are wrapped in [CLIENT MESSAGE] tags and treated as untrusted input
  • Coding prompts are rewritten by the chat agent — never passed raw

File Structure

muxclaw/
|
+-- src/
|   +-- bot.ts           # entry point + startup validation
|   +-- telegram.ts      # Telegraf bot
|   +-- whatsapp.ts      # Baileys WhatsApp
|   +-- handler.ts       # thin bridge to router
|   +-- router.ts        # Layer 1: chatId -> project dispatch
|   +-- agents.ts        # agent registry (one ChatAgent per project)
|   +-- chat-agent.ts    # Layer 2: Anthropic SDK agentic loop
|   +-- docker.ts        # Layer 3: spawn/monitor/cancel containers
|   +-- devserver.ts     # preview session lifecycle (calls project's pnpm preview)
|   +-- ports.ts         # dynamic port allocator
|   +-- history.ts       # per-project conversation persistence
|   +-- git.ts           # git status helper
|   +-- types.ts         # shared TypeScript interfaces
|
+-- scripts/
|   +-- create-project.ts  # pnpm create-project CLI (scaffold + register)
|   +-- remove-project.ts # pnpm remove-project CLI (unregister + optional delete)
|   +-- add-project.ts    # pnpm add-project CLI (register existing)
|   +-- add-channel.ts    # pnpm add-channel CLI
|
+-- pi.dockerfile        # Pi coding agent image
+-- opencode.dockerfile  # OpenCode agent image
+-- config.json          # defaults + projects
+-- .env.example         # environment variables template
+-- package.json
+-- tsconfig.json