Gateways connect external chat platforms to Vibe semantic sessions. Platform code normalizes incoming updates into Vibe.Gateway.Message, the generic runtime authorizes and dispatches them, and a session bridge streams assistant responses back through the platform adapter.
Telegram polling
Set at least a bot token and one authorization rule:
TELEGRAM_BOT_TOKEN=123:abc \
TELEGRAM_ALLOWED_USERS=123456 \
vibe gateway telegram --foreground --bot-username vibe_bot
For groups, prefer explicit chat allowlists and mention/reply gating:
TELEGRAM_BOT_TOKEN=123:abc \
TELEGRAM_GROUP_ALLOWED_CHATS=-100123456 \
vibe gateway telegram --foreground --bot-username vibe_bot --require-mention
Useful environment variables:
TELEGRAM_BOT_TOKEN— required unless--tokenis passed.TELEGRAM_BOT_ID/TELEGRAM_BOT_USERNAME— used for mention and reply detection.TELEGRAM_ALLOWED_USERS— comma-separated private/user allowlist.TELEGRAM_GROUP_ALLOWED_USERS— comma-separated user allowlist for groups.TELEGRAM_GROUP_ALLOWED_CHATS— comma-separated group chat allowlist.TELEGRAM_ALLOW_ALL_USERS=true— local testing only.TELEGRAM_REQUIRE_MENTION=true— require bot mention/reply/wake trigger in groups.TELEGRAM_FREE_RESPONSE_CHATS— group chats where every message is accepted after auth.TELEGRAM_IGNORED_THREADS— comma-separated forum topic ids to ignore.TELEGRAM_STREAM_MODE=edit|draft|auto— response streaming policy; edit mode is the stable fallback.TELEGRAM_POLL_TIMEOUT_S— long-poll timeout, default5to keep diagnostics responsive.TELEGRAM_POLL_RECEIVE_TIMEOUT_MS— HTTP receive timeout for long-poll requests, default10000.TELEGRAM_POLL_MAX_CONSECUTIVE_CONFLICTS— stop scheduling polls after repeatedgetUpdatesconflicts, default12.
Telegram responses are rendered as safe Telegram HTML. Vibe escapes raw HTML, maps a small Markdown-like subset (**bold**, *italic*, inline code, fenced code) to Telegram tags, splits long final sends below Telegram's 4096-character limit, treats message is not modified edits as success, and falls back to plain text when HTML delivery is rejected.
The polling transport clears stale webhooks before long polling so a bot can be moved between webhook and polling mode safely. It records polling diagnostics for /gateways, backs off after getUpdates conflicts, and stops scheduling polls after the configured consecutive conflict limit so an external bot instance is not hammered indefinitely.
Telegram topics
Vibe preserves Telegram message_thread_id as Vibe.Gateway.Source.thread_id for both forum-enabled groups and private chats with bot topics enabled. This matches Telegram Bot API 9.4+ private-chat topics and keeps independent Vibe sessions per visible bot topic:
gateway:telegram:dm:<chat-id>:<message-thread-id>
gateway:telegram:group:<chat-id>:<message-thread-id>[:<user-id>]For forum groups, Telegram omits message_thread_id for the General topic. Vibe represents that internal source thread as "1", but outbound adapters omit message_thread_id: 1 because Telegram expects General-topic sends without the wire thread id.
Hermes currently supports Telegram topics in the same broad shape: it preserves message.message_thread_id, maps forum General to thread id "1", sends/edit/photos/actions with message_thread_id, and has configured DM topic setup/mapping plus configured group topic metadata. Hermes topic-profile routing is still under active work in upstream PRs/issues, so Vibe should treat per-topic profile/skill routing as a follow-up rather than relying on it as a settled upstream contract.