A Matrix-Mattermost bridge built on the mautrix bridgev2 framework with puppet identity routing -- each Matrix user can post to Mattermost under their own dedicated bot account, preserving individual identity across platforms.
- Puppet Identity Routing -- Map Matrix users to dedicated Mattermost bot accounts. Messages appear under the bot's name and avatar, not a generic relay user.
- Double Puppeting -- When a Mattermost user posts, the bridge creates the Matrix event as their real MXID (e.g.,
@admin:example.com) instead of a ghost user (@mattermost_abc:example.com). Configured viadouble_puppet.secretsusing the bridge's appservice token. - Hot-Reload API -- Add or remove puppet mappings at runtime via
POST /api/reload-puppetswithout restarting the bridge. - Bidirectional Messaging -- Full two-way sync: text, images, video, audio, files, reactions, edits, deletes, typing indicators, and read receipts.
- Rich Formatting -- Converts Matrix HTML to Mattermost markdown and back (bold, italic, code blocks, links, lists, blockquotes, headings).
- Echo Prevention -- Multi-layer filtering prevents infinite message loops: puppet bot filtering, bridge bot filtering, relay bot filtering, and configurable username prefix filtering.
- Auto Portal Relay -- Background goroutine watches for new Matrix portal rooms and automatically enables relay mode.
- Multiple Auth Methods -- Token-based and password-based Mattermost login flows.
- bridgev2 Native -- Built on mautrix bridgev2 for robust Matrix protocol handling, encryption support, and proven reliability.
Matrix Homeserver Mattermost Server
| |
v v
[mautrix-mattermost bridge] |
| |
+-- Puppet Router ----+ |
| Maps @user:hs --> |-- Bot Token A ---->| (posts as Bot A)
| to MM bot tokens |-- Bot Token B ---->| (posts as Bot B)
| |-- Bot Token C ---->| (posts as Bot C)
| + |
+-- Relay Fallback ----------------------->| (posts as relay bot)
| |
+-- Event Stream <-------------------------| (WebSocket listener)
When a Matrix user sends a message:
- The bridge receives the Matrix event via appservice.
- The puppet router checks if the sender's MXID has a mapped Mattermost bot token.
- If matched, the message is posted to Mattermost using that bot's token -- it appears under the bot's identity.
- If no puppet match, the message goes through the standard relay bot.
When a Mattermost user posts:
- The bridge receives the event via WebSocket.
- Echo prevention filters out messages from bridge bots and puppet bots.
- If double puppeting is enabled for this user, the Matrix event is sent as their real MXID (e.g.,
@admin:example.com) instead of a ghost user. - Otherwise, the message is relayed to the corresponding Matrix room with ghost user attribution.
docker run -d \
--name mautrix-mattermost \
-v /path/to/config:/data \
-p 29319:29319 \
ghcr.io/aiku/mautrix-mattermost:latestSee 3 AI agents posting under distinct Mattermost identities in under 2 minutes:
cd example/multi-agent-puppeting
docker compose up --build
# Open http://localhost:18065 — login: admin / DemoAdmin123!See example/multi-agent-puppeting/ for the full walkthrough.
See docker-compose.yml for a full stack with Mattermost, Synapse, and PostgreSQL.
# Copy and edit configuration
cp config.yaml.example config.yaml
# Edit config.yaml with your settings
# Start the stack
docker compose up -d# Clone
git clone https://github.com/aiku/mautrix-mattermost.git
cd mautrix-mattermost
# Build
make build
# Run
./mautrix-mattermost -c config.yamlThe bridge is configured via config.yaml. Key sections:
# Homeserver connection
homeserver:
address: https://matrix.example.com
domain: example.com
# Appservice registration
appservice:
address: http://localhost:29319
hostname: 0.0.0.0
port: 29319
id: mattermost
bot:
username: mattermost-bridge
displayname: Mattermost Bridge
# Bridge behavior
bridge:
relay:
enabled: true
message_formats:
m.text: "<b>{{ .Sender.Displayname }}</b>: {{ .Message }}"
m.notice: "<b>{{ .Sender.Displayname }}</b>: {{ .Message }}"
m.emote: "* <b>{{ .Sender.Displayname }}</b> {{ .Message }}"
m.file: "<b>{{ .Sender.Displayname }}</b> sent a file: {{ .Message }}"
m.image: "<b>{{ .Sender.Displayname }}</b> sent an image: {{ .Message }}"
m.audio: "<b>{{ .Sender.Displayname }}</b> sent audio: {{ .Message }}"
m.video: "<b>{{ .Sender.Displayname }}</b> sent a video: {{ .Message }}"
permissions:
"*": relay
"example.com": user
"@admin:example.com": admin| Variable | Description | Example |
|---|---|---|
MATTERMOST_URL |
Mattermost server URL | http://mattermost:8065 |
MATTERMOST_AUTO_SERVER_URL |
Auto-login server URL | http://mattermost:8065 |
MATTERMOST_AUTO_OWNER_MXID |
Auto-login Matrix user | @admin:example.com |
MATTERMOST_AUTO_TOKEN |
Auto-login bot token | abc123... |
MATTERMOST_PUPPET_{SLUG}_MXID |
Puppet Matrix user ID | @bot-user:example.com |
MATTERMOST_PUPPET_{SLUG}_TOKEN |
Puppet Mattermost bot token | xyz789... |
The puppet identity system maps Matrix user IDs to Mattermost bot accounts via environment variables. For the full deployment guide — including Kubernetes setup, bulk provisioning, and programmatic hot-reload — see doc/puppet-deployment-guide.md.
- Create a Mattermost bot account for each identity you want to puppet.
- Generate a token for each bot.
- Set environment variables following the naming convention:
# Pattern: MATTERMOST_PUPPET_{SLUG}_MXID and MATTERMOST_PUPPET_{SLUG}_TOKEN
# SLUG: uppercase, hyphens replaced with underscores
export MATTERMOST_PUPPET_ALICE_MXID="@alice:example.com"
export MATTERMOST_PUPPET_ALICE_TOKEN="bot-token-for-alice"
export MATTERMOST_PUPPET_BOB_SMITH_MXID="@bob-smith:example.com"
export MATTERMOST_PUPPET_BOB_SMITH_TOKEN="bot-token-for-bob"- Start or restart the bridge. Puppets are loaded on startup.
Add or remove puppets at runtime without restarting the bridge:
# Reload from current environment variables
curl -X POST http://localhost:29320/api/reload-puppets
# Reload with explicit puppet entries
curl -X POST http://localhost:29320/api/reload-puppets \
-H "Content-Type: application/json" \
-d '[
{"slug": "ALICE", "mxid": "@alice:example.com", "token": "bot-token"},
{"slug": "BOB", "mxid": "@bob:example.com", "token": "bot-token"}
]'The response includes the count of active puppets and any errors encountered.
- Go 1.26 or later
- Docker (for integration tests)
- golangci-lint (for linting)
# Build
make build
# Run all tests
make test
# Run tests with race detector
make test-race
# Lint
make lint
# Format
make fmt.
├── cmd/
│ └── mautrix-mattermost/ # CLI entrypoint
├── pkg/
│ └── connector/ # bridgev2 NetworkConnector implementation
│ ├── matrixfmt/ # Matrix HTML → Mattermost markdown
│ └── mattermostfmt/ # Mattermost markdown → Matrix HTML
├── example/
│ └── multi-agent-puppeting/ # Self-contained multi-agent demo (docker compose up)
├── doc/ # Design and usage documentation
├── config.yaml.example # Example configuration
├── Dockerfile # Multi-stage container build
├── docker-compose.yml # Example full stack
└── Makefile # Build automation
- mautrix/go -- The bridgev2 framework that powers this bridge
- Mattermost -- Open source messaging platform
- Matrix -- Open standard for decentralized communication
Mozilla Public License 2.0. See LICENSE for details.