Research Report

4 Distinct Telegram Channels on One Hermes Agent

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.

Date: April 26, 2026 Scope: Hermes Agent Gateway Strategy: 3 Viable Approaches Analyzed

Contents

  1. Architecture Overview
  2. How Hermes Telegram Integration Works
  3. Approach A — Private Chat Topics (DM Topics)
  4. Approach B — Multiple Bot Tokens
  5. Approach C — Group Supergroup with Topics
  6. Architecture Comparison Matrix
  7. Complete Configuration Walkthrough
  8. Session Routing Logic
  9. Security Considerations
  10. Implementation Checklist
  11. Final Recommendation

🏗️ Architecture Overview

Hermes Gateway — Single Adapter Model

┌─────────────────────────────────────────────────────┐ │ Hermes Gateway Process │ │ │ │ config.yaml ──► GatewayConfig │ │ │ │ │ platforms: │ │ │ telegram: ─────►│──► TelegramAdapter ◄──► Telegram Bot API │ token: "..." │ (1 instance) (1 bot token) │ home_channel │ │ │ extra: {...} │ │ │ │ │ │ discord: ─────────►│──► DiscordAdapter │ │ whatsapp: ────────►│──► WhatsAppAdapter │ │ ... │ │ └─────────────────────────────────────────────────────┘ KEY INSIGHT: The gateway instantiates exactly ONE TelegramAdapter per Platform.TELEGRAM entry. There is no native support for multiple independent Telegram adapters in a single gateway process.

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.

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.

Session Level

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.

🔍 How Hermes Telegram Integration Works

Core Mechanism Platform Enum + Single Token + Session Keys

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.

2.1 Config Loading Chain

~/.hermes/.env → gateway/config.py → PlatformConfig
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

2.2 Message Routing

User sends message on Telegram │ ▼ TelegramAdapter._handle_text_message() - Extracts: chat_id, user_id, message_thread_id, text - Builds: SessionSource(platform=telegram, chat_id, user_id, thread_id) - Calls: self.handle_message(event) │ ▼ Gateway.handle_message() - Looks up session key: "agent:main:telegram:dm:{user_id}:{thread_id}" - Routes to the AIAgent instance for that session - Agent processes and returns a response │ ▼ TelegramAdapter.send(chat_id, content) - Formats message (MarkdownV2) - Splits if > 4096 chars - Sends via python-telegram-bot Bot.send_message()

2.3 Session Key Format

Session Key Formats
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

🗂️ Approach A — Private Chat Topics (Bot API 9.4)

⭐ Recommended Bot API 9.4 Native Feature — Zero Extra Cost

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.

How It Works

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.

ONE Telegram Bot Token │ │ bot: @MyPersonalAssistant │ ▼ ┌──────────────────────────┐ │ Your DM with the Bot │ ◄── One adapter, one token │ │ │ 📌 General [T1] │ ◄── thread_id: 1 │ 📌 Alice Projects [T2] │ ◄── thread_id: 2 │ 📌 Bob Projects [T3] │ ◄── thread_id: 3 │ 📌 Charlie Projects [T4] │ ◄── thread_id: 4 └──────────────────────────┘ Each topic = isolated session: session:dms:123456789:1 (General) session:dms:123456789:2 (Alice) session:dms:123456789:3 (Bob) session:dms:123456789:4 (Charlie)

Configuration

~/.hermes/config.yaml
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
+ Zero extra cost — single bot token, no infrastructure
+ Clean UX — each user/project gets its own topic tab in Telegram
+ Auto-created — Hermes creates topics via API on startup if missing
+ Skill binding — each topic can auto-load a specific skill
+ Full isolation — each thread_id has its own session history
All users share the same bot token (same AI, same rate limits)
Requires Bot API 9.4 support from python-telegram-bot
User must enable Topics mode in their Telegram client

Topic Creation Flow

Gateway Startup │ ▼ TelegramAdapter._setup_dm_topics() │ For each topic in config WITHOUT thread_id: │ ▼ Bot.createForumTopic(chat_id=123456789, name="Alice") │ ▼ Telegram API returns { message_thread_id: 5 } │ ▼ Persist thread_id back to config.yaml (so next restart skips API call) │ ▼ Sessions now route to agent:main:telegram:dm:123456789:5

🤖 Approach B — Multiple Bot Tokens (Multiple Gateway Instances)

Advanced N Bots × N Gateway Instances — Full Hard Isolation

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.

┌─────────────────────────────────────────────────┐ │ Gateway Instance 1 (User Alice) │ │ .env: TELEGRAM_BOT_TOKEN=bot_alice_token │ │ Adapter: TelegramAdapter(PlatformConfig) │ │ Bot: @AliceAssistantBot │ └─────────────────────────────────────────────────┘ ▲ (completely independent processes) ▼ ┌─────────────────────────────────────────────────┐ │ Gateway Instance 2 (User Bob) │ │ .env: TELEGRAM_BOT_TOKEN=bot_bob_token │ │ Adapter: TelegramAdapter(PlatformConfig) │ │ Bot: @BobAssistantBot │ └─────────────────────────────────────────────────┘ ▲ ▼ ┌─────────────────────────────────────────────────┐ │ Gateway Instance 3 (User Charlie) │ │ .env: TELEGRAM_BOT_TOKEN=bot_charlie_token │ │ Bot: @CharlieAssistantBot │ └─────────────────────────────────────────────────┘ ▲ ▼ ┌─────────────────────────────────────────────────┐ │ Gateway Instance 4 (Shared Team) │ │ .env: TELEGRAM_BOT_TOKEN=bot_team_token │ │ Bot: @TeamAssistantBot │ └─────────────────────────────────────────────────┘

