CorvinOS
July 22, 2026 · View on GitHub
Add a messaging bridge to CorvinOS in minutes. Each bridge connects one messenger channel to the AI assistant. You can add or remove bridges at any time — no reinstall needed.
Quick overview
| Bridge | What you need | Setup time |
|---|---|---|
| Discord | A Discord bot token | ~5 min |
| Telegram | A bot token from @BotFather | ~3 min |
| A WhatsApp account (QR-code scan) | ~2 min | |
| Slack | A Slack app with OAuth token | ~10 min |
| IMAP/SMTP credentials | ~5 min |
Option A — Console UI (recommended)
- Open the web console:
corvin serve→ http://localhost:8765/console/ - Go to Settings → Bridges
- Click Add bridge, pick the messenger, and follow the wizard
- The bridge starts automatically once the token is saved
Option B — Command line
# Interactive bridge wizard (all steps guided):
corvin-install # or: corvin setup (if already installed)
# Add a single bridge later:
corvin-install --bridge discord # guided token setup for Discord only
Discord
1. Create a bot
- Open https://discord.com/developers/applications
- Click New Application → give it a name → Create
- Left sidebar: Bot → Add Bot → confirm
- Under Token: click Reset Token → copy the token
2. Privileged Intents (optional)
The bot token alone is enough: without any privileged intent, DMs and @mentions work out of the box (the daemon detects the portal state and starts in token-only mode). Enable on the Bot page under Privileged Gateway Intents only if you want more:
- Message Content Intent — read all guild-channel text (not just @mentions)
- Server Members Intent — optional, for user management
3. Invite the bot to your server
- Left sidebar: OAuth2 → URL Generator
- Scopes:
bot - Bot permissions:
Send Messages,Read Message History,Attach Files,Use Slash Commands - Copy the generated URL → open in browser → invite to your server
4. Save the token
In the console: Settings → Bridges → Discord → paste token → Save
Or on the command line:
# Place the token in the bridge config:
mkdir -p ~/.corvin/bridges/discord
cat > ~/.corvin/bridges/discord/settings.json <<'EOF'
{
"discord_token": "YOUR_BOT_TOKEN_HERE",
"whitelist": ["your_discord_user_id"],
"rate_limit_per_minute": 20
}
EOF
Find your Discord user ID: Discord Settings → Advanced → Developer Mode on → right-click your name → Copy User ID
Telegram
1. Create a bot via @BotFather
- Open Telegram → search for @BotFather →
/start - Send
/newbot→ follow the prompts - Copy the HTTP API token (looks like
123456:ABC-DEF...)
2. Set up the bridge
Console: Settings → Bridges → Telegram → paste token → Save
Or via command line:
mkdir -p ~/.corvin/bridges/telegram
cat > ~/.corvin/bridges/telegram/settings.json <<'EOF'
{
"telegram_token": "YOUR_BOT_TOKEN",
"whitelist": ["your_telegram_user_id"],
"rate_limit_per_minute": 20
}
EOF
Find your Telegram user ID: message @userinfobot → it replies with your numeric ID.
3. Disable the privacy mode (optional)
If you want the bot to read group messages:
/setprivacy → select your bot → Disable
WhatsApp uses a QR-code scan — no token needed.
1. Start the pairing flow (one click — no terminal)
In the console: Setup wizard → WhatsApp → Start WhatsApp bridge, or Settings → Bridges → WhatsApp → QR / Re-link → Start WhatsApp bridge.
The button installs Node.js + the WhatsApp dependencies on demand (one-time) and starts the bridge daemon for you. Live progress is shown; the QR code then appears in the console as soon as the daemon is running.
Terminal alternative (Linux/macOS):
bridge.sh up # starts configured bridges; QR served on :7891
2. Scan the QR code
Open WhatsApp on your phone → Settings → Linked Devices → Link a Device → scan
the QR shown in the console. To link by number instead, start the bridge with
--pair-code +49123456789.
The session is saved automatically. Re-authentication is needed every ~14 days.
Note: WhatsApp requires Node.js ≥ 20 (Baileys). The console auto-installs a pinned Node.js LTS if your system Node is missing or older than 20, then runs
npm installin~/.corvin/bridges/whatsapp/on first start. If auto-install fails (e.g. no winget on Windows), the console shows per-OS manual steps with a link to nodejs.org.
Slack
1. Create a Slack app
- Open https://api.slack.com/apps → Create New App → From scratch
- Name the app, pick your workspace
2. Add OAuth scopes
Left sidebar → OAuth & Permissions → Scopes → Bot Token Scopes:
channels:history,channels:readchat:write,files:writeim:history,im:read,im:writeusers:read
3. Install the app and copy the token
Left sidebar → Install App → Install to Workspace → copy the Bot User OAuth Token (xoxb-...)
4. Save the token
Console: Settings → Bridges → Slack → paste xoxb-... token → Save
1. Prepare credentials
You need:
- IMAP server + port (e.g.
imap.gmail.com:993) - SMTP server + port (e.g.
smtp.gmail.com:587) - Login email + password (or app-specific password)
For Gmail: enable IMAP in Gmail settings and create an App Password (requires 2FA): https://myaccount.google.com/apppasswords
2. Save the config
Console: Settings → Bridges → Email → fill in the form → Save
3. Sender authentication (important)
The From header alone is forgeable, so inbound email is trusted only when the
receiving provider's top Authentication-Results line shows DMARC (or aligned
DKIM) pass. Consequences:
- An empty whitelist denies every sender — claim ownership with the PIN
/auth <pin>flow (setpinin the email settings) instead of listing addresses up front. - On Gmail / iCloud / Outlook / Yahoo and other well-known providers this works out of the box (their authserv-id is recognised).
- On a self-hosted / non-stamping IMAP provider you must set
auth_results_authserv_idto your receiver's authserv-id, otherwise inbound messages fail closed and senders fall back to the PIN flow. dev_mode: truerestores the legacy open behaviour for local testing only.
Adding a second bridge
You can run multiple bridges simultaneously (e.g. Discord + Telegram):
# Each bridge is an independent process.
# Start all enabled bridges:
bridge.sh start all
# Or start/stop individually:
bridge.sh start discord
bridge.sh stop discord
In the console: Settings → Bridges — each bridge has its own Start / Stop toggle.
Removing a bridge
Console: Settings → Bridges → [bridge name] → Remove
This stops the bridge process and deletes its credentials.
The bridge package (npm / pip) is NOT uninstalled — run corvin-uninstall for a full cleanup.
Troubleshooting
"Bridge did not start" / no response in the chat app
- Check logs:
bridge.sh logs discord(or the bridge name) - Verify the token is correct and has the right permissions
- On Discord: without Message Content Intent the bot only sees DMs and @mentions — mention the bot, or enable the intent for full channel reading
- Restart the bridge:
bridge.sh restart discord
Voice notes not being sent
edge-tts and Piper need ffmpeg to convert their output to OGG-Opus. A
bundled imageio-ffmpeg binary is used automatically when no system
ffmpeg is found on PATH (or FFMPEG_BIN), so this works out of the box on
every platform — including a fresh Windows install, where the installer
intentionally skips installing system ffmpeg. If you still want a system
ffmpeg (e.g. for other tools):
# Linux / WSL:
sudo apt install ffmpeg
# macOS:
brew install ffmpeg
# Windows:
winget install ffmpeg
TTS without an OpenAI API key
CorvinOS falls back automatically:
OpenAI TTS → edge-tts (free, Microsoft, internet) → Piper (fully local, offline)
No action needed — if OPENAI_API_KEY is absent, edge-tts is used. It is a base
dependency and the installer's TTS step (ensure_edge_tts) reinstalls it explicitly,
so the middle tier stays available even when the bridge runs on a separate/pre-existing
Python interpreter that only had openai.
To force fully offline TTS: CORVIN_TTS_PROVIDER=piper in service.env
(requires a Piper voice model — downloaded automatically as part of a normal
corvin-install run since ADR-0185 M2/M3; no separate flag needed. Re-run
corvin-install to fetch it if it was skipped due to no network at install
time, or set piper_model_<lang> in ~/.config/corvin-voice/config.json
manually.)
Setting CORVIN_SAY_NO_FALLBACK=1 makes a pinned provider hard-fail instead of
falling through to the auto-chain — a strict/isolation switch (default off) used by
test_say.sh to prove a specific tier actually produced the audio rather than being
masked by a later tier. It is not needed for normal runtime.
Windows — "corvin is not recognized as a command"
The pip install corvinOS PATH auto-fix runs on every Python start.
If it did not take effect in the current terminal, either:
- Close and re-open the terminal (PowerShell / CMD)
- Or run:
python -m corvinOS(path-independent fallback)