Коротко

  • Реальный сетап: @BotFather/newbot → токен в channels.telegram.botToken (или в переменную TELEGRAM_BOT_TOKEN) → openclaw gatewayopenclaw pairing approve telegram <CODE>. Никакого openclaw channels login telegram: в доке прямо написано, что Telegram подключается не так.
  • «Работал, обновился — пропал» — обычно битое дерево зависимостей канал-плагина. Лечение: openclaw doctor --fix, затем openclaw gateway restart.
  • В свежих версиях доступ в группах не наследуется из DM-пейринга. В личке бот отвечает, в группе молчит — добавь свой numeric user ID в groupAllowFrom.
  • ID — два разных: твой user ID идёт в allowFrom/groupAllowFrom, а ID группы вида -100… — ключ под channels.telegram.groups. Перепутал местами — получил «всё настроено, бот молчит».

По запросу «openclaw telegram bot not working» в выдаче одно и то же: официальная дока и её пересказы, где команды переписаны по памяти. Я держу OpenClaw, подключённый к Telegram, на боевых серверах — когда канал молчит, я узнаю об этом первым, и не из дашборда, а от людей, которым бот не ответил. Эта статья — маршрут целиком: подключить с нуля, впустить нужных людей и не впустить лишних, и разобрать типовые поломки — после апдейта, в группе, 401 по токену, рвущийся polling.

Сразу главное: это не `channels login`

В выдаче встречаются гайды, где Telegram подключают через openclaw channels login telegram. В доке на это дословно: «Telegram does not use openclaw channels login telegram; configure token in config/env, then start gateway». Токен кладётся в конфиг или в окружение, затем стартует gateway. Login-команды в этом маршруте нет вообще. Если ты полчаса дебажил, почему login «не видит» Telegram, — ты дебажил шаг, которого не существует. Кто такое советует, доку не открывал.

Подключение с нуля: четыре шага

Пара слов о том, что подключаем. Telegram-канал в OpenClaw — production-ready, личка и группы, под капотом grammY. Каналом владеет gateway-процесс, и роутинг детерминирован: что пришло из Telegram, в Telegram и вернётся — модель канал не выбирает.

Шаг 1. Бот у BotFather. В Telegram пишешь @BotFather — проверь, что handle именно такой, — команда /newbot, забираешь токен.

Шаг 2. Токен и DM-политика в конфиг:

{ channels: { telegram: {
  enabled: true, botToken: "123:abc", dmPolicy: "pairing",
  groups: { "*": { requireMention: true } },
} } }

Запасной путь — переменная окружения TELEGRAM_BOT_TOKEN=…, но она работает только для default-аккаунта, и при конфликте конфиг побеждает env. Хранишь токен в файле через tokenFile — файл должен быть обычным, симлинки не проходят. И неочевидное: после успешного старта identity бота кешируется в state-директории, по докам — до суток; смена или удаление токена этот кеш сбрасывает.

Шаг 3. Gateway и первый апрув:

openclaw gateway
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>

При дефолтной dmPolicy: "pairing" на первое сообщение боту в личку прилетает код пейринга. Код живёт час. pairing list telegram показывает, кто стучится; approve впускает. Первый одобренный пейринг заодно назначает владельца команд: проставляет commands.ownerAllowFrom, если тот ещё не задан.

Шаг 4. Группа и два ID. Чтобы бот заработал в группе, нужны два разных идентификатора, и их регулярно путают. Твой личный user ID — кто имеет право говорить с ботом — идёт в allowFrom/groupAllowFrom. ID самой группы — где боту разрешено отвечать — становится ключом под channels.telegram.groups. Отрицательный ID супергруппы вида -100… — это ID чата: его место под groups, а в groupAllowFrom его класть бесполезно.

Свой user ID проще всего подсмотреть в логах: напиши боту в личку и смотри openclaw logs --follow — в записи будет from.id. Либо спроси Bot API напрямую:

curl "https://api.telegram.org/bot<token>/getUpdates"

Кто допущен: dmPolicy и группы

dmPolicy принимает четыре значения. pairing — дефолт: каждый новый собеседник ждёт апрува. allowlist — жёсткий список, требует хотя бы один numeric ID в allowFrom. open — впускает всех и требует явного allowFrom: ["*"], чтобы бот не оказался открытым случайно. disabled — личка закрыта.

Для бота с одним хозяином я держу allowlist с numeric user ID: доступ прописан в конфиге и не зависит от того, какие пейринги были одобрены когда-то. Пейринг удобнее, когда собеседники добавляются по одному. А open — осознанный exposure; чем он оборачивается и как его резать, разобрано в гайде по безопасности OpenClaw.

У групп политика отдельная: groupPolicyopen, allowlist (дефолт) или disabled. requireMention по умолчанию true: бот отвечает, только когда его упомянули. groupAllowFrom — это numeric user ID отправителей, не ID чатов. Полезная деталь про дефолты: если секции channels.telegram в конфиге нет вовсе, рантайм сам закрывается в groupPolicy="allowlist". Fail-closed, как и должно быть.

Смежный случай, чтобы не путать: если пейринга требует не Telegram-канал, а сам gateway при подключении устройства — это другая поломка с другой механикой, я разбирал её отдельно: почему OpenClaw пишет gateway pairing required.

Перестал работать после апдейта

Самый нервный сценарий: вчера бот отвечал, сегодня обновился — тишина. Первый порыв — найти «версию, которая сломала», и в поиске гуляют запросы с конкретными номерами. Я на номер валить не буду: дело обычно не в нём, а в том, в каком состоянии обновление оставило установку.

Типовой механизм такой: после обновления канал-плагин не загрузился, потому что дерево зависимостей плагина осталось битым. Проверка и лечение — четыре команды по порядку:

openclaw status --all
openclaw doctor --fix
openclaw gateway restart
openclaw status --all

В первом выводе ищи строку plugin load failed: dependency tree corrupted; run openclaw doctor --fix. Означает ровно то, что написано: канал настроен, но загрузка плагина упала на битом dep-tree. doctor --fix выметает устаревший plugin-staging и auth-shadow, gateway restart стартует уже с чистого состояния. Второй status --all — подтвердить глазами, что канал вернулся.

Вторая пост-апдейтная ловушка тоньше, и жалуются на неё как на «сломали обновлением». В свежих версиях group-авторизация отправителя не наследует DM-пейринг: одобрение в личке больше не даёт права голоса в группах. Симптом узнаваемый: в личке бот отвечает, в группе молчит, конфиг никто не трогал. Это не бага, а security boundary: пейринг остался механикой личных сообщений. Фикс: явно задать groupAllowFrom или per-group allowFrom.

Третья: после апгрейда тебя блокирует собственный allowlist. Лечится openclaw doctor --fix либо заменой @username на numeric ID в списках.

И рефлекс, который я вынес из прод-инцидентов: «обновление прошло» и «канал жив» — два разных утверждения. После апдейта я проверяю фактическое состояние — status --all, channels status --probe — а не верю зелёному выводу инсталлера. Как строить сам процесс обновления, чтобы сюрпризов было меньше, — в гайде по обновлению OpenClaw.

Бот онлайн, но группа молчит

Если два ID разложены по местам и groupAllowFrom заполнен, а в группе всё равно тишина, — скорее всего, это вообще не OpenClaw. Боты в Telegram по умолчанию живут в Privacy Mode и видят не все сообщения группы. Выключается у BotFather: /setprivacy → Disable. Дальше шаг, который легко пропустить: бота надо удалить из группы и добавить заново, иначе Telegram смену privacy-режима не применит. Альтернатива — сделать бота админом группы.

