Connectors¶
Connectors bridge external chat platforms to the LegionForge gateway. They translate platform messages into gateway task submissions and stream the SSE response back as platform-native updates.
All connectors follow the same pattern:
- Listen for messages with a trigger pattern (e.g.,
!<task>for Discord) - Submit the task to the gateway with the platform user's credentials
- Subscribe to the SSE stream
- Edit a placeholder reply with streaming updates
- Post the final result
Available connectors¶
| Connector | Platform | Trigger | Module |
|---|---|---|---|
| Discord | Discord servers | !<task> or @bot <task> |
src/connectors/discord.py |
| Telegram | Telegram bot | /task <task> or @bot <task> |
src/connectors/telegram.py |
| Slack | Slack workspaces | /legionforge <task> slash command |
src/connectors/slack.py |
| WhatsApp Business | message starting with ! |
src/connectors/whatsapp.py |
|
| Webhook | Generic HTTP | POST with JSON body |
src/connectors/webhook.py |
Starting a connector¶
Each connector has its own Make target:
Connectors read their platform credentials (Discord bot token, Slack signing secret, etc.) from macOS Keychain at startup. Service names follow legionforge_<platform>_<credential>.
Auth bridging¶
Connectors don't have their own API key into the gateway. Instead, each platform user is mapped to a gateway_users row at first message via the connector_identities table:
CREATE TABLE connector_identities (
connector TEXT NOT NULL, -- 'discord', 'telegram', etc.
platform_user_id TEXT NOT NULL,
gateway_user_id BIGINT REFERENCES gateway_users(id),
PRIMARY KEY (connector, platform_user_id)
);
First-time users get auto-provisioned with a default quota. Admins can adjust per-user quotas via make set-quota.
Discord connector¶
The Discord connector is the most polished and serves as the reference implementation.
Setup¶
- Create a Discord application and bot at https://discord.com/developers/applications
- Enable the Message Content Intent
- Copy the bot token, store it:
- Invite the bot to your server with the
Send MessagesandRead Message Historypermissions - Run
make discord-start
Usage¶
The bot acknowledges with a "Thinking..." reply, then edits it as the SSE stream produces output. The final reply contains the full result and a footer with token usage.
Slack connector¶
Slack uses a slash command rather than a message prefix. The slash command points to the gateway's /connectors/slack/command endpoint, which validates the signing secret and forwards to the worker.
security add-generic-password -A \
-s legionforge_slack_signing_secret -a api_key -w <secret>
security add-generic-password -A \
-s legionforge_slack_bot_token -a api_key -w <token>
make slack-start
Webhook connector¶
The generic webhook connector is the simplest:
POST /connectors/webhook
Content-Type: application/json
{
"prompt": "What's the weather in Tokyo?",
"callback_url": "https://example.com/legionforge/callback"
}
The gateway processes the task and posts the result to callback_url when done.
Writing a new connector¶
The connector contract is minimal:
class Connector:
async def listen(self) -> None:
"""Listen for platform messages and submit them to the gateway."""
async def stream_back(self, task_id: str, platform_target: str) -> None:
"""Subscribe to /tasks/{task_id}/stream and post updates to the platform."""
Copy src/connectors/discord.py as a template. The trickiest part is platform-specific: how to edit a previously-sent message as the stream progresses without spamming the API.