Работа в команде и группы

По умолчанию aipager это личный бот: ты и бот в одном личном чате, больше никого. Командный режим открывает его для других людей: группа Telegram, где сессиями управляют несколько программистов, личные чаты других людей с ботом или и то и другое. У каждого чата свои участники, и у каждого участника есть роль, которая решает, что ему там можно: отправлять сообщения, отвечать на вопросы и запросы разрешения Claude, управлять сессиями или только смотреть.

Исходник на GitHub ↗Эта страница переведена с английской; если они расходятся, верна английская версия. English

По умолчанию aipager это личный бот: ты и бот в одном личном чате, больше никого. Командный режим открывает его для других людей: группа Telegram, где сессиями управляют несколько программистов, личные чаты других людей с ботом или и то и другое. У каждого чата свои участники, и у каждого участника есть роль, которая решает, что ему там можно: отправлять сообщения, отвечать на вопросы и запросы разрешения Claude, управлять сессиями или только смотреть.

Командный режим включается по желанию. Установка только с твоим личным чатом работает как раньше.

Решай осторожно#

Добавить человека из Telegram в чат значит дать ему право выполнять код на компьютере, где работает aipager. В зависимости от роли этот человек может:

  • отправлять сообщения, которые Claude превращает в команды shell, правки файлов и сетевые запросы;
  • отвечать на запросы разрешения (Разрешить / Отклонить). Твой ~/.claude/settings.json по-прежнему решает, о каких инструментах Claude спрашивает, но нажать Разрешить может любой, чья роль позволяет одобрять;
  • запускать, останавливать, завершать сессии и переключаться между ними.

Относись к списку участников так же, как к доступу по SSH к компьютеру. Журнал аудита (~/.claude/aipager-audit.jsonl) записывает, кто что сделал, но только после того, как это случилось.

Настройка#

Всё настраивается через aipager config. Править файлы вручную никогда не нужно.

Первый запуск (конфигурации ещё нет). Мастер спрашивает в четыре шага:

  1. токен бота;
  2. твой собственный личный чат с ботом (определяется сам или вставляется);
  3. является ли твой аккаунт owner (по умолчанию да; если ответить нет, будет admin, и для тебя останется включён нижний порог безопасности);
  4. он проверяет зависимости и ставит hooks Claude Code.

Он записывает твой личный чат как первый чат. Режим по умолчанию он не спрашивает: в его итоге написано «New sessions start in Auto mode; owners and admins can choose Full access in Telegram under /settings → New sessions.» (новые сессии запускаются в режиме Авто; владельцы и админы могут выбрать режим «Полный доступ» в Telegram в /settings → Новые сессии). Потом он спрашивает «Connected. Add a team group or other people now?» с Add a group, Add a person (DM) и I'm done.

Следующие запуски открывают меню изменений. Оно показывает твои чаты и предлагает:

  • Add a group scope: новая группа с её участниками (ниже).
  • Add a DM scope: собственный личный чат другого человека с ботом. В личном чате один участник; ты выбираешь его роль (по умолчанию user; выбирай owner только для установки на одного человека, например для собственного контейнера друга). Для роли без can_manage (вроде user) он потом спрашивает корневую папку, с уже подставленным значением по умолчанию (~/aipager-users/<label>). Для человека, у которого личный чат уже настроен, мастер говорит об этом и ничего не меняет: чтобы сменить роль, используй Edit a member.
  • Edit a scope: для группы Add a member; для любого чата Rename, Edit scope deny_tools, Set the members' root folder (см. Корневые папки) и Remove this scope (последний чат убрать нельзя). Завершай сессии чата, прежде чем убирать его: его работающие сессии продолжают туда писать, и ни один чат больше не может до них добраться из Telegram (с компьютера aipager session ls и aipager session kill <name> по-прежнему могут).
  • Edit a member: Set role, Edit member deny_tools, Remove member (не в личном чате и не последний участник группы). Для владельца или админа (или твоей роли с bypass_role_denies) Edit member deny_tools только сообщает, что заблокированные инструменты к этой роли не применяются.
  • Test bot reachability, View policy, Re-install Claude Code hooks и Refresh bot token.

Добавление группы#

  1. Добавь бота в группу, потом выбери Add a group scope (или Add a group при первом запуске).
  2. ID группы. Выбери автоопределение и отправь /start в группе или вставь ID (отрицательное число). Мастер отправляет тестовое сообщение и спрашивает, дошло ли оно. Группа, которая уже настроена, на этом останавливается с «This group is already set up. Use Edit a scope → Add a member.», и ничего не меняется.
  3. Название группы (показывается в мастере и в Mini App).
  4. Сначала ты. Когда ты владелец своего личного чата, мастер предлагает добавить тебя первым участником группы с ролью owner (по умолчанию да; можно пропустить). Без владельца или админа в группе там никто не смог бы пользоваться режимом «Полный доступ», /settings или /update.
  5. Остальные участники, по одному: как их найти (автоопределение или вставить ID или @handle), имя (показывается в чате как @label) и роль (по умолчанию user). В списке ролей есть owner, с предупреждением: у владельца полный контроль над этим компьютером, включая конфигурацию aipager, токен бота и учётные данные Claude. Давай её только себе. Давай admin тем, кто должен пользоваться в группе режимом «Полный доступ», /settings и /update. (В собственном личном чате с ботом любой, кто может отправлять сообщения и отвечать Claude, может пользоваться режимом «Полный доступ» для своих сессий, какая бы у него ни была роль.)
  6. Одно необязательное правило: «Block file edits (Write, Edit) for user members in this group? Admins and the owner are not affected.» (Запретить правку файлов участникам user в этой группе? Админов и владельца это не касается.) По умолчанию «нет»: user и так пишет только в папке проекта сессии. Если ответить «да», каждый Write и Edit в задаче участника, чья роль не обходит правила ролей (user, read_only и роли, которые ты задаёшь без bypass_role_denies), отклоняется без вопроса, и задача останавливается. Тогда эту работу должен отправить админ или владелец.
  7. Корневая папка участников, с уже подставленным ~/aipager-users/group-<label>: где участники группы с user и read_only запускают сессии и работают (см. Корневые папки).

Чтобы добавить кого-то в уже настроенную группу, используй Edit a scope → группа → Add a member. Все, кто уже в группе, сохраняют своё место и роль.

Как найти ID (автоопределение)#

