BridgeMost 👻
Telegram ↔ Mattermost Transparent Bridge
BridgeMost makes your Telegram messages appear natively in Mattermost — as your real user, with your avatar and name. Bot responses relay back to Telegram instantly via WebSocket.
Unlike Matterbridge or webhooks that post with [User] prefixes, BridgeMost posts as your actual Mattermost account. Nobody in Mattermost can tell you're writing from Telegram.
✨ Features
| Feature | Description |
|---|---|
| 🪪 Transparent identity | Posts as your real MM user (avatar, name, everything) |
| 📁 Full media | Photos, documents, audio, video, voice — bidirectional |
| 🎤 Voice-to-text | Voice messages auto-transcribed via Whisper API |
| 🤖 Multi-bot routing | Talk to multiple bots; switch with /bot name |
| ⚡ Real-time WebSocket | Responses arrive instantly (no polling) |
| ✏️ Edit & delete sync | Edits and deletes stay in sync both ways |
| 😀 Reactions | Emoji reactions synced between TG and MM |
| ⌨️ Typing indicator | "Bot is typing..." shown in Telegram |
| 📝 Markdown | MM markdown → Telegram MarkdownV2 auto-conversion |
| 🔒 Startup checks | Validates tokens + discovers channels before starting |
| 💾 Persistent mapping | SQLite store for message IDs (survives restarts) |
| 🩺 Health endpoint | HTTP /health on configurable port |
| 👥 Multi-user | Multiple Telegram users, each with their own MM identity |
~55 MB RAM · ~250 ms latency · asyncio-based · Python 3.11+
Multi-user ready: Multiple people can use the same BridgeMost instance — each with their own Telegram account, Mattermost identity, and bot routing. Add users to
config.yamland they appear as themselves in Mattermost. No shared accounts, no impersonation.
🚀 Installation — Step by Step
What you need before starting
| # | Item | Where to get it |
|---|---|---|
| 1 | Mattermost server (self-hosted) | You must be admin or have an admin enable PAT support |
| 2 | Telegram bot token | Create via @BotFather → /newbot |
| 3 | Your Telegram user ID | Send any message to @userinfobot — it replies with your numeric ID |
| 4 | Python 3.11+ | python3 --version to check |
| 5 | Git | git --version to check |
Step 1 — Enable Personal Access Tokens on Mattermost
⚠️ This step is REQUIRED. Without it, BridgeMost cannot post as your user.
Option A — Via Mattermost UI (admin):
- Go to System Console → Authentication → Token Access
- Set Enable Personal Access Tokens to
true - Save
Option B — Via command line (requires access to the server):
# If mmctl is available:
mmctl --local config set ServiceSettings.EnableUserAccessTokens true
# Or via REST API with admin token:
curl -X PUT http://localhost:8065/api/v4/config/patch \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ServiceSettings": {"EnableUserAccessTokens": true}}'
Step 2 — Clone and install
git clone https://github.com/JuanjoPM-Developer/BridgeMost.git
cd BridgeMost
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
Step 3 — Configure
Option A — Interactive wizard (recommended):
python3 -m bridgemost setup
The wizard will:
- Connect to your Mattermost server
- Log you in (password is NOT stored)
- Auto-create a Personal Access Token for BridgeMost
- List all bots on the server — you pick which ones to bridge
- Ask for your Telegram bot token and user ID
- Generate
config.yamlautomatically
Option B — Manual configuration:
cp config.example.yaml config.yaml
Then edit config.yaml — see the Configuration Reference below for each field.
Step 4 — Run
# Foreground (for testing):
python3 -m bridgemost
# Or as a systemd service (recommended for production):
sudo cp bridgemost.service.example /etc/systemd/system/bridgemost.service
# Edit the service file — update paths to match your installation
sudo systemctl daemon-reload
sudo systemctl enable --now bridgemost
Step 5 — Test
- Open Telegram and send a message to your BridgeMost bot
- The message should appear in Mattermost as your real user
- When the MM bot responds, the response should appear in your Telegram chat
⚙️ Configuration Reference
Minimal config.yaml
telegram:
bot_token: "123456:ABC-DEF..." # From @BotFather
mattermost:
url: "http://localhost:8065" # Your MM server URL (http or https)
bot_token: "abc123..." # Any bot's access token (for WebSocket)
bot_user_id: "a1b2c3d4..." # User ID of that bot
users:
- telegram_id: 123456789 # Your numeric Telegram user ID
telegram_name: "Your Name" # Display name (for logs only)
mm_user_id: "x1y2z3..." # Your Mattermost user ID
mm_token: "your-pat-here" # Your Personal Access Token
bots:
- name: "mybot" # Friendly name (used with /bot command)
mm_bot_id: "bot-user-id-here" # The bot's Mattermost user ID
mm_dm_channel: "" # Leave empty — auto-discovered at startup
default: true # First bot to talk to when bridge starts
How to find each value
| Field | How to get it |
|---|---|
telegram.bot_token |
@BotFather → /newbot → copy the token |
telegram_id |
Send any message to @userinfobot |
mattermost.url |
The URL you use to open Mattermost in your browser |
mattermost.bot_token |
MM → Integrations → Bot Accounts → pick any bot → copy token. Or ask your admin. |
mattermost.bot_user_id |
Run: mmctl user search <botname> → copy the id field. Or: curl http://YOUR_MM/api/v4/users/username/<botname> -H "Authorization: Bearer TOKEN" → "id" field |
mm_user_id |
Same as above but with your own username instead of the bot's |
mm_token (PAT) |
MM → click your avatar → Profile → Security → Personal Access Tokens → Create. Or the setup wizard creates it for you. |
mm_bot_id |
Same method as bot_user_id — the Mattermost user ID of the bot you want to talk to |
mm_dm_channel |
Leave empty — BridgeMost discovers it automatically. Only fill in if auto-discovery fails (check logs). |
Optional sections
# Voice-to-text transcription (requires a Whisper-compatible API)
voice_to_text:
url: "http://localhost:9000" # Whisper endpoint
api_key: "" # For OpenAI/Groq; empty for local Whisper
model: "large-v3" # large-v3, whisper-1, whisper-large-v3-turbo
language: "" # "es", "en", or "" for auto-detect
keep_audio: true # Also attach audio file alongside transcript
# Health monitoring endpoint
health:
port: 9191 # HTTP health check on this port
# Message persistence
storage:
data_dir: "" # SQLite DB location; empty = working directory
# Logging
logging:
level: "INFO" # DEBUG, INFO, WARNING, ERROR
file: "" # Log file path, or "" for stdout only
🤖 Telegram Commands
| Command | Description |
|---|---|
/bot |
List all available bots and show which one is active |
/bot name |
Switch to a different bot |
/bots |
Show all bots with live 🟢/⚫ online status |
/status |
Detailed info about the active bot (state, last message, store stats) |
Just type normally to send messages — commands are only for bot management.
🎤 Voice-to-Text
When voice_to_text is configured, voice messages are transcribed before posting:
🎤 Hello, this is what I said in the voice message
If keep_audio: true, the original audio file is also attached.
Compatible APIs:
- OpenAI Whisper API (
whisper-1) - Groq Whisper (
whisper-large-v3-turbo— free tier) - faster-whisper-server (self-hosted, any model)
- Any endpoint accepting
POSTwithmultipart/form-dataand returning{"text": "..."}
📊 Health Endpoint
curl http://localhost:9191/health
{
"status": "ok",
"version": "0.9.5",
"transport": "websocket",
"uptime": "2h15m30s",
"messages": { "tg_to_mm": 42, "mm_to_tg": 38, "errors": 0 },
"store": { "persistent_mappings": 156 }
}
🏗️ Architecture
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ Telegram │◄────────────►│ BridgeMost │◄────────────►│ Mattermost │
│ (User) │ Bot API │ (Bridge) │ REST + WS │ (Bots) │
└──────────┘ └──────────────┘ └──────────────┘
- TG → MM: User sends via Telegram → BridgeMost posts to MM using the user's PAT (appears as real user)
- MM → TG: Bot responds → WebSocket delivers event instantly → BridgeMost relays to Telegram
- Edits/Deletes/Reactions: Tracked via bidirectional message ID mapping (SQLite-backed, 30-day TTL)
🔧 Troubleshooting
| Problem | Solution |
|---|---|
FATAL: Token validation FAILED |
Your PAT is invalid or expired. Create a new one in MM → Profile → Security → Personal Access Tokens. Also verify EnableUserAccessTokens is true in System Console. |
⚠️ Tu token de Mattermost ha expirado (Telegram alert) |
Same as above — renew the PAT and update mm_token in config.yaml, then restart. |
Zero DM channels discovered |
BridgeMost couldn't find any DM channel with the configured bots. Make sure you have sent at least one DM to each bot in Mattermost before starting. The mm_bot_id values must be correct user IDs (26 alphanumeric characters). |
WS auth rejected (CLOSE on connect) |
The mattermost.bot_token is invalid. Get a valid bot token from Integrations → Bot Accounts. |
OSError: [Errno 98] address already in use (health port) |
Another process is using the health port (default 9191). Change health.port in config or stop the conflicting service. |
Messages arrive but with [BotName] prefix |
This is normal in multi-bot mode — it identifies which bot sent the response. With a single bot, no prefix is added. |
| Voice messages not transcribed | Check that voice_to_text.url is reachable: curl http://YOUR_WHISPER_URL/asr. For OpenAI/Groq, verify api_key is set. |
EnableUserAccessTokens keeps turning off |
Something (another admin, a script, or a bot) is toggling it. Set it permanently and check who has access to System Console. |
| Bridge starts but no messages relay | Check logs (journalctl -u bridgemost -f). Common causes: wrong telegram_id (messages from unknown users are silently ignored), bot not yet DM'd in MM, or firewall blocking MM API. |
🛡️ Security Notes
config.yamlcontains secrets — it's in.gitignore, never commit it- Personal Access Tokens have your full user permissions — use a dedicated account if concerned
- Health endpoint binds to
127.0.0.1by default (not exposed externally) - Only Telegram users whose
telegram_idis in config can use the bridge - Message ID mappings stored in SQLite (local disk only, 30-day auto-prune)
📋 Changelog
| Version | Date | Feature |
|---|---|---|
| v0.9.5 | 2026-03-25 | Fix NameError in whisper.py finally block (GitHub #1), version alignment |
| v0.9.4 | 2026-03-25 | Smart MM→TG file relay with MIME dispatch (photo/gif/audio/voice/video) |
| v0.9.3 | 2026-03-24 | Audit fix: 3 bugs in sticker/location/poll handlers |
| v0.9.2 | 2026-03-24 | Stickers, locations, venues, polls — TG→MM |
| v0.9.1 | 2026-03-25 | Multi-user highlighted in README, unit tests added |
| v0.9.0 | 2026-03-24 | README rewrite, improved config.example.yaml with inline docs |
| v0.8.3 | 2026-03-24 | Code audit cleanup (dead code, unused imports, version alignment) |
| v0.8.2 | 2026-03-24 | Remove /ping (ghost typing fix), typing timeout 300→60s |
| v0.8.1 | 2026-03-24 | /bots and /status Telegram commands |
| v0.8.0 | 2026-03-24 | SQLite persistent store, WS reconnect jitter, TG rate limiter |
| v0.7.0 | 2026-03-24 | 7-bug audit fix (voice handler, file leak, typing timeout, PAT expiry) |
| v0.6.0 | 2026-03-24 | Interactive setup wizard (bridgemost setup) |
| v0.5.0 | 2026-03-24 | Startup resilience — token validation, DM retry, zero-channel abort |
| v0.4.0 | 2026-03-24 | Voice-to-text via Whisper API |
| v0.3.1 | 2026-03-24 | Synthetic typing indicator |
| v0.3.0 | 2026-03-24 | Multi-bot routing with /bot command |
| v0.2.0 | 2026-03-24 | Emoji/reaction relay |
| v0.1.1 | 2026-03-24 | Edit and delete sync (bidirectional) |
| v0.1.0 | 2026-03-24 | WebSocket transport (replaced polling) |
| v0.0.5 | 2026-03-24 | First public release |
📄 License
MIT — see LICENSE
🙏 Built with
Metadata
Release files for bridgemost 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bridgemost-2.0.0.tar.gz | 44.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bridgemost-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 83.8 kB
Release files / bridgemost-2.0.0.tar.gz
| Download URL | bridgemost-2.0.0.tar.gz |
|---|---|
| Size | 44.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
48336c055c81e58c4cea6050c474eef5e8e824a16f14a01adda58ffe31f780a1
|
|
BLAKE2b-256 checksum How to use checksums |
fd7c40aaf87f81086ea5810ada8759e13d0cdfadcc8ed9a67e874cb5b766bac2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / bridgemost-2.0.0-py3-none-any.whl
| Download URL | bridgemost-2.0.0-py3-none-any.whl |
|---|---|
| Size | 39.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bad48ec69960de3b7a6fbe04e9f0ddb16c4f9031b386af47e0f279a04f8836f2
|
|
BLAKE2b-256 checksum How to use checksums |
c35d31025ff05fdd3da5bcdb124a43ab0f19fbd9142288c4c3c98ea8bff3e141
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|