--- name: hermes-telegram description: Configure, troubleshoot, and manage Telegram integration for Hermes Agent — bot setup, .env configuration, gateway restart, and common failure modes. version: 1.0.0 author: Hermes Agent license: MIT platforms: [linux, macos] metadata: hermes: tags: [hermes, telegram, messaging, gateway, bot] related_skills: [hermes-agent] related_skills: [hermes-agent] --- # Hermes Telegram Integration Configure the Hermes Agent gateway to send and receive messages on Telegram. Covers bot creation, .env setup, allowed users, home channel, gateway restart, and troubleshooting. ## Prerequisites - Hermes Agent gateway installed and running (`hermes gateway status` or `ps aux | grep 'hermes gateway run'`) - A Telegram account to create and manage the bot ## Setup Steps ### 1. Create a Bot on Telegram Message [@BotFather](https://t.me/BotFather) on Telegram: ``` /newbot ``` Follow the prompts to choose a name and username. BotFather will return a bot token like: ``` 8971430276:AAFu...Amq4 ``` Save this token — you'll need it in the next step. ### 2. Find Your Numeric IDs You need numeric Telegram IDs, not usernames. Message [@userinfobot](https://t.me/userinfobot) on Telegram — it will reply with: - **Your user ID** (a number like `123456789`) — used for `TELEGRAM_ALLOWED_USERS` - For groups/channels: add the bot to the group, send a message, then use @userinfobot in the group to get the **chat ID** Note: `TELEGRAM_ALLOWED_USERS` and `TELEGRAM_HOME_CHANNEL` require **numeric IDs**, not `@username` strings. ### 3. Configure .env Edit the `.env` file. The default template has all Telegram variables **commented out** — you must uncomment and fill them in: ```bash hermes config env-path # prints the path (typically ~/.hermes/.env) ``` The relevant lines (find them under the `# TELEGRAM INTEGRATION` section): ```env TELEGRAM_BOT_TOKEN=your_bot_token_here TELEGRAM_ALLOWED_USERS=123456789 # Comma-separated numeric user IDs TELEGRAM_HOME_CHANNEL=123456789 # Numeric chat ID for cron deliveries TELEGRAM_HOME_CHANNEL_NAME=@yourusername # Display name (optional, username is fine here) ``` **Important:** The default template uses a combined single-line format: ``` # TELEGRAM_BOT_TOKEN=*** TELEGRAM_ALLOWED_USERS= ``` When uncommenting, split this into **separate lines** as shown above — one variable per line. Use your editor or `sed` to do it cleanly. For the `HOME_CHANNEL`, if you only want DM delivery (bot messages you directly), set it to your own user ID — same as `ALLOWED_USERS`. ### 4. Restart the Gateway Configuration changes in `.env` are read at startup. Restart the gateway to pick them up: ```bash hermes gateway restart ``` Or if running as a systemd user service: ```bash systemctl --user restart hermes-gateway ``` #### Manual Restart (no systemd service) If `systemctl --user list-units --type=service --all | grep hermes` returns nothing, the gateway was started manually. Kill and restart it: ```bash # Find the gateway PID ps aux | grep 'hermes gateway run' # Kill it (use -9 if plain kill won't work) kill -9 # Wait for it to die sleep 2 # Start fresh — MUST use background=true (nohup/disown is blocked by tool policy) # In the Hermes CLI session: # terminal(background=true, notify_on_complete=true, command="hermes gateway run") ``` **Important:** Do not use `nohup`, `disown`, or trailing `&` in a foreground terminal() call — the tool policy blocks shell-level background wrappers. Always use `terminal(background=true)` so Hermes tracks the process. ### 5. Verify It's Working Send a message to your bot on Telegram. It should respond. Check the gateway logs for confirmation: ```bash grep -i telegram ~/.hermes/logs/gateway.log | tail -20 ``` Look for these lines to confirm a successful connection: ``` Connecting to telegram... [Telegram] Auto-discovered Telegram fallback IPs: 149.154.166.110 [Telegram] set_my_commands OK for scope BotCommandScopeDefault (30 cmds) [Telegram] Connected to Telegram (polling mode) ✓ telegram connected ``` If you see `Connected to Telegram (polling mode)` and `✓ telegram connected`, the bot is live. For a full reference of restart commands, log signatures, curl test-message patterns, and sed snippets, see [`references/gateway-restart-and-test.md`](references/gateway-restart-and-test.md). #### Sending a Test Message from the CLI The Hermes `send_message` tool only works in sessions initiated from a messaging platform (Telegram, Discord, etc.). In a CLI session, it returns `"No messaging platforms connected"` even when the gateway has Telegram active. **Workaround — use the Telegram Bot API directly via curl:** ```bash curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ -d "chat_id=${CHAT_ID}" \ -d "text=Hello from Hermes! 👋" ``` The `${TELEGRAM_BOT_TOKEN}` is the value set in `.env` and `${CHAT_ID}` is the numeric user/chat ID. This sends a message bypassing the Hermes gateway — useful for testing or one-off notifications from the CLI. ## Gateway Check To see if the gateway is running before troubleshooting: ```bash ps aux | grep 'hermes gateway run' ``` ## Key Configuration Variables | Variable | Required | Description | |----------|----------|-------------| | `TELEGRAM_BOT_TOKEN` | Yes | Bot token from @BotFather | | `TELEGRAM_ALLOWED_USERS` | Recommended | Comma-separated numeric user IDs allowed to chat. **Leave empty to allow anyone** (not recommended for production). | | `TELEGRAM_HOME_CHANNEL` | For cron | Default chat ID for cron job deliveries | | `TELEGRAM_HOME_CHANNEL_NAME` | No | Display name for the home channel | | `TELEGRAM_CRON_THREAD_ID` | No | Forum topic ID for cron deliveries in topic-mode groups | ## Long-Running Tasks & Blocking Behavior The gateway processes **one turn at a time per session**. While the agent is inside a turn (thinking, running tools, waiting for a terminal command), it cannot receive or process new messages from you. Telegram shows "typing..." the entire time. ### Why the bot blocks | Phase | What's happening | Can you message? | |-------|-----------------|-----------------| | 🔄 Agent calls a tool (e.g. `terminal()`) | Blocks waiting for result | ❌ Queued | | 🤖 Agent calls the LLM again with tool output | Generating next action | ❌ Queued | | 📨 Agent sends you a progress update | Brief mid-turn message | ❌ Still in same turn | | ✅ Agent sends final response and ends turn | **Done** | ✅ Next message processed | ### "Typing..." = active LLM calls = cost Every iteration of the agent loop makes a new API call to your LLM provider. While the bot shows "typing...", it is actively making LLM calls — you are being charged for input + output tokens each round. Input tokens grow each iteration as tool results are appended to the conversation context. ### How to avoid blocking the bot Three approaches, in order of preference: | Approach | How | Best for | |----------|-----|----------| | ⏰ **Cron job** | `cronjob(action='create', schedule='...', prompt='run my script', no_agent=True)` — script runs independently, stdout delivered verbatim to Telegram | Standalone scripts that run on a schedule or fire-and-forget | | 🏃 **Background terminal** | `terminal(command='python long_script.py', background=true, notify_on_complete=true)` — agent returns immediately, pings you when done | One-off long scripts the user triggers | | 📋 **/queue** | In CLI: `/queue ` — queues work for after current turn ends | Quick follow-ups during an active session | The cron approach is cleanest: the bot never blocks, and `no_agent=True` means zero LLM calls during execution — the script's stdout is delivered verbatim. ### Verifying the bot is stuck mid-turn Check the gateway logs for the last activity: ```bash tail -20 ~/.hermes/logs/gateway.log ``` Look for: - `inbound message: ... msg='your prompt'` — last message received - `Flushing text batch ... (N chars)` — last update sent (but turn not over) - No new `inbound message` entries — session is blocked, new messages are queued ## Pitfalls - **Usernames are not IDs.** `TELEGRAM_ALLOWED_USERS` and `TELEGRAM_HOME_CHANNEL` need **numeric** Telegram IDs, not `@username` strings. Use @userinfobot to get them. - **All vars start commented out.** The `.env` template ships with `#` prefix on every Telegram line. You must uncomment them. - **Multi-variable line trap.** The default `.env` template writes `TELEGRAM_BOT_TOKEN` and `TELEGRAM_ALLOWED_USERS` on the same line: `# TELEGRAM_BOT_TOKEN=*** TELEGRAM_ALLOWED_USERS=`. This is NOT valid env format with the token value — split into two separate lines when configuring. - **Gateway restart required.** `.env` is read at process startup. Simply running `hermes` in a new CLI session does not reload the gateway's env vars. Use `hermes gateway restart` (or `systemctl --user restart hermes-gateway`) every time you change `TELEGRAM_*` variables. - **Config schema warnings can block clean startup.** If gateway status/logs show `custom_providers is a dict — it must be a YAML list`, fix it in `~/.hermes/config.yaml` by making `custom_providers` a list (or clear it with `hermes config set custom_providers "[]"`), then restart the gateway. - **Token secrecy.** The bot token is a secret — anyone with it can control your bot. Keep it out of version control and shell history. - **Gateway API server must be running.** The gateway also starts the API server (typically port 8642). If tools or web UI can't reach the agent, the root cause is often a stopped gateway, not Telegram itself. - **send_message tool is CLI-blind to Telegram.** From a CLI session, `send_message(action=list)` returns `No messaging platforms connected` even when the gateway has Telegram active. This is by design — the tool only routes through gateway-originated sessions. Use the Telegram Bot API directly via curl to send messages from CLI sessions (see the Verification section for the exact curl command). ### Bot Commands: Registration & Limits The gateway auto-registers bot commands from `hermes_cli.commands.telegram_bot_commands()` on startup. Commands come from three sources: built-in CommandDef entries, plugin slash commands, and skill entries. Gateway caps the command list at `MAX_COMMANDS_PER_SCOPE = 30` (telegram.py:108) to stay under Telegram's undocumented ~4KB payload limit. **Adding a custom command persistently:** 1. Edit `~/.hermes/hermes-agent/hermes_cli/commands.py` -- add your (name, description) pair at the end of `telegram_bot_commands()`: ```python result.append(("imagine", "Generate an image from a text prompt")) ``` 2. Add the command to `_TELEGRAM_MENU_PRIORITY` if the cap is tight -- commands outside the priority list get trimmed first. 3. If you go over 30 commands, raise `MAX_COMMANDS_PER_SCOPE` in `telegram.py`. 4. Restart the gateway to pick up changes. Without these three changes, custom commands get overwritten on gateway restart or silently truncated at the 30-command cap. ## Troubleshooting ### Diagnostic Flow: Bot Not Responding Start with a **status check first** — it's the fastest way to narrow the cause. ``` hermes gateway status # Primary check ``` If that's unavailable, fall back to: ``` ps aux | grep 'hermes gateway run' # Second — gateway process exists? systemctl --user status hermes-gateway 2>/dev/null # Third — systemd service? ``` #### Branch A: Gateway is not running The most common cause of "stopped working" is the gateway having been shut down. Check the logs to find out why: ``` grep -i "telegram\|error\|fail\|warn\|sigterm\|sigkill\|oom" ~/.hermes/logs/gateway.log | tail -20 ``` Common shutdown signatures in the logs: | Log pattern | Likely cause | Action | |-------------|-------------|--------| | `WARNING ... Shutdown context: signal=SIGTERM under_systemd=yes parent_pid=1` | systemd sent SIGTERM (user logout, reboot, service stop) | Restart gateway or install as permanent service | | `ERROR ... signal=SIGKILL` | OOM killer or forced kill | Check memory pressure, `dmesg | grep -i oom` | | `ERROR ... Traceback (most recent call last)` | Crash / unhandled exception | Read the traceback, fix the root cause | | Logs end abruptly with no shutdown message | Process was killed externally (shell session closed, SSH disconnect) | Restart gateway | | No Telegram-related log entries at all | Telegram may not be configured or enabled in config | Check `.env` for `TELEGRAM_*` vars, check `config.yaml` → `telegram` section | If the log shows the gateway was working fine then received SIGTERM, the fix is straightforward — restart it: ```bash hermes gateway run # foreground (session-dependent) hermes gateway install # as permanent systemd user service (auto-restarts) ``` If no systemd service exists (`systemctl --user list-units --type=service --all | grep hermes` returns empty), the gateway was started manually and won't survive a logout/reboot without the service. #### Branch B: Gateway is running but not responding ``` grep -i telegram ~/.hermes/logs/gateway.log | tail -30 ``` Look for: - `[Telegram] Connected to Telegram (polling mode)` — connection was established - `inbound message: platform=telegram user=...` — messages are being received - `Sending response (... chars) to 1498679692` — responses are being sent - `ERROR` or `WARNING` entries — something went wrong If messages arrive but responses fail, check: 1. `TELEGRAM_BOT_TOKEN` is correct and uncommented in `.env` 2. The bot hasn't been blocked by Telegram (try sending a test from a different bot) 3. Network/firewall: Telegram polling needs outbound connectivity to `api.telegram.org` #### Branch C: Never worked (first-time setup) If the user says the bot never responded: 1. Follow the full Setup Steps section above 2. Check that `TELEGRAM_BOT_TOKEN` is on its own line (not merged with another var) 3. Verify with `curl` directly: `curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"` — should return `{"ok":true,"result":{"id":...,"is_bot":true,"first_name":"...","username":"..."}}` 4. Check `TELEGRAM_ALLOWED_USERS` — without it, the bot defaults to allowing everyone; if it's set to the wrong numeric ID, the bot ignores your messages 5. After fixing, restart the gateway 6. Wait 5-10 seconds, then send a message to the bot on Telegram ### Symptom: "Bot responds to everyone / ignores me" Check `TELEGRAM_ALLOWED_USERS` is set to your numeric user ID. Without this, the bot is open to anyone who finds it. ### Symptom: "Cron messages don't arrive on Telegram" 1. Ensure `TELEGRAM_HOME_CHANNEL` is set to the correct numeric chat ID 2. The home channel is where cron delivers by default — if you DM'd the bot manually but set the home channel to a group, cron goes to the group, not your DMs ### Symptom: "send_message tool says 'No messaging platforms connected' from CLI" This is expected behavior — the `send_message` tool only routes through a session that was initiated from that platform. From a CLI session, it cannot discover Telegram even if the gateway has it connected. **Workaround:** Call the Telegram Bot API directly: ```bash curl -s -X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \ -d "chat_id=${CHAT_ID}" \ -d "text=Your message" ``` ### Symptom: "Can't restart — no systemd service found" If `systemctl --user list-units` shows no hermes service, the gateway was started manually (e.g., via `hermes gateway run` in a background terminal). See the **Manual Restart (no systemd service)** section in step 4 above.