Команды и интерфейс бота
Как управлять aipager из Telegram. Четыре способа ввода: slash-команды, кнопки клавиатуры, панель Mini App и свободные сообщения (текст, файлы, голосовые).
Бот принимает ввод только из настроенных чатов; про границу доверия см. Модель безопасности.
Slash-команды#
Они регистрируются в aipager/bot/lifecycle.py. Меню команд Telegram их показывает и обновляется при запуске aipager и при каждом изменении сессий.
| Команда | Аргументы | Что делает |
|---|---|---|
/start | - | Главный экран: сессии этого чата, куда уходит обычное сообщение (✍️ Сообщения уходят в x1.), и 🆕 Новая сессия, ⚙️ Настройки и, когда в этом чате есть завершённая сессия, которую можно вернуть, ↩️ Продолжить. Ещё показывает постоянную клавиатуру. |
/help | - | Короткое руководство по задачам (начать, общаться, управлять, сессии, настройки и, для админов, /update) с советом, что нажатие на команду сразу её отправляет: удерживай её (телефон) или нажми Tab (компьютер), чтобы сначала дописать текст. Для владельца установки (человека из собственного личного чата установки с ботом) в нём ещё есть кнопка 🐞 Сообщить о проблеме: она открывает в этом личном чате предпросмотр точного отчёта о проблеме с кнопками Отправить, Добавить заметку и Отмена. Ничего не отправляется, пока не нажмёшь Отправить (что содержит отчёт). |
/app | - | Открывает панель Mini App (сессии, просмотр diff, настройки). |
/status | - | Сессии этого чата списком, с которым можно работать. Каждая говорит своё состояние словами (⚙️ работает 3:12 · Bash: run tests, ⏳ ждёт тебя · Bash: make deploy, 💤 готова), с ✍️ на той, куда уходят обычные сообщения, и второй строкой с моделью, контекстом, стоимостью, тем, что стоит в очереди (очередь 3 (1 в очереди, 2 заметки)), и работающими агентами и фоновыми командами. У каждой есть ряд кнопок: ✍️ x1 направляет туда твои следующие сообщения, ⏹ Остановить, пока она работает, Ответить, пока она ждёт тебя, и ⋮ для остального. Ниже: 🆕 Новая и ⚫ Завершённые (n) для сессий, которые завершились (продолжить, удалить или убрать их все из списка; они остаются в /resume). |
/stop [label] | по желанию | Прерывает текущую задачу сессии. Без имени останавливает единственную сессию этого чата, которая работает (даже если твои сообщения уходят в другую; сессия, у которой ещё работает фоновый агент или фоновая команда, считается работающей), спрашивает списком, какую, если их несколько, и пишет Сейчас ничего не работает., если ни одной. /stop x1 (или /x1 stop) останавливает x1 (или отвечает x1 сейчас ничего не делает., когда она не работает). Ещё и выбрасывает сообщения из очереди и говорит, сколько выброшено. |
/now | - | Сразу отправляет сообщения, которые Claude держит в очереди активной сессии, а не после текущего шага (собственные клавиши «отправить сейчас» у Claude Code, Ctrl+X Ctrl+S). Работает в любой момент, в том числе когда отправка в чат отключена или чат в минимальном режиме; отвечает В очереди ничего не ждёт, когда Claude ничего не держит. См. Отправить сообщение из очереди сейчас. |
/new [name] [first message] | всё по желанию | Запускает сессию. /new x1 сразу её запускает, а /new x1 fix the tests ещё и отправляет «fix the tests» первым сообщением. Отправленная сама по себе (например, нажатая в меню), /new спрашивает имя, и следующее отправленное сообщение используется ровно как аргумент, так что /new, а потом x1 fix the tests дают тот же результат. В группе ответь на карточку именем (или упомяни бота: @aipagerbot x1), потому что обычное сообщение там до бота не доходит. Только это следующее сообщение: если сначала сделать что-то другое (фото, другая команда, ответ на другое сообщение, шаблон клавиатуры, другая кнопка), это обрабатывается как обычно, и карточка закрывается; /status, /settings и меню клавиатуры оставляют её открытой. Карточка, которая спрашивает, ещё показывает режим, модель и папку, которые получит сессия, с кнопками, чтобы сначала их сменить. Все пути заканчиваются одной и той же карточкой «x1 готова»: что получила сессия, что твоё следующее сообщение уйдёт в неё, и кнопки в одно нажатие, чтобы перейти в другой режим или сменить модель. Новые сессии у всех запускаются в режиме Авто; что использует /new, меняется в /settings → Новые сессии. ! перед именем запускает сессию в режиме «Полный доступ», для админа (роли owner и admin) или человека в его собственном личном чате с ботом, чья роль может отправлять сообщения и отвечать Claude (user, не read_only); для всех остальных она запускается в режиме Авто, и карточка говорит почему. Занятое имя предлагает ↩️ Перейти к ней (когда эта сессия работает) или ♻️ Продолжить (когда она завершена), 🆕 Заменить на новую и ↩️ Отмена, только тому, кто отправил /new. Карточка, которая просит имя, устаревает через 10 минут без использования (⏱ Карточка новой сессии устарела. Отправь /new снова.). Участник, чья роль без can_manage (user, read_only), запускает сессии только внутри корневой папки чата: папка карточки это корневая папка, страница «Папка» показывает её и папки прямо внутри неё (без строки «Папка по умолчанию»), «Новая папка» создаёт папку внутри выбранной, а «Перейти к ней», «Продолжить» и «Заменить» для сессии, которая работает вне корневой папки, отклоняются («Эта сессия работает вне твоей папки ~/..., поэтому твоя роль не может её продолжить, перезапустить или сменить её режим. Попроси админа.»). |
/resume [label] | по желанию | Продолжает по имени уже завершённую сессию или открывает список. Сессия возвращается в том режиме, в котором была. Сессия, которая была в режиме «Полный доступ», возвращается в режиме «Полный доступ» только для админа или человека в его собственном личном чате; для всех остальных она возвращается в режиме Авто, и ответ это говорит (♻️ x1 снова работает, в режиме Авто: режим «Полный доступ» только для админов.). Сессия, которую более старый aipager сохранил в своём старом Auto (который работал без проверок), возвращается в режиме «Полный доступ», а сохранённая в Ask возвращается в режиме «Спрашивать». Завершённая сессия остаётся в списке GONE_SESSION_MAX_AGE_DAYS дней (по умолчанию 14), а потом уходит из списка сессий; сохранённая переписка Claude не трогается. Участник, чья роль без can_manage, не может продолжить сессию, чья папка вне корневой папки чата (владельцы и админы могут); то же самое для Перезапустить и любой смены режима, включая смену без перезапуска между режимами «Спрашивать» и Авто. |
/kill [label] | по желанию | Завершает сессию, всегда после подтверждения: ⏹ Завершить x1? Claude остановится, и сессия закончится. с [⏹ Завершить] [Отмена]. Без имени идёт к подтверждению, когда в этом чате одна работающая сессия, иначе к списку работающих сессий этого чата. Есть и в /status → ⋮ → ⏹ Завершить сессию. |
/restart [label] | по желанию | Перезапускает сессию после подтверждения: Claude останавливается и запускается снова, сохраняя переписку, в том режиме, в котором aipager последний раз её запустил или на который переключил. Сессия, запущенная в терминале через aipager session, возвращается в режиме «Спрашивать», если её режим с тех пор не меняли из Telegram (aipager не знает, в каком режиме её запустил терминал, и никогда не угадывает более свободный); то же самое при её продолжении из Telegram. |
/rename [label] [new] | по желанию | Даёт сессии новое имя (и завершённой тоже). /rename x1 newname переименовывает сразу. С меньшим числом слов спрашивает: сразу новое имя, когда команда может означать только одну сессию, иначе список (одно слово после /rename не выбирает сессию, потому что это может быть и старое имя, и новое). В группе ответь на вопрос именем. |
/delete [label] | по желанию | Убирает завершённую сессию из списка, после подтверждения. |
/diff [label] | по желанию | Показывает git diff рабочей папки сессии. Без имени показывает сессию, куда уходят твои сообщения. |
/clearqueue | - | Выбрасывает все сообщения, которые активная сессия ещё не забрала (и те, что придерживает aipager, и те, что уже в очереди внутри Claude), не прерывая идущую задачу. Отвечает, сколько выброшено. |
/mode [label] [ask|auto|full] | по желанию | Показывает режим разрешений сессии с кнопкой для перехода в каждый другой режим: ✍️ x1: 🤖 Режим Авто. [💬 Включить режим «Спрашивать»] [🔓 Включить режим «Полный доступ»]. Режимов три. 💬 Режим «Спрашивать»: Claude спрашивает перед каждым действием. 🤖 Режим Авто (по умолчанию): собственная проверка безопасности Claude Code пропускает безопасные действия и останавливает рискованные, чтобы решил ты. 🔓 Режим «Полный доступ»: всё выполняется без каких-либо проверок (--dangerously-skip-permissions); выбрать его может только админ или человек в своём собственном личном чате с ботом, чья роль может отправлять сообщения и отвечать Claude (user, не read_only). Режимы Авто и «Полный доступ» меняют только собственные запросы разрешения Claude Code: hook aipager по-прежнему применяет правила роли участника. /mode ask, /mode auto, /mode full или /mode x1 ask переключают сразу; слово самого режима на языке чата тоже работает, без слова «режим» (/mode x1 Спрашивать для 💬 Режим «Спрашивать», /mode x1 Полный для 🔓 Режим «Полный доступ»). Когда у работающей сессии в этом чате ровно такое имя (скажем, сессия demander), слово называет сессию: /mode demander показывает режим этой сессии, а /mode x1 demander по-прежнему переключает x1. ask, auto и full всегда означают режим, в любом порядке (/mode x1 ask или /mode ask x1); только когда оба слова это слова режима и только одно из них имя работающей сессии, оно называет сессию, поэтому с сессией по имени full и /mode full ask, и /mode ask full переключают её в режим «Спрашивать», а /mode full само по себе остаётся режимом. Переключение между режимами «Спрашивать» и Авто идёт без перезапуска и в любой момент (даже пока Claude работает): aipager нажимает в сессии Shift+Tab, как это делают в терминале, а карточка пишет ⚙️ x1 переходит на 🤖 Режим Авто без перезапуска., пока Claude Code не сообщит новый режим на следующем шаге, а потом показывает результат. Если режим Авто для сессии недоступен (из-за её модели или тарифа), карточка это говорит, и сессия остаётся в режиме «Спрашивать». Не тогда, когда сессия показывает вопрос или запрос разрешения: сначала ответь на него. Переход в режим «Полный доступ» требует админа (или человека в его собственном личном чате) и подтверждения и перезапускает сессию (переписка сохраняется); выход из режима «Полный доступ» тоже перезапускает её, сразу. Сессия, запущенная в режиме «Полный доступ», перезапускается при каждой смене, даже после того как её в терминале переключили на режим «Спрашивать» или Авто, и так же сессия, которая с момента запуска сообщала о режиме «Полный доступ» (терминальная сессия, запущенная с --dangerously-skip-permissions): Shift+Tab там мог бы по кругу вернуть её в режим «Полный доступ». Для работающей сессии перезапуск предлагает 🛑 Остановить и сменить / ⏳ Не сейчас. Участник, чья роль без can_manage, не может сменить режим сессии, чья папка вне корневой папки чата, ни без перезапуска, ни с ним. Нажатие на смену меняет саму карточку, а не отправляет второе сообщение. /perms это старое имя, и оно работает так же. |
/settings | - | Как выглядят и отвечают сессии этого чата: язык aipager, вид сообщений, предпросмотр изменений, обновление карточки в долгих задачах, оформление, длина ответа, уровень словаря; с чем /new запускает сессию; настройки каждой сессии; и, в личном чате владельца, предложения отчётов о проблемах. См. Настройки. В группе смотреть может любой, а менять настройку может только админ. |
/language | - | Язык, который aipager использует для своих сообщений и кнопок в этом чате (тот же список, что в первой строке /settings). Каждый язык показан своим собственным именем: English, затем Español, Русский, Português (Brasil), 简体中文 (китайский упрощённый), Français, Deutsch (немецкий), 한국어 (корейский), العربية (арабский), Bahasa Indonesia, Українська (украинский), Italiano, Türkçe (турецкий), فارسی (персидский) и Tiếng Việt (вьетнамский). Личный чат, который начинается после этой версии, следует языку твоего приложения Telegram; чат, который существовал раньше, остаётся на английском, пока ты не выберешь (см. Языки). На испанском, португальском, французском, итальянском и индонезийском слова нижней клавиатуры остаются status, stop, new и kill, как и их команды. Немецкий использует Status, Stop, Neu… и Beenden…, а турецкий Özet, Stop, Oluştur и Sonlandır; английские слова продолжают работать, если их набрать. На персидском и арабском тексты aipager читаются справа налево, с персидскими или арабскими цифрами; имена сессий, команды, названия моделей и код остаются как есть. Список говорит, что он меняет: только тексты aipager, здесь и в Mini App; твои сессии Claude не меняются, и Claude отвечает на том языке, на котором ты ему пишешь. В группе смотреть может любой, а менять может только админ. language это зарезервированное имя сессии. |
/whoami | - | Показывает, кто ты здесь: в командном режиме твоё имя, твою роль в этом чате и правила, которые она тебе даёт. |
/update | - | Только для админов (роли owner и admin или роль с can_manage). Проверяет, есть ли новые версии aipager и Claude Code, а потом одной кнопкой обновляет то, у чего они есть. См. Обновление. |
Меню / сначала показывает твои сессии (/x1 · Общаться с x1), потом частые команды: new, status, stop, now, resume, mode, settings, language, help (и app, когда Mini App включена, только в личном чате). kill, restart, rename, delete, diff, clearqueue, perms, whoami и update в меню нет, но они работают, если их набрать; действия с сессиями есть и в /status → ⋮.
Команды, которые действуют на сессию (/stop, /mode, /kill, /restart, /rename, /delete, /diff), подчиняются одному правилу:
- С именем (
/restart x1) они действуют на эту сессию этого чата (/renameдля этого нужны старое и новое имя, см. выше). - Без имени они действуют на ту единственную сессию, которую может означать команда (единственную работающую для
/stop, единственную запущенную для/killи/restart, единственную завершённую для/delete), через обычное подтверждение, если оно есть. - Иначе они показывают список только тех сессий этого чата, для которых команда имеет смысл: сначала та, куда уходят твои сообщения, с пометкой
✍️, потом остальные по имени, и✖️ Отмена. Выбор одной ведёт к той же карточке, что и набор её имени. - В группе без имени они действуют только на твою собственную текущую сессию, когда команда для неё имеет смысл; иначе всегда показывают список, даже с одной сессией, потому что она может принадлежать другому участнику (см. работа в команде).
/mode и /diff сначала смотрят на сессию, куда уходят твои сообщения.
Настройки#
/settings (и вкладка «Настройки» в Mini App, где те же варианты) задаёт, как выглядят и отвечают сессии этого чата. У каждого чата свои; в группе смотреть может любой, а менять настройку может только админ. В своём собственном личном чате их меняешь ты, какая бы у тебя ни была роль, в Telegram и в Mini App. Строка с ✅ стоит не на значении по умолчанию («Вид сообщений» всегда показывает свой выбор).
| Настройка | Варианты (по умолчанию первый) | Что делает |
|---|---|---|
| 🌐 Язык | Автоматически (язык твоего Telegram), в личном чате; English | Язык собственных сообщений и кнопок aipager в этом чате и в Mini App, показанный своим собственным именем (тот же список, что в /language). Он не меняет твои сессии Claude: Claude отвечает на том языке, на котором ты ему пишешь. Предлагаются English, Español, Русский, Português (Brasil), 简体中文 (китайский упрощённый), Français, Deutsch (немецкий), 한국어 (корейский), العربية (арабский), Bahasa Indonesia, Українська (украинский), Italiano, Türkçe (турецкий), فارسی (персидский) и Tiếng Việt (вьетнамский); «Автоматически» следует языку твоего приложения Telegram (см. Языки). |
| 🖼 Вид сообщений | Карточка + ответ отдельно; Ответ внутри карточки; Только ответ (без карточки) | Как выглядит законченная задача. «Карточка + ответ отдельно» оставляет карточку над ответом как запись того, как к нему пришли; «Ответ внутри карточки» помещает ответ в карточку; «Только ответ» убирает карточку и оставляет ответ один. По умолчанию «Карточка + ответ отдельно» (KEEP_FINISHED_CARD=0 делает «Только ответ» для чатов, которые никогда не выбирали). См. ответы. |
| 📝 Предпросмотр изменений | Выкл; Вкл | «Вкл» публикует каждый Write/Edit своим сообщением с diff под рабочей карточкой. «Выкл» оставляет одну карточку и один ответ; карточка по-прежнему перечисляет каждую правку, а в Mini App есть просмотр diff. |
| ⏱ Обновление карточки в долгих задачах | Вкл; Выкл | «Вкл»: рабочая карточка обновляется каждые 10 с после 2 минут задачи и каждые 30 с после 10 (никогда не медленнее, сколько бы ни шла задача), а её часы тогда идут шагами по 30 с; «Выкл» держит темп первых минут на всю задачу (см. решение проблем). |
| ✏️ Простое оформление | Выкл; Вкл | «Вкл» просит Claude писать только простым текстом и списками с дефисами: без таблиц, блоков кода, заголовков и жирного. |
| 📏 Длина ответа | Без правил; Очень короткий; Короткий; Средний; Длинный | Просит Claude отвечать такой длины. |
| 🎓 Уровень словаря | Без правил; Простые слова; Обычный; Продвинутый | Просит Claude такой словарь. |
| 🎨 Оформление | Кнопка «Остановить», Кнопки «Разрешить» и «Отклонить», Кнопка App, Меню «Настройки» | Как выглядят кнопки aipager в этом чате; всё начинается с «Обычный» (собственный вид Telegram). Telegram разрешает боту красить кнопку только в синий, зелёный или красный, поэтому: кнопка «Остановить» (на рабочей карточке и под вопросом или запросом разрешения) Обычный, Синий, Зелёный или Красный; «Разрешить» и «Отклонить» Обычный или цветные (зелёные «Разрешить» и «Разрешать всегда», красная «Отклонить»); кнопка App (в закреплённом сообщении и под /app) Обычный, Синий, Зелёный или Красный (кнопку меню рядом с полем ввода покрасить нельзя); меню «Настройки» Обычный (✅ отмечает текущий выбор) или ещё и текущий выбор синим. Для всего чата, не для отдельной сессии; в группе это меняет только админ. Приложения Telegram без поддержки цветов показывают все кнопки обычными. На вкладке «Настройки» в Mini App те же варианты есть в отдельном разделе «Оформление» после «Настройки чата», у каждого цветная точка. |
| 🆕 Новые сессии | Разрешения (режим), Модель, Папка | С чем /new запускает сессию, когда ты не выбираешь: режим «Спрашивать», Авто (по умолчанию) или «Полный доступ», модель из списка моделей или модель Claude Code по умолчанию, и папка. Выбрать здесь режим «Полный доступ» может только админ или человек в своём собственном личном чате с ботом (экран личного чата больше никому его не показывает), и он никогда не применяется к тому, кому им нельзя пользоваться: такие сессии запускаются в режиме Авто. |
| 👤 Настройки каждой сессии | сессия, потом любая настройка выше, кроме «Новые сессии» | Значения для одной сессии (есть и в /status → ⋮ → 👤 Настройки); ⭐ отмечает настройку, которую она переопределяет, а «Как в чате (по умолчанию)» убирает переопределение. Страница сессии в Mini App задаёт те же значения. |
| 🐞 Отчёты о проблемах | Спрашивать меня; Выкл | Только в личном чате владельца установки. «Спрашивать меня» позволяет aipager время от времени предлагать отправить отчёт о внутренней ошибке, которая случалась больше одного раза (не чаще раза в 3 дня); «Выкл» никогда не предлагает (кнопка «Сообщить о проблеме» в /help по-прежнему работает). Два отказа подряд выключают предложения, и эта строка тогда об этом говорит, с кнопкой, чтобы снова их включить. См. отчёты о проблемах. |
Длина ответа, уровень словаря и простое оформление доходят до Claude короткой инструкцией, добавленной к каждому сообщению из Telegram (через hook, см. hooks), с собственными значениями сессии, если они у неё есть.
При любом виде каждая рабочая карточка заканчивается строкой состояния своей сессии (⏳/✅ имя · …), а каждый ответ начинается своей строкой результата (💬 имя, плюс · Завершено (…), когда не осталось законченной карточки, которая показала бы цифры); вид «Ответ внутри карточки» ставит их одну над другой, каждую строку в своём разделе. Над строкой состояния рабочей карточки стоит разделительная линия (мелким шрифтом), а в виде «Ответ внутри карточки» вторая такая линия отделяет законченную карточку от ответа. В виде с карточкой ответ намеренно идёт за законченной карточкой с небольшим отставанием, чтобы было видно, как карточка говорит «Завершено», прежде чем ответ появится под ней; настрой или выключи эту фору через FINISH_CARD_GRACE_SECONDS (секунды, по умолчанию 0,8; 0 отправляет оба сразу). В виде с карточкой задача, которая не вызвала ни одного инструмента, карточки не оставляет: карточка убирается, прежде чем скажет «Готово», а первая строка ответа показывает цифры, как в виде «Только ответ (без карточки)».
Собственные команды каждой сессии#
Одна команда на каждую работающую сессию, регистрируется по её имени:
| Форма | Что делает |
|---|---|
/<label> | Делает <label> сессией, куда уходят твои сообщения. Ответ говорит об этом с её состоянием и режимом (✍️ Теперь ты общаешься с x1 · 💤 готова · 🤖 Режим Авто, потом «Напиши сообщение, и оно уйдёт в x1.»), предлагает Ответить, когда она тебя ждёт, и ⋮ Ещё для её меню. Полные цифры есть в /status. В группе он вместо этого говорит «Ответь на сообщение от x1 (или упомяни @aipagerbot), чтобы общаться с ней.», потому что обычное сообщение там до бота не доходит (см. работа в команде). /x1@aipagerbot, который Telegram отправляет, когда выбираешь /x1 в меню группы, работает так же. |
/<label> <prompt> | Отправляет <prompt> прямо в эту сессию. Она ещё и становится сессией, куда уходят твои следующие обычные сообщения. |
/<label> stop | Прерывает текущую задачу этой сессии. |
Результаты /status берутся из тех же данных, что показывает aipager status в командной строке; для самого списка сессий обращаться к Telegram не нужно.
На компьютере aipager status и aipager session ls дают каждой сессии одно состояние: IDLE, BUSY, WAITING (тебя ждёт разрешение или вопрос, с указанием, что именно, когда это известно, например permission: Bash: make deploy) или GONE. С --json у каждой сессии ещё есть waiting_kind (permission или question) и waiting_summary, оба null, если она не ждёт.
Языки#
aipager говорит на English, Español, Русский, Português (Brasil), 简体中文, Français, Deutsch, 한국어, العربية, Bahasa Indonesia, Українська, Italiano, Türkçe, فارسی и Tiếng Việt, каждый показан своим собственным именем.
- Меняются только тексты aipager. Язык относится к сообщениям, кнопкам, карточкам и Mini App у aipager. Твои сессии Claude не меняются, и Claude отвечает на том языке, на котором ты ему пишешь. Имена сессий, команды, названия моделей и код остаются как есть.
/language(или первая строка/settings) выбирает язык того чата, где ты находишься. В личном чате это ещё и твой собственный язык: его используют короткие уведомления, которые ты видишь в группе, и твоя Mini App.- Автоматически (только в личных чатах) следует языку твоего приложения Telegram и снова следует ему, если ты его меняешь. Язык, которого у aipager нет, показывается по-английски.
- Новые и старые чаты. Личный чат, который начинается после этой версии, следует языку твоего приложения Telegram, пока ты не выберешь язык, а за его первым сообщением на языке, отличном от английского, идёт одна короткая строка, которая говорит об этом и о том, как сменить. Чат, который существовал раньше, остаётся на английском. Если твоё приложение Telegram на языке, на котором говорит aipager, ты получишь одну карточку с предложением этого языка и кнопкой «Оставить английский»; она приходит один раз, каким бы ни был ответ.
- У групп один язык, его задаёт админ в
/language; до этого они на английском. Короткое уведомление после нажатия приходит на собственном языке того, кто нажал: его выбор в личном чате с ботом, иначе язык его приложения Telegram, если человек пришёл после этой версии, иначе язык группы. См. работа в команде. - Справа налево. На персидском и арабском тексты aipager читаются справа налево, с персидскими или арабскими цифрами. Рабочая карточка подстраивается под язык чата, на каком бы языке ни писал Claude: в английском чате она читается слева направо, в персидском или арабском справа налево, а фраза Claude на ней, написанная в другую сторону, всё равно читается в своём направлении. Ответ следует тексту Claude: когда Claude отвечает на персидском или арабском в чате, язык которого пишется слева направо, весь ответ становится сообщением справа налево, и собственные строки aipager в нём (агенты под ответом, а в виде «Ответ внутри карточки» законченная карточка над ним) стоят справа, как и всё остальное, но по-прежнему читаются слева направо.
- Слова режимов.
/modeпринимает слово режима на твоём языке (/mode Спрашивать), аask,autoиfullработают всегда. Если у работающей сессии ровно такое имя, слово вместо этого называет сессию (см./modeвыше). - Описание бота. При запуске aipager записывает описание бота (текст на экране пустого чата) и короткое описание на каждом из этих языков, для людей, у которых Telegram на этом языке. Telegram показывает такой текст вместо того, что написан в BotFather, поэтому aipager ничего не ставит, пока у тебя есть свой (описание и короткое описание проверяются отдельно). Он никогда не перезаписывает твой текст и никогда не меняет английский текст или текст по умолчанию. Когда его текущий текст уже стоит на всех языках, запуск ничего не спрашивает у Telegram. Иначе он сначала читает твой текст в BotFather (одно чтение для описания и одно для короткого описания): если он есть, aipager на этом останавливается, так что со своим текстом каждый запуск стоит этих чтений и не больше. Если твоего текста нет, он читает каждый язык, где ещё нет его текущего текста, поэтому язык, где в BotFather есть твой собственный текст, читается заново при каждом запуске. Если написать описание в BotFather после того, как aipager поставил своё, читатели на этих языках по-прежнему видят описание aipager (см. решение проблем).
Mini App#
/app (и кнопка меню Telegram) открывает панель, которую отдаёт сам aipager. Она включена по умолчанию; управляй ею через aipager miniapp enable|disable|status. Каждый запрос проверяется по подписи initData от Telegram (см. безопасность → туннель Mini App). Страница ничего не грузит со стороны: ни шрифтов, ни картинок, ни скриптов с других сайтов.
- Чаты. Приложение показывает один чат за раз. Если ты состоишь больше чем в одном чате (скажем, в своём личном и в группе), строка с названиями чатов вверху переключает между ними; приложение открывается на твоём собственном личном чате и запоминает твой последний выбор на этом телефоне. Всё ниже относится к выбранному чату, с твоей ролью в нём. С одним чатом строка не показывается. См. работа в команде.
- Сессии. Одна фраза подводит итог чата, например «1 ждёт тебя, 2 работают, 3 готовы», а под ней потраченная сумма. Каждая запущенная сессия это плитка с кольцом контекста, её папкой, моделью и стоимостью; работающие светятся цветом акцента. Законченные сессии лежат на сворачиваемой полке Завершённые. Кнопка + запускает новую сессию.
- Ждут тебя. Сессия, которая ждёт запрос разрешения или вопрос, стоит в янтарной полосе наверху и показывает, о чём она спрашивает. Ответить в чате снова отправляет этот запрос с его кнопками в конец чата, так же как кнопка Ответить в закреплённом сообщении, и ты отвечаешь там. Если это была единственная ожидающая сессия, приложение закрывается, чтобы запрос был прямо перед тобой; иначе оно остаётся открытым и пишет «Отправлено в чат». Для этого нужно право отправлять сообщения сессии, а копия, нажатая после того, как на запрос ответили или его заменили, пишет «уже есть ответ».
- Страница сессии. Шапка показывает кольцо контекста, состояние («Работает (3:12)», «Ждёт тебя (разрешение)», «Готова, последняя активность 5 мин назад», «Завершена») и Остановить в одно нажатие (пока она работает или ждёт) или Продолжить (когда она закончилась). Ниже: ожидающий запрос с Ответить в чате, последние вызовы инструментов полоской (нажми, чтобы увидеть полную хронологию), последний ответ, сведения, переключатель модели, собственные настройки сессии, изменённые файлы и хронология. Меню ⋮ содержит все действия, с теми же подтверждениями, что и раньше.
- Новая сессия. Пошаговая карточка: имя, потом где (с подсказками Недавние для папок, которые используют твои сессии, сначала новые), потом модель (с подсказками Советуем), потом Ещё параметры для режима разрешений и стиля ответов. Собственная кнопка Telegram внизу называется Запустить сессию. Для участника, чья роль без
can_manage, «где» предлагает только корневую папку чата и папки прямо внутри неё (корневая папка по умолчанию, а «Новая папка» создаёт внутри выбранной); папка вне её отклоняется с причиной, а «Продолжить», «Перезапустить» и смена режима сессии, которая работает вне неё, отвечают «Эта сессия работает вне твоей папки ~/..., поэтому твоя роль не может её продолжить, перезапустить или сменить её режим. Попроси админа.» - Настройки. Сначала Язык приложения: твой собственный язык для текстов aipager в приложении и в твоём личном чате (английский, испанский, русский, португальский (Бразилия), китайский (упрощённый), французский, немецкий, корейский, арабский, индонезийский, украинский, итальянский, турецкий, персидский или вьетнамский; «Автоматически» следует языку твоего приложения Telegram, см. Языки). Каждый может менять свой, он никогда не публикуется в чате и не меняет твои сессии Claude. Потом настройки чата (в группе менять их может только админ; в своём собственном личном чате можешь ты, какая бы ни была роль, так же как
/settingsтам) и, для админа, Обновления, которые повторяют/update. Для владельца в его личном чате Сообщить о проблеме открывает свою страницу: напиши заметку, проверь отчёт, отправь его и посмотри его номер, не выходя из приложения (см. отчёты о проблемах).
Приложение следует светлой или тёмной теме Telegram, когда ты её переключаешь, и останавливает свои мягкие анимации, когда телефон просит меньше движения. Всё, что есть в Mini App, доступно и из чата: меню ⋮ на панели сессии содержит те же действия.
Смена модели у работающей сессии#
На странице работающей сессии есть переключатель Модель, который показывает модель, о которой сообщает сессия (из строки состояния Claude Code), и тот же список, что предлагают выбор при запуске и клавиатура моделей в чате. Выбор одной вводит в эту сессию ровно /model <name>, тот же ввод, что использует клавиатура моделей в чате, с тем же правилом о том, кому это можно (любому, кто может отправлять сообщения сессии). Переключатель показывает переключаю…, пока строка состояния не сообщит о другой модели, а потом показывает её; если за 15 секунд ничего не изменилось, он показывает не подтверждено (проверь сессию).
- Только пока сессия готова, а не пока Claude работает или открыт запрос. Claude Code выполняет
/modelсразу, даже посреди задачи, а не после неё, поэтому смена отклоняется, пока задача не закончится. Клавиатура в чате отказывает в тех же состояниях теми же словами. - Вопрос «Switch model?» от Claude Code. Перед сменой Claude Code обычно задаёт этот вопрос, потому что следующий ответ должен перечитать всю переписку. С Claude Code 2.1.251 или новее hook
PreModelSwitchот aipager одобряет смену, которую aipager только что ввёл, поэтому вопрос не задаётся (см. hooks). Любая другая смена по-прежнему спрашивает. Со старым Claude Code или при смене наopusplanили с него вопрос всё ещё может появиться. Тогда смена показывается как не подтверждено, а вопрос ждёт в терминале. Ответь там, прежде чем отправлять сессии что-то ещё, иначе твоё следующее сообщение было бы введено в этот вопрос. По той же причине aipager отказывает в ещё одной смене этой сессии в течение минуты после неподтверждённой или пока сессия не сообщит о новой модели.
Закреплённое сообщение со статусом#
В каждом чате, где говорит aipager (твой личный чат и каждая группа), есть одно закреплённое сообщение со статусом. Полоса Telegram вверху чата показывает сообщение с его первой строки, склеивая строки подряд, поэтому эта строка говорит о том, что сильнее всего тебя ждёт:
| Первая строка | Когда |
|---|---|
⏳ jim ждёт тебя - Bash: make deploy | сессия ждёт запрос разрешения, вопрос или другой диалог; (+ещё 2 сессии), когда ждут и другие |
⚙️ jim (работает) / 💤 jim (готова) | в чате одна работающая сессия, и она работает / готова (🔄 jim (запускается), пока запускается): эта строка и есть всё закреплённое сообщение, кроме строки про лимиты |
⚙️ 2 работают · 1 готова | несколько сессий, ни одна не ждёт: сколько в каждом состоянии (работает, готова, запускается); 🔄, когда ни одна не работает, а одна запускается, 💤, когда все готовы |
💤 все готовы | нет работающих сессий |
Ниже, только пока это актуально, строка про лимиты (🐢 отправляет медленнее после предупреждения Telegram (шесть часов после 429) или ⏸ карточки пока не обновляются (часовой лимит Telegram) / (лимит Telegram) (минимальный режим, см. решение проблем)), а потом, когда в чате больше одной работающей сессии, ✍️ Сообщения идут в jim (сессия, куда уходит обычное сообщение в этом чате, см. ниже; не в группе, где у каждого своя) и по строке на сессию с её состоянием: работает, ждёт тебя, готова или запускается. Закреплённое сообщение называет каждую сессию один раз: ожидающая сессия, которую называет первая строка, своей строки не получает, а первая строка никогда не перечисляет имена, которые повторяют строки ниже. Сессия, у которой в фоне ещё работают агенты, говорит, сколько их, в своей строке (или в единственной строке, если сессия одна): 💤 jim (готова, 1 агент работает). Команды, которые Claude выполняет в фоне, считаются так же: (готова, 1 фоновая команда работает) или (готова, 2 агента и 1 фоновая команда в работе), если есть и то и другое. Это всегда число, а не их имена, поэтому строка меняется, только когда меняется число. Нажми на строку, чтобы перейти к сообщению.
Куда уходит обычное сообщение. Сообщение, которое не ответ, уходит в сессию, с которой этот чат общался последней: на которую чат последний раз переключали через /<label>, которой здесь последний раз писали, которую здесь запустили или которая последней ответила тебе здесь. Голые /mode, /clearqueue, /diff или /now действуют на эту же сессию (/stop останавливает ту, что работает). У каждого чата своя: сообщение в одном чате никогда не уходит в сессию, которая принадлежит другому чату. В группе считаются только ответ боту, сообщение с его упоминанием, команда или нажатие на клавиатуру группы (см. работа в команде), и у каждого человека свой адрес, который ответ сессии не сдвигает (см. работа в команде).
Кнопки закреплённого сообщения:
- Ответить <label> (по одной на каждую ожидающую сессию, не больше трёх) снова отправляет запрос этой сессии с его кнопками ответа в конец чата, чтобы на него можно было ответить без прокрутки. Если на него тем временем ответили, вместо этого придёт короткое уведомление «уже есть ответ», а копия (или исходный запрос), нажатая после того, как на запрос ответили где-то ещё, отклоняется так же: она никогда не отвечает на более поздний запрос. После перезапуска aipager запрос, который ждал, продолжает работать из рабочей карточки или из своего сообщения, но aipager уже не знает, какой запрос показывала более старая копия, поэтому нажатие на копию, которую закреплённое сообщение отправило до перезапуска, отклоняется с «этот запрос уже закрыт». Пользоваться ею может любой, кто может ответить на запрос; больше никто.
- 📱 App открывает Mini App, в твоём личном чате, пока Mini App включена.
В закреплённом сообщении нет часов, стоимости, % контекста и модели, поэтому оно меняется, только когда меняется состояние сессии. aipager правит его (тихо, без уведомления) только когда изменилось то, что оно показывает, не чаще раза в 30 с на чат (PINNED_MIN_EDIT_GAP); изменение внутри этого промежутка показывается, когда промежуток закончится, и никогда не теряется. Оно никогда не правится, пока отправка в чат отключена из-за блокировки, и догоняет, когда блокировка снимается.
В группе боту нужны права админа, чтобы закреплять. Если закрепить не дали, aipager удаляет только что отправленное сообщение состояния (чтобы оно никогда не висело незакреплённым в истории группы) и не показывает закреплённое сообщение в этой группе до перезапуска aipager; то же самое для чата, который вообще отказывает боту (выгнал, заблокировал). Если удалить закреплённое сообщение, aipager отправит и закрепит новое, не чаще раза в час на чат.
Постоянная клавиатура#
Под полем ввода чата есть постоянная клавиатура. Ряды сверху вниз:
| Ряд | Кнопки | Заметки |
|---|---|---|
| Сессии | по кнопке на имя каждой работающей сессии | собирается сам по списку сессий |
| Действия | статус, стоп, новая | быстрые текстовые кнопки (завершить по-прежнему работает, если его набрать; завершение сессии есть в /status → ⋮) |
| Навигация | Шаблоны, Команды | Mini App открывается кнопкой меню рядом с полем ввода или командой /app, а не с этой клавиатуры |
Модель › находится внутри подменю «Команды». Нажатие на пункт подменю отправляет готовое сообщение или slash-команду:
- Шаблоны: сообщения, которые ловишь себя на том, что набираешь снова и снова, например «Напиши тесты», «Объясни план», «Обнови память».
- Команды: slash-команды, которые понимает сам Claude Code (
/compact,/clearи т. д.), вводятся сразу. Команда или шаблон называет сессию, куда ушли (🧹 /clear отправлено в x1). Очистка переписки отклоняется, пока сессия работает (⚠️ Нельзя очистить переписку, пока сессия работает). - Модели: быстрая смена модели для активной сессии. Есть алиасы семейств (
sonnet,opus,haiku,fable,opusplan), которые всегда означают новейшую модель своего семейства, и конкретные версии моделей (claude-opus-5-5,claude-opus-5-5[1m]с окном контекста 1M,claude-sonnet-5-5,claude-fable-5-1,claude-haiku-5-5). Выбор при запуске и на странице сессии в Mini App использует тот же список. Смена отклоняется, пока сессия работает или открыт запрос. Ответ🔄потом меняется и показывает модель, о которой сообщает сессия, или говорит, что смена не подтверждена (см. Смена модели у работающей сессии).
Чтобы изменить раскладку по умолчанию, напиши ~/.config/aipager/keyboard.json:
{
"templates": [{"label": "Deploy", "prompt": "Deploy to staging"}],
"commands": [{"label": "Compact", "send": "/compact"}],
"models": [{"label": "Sonnet", "send": "/model sonnet"}]
}
Каждый раздел независим: недостающие разделы берутся из встроенных значений, так что можно поменять один, не указывая остальные. Повреждённый JSON игнорируется с предупреждением в логе. Изменения требуют перезапуска aipager.
Кнопки под каждым сообщением#
У большинства ответов бота есть кнопки под ситуацию:
Запросы разрешения#
Когда Claude хочет запустить инструмент, которому нужно одобрение, рабочая карточка становится запросом разрешения:
🔐 Bash: List the temp directory
ls -la /tmp
[✅ Разрешить] [❌ Отклонить]
[🟢 Разрешать всегда] [⏹ Остановить]
Карточка показывает настоящую команду (или путь к файлу), которую Claude хочет запустить, под его собственным описанием: одобряй то, что можешь прочитать. Символ, который изменил бы порядок, в котором рисуется текст (управляющий символ направления Unicode вроде U+202E, из-за которого одна команда может выглядеть как другая), показывается меткой вида ⟨U+202E⟩, и тогда карточка добавляет ⚠️ Здесь есть скрытые символы, меняющие направление текста (показаны как ⟨U+...⟩). Выполниться может не то, что ты видишь.
- Разрешить: одобряет этот один вызов.
- Отклонить: отклоняет его; Claude не запускает инструмент.
- Разрешать всегда: одобряет и добавляет постоянное правило, которое предлагает Claude («больше не спрашивать для …»). Кнопка появляется только когда Claude предлагает такое правило; для команды, из которой он не может вывести правило (большинство составных команд), на карточке вместо этого Разрешить / Отклонить / Остановить, как и для доступа к файлу только на чтение (
Read,Grep,Glob) вне рабочей папки сессии. Claude Code 2.1.259 и новее ставит на это место в собственном диалоге Bash строку «перейти в режим авто», в диалоге чтения вне папки строку «впредь блокировать чтение вне рабочих папок», а для Write/Edit, из которого он не может вывести правило для файла, смену режима разрешений вроде автоматического принятия всех правок файлов (acceptEdits); aipager никогда не выбирает ни одну из них; меняй режимы осознанно через/mode. - Остановить: прерывает задачу вместо ответа.
Ответ уходит в Claude Code через hook разрешений aipager, который ждёт его до 20 секунд. Запрос, пришедший раньше рабочей карточки (тогда он отправляется своим сообщением, только с Разрешить и Отклонить), отвечается так же. Когда это ожидание закончилось, кнопки вместо этого вводят ответ в собственный диалог Claude Code; Отклонить тогда выбирает последнюю строку диалога («No, and tell Claude what to do differently»), которая заканчивает задачу Claude, как Остановить, и карточка пишет 🚫 jim · Разрешение отклонено.
Каждое нажатие записывается в ~/.claude/aipager-audit.jsonl и повторяется однострочным ответом под рабочей карточкой: ✅ jim · Разрешено · @alice · Bash: List the temp directory (описание вызова или его команда, если описания нет; с чатом, настроенным через aipager config; в личном режиме просто Разрешено).
Пока тебя ждёт запрос (или AskUserQuestion), сессия показывается ожидающей, а не готовой. Если Claude Code во время этого ожидания напоминает, что ввод простаивает, чат получает ⬆️ jim · всё ещё ждёт твоего ответа выше ответом на запрос, один раз за ожидание.
Диалоги AskUserQuestion показываются так же, с кнопкой на каждый вариант (первые четыре), а для вопроса, где можно выбрать несколько ответов, с флажками ⬜/☑ и кнопкой ✅ Отправить. Вопрос и описание каждого варианта показываются целиком, как в терминале. Сокращается только форма, слишком длинная для одного сообщения Telegram: рабочая карточка сначала показывает меньше строк инструментов, а потом самые длинные из вопроса и описаний обрезаются по слову с ….
Больше одного запроса. Claude Code может ждать два запроса сразу: фоновый агент просит разрешения, пока Claude задаёт тебе вопрос, или наоборот. aipager показывает каждый из них: первый на рабочей карточке (или своим сообщением), каждый следующий своим сообщением под карточкой, со своими кнопками. Сессия показана ждущей, пока не будет ответа на последний, а сообщение, отправленное за это время, придерживается до тех пор. Отвечай в любом порядке. Разрешить и Отклонить идут через hook разрешений, пока он ждёт, и он доходит именно до этого запроса, где бы тот ни был. Нажатие, которому нужно вводить клавиши (вариант вопроса или Разрешить и Отклонить, когда hook уже не ждёт), вводит их только в тот запрос, который Claude Code показывает первым: Claude Code показывает один диалог за раз, и клавиши попадают в верхний. Иначе нажатие ничего не вводит, оставляет свои кнопки и говорит Claude Code сейчас показывает сначала другой запрос: ответь сначала на него, потом на этот. или, когда aipager не знает порядка (например, у агента, чей запуск он не видел), aipager не может понять, какой запрос Claude Code показывает первым, поэтому ответь на этот в терминале. Если на запрос карточки ответили первым, карточка показывает, что ждёт, только с кнопкой Остановить, а у остальных запросов кнопки остаются. Если Claude заканчивает задачу, пока запрос агента ещё открыт, ответ приходит как обычно, и сессия продолжает ждать этот запрос, который снова приходит своим сообщением. Перезапуск при двух и более открытых запросах не возвращает ни один: их кнопки отвечают уже есть ответ и ничего не вводят, а на запросы по-прежнему можно ответить в терминале. Один открытый запрос возвращается, как раньше.
На 80 % контекста чат получает ⚠️ name · Контекст заполнен на 82% - скоро сожмётся автоматически с 📦 Сжать сейчас, которая отправляет /compact этой сессии. Предупреждение приходит один раз за переписку: сжатие его не возвращает, а новая переписка (например, после /clear) получает его снова.
Старые кнопки#
Кнопки, которые действуют на идущую задачу (Остановить, Завершить, Перезапустить, смена /mode и её «Остановить и сменить», «Заменить» у /new), привязаны к задаче, для которой их показали. Кнопка, оставшаяся от прежней задачи, ничего не меняет, а не действует на то, что идёт сейчас, и так же кнопка, показанная до того, как сессия завершилась и её продолжили или перезапустили. Завершить, Перезапустить, смена /mode и Остановить в /status или в списке /stop отвечают x1 начала новую задачу: … с тем, что нажать или отправить снова (или Эта сессия завершена.); Остановить на рабочей карточке отвечает Эта задача уже закончилась: …, а «Остановить и сменить» у /mode превращает свою карточку обратно в карточку /mode под ⚠️ x1 начала новую задачу, поэтому ничего не изменилось. «Заменить» у /new пишет x1 тем временем начала работу. Отправь /new снова, чтобы заменить её., когда сессия начала задачу после того, как была показана её карточка.
Кнопки запроса привязаны к этому запросу. Когда на него ответили, в Telegram или в терминале, они отвечают уже есть ответ и ничего не вводят, даже пока другой запрос сессии ещё открыт.
Кнопка ⚡ Отправить сейчас действует только на то сообщение, под которым стоит: если Claude это сообщение уже забрал, нажатие отвечает Claude уже забрал его, ничего не отправляет и убирает строки очереди.
Ответы#
Когда задача заканчивается, ответ приходит так, как говорит твой вид сообщений (см. ниже и Настройки). Если ответ Claude длиннее, чем помещается в одно сообщение (около 32 КБ), сообщение показывает столько, сколько помещается под пометкой 📎 Полный ответ в файле ниже ↓, а вся задача (её шаги и полный ответ) приходит файлом <name>_full_log.md, который Telegram показывает без другого приложения. Тот же файл прикладывается, когда рабочей карточке пришлось выбросить строки.
Задача, которая заканчивается ошибкой API Anthropic (кредиты, перегрузка, лимит запросов, сеть), показывает ⚠️ name · <what went wrong> вместо ответа, с 🔄 Повторить, которая снова отправляет последнее сообщение в ту же сессию. Пока отправка в чат отключена из-за блокировки, нажатие вообще ничего не делает (сообщение не отправляется снова, кнопка остаётся), так что нажми её ещё раз, когда блокировка снимется.
В виде с карточкой («Карточка + ответ отдельно») законченная карточка остаётся над ответом как запись того, как к нему пришли: её строки инструментов, строки агентов и то, что Claude говорил между ними. Ответ приходит отдельным сообщением (с уведомлением). От задачи, которая не вызвала ни одного инструмента (ни инструмента, ни агента, ни фоновой команды, ни вопроса или запроса разрешения), осталось бы только ✅ name · Готово · Ns, поэтому её карточка убирается, пока на ней ещё «Работает», и никогда не становится «Готово», а первая строка ответа вместо неё показывает время (💬 name · Завершено (…)). Отправка тебе файла здесь не считается вызовом инструмента: файлы приходят после ответа. Задача без ответа, который можно показать, или закончившаяся ошибкой API, сохраняет свою карточку. Чтобы было одно сообщение на задачу, выбери «Ответ внутри карточки» (ответ попадает в карточку) или «Только ответ (без карточки)» (карточка убирается, и ответ стоит один).
У каждой задачи ровно одна рабочая карточка. Сообщение, которое ты отправляешь, пока идёт задача, никогда не добавляет этой задаче вторую карточку, а карточка, чья задача закончилась, больше не держит кнопку Остановить: если её ничто не закрыло (потерянный hook Stop, перезапуск), aipager закрывает её через 30 секунд так, как говорит твой вид. После перезапуска aipager карточка, чья задача ещё идёт, сохраняется и сразу продолжает тикать, отсчитывая время от начала задачи, а сессия показывается работающей до конца задачи; любая другая карточка, оставшаяся от времени до перезапуска, закрывается («aipager перезапущен», без Остановить). Сессия, которая ждала запрос разрешения или один вопрос от Claude, возвращается ожидающей, а не работающей: её карточка и закреплённое сообщение говорят, что она ждёт тебя, а кнопки запроса по-прежнему на него отвечают, если только история переписки не показывает, что на него тем временем ответили в терминале. Вопросы из нескольких частей или с несколькими вариантами и запросы от субагента остаются терминалу. Когда известно, что запрос закончен (на него ответили нажатием или в терминале, его задача закончилась, или перезапуск его не вернул, потому что на него тем временем ответили или его не удалось сохранить и прочитать обратно), его старые кнопки ответа отвечают «уже есть ответ» и ничего не вводят, даже после перезапуска. Запрос, на который никто не отвечает, остаётся открытым, пока Claude его ждёт. aipager перестаёт его ждать, только если от Claude 5 минут нет новостей и сохранённая переписка показывает, что запрос уже пройден (весть об ответе потерялась); такой запрос не считается законченным, поэтому его кнопки по-прежнему отвечают в диалоге. Считаются только новости от самого Claude и от агента, который спросил: фоновый агент, который работает сам по себе, не считается, а сохранённая переписка ничего не говорит о запросе агента: такой запрос ждёт новостей от самого этого агента.
Задача, которую Claude начинает сам (фоновый агент отчитывается через <task-notification>, когда никакая работа не открыта), получает рабочую карточку только когда что-то делает: при первом вызове инструмента или через 15 с, что раньше. Большинство таких пробуждений это несколько секунд «ничего нового»; они теперь показывают только ответ. Индикатор «печатает…» по-прежнему виден, пока она идёт, а сам ответ всегда доставляется: ничего не отфильтровывается как неважное. Задачи, которые начинаешь ты, из Telegram или из терминала, по-прежнему сразу получают карточку.
Пока сессия работает, каждый фоновый агент, которого запускает Claude (через инструмент Agent в Claude Code, Task в старых версиях), получает свою строку на рабочей карточке: 🤖 <type> · <activity> · <elapsed>, с типом агента и тем, что он сейчас делает, и она обновляется по мере его собственных вызовов инструментов. Когда этот агент сделал три вызова инструментов или больше, они сворачиваются в свою кнопку ▸ использовано N инструментов прямо под его строкой; они никогда не появляются в хронологии основной задачи и в её подсчётах Bash ×N. Когда агент заканчивает, его строка застывает в ✅ 🤖 <type> · N инструментов · <elapsed> и сохраняет ту же кнопку. Агент, которого запустил другой агент (помощник), перед своим типом называет агента на вершине своей цепочки, 🤖 pipeline-runner › ship-tester, если в момент запуска aipager знает, кто его запустил; строки остаются в том порядке, в котором запускались агенты. Файл .md выше получает раздел «Агенты» с каждым агентом, который работал в задаче, его временем, числом инструментов и инструментами, которые он использовал.
Пока фоновые агенты ещё работают после конца своей задачи, карточка остаётся и показывает состояние работы. Когда Claude тем временем забирает новое сообщение, живая карточка это та, что под этим сообщением, и она по-прежнему показывает работающих агентов. Сообщение, которое ты отправляешь в готовую сессию, начинает новую задачу: карточка прежней задачи застывает там, где стоит, с сохранёнными шагами, а новая задача получает свою карточку. Сообщение, которое стояло в очереди и было забрано, продолжает ту же задачу: его карточка отправляется заново под этим сообщением, а старая копия удаляется. Вызовы инструментов внутри агента никогда не показываются собственными строками основной задачи и никогда не заставляют aipager думать, что началась новая задача.
Команда, которую Claude выполняет в фоне (run_in_background, Ctrl+B или та, которую Claude Code переносит туда, когда она идёт слишком долго), получает свою строку, пока работает: ⏳ фоновая команда: <description> (3:12), названную по описанию вызова или иначе по первой строке команды. Когда она заканчивается, строка застывает в ✅ фоновая команда: <description> - завершена (6:12), ❌ ... - завершена с ошибкой (код выхода 1) или ⏹ ... - остановлена (6:12) (Claude остановил её через TaskStop или Claude Code остановил её из-за нехватки памяти); строки с ошибкой и остановленные сохраняют эту пометку на законченной карточке. Задача, которая заканчивается, пока такая команда ещё работает, не закончена: карточка ждёт и показывает состояние работы (🔄 name · 1 фоновая команда ещё в работе · 4:10 или 1 агент (ship-reviewer) и 1 фоновая команда ещё в работе, если есть и агент), а когда команда заканчивается, продолжение Claude идёт на той же карточке. Команды, запущенные внутри агента, принадлежат этому агенту и не показываются. Команда, конец которой aipager так и не видит (перезапуск, потерянное событие), перестаёт считаться через два часа (AIPAGER_BG_SHELL_MAX_TRACK, в секундах): её строка пишет ⏹ ... - конец не замечен, а работа, которая ждала только её, закрывается с ⚠️ name · Завершено (2:00:04, от фоновой команды нет новостей).
Когда хронология задачи становится длинной, каждый более ранний отрезок вызовов инструментов (три или больше подряд, и не тот, что идёт сейчас) сворачивается в свою кнопку ▸ использовано N инструментов прямо там, где он был, вместо того чтобы копиться целиком или обрезаться собственным лимитом длины сообщения Telegram; нажми любую, чтобы прочитать на месте. Комментарии никогда не сворачиваются; самая свежая активность и строка состояния всегда видны без нажатий. Собственная строка фонового агента, который ещё работает (или только что застыл), никогда не сворачивается сама, только её вызовы инструментов, и никогда, пока она единственное, что стоит между хронологией и лимитом. Только если хронология настолько большая, что не помещается даже со всем свёрнутым, содержимое действительно убирается из карточки; тогда полная запись есть в файле .md выше.
Агенты, которые ещё работают, когда уходит ответ#
Claude Code может запускать агентов в фоне, а задача, которая их запустила, может закончиться, пока они работают. Тогда ответ заканчивается разделительной линией и коротким состоянием этой фоновой работы, в стиле собственной панели агентов Claude Code, и оно обновляется, пока работа идёт. Всё под линией написано мелким шрифтом (подвалом Telegram), чтобы сам ответ выделялся:
⏳ В работе: 5 агентов · 🖥 В работе: 1 фоновая команда (shell)
○ 🤖 pipeline-runner · Writing final.md for the pipeline
- 🤖 ship-tester · Write and run criteria tests
- 🤖 ship-developer · Editing state.py
- 🤖 ship-developer › ship-reviewer · Collect line numbers
‖ 🤖 r2-runner · ждёт своих агентов
Когда агенты закончат, результат придёт прямо сюда.
- Первая строка считает. Агентов, которые работают (или закончили), и фоновые команды этой работы, которые идут, закончились или остановлены. Фоновая команда это всегда только число, никогда не её команда.
- По строке на агента, 🤖 и его тип жирным, потом то, что он делает сейчас: его собственная последняя строка текста (слова Claude, как они написаны, никогда не переведённые), иначе его последний инструмент короткой фразой, которая называет, над чем он работает (
Reading state.py,Writing final.md,Searching for …или собственное описание команды), иначе задача, которую Claude дал агенту при запуске, иначе просто его последний инструмент (Running a command,Using TodoWrite), иначе просто тип. Так два агента одного типа, выполняющие команды без описания, всё равно показывают каждый свою задачу. Агент, который остановился, чтобы подождать агентов, которых запустил сам, пишет вместо этого‖ … ждёт своих агентов. - Агенты деревом. Агенты, которых запустила сессия, это первый уровень. Каждый агент, которого запустил один из них, на любой глубине, стоит прямо под ним, каждый сразу после агента, который его запустил; агент, которого запустил агент второго уровня, сначала называет этого агента (
ship-developer › ship-reviewer). Рабочая карточка вместо этого называет того же агента после агента на вершине (pipeline-runner › ship-reviewer). Уровней никогда не больше двух. У работающего агента второго уровня нет своего ○: там Telegram рисует маркер списка. Агент, про которого aipager ещё не знает, кто его запустил, показывается на первом уровне, никогда не под догадкой, и переезжает под того, кто его запустил, как только это становится известно. - Не больше шести строк, сначала агенты, которые ещё работают, потом
и ещё N агентовдля агентов без строки. Агент никогда не показывается без агентов над ним. - Обещание «Когда агенты закончат, результат придёт прямо сюда.» остаётся, только пока какой-то агент ещё работает. У фоновых команд его никогда нет: сервер разработки может не закончиться никогда.
Строка каждого агента сама застывает, когда этот агент останавливается, в ✓ 🤖 Explore · готово (0:42) (сколько работал этот агент), а первая строка уменьшает счёт. Агент, которого агент из списка запускает уже после того, как ответ ушёл, попадает в состояние под ним при следующем обновлении; агент, которого позже запускает сама сессия, показывается под одним из следующих ответов. Когда все агенты закончили, строки уступают место одной строке со временем от ответа до конца последнего агента:
✅ Готово: 2 агента (6:12) · 🖥 В работе: 1 фоновая команда (shell)
а когда эта команда заканчивается, ✅ Готово: 2 агента (6:12) · Завершено: 1 фоновая команда (shell) (2:13:05) (сколько шла команда; Остановлено, когда её принудительно остановили или её остановил Claude, Завершено, когда она закончилась сама, с ошибкой или без; её строка на карточке говорит, как). Ответ, у работы которого есть только фоновая команда, показывает 🖥 В работе: 1 фоновая команда (shell), которая застывает в Завершено: 1 фоновая команда (shell) (…) или Остановлено: 1 фоновая команда (shell) (…).
Считаются только фоновые команды собственной работы ответа: сервер разработки, который оставила работать прежняя задача, не повторяется под каждым ответом (закреплённое сообщение по-прежнему считает все команды). /stop заканчивает работу, но Escape не заканчивает фоновую команду: та, что ещё идёт, остаётся в закреплённом сообщении до своего конца и больше не считается под следующими ответами; её позднейшее продолжение тогда начинает свою задачу.
Этот ответ уходит в момент, когда задача заканчивается, обычным сообщением (с уведомлением) в ответ на твоё сообщение: тот же текст, что показывает терминал. Рабочая карточка остаётся над ним как живое состояние работы, при любом виде: 🔄 name · 1 агент (general-purpose) ещё в работе · 1:18, со своей кнопкой Остановить. Когда агенты отчитываются, ответ Claude на это приходит отдельным сообщением; прежний ответ никогда не отправляется снова, даже после перезапуска aipager. Работа, чьи агенты отчитываются больше одного раза, даёт по ответу на каждый отчёт, каждый отправляется по мере написания.
Агент, который остановился, пока его собственная фоновая работа ещё идёт, считается работающим, потому что он продолжит позже. Агент, который запустил собственного агента, а потом остановился, чтобы его подождать, узнаётся по этому запуску (по его собственному вызову, который запустил другого агента): он остаётся в состоянии как работающий и держит работу открытой, пока не остановится, когда ни один из его собственных агентов уже не идёт. Если он не продолжил через две минуты после того, как закончился последний из них, он больше не считается работающим, а состояние остаётся таким, каким было показано в последний раз. <task-notification> от Claude для агента говорит то же самое в заметке; aipager читает её, когда это уведомление начинает задачу, а также когда Claude забирает его посреди идущей задачи, пока рабочая карточка на месте. Строка ждёт несколько секунд, прежде чем показаться законченной, чтобы эта заметка успела её вернуть. Состояние добавляется при любом виде, на языке чата.
Как оно обновляется. aipager правит ответ тихо, только когда изменилось то, что показывает состояние, и не чаще раза в 30 секунд на ответ (сам ответ считается первым). Каждый ответ с состоянием обновляется так (до пяти ожидающих на сессию). Правки имеют низкий приоритет: та, которую отклоняет бюджет отправки или которая пришлась бы на время, когда отправка в чат отключена, не делается, и состояние ждёт следующего изменения. Последнюю правку, когда всё закончилось, пробуют ещё раз после снятия отключения или отказа бюджета, а потом бросают. Никаких правок в удалённом ответе, для сессии, которая завершилась сама или которую завершили, или когда правка сделала бы ответ слишком длинным для Telegram (когда длинный ответ обрезается, место для состояния оставляется).
Состояние остаётся таким, каким было показано последний раз, и никогда не превращается в «готово», когда aipager не может знать, что работа закончилась:
- агент, о котором aipager ничего не слышит 30 минут (
AIPAGER_SUBAGENT_SILENCE), больше не считается работающим, но молчание это не завершение; - фоновая команда, которая идёт дольше двух часов (
AIPAGER_BG_SHELL_MAX_TRACK), а её конец не замечен, больше не считается; - перезапуск aipager забывает, какие ответы ожидают.
Перезапуск aipager сохраняет агентов, которые ещё работают, в том числе тех, что ждут своих собственных агентов: ответ, отправленный после перезапуска, перечисляет их, рабочая карточка, которую перезапуск подхватывает, снова их показывает, а их дальнейшее окончание распознаётся как обычно. Агенты, сохранённые больше чем за 30 минут до перезапуска, не возвращаются.
Ответ, придержанный из-за отключения отправки, или доставленный простым текстом после того, как отправка с оформлением не удалась, уходит без состояния, как и задача, которая заканчивается без текста ответа (только заголовок).
Подтверждение завершения#
/kill, его список и ⋮ → ⏹ Завершить сессию всегда спрашивают подтверждение:
⏹ Завершить jim? Claude остановится, и сессия закончится.
[⏹ Завершить] [Отмена]
После ⏹ Завершить сообщение пишет ⏹ jim завершена над оставшимися сессиями этого чата. Подтверждение, нажатое после того, как сессия начала новую задачу, отклоняется (jim начала новую задачу: …), как и подтверждение для сессии с тем же именем, запущенной с тех пор.
Установка голосовых (когда пакета нет)#
Когда ты отправляешь голосовое, а aipager[voice] не установлен:
⚠️ Для голосовых нужен дополнительный пакет
(около 200 МБ на установку и около 74 МБ на модель при первом использовании).
[📦 Установить голосовые] [Отмена]
Нажатие Установить запускает правильную команду установки для твоего установщика (uv tool install --reinstall aipager[voice], pipx install --force или, на крайний случай, pip install faster-whisper) с правкой сообщения каждые 5 с, а при успехе предлагает кнопку [🔄 Перезапустить aipager].
Перезапуск#
🔄 Перезапустить aipager:
- aipager, который работает как пользовательская служба systemd, планирует отсоединённый
systemctl --user restart aipager.serviceчерез 5 с (с таймером точностью 1 с), во временной службе вне группы процессов самого aipager, чтобы он пережил выход aipager. Он отказывается, пока служба завершила бы твои сессии (KillModeнеprocessи неnone), и говорит сначала запуститьaipager service install. - macOS, когда агент launchd установлен (
~/Library/LaunchAgents/com.aipager.daemon.plist):launchctl kickstart -k gui/<uid>/com.aipager.daemon, даже для aipager, запущенного тобой вручную. - Иначе aipager, запущенный тобой вручную (
aipager start), на Linux даже когда служба тоже установлена: он запускает отсоединённую замену, которая ждёт, пока завершится родительский процесс, а потом выполняет ту же команду, которой был запущен aipager (её вывод идёт в лог самоперезапуска). Текущий aipager аккуратно останавливается, как только замена запустилась.
SSH не нужен. Чтобы закончить обновление aipager, кнопка 🔄 Перезапустить сейчас на карточке обновления вместо этого перезапускает aipager на месте, в том же терминале (см. Обновление).
Обновление#
/update (только для админов; в личном режиме только для того, кто установил aipager) отвечает одной кнопкой, 🔄 Проверить обновления. Проверка идёт, только когда её нажимают. Нажатие превращает это сообщение в строку на каждый продукт:
aipager 1.0.1 → 1.1.0, когда есть версия новее (новейшая на PyPI);aipager 1.0.1 (последняя версия), когда нет;Claude Code 2.1.282 (не удалось проверить), когда проверка не удалась (нет сети, лимит в 5 с илиclaudeне найден).
Claude Code сравнивается с новейшей версией его собственного канала обновлений (autoUpdatesChannel: latest, stable или rc). Под строками мелко написано, как установлен aipager (например, pipx, from PyPI или pipx, from local path …; групповые чаты никогда не показывают пути).
Если что-то новее, есть ОДНА кнопка, которая обновляет только те продукты, у которых есть обновление: Обновить aipager, Обновить Claude Code или Обновить оба, плюс Отмена. Когда предлагается aipager, сообщение говорит и о том, как пройдёт перезапуск: Перезапуск: автоматически, когда не идёт ни одна задача., Перезапуск: после установки нажми «Перезапустить сейчас». (aipager без службы, см. ниже) или Перезапуск: вручную (причина).
Если более новый aipager уже установлен, но работает всё ещё старый (обновление, которое закончилось без перезапуска, или pip install -U вручную), строка пишет aipager 1.1.0 установлен и ждёт перезапуска (сейчас работает 1.0.1)., а сообщение предлагает 🔄 Перезапустить сейчас вместо обновления: «Обновить aipager» никогда не предлагается для версии, которой нужен только перезапуск. Установленная версия проверяется запуском интерпретатора, в который перезапустился бы aipager, поэтому версия, которая установлена, но не загружается, так и говорит (aipager 1.1.0 установлен, но не загружается. Переустанови его командой …) и ничего не предлагает. Выпуск новее установленного по-прежнему предлагается как обновление. Более новый aipager при установке, которую отсюда не обновить (editable, Nix, Snap, системный пакет, контейнер или установка другого пользователя), показывается с причиной и не предлагается. Так же и более новый Claude Code, установленный через npm в папку, куда твой пользователь не может писать (например, sudo npm install -g в /usr/lib/node_modules), где claude update может только упасть: строка пишет отсюда не обновить: installed with npm into a folder your user can't write to; run "claude install" once to switch to Claude Code's own installer, then restart aipager. Когда обновлять нечего, сообщение говорит «Всё актуально.», говорит, что одна из проверок не удалась, или, когда есть что-то новее, что отсюда не установить, «Есть обновление, но отсюда его не установить.», с кнопкой Проверить снова и без кнопки обновления.
Кнопка обновления запускает только то, что предложила проверка. Если проверке больше 10 минут, с тех пор прошло другое обновление или версии больше не совпадают с кнопкой, она вместо этого просит проверить ещё раз. Кнопки из более старого меню /update (отдельные Обновить Claude Code / Обновить aipager / Оба) отвечают «Это меню устарело: отправь /update ещё раз» и ничего не делают. Каждое нажатие заново проверяет правило про админов.
Обновление Claude Code запускает claude update (по абсолютному пути, лимит 5 мин) и сообщает Claude Code A → B, «уже последняя версия» или ошибку с концом его вывода. Работающие сессии остаются на старой версии, пока их не перезапустить (/restart); ответ их перечисляет. Ни одна сессия не перезапускается за тебя. Новые сессии используют новую версию.
Обновление aipager (Обновить aipager или вторая половина Обновить оба, которое сначала обновляет Claude Code):
- При установке с PyPI, которая уже последней версии, говорит об этом и останавливается.
- Если aipager может перезапустить себя сам, сначала ждёт, пока ничего не идёт: ни одной сессии, которая выполняет задачу, ждёт ответа на вопрос, держит работающего фонового агента, показывает живую рабочую карточку, выполняет инструмент или держит открытый запрос разрешения, и ни одного придержанного ответа, ждущего конца лимита. Сообщение перечисляет, чего оно ждёт, с Перезапустить сейчас (не ждать) и Отмена. Через 10 минут спрашивает снова: Подождать ещё 10 мин, Перезапустить сейчас, Отмена. Час без ответа, и оно отменяется само.
- Обновляет через установщик, которому принадлежит работающий aipager (
pipx upgrade aipager,uv tool upgrade aipager,brew upgrade aipagerили<venv>/bin/python -m pip install --upgrade aipager), по абсолютному пути и с лимитом в 10 мин. Пока установщик работает, отменить нельзя. - Проверяет, что новая версия загружается в свежем интерпретаторе. Обновление, которое не удалось, шло слишком долго или не загружается, ничего не перезапускает. Обновление, превысившее лимит, было остановлено посередине, поэтому сообщение предупреждает, что установка может быть неполной, и даёт команду переустановки, которую нужно выполнить до следующего перезапуска. Вывод установщика показывается только в личном чате; группа получает «(вывод в логе aipager)».
- Если за время обновления началась задача, ждёт снова.
- Планирует отсоединённый
systemctl --user restart aipager.serviceчерез 5 с (с таймером точностью 1 с), и сообщение о состоянии пишет⏳ aipager A → B установлен, перезапуск…. Пока ждёт шаг 5, оно пишет⏳ aipager A → B установлен; перезапуск, когда закончится текущая задача. После перезапуска новый aipager превращает это же сообщение в✅ aipager обновлён A → B; снова подключено N сессий(и⚠️ Не вернулись: …для каждой сессии, которая не вернулась). Если сообщение удалили или его больше нельзя править, он отправляет результат новым сообщением в чат, который спрашивал.
В Mini App Настройки → Обновления показывают «Перезапускаю aipager…» с вращающимся фонариком, пока новый aipager не ответит, потом «Обновлено до B; снова подключено N сессий.». Обратного отсчёта нет никогда. Примерно через 2 минуты без ответа (никогда раньше, чем старый aipager смог бы сообщить о перезапуске, которого не было) она пишет «Всё ещё перезапускается, открой приложение чуть позже.». С управляемым туннелем aipager перезапуск после обновления сохраняет адрес приложения (новый aipager подхватывает туннель), поэтому открытая страница переживает перезапуск и показывает «Обновлено до B». Если туннель всё-таки не удалось сохранить, примерно через 2 минуты страница пишет «Всё ещё перезапускается, открой приложение чуть позже.». Обновление, запущенное из aipager без этой возможности (или с MINIAPP_KEEP_TUNNEL=0), по-прежнему меняет адрес: как только старый aipager перестаёт отвечать, открытая страница пишет «aipager перезапустился. Открой приложение снова, когда чат сообщит об обновлении»; закрой её и открой снова через кнопку меню чата или /app. Вход в приложение действует 5 минут, поэтому страница, открытая дольше, вместо этого пишет «Открой приложение снова, чтобы увидеть результат обновления.».
После обновления aipager перезапускает себя сам, только когда работает как пользовательская служба systemd и у этой службы KillMode=process (или none). С небезопасным KillMode aipager всё равно обновляется, а сообщение пишет Нужен перезапуск: …: сначала выполни aipager service install (он перечисляет сессии, которые завершил бы перезапуск).
Перезапустить сейчас, без службы. aipager, который не перезапускает никакой менеджер служб (aipager start в терминале или tmux, Docker или агент launchd на macOS), устанавливает обновление и потом показывает Нажми «Перезапустить сейчас», чтобы запустить её (aipager подождёт, пока не останется идущих задач). с кнопкой 🔄 Перезапустить сейчас. Нажатие (только для админов, как и любая кнопка обновления):
- проверяет, что установленный aipager загружается (
⏳ Проверяю установленный aipager…); сломанная установка ничего не перезапускает, а при той же версии говорится, что перезапускать нечего; - ждёт, как и перезапуск через systemd, пока ничего не останется в работе, с кнопками Перезапустить сейчас (не ждать) и Отмена;
- ещё раз проверяет установку, потом пишет
⏳ aipager A → B установлен, перезапуск…и аккуратно останавливает aipager (как это делает Ctrl+C); - запускает новый aipager на месте: тот же процесс, та же команда, то же окружение и та же папка, в том же окне терминала или tmux (а в Docker тот же процесс контейнера). Сессии продолжают работать. Новый aipager меняет сообщение на
✅ aipager обновлён A → B; снова подключено N сессий.
Нажатия за те несколько секунд, что идёт перезапуск, теряются, как при любом перезапуске. Ctrl+C или docker stop во время перезапуска побеждает: aipager останавливается и больше не запускается. Если новый aipager не удаётся запустить на месте, отдельная копия запускает его, когда старый уже завершился (её вывод идёт в лог самоперезапуска, aipager.log в папке экземпляра или /tmp/aipager.log, а лог aipager называет команду, которую нужно выполнить, если эта копия не вернётся); если не выходит и это, или пропал сам интерпретатор, aipager завершается с кодом 1, а лог aipager пишет restart.failed: с командой, которую нужно выполнить.
Когда aipager вообще не может перезапустить себя сам, сообщение вместо кнопки даёт точные шаги для твоей установки:
- терминал или tmux:
В окне терминала или tmux, где работает aipager, нажми Ctrl+C, а потом выполни aipager start. - macOS:
На Mac выполни launchctl kickstart -k gui/<uid>/com.aipager.daemon. - Docker:
На компьютере, где работает Docker, выполни docker restart <container>.(короткий ID контейнера, если его имя хоста и есть такой ID) с напоминанием, что пересозданный из образа контейнер возвращает версию aipager из этого образа.
Перезапустить сейчас появляется и в результате Проверить обновления, когда более новый aipager установлен и ждёт, и в разовом уведомлении: когда hooks Claude Code (которые запускаются заново на каждое событие, из установленного aipager) уже работают на более новом aipager, чем запущенный, владелец получает одно тихое сообщение на каждую более новую версию и каждый запуск aipager, ⚠️ Обновление aipager сделано только наполовину: …, с этой кнопкой. Оно ждёт две минуты с момента, когда hooks впервые запустили более новую версию (перезапуск сразу после установки его никогда не показывает), а потом ждёт, пока в личном чате владельца не останется идущих задач. После перезапуска в эту версию уведомление меняется на ✅ Обновление aipager завершено: aipager теперь работает на B., без кнопки. В Mini App Настройки → Обновления показывают то же состояние строкой над карточкой, с Перезапустить сейчас (сначала спрашивает).
В Mini App Обновления это первая карточка на вкладке «Настройки»: её название, работающая версия и маленькая Проверить обновления в конце строки. Открытие вкладки «Настройки» само запускает проверку (не чаще раза в десять минут и никогда во время обновления или перезапуска aipager; неудачная проверка там ничего не пишет), а нажатие проверяет всегда. Карточка остаётся одной спокойной строкой, пока нет дела: более новая версия приносит свои строки и одну кнопку обновления, «Всё обновлено.» это одна строка без кнопки, а идущее обновление, перезапуск или Перезапустить сейчас сохраняют свои кнопки.
Одновременно идёт только одно обновление, через /update, карточку Настройки → Обновления в Mini App (та же проверка, та же одна кнопка обновления, та же работа) и aipager update в командной строке. Это включает и секунды между «установлен, перезапуск…» и самим перезапуском: /update отвечает, что aipager сейчас перезапустится, Mini App не предлагает кнопок, а Перезапустить aipager у голосовых отказывает, пока обновление идёт или ждёт перезапуска. Если через две минуты после того, как aipager запланировал свой перезапуск, он всё ещё жив, он останавливает запланированный таймер перезапуска, снимает блокировку обновления и говорит тебе перезапустить его самостоятельно.
Если aipager выключается, пока работает установщик, установщику дают 3 с на завершение, а потом останавливают (иначе он продолжил бы писать в установку, пока запускается следующий aipager). Сообщение о состоянии и после перезапуска новое сообщение говорят, что установка может быть неполной, и как её починить.
Когда выключение началось, ничего не перезапускается и ничего нового не начинается: кнопки /update отвечают, что aipager выключается, Mini App отвечает 503, и не запускается ни установщик, ни проверка версий. Установщик, который успевает закончить за свои 3 с, всё равно считается. Сообщение о состоянии говорит, что новая версия установлена и ничего не перезапущено, а следующий запуск сообщает aipager обновлён A → B. aipager, остановленный через aipager service stop, остаётся остановленным. Доля обновления в выключении занимает в сумме не больше 8 с.
Обычные сообщения#
Текст#
Считается следующим сообщением для активной сессии: адреса этого чата, сессии, на которую чат последний раз переключали, которой здесь последний раз писали, которую здесь запустили или которая последней ответила тебе здесь (см. закреплённое сообщение со статусом). В группе у каждого человека свой адрес, который ответ сессии не сдвигает (см. работа в команде). Сообщения доходят до Claude сразу, даже пока идёт твоя собственная задача, точно как ввод в терминале (в группе сообщение другого человека ждёт, пока эта задача закончится; см. ниже). Отправь несколько, и они встанут в очередь в самом Claude, который забирает каждое на естественной границе:
Реакция на твоём сообщении следует за ним, как в Claude Code ожидающее сообщение становится из серого белым:
- 👀: передано сессии (или придержано, см. ниже), но Claude его ещё не забрал. Сообщение, отправленное во время идущей задачи, остаётся 👀, пока ждёт в очереди Claude.
- 👍: Claude его забрал: начал с ним задачу, принял в идущую задачу или передал работающему фоновому агенту.
- 🤷: его никогда не заберут: придержанное сообщение, которое выбросили
/stop,/clearqueueили/killили которое не удалось отправить, когда его отпустили; сообщение или команда, которые ещё ждали, когда их выбросили/stop,/clearqueue,/killили конец сессии (не/clearи не/resume); или сообщение, которое Claude Code отверг (см. ниже). Сообщения, которые Claude уже поставил в очередь, отмечаются, только пока aipager видит эту очередь (живое чтение истории переписки работает, и не ждёт ни одна фоновая работа); иначе они остаются 👀. Escape в терминале возвращает очередь Claude в его поле ввода, откуда её можно отправить снова, поэтому сообщение, выброшенное так, тоже остаётся 👀. - 👌: команда Claude Code, которая выполнилась (см. ниже), или aipager, подтверждающий
/stop.
Реакция всегда идёт только вперёд, поэтому у сообщения не больше трёх, каждая один раз. Реакция, которая попадает на блокировку из-за лимита Telegram, пропускается, а не ставится позже, а очистка отмечает не больше десяти самых новых сообщений, которые она выбрасывает.
Кнопки команд (Сжать, /model …): нажатая, пока сессия готова, команда сразу получает 👌; Claude Code выполняет её по Enter, а локальная команда вроде /model не вызывает hook, который мог бы сказать об этом позже. Нажатая во время идущей задачи (не /model: её отклоняют до конца задачи, см. Смена модели у работающей сессии), она остаётся 👀, пока эта задача не закончится (обычно, как промежуточная остановка фоновой работы или из-за ошибки API), а потом 👌; выброшенная до этого через /stop, /clearqueue, /kill или конец сессии, она так и не выполнилась: 🤷. Если Claude Code вместо этого ставит её в очередь как сообщение, она идёт путём 👀 → 👍. Голосовое получает те же реакции, что и текст, как только его текст отправлен.
Рабочая карточка и потом ответ следуют за сообщением, которое Claude действительно забрал для задачи (тем, с которого он начал, если сессия была готова, или тем, которое он принял в идущую задачу), а не просто за последним отправленным сообщением. Ещё одно сообщение посреди задачи не «перетягивает ответ» к себе: если Claude включает его в ответ, который сейчас пишет, карточка переходит к нему в этот момент; если Claude сначала заканчивает, а потом забирает его, первый ответ остаётся под первым сообщением, а следующее получает свою задачу, со своей карточкой и ответом под ним.
Если Claude Code отвергает сообщение сразу (неизвестная slash-команда или встроенная, которая в терминале только открывает диалог), никакой hook не срабатывает, поэтому ничто не закончило бы задачу, которую aipager только что объявил. Через 8 с без единого hook (PROMPT_HOOK_GRACE_SECONDS) рабочая карточка становится ⚠️ name · Claude Code не принял сообщение с объяснением в одну строку, и сессия снова готова; причина видна в терминале, а сообщение получает 🤷 (slash-команда вместо этого получает 👌: встроенная команда, которая открывает диалог, тоже не вызывает hook). Так оценивается только сообщение, которое начало задачу; сообщение, которое ждёт за идущей задачей, остаётся 👀, пока Claude его не заберёт или его не выбросят.
Три случая придерживаются вместо отправки и доставляются сами, когда разрешатся:
- Открыт запрос разрешения или вопрос, и так всё время, пока он открыт (ограничения по времени нет): иначе твой текст прочитали бы как ответ на этот диалог. Тогда на первое твоё сообщение приходит один ответ под запросом: Claude всё ещё ждёт твоего ответа (следующие получают только 👀). Как только ты ответишь, в Telegram или в терминале, задержанные сообщения уходят Claude в том порядке, в каком были отправлены, а этот ответ удаляется. Если сессия закончится, пока запрос открыт, они отбрасываются с 🤷.
- (Командный режим) Сообщение другого человека ещё ждёт, когда его заберут.
- (Командный режим) Идёт задача другого человека, включая фонового агента, которого он запустил. Задача, набранная в терминале, считается задачей владельца, поэтому к ней присоединяется только сообщение владельца (или, в личном чате, его собственного участника).
Последние два держат сообщения разных людей вне общей задачи, чтобы каждое выполнялось с правами своего отправителя. Если какое-то всё же присоединяется (например, от отправителя, которого aipager не знает и который никогда не придерживается), задача выполняется по самым строгим правилам из всех участников (см. работа в команде). Если задачу, которую ждёт сообщение, останавливают или её прерывает заблокированный инструмент, придержанные сообщения выбрасываются с 🤷.
Придержанных сообщений не больше 50 на сессию, и они истекают через 24 ч; /clearqueue выбрасывает их вместе со всем, что держит Claude.
Отправить сообщение из очереди сейчас#
Сообщение, которое ты отправляешь, пока Claude работает над твоей собственной задачей, сразу уходит в Claude (aipager его не придерживает) и ждёт в очереди Claude, пока не закончится текущий шаг. Как только очередь Claude его показывает, aipager отвечает под ним:
⏳ В очереди: Claude прочитает его после текущего шага
[⚡ Отправить сейчас]
У каждого ожидающего сообщения своя строка, и каждая строка исчезает со своим 👍 в момент, когда Claude забирает это сообщение. Сообщение, которое Claude забирает до того, как замечена его запись в очереди, строки не получает, только 👀, а потом 👍.
Нажатие на ⚡ Отправить сейчас (или отправка /now) нажимает в этой сессии собственные клавиши «отправить сейчас» Claude Code (Ctrl+X, потом Ctrl+S). Тогда Claude читает всё, что у него в очереди, разом, а не только сообщение, под которым нажали. Что происходит с идущей работой, решает Claude Code: идущая команда или агент продолжает работать в фоне; если Claude пишет ответ, он прерывается и начинается заново с твоим сообщением. Любой другой вид шага (например, другой инструмент) тоже может быть прерван после короткой отсрочки. В некоторых случаях (например, когда фоновые задачи Claude Code выключены) «отправить сейчас» становится простым прерыванием текущего шага. Всё это собственное поведение «отправить сейчас» в Claude Code, а не решение aipager.
Нажатие отвечает Сразу отправлено Claude, и все строки исчезают разом, потому что «отправить сейчас» отдаёт Claude всё, что он держит; /now убирает их так же, и для сообщений, которые отправило «Отправить сейчас», строки не будет (у сообщения, отправленного после этого, будет своя). Если Claude прерывает текущий шаг, а не уводит его в фон, он сразу забирает только самое старое ожидающее сообщение, а остальные читает на следующем шаге; ответ приходит под сообщением, которое он забрал, и это сообщение не выполняется дважды. Если клавишам нужно больше мгновения, чтобы дойти до Claude (загруженный компьютер), нажатие вместо этого отвечает Сразу отправляю Claude; строка тогда исчезает, когда они дошли, или, если их не удалось доставить, остаётся и пишет ⏳ В очереди: нет связи с Claude, нажми «Отправить сейчас», чтобы попробовать снова, со своей кнопкой, чтобы можно было нажать снова. Клавиши нажимаются, только когда история переписки Claude показывает, что он ещё держит сообщение; иначе нажатие отвечает Claude уже забрал его и убирает строку. Отказ без нажатия клавиш бывает, пока открыт запрос разрешения или вопрос (Сначала ответь на открытый вопрос), пока Claude, возможно, только что открыл такой, который aipager ещё не показал (события новой задачи придерживаются, пока доставляется ответ прежней задачи: Занято, попробуй чуть позже), и пока aipager вводит в сессию другое сообщение (aipager сейчас вводит сообщение, попробуй чуть позже). Кнопкой и /now может пользоваться любой, кто может писать сессии; участник с read_only не может.
Строка исчезает сама, когда её сообщение покидает очередь Claude: Claude его забирает (принимает в идущую задачу, передаёт фоновому агенту или начинает с ним следующую задачу), Escape в терминале возвращает очередь в поле ввода, или его выбрасывают /stop, /clearqueue, /kill, /restart, остановка по безопасности или конец сессии. Перезапуск aipager убирает все строки, которые ещё видны.
Строки никогда не ждут управления лимитами: они уходят и убираются сразу, даже в загруженном или медленном чате и в минимальном режиме. Только пока сам Telegram заглушил чат, строки не отправляются (/now тогда по-прежнему работает), а если Telegram только что попросил aipager притормозить, строка ждёт те несколько секунд, о которых он попросил. Каждое ожидающее сообщение стоит одного вызова в чат за свою строку; строки, которые уходят вместе, убираются одним вызовом.
Файлы#
Загруженные файлы скачиваются в закрытую папку того чата, из которого они пришли, /tmp/aipager-files/<chat>/ (с именем <time>_<file name>; <chat> это имя, составленное из id чата и токена бота, по которому id чата не узнать). Читать эти папки может только пользователь, под которым работает aipager (0700, файлы 0600), а задача участника в одном чате не может читать, искать или записывать загрузки другого чата (см. безопасность). Файлы, присланные до этого изменения, остаются там, где были, прямо в /tmp/aipager-files/; ничего не переносится и не удаляется, а при запуске aipager сужает права на папку до 0700, так что добраться до них может только этот пользователь. С новым токеном бота у каждого чата появляется новая папка; загрузки, присланные до него, остаются в старых, и задача участника больше не может их прочитать. Папка для скачивания, которая оказалась символической ссылкой или принадлежит другому пользователю, отклоняется, и загрузка не удаётся. Путь предлагается Claude: с подписью сообщение это подпись, за которой идёт путь (или пути); без неё это просто check this: <path> (или check these: <paths> для альбома), так что Claude указывают на файл, не говоря, что с ним делать. Подпись, которая начинается с /<label>, выбирает сессию, точно как /<label> <prompt> у текста, а имя из сообщения убирается: /api сам по себе отправляет check this: <path> в api, а /api compare these отправляет туда compare these <paths>. Адрес выбирает только /<label> в самом начале; косая черта дальше в подписи это просто текст. Имя, на которое не откликается ни одна сессия, отклоняется с ⚠️ Нет сессии с таким именем, и ничего не отправляется. Лимит Telegram в 20 МБ на скачивание ботами применяется заранее; слишком большие файлы получают понятный отказ до попытки скачать. Скачивание, которое натыкается на временную ошибку сети, пробуется всего до трёх раз (с паузой 1 с, потом 2 с), прежде чем ты увидишь ошибку, и эта ошибка называет файл. Альбом (несколько фото или документов, отправленных одним сообщением) передаётся Claude одним сообщением (подпись, потом путь каждого файла по порядку), как только пришёл его последний элемент; если один элемент не удаётся скачать, остальные всё равно уходят с пометкой, которая называет недостающий.
Файлы, которые присылает Claude#
Claude может прислать тебе файлы из своей сессии: попроси своими словами («пришли скриншот», «пришли картинку ~/proj/chart.png»), или он пришлёт файл сам, когда решит, что он тебе нужен. Для этого он использует инструмент SendUserFile из Claude Code (Claude Code 2.1.301 или новее), который получает каждая сессия, запущенная aipager: aipager запускает её с CLAUDE_CODE_ATTACHMENTS_BY_PATH=1 и сообщает Claude, что инструмент есть. Сессия, запущенная до того, как твой aipager научился этому, получит инструмент только после перезапуска: /restart, смена режима с перезапуском или Возобновление.
- Файлы приходят после ответа задачи, ответом на него (на твоё сообщение, если у задачи нет ответа), без звука уведомления и только в чат самой сессии. Пока задача идёт, рабочая карточка показывает
📎 Отправка: 2 файла. - Каждый файл уходит по своему содержимому, а не по имени: картинка как фото, если она укладывается в лимиты Telegram для фото (не больше 10 МБ, ширина плюс высота не больше 10 000, длинная сторона не больше чем в 20 раз длиннее короткой), иначе как файл; GIF как анимация; MP4 как видео; MP3 или M4A как аудио; всё остальное как файл. Когда Claude просит обычное вложение, всё уходит как файл.
- От 2 до 10 фото и видео уходят одним альбомом; файлы идут с файлами, аудио с аудио; анимация уходит одна. Если их больше, они делятся поровну (11 уходят как 6 и 5), и ни один альбом не больше 50 МБ.
- Подпись:
💬 <session>, а подпись самого Claude идёт следующей строкой первого сообщения, не длиннее 1024 символов. - Каждый файл сначала проверяется, для всех, включая owner (безопасность): настройки aipager, учётные данные Claude, ключи и файлы, похожие на секреты, не отправляются никогда; файл должен быть обычным файлом, не пустым и не больше 50 МБ; участник отправляет только файлы из корневой папки чата. Если один файл запроса отклонён, из этого запроса не уходит ничего: Claude узнаёт причину и сообщает тебе, а задача продолжается.
- aipager отправляет личную копию, сделанную в момент, когда Claude Code прочитал файл; она хранится в
~/.local/state/aipager/outbox/и удаляется сразу после отправки или через сутки. - У aipager нет своего лимита на количество: отправка идёт в темпе лимитов Telegram, альбом считается по одному на файл. Пока чат заглушён, файлы ждут и приходят после ответа.
- Файл, который не удалось отправить, получает одну строку в чате, например
⚠️ Не удалось отправить report.pdf: Telegram не принял файл.Файл, запрос на который aipager не находит в собственной истории переписки Claude, строки не получает (безопасность). Файл, запрос на который там есть, но который aipager не может связать с идущей задачей, получает⚠️ Не удалось отправить report.pdf: aipager не смог подтвердить, что Claude отправил этот файл в рамках текущей задачи.Файлы приходят и из сообщения, которое вы отправили, пока Claude работает, и которое он берёт следующим, и из задачи, которую продолжает Stop-хук (/goal). У каждого отправленного, отклонённого или не отправленного файла есть своя запись в журнале аудита.
Голосовые#
Голосовые проходят через faster-whisper (пакет aipager[voice]). Звук превращается в текст на этом компьютере, возвращается как 🎙️ Услышано: … и вводится, как если бы его напечатали, в том числе как имя для /new или для ожидающего переименования. Голосовое больше лимита Telegram в 20 МБ на скачивание ботами отклоняется. Что происходит дальше, см. в Hooks → UserPromptSubmit.
Командная строка: все команды#
Выполни aipager <command> --help, чтобы увидеть этот же список на своём компьютере.
| Команда | Что делает |
|---|---|
aipager config | Интерактивный мастер настройки: токен бота, чаты, участники и роли, hooks Claude Code. Запусти снова, чтобы что-нибудь изменить (см. работа в команде). |
aipager setup | Та же первая настройка без вопросов, для скриптов и агентов для программирования (см. ниже). |
aipager start | Запускает aipager на переднем плане. Отказывается запускаться, пока работает другой aipager. |
aipager service install [--yes] | Устанавливает aipager как фоновую службу (пользовательская служба systemd на Linux, агент launchd на macOS) и запускает его. --yes пропускает вопрос, когда установленная служба отличается. |
aipager service start|stop|status|logs|uninstall | Запускает, останавливает или показывает службу, следит за её логом или удаляет её. |
aipager status [--json] | aipager и каждая сессия одним взглядом: состояние, модель, контекст, стоимость и состояние лимитов Telegram. |
aipager logs [-f] [-n LINES] | Лог aipager (journald на Linux, лог launchd на macOS): последние 100 строк или -n строк; -f следит за ним. |
aipager doctor [--fix] [--safety-check] [--json] | Проверки состояния (см. решение проблем). --fix предлагает починить вход в Claude и неоднозначную установку claude, спрашивая перед этим; --safety-check выводит действующие правила безопасности; --json для скриптов (см. ниже). |
aipager session <name> [claude args] | Запускает сессию Claude Code с именем <name> под dtach в текущей папке или подключается к ней, если она работает. Аргументы после имени (или после --) уходят в claude как есть, например --resume. Нужен работающий aipager. |
aipager session ls [-a] [--json] | Перечисляет сессии; -a включает завершённые. Также aipager session list. |
aipager session kill <name> [-y] | Завершает сессию после вопроса, если не указан -y. |
aipager resume [name] | Возвращает завершённую сессию с её перепиской; без имени даёт выбрать. |
aipager miniapp enable [--port PORT] [--url URL] | Включает Mini App, на 127.0.0.1:PORT (по умолчанию 8765), за управляемым туннелем или по твоему собственному https://-адресу. Действует со следующего перезапуска aipager. |
aipager miniapp disable|status | Выключает её (со следующего перезапуска) или показывает её настройки и адрес. |
aipager policy validate | Проверяет policy.yaml (и policy.d); при проблеме завершается с ненулевым кодом. |
aipager update | Обновляет aipager через установщик, которому он принадлежит (uv, pipx, Homebrew, pip). Никогда не перезапускает aipager; перезапусти его вручную или используй /update в Telegram, который это умеет (см. Обновление). |
aipager report [--note TEXT] | Показывает отчёт о проблеме и отправляет его, если ответить «да» (см. ниже). |
aipager uninstall [-y] | Останавливает и удаляет aipager и его настройки, сохраняя его данные (см. ниже). |
aipager version, aipager --version | Выводит версию. |
aipager help [command] | Справка по aipager или по команде. |
Командная строка: aipager setup (для агентов для программирования)#
Разделы выше описывают бота Telegram. Этот описывает команду, которую ты запускаешь в терминале или которую за тебя запускает скрипт или твой агент для программирования: aipager setup настраивает aipager без вопросов и даёт то же, что первый запуск aipager config.
# 1. узнать Telegram id человека (он открывает бота и нажимает Start)
aipager setup detect-chat --token-file ~/bot-token.txt --json
# 2. когда человек подтвердил, что это он, настроить aipager
aipager setup --token-file ~/bot-token.txt --chat-id 123456789 --service --json
# 3. проверить установку
aipager doctor --json
Что она делает, по порядку: читает токен бота, проверяет его в Telegram (getMe), проверяет всё на этом компьютере, ничего не записывая (существующие настройки, зависимости, ~/.claude/settings.json, работает ли aipager), отправляет человеку тестовое сообщение («aipager is set up for you. ...») и только потом записывает. Записанные файлы, ровно такие, какие пишет мастер:
~/.config/aipager/aipager.yaml(права 0600):bot_tokenи личный чат, где единственный участник этот человек (label: owner, роль owner или admin).~/.claude/settings.json: hooks aipager и statusLine (существующий файл сохраняется какsettings.json.bak.<time>, когда он меняется).- Журнал аудита получает запись
grant-owner, когда кто-то становится владельцем. - С
--serviceфоновая служба (то же, чтоaipager service install --yes). - Только при старой установке с
config.env(ещё безaipager.yaml) перенос, который делает мастер: копияconfig.env.bak.<time>(иteam.yaml.bak.<time>, если естьteam.yaml) и шаблон~/.config/aipager/policy.yaml, если его нет. Самconfig.envостаётся как есть.
Если какая-то проверка не проходит, ничего не отправляется и ничего не записывается. Если aipager уже работает, изменение чата или роли перезагружается на ходу; новый токен бота требует перезапуска (aipager service stop, потом aipager service start), который setup никогда не делает сама, а --service пропускается. Если setup не может определить, работает ли aipager, она ведёт себя так, будто работает (предупреждение daemon_unknown): тогда она никогда не устанавливает службу, поэтому никогда не может перезапустить работающий aipager, не отправляет перезагрузку после изменения и вместо этого сообщает restart_needed: true.
Параметры aipager setup#
| Параметр | Значение |
|---|---|
--token-file PATH | Читает токен бота из этого файла (не больше 4096 байт; текст вокруг токена допустим). Файл, который могут читать другие пользователи, работает, но даёт предупреждение token_file_shared: сделай ему chmod 600 или удали его, когда setup прошла. |
--token-stdin | Читает токен бота из stdin (pipe или перенаправленный файл, никогда терминал). Pipe должен закрыться: setup ждёт конца stdin не больше 30 секунд, а потом завершается с 2 и token_stdin_timeout. printf '%s\n' "$TOKEN" | aipager setup --token-stdin ... и < token.txt оба его закрывают. |
--chat-id N | Обязателен. Числовой Telegram id пользователя этого человека, он же id его личного чата. Группы добавляются через aipager config. |
--role owner|admin | Роль этого человека (по умолчанию owner). |
--service | Также устанавливает и запускает фоновую службу (пропускается, пока работает aipager). |
--force | Разрешает заменить токен бота, личный чат владельца или роль у существующей установки. Групповые чаты и другие личные чаты сохраняются. |
--dry-run | Выполняет все проверки, ничего не отправляет, ничего не записывает и сообщает, что изменилось бы. |
--json | Выводит ровно один объект JSON в stdout; всё остальное идёт в stderr. |
Укажи ровно один из --token-file и --token-stdin. Токен никогда не принимается значением параметра: --token и --bot-token отклоняются (token_on_command_line), а значение не показывается. Сокращённые параметры (--token-f, --dry) не принимаются. setup никогда не задаёт вопросов, никогда не требует терминала и никогда не читает токен из переменной окружения.
Повторный запуск с тем же токеном, чатом и ролью ничего не меняет и говорит об этом (unchanged, без тестового сообщения). Другой токен, чат или роль при существующей установке завершается с 6, пока не добавить --force. Старая установка с config.env сначала переносится, как это делает мастер (она получает роль admin, поэтому --role owner поверх неё требует --force).
aipager setup detect-chat#
aipager setup detect-chat (--token-file PATH | --token-stdin) [--timeout SECONDS] [--json]
Ждёт самое новое личное сообщение боту (нажатие «Запустить» его отправляет) и выводит его отправителя: id, имя и имя пользователя. Ничего не сохраняет, поэтому сначала покажи найденного человека и запускай aipager setup --chat-id, только когда он подтверждён. Считаются только сообщения, отправленные не раньше чем за 10 минут до запуска команды. --timeout от 0 до 3600 секунд (по умолчанию 300; 0 значит посмотреть один раз). Она читает Telegram, не подтверждая ни одного сообщения, поэтому /start остаётся доступным для мастера и для aipager.
Если работает aipager для того же бота, сообщения бота получает aipager, и он не записывает личные сообщения от людей, которые ещё не настроены. Тогда detect-chat завершается с 9 (source: "daemon"): останови aipager (aipager service stop) и запусти команду снова или спроси у человека его числовой id. С aipager для другого бота она читает Telegram напрямую (source: "telegram").
Ограничение: поскольку detect-chat никогда не подтверждает сообщения, Telegram показывает ей только 100 самых старых непрочитанных обновлений за последние 24 часа. Если у бота столько ждёт, новое /start не увидеть: detect-chat тогда завершается по лимиту времени (выход 8) с предупреждением updates_backlog, и повторное нажатие «Запустить» не поможет. Вместо этого спроси у человека его числовой Telegram id (или запусти aipager один раз, он прочитает эти обновления и очистит их).
Коды выхода#
| Код | error | Значение |
|---|---|---|
| 0 | Успех (installed, updated, unchanged, dry_run или detect-chat found). | |
| 1 | config_malformed, ambiguous_install, settings_invalid, test_send_failed, write_failed, service_failed, internal_error | Неудача. ambiguous_install: больше одного личного чата может быть чатом владельца; исправь это в aipager config. |
| 2 | usage, missing_token_source, token_source_conflict, token_file_unreadable, token_stdin_is_tty, token_stdin_timeout, token_malformed, token_on_command_line, bad_chat_id, bad_role, bad_timeout | Неверный или отсутствующий ввод; fix называет параметр. Неизвестный параметр или неверное слово после setup сообщает разборщик аргументов (простой текст, не JSON), тоже с 2. |
| 3 | deps_missing | Нет dtach, claude, aipager-hook или aipager-statusline; fix содержит команды. Ничего не записано. |
| 4 | token_rejected | Telegram отклонил токен. |
| 5 | chat_not_started, bot_blocked | Человек не нажал «Запустить» в боте («Open t.me/<bot> and press Start, then run this again.») или заблокировал его. Ничего не записано. |
| 6 | existing_install | Уже настроены другой токен, чат или роль; добавь --force. |
| 7 | telegram_unreachable | Ошибка сети, или Telegram ответил 429 или 5xx. |
| 8 | detect_timeout | detect-chat не увидела личного сообщения до --timeout (с предупреждением updates_backlog, когда 100 старых непрочитанных обновлений закрывают более новые). |
| 9 | daemon_running | detect-chat: сообщения бота получает работающий aipager. |
| 10 | updates_conflict | detect-chat: сообщения этого бота читает другая программа. |
| 130 | interrupted | Ctrl-C. |
Если несколько проверок не проходят сразу, код следует этому порядку: config_malformed, ambiguous_install, existing_install, settings_invalid, deps_missing. --dry-run завершается с кодом, который был бы у настоящего запуска по этим проверкам.
JSON: aipager setup --json#
Каждый ключ есть всегда; ещё неизвестное значение это null.
{
"command": "setup",
"status": "installed",
"ok": true,
"exit_code": 0,
"error": null,
"message": "aipager is set up for @example_bot (chat 123456789, role owner). ...",
"fix": null,
"dry_run": false,
"bot_username": "example_bot",
"chat_id": 123456789,
"role": "owner",
"changed": ["bot_token", "owner_dm", "settings_json"],
"test_message": "sent",
"deps": {"ok": true, "items": [{"name": "dtach", "found": true, "path": "/usr/bin/dtach", "fix": null}]},
"settings_json": {"path": "/home/you/.claude/settings.json", "status": "created", "backup": null, "repointed": 0},
"daemon": {"running": false, "reload": "not_needed", "restart_needed": false},
"service": {"requested": false, "result": "not_requested"},
"warnings": [],
"next_step": "Start aipager with `aipager service install` ..."
}
status:installed,updated,unchanged,dry_runилиerror.changed: что изменилось (или изменилось бы при пробном запуске), в таком порядке:migrated_v1,bot_token,owner_dm,role,settings_json,service.test_message:sent,not_needed,skipped_dry_run,failedилиnot_attempted.settings_json.status:created,patched,unchanged,would_changeилиnot_checked.daemon.reload:reloaded,refused,not_reloadedилиnot_needed.restart_neededравен true после нового токена, пока работает aipager, и после любого изменения, когда aipager не удалось перезагрузить или setup не смогла определить, работает ли он.service.result:not_requested,installed,already_installed,skipped_daemon_running,would_install,failedилиnull, когда setup остановилась раньше.warnings: объекты сcode(token_file_shared,reload_refused,daemon_unknown,audit_write_failed) иmessage.audit_write_failed: роль владельца записана, но её записьgrant-ownerне удалось добавить в журнал аудита; эта запись делается по возможности, поэтому код выхода остаётся 0.next_stepпосле изменения, пока работает aipager, которого не удалось перезагрузить, говорит его перезапустить (aipager service stop, потомaipager service start); токен бота он упоминает, только если токен изменился.- С предупреждением
daemon_unknownnext_stepникогда не говорит, что aipager работает. Он говорит, что setup не смогла это определить, отсылает кaipager doctor --jsonи говорит запустить aipager черезaipager service installилиaipager start, если он не работает. Если нужен был бы перезапуск, он просит о нём, только если aipager работает, а иначе говорит запустить его так же. - При ошибке
statusравенerror, аerror,messageиfixговорят, что пошло не так и что делать;next_stepповторяетfix. Если ошибка случилась после записи,changedперечисляет, что было записано, а обычный вывод добавляет строку в stderr:Already written: aipager.yaml, ... (changed: ...).
JSON: aipager setup detect-chat --json#
{
"command": "detect-chat",
"status": "found",
"ok": true,
"exit_code": 0,
"error": null,
"message": "Found Ada L (@ada), Telegram id 123456789.",
"fix": null,
"bot_username": "example_bot",
"source": "telegram",
"candidate": {"id": 123456789, "first_name": "Ada", "last_name": "L", "username": "ada", "date": 1700000000},
"other_candidates": 0,
"warnings": [],
"next_step": "Show this person to the user; once they confirm, run: aipager setup --token-file <path> --chat-id 123456789"
}
candidate равен null, если status не found. warnings содержит объекты с code (token_file_shared, updates_backlog) и message. other_candidates считает других людей, которые писали боту в те же 10 минут: если это не 0, убедись, что выбран нужный человек. next_step повторяет параметр токена, который был использован, но никогда сам токен.
aipager doctor --json#
Проверки aipager doctor одним объектом JSON в stdout. Как и обычный aipager doctor, он только читает и не отправляет сообщений в Telegram. Выход 1, если какая-то проверка не прошла, иначе 0. Его нельзя сочетать с --fix или --safety-check (выход 2 с объектом ошибки).
{
"command": "doctor",
"version": "1.0.1",
"ok": true,
"summary": {"ok": 14, "warn": 1, "fail": 0},
"checks": [{"key": "token_valid", "status": "ok", "title": "Telegram bot token", "detail": ["@example_bot"], "fix": null}]
}
checks идут в таком порядке, с такими ключами: config_parses, config, token_valid, chat_reachable, team, role_shell_access, peer_messages, claude, claude_auth, dtach, hook_scripts, settings_json, daemon, service_installed, service_unit_path, miniapp. Проверка, которая падает, сохраняет свой ключ со статусом warn. Тексты простые (без разметки), а всё, что похоже на токен бота, заменяется на <redacted>.
Командная строка: aipager uninstall#
aipager uninstall останавливает aipager и удаляет его службу, удаляет папку настроек (~/.config/aipager: токен бота, чаты и настройки) и список сессий (~/.claude/aipager-sessions.json), убирает файлы aipager в /tmp и удаляет сам aipager. Перед этим спрашивает (-y пропускает вопрос).
Он сохраняет данные aipager, чтобы новая установка продолжила с того же места: ~/.local/share/aipager (папки сессий, скачанные вспомогательные программы, файлы блокировок и отметок), ~/.local/state/aipager (записи для отчётов о проблемах и состояние языков), ~/.claude/aipager-audit.jsonl (журнал ответов на разрешения), ~/.claude/aipager-flood-state.json (история лимитов Telegram), ~/.claude/aipager-pending-users.json (люди, которые пробовали бота без доступа) и ~/aipager-users (корневые папки участников, с их работой). Перед вопросом он перечисляет, какие из них есть на твоём компьютере, а в конце выводит команду rm -rf, которая удаляет и их.
Ещё он убирает собственные записи aipager из ~/.claude/settings.json Claude Code: hooks, которые запускают aipager-hook, и строку состояния, которая запускает aipager-statusline (твоя собственная строка состояния остаётся). Всё остальное в этом файле остаётся как было, а файл в прежнем виде сохраняется рядом как settings.json.bak.<time>. Если файл это ссылка на другой файл, не читается, не является корректным JSON или не той формы, которую читает Claude Code, он остаётся ровно как есть, а uninstall говорит, какие записи убрать вручную. Твой собственный hook, который ещё упоминает aipager-hook или aipager-statusline (например, обёртка aipager-hook-capped.sh), тоже остаётся, и uninstall его называет. Уже открытые сессии Claude Code продолжают запускать загруженные ими hooks, пока их не перезапустить. aipager config добавляет записи снова после новой установки. Твой бот Telegram и более старые копии settings.json.bak.* не трогаются, как и skipDangerousModePermissionPrompt (настройка, которая пропускает предупреждение Claude Code перед работой без проверок разрешений): её ставит aipager, но она могла быть задана и тобой.
Командная строка: aipager report#
aipager report собирает отчёт о проблеме того же вида, что и кнопка «Сообщить о проблеме» в боте, из того, что aipager записал на этом компьютере (с меньшим числом фактов о работающем aipager: режим, чаты, функции, время работы, сессии и сведения о Claude Code остаются неизвестными или пустыми), выводит его целиком и спрашивает Send this report? [y/N]. Отправляет только y или yes; всё остальное или отсутствие терминала (скрипт, pipe, shell сессии Claude Code) ничего не отправляет. --note "text" добавляет заметку не длиннее 500 символов, которая видна в выведенном отчёте. Завершается с 0, когда отчёт отправлен, не отправлен по твоему выбору или только выведен, и с 1, когда подтверждённая отправка не ушла. Что содержит отчёт и куда он уходит, см. в Отчётах о проблемах.
Настройки из окружения#
Несколько настроек читаются из окружения aipager, а не из aipager.yaml. Для службы systemd добавь их через systemctl --user edit aipager в [Service] (Environment=STALE_BUSY_TIMEOUT=900), потом aipager service stop и aipager service start; для службы launchd на macOS добавь их в EnvironmentVariables в plist (~/Library/LaunchAgents/com.aipager.daemon.plist; aipager service install переписывает этот файл, так что потом добавь их снова); для aipager, который запускаешь вручную, задай их перед aipager start. Ни одна из них не нужна для обычной работы.
| Настройка | По умолчанию | Что меняет |
|---|---|---|
AIPAGER_WHISPER_MODEL | base | Модель распознавания для голосовых (tiny, base, small, medium, ...): больше значит точнее и медленнее. |
MINIAPP_PORT | 8765 | Порт Mini App на 127.0.0.1 (aipager miniapp enable --port вместо этого его сохраняет). |
MINIAPP_ENABLED | из aipager.yaml | 0 выключает Mini App, а 1 включает, что бы ни говорил aipager.yaml (aipager miniapp enable|disable вместо этого сохраняет выбор). |
MINIAPP_PUBLIC_URL | нет | Открывает Mini App по твоему собственному https://-адресу вместо управляемого туннеля (модель безопасности). |
KEEP_FINISHED_CARD | 1 | 0 делает «Только ответ (без карточки)» видом для чатов, которые никогда не выбирали вид в /settings. |
STALE_BUSY_TIMEOUT | 7200 (2 часа) | Сколько секунд работающая сессия может быть без новостей, прежде чем чат получит заметку «всё ещё работает (120 минут без новостей)». |
PROMPT_HOOK_GRACE_SECONDS | 8 | Секунды, после которых сообщение, которое Claude Code так и не принял, отмечается как «Claude Code не принял сообщение» (обычные сообщения). |
FINISH_CARD_GRACE_SECONDS | 0.8 | Насколько законченная карточка опережает ответ в виде с карточкой; 0 отправляет их одновременно. |
GONE_SESSION_MAX_AGE_DAYS | 14 | Сколько дней завершённая сессия остаётся в /resume; 0 хранит её всегда. |
STREAM_EDIT_INTERVAL, BUSY_EDIT_INTERVAL | 1.2, 3.0 | Обновление рабочей карточки, пока текст идёт потоком и пока она спокойна, в секундах; лимит Telegram на чат по-прежнему важнее (решение проблем). |
TYPING_INDICATOR_INTERVAL | 4.5 | Секунды между пузырями «печатает…»; 0 их выключает. |
TELEGRAM_MAX_RETRY_AFTER | 90 | Ожидание Telegram в секундах, начиная с которого aipager считает лимит блокировкой (не уменьшай; см. решение проблем). |
CLAUDE_RICH_SUMMARIES | 1 | 0 выключает богатое оформление ответов с блоками кода (обходной путь из старых версий). |
AIPAGER_INTERACTIVE_TIMEOUT | 300 | Сколько секунд запрос разрешения или вопрос может ждать без новостей от Claude Code, прежде чем aipager проверит сохранённую переписку; сессия снова считается работающей, только если она показывает, что запрос закончен (решение проблем). |
AIPAGER_SUBAGENT_SILENCE | 1800 | Секунды тишины, после которых субагент без замеченной остановки убирается (hooks). |
AIPAGER_BG_SHELL_MAX_TRACK | 7200 | Секунды, после которых фоновая команда без замеченного конца больше не считается. |
AIPAGER_REPORT_PROMPTS | включено | 0 выключает автоматические предложения отправить отчёт о проблеме (отчёты о проблемах). |
AIPAGER_CLAUDE_BIN | нет | Какой claude запускать, когда установлено несколько (claude_path в aipager.yaml важнее). |
AIPAGER_SOCKET_PATH | $XDG_RUNTIME_DIR/aipager.sock | Управляющий сокет aipager. Сессии, которые запускает aipager, передают его своим hooks. |
AIPAGER_DEBUG | выключено | 1 в окружении сессии заставляет aipager-hook и aipager-statusline выводить свою диагностику в stderr. |
AIPAGER_INSTANCE_DIR, AIPAGER_TELEGRAM_API_BASE | нет | Второй, изолированный aipager для тестов (архитектура). |
См. также#
- Архитектура: где находится бот.
- События hooks: что aipager слышит обратно от claude.
- Решение проблем: когда команды ведут себя странно.