pi-courier
Run pi coding agent from Matrix. Slash commands, skills and prompts fully work from messengers via the RPC protocol.
Package details
Install pi-courier from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-courier- Package
pi-courier- Version
0.1.23- Published
- Aug 9, 2026
- Downloads
- 3,346/mo · 3,346/wk
- Author
- barryfan2045
- License
- MIT
- Types
- extension
- Size
- 314.7 KB
- Dependencies
- 1 dependency · 2 peers
Pi manifest JSON
{
"extensions": [
"./extensions/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-courier
Run the pi coding agent from Matrix. Send a message in a chat, pi answers — and every slash command, skill and prompt template works, exactly like in the terminal.
Unlike pi's classic extension mode, pi-courier drives pi over the RPC protocol, which is why commands work from chat: the extension mode can't do this because pi's sendUserMessage() deliberately skips command handling.
1. What is it
pi-courier is a small standalone service that bridges Matrix to a locally installed pi:
Matrix bot ←→ pi-courier ←→ pi --mode rpc (system-installed)
- You talk to a Matrix bot account; messages are forwarded to pi over the RPC protocol
- Full command support:
/new,/compact,/model,/thinking,/skill:name, prompt templates, extension commands - pi is not bundled — installed independently on the system, upgraded on its own
- Sessions persist to
~/.pi/agent/sessionsand resume automatically after restarts - One-command CLI: setup wizard, systemd auto-start, self-update
2. Install
Prerequisites
| Component | Requirement |
|---|---|
| Node.js | >= 20 (tested on 24.x) |
| pi | >= 0.83, installed globally |
Install pi first — pi-courier connects to it:
npm install -g @earendil-works/pi-coding-agent
pi --version
Using nvm? Run source ~/.nvm/nvm.sh in each new terminal so pi and node are on PATH.
Option A: Regular users — one command
npm install -g pi-courier
That's it. Verify: pi-courier help.
Option B: Developers — from source
git clone https://github.com/Hi-Barry/pi-courier.git
cd pi-courier
npm install
npm run build
npm link # make the `pi-courier` command available globally
Do not use --ignore-scripts: the Matrix E2EE library downloads its native binary via postinstall. If your npm blocks it and you hit Cannot find module '@matrix-org/matrix-sdk-crypto-nodejs-linux-x64-gnu', run:
cd node_modules/@matrix-org/matrix-sdk-crypto-nodejs
node download-lib.js
cd ../..
Slow download (20-60 kB/s)? The binary comes from GitHub Releases and ignores npm's proxy — set export https_proxy=... http_proxy=... first.
3. Get started
Step 0 — Make sure pi can chat (one-time)
pi needs an LLM provider configured in ~/.pi/agent/ (models.json, auth.json, settings.json). Easiest check: run pi, send any message, confirm it answers. If it can't, configure it first — pi's own docs cover this; the field names are defaultProvider/defaultModel in settings.json.
Step 1 — Run the setup wizard
pi-courier setup
It walks you through, prompting for each value (defaults in brackets; press Enter to accept):
=== pi-courier 首次配置向导 ===
将生成 ~/.pi/pi-courier.json(权限 600)
Matrix homeserver URL (如 https://matrix.example.com): ← 输入,如 https://matrix.example.com
获取 token 方式 [1=用户名密码登录, 2=粘贴已有 token] (1): ← 1 或 2(Enter 默认 1)
[方式 1] bot 用户名 (如 test2): ← bot 账号名,如 test3
bot 密码: ← 密码(不回显)
[方式 2] 粘贴 access token (syt_...): ← 已有 token
✅ 登录成功,账号: @test3:matrix.example.com
信任用户(管理员)MXID [默认 @test3:matrix.example.com]: ← 直接回车 = 只有 bot 自己可信;建议填你的账号,如 @barry:matrix.example.com
启用 E2EE 加密? [y/N]: ← y/n(非加密房间也选 y 无妨)
pi 工作目录 [默认 /home/you/Projects]: ← Enter 或输入其他目录
✅ 配置已写入 ~/.pi/pi-courier.json
账号: @test3:...
信任用户: @barry:...
E2EE: 开启
工作目录: /home/you/Projects
The wizard verifies the token and writes ~/.pi/pi-courier.json. To skip the wizard, create that file manually — the format is in the FAQ.
Step 2 — Start it
pi-courier enable # install a systemd service: auto-start on boot + start now
Or run in the foreground for a quick test: pi-courier run (Ctrl+C to stop).
Startup success looks like:
✅ Matrix connected as @test3:... (2 rooms, E2EE enabled)
✅ pi RPC connected (model: deepseek-v4-flash, session: 019f...)
🚀 pi-courier ready. Waiting for messages...
Step 3 — Use it from Matrix
First contact (one-time pairing):
- DM the bot from your account and send any message
- You are not a trusted user yet (e.g. you pressed Enter on the trusted-user prompt in setup, leaving only the bot itself trusted), so the bridge prints a challenge code in its log (
pi-courier logsorjournalctl --user -u pi-courier -f):
[2026-08-06T02:38:34.833Z] [INFO] 🔐 Challenge code for @barry: 529311
- Reply with that code in the chat (just the digits) — the log confirms the pairing:
[2026-08-06T02:38:44.487Z] [INFO] [auth:info] ✅ barry authenticated
You can chat normally right away:
[2026-08-06T02:38:55.685Z] [INFO] 📥 [matrix] @barry: 你好,收到请回复!
[2026-08-06T02:38:57.884Z] [INFO] [agent] 回复 @barry: 你好!收到,我在线。...
You are now a trusted user (the first trusted user also becomes admin). Any user not in auth.trustedUsers goes through this flow once; pre-listed users skip it entirely.
Then chat normally, or send commands:
| Command | Action |
|---|---|
/new /clear |
New session |
/compact [notes] |
Compact context |
/model / /model <provider/id> |
Show / switch model |
/models |
List models |
/thinking [level] |
Show / set thinking level |
/session /cost |
Session stats & cost |
/status |
Current model & state |
/name <name> |
Name the session |
/export [path] |
Export session HTML |
/bash <cmd> |
Run a shell command |
/stop |
Stop all tasks immediately (like Esc in the TUI; alias /abort) |
/reload |
Restart pi (after installing extensions/config) |
/help |
Full help |
Bridge admin commands: /trusted, /revoke <userId>, /channels, /enable <chatId> <mode>, /disable <chatId>, /toggletools
Anything else starting with / passes through to pi directly — extension commands, /skill:name, prompt templates. Plain text is a normal conversation turn.
Group chats: enable the room first with /enable <roomId> <all|mentions|trusted-only> (in a DM to the bot), or add it during setup (trusted-room step; default mode trusted-only). Without this, nobody in the room is answered — including trusted users. Room IDs look like !xxx:server (visible in the logs).
Managing the service
pi-courier status # status + recent logs
pi-courier logs # tail logs (INFO and above)
pi-courier logs --level debug # tail ALL logs (incl. thinking, stream deltas)
pi-courier logs --level error # errors only
pi-courier run --level debug # foreground with full detail
pi-courier restart # restart
pi-courier stop # stop
pi-courier start # start
pi-courier disable # uninstall the service
pi-courier update # update pi-courier itself
Log levels: debug < info < warn < error. The service writes everything;
logs shows INFO+ by default, --level debug shows the full session replay
(user messages, thinking, tool calls, replies). The complete conversation is
always stored in pi's session files (~/.pi/agent/sessions/).
Upgrading pi is independent — pi-courier always uses the system pi via which pi:
npm install -g @earendil-works/pi-coding-agent@latest
pi-courier restart
4. FAQ
Q: npm install hangs / crawls at 20-60 kB/s?
A: The 21 MB E2EE native library downloads from GitHub Releases and ignores npm's proxy. Set export https_proxy=... http_proxy=... (add to ~/.bashrc) and reinstall.
Q: Cannot find module '@matrix-org/matrix-sdk-crypto-nodejs-linux-x64-gnu'?
A: The native binary didn't download (postinstall blocked). Run manually: cd node_modules/@matrix-org/matrix-sdk-crypto-nodejs && node download-lib.js.
Q: npm install -g pi-courier fails with EEXIST?
A: A previous npm link left a conflicting bin. npm unlink -g pi-courier && rm -f $(npm prefix -g)/bin/pi-courier && npm install -g pi-courier.
Q: The systemd service restarts in a loop?
A: Almost always a Node version mismatch — the pi child crashes on system node v20 (webidl.util.markAsUncloneable is not a function). Load nvm and re-run pi-courier enable (v0.1.2+ writes the correct PATH into the unit). Stick to one Node version everywhere.
Q: Startup shows model: unknown?
A: pi's provider isn't configured. Check ~/.pi/agent/: models.json + auth.json + settings.json (defaultProvider / defaultModel — exact field names).
Q: Lots of Decryption error lines in the log?
A: Historical events that can't be decrypted (new device without old keys). Normal — new messages work fine.
Q: Encrypted room: no reply / can't decrypt new messages?
A: The bot's new device never received the room keys. The bot account has no cross-signing, so the most reliable fix is to use a non-encrypted room (create a room without encryption and invite the bot) — the bridge handles plain rooms fine even with encryption: true.
Q: M_BAD_JSON: Provided device_id in device_keys does not match...?
A: The crypto store's device identity doesn't match the token's device (re-logged, or a pasted token from another device). Since 0.1.20 password login uses a fixed device ID, so re-running setup no longer triggers this. If it still happens: delete the crypto store and restart — rm -rf ~/.pi/pi-courier-matrix-crypto && pi-courier restart (do this whenever you re-run setup / change the token).
Q: One time key signed_curve25519:... already exists (M_UNKNOWN)?
A: The token is bound to an old device on the server and the local OTK bookkeeping is out of sync — deleting the local crypto store does NOT help (the server assigns the device ID from the token, so a rebuilt store uses the same device). You must get a new token: re-run pi-courier setup and answer n to "keep the existing token?" (or log in with the password); a new token = a new device = clean server state. Pair with a crypto-store delete if device residue persists.
Q: First message asks for a 6-digit code? A: That's the challenge auth — reply with the code to become a trusted user.
Q: No reply to messages at all?
A: Check in order: (1) pi-courier status — Matrix connected? Decryption errors (encrypted room)? (2) pi RPC connected? (3) the model call itself — curl the provider endpoint with your key.
Q: pi RPC did not become ready?
A: pi failed to start. Run node node_modules/@earendil-works/pi-coding-agent/dist/cli.js --mode rpc manually to see the real error. Common causes: Node version mismatch, invalid provider config, no network to the provider.
Q: After a restart the conversation context is gone?
A: Since v0.1.1 the bridge passes --continue to pi, resuming the most recent session per workdir. Update pi-courier and restart; /new starts a fresh session and the next restart resumes that one.
Q: Element (web client) intercepts /-prefixed messages?
A: Prefix with // to send a literal slash (//compact sends /compact).
Q: What exactly is in ~/.pi/pi-courier.json?
A: The wizard-generated config. Example:
{
"matrix": { "homeserverUrl": "https://matrix.example.com", "accessToken": "syt_...", "encryption": true },
"auth": { "trustedUsers": ["matrix:@you:matrix.example.com"], "adminUserId": "matrix:@you:matrix.example.com" },
"workdir": "/home/you/Projects",
"autoConnect": true,
"debug": true
}
Env var alternatives (priority: env vars > config file > wizard):
| Variable | Maps to |
|---|---|
PI_MATRIX_HOMESERVER + PI_MATRIX_ACCESS_TOKEN |
matrix.homeserverUrl / accessToken (both must be set) |
PI_MATRIX_ENCRYPTION |
matrix.encryption (true/false) |
PI_MATRIX_TRUSTED_USERS |
auth.trustedUsers (comma-separated MXIDs, e.g. @barry:matrix.example.com) |
PI_WORKDIR |
workdir |
PI_LOG_LEVEL |
logLevel (debug/info/warn/error) |
The LLM key can also come from an env var: write "key": "${PI_LLM_API_KEY}" in auth.json and pi reads it from the environment at startup (the Docker template does this by default).
5. License & Acknowledgements
MIT License — see LICENSE.
Upstream: this project is a rework of tintinweb/pi-messenger-bridge (MIT). The Matrix transport layer and challenge auth come from upstream; the RPC-based standalone architecture, slash-command mapping, CLI, setup wizard and docs are new.
pi-courier is an independent companion app for pi — it is not affiliated with Earendil Inc.