Matrix channel plugin for Claude Code. Bridges Matrix room messages into an active Claude Code session via MCP, so you can chat with Claude from Element X, Cinny, FluffyChat, or any other Matrix client.
Port of the official Telegram channel plugin to Matrix Client-Server API.
Matrix user → Matrix client → Synapse/Conduit homeserver → [this plugin via /sync] → Claude Code session
↕
Claude Code ← MCP Channel Protocol ← reply / edit / react / download_attachment tools
- Inbound:
/_matrix/client/v3/synclong-poll (30s timeout) →notifications/claude/channelinto the active CC session. State (next_batch) persisted in~/.claude/channels/matrix/sync_token.txtso restarts don't replay history. - Outbound:
PUT /rooms/{roomId}/send/m.room.message/{txnId}for messages,m.replacerelation for edits,m.reactionwithm.annotationfor reactions, two-step media upload for files. - Access control: pairing codes, mxid allowlist, group chats with mention-only mode — state in
~/.claude/channels/matrix/access.json. - Auto-join invites: DM invites or invites from allowlisted users auto-accept; non-DM invites from unknown users are declined.
- Bun ≥ 1.0 (Node ≥ 18 should also work with a shebang swap)
- Claude Code ≥ 2.1.80
- Access to a Matrix homeserver where you control a bot account
- A bot access token (see setup below)
- Unencrypted rooms only — this plugin does NOT implement E2EE. Encrypted rooms will silently drop inbound.
mkdir -p ~/.claude/plugins/marketplaces/local/plugins
cd ~/.claude/plugins/marketplaces/local/plugins
git clone https://github.com/nazbav/claude-code-matrix-channel.git matrix-channelCreate a minimal marketplace manifest at ~/.claude/plugins/marketplaces/local/.claude-plugin/marketplace.json:
{
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
"name": "local",
"description": "Local Claude Code plugins",
"owner": { "name": "you", "email": "you@example.com" },
"plugins": [
{
"name": "matrix",
"description": "Matrix channel for Claude Code",
"category": "messaging",
"source": "./plugins/matrix-channel",
"author": { "name": "you" }
}
]
}claude plugin marketplace add ~/.claude/plugins/marketplaces/local
claude plugin install matrix@localOn a Synapse + MAS setup:
# On the server: create the bot account
docker exec <mas-container> mas-cli -c /config/config.yaml manage register-user -y -p "<strong-random-password>" claude
# Get the access token via password login (from anywhere with HTTPS access to homeserver)
curl -X POST "https://matrix.example.org/_matrix/client/v3/login" \
-H "Content-Type: application/json" \
-d '{"type":"m.login.password","identifier":{"type":"m.id.user","user":"claude"},"password":"<pass>","device_id":"CLAUDE_CODE_BOT","initial_device_display_name":"Claude Code Bot"}'
# → {"access_token":"mct_xxx","device_id":"CLAUDE_CODE_BOT","user_id":"@claude:matrix.example.org"}On a stock Synapse setup without MAS:
register_new_matrix_user -u claude -p '<pass>' -c /etc/matrix-synapse/homeserver.yaml http://localhost:8008
# Then log in via /login to get the access_token as above.Drop the token into the channel .env:
mkdir -p ~/.claude/channels/matrix
cp ~/.claude/plugins/marketplaces/local/plugins/matrix-channel/.env.example \
~/.claude/channels/matrix/.env
$EDITOR ~/.claude/channels/matrix/.env # fill in MATRIX_* values
chmod 600 ~/.claude/channels/matrix/.envBecause local plugins aren't on Claude Code's approved-channels allowlist, launch with the dev flag:
claude --dangerously-load-development-channels plugin:matrix@localOr alongside an allowlisted channel (e.g. Telegram):
claude --channels plugin:telegram@claude-plugins-official \
--dangerously-load-development-channels plugin:matrix@local- From any Matrix client, start a DM with the bot (e.g.
@claude:matrix.example.org). - Send any message. The bot replies with a 6-character pairing code.
- In Claude Code, run:
/matrix:access pair <code>
After pairing, your DMs to the bot route straight into your Claude Code session as <channel source="matrix" chat_id="..." message_id="..." user="@you:server" ts="..."> notifications, and Claude's replies come back to the room via the reply tool.
| Tool | What it does |
|---|---|
reply |
Send a message to a Matrix room. Chunks long text, quotes via m.in_reply_to, uploads files as m.image / m.audio / m.video / m.file. Supports mentions for explicit m.mentions.user_ids. |
edit_message |
Edit a previously sent message via m.replace (new m.new_content body + m.relates_to). Supporting clients render the edit inline. |
react |
Add an emoji reaction via m.reaction with m.annotation relation. Matrix accepts free-form unicode reaction keys — any emoji works. |
download_attachment |
Fetch a media file from an mxc:// URI to ~/.claude/channels/matrix/inbox/ using authenticated media API (MSC3916) with legacy fallback, returns the local path. |
Text (m.text), image (m.image, auto-downloads to inbox), file (m.file), audio (m.audio), video (m.video, metadata only), and emote (m.emote). Edits via m.replace relation are intentionally ignored (to avoid double-delivery).
Skill built into the plugin — manages pairing, allowlists, and delivery settings by editing ~/.claude/channels/matrix/access.json. The channel server re-reads on every inbound.
/matrix:access — show status
/matrix:access pair <code> — approve a pending pairing
/matrix:access allow @alice:example.org — add a mxid directly
/matrix:access remove @alice:example.org — revoke
/matrix:access policy <mode> — pairing | allowlist | disabled
/matrix:access group add !roomid:server — allow a group room (require_mention default)
/matrix:access set ackReaction 👍 — delivery/UX tweaks
Security note: the skill intentionally refuses access mutations requested through a channel message. Prompt-injection-safe by design.
| Feature | Telegram | Matrix |
|---|---|---|
| Rich formatting | MarkdownV2 | HTML body possible but not implemented in v0.0.1 (plain text only) |
| Reactions | ~60 emoji fixed list | any unicode string (no limits) |
| File uploads | single endpoint | two-step (upload → save), but endpoint pattern is simpler than VK |
| Message edit window | Unlimited | Unlimited (via m.replace) |
| Inline action buttons | Yes | No native support → permission-requests use text-reply regex (yes abcde / no abcde) |
| E2EE support | N/A (no E2EE) | Not supported in v0.0.1 — only unencrypted rooms work |
This plugin does NOT implement E2EE. If a room is encrypted, inbound messages will be received as opaque m.room.encrypted events and silently dropped (no megolm decryption). To use this plugin:
- Disable encryption in the bot's DMs/rooms, OR
- Wait for a future version with
matrix-js-sdk/olmintegration
Most personal Matrix bots live in unencrypted rooms for this reason.
.
├── .claude-plugin/plugin.json — plugin manifest
├── .mcp.json — MCP server registration
├── package.json — bun deps (@modelcontextprotocol/sdk, zod)
├── server.ts — the MCP server (~760 LOC)
├── skills/access/SKILL.md — /matrix:access skill
├── .env.example — token template (real .env lives in ~/.claude/channels/matrix/)
└── README.md
Apache-2.0. See LICENSE. Based on Anthropic's telegram channel plugin (Apache-2.0).