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

openclaw-msg9

v0.2.1

Published

OpenClaw msg9.io channel plugin — turn a msg9 agent inbox into an OpenClaw channel (poll-based inbound, reply_to thread closing).

Readme

openclaw-msg9

OpenClaw channel plugin for msg9.io agent inboxes. Turns a msg9 agent inbox into an OpenClaw channel: inbound mail drives the agent, agent replies are delivered back on the original msg9 thread.

  • Channel id: msg9 (package / plugin id: openclaw-msg9)
  • Transport: poll-based inbound (agent.unread()), direct outbound (agent.send())
  • Content: text only — msg9 has no attachments, so no sendMedia

Configuration

Single account (channels.msg9):

{
  channels: {
    msg9: {
      enabled: true,
      address: "[email protected]",   // your agent inbox address
      apiKey: "msg9_sk_...",                    // the inbox's agent key — a secret
      // baseUrl: "https://api.msg9.io",        // optional, this is the default
      pollIntervalMs: 3000,                     // inbox poll interval (default 3000)
      allowFrom: ["[email protected]"],  // optional sender whitelist
    },
  },
}

Multi-account:

{
  channels: {
    msg9: {
      enabled: true,
      address: "[email protected]",
      apiKey: "msg9_sk_...",
      accounts: {
        side: {
          address: "[email protected]",
          apiKey: "msg9_sk_...",
          pollIntervalMs: 1000,
        },
      },
    },
  },
}

Or via environment variables (default account only): MSG9_ADDRESS, MSG9_API_KEY, MSG9_BASE_URL.

CLI-style setup tokens follow the same shape as other channels: --token "address,apiKey[,baseUrl]", or --use-env to read the env vars above.

Addressing

Outbound targets use the msg9: prefix:

msg9:[email protected]

normalizeTarget strips the prefix; a bare address containing @ is also recognized as a msg9 id (<user>@<pod>.msg9.io).

Inbound semantics

Each poll sweep drains the inbox's unread folder:

  1. Dedupe by message_id (bounded in-memory set, reset at 1000 entries). The platform is at-least-once; the set covers a gateway run.
  2. allowFrom — when the list is non-empty and the sender is not listed, the message is markRead and skipped: it never reaches the agent, but stays in the owner's unprocessed folder for manual review. Empty allowFrom allows everyone — configure it before enabling text commands.
  3. markProcessed — allowed messages are marked processed (implies read, idempotent) before dispatch, so the agent is driven at-most-once even if dispatch or delivery fails.
  4. Dispatch — the standard channel pipeline (activity.record → resolveAgentRoute → envelope → finalizeInboundContext → dispatchReplyWithBufferedBlockDispatcher). The deliver callback sends via agent.send({ ..., reply_to: <original message_id> }).

reply_to auto-close

Sending a reply with reply_to set makes the server close the original message automatically. Combined with the mark-processed-first policy, replied threads are closed exactly once, and messages that never get a reply remain visible in the unprocessed folder.

Outbound

outbound.sendText resolves the account, strips the msg9: prefix, and calls agent.send. A core-provided replyToId (the inbound MessageSid) is mapped to msg9 reply_to. Returns { channel: "msg9", messageId }. There is no sendMedia — msg9 carries text bodies only.

Credential hygiene

apiKey is a msg9_sk_... agent key: anyone holding it can read and send as that inbox. Keep it in OpenClaw's config/secret stores with restricted file permissions (0600), never in a repo or a chat log. If a key leaks in plaintext, rotate it at the platform before reusing the inbox.

Requirements

  • Node.js >= 18
  • OpenClaw plugin API >=2026.3.23-1 (built against SDK 2026.4.26)

Development

npm install
npm run build        # tsc → dist/
npm test             # vitest (no network — the client factory is mocked)
npm run pack:dry-run

Roadmap

  • Webhook inbound — replace polling with tenant-key webhook subscriptions (registerHttpRoute + signature verification) once a webhook is provisioned.
  • Inbox tools — expose list_inbox / mark_processed style tools to the agent via registerTool.
  • ClawHub publish — publishing pipeline (openclaw.plugin.json already carries the required compat/build metadata; schema is fully flat, no $ref/$defs).