Connecting Discord, Slack, Telegram, and WhatsApp Integrations
Wire Discord, Slack, Telegram, and WhatsApp as adapters into one self-hosted personal agent brain - not as four separate agents.
Search across all documentation pages
Wire Discord, Slack, Telegram, and WhatsApp as adapters into one self-hosted personal agent brain - not as four separate agents.
Platform APIs and terms change. Verify bot capabilities, rate limits, and automation rules at build time.
Normalize every platform into one event shape, authorize per-platform sender ids, run a single bounded agent loop, and egress through the same adapter that received the message. Add platforms only after the first private channel is boringly reliable.
chmod 600).parse_inbound → ChatEvent, authorize, send_message.max_turns and shared prefs/memory.platform, thread_id, channel_id) so answers return to the right place.Shared types and a multi-adapter dispatch sketch:
from pydantic import BaseModel
from typing import Callable, Protocol
class ChatEvent(BaseModel):
platform: str
sender_id: str
text: str
channel_id: str
thread_id: str | None = None
message_id: str
class ChatAdapter(Protocol):
name: str
def poll_or_handle(self) -> list[ChatEvent]: ...
def send(self, event: ChatEvent, text: str) -> dict: ...
ALLOWED = {
"telegram": {"111"},
"discord": {"222"},
"slack": {"U333"},
# whatsapp: add only after Business API setup is real
}
SEEN: set[str] = set() # persist to disk in production
def authorize(event: ChatEvent) -> bool:
return event.sender_id in ALLOWED.get(event.platform, set())
def handle_event(event: ChatEvent, adapters: dict[str, ChatAdapter], run_agent) -> None:
key = f"{event.platform}:{event.message_id}"
if key in SEEN:
return
SEEN.add(key)
if not authorize(event):
return
answer = run_agent(event.text, meta=event.model_dump())
adapters[event.platform].send(event, answer)
def tick(adapters: dict[str, ChatAdapter], run_agent: Callable) -> None:
for adapter in adapters.values():
for event in adapter.poll_or_handle():
handle_event(event, adapters, run_agent)Telegram-shaped parse (structure only; use the official Bot API client of your choice):
def telegram_to_event(update: dict) -> ChatEvent | None:
msg = update.get("message") or {}
if "text" not in msg:
return None
return ChatEvent(
platform="telegram",
sender_id=str(msg["from"]["id"]),
text=msg["text"],
channel_id=str(msg["chat"]["id"]),
thread_id=str(msg["chat"]["id"]),
message_id=str(msg["message_id"]),
)Per-platform env sketch:
TELEGRAM_BOT_TOKEN=...
DISCORD_BOT_TOKEN=...
SLACK_BOT_TOKEN=...
SLACK_APP_TOKEN=... # if using socket mode
# WhatsApp Cloud API (verify current field names at build)
WHATSAPP_TOKEN=...
WHATSAPP_PHONE_NUMBER_ID=...Clawdbot/OpenClaw-style personal agents treat each platform as a connector. The model, tools, memory, and policy stay central.
Duplicating a full agent per platform multiplies cost, drift, and incident surface. Share the runner; isolate credentials and rate limits.
| Platform | Common personal pattern | Integration style | Watch-outs |
|---|---|---|---|
| Telegram | Solo DM control room | Bot API long poll or webhook | Group privacy; bot command UX |
| Discord | Private server + channel | Gateway bot | Shared servers need role gates |
| Slack | Private channel in a workspace | Events API / Socket Mode | Workspace admin and retention policies |
| Notify trusted contacts | Business / Cloud API | Heavier setup; stricter automation rules |
Exact intents, slash commands, and button payloads differ. Keep those differences inside the adapter, not in tool code.
telegram:111 and discord:222 as the same human only after an explicit link flow you control.Never trust a display name. Ids are the unit of auth.
| Surface | Default tool set |
|---|---|
| Private DM with allowlisted you | Personal tools per your risk policy |
| Private channel, only you | Same as DM |
| Shared group / server | Read-only or no tools; maybe FAQ only |
| Public channel | Do not connect personal mail/calendar/shell |
Chat platforms retry. Persist processed platform:message_id keys (SQLite or a file-backed set) so double delivery does not double-send mail later.
Do not assume global ordering across platforms. Task state should key off your internal task id, not "the last Discord message."
Cap outbound messages per minute per platform.
Batch digests instead of one bubble per email.
Disable proactive posts during quiet hours except explicit VIP break-glass rules.
WhatsApp is often excellent for notifications and weaker as a first deep tool-control surface because of Business API setup and policy constraints.
If you add it, start with outbound digests to yourself, not full bidirectional shell control.
| Approach | Pros | Cons |
|---|---|---|
| Single platform only | Simple auth and UX | No fallback if that app is down |
| Multi-adapter one brain | Consistent tools/memory | More tokens to rotate |
| Agent per platform | Isolation | Drift and duplicated spend |
| Chat as notify-only + web UI for control | Stronger forms UX | Extra surface to host |
| Email as the only channel | Universal | Poor real-time control |
One. Add a second only when you have a concrete reason (for example work lives in Slack, personal control in Telegram).
Not if it has personal mail, calendar, or shell. Shared invocation with personal tools is an incident pattern.
Long poll is simpler for a private VPS without public HTTP. Webhooks need TLS and verified signatures; use them when latency or platform requirements demand it.
Explicit link: from an authenticated DM, issue a one-time code the user pastes in the other platform. Never auto-merge on display name.
Usually no. Require a hard mention plus a reduced tool set, or ignore groups entirely for personal hosts.
Adapters can translate /digest into a structured goal string before the model runs. That reduces prompt ambiguity for frequent jobs.
Use a private channel and a second throwaway account as the non-allowlisted negative test.
Deduplicate on your task layer (goal hash + time window) or accept that two wakes may run - budgets make that safe.
No. Route by task difficulty, not by chat brand.
Those projects popularized multi-chat personal hosts. Copy the connector pattern; evaluate any concrete integration code on security and maintenance, not marketing.
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.
Reviewed by Chris St. John·Last updated Jul 16, 2026