Process Isolation via Profiles

hermes profiles — use separate config per user
# 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

Service Management

systemd service files (one per user)
# ~/.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
+ True hard isolation — separate processes, separate memory, separate rate limits
+ Each user can have different AI models, different skills, different SOUL.md
+ One bot compromised = others unaffected
+ Each can run different Hermes versions independently
Higher operational complexity — 4 processes to manage
Each instance uses RAM for the LLM context window independently
No shared context between users (could be a pro or con)
4× the update overhead on the server

👥 Approach C — Supergroup with Forum Topics

Shared Space One Bot + One Supergroup + N Forum Topics

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.

Supergroup: "Team Workspace" (chat_id: -1001234567890) │ │ bot: @TeamHermesBot │ ▼ ┌─────────────────────────────────┐ │ 🏠 General [T1] │ │ 📊 Alice Project [T2] │ session: agent:main:telegram:dm:ALICE_ID:2 │ 📊 Bob Project [T3] │ session: agent:main:telegram:dm:BOB_ID:3 │ 📊 Charlie Project [T4] │ session: agent:main:telegram:dm:CHARLIE_ID:4 └─────────────────────────────────┘ session routing: chat_id + thread_id → unique session ─────────────────────────────────────────────── Note: In a supergroup, chat_id is the GROUP (-100123...), thread_id is the topic number. Sessions still isolate per user_id via group_sessions_per_user config.

Configuration

~/.hermes/config.yaml — group topics
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"
+ Shared team space — everyone in one group
+ Topic isolation with skill binding
+ Single bot token, single gateway process
Users need to join the supergroup (onboarding friction)
Privacy — all messages visible to all group members
All users share one bot token and rate limits

⚖️ Architecture Comparison Matrix

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)
Recommended for Personal multi-project Multi-tenant SaaS Team collaboration

⚙️ Complete Configuration Walkthrough

7.1 Find Your Telegram User ID

Step 1: Get your user ID
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

7.2 Create Topics in Telegram (Prerequisite)

⚠️ User must enable Topics mode manually — The user (not the bot owner) must open their DM with the bot, tap the bot name at the top, and enable "Topics". Without this, Hermes logs "The chat is not a forum" and skips topic creation.

7.3 Full config.yaml Example (Approach A)

~/.hermes/config.yaml — 4-user DM Topics setup
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

7.4 Multi-Instance Profile Setup (Approach B)

~/.hermes/.env — shared env vars
# Shared across all profiles
OPENAI_API_KEY=sk-...
MINIMAX_API_KEY=sk-...
CLOUDFLARE_API_TOKEN=cfat_...
~/.hermes/profiles/alice/.env
TELEGRAM_BOT_TOKEN=712345678:alice_bot_token_here
TELEGRAM_ALLOWED_USERS=111111  # Alice's user ID only
HERMES_PROFILE=alice
~/.hermes/profiles/bob/.env
TELEGRAM_BOT_TOKEN=712345679:bob_bot_token_here
TELEGRAM_ALLOWED_USERS=222222  # Bob's user ID only
HERMES_PROFILE=bob

🧭 Session Routing Logic

Telegram Update arrives at TelegramAdapter │ ├── chat.type = "private" (DM) │ │ │ ├── message_thread_id present (Bot API 9.4 DM Topics)? │ │ └── session = telegram:dm:{user_id}:{thread_id} │ │ │ └── no thread_id (regular DM)? │ └── session = telegram:dm:{user_id} │ ├── chat.type = "supergroup" (Group) │ │ │ ├── Topics mode enabled? │ │ └── session = telegram:group:{chat_id}:{thread_id} │ │ │ └── No topics? │ └── session = telegram:group:{chat_id} │ └── chat.type = "channel" └── session = telegram:channel:{chat_id}

Key Config: group_sessions_per_user

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.

🔒 Security Considerations

ConcernApproach 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
⚠️ TELEGRAM_ALLOWED_USERS — Always set this. Without it, anyone who finds your bot token can interact with your Hermes instance. Use numeric user IDs (not @usernames) for stable allowlists.

Implementation Checklist

Approach A (DM Topics) — Checklist

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

Approach B (Multi-Bot) — Checklist

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

🎯 Final Recommendation

Use Approach A (DM Topics) for Personal Use

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.

1 Bot / 4 Topics (Approach A)

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.

4 Bots / 4 Gateways (Approach B)

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.

Key Files Reference
gateway/platforms/telegram.pyTelegramAdapter — handles all Telegram I/O, DM topics, polling/webhook
gateway/config.pyPlatformConfig dataclass, Platform enum, env var loading
gateway/run.pyGateway._create_adapter(), session routing, message dispatch
~/.hermes/config.yamlPlatform configs, dm_topics, group_topics, reply_to_mode
~/.hermes/channel_directory.jsonDiscovered channels and session keys at runtime