Автоопределение участника берёт самое новое сообщение от кого-то, кто ещё не добавлен, и спрашивает «Is this the person to add?» (Это тот человек, которого нужно добавить?), прежде чем его использовать (ответь «нет», и оно будет искать дальше). В качестве имени оно предлагает имя пользователя Telegram этого человека. В группе человек должен обратиться к боту: упомянуть его или отправить /start (см. что читает бот). Мастер говорит, где он смотрит:

  • «Watching through the running daemon» (через работающий aipager): пока работает aipager start, aipager получает каждое сообщение для бота, поэтому мастер читает то, что aipager записал в ~/.claude/aipager-pending-users.json. aipager записывает, кто обращается к боту в группе, которую он ещё не обслуживает (ID, название и тип группы, а также ID, имя пользователя и имя человека), и каждого, кто не участник группы, которую он обслуживает. В группе, которую он не обслуживает, он никогда не отвечает. Личное сообщение от того, кто не настроен, получает ответ и не записывается, поэтому чтобы добавить личный чат человека, пока работает aipager, вставь его ID (или сначала останови aipager).
  • «Watching Telegram directly» (прямо в Telegram): когда aipager остановлен, мастер сам спрашивает у Telegram последние сообщения бота.

Твой собственный личный чат при первом запуске всегда читается из Telegram. Сообщение анонимного админа группы или сообщение, опубликованное от имени группы или канала, не считается: его ID отправителя (1087968824, 136817688 или 777000) одинаков у всех, кто так публикует, поэтому мастер его отклоняет, набранное или найденное. Попроси человека написать от своего аккаунта.

Где лежит конфигурация#

Мастер пишет ~/.config/aipager/aipager.yaml (права 0600): токен бота, чаты, которые обслуживает бот, и участников каждого чата с их ролями. Что может каждая роль, лежит в ~/.config/aipager/policy.yaml, и это твой файл: мастер его никогда не пишет (см. Как работают правила). Установки, настроенные в старом формате team.yaml, переносятся автоматически: aipager при запуске или мастер при следующем запуске.

Перезагрузка без перезапуска#

После каждого изменения чатов или участников из меню изменений (добавить или убрать группу или личный чат, добавить или убрать участника, задать роль, изменить deny_tools, переименовать чат), а также после группы или человека, добавленных в конце первого запуска, или недоделанной группы, которую ты продолжаешь (одна перезагрузка на всё добавленное там), aipager config отправляет работающему aipager перезагрузку на лету (SIGUSR1) и пишет «Scopes reloaded live (no daemon restart needed)». Перезагрузка заново читает aipager.yaml и policy.yaml. Если конфигурация на диске была бы отклонена, мастер пишет «Not applied» с причиной, и aipager держит прежнюю конфигурацию, пока ты не исправишь. Если мастер не может точно сказать, какой процесс это aipager, он говорит перезапустить его.

Что перезагрузка применяет сразу:

  • кто может пользоваться ботом в каждом чате, с какой ролью и какими правилами;
  • новая группа или новый личный чат начинает получать сообщения и получает своё меню /; убранный перестаёт (его сессии продолжают работать, пока ты их не завершишь);
  • придержанное сообщение (то, что ждёт ответа на запрос или конца чужой задачи) от человека, которому больше нельзя писать в этом чате, выбрасывается: оно получает 🤷, а бот отвечает «Не отправлено Claude: @bob больше не может писать здесь.»;
  • идущая задача человека, которого убрали или который потерял права, до конца задачи сохраняет только самое строгое из своих старых правил и новых (для убранного человека ограниченный порог). Задача, набранная в терминале, не меняется, если только к ней не присоединилось сообщение из Telegram: aipager не записывает, от кого, поэтому такая задача сужается, когда права теряет любой владелец этого чата (или, в личном чате, его участник). Задача, которая уже шла, когда aipager перезапустился (ещё работает или ждёт вопроса или разрешения), сужается для каждого участника её чата, который потерял права. Повышение никогда не расширяет идущую задачу: новые права действуют со следующей задачи этого человека.

Перезапуска требует только новый токен бота (aipager config говорит об этом после Refresh bot token). Когда aipager не работает, перезагрузка не отправляется: следующий aipager start прочитает новую конфигурацию.

Чтобы перезагрузить вручную (например, после правки policy.yaml), отправь сигнал только процессу aipager. Под фоновой службой:

sh
pid=$(systemctl --user show -p MainPID --value aipager.service)
[ "${pid:-0}" -gt 0 ] && kill -USR1 "$pid"

(Проверка важна: когда служба не работает, MainPID равен 0, и kill -USR1 0 отправил бы сигнал процессам твоего собственного shell.)

Для aipager, запущенного тобой через aipager start, отправь kill -USR1 <pid> этому процессу. Не отправляй сигнал всему, что находит pgrep -f 'aipager start' (shell или контейнер, в котором работает aipager, тоже совпадёт, а SIGUSR1 останавливает процесс, который его не обрабатывает), и не используй systemctl --user kill без --kill-whom=main (сессии службы в её группе и были бы остановлены).

Если в момент перезагрузки aipager.yaml или policy.yaml повреждён или aipager.yaml отсутствует, aipager пишет в лог предупреждение и держит прежнюю конфигурацию в памяти. Опечатка или убранный в сторону файл не могут ни запереть тебя снаружи, ни впустить кого-то: перезагрузка никогда не возвращает aipager с настроенными чатами в личный режим (это делает только перезапуск).

Права админа у бота и режим приватности#

Сделай бота админом группы с правом закреплять сообщения. Это нужно ему, чтобы закрепить в группе сообщение со статусом (см. Что видят все). Без этого группа работает, но закреплённого сообщения со статусом у неё нет; если дать боту это право позже, перезапусти aipager, чтобы оно появилось.

Бот, который админ группы, получает каждое сообщение в группе, какой бы ни был его режим приватности в BotFather. Это безопасно: aipager обрабатывает только сообщения, перечисленные в разделе что читает бот, а остальные игнорирует, поэтому разговоры в группе никогда не попадают в сессию. Бот, который не админ, по умолчанию в режиме приватности (оставь его включённым), и тогда Telegram передаёт ему только некоторые сообщения группы; если какое-то твоё не дошло, ответь на одно из сообщений бота или используй команду. Настройка приватности ничего не меняет в том, что обрабатывает aipager.

Быть админом группы в Telegram ничего не даёт человеку в aipager. Что кому можно, определяет только роль в aipager.yaml.

Когда Telegram обновляет группу#

Telegram превращает обычную группу в супергруппу, когда её делают публичной, включают темы, переходят за 200 участников или меняют некоторые права админов, и это обновление даёт группе новый ID чата. aipager следует за ним сам: когда он видит обновление (уведомление Telegram в группе или первую отправку на старый ID), он переносит запись группы в aipager.yaml на новый ID, переносит с ней сессии, адреса сообщений и /settings группы и пишет в группу одну строку: «Telegram обновил эту группу. aipager переехал вместе с ней, ничего делать не нужно.» Закреплённое сообщение со статусом начинается заново в обновлённой группе. В логе aipager есть предупреждение с обоими ID.

