A deep technical investigation into architecting fully isolated per-user Telegram experiences on a single Hermes gateway deployment — using DM Topics, bot tokens, and routing strategies.
The critical finding from source code analysis: Hermes runs a single TelegramAdapter per gateway process, connected to one bot token. All users — whether DMs, group members, or thread participants — share the same adapter instance. Session isolation is achieved at the session key level, not the adapter level.
One TelegramAdapter handles ALL incoming messages regardless of which chat they come from. The adapter dispatches each message to the gateway's session manager, which routes it to the correct isolated session based on chat_id + thread_id.
Per-user session isolation is achieved via session keys: agent:main:telegram:dm:{user_id}:{thread_id}. The agent maintains separate conversation histories and memory flushes for each unique session key.
Telegram is registered as a single Platform.TELEGRAM enum value in gateway/config.py. The gateway loads one PlatformConfig for Telegram, which holds exactly one bot token. The TelegramAdapter is instantiated once in _create_adapter() and handles all incoming updates.
TELEGRAM_BOT_TOKEN=7123456789:ABCdefGHI...
│
▼
config.py _apply_env_overrides():
telegram_token = os.getenv("TELEGRAM_BOT_TOKEN")
config.platforms[Platform.TELEGRAM] = PlatformConfig()
config.platforms[Platform.TELEGRAM].enabled = True
config.platforms[Platform.TELEGRAM].token = telegram_token
Personal DM (no topics): agent:main:telegram:dm:7192357563 Group chat: agent:main:telegram:group:-5235499430 DM Topic (Bot API 9.4): agent:main:telegram:dm:7192357563:100
Use one bot, create up to N topics inside your personal DM with the bot. Each topic acts as a fully isolated conversation with its own session history and context. This is the cleanest solution — no additional bot tokens, no additional gateway processes, no cost overhead.
Telegram Bot API 9.4 (February 2026) introduced Private Chat Topics — bots can now create forum-style threads inside regular 1-on-1 DM chats. Previously only supergroups supported forum topics. Now you get forum topics in any private chat with a bot.
platforms: telegram: extra: dm_topics: - chat_id: 123456789 # YOUR Telegram user ID topics: - name: "General" icon_color: 7322096 - name: "Alice" icon_color: 9367192 - name: "Bob" icon_color: 16766590 - name: "Charlie" icon_color: 11134880
Run 4 separate Hermes gateway processes, each with its own bot token, connecting to a different Telegram bot. Each user gets their own completely independent AI instance — different sessions, different memory, different rate limits.
# Alice's gateway hermes gateway --profile alice # → reads ~/.hermes/profiles/alice/config.yaml # → reads ~/.hermes/profiles/alice/.env # Bob's gateway hermes gateway --profile bob # → reads ~/.hermes/profiles/bob/config.yaml # → reads ~/.hermes/profiles/bob/.env
# ~/.config/systemd/user/hermes-alice.service [Service] ExecStart=/usr/bin/hermes gateway --profile alice Restart=always # ~/.config/systemd/user/hermes-bob.service [Service] ExecStart=/usr/bin/hermes gateway --profile bob Restart=always
Create a Telegram Supergroup (which supports forum topics natively), add the single bot, and route each user's conversations to specific forum topics. This provides a shared team space with per-user/per-project topic isolation.
platforms: telegram: extra: group_topics: - chat_id: -1001234567890 # Supergroup ID topics: - name: "General" thread_id: 1 - name: "Alice" thread_id: 2 skill: "software-development" - name: "Bob" thread_id: 3 skill: "arxiv" - name: "Charlie" thread_id: 4 skill: "data-science"
| Criteria | DM Topics (A) | Multi-Bot Instances (B) | Supergroup Topics (C) |
|---|---|---|---|
| Isolation level | Session-level (shared AI) | Process-level (hard) | Session-level (shared AI) |
| Bot tokens needed | 1 | 4 | 1 |
| Gateway processes | 1 | 4 | 1 |
| Setup complexity | Low | High | Medium |
| Operational overhead | Low (one process) | High (4 processes) | Low (one process) |
| Per-user AI model | No (shared model) | Yes (per instance) | No (shared model) |
| Per-user skills | Yes (topic skill binding) | Yes (per profile) | Yes (topic skill binding) |
| Rate limit sharing | Yes (shared quota) | No (independent) | Yes (shared quota) |
| Privacy between users | Full (their own DM) | Full (separate bots) | None (same group) |
| Cost (infrastructure) | 1× | 4× | 1× |
| Recommended for | Personal multi-project | Multi-tenant SaaS | Team collaboration |
1. Open Telegram 2. Search for @userinfobot 3. Send any message 4. Bot replies: "Your ID: 123456789" 5. Save this number — you'll need it as chat_id for DM topics
model: default: minimax-m2.7 provider: opencode-go telegram: channel_prompts: {} group_sessions_per_user: true platforms: telegram: enabled: true token: "$TELEGRAM_BOT_TOKEN" reply_to_mode: "first" home_channel: platform: telegram chat_id: 123456789 # Owner user ID name: "Home" extra: dm_topics: - chat_id: 123456789 # User: Alice (you) topics: - name: "General" icon_color: 7322096 - name: "Alice Work" icon_color: 9367192 skill: "software-development" - name: "Bob Space" icon_color: 16766590 - name: "Charlie Space" icon_color: 11134880
# Shared across all profiles OPENAI_API_KEY=sk-... MINIMAX_API_KEY=sk-... CLOUDFLARE_API_TOKEN=cfat_...
TELEGRAM_BOT_TOKEN=712345678:alice_bot_token_here TELEGRAM_ALLOWED_USERS=111111 # Alice's user ID only HERMES_PROFILE=alice
TELEGRAM_BOT_TOKEN=712345679:bob_bot_token_here TELEGRAM_ALLOWED_USERS=222222 # Bob's user ID only HERMES_PROFILE=bob
When group_sessions_per_user: true, each user in a group gets their own session history rather than sharing one group-wide session. This is essential for Approach C to work properly with multiple users in the same group.
| Concern | Approach A (DM Topics) | Approach B (Multi-Bot) |
|---|---|---|
| User authentication | TELEGRAM_ALLOWED_USERS per bot |
Separate bot tokens, separate allowlists |
| Data isolation | Session-key isolated (same process) | Process-isolated (OS-level) |
| Rate limiting | Shared across all users (30 msg/sec per bot) | Each bot has own 30 msg/sec quota |
| Bot token compromise | Affects all topics | Only that user's instance affected |
| Memory/Memory bleed | None — sessions are separate SQLite entries | None — separate processes, separate state directories |
| Terminal access | Shared — users can only run allowed commands | Per-instance terminal config |
| ☐ | Get your Telegram user ID from @userinfobot |
| ☐ | Enable Topics mode in your DM with the bot (Telegram client setting) |
| ☐ | Add dm_topics config to config.yaml with 4 topic entries |
| ☐ | Set TELEGRAM_BOT_TOKEN in .env |
| ☐ | Set TELEGRAM_ALLOWED_USERS (your user ID) |
| ☐ | Set TELEGRAM_HOME_CHANNEL (your DM chat ID) |
| ☐ | Start gateway — topics auto-create on first run |
| ☐ | Verify thread_ids persisted back to config.yaml |
| ☐ | Create 4 bot tokens via @BotFather (one per user) |
| ☐ | Create 4 hermes profiles: alice, bob, charlie, team |
| ☐ | Add per-profile .env with unique TELEGRAM_BOT_TOKEN |
| ☐ | Configure per-profile TELEGRAM_ALLOWED_USERS |
| ☐ | Create systemd/launchd services for each profile |
| ☐ | Set up monitoring for all 4 processes |
| ☐ | Configure per-profile skill sets and SOUL.md |
For a single Hermes deployment serving 4 "channels" for yourself or a small team, Private Chat Topics (Bot API 9.4) is the clear winner. It's zero-cost, low-complexity, fully isolated at the session level, and supports skill binding per topic. The only real limitation is shared rate limits — but for personal use that's never an issue.
Best for: personal multi-project workflows, solo users wanting isolated contexts. Minimum hassle, maximum capability. Each "channel" is a topic tab in your DM with the bot.
Best for: multi-tenant deployments, different AI models per user, hard security isolation requirements. Worth the operational overhead only if you need true process-level separation.
gateway/platforms/telegram.py | TelegramAdapter — handles all Telegram I/O, DM topics, polling/webhook |
gateway/config.py | PlatformConfig dataclass, Platform enum, env var loading |
gateway/run.py | Gateway._create_adapter(), session routing, message dispatch |
~/.hermes/config.yaml | Platform configs, dm_topics, group_topics, reply_to_mode |
~/.hermes/channel_directory.json | Discovered channels and session keys at runtime |