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

pi-matrix-bridge

v0.5.0

Published

Bridge Matrix into pi (Matrix-only fork of pi-messenger-bridge)

Readme

pi-matrix-bridge

Bridge Matrix into pi — talk to your pi coding agent from any Matrix client.

Remote users can interact with your pi coding agent via Element, FluffyChat, or any other Matrix app.

Matrix-only fork of tintinweb/pi-messenger-bridge (MIT). The original supports Telegram, WhatsApp, Slack, Discord, and Matrix; this fork keeps Matrix only.

Features

  • 💬 Matrix support (Element X, Element Web, FluffyChat, any homeserver)
  • 🔐 Challenge-based authentication (6-digit codes)
  • 🎛️ Interactive menu (/matrix-bridge) for setup and management
  • 🔒 Single-instance guard — prevents duplicate bot polling with sub-agents
  • 📊 Live status widget (toggleable)
  • 💾 Persistent config (auth state, auto-connect, widget preference)
  • 🔧 Tool call visibility for remote users
  • 💭 Live streaming — thinking and the response stream into editable messages so you can steer/stop mid-turn
  • ⏳ Rate-limit handling — backs off and retries on Matrix 429s so messages are never silently dropped
  • 📝 Multi-turn conversation support
  • 🔑 Secure permissions (chmod 600 for config files, 700 for directories)

Setup

1. Install

pi install npm:pi-matrix-bridge

2. Configure Matrix