Имена сессий внутри aipager сохраняют старый ID (ты их никогда не видишь), а aipager.yaml хранит короткую запись chat_migrations о переезде, чтобы сессия, запущенная до обновления, по-прежнему принадлежала обновлённой группе, даже после перезапуска. Внутреннее имя сессии со старым ID (/name__g<old id>) работает в обновлённой группе и больше нигде. Если aipager был остановлен во время обновления, он заметит его при следующем запуске. Задача, которая идёт в момент обновления, заканчивается, и её ответ доходит до обновлённой группы, но её рабочая карточка до конца этой задачи больше не показывается. Если новый ID уже отдельный чат в конфигурации, ничего не переносится, и лог об этом говорит; убери один из двух через aipager config. «Test bot reachability» в aipager config показывает новый ID, когда встречает обновлённую группу.

При каждом запуске aipager один раз проверяет каждую группу. Если Telegram отвечает, что группа не найдена или бот не может ею пользоваться (группу удалили, бота убрали или группу обновили, пока aipager был остановлен, а Telegram не сказал, на какой ID), в логе aipager есть одно предупреждение с названием чата: проверь, что бот всё ещё в группе, и если её обновили, снова добавь группу в aipager config через Add a group scope (она получит новый ID; добавь её участников заново), потом убери старую через Edit a scope → Remove this scope (старый ID больше не работает). aipager ничего не публикует и не пытается снова.

Темы форума не поддерживаются#

Используй одну обычную группу (без тем) на команду. В группе с включёнными темами aipager всё равно работает, но не держится темы:

  • ответ на команду или сообщение (например, /status или ответ на «Какая сессия?») остаётся в той теме, где его отправили;
  • уведомления, рабочие карточки, ответы, запросы разрешения и закреплённое сообщение со статусом публикуются в группу без темы, поэтому могут оказаться в General;
  • у каждого человека одна текущая сессия на всю группу, а не по одной на тему.

Включение тем ещё и превращает обычную группу в супергруппу, за чем aipager следует (выше).

Роли#

Четыре встроенные роли (см. aipager/safety.py). Считается роль человека в том чате, где он действует. Никто не может менять участников или роли из Telegram или Mini App: это делает только aipager config на компьютере, и так это остаётся за владельцем.