Второй слой — requireMention: true, дефолт: бот отвечает только на упоминание. Это поведение по конфигу, а не поломка; хочешь реакции на всё подряд — меняй requireMention для конкретной группы и понимай, что делаешь.

Третий слой — снова два ID: группа ключом под channels.telegram.groups, отправители numeric-ID в groupAllowFrom, и -100… — не user ID.

`getMe returned 401`

Самая честная из ошибок: Telegram отверг токен. Не сеть, не polling, не политика доступа. Токен обрезался при копировании или отозван. Лечение одно: перекопировать или пересоздать токен у BotFather и обновить его там, где он у тебя задан, — botToken, tokenFile или TELEGRAM_BOT_TOKEN, — затем рестарт.

Здесь же прод-урок, который стоил мне времени. Токен и конфиг применяются рестартом сервиса, а не сохранением файла. «Я же поправил токен» — поправил на диске; gateway продолжает жить со старым, пока его не перезапустили. Файл правильный, процесс вчерашний. Выглядит как мистика, лечится рестартом.

Polling рвётся: сеть, 409, watchdog

Режим по умолчанию — long polling: gateway сам ходит к api.telegram.org, входящий порт не нужен, публичный адрес не нужен. Webhook опционален (webhookUrl/webhookSecret, локальный листенер 127.0.0.1:8787) — большинству установок он не требуется.

Отсюда неудобный вывод: устойчивость Telegram-канала — это устойчивость egress твоего хоста. Когда polling рвётся и реконнектится, «модель тупит» тут ни при чём — разбираться надо с сетью между машиной и api.telegram.org. Реконнект-ретраи в канале есть, но они смягчают симптом; корень остаётся в сети.

Чек-лист в том порядке, в каком ловлю сам:

  • `getUpdates` 409 conflict. На токене висит второй поллер: другой gateway, скрипт, забытая копия после переезда. Внутри одного gateway поллер на токен — один, а 409 — честный ответ Telegram, что апдейты этим токеном читает кто-то ещё. «Мигающий» после переезда инстанса бот — в моей практике это всегда он.
  • DNS/IPv6. Быстрая проверка: dig +short api.telegram.org A/AAAA. На Node 22+ вмешивается autoSelectFamily; лечится OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first либо channels.telegram.network.autoSelectFamily: false.
  • Нестабильный egress на VPS. Прокси: channels.telegram.proxy: socks5://…; стандартные HTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY тоже учитываются. Как вообще поднять и закрыть этот VPS — отдельный гайд.
  • apiRoot-грабля. getMe/setMyCommands отдают 404, а прямой curl к Bot API работает — значит, apiRoot указывает на полный /bot<TOKEN>-эндпоинт, а должен быть только корень Bot API. doctor --fix срезает хвост /bot<TOKEN> сам.

Про watchdog. Если за 120 секунд (дефолт) не завершился ни один getUpdates, polling перезапускается сам. Порог pollingStallThresholdMs крутится в диапазоне 30000–600000, но только при явно ложных срабатываниях. Устойчивый stall тюнингом порога не лечится — это глушение пожарной сигнализации; корень ищи в proxy/DNS/IPv6.

И экзотика напоследок: Telegram отклонил setMyCommands с BOT_COMMANDS_TOO_MUCH — набралось слишком много plugin/skill/custom-команд. Урезай список или отключай native-меню.

Диагностическая лесенка

Когда непонятно, откуда заходить, я иду сверху вниз, от рантайма к каналу:

openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe

Здоровый бейзлайн: Runtime: running, Connectivity probe: ok, у Telegram-канала проба показывает подключённый transport. Любое отклонение — уже зацепка: не поднялся рантайм, нет связности, канал не загрузился. logs --follow держи открытым, пока пишешь боту: там виден и from.id отправителя, и причина, по которой сообщение не прошло. Классика — /start без ответа: почти всегда это висящий пейринг (openclaw pairing list telegram покажет) или слишком строгая DM-политика.

Когда OpenClaw не виноват

