Настройка Signal
Hermes подключается к Signal через демон signal-cli, запущенный в режиме HTTP. Адаптер получает сообщения в реальном времени по SSE (Server-Sent Events), а ответы отправляет через JSON-RPC.
Среди массовых мессенджеров Signal больше всех заботится о приватности: сквозное шифрование по умолчанию, открытый протокол, минимум собираемых метаданных. Для агентских сценариев, где безопасность критична, это удачный выбор.
Для всего обмена данными адаптер Signal использует httpx — он уже входит в ядро зависимостей Hermes. Дополнительных пакетов Python ставить не нужно. Понадобится лишь установить signal-cli отдельно.
Что понадобится
- signal-cli — клиент Signal на Java (GitHub)
- среда выполнения Java 17+ — её требует signal-cli
- номер телефона с установленным Signal (чтобы привязать как вторичное устройство)
Установка signal-cli
# macOS
brew install signal-cli
# Linux (download latest release)
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} \
https://github.com/AsamK/signal-cli/releases/latest | sed 's/^.*\/v//')
curl -L -O "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}.tar.gz"
sudo tar xf "signal-cli-${VERSION}.tar.gz" -C /opt
sudo ln -sf "/opt/signal-cli-${VERSION}/bin/signal-cli" /usr/local/bin/
В репозиториях apt и snap signal-cli отсутствует. Команды для Linux выше скачивают его напрямую из релизов на GitHub.
Шаг 1. Привяжите аккаунт Signal
signal-cli работает как привязанное устройство — по принципу WhatsApp Web, только для Signal. Телефон при этом остаётся основным устройством.
# Generate a linking URI (displays a QR code or link)
signal-cli link -n "HermesAgent"
- Откройте Signal на телефоне
- Перейдите в Settings → Linked Devices
- Нажмите Link New Device
- Отсканируйте QR-код или введите URI
Шаг 2. Запустите демон signal-cli
# Replace +1234567890 with your Signal phone number (E.164 format)
signal-cli --account +1234567890 daemon --http 127.0.0.1:8080
Пусть процесс работает в фоне. Подойдут systemd, tmux, screen или запуск в виде службы.
Проверьте, что демон запущен:
curl http://127.0.0.1:8080/api/v1/check
# Should return: {"versions":{"signal-cli":...}}
Шаг 3. Настройте Hermes
Самый простой путь:
hermes gateway setup
Выберите в меню платформ Signal. Мастер настройки:
- проверит, установлен ли signal-cli
- спросит HTTP-URL (по умолчанию
http://127.0.0.1:8080) - протестирует связь с демоном
- запросит номер телефона вашего аккаунта
- настроит список разрешённых пользователей и политики доступа
Ручная настройка
Добавьте в ~/.hermes/.env:
# Required
SIGNAL_HTTP_URL=http://127.0.0.1:8080
SIGNAL_ACCOUNT=+1234567890
# Security (recommended)
SIGNAL_ALLOWED_USERS=+1234567890,+0987654321 # Comma-separated E.164 numbers or UUIDs
# Optional
SIGNAL_GROUP_ALLOWED_USERS=groupId1,groupId2 # Enable groups (omit to disable, * for all)
SIGNAL_HOME_CHANNEL=+1234567890 # Default delivery target for cron jobs
После этого запустите шлюз:
hermes gateway # Foreground
hermes gateway install # Install as a user service
sudo hermes gateway install --system # Linux only: boot-time system service
Контроль доступа
Доступ к личным сообщениям
Доступ к личным сообщениям устроен так же, как на остальных платформах Hermes:
SIGNAL_ALLOWED_USERSзадан → писать могут только перечисленные пользователи- список разрешений не задан → незнакомый пользователь получает код сопряжения в личке (подтвердите его командой
hermes pairing approve signal CODE) SIGNAL_ALLOW_ALL_USERS=true→ писать может кто угодно (используйте с осторожностью)
Доступ к группам
Группами управляет переменная окружения SIGNAL_GROUP_ALLOWED_USERS:
| Конфигурация | Поведение |
|---|---|
| Не задана (по умолчанию) | Все групповые сообщения игнорируются. Бот отвечает только в личке. |
| Заданы ID групп | Отслеживаются лишь перечисленные группы (например, groupId1,groupId2). |
Значение * | Бот отвечает в любой группе, участником которой состоит. |
Возможности
Вложения
Адаптер умеет принимать и отправлять медиафайлы в обе стороны.
Входящие (пользователь → агент):
- Изображения — PNG, JPEG, GIF, WebP (тип определяется по сигнатуре файла)
- Аудио — MP3, OGG, WAV, M4A (голосовые сообщения расшифровываются, если настроен Whisper)
- Документы — PDF, ZIP и другие форматы файлов
Исходящие (агент → пользователь):
Агент отправляет медиафайлы через теги MEDIA: в ответах. Доступны такие способы доставки:
- Изображения —
send_multiple_imagesиsend_image_fileотправляют PNG, JPEG, GIF, WebP как нативные вложения Signal - Голос —
send_voiceотправляет аудиофайлы (OGG, MP3, WAV, M4A, AAC) вложениями - Видео —
send_videoотправляет видеофайлы MP4 - Документы —
send_documentотправляет файл любого типа (PDF, ZIP и т. д.)
Все исходящие медиа идут через стандартный API вложений Signal. В отличие от ряда других платформ, Signal на уровне протокола не разделяет голосовые сообщения и файловые вложения.
Лимит размера вложения — 100 МБ (в обе стороны).
Серверы Signal ограничивают скорость загрузки вложений: при отправке нескольких изображений адаптер задействует планировщик, который разбивает их на партии по 32 штуки и придерживает выгрузку под политику серверов Signal.
Нативное форматирование, цитаты в ответах и реакции
Сообщения в Signal отображаются с нативным форматированием, а не сырыми символами markdown. Адаптер переводит markdown (**bold**, *italic*, `code`, ~~strike~~, ||spoiler||, заголовки) в bodyRanges Signal — и текст приходит получателю уже со стилями, без видимых ** или `.
Цитаты в ответах. Когда Hermes отвечает на конкретное сообщение, он теперь оформляет нативный ответ-цитату — тот самый интерфейс, который пользователи Signal видят, нажимая «Reply» сами. Для ответов на входящие сообщения это происходит автоматически.
Реакции. Агент может реагировать на сообщения через стандартный API реакций; в Signal они появляются как эмодзи-реакции на упомянутом сообщении, а не отдельным текстом.
Ничего из этого настраивать не нужно — в свежих сборках signal-cli всё включено по умолчанию. Если версия signal-cli слишком старая, Hermes откатывается на доставку обычным текстом и один раз пишет предупреждение в лог.
Индикаторы набора
Пока бот обрабатывает сообщение, он показывает индикатор набора текста и обновляет его каждые 8 секунд.
Отображение прогресса инструментов
Signal не поддерживает редактирование уже отправленных сообщений. Поэтому Hermes не показывает всплывающие пузыри прогресса вызова инструментов в Signal — даже если включён режим /verbose и для платформы сохранён режим, отличный от off.
Активность инструментов по-прежнему видна в CLI, а итоговые ответы в Signal содержат обычный вывод агента. Если нужен прогресс по каждому инструменту прямо в чате — используйте платформу с поддержкой редактирования сообщений.
Скрытие номеров телефонов
В логах все номера телефонов скрываются автоматически:
+15551234567→+155****4567- Это касается и логов шлюза Hermes, и глобальной системы редактирования
Заметки себе (настройка на одном номере)
Если вы запускаете signal-cli как привязанное вторичное устройство на собственном номере (а не на отдельном номере для бота), то общаться с Hermes можно через функцию Signal «Note to Self».
Просто отправьте сообщение самому себе с телефона — signal-cli его подхватит, и Hermes ответит в той же переписке.
Как это работает:
- сообщения «Note to Self» приходят как конверты
syncMessage.sentMessage - адаптер распознаёт те из них, что адресованы собственному аккаунту бота, и обрабатывает их как обычные входящие
- защита от эха (отслеживание timestamp отправленных сообщений) не даёт зациклиться — ответы самого бота отфильтровываются автоматически
Дополнительная настройка не нужна. Всё работает само, пока SIGNAL_ACCOUNT совпадает с вашим номером телефона.
Контроль состояния
Адаптер следит за SSE-соединением и автоматически переподключается, если:
- соединение разорвалось (с экспоненциальной задержкой: 2 с → 60 с)
- активности нет в течение 120 секунд (тогда адаптер пингует signal-cli для проверки)
Решение проблем
| Проблема | Решение |
|---|---|
| «Cannot reach signal-cli» при настройке | Убедитесь, что демон signal-cli запущен: signal-cli --account +YOUR_NUMBER daemon --http 127.0.0.1:8080 |
| Сообщения не приходят | Проверьте, что SIGNAL_ALLOWED_USERS содержит номер отправителя в формате E.164 (с префиксом +) |
| «signal-cli not found on PATH» | Установите signal-cli и добавьте его в PATH либо используйте Docker |
| Соединение постоянно рвётся | Загляните в логи signal-cli на предмет ошибок. Убедитесь, что установлена Java 17+. |
| Групповые сообщения игнорируются | Задайте SIGNAL_GROUP_ALLOWED_USERS с конкретными ID групп или *, чтобы разрешить все группы. |
| Бот никому не отвечает | Задайте SIGNAL_ALLOWED_USERS, используйте сопряжение в личке или явно разрешите всех пользователей через политику шлюза, если нужен более широкий доступ. |
| Дублирующиеся сообщения | Убедитесь, что на вашем номере слушает только один экземпляр signal-cli |
Безопасность
Всегда настраивайте контроль доступа. По умолчанию у бота есть доступ к терминалу. Без SIGNAL_ALLOWED_USERS или сопряжения в личке шлюз из соображений безопасности отклоняет все входящие сообщения.
- Номера телефонов скрываются во всём выводе логов
- Для безопасного подключения новых пользователей применяйте сопряжение в личке или явные списки разрешений
- Держите группы выключенными, пока поддержка групп вам реально не нужна, либо вносите в список разрешений только те группы, которым доверяете
- Сквозное шифрование Signal защищает содержимое сообщений при передаче
- Данные сессии signal-cli в
~/.local/share/signal-cli/содержат учётные данные аккаунта — берегите их как пароль
Справочник переменных окружения
| Переменная | Обязательна | По умолчанию | Описание |
|---|---|---|---|
SIGNAL_HTTP_URL | Да | — | HTTP-эндпоинт signal-cli |
SIGNAL_ACCOUNT | Да | — | Номер телефона бота (E.164) |
SIGNAL_ALLOWED_USERS | Нет | — | Номера телефонов/UUID через запятую |
SIGNAL_GROUP_ALLOWED_USERS | Нет | — | ID групп для отслеживания или * для всех (без значения группы отключены) |
SIGNAL_ALLOW_ALL_USERS | Нет | false | Разрешить взаимодействие любому пользователю (пропустить список разрешений) |
SIGNAL_HOME_CHANNEL | Нет | — | Цель доставки по умолчанию для cron-задач |