owneradminuserread_only
Отправлять сообщения (can_prompt)✅✅✅❌
Отвечать Claude: Разрешить, Отклонить, вопросы (can_approve)✅✅✅❌
Управлять: режим «Полный доступ», /settings группы, /update, установка голосовых (can_manage)✅✅❌ (режим «Полный доступ»: ✅ в своём личном чате)❌
Менять участников и роли из Telegram или Mini App❌❌❌❌
Обходит правила запрета роли (bypass_role_denies)✅✅❌❌
Обходит нижний порог безопасности (bypass_safety)✅❌❌❌
Bash и другие инструменты, выполняющие код✅✅ (правила в меру возможного)❌❌
Любая slash-команда✅✅только команды клавиатуры «Команды», /compact и смена моделикак user
Где запускаются сессии (/new, Продолжить, Перезапустить, смена режима)где угодногде угоднотолько внутри корневой папки чатакак user
Куда попадает запись файловкуда угоднокуда позволяет порог безопасностипапка проекта сессии (когда она внутри корневой папки) и её scratchpad, никогда не домашняя папкакак user
Чтение в твоей домашней папкегде позволяет порог безопасностигде позволяет порог безопасноститолько внутри корневой папки (другие папки компьютера как раньше, корневые папки других участников никогда)как user
Файлы учётных данных (~/.ssh, ~/.git-credentials, ...)читаютсячитаютсяникогда (по умолчанию)никогда (по умолчанию)
Grep/Globгде угодногде угодно, кроме защищённых папок aipager (не в папке, которая ею является, лежит в ней или содержит её)папка проекта сессии и её scratchpadкак user
  • owner: полный контроль, включая встроенный порог безопасности. Владелец должен быть ровно один: человек, который управляет компьютером.

  • admin: всё, что владелец может в Telegram и Mini App: переводить сессии в режим «Полный доступ» (и запускать в нём), продолжать сессию в режиме «Полный доступ», менять /settings группы, запускать /update, ставить поддержку голосовых, отправлять любую slash-команду. Админ ещё и обходит правила запрета роли (deny_tools чата и участника к админам не применяются). Две вещи остаются за владельцем:

    • менять участников и роли: это делает только aipager config на компьютере, и ничто в Telegram или Mini App этого не может;
    • обходить порог безопасности (конфигурация и токен бота aipager, учётные данные Claude Code, управляющие файлы aipager). Grep и Glob админа могут искать где угодно ещё, но не в папке, которая одна из этих, лежит внутри одной из них или содержит одну из них: Grep по ~, / или /tmp (или без папки из сессии в домашней папке) отклоняется, как и Glob, чей шаблон начинается в одной из них (вроде /home/you/.config/aipager/*). Ищи вместо этого внутри папки проекта. В версиях Claude Code без инструмента Grep Claude ищет через Bash; там тоже отклоняется рекурсивный поиск или перечисление всей домашней папки или / (grep -rn x ~, rg x $HOME, find / -name x), в меру возможного (поиск без папки или с .., запущенный из домашней папки или ниже, не виден), а поиск по проектам нет, включая поиск самого домашнего пути (grep -rn "$HOME" src) (безопасность).

    У админа остаётся Bash, а с shell шаблоны команд порога работают в меру возможного, это не граница: делай человека админом, только если ему можно доверить shell на этом компьютере.

  • user: правила запрета действуют. Никакого Bash и никакого другого инструмента, выполняющего код (PowerShell, Monitor, запланированные сообщения, workflows; список это safety.CODE_EXECUTION_TOOLS), никакого SendMessage другим сессиям, никакой смены worktree. Файлы пишутся только в папку сессии и её scratchpad Claude Code и никогда в .claude/, .git/ или .mcp.json этой папки (каждый из них запускает команды). Grep и Glob ищут только в этих папках, с простыми относительными glob. user запускает, продолжает, перезапускает и переключает сессии только внутри корневой папки чата и не читает ничего в твоей домашней папке вне её. Папка сессии, которая твоя домашняя папка, / или папка выше, или которая лежит вне корневой папки (сессия, запущенная до корневых папок или кем-то другим), не считается: там user может писать и искать только в scratchpad. Чтение подчиняется правилам защищённых путей, а твои файлы учётных данных никогда не читаются: ~/.ssh, ~/.gnupg, ~/.aws, ~/.config/gh, ~/.git-credentials, ~/.netrc, ~/.docker/config.json, ~/.kube, ~/.config/gcloud, ~/.azure, ~/.password-store, ~/.pgpass, ~/.npmrc и ~/.pypirc. Slash-команды: только команды клавиатуры «Команды», /compact и смена модели (см. С чьими правами выполняется сообщение).

  • read_only: наблюдатели. Они видят всё в группе и могут пользоваться /status, /diff, /whoami, /help, /start и /app, смотреть /settings и листать список /resume, который кто-то открыл. Их собственные текстовые, голосовые сообщения и файлы никуда не отправляются. Первое, что они отправят в чате, получает ответ, что их роль read_only; после этого бот для них в этом чате молчит (ни ответа, ни реакции), пока aipager не перезапустится. У них те же ограничения на инструменты и запись, что у user, на случай если какое-то их сообщение всё же дойдёт до сессии.

Свои роли#

policy.yaml может менять любое поле встроенной роли или задавать новые роли. Поле, которое ты задаёшь, заменяет встроенное значение. Поля:

  • can_prompt, can_approve: отправлять сообщения; отвечать Claude.
  • can_manage: пользоваться режимом «Полный доступ», менять /settings группы, запускать /update и ставить поддержку голосовых (встроенные: owner и admin true, user и read_only false). Оно никогда не позволяет менять участников или роли и никогда не обходит порог безопасности.
  • bypass_role_denies, bypass_safety: см. таблицу.
  • deny_tools, allow_tools, deny_bash_patterns, deny_paths_no_access, deny_paths_no_write: см. Как работают правила.

Роль, заданная с нуля, начинает с включёнными can_prompt и can_approve, выключенными can_manage и обоими исключениями, с файлами учётных данных в её deny_paths_no_access и без запрещённых инструментов, то есть с Bash, пока ты не задашь deny_tools (aipager doctor один раз предупреждает, когда она есть у участника). Ограничение записи и поиска действует для каждой роли без bypass_safety или bypass_role_denies. Корневая папка действует для каждой роли без can_manage, какие бы у неё ни были исключения: роль, которую ты задаёшь с bypass_role_denies или bypass_safety, но без can_manage, пишет и ищет где угодно внутри своей корневой папки (и своего scratchpad) и больше нигде, а в твоей домашней папке не читает ничего вне своей корневой папки (с bypass_safety в сессии, которая работает вне её корневой папки, она пишет только в свой scratchpad). Без ограничений только владельцы и админы.

Корневые папки#

У каждого чата есть корневая папка участников: папка, где участники, чья роль там без can_manage (встроенные user и read_only и роли, которые ты задаёшь без него), запускают и держат свои сессии. Владельцев и админов она не держит. Корневая папка личного чата принадлежит этому человеку; корневая папка группы общая для ограниченных участников группы. Два чата никогда не делят одну, если только ты намеренно не дашь им одну и ту же папку (мастер попросит это подтвердить).

  • Как задать. aipager config спрашивает её, когда ты добавляешь группу или личный чат для роли без can_manage, с уже подставленным значением по умолчанию, а Edit a scope → Set the members' root folder её меняет (применяется сразу, перезагрузкой на лету). Текущая конфигурация показывает корневую папку каждого чата, с (default), если она не задана.
  • По умолчанию это ~/aipager-users/<label> для личного чата (имя человека) и ~/aipager-users/group-<label> для группы. Имя переводится в нижний регистр, а всё, кроме букв, цифр, ., _ и -, становится -; если два чата получили бы одну папку, к каждой добавляется ID её чата (sara-123456). Папка (и ~/aipager-users, если она новая) создаётся с правами 0700, чтобы открыть её мог только ты, когда участник впервые открывает /new или форму «Новая сессия» в Mini App. Перед запуском сессии в ней aipager отмечает её для Claude Code как доверенную, чтобы вопрос Claude Code «Do you trust this folder?» не завершил первую сессию участника. Значение по умолчанию никогда не переезжает: когда изменение в aipager config (корневая папка другого чата, убранный чат, новое имя) изменило бы папку чата по умолчанию, мастер записывает папку, которая у него была, как корневую папку этого чата.
  • Что мастер отклоняет: относительный путь, подстановочные знаки, /, твою домашнюю папку или папку выше, папку, которая является одной из защищённых папок aipager или файлов учётных данных, лежит в ней или содержит её (~/.claude, ~/.config/aipager, ~/.config, ~/.ssh, ...), и временную папку Claude Code (/tmp/claude-*, где лежит scratchpad каждой сессии). Папка, которой ещё нет, подходит. Он просит подтвердить папку, откуда твоя система запускает программы (~/bin, ~/.local/bin, ~/.config/systemd, ~/.config/autostart или папку внутри них).
  • Запуск сессий. Страница «Папка» в /new и Mini App показывают корневую папку и папки прямо внутри неё (не скрытые и не ссылку, которая ведёт наружу), без строки «Папка по умолчанию»; новая сессия запускается в корневой папке, если не выбрать одну из них. «Новая папка» создаёт папку внутри выбранной. Всё остальное получает «Твоя роль может запускать сессии только в твоей папке ~/... или в папке внутри неё.»
  • Сессии вне её. Продолжить, перезапустить, Заменить и сменить режим сессии, чья папка вне корневой папки, получают «Эта сессия работает вне твоей папки ~/..., поэтому твоя роль не может её продолжить, перезапустить или сменить её режим. Попроси админа.» Сообщения в такую работающую сессию по-прежнему отправляются, а hook безопасности ограничивает задачу: там она пишет только в scratchpad.
  • Чем hook ограничивает задачу. Задача ограниченного участника пишет только в папку сессии (когда она внутри корневой папки) и в её scratchpad, не читает, не делает Grep и Glob ни по чему в твоей домашней папке вне корневой папки (кроме своего scratchpad и своего файла ответа) и никогда не трогает корневую папку другого чата, где бы та ни лежала. Папки вне твоей домашней папки (/usr, /etc, ...) остаются доступными для чтения, защищённые папки остаются под запретом, и Bash для user остаётся запрещён. Когда в задаче смешаны два участника с разными корневыми папками, побеждает более узкая; две, которые не вложены друг в друга, оставляют только собственную папку сессии.

Чтобы вернуть user Bash (только для людей, которым можно доверить shell), назови его в allow_tools (который тогда становится ещё и списком разрешённого для этой роли) или замени её deny_tools:

yaml
roles:
  user:
    # встроенный список без Bash
    deny_tools: [PowerShell, Monitor, REPL, Workflow, CronCreate,
                 RemoteTrigger, AppifactRepl, self_hosted_runner_spawn_local,
                 self_hosted_runner_requeue_session, SendMessage,
                 EnterWorktree, ExitWorktree]

Тогда aipager doctor предупреждает: role user has Bash: its safety rules are best-effort, not a boundary. Если в твоём policy.yaml deny_tools для user был задан ещё до появления этого значения по умолчанию, твой список по-прежнему его заменяет, поэтому у этой роли есть Bash, пока ты не добавишь его обратно; предупреждение doctor об этом скажет. О том, что эти ограничения не покрывают, см. безопасность → как правила действуют в команде.

Общение с ботом в группе#

Что бот читает в группе#

В группе aipager обрабатывает только сообщение, которое:

  • команда: /status, /x1 fix the tests или то же самое с @aipagerbot после команды (/x1@aipagerbot), что Telegram добавляет, когда выбираешь её в меню. Команда для другого бота (/x1@otherbot) игнорируется;
  • ответ на одно из сообщений бота;
  • сообщение с упоминанием бота: @aipagerbot fix the tests;
  • нажатие на клавиатуру бота в группе. В группе каждая кнопка клавиатуры начинается с маленького квадрата (▫️ стоп, ▫️ Очистить переписку), и нажатием считается только этот помеченный текст. Набрать слово просто так это обычный разговор: участник, который набирает стоп, Очистить переписку, Opus или имя сессии, ничего не меняет. Чтобы нарочно использовать слово клавиатуры без клавиатуры, обратись к боту: @aipagerbot стоп или стоп в ответ на одно из его сообщений.

Всё остальное (участники говорят друг с другом, фото или голосовое, которое не ответ боту) не получает ни реакции, ни ответа. И неважно, админ ли бот в группе. Изменённые сообщения игнорируются везде: измени сообщение, и ничего не произойдёт; отправь его заново.

Фото, файл или голосовое работают так же: отправь их ответом боту или упомяни бота в подписи. Для альбома ставь подпись на первый элемент: элементы альбома, которые приходят после того, где подпись, упоминание или ответ, берутся, а те, что до него, нет.

Упоминание убирается. @aipagerbot fix the tests доходит до Claude как fix the tests (Claude Code прочитал бы @word как файл). @aipagerbot status и @aipagerbot x2 работают как набор status или x2 в личном чате, а одно @aipagerbot показывает, куда идут твои сообщения. Команда сессии после упоминания работает (@aipagerbot /x1 fix it), а одна из собственных команд aipager нет: @aipagerbot /stop получает «Отправь /stop отдельно, без упоминания бота.»

Только участники. Человек, который не участник группы, получает один ответ («🚫 Тебя нет в списке разрешённых в этом чате.») со своим Telegram ID, чтобы передать его тебе, и записывается для aipager config; после этого бот его игнорирует, пока aipager не перезапустится. Участник с read_only один раз узнаёт свою роль (см. Роли).

Анонимные админы должны писать от своего аккаунта. Админ группы с включённым «Remain anonymous» или сообщение, опубликованное от имени группы или канала, не говорят, кто его написал: Telegram показывает одного и того же отправителя для всех анонимных админов. aipager не может дать такому сообщению ничью роль, поэтому отвечает «Пиши от своего аккаунта, чтобы пользоваться ботом.» (один раз на чат, пока aipager не перезапустится) и больше ничего не делает. Его никогда не записывают как ожидающего пользователя, а мастер отклоняет этот общий ID. Выключи «Remain anonymous» для себя в настройках админа группы или пиши от своего аккаунта.

Общение с сессией в группе#

Ответь на одно из сообщений сессии (её ответ, её карточку), и твоё сообщение уйдёт в эту сессию. Или отправь /x1 твоё сообщение или подпись, которая начинается с /x1.

У каждого человека своя текущая сессия: та, на которую он последним переключился (/x1), которой отправил сообщение, на которую ответил или которую запустил. Ответ сессии другого участника её не меняет, как и чужие сообщения. Упоминание, голосовое, шаблон или команда клавиатуры уходят в твою собственную текущую сессию, а команда клавиатуры или шаблон называют её в ответе («🧹 /clear отправлено в x1»). Голые /stop, /mode, /kill, /restart, /rename, /delete или /diff действуют только на твою собственную текущую сессию (с обычным подтверждением) и только когда команда для неё имеет смысл (работает для /stop, завершена для /delete); иначе всегда показывают список, даже когда осталась одна сессия, потому что она может быть чужой. /clearqueue и /now действуют на твою текущую сессию. /kill x1 и другие команды с именем действуют на эту сессию, как раньше.

  • Если у тебя нет текущей сессии, а работает больше одной, бот спрашивает «Какая сессия? Ответь на одно из её сообщений или напиши /x1 и дальше своё сообщение.» с кнопкой на каждую сессию и ничего не отправляет. Если работает только одна, сообщение уходит туда.
  • Если твоя собственная текущая сессия завершилась, сообщение не уходит в единственную ещё работающую сессию (она может быть чужой): бот отвечает «x1 завершена. Какая сессия?» с кнопкой на каждую работающую сессию и, когда x1 можно продолжить, «▶️ Продолжить x1», и ничего не отправляет.
  • Нажатие на кнопку сессии в любом из этих вопросов ещё и отправляет в эту сессию сообщение, о котором шла речь (текст, расшифровку голосового или файл), как будто оно было отправлено туда, а вопрос меняется на «Отправлено в x2.». Пользоваться кнопками может только тот, кто отправил сообщение, и только десять минут и до перезапуска aipager: после этого кнопка только делает сессию твоей текущей («Это сообщение слишком старое и не отправлено; отправь его ещё раз.»). ▶️ Продолжить возвращает x1, но ничего не отправляет: отправь своё сообщение заново.
  • В группе в закреплённом сообщении нет строки «Сообщения идут в», потому что у каждого человека она своя.

Карточки, которые ждут ответа, принадлежат одному человеку. Карточка новой сессии говорит «Ответь на это сообщение именем и, если хочешь, тем, что сделать сначала:», вопрос о переименовании «… Ответь на это сообщение новым именем.». В группе каждая показывает, чья она («🆕 Новая сессия (@alice)»), ответить на неё может только этот человек, и два человека могут одновременно запускать или переименовывать сессии. Ответ другого участника на чужую карточку новой сессии получает «Это карточка @alice. Отправь /new, чтобы получить свою.» и никуда не уходит. Вопрос о переименовании перестаёт ждать через 10 минут или как только его человек сделает что-то другое. Карточка «x1 готова», ответ на /x1, /start и /help говорят ответить на сообщение сессии или упомянуть бота («Ответь на сообщение от x1 (или упомяни @aipagerbot), чтобы общаться с ней.»), потому что обычное сообщение до бота не доходит.

Клавиатура у каждого своя. Шаблоны, Команды, Модель › и « Назад меняют клавиатуру только того, кто их нажал: бот отвечает в ответ на нажатие этого человека, и ничья другая клавиатура не двигается. « Назад поднимается на уровень вверх оттуда, где ты сейчас, что бы ни смотрели другие участники. Основная клавиатура, которую присылает /start, общая для всей группы и возвращает всех на основную клавиатуру. Когда сессия группы запускается или завершается, aipager один раз снова присылает группе эту основную клавиатуру, чтобы её кнопки сессий оставались актуальными. После обновления с версии без помеченных кнопок нажатие кнопки старой клавиатуры может игнорироваться: отправь /start один раз, чтобы дать группе новую клавиатуру. У клавиатуры личного чата пометки нет, и она работает как раньше.

Mini App#

/app открывает Mini App только в личном чате. В группе её нет в меню /; набранная там, она говорит участнику, у которого настроен свой чат с ботом, «📱 Mini App работает только в личном чате: напиши боту в личку и отправь там /app.», а всем остальным «Mini App открывается из твоего личного чата с ботом. Попроси владельца бота добавить тебя.»

Mini App показывает один чат за раз. Тот, кто состоит больше чем в одном чате (например, в своём личном чате и в группе), получает вверху строку с названиями чатов, чтобы переключаться между ними; она открывается на собственном личном чате человека, иначе на первом чате, где он есть, и запоминает последний выбор на этом телефоне. Всё в ней (сессии, их кнопки, настройки и уведомления, которые она публикует) относится к выбранному чату, с той ролью, которая у человека в этом чате. С одним чатом ничего лишнего не показывается.

С чьими правами выполняется сообщение#

Каждое сообщение выполняется с правами того, кто его отправил, в том чате, откуда оно отправлено. Тот, кто user в группе и owner в своём личном чате, отправляет, нажимает и запускает команды в группе как user, в каком бы порядке чаты ни стояли в aipager.yaml.

  • Каждое сообщение из Telegram приносит в сессию личность и правила своего отправителя (см. безопасность → как правила действуют в команде). Claude видит, кто отправил каждое сообщение ([via Telegram · @bob · role:user] в группе), и никогда не того, кто управлял сессией до этого. Тот, кто отправляет сообщение, становится тем, кто управляет сессией, набрано ли оно, отправлено через /x1, шаблоном или командой клавиатуры.
  • Придержанные сообщения сохраняют своего отправителя. Пока идёт задача другого человека (включая фонового агента, которого она запустила), или пока чужое сообщение ещё ждёт, чтобы его забрали, или пока открыт запрос разрешения или вопрос, новое сообщение придерживается (👀) и отправляется, когда это пройдёт, своей задачей, с правами своего собственного отправителя. Задача, набранная в терминале, считается задачей владельца: к ней присоединяется только сообщение владельца (или, в личном чате, его собственного участника). Твои собственные сообщения никогда не ждут твою собственную задачу. Если задачу, которую они ждут, остановят, или она остановится из-за заблокированного инструмента, придержанные сообщения выбрасываются (🤷): отправь их заново.
  • Побеждает самое строгое. Если сообщения разных людей всё же оказались в одной задаче, задача идёт с самым строгим сочетанием всех, кто в ней участвует. Сообщение, которое присоединилось к идущей задаче, никогда её не расширяет: остаток задачи сохраняет самые строгие правила всех, кто присоединился.
  • Slash-команды ограниченных ролей. Роль, которая не обходит правила ролей (user, read_only, роли, которые ты задаёшь без bypass_role_denies, и отправитель, которого aipager не знает), может отправлять только slash-команды клавиатуры «Команды» (твоей, если keyboard.json её меняет), /compact и смену модели (/model <name>). Всё остальное, набранное, отправленное через /x1 /deliver ..., подписью к файлу, первым сообщением /new x1 /review ... или шаблоном, получает «Эта команда только для админов.» и 🤷, и ничего не доходит до Claude. Владельцы и админы отправляют любые.
  • Ограниченные роли держатся вне домашней папки и подальше от файлов учётных данных. Задача user или read_only никогда не пишет в папку сессии, которая твоя домашняя папка, / или выше (только в свой scratchpad), и никогда не читает файлы учётных данных, перечисленные в Ролях.
  • Ограниченные роли остаются в своей корневой папке. Задача роли без can_manage ничего не читает в твоей домашней папке вне корневой папки чата и ничего не пишет в папку сессии вне её. Корневая папка это папка того чата, откуда пришло сообщение участника, в какую бы сессию оно ни шло.
  • Убранный участник теряет права сразу, но не свою идущую задачу. Отправитель, которого aipager больше не знает (убран, пока его сообщение ждало), идёт по ограниченному порогу. После перезагрузки на лету его придержанные сообщения выбрасываются, а его задача, которая ещё идёт, продолжает работать, ограниченная порогом до конца; отправь /stop, чтобы закончить её сейчас (см. Перезагрузка без перезапуска).
  • Сообщение от другой сессии Claude несёт права своего отправителя. Сообщение, которое одна сессия отправляет другой (SendMessage у Claude Code), идёт с правами задачи, которая его отправила, в том виде, в каком их проверил aipager, и никогда с прежними правами получающей сессии. Сообщение, которое aipager не может проверить, идёт с самыми строгими правилами и без изменений файлов и доступа в интернет (см. безопасность → сообщения между сессиями Claude).
  • Заблокированный инструмент останавливает задачу. Когда задача пробует инструмент, который запрещают её правила, задача сразу останавливается с «🛑 x1 · Заблокировано правилом безопасности: ... (остановлена)», и каждый следующий вызов инструмента в этой задаче тоже отклоняется.

Кто что может нажимать#

Каждая кнопка проверяет роль того, кто её нажимает, в том чате, где кнопка, в момент нажатия. Роль того, кто отправил команду, создавшую кнопку, не считается. (Некоторые карточки ещё проверяют, кто их запросил: карточки подтверждения и карточки /new, ниже.)

  • Смотреть может любой участник (VIEW). Участники read_only могут листать /resume, открывать вид «Завершённые» в /status, меню ⋮ сессии, её режим или её diff, просматривать /settings и закрывать меню. Действовать они не могут: любая другая кнопка отвечает «Твоя роль в этом чате этого не позволяет.»
  • Отвечать Claude нужно can_approve (APPROVE): Разрешить, Разрешать всегда, Отклонить, варианты вопроса, Отправить, Продолжить и Ответить в закреплённом сообщении. У read_only его нет.
  • Действовать с сессией нужно can_prompt (PROMPT): Остановить, Повторить, Сжать, Отправить сейчас, Завершить, Перезапустить, Переименовать, Удалить, Продолжить, смена режима, ✍️ общаться, Убрать все, собственные настройки сессии и карточки /new. Кнопке, которую aipager не знает, это тоже нужно.
  • Переход в режим «Полный доступ» требует админа (MANAGE: owner, admin или роль с can_manage, то же правило, что для /mode full): «Да, сменить» и «Остановить и сменить» на карточке, которая переключает на режим «Полный доступ», и продолжение в режиме «Полный доступ». Переключаться между режимами «Спрашивать» и Авто может любой, кто может действовать с сессией. Продолжение сессии, которая была в режиме «Полный доступ» (набранный /resume x1, список, Продолжить на карточке имени /new или Mini App), для всех остальных возвращает её в режиме Авто, и ответ это говорит: «♻️ x1 снова работает, в режиме Авто: режим „Полный доступ“ только для админов.»
  • В своём собственном личном чате человек может пользоваться режимом «Полный доступ», какая бы ни была роль (включая user; не read_only, который не отправляет сообщений; его роли нужны can_prompt и can_approve, потому что режим «Полный доступ» отвечает на все запросы разрешения Claude Code). Все пути в режим «Полный доступ» выше там для него работают: /mode full, карточка режима, /new !x1, карточки /new, /resume и Mini App. Его собственный чат это единственное место, где это действует: в группе и в личном чате любого другого человека режим «Полный доступ» по-прежнему требует админа. Его новые сессии запускаются в режиме Авто, как у всех, пока он не выберет режим «Полный доступ» в /settings → Новые сессии. Больше ничего из того, что делает админ, ему не открывается (/update, кнопка установки голосовых и /settings группы остаются только для админов). Раздавать режим «Полный доступ» так безопасно: он запускает Claude Code с --dangerously-skip-permissions, который пропускает только собственные запросы разрешения Claude Code. Hook PreToolUse от aipager по-прежнему работает на каждом вызове инструмента и применяет правила роли участника (порог безопасности, ограничение папкой, правила запрета, файлы учётных данных) ровно как в режимах «Спрашивать» и Авто.
  • Установка требует админа (UPDATE): кнопки установки и перезапуска для голосовых, как у /update.
  • Менять /settings группы может только админ. Смотреть может кто угодно.
  • Карточка подтверждения принадлежит тому, кто её запросил. В группе карточки подтверждения для Завершить (/kill, ⋮ Завершить сессию), Перезапустить, Удалить и смены режима, списки сессий, которые показывают /kill, /restart, /delete, /mode, /stop, /rename и /diff, и карточка «Как продолжить x1?», которую открывает нажатие Продолжить (её кнопки режимов), отвечают только тому, кто отправил команду или нажал кнопку, которая их открыла. Нажатие любого другого, включая Отмену, получает «Это карточка @alice. Отправь /kill x2, чтобы получить свою.» (с командой этой карточки) и ничего не меняет. Сама карточка /mode (в каком режиме сессия) общая: смена, нажатая на ней, открывает подтверждение, которое принадлежит нажавшему. Карточки /new отвечают только тому, кто отправил /new. Хозяин карточки запоминается, пока её не используют или не отменят, даже через перезапуск aipager (последние 4 096 карточек). Исключения это карточка имени /new и вопрос об имени /rename: они в любом случае истекают через 10 минут, поэтому после перезапуска отправь команду снова.
  • Кнопка работает только в чате своей сессии. Нажатая где-то ещё, она отвечает «Эта кнопка из другого чата.» и ничего не делает, а Продолжить всегда продолжает ту сессию, которую называет кнопка, и никогда не сессию другого чата с тем же именем.
  • Старые кнопки ничего не меняют. Кнопка, оставшаяся от прежней задачи или с того времени, когда сессия ещё не завершилась и не вернулась, не действует на то, что идёт сейчас; она об этом говорит (см. команды → старые кнопки).

Что видят все#

Ответы Claude. Каждое Разрешить, Отклонить и ответ публикуются в чате под карточкой сессии, с тем, кто это сделал:

text
✅ x1 · Разрешено · @alice · Bash: ls -la /tmp
🚫 x1 · Отклонено · @bob · WebFetch: https://example.com
✓ x1 · Ответ · @carol · Which database? → Postgres

Кто изменил сессию. Нажатие кнопки видит только тот, кто нажал, поэтому в группе каждый результат, который меняет сессию, называет, кто это сделал:

text
⚠️ x1 · @bob остановил(а)
⏹ @bob завершил(а) x2
🔄 @alice перезапустил(а) [x1].
🗑️ @carol удалил(а) [x3].
⚙️ @alice переключил(а) сессию на 🤖 Режим Авто.
@alice изменил(а) это.          (под /settings)

Карточка «x1 готова» называет, кто сменил её режим или модель («@bob сменил(а) модель на Opus.»). В личном чате эти строки результата никого не называют. Изменение, сделанное в Mini App, публикуется в чате как «... через Mini App» (остановка оттуда ещё и называет на карточке сессии, кто это сделал).

Инструмент, заблокированный правилом. Задача останавливается с «🛑 x1 · Заблокировано правилом безопасности: Write is in this role's deny_tools (остановлена)». Если Claude Code просит разрешения на инструмент, которым не может пользоваться человек, чьё сообщение начало идущую задачу, бот сам отвечает Отклонить, не показывает никакого запроса и публикует ⛔ x1 · Edit заблокирован для @bob (роль user) с кратким описанием вызова ниже, называя этого человека. Задача, которую начали сообщения нескольких людей, блокируется, когда хоть один из них не может пользоваться инструментом, и называет его. Задача, набранная в терминале, твоя и никогда не блокируется правилами участника, если только к ней не присоединилось сообщение из Telegram: тогда она проверяется по правилам того, кто отправил последнее сообщение сессии (собственный список группы, если это неизвестно). Когда aipager не знает, чья это задача (она уже шла, когда aipager перезапустился), он использует правила того, кто отправил последнее сообщение сессии, а если и это неизвестно, собственный список группы.

Состояние сообщений. 👀 на сообщении значит, что оно отправлено в сессию (или придержано, пока это возможно); 👍 значит, что Claude его забрал; 🤷 значит, что его выбросили до того, как Claude забрал. /whoami показывает твоё имя, роль и правила в этом чате.

Закреплённое сообщение со статусом. У группы своё закреплённое сообщение со статусом (см. команды → закреплённое сообщение со статусом), где перечислены только сессии этой группы, если бот админ с правом закреплять. Без этого права у группы его нет: сообщение удаляется, а не остаётся незакреплённым в истории.

Аудит на диске. ~/.claude/aipager-audit.jsonl записывает каждое решение с user_id, username и чатом, чтобы потом можно было восстановить, что делал каждый человек. Он всегда пишется по-английски, на каком бы языке ни был чат.

Язык. У группы один язык для собственных сообщений, карточек и клавиатур aipager, его задаёт админ через /language; пока админ его не выбрал, он английский. Он никогда не следует за приложением Telegram кого-либо. То, что видит только один человек, короткое уведомление после нажатия, приходит на его собственном языке: его выбор в личном чате с ботом, иначе язык его приложения Telegram, если человек пришёл после этой версии, иначе язык группы. Меняются только тексты aipager; Claude отвечает на том языке, на котором ему пишет каждый человек. См. Языки.

Куда уходят сообщения#

  • Каждая сессия принадлежит одному чату, и всё о ней уходит туда: её карточки, ответы, запросы разрешения, файлы и уведомления. Сообщение в одном чате никогда не уходит в сессию другого чата, а имя сессии работает только в её собственном чате: если набрать имя сессии другого чата, ответ будет «Нет сессии с таким именем». Сессия, запущенная, пока aipager работал без настроенных чатов, получает свой чат, как только aipager config их добавит; пока у сессии нет чата, ни один чат её не показывает и не может с ней действовать.
  • Сессии, запущенные в терминале (aipager session <name>), принадлежат личному чату владельца: личному чату, у участника которого роль owner (роль с bypass_safety). Если личных чатов несколько и ни один не владельца, это первый личный чат в списке; если личных чатов нет совсем, первый чат. На установке с личным чатом они никогда не уходят в группу.
  • Переход в супергруппу отслеживается автоматически (см. Когда Telegram обновляет группу).

Структура aipager.yaml (части для команды)#

yaml
schema_version: 3
bot_token: "…"

scopes:
  - kind: dm
    chat_id: 12345       # твой собственный личный чат: его ID это твой ID пользователя
    label: owner DM
    members:
      - id: 12345
        label: alice
        role: owner
  - kind: group
    chat_id: -100123456789
    label: team
    deny_tools: [Write, Edit]   # по желанию: ответ на «Block file edits»
    root: /home/alice/aipager-users/group-team   # корневая папка участников
    members:
      - id: 12345        # ID пользователя Telegram (НЕ имя, НЕ ID чата)
        label: alice     # как человек показывается в чате (@alice)
        role: owner
      - id: 67890
        label: bob
        role: user
        deny_tools: [WebFetch]  # по желанию, для участника
      - id: 11111
        label: charlie
        role: read_only

Личный чат и групповые чаты живут вместе: бот обслуживает каждый чат из списка, а сессии каждого чата держатся отдельно. Этот файл пишет aipager config; править его тебе никогда не нужно.

Как работают правила#

~/.config/aipager/policy.yaml задаёт правила для каждой роли. Проверяй его через aipager policy validate. Поля, которые принимает каждая роль (кроме перечисленных в Своих ролях):

  • deny_tools: имена инструментов, запрещённых без вопроса (например, Write, Edit, Bash, WebFetch).
  • allow_tools: если не пусто, список разрешённого: всё остальное для этой роли запрещено.
  • deny_bash_patterns: шаблоны, которые сравниваются с вводом Bash.
  • deny_paths_no_access / deny_paths_no_write: правила для путей. Для user, read_only и каждой роли, которую ты задаёшь без bypass_role_denies, deny_paths_no_access начинается с файлов учётных данных, перечисленных выше у user; если его задать, этот список заменяется, поэтому скопируй в свой те, которые хочешь сохранить (идущая задача, к которой присоединяется другое сообщение, снова держится этого списка до своего конца). Правило без / или ~ в начале (**/.env) совпадает где угодно, поэтому пока оно есть, каждый Grep/Glob ограниченной роли отклоняется (любой поиск мог бы прочитать такой файл), и это останавливает задачу.