Раздел, которого в выдаче не хватает. Не всё из перечисленного — грехи OpenClaw, и валить всё на рантайм — верный способ дебажить неделю не в ту сторону.

  • Privacy Mode — сторона Telegram. Бот не видит сообщения группы, потому что Telegram их по умолчанию не отдаёт. Чинится через BotFather и переприглашение бота; конфиг OpenClaw ни при чём.
  • Egress — сторона хоста. DNS, IPv6, кривой прокси уронят любой софт, который ходит к api.telegram.org с этой машины. OpenClaw просто первый, на ком это заметно.
  • Второй поллер — рукотворное. 409 — не поломка канала, а сигнал, что этим токеном уже читает апдейты кто-то ещё. Обычно — твой же забытый инстанс.

Если возиться не хочется

Всё выше — обычная операторская работа: разложить ID, одобрить пейринг, последить за egress, прогнать doctor после апдейта. Она несложная, но она не кончается. Если хочется, чтобы Telegram-канал просто был, — на это есть Cain: он держит OpenClaw на выделенном под клиента сервере, один клиент на сервер, и Telegram там привязывается из панели Assistant Control одной кнопкой: без ручного конфига, кодов пейринга и охоты за numeric ID. Запросы при этом уходят напрямую тому провайдеру модели, которому ты и так платишь, а не через чьё-то общее облако. Это один из вариантов, не единственно правильный: всё то же самое делается руками по шагам выше.

Частые вопросы

Как подключить OpenClaw к Telegram? Создать бота у @BotFather командой /newbot, положить токен в channels.telegram.botToken (или в TELEGRAM_BOT_TOKEN), задать dmPolicy, запустить openclaw gateway, затем одобрить свой первый DM: openclaw pairing approve telegram <CODE>. Через openclaw channels login telegram Telegram не подключается — доки говорят это прямым текстом.

OpenClaw Telegram-бот перестал работать после обновления — что делать? По порядку: openclaw status --allopenclaw doctor --fixopenclaw gateway restart. Частая причина — plugin load failed: dependency tree corrupted в выводе статуса: doctor --fix чистит битый plugin-staging, рестарт перегружает канал начисто.

Какая команда пейринга Telegram в OpenClaw? openclaw pairing list telegram — посмотреть ожидающие запросы, openclaw pairing approve telegram <CODE> — одобрить. Коды живут 1 час. Это не channels login.

Бот онлайн, но не отвечает в группе. Почему? Чаще всего это Telegram privacy mode: у BotFather /setprivacy → Disable, потом удалить бота из группы и добавить заново (или сделать бота админом). При requireMention бот ждёт упоминания. И проверь, что группа задана ключом в channels.telegram.groups, а твой numeric ID — в groupAllowFrom.

Что значит `getMe returned 401`? Telegram отверг токен бота. Перекопировать или пересоздать токен у BotFather, обновить botToken/tokenFile/TELEGRAM_BOT_TOKEN и перезапустить gateway: токен перечитывается рестартом, а не сохранением файла.

Polling постоянно рвётся или реконнектит. Куда смотреть? Обычно это egress хоста: DNS/IPv6/прокси до api.telegram.org. Проверка — dig +short api.telegram.org A/AAAA; лечение — ipv4first или channels.telegram.proxy. getUpdates 409 — второй поллер на том же токене. Ложные рестарты watchdog — тюнить pollingStallThresholdMs (30000–600000).

Нужен ли публичный сервер или webhook, чтобы OpenClaw работал в Telegram? Нет. Режим по умолчанию — long polling: gateway сам опрашивает Telegram, входящий порт не нужен. Webhook опционален (webhookUrl/webhookSecret) и большинству установок не требуется.

Илья Прудников держит приватные инстансы OpenClaw и Hermes. Это заметки оператора про Telegram-канал в проде, а не документация проекта; точные команды, ключи конфига и дефолты сверяй по свежим докам OpenClaw.