Works with any Matrix homeserver — Element X, Element Web, FluffyChat, etc. The bot auto-joins rooms it's invited to.

  1. Register a bot account on your homeserver (or reuse an existing user)
  2. Get a dedicated access token by logging in via the API (see below)
  3. Note your homeserver URL (e.g. https://matrix.org)

Generate a fresh token — don't reuse an existing one. Reusing the access token from a client you're already signed into (e.g. Element Web's Settings → Help & About → Advanced) shares that client's device and crypto store, which causes E2EE key conflicts and decryption failures. Instead, log in via the API to mint a brand-new device + token just for the bridge:

curl -XPOST 'https://matrix.org/_matrix/client/v3/login' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "m.login.password",
    "identifier": { "type": "m.id.user", "user": "your_username" },
    "password": "YOUR_ACCOUNT_PASSWORD",
    "initial_device_display_name": "pi-matrix-bridge"
  }'

Replace your_username, the password, and the homeserver URL. The JSON response contains access_token (use it below) and a fresh device_id. To revoke it later, log that device out from your Matrix client.

/matrix-bridge configure matrix <homeserver-url> <access-token>

Or set via environment variables:

export PI_MATRIX_BRIDGE_HOMESERVER="https://matrix.org"
export PI_MATRIX_BRIDGE_ACCESS_TOKEN="syt_..."

E2EE is on by default. Verify the bot's device once from another Matrix client (Element, etc.) — until verified, encrypted rooms can't be decrypted in either direction.

Set "encryption": false in the matrix config to disable — useful for non-encrypted rooms only, or to bypass crypto-store/server desync (e.g. M_UNKNOWN: One time key … already exists). Caveat: with E2EE off, the homeserver sees plaintext, and the bot can't participate in encrypted rooms at all.

3. Connect

/matrix-bridge connect

4. Authenticate Users

When a user messages your bot for the first time, they'll receive a 6-digit challenge code. The code is displayed in your pi terminal. Share it with the user (e.g., via DM).

The user enters the code in the bot chat to become a trusted user.

Commands

| Command | Description | |---|---| | /matrix-bridge | Open interactive menu (configure, connect, widget, help) | | /matrix-bridge status | Show connection and user status | | /matrix-bridge connect | Connect to Matrix | | /matrix-bridge disconnect | Disconnect from Matrix | | /matrix-bridge configure matrix <homeserver-url> <access-token> | Set Matrix credentials via CLI | | /matrix-bridge widget | Toggle status widget on/off | | /matrix-bridge toggletools | Toggle tool call visibility in remote messages | | /matrix-bridge togglethinking | Toggle live thinking (💭) visibility | | /matrix-bridge help | Show command reference |

Admin commands (in DM with the bot)

Trusted users can DM the bot directly to manage state. Reply with /help for the full list. Commands accept either a / or ! prefix (e.g. /help or !help).

| Command | Description | |---|---| | /help | Show admin command reference | | /trusted | List trusted users | | /revoke <userId> | Revoke trust for a user | | /channels | List enabled channels | | /enable <chatId> <all\|mentions\|trusted-only> | Enable a channel | | /disable <chatId> | Disable a channel | | /toggletools | Toggle tool call visibility in replies | | /togglethinking | Toggle live thinking (💭) visibility | | /session | Show current session info (model, context usage, status) | | /shutdown | Stop pi — under systemd this restarts into a fresh session (see below) |

Any authorized user (not just admins) can also send:

| Message | Description | |---|---| | stop | Interrupt the current turn. Also accepts /stop or !stop. |

Live streaming

Both the model's thinking (💭) and its response stream into messages that are edited in place (token-by-token, throttled) as they're generated — so you can read where a turn is heading and stop (or steer) before it commits to a wrong action. Each tool call (🔧) appears the moment it starts running (handy for tools that take a few seconds), and its output (↳, truncated) is appended when it finishes. The typing indicator stays active alongside them.

Thinking is on by default — toggle with /togglethinking (DM admin) or /matrix-bridge togglethinking, or set "hideThinking": true in the config. (The response always streams.)

Rate-limit handling

Matrix homeservers return 429 Too Many Requests (with a retry_after_ms hint) when you send too fast — and live streaming, which edits messages many times per turn, makes bursts common. Rather than letting a rate-limited message silently vanish, the bridge routes every outbound send and edit through a single serialized queue:

  • On a 429 it pauses all sends, waits the server-requested retry_after, then retries the same message — so nothing is dropped, and ordering is preserved.
  • The first message delivered after a backoff carries a small note (⏳ *(delayed — rate limited)*) so you know a delay occurred.
  • Typing indicators are suppressed while rate-limited (they'd only add load), and rapid in-place edits to the same message are coalesced so a backoff doesn't flush a run of stale intermediate edits.

This is automatic — there's nothing to configure.

Configuration

Config is stored at ~/.pi/matrix-bridge.json with secure permissions (chmod 600).

Example config:

{
  "matrix": { "homeserverUrl": "https://matrix.org", "accessToken": "syt_...", "encryption": true },
  "auth": {
    "trustedUsers": ["matrix:@alice:matrix.org"]
  },
  "showWidget": true
}

Environment Variables

Environment variables override file config:

  • PI_MATRIX_BRIDGE_AUTO_CONNECT — connect on startup. Defaults to off — set to 1 to activate the bridge. Left unset, the plugin stays dormant (no connection) and you can connect manually with /matrix-bridge connect. See Headless / always-on.
  • PI_MATRIX_BRIDGE_HOMESERVER — Matrix homeserver URL (e.g. https://matrix.org)
  • PI_MATRIX_BRIDGE_ACCESS_TOKEN — Matrix access token

Security

  • Config file: ~/.pi/matrix-bridge.json (chmod 600 - owner read/write only)
  • Config directory: ~/.pi/ (chmod 700 - owner only)
  • Environment variables take precedence over config file
  • Challenge-based authentication for all new users
  • Transport-namespaced user IDs prevent impersonation

Troubleshooting

⚠️ Matrix setup error: M_UNKNOWN: One time key signed_curve25519:… already exists

The bot's crypto store has drifted out of sync with the homeserver (the device's one-time keys no longer match).

  1. Stop pi
  2. Delete your old pi matrix crypto storage rm ~/.pi/matrix-bridge-crypto ~/.pi/matrix-bridge-store.json -r
  3. Mint a fresh access token / device and reconfigure with it:
curl -XPOST 'https://matrix.org/_matrix/client/v3/login' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "m.login.password",
    "identifier": { "type": "m.id.user", "user": "your_username" },
    "password": "YOUR_ACCOUNT_PASSWORD",
    "initial_device_display_name": "pi-matrix-bridge"
  }'

Then set the new access_token (via /matrix-bridge configure matrix <homeserver> <token> or PI_MATRIX_BRIDGE_ACCESS_TOKEN) and reconnect. Deleting the stale crypto store (~/.pi/matrix-bridge-crypto) before reconnecting also clears it — the bot's device will then need re-verifying. Alternatively, set "encryption": false in the matrix config to bypass E2EE entirely (the homeserver then sees plaintext).

Architecture

Uses pi's native sendUserMessage() and turn_end events for two-way communication. No tool-loop hacks needed — this is the pi-native way.

Single-instance connection guard prevents duplicate polling when sub-agents spawn (global flag + PID lock file at ~/.pi/matrix-bridge.lock).

Headless / always-on (systemd)

Run pi as a dedicated, always-on Matrix endpoint you can talk to from your phone — including starting a fresh conversation remotely.

Activation

The plugin does not connect on startup unless PI_MATRIX_BRIDGE_AUTO_CONNECT=1. This lets a dedicated headless instance own the bot (it sets the env var) while a desktop pi with the same plugin installed stays dormant — no connection, no status widget, no notices. The desktop can still connect on demand with /matrix-bridge connect.

Install the service

The bundled installer writes a systemd --user unit, enables lingering (so it runs without an active login), and starts it:

./scripts/install-systemd.sh

Options: --name (unit name, default pi-matrix-bridge), --workdir (the agent's working directory — required; prompted if omitted), --pi (path to the pi binary), and --uninstall. If PI_MATRIX_BRIDGE_HOMESERVER / PI_MATRIX_BRIDGE_ACCESS_TOKEN are exported in your shell, they're baked into the unit; otherwise pi reads ~/.pi/matrix-bridge.json.

The generated unit sets PI_MATRIX_BRIDGE_AUTO_CONNECT=1, Restart=always, and RestartSec=2. Manage it with:

systemctl --user status pi-matrix-bridge
journalctl --user -u pi-matrix-bridge -f

/shutdown = fresh session

pi runs headless in "print" mode, but the bridge's open sockets keep the process alive as a daemon. The /shutdown admin command stops that process; with Restart=always, systemd relaunches pi, and since there's no --continue/--resume, it comes back in a brand-new session. The restart is the new session — no PTY, no tmux, no hacks.

Note: /shutdown resets the conversation for everyone and causes a few seconds of downtime. That's fine for a single-user mobile bridge. Without a supervisor, /shutdown simply stops pi — exactly what the name says.

Development

npm install
npm run build        # compile TypeScript
npm run typecheck    # type-check without emitting
npm run test         # run tests
npm run lint         # biome lint
npm run lint:fix     # biome lint with auto-fix

Credits

Forked from tintinweb/pi-messenger-bridge by tintinweb and contributors (MIT). This fork strips it down to Matrix only.

License

MIT — see LICENSE.