deny_tools чата и deny_tools участника в aipager.yaml добавляются к роли, а allow_tools участника добавляется к списку разрешённого роли. Всё это действует только для ролей без bypass_role_denies: владельца или админа это не касается.

Файлы ~/.config/aipager/policy.d/*.yaml читаются после policy.yaml, по порядку имён, в том же формате: поле роли, заданное в более позднем файле, заменяет прежнее значение, а список safety: только добавляется. aipager policy validate проверяет их все.

Под всеми ролями лежит нижний порог безопасности (защищённые пути и шаблоны команд), который обходит только owner: админы тоже его держатся. Это встроенный список aipager плюс раздел safety: в policy.yaml, который может только добавлять:

yaml
safety:
  deny_paths_no_access: [/srv/secrets/**]   # ни читать, ни писать, ни искать
  deny_paths_no_write: [~/notes/**]         # читать можно, писать нельзя
  deny_bash_patterns: ['\bcurl\b']          # команды Bash, которые блокируются

Каждая задача каждой роли, кроме owner, получает его целиком, как и задачи, которые aipager не может ни к кому отнести; aipager doctor --safety-check показывает, что действует. После перезагрузки на лету изменение в нём применяется к сообщениям, отправленным после перезагрузки; уже идущая задача или сообщение, которое уже ждёт в очереди, сохраняют старый список (останови эту задачу, чтобы применить изменение сразу). Путь в deny_paths_no_access там без / или ~ в начале совпадает где угодно, поэтому пока он есть, каждый Grep/Glob каждой роли, кроме owner, отклоняется (aipager doctor об этом предупреждает). Защищённые пути применяются к файловым инструментам Claude Code (Read, Write, Edit, MultiEdit, NotebookEdit, LSP, Grep, Glob); Grep/Glob ограниченной роли ещё и должен оставаться внутри папки сессии (поиск aipager/** в ~/.config отклоняется). WebFetch по пути не проверяется; SendUserFile (файлы, которые Claude отправляет в чат) проверяется, как Read, и участник отправляет только из корневой папки чата (безопасность). Задача из Telegram, которую aipager не может отнести к отправителю, получает порог, который не мягче user. Повторить идёт с ролью того, кто нажимает, если этот человек отправил повторяемое сообщение, а иначе по порогу. Шаблоны команд важны только для роли с Bash, и там они фильтр, а не стена; см. Модель безопасности → как правила действуют в команде.

Вопросы приватности#

  • Бот слушает только настроенные чаты. Если добавить бота в другую группу, он там не включится: он там никогда не отвечает. Он записывает, кто к нему там обращается (ID, имя пользователя и имя человека, ID и название группы), в ~/.claude/aipager-pending-users.json, чтобы aipager config мог добавить эту группу. Читать этот файл можешь только ты, и он хранит последних 200 человек, замеченных за 30 дней.
  • Участники read_only могут читать сообщения, ответы и ввод инструментов. Действовать они не могут, но видят в группе всё. Если какая-то работа должна быть скрыта от кого-то, этому человеку не место в группе.
  • На установке с личным чатом твои терминальные сессии и сессии твоего личного чата никогда не появляются в группе (см. Куда уходят сообщения). Терминальная сессия, которую более старый aipager уже перенёс в группу, остаётся в группе: заверши её, удали её из завершённых сессий группы и запусти заново.
  • У aipager.yaml права 0600 (только владелец). aipager не задаёт права policy.yaml: держи его доступным только владельцу (chmod 600 ~/.config/aipager/policy.yaml).
  • У журнала аудита (~/.claude/aipager-audit.jsonl) своих прав нет: он настолько же личный, насколько твоя папка ~/.claude.

Как забрать доступ у человека#

  1. Запусти aipager config → Edit a member → чат → человек → Remove member. Чтобы забрать право отправлять сообщения, но оставить возможность читать, используй Set role и выбери read_only. (Чтобы потом добавить снова: Edit a scope → группа → Add a member.) Для личного чата человека заверши его сессии, потом Edit a scope → его личный чат → Remove this scope.
  2. Мастер перезагружает aipager на лету; он пишет «Scopes reloaded live». Сразу его придержанные сообщения выбрасываются (🤷 и ответ «Не отправлено Claude»), а его задача, которая ещё идёт, ограничивается порогом до своего конца. Отправь /stop, чтобы закончить эту задачу сейчас.
  3. Убери его и из группы Telegram. Пока он там, он по-прежнему может читать всё, что туда публикуется: карточки, ответы, ввод инструментов и запросы разрешения.

Проверь, что говорит мастер после шага 1. Если он говорит перезапустить aipager, он до него не достучался: перезапусти его (aipager service stop, потом aipager service start), потому что до этого в памяти остаётся прежний список участников. Если он пишет «Not applied», исправь проблему, которую он называет: до этого aipager держит прежнюю конфигурацию. После ручной правки aipager.yaml отправь перезагрузку вручную (см. Перезагрузка без перезапуска).