pi-matrix-bridge
Bridge Matrix into pi (Matrix-only fork of pi-messenger-bridge)
Package details
Install pi-matrix-bridge from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-matrix-bridge- Package
pi-matrix-bridge- Version
0.5.0- Published
- Jun 7, 2026
- Downloads
- not available
- Author
- rolznz
- License
- MIT
- Types
- extension
- Size
- 275.3 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"extensions": [
"./dist/index.js"
],
"video": "https://github.com/rolznz/pi-matrix-bridge/raw/master/media/demo.mp4",
"image": "https://github.com/rolznz/pi-matrix-bridge/raw/master/media/screenshot.png"
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
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.
- Register a bot account on your homeserver (or reuse an existing user)
- Get a dedicated access token by logging in via the API (see below)
- 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 containsaccess_token(use it below) and a freshdevice_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 to1to 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).
- Stop
pi - Delete your old pi matrix crypto storage
rm ~/.pi/matrix-bridge-crypto ~/.pi/matrix-bridge-store.json -r - 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:
/shutdownresets the conversation for everyone and causes a few seconds of downtime. That's fine for a single-user mobile bridge. Without a supervisor,/shutdownsimply 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.
