Custom Discord–IRC–XMPP bridge with multi-presence. Portal is the identity source; no account provisioning on the bridge.
- Event bus — Central dispatcher; adapters produce/consume typed events
- Multi-presence — Webhooks per IRC nick / XMPP JID for Discord; IRC puppets for Discord users (when linked in Portal)
- Channel mappings — Config maps Discord channel ↔ IRC server/channel ↔ XMPP MUC
- Identity — Portal API (or read-only DB) for Discord ID ↔ IRC nick ↔ XMPP JID
- Python 3.10+
- uv or pip
uv sync --all-extras # or: pip install -e ".[dev]"
cp config.example.yaml config.yaml
# Edit config.yaml with your mappingsSee config.example.yaml. Key sections:
- mappings — List of Discord channel ID ↔ IRC ↔ XMPP MUC
- announce_joins_and_quits — Relay join/part/quit (default: true)
- irc_puppet_idle_timeout_hours — Idle timeout for IRC puppets (default: 24)
| Variable | Description |
|---|---|
DISCORD_TOKEN |
Discord bot token |
PORTAL_BASE_URL |
Portal API base URL (e.g. https://portal.example.com) |
PORTAL_TOKEN |
Portal API token (service auth) |
IRC_NICK |
IRC main connection nick (default: atl-bridge) |
XMPP_JID |
XMPP JID for MUC client |
XMPP_PASSWORD |
XMPP password |
XMPP_NICK |
MUC nickname (default: atl-bridge) |
bridge --config config.yaml
# or: python -m bridge --config config.yaml# Build
uv run uv build # or: docker build -f Containerfile -t atl-bridge .
# Run (bind-mount config)
docker run -v $(pwd)/config.yaml:/app/config.yaml \
-e DISCORD_TOKEN=... \
-e XMPP_JID=... -e XMPP_PASSWORD=... \
atl-bridgeOne bridge instance per Discord guild. Do not use the same bot across multiple guilds without clear documentation.
src/bridge/— Core: config, events, identity, gatewaysrc/bridge/adapters/— Discord, IRC, XMPP adaptersaudit/— Reference audits and consensus (AUDIT.md, STRUCTURE.md)
uv run pytest tests -v
uv run ruff check src testsMIT