Конфигурация
Все настройки хранятся в каталоге ~/.hermes/ — так до них проще добраться.
config.yaml
Запустите hermes setup --portal — один OAuth даёт вам провайдера модели и все четыре инструмента Tool Gateway без ручной правки YAML. Подписчикам Portal вдобавок идёт скидка 10% на провайдеров с потокеновой оплатой. Подробности — в разделе Nous Portal.
Структура каталога
~/.hermes/
├── config.yaml # Настройки (модель, терминал, TTS, сжатие и т.д.)
├── .env # API-ключи и секреты
├── auth.json # OAuth-учётки провайдеров (Nous Portal и др.)
├── SOUL.md # Основная идентичность агента (слот №1 в системном промпте)
├── memories/ # Постоянная память (MEMORY.md, USER.md)
├── skills/ # Навыки, созданные агентом (управляются через инструмент skill_manage)
├── cron/ # Запланированные задачи
├── sessions/ # Сессии шлюза
└── logs/ # Логи (errors.log, gateway.log — секреты затираются автоматически)
Управление конфигурацией
hermes config # Посмотреть текущую конфигурацию
hermes config edit # Открыть config.yaml в редакторе
hermes config set KEY VAL # Задать конкретное значение
hermes config check # Проверить, не пропущены ли опции (после обновлений)
hermes config migrate # Интерактивно добавить недостающие опции
# Примеры:
hermes config set model anthropic/claude-opus-4
hermes config set terminal.backend docker
hermes config set OPENROUTER_API_KEY sk-or-... # Сохраняется в .env
Команда hermes config set сама раскладывает значения по нужным файлам: API-ключи уходят в .env, всё остальное — в config.yaml.
Приоритет настроек
Настройки разрешаются в таком порядке (сначала — наивысший приоритет):
- Аргументы CLI — например,
hermes chat --model anthropic/claude-sonnet-4(переопределение на один запуск) ~/.hermes/config.yaml— главный конфиг для всех несекретных настроек~/.hermes/.env— запасной вариант для переменных окружения; обязателен для секретов (API-ключи, токены, пароли)- Встроенные значения по умолчанию — зашитые безопасные дефолты, когда не задано ничего другого
Секреты (API-ключи, токены ботов, пароли) кладите в .env. Всё остальное (модель, бэкенд терминала, настройки сжатия, лимиты памяти, наборы инструментов) — в config.yaml. Если значение задано в обоих местах, для несекретных настроек побеждает config.yaml.
Администратор может закрепить конкретные значения конфига и секретов так, что обычный пользователь не сможет их переопределить, — через управляемый каталог на уровне системы. См. Управляемая область.
Подстановка переменных окружения
В config.yaml можно ссылаться на переменные окружения через синтаксис ${VAR_NAME}:
auxiliary:
vision:
api_key: ${GOOGLE_API_KEY}
base_url: ${CUSTOM_VISION_URL}
delegation:
api_key: ${DELEGATION_KEY}
В одном значении можно сослаться сразу на несколько переменных: url: "${HOST}:${PORT}". Если переменная не задана, плейсхолдер остаётся как есть (${UNDEFINED_VAR} сохранится дословно). Поддерживается только синтаксис ${VAR} — голый $VAR не разворачивается.
Настройку провайдеров ИИ (OpenRouter, Anthropic, Copilot, кастомные эндпоинты, self-hosted LLM, резервные модели и т.д.) смотрите в разделе Провайдеры ИИ.
Тайм-ауты провайдеров
Через providers.<id>.request_timeout_seconds задаётся тайм-аут запроса на уровне всего провайдера, а providers.<id>.models.<model>.timeout_seconds переопределяет его для конкретной модели. Параметр действует на основной клиент хода диалога во всех транспортах (OpenAI-wire, нативный Anthropic, Anthropic-совместимый), на цепочку резервных провайдеров, на пересборку после ротации учётных данных и (для OpenAI-wire) на per-request аргумент тайм-аута — так что заданное значение перебивает устаревшую переменную окружения HERMES_API_TIMEOUT.
Ещё есть providers.<id>.stale_timeout_seconds для детектора зависших не-потоковых вызовов и providers.<id>.models.<model>.stale_timeout_seconds для переопределения под конкретную модель. Эта настройка перебивает устаревшую HERMES_API_CALL_STALE_TIMEOUT.
Если оставить всё это незаданным, в силе остаются прежние дефолты (HERMES_API_TIMEOUT=1800с, HERMES_API_CALL_STALE_TIMEOUT=300с, нативный Anthropic — 900с). Для AWS Bedrock пока не подключено (оба пути — bedrock_converse и SDK AnthropicBedrock — используют boto3 с его собственной настройкой тайм-аутов). Закомментированный пример смотрите в cli-config.yaml.example.
Поведение при обновлении
Настройки hermes update живут под ключом updates в config.yaml:
updates:
pre_update_backup: false # Делать полный zip HERMES_HOME перед каждым обновлением
backup_keep: 5 # Хранить столько zip-бэкапов перед обновлением
non_interactive_local_changes: stash # stash | discard
Для git-установок Hermes перед переключением на ветку обновления или pull автоматически прячет в stash грязные отслеживаемые и неотслеживаемые файлы. Интерактивные обновления из терминала спрашивают, прежде чем восстановить этот stash. Неинтерактивные обновления (десктопное/чат-приложение, шлюз или --yes) опираются на updates.non_interactive_local_changes: stash восстанавливает локальные правки исходников после успешного pull, а discard отбрасывает созданный обновлением stash после успешного pull. Используйте discard только на управляемых установках, где локальные правки исходников и не должны сохраняться.
Перед шагом со stash Hermes также откатывает diff’ы отслеживаемого package-lock.json, оставленные суетой npm install/build. Осознанные правки lockfile закоммитьте или вручную спрячьте в stash до обновления.
Настройка бэкенда терминала
Hermes поддерживает шесть бэкендов терминала. Каждый определяет, где на самом деле выполняются shell-команды агента: на вашей локальной машине, в контейнере Docker, на удалённом сервере по SSH, в облачной песочнице Modal (напрямую или через управляемый Nous шлюз), в воркспейсе Daytona или в контейнере Singularity/Apptainer.
terminal:
backend: local # local | docker | ssh | modal | daytona | singularity
cwd: "." # Рабочий каталог для шлюза/cron (CLI всегда берёт каталог запуска)
timeout: 180 # Тайм-аут на одну команду в секундах
home_mode: auto # auto | real | profile — политика HOME для подпроцессов
env_passthrough: [] # Имена переменных окружения для проброса в изолированное выполнение (terminal + execute_code)
singularity_image: "docker://nikolaik/python-nodejs:python3.11-nodejs20" # Образ контейнера для бэкенда Singularity
modal_image: "nikolaik/python-nodejs:python3.11-nodejs20" # Образ контейнера для бэкенда Modal
daytona_image: "nikolaik/python-nodejs:python3.11-nodejs20" # Образ контейнера для бэкенда Daytona
Для облачных песочниц вроде Modal и Daytona container_persistent: true означает, что Hermes постарается сохранить состояние файловой системы при пересоздании песочницы. Это не гарантия того, что позже будет работать та же живая песочница, то же PID-пространство или фоновые процессы.
Обзор бэкендов
| Бэкенд | Где выполняются команды | Изоляция | Для чего лучше всего |
|---|---|---|---|
| local | Прямо на вашей машине | Нет | Разработка, личное использование |
| docker | Один долгоживущий контейнер Docker (общий для сессии, /new, субагентов) | Полная (namespaces, cap-drop) | Безопасная песочница, CI/CD |
| ssh | Удалённый сервер по SSH | Сетевая граница | Удалённая разработка, мощное железо |
| modal | Облачная песочница Modal | Полная (облачная VM) | Эфемерные облачные вычисления, эвалы |
| daytona | Воркспейс Daytona | Полная (облачный контейнер) | Управляемые облачные среды разработки |
| singularity | Контейнер Singularity/Apptainer | Namespaces (—containall) | HPC-кластеры, общие машины |
Локальный бэкенд
Вариант по умолчанию. Команды выполняются прямо на вашей машине, без изоляции. Никакой особой настройки не требуется.
terminal:
backend: local
По умолчанию локальные подпроцессы инструментов сохраняют ваш настоящий HOME
от OS-пользователя. Так внешние CLI — git, ssh, gh, az, npm, Claude Code,
Codex — находят учётные данные и конфиги, которыми вы уже пользуетесь в обычном
шелле. Состояние Hermes всё равно привязано к профилю через HERMES_HOME; HOME
не отвечает за то, как профиль выбирает конфиг, память, сессии или навыки.
Hermes не меняет ваш системный HOME, файлы автозапуска шелла или домашний
каталог учётной записи в ОС. Эта настройка управляет только окружением,
передаваемым подпроцессам, которые Hermes запускает через инструменты вроде
terminal, фоновые терминальные процессы, execute_code и ACP-помощники.
terminal.home_mode
| Режим | Установки на хосте | Контейнеры | Компромисс |
|---|---|---|---|
auto | Сохранять настоящий HOME OS-пользователя | Использовать {HERMES_HOME}/home | Рекомендуемый дефолт. CLI на хосте продолжают работать; состояние контейнера сохраняется. |
real | Принудительно настоящий HOME OS-пользователя | Принудительно настоящий HOME OS-пользователя, если он виден | Пригодится, если родительский процесс случайно стартовал с HOME, указывающим на домашний каталог профиля. |
profile | Использовать {HERMES_HOME}/home, если он существует | Использовать {HERMES_HOME}/home, если он существует | Строгая изоляция конфигов CLI по профилю, но обычные ~/.ssh, ~/.gitconfig, ~/.azure, ~/.config/gh, авторизация Claude/Codex, состояние npm и т.п. не будут видны, пока вы не инициализируете или не слинкуете их внутри домашнего каталога профиля. |
Обратная сторона дефолта в том, что профили на хосте делят одни и те же обычные
учётные данные и конфиги CLI на уровне пользователя под ~. Если нужен профиль
с отдельной git-идентичностью, SSH-ключами, логином GitHub CLI, конфигом npm или
логином облачного CLI, используйте home_mode: profile и осознанно
инициализируйте эти инструменты внутри домашнего каталога такого профиля.
Если вы намеренно хотите строгую изоляцию конфигов инструментов по профилю, задайте:
terminal:
home_mode: profile
В этом режиме подпроцессы инструментов используют {HERMES_HOME}/home как HOME.
Hermes также задаёт HERMES_REAL_HOME, чтобы скрипты при необходимости всё ещё
могли найти настоящий домашний каталог пользователя. Контейнерные бэкенды в
режиме auto продолжают использовать {HERMES_HOME}/home, поскольку этот каталог
лежит на постоянном томе данных Hermes.
Скриптам, которым нужно отличать состояние профиля от настоящего домашнего
каталога пользователя, стоит брать HERMES_HOME для данных Hermes и
HERMES_REAL_HOME — для домашнего каталога учётной записи:
from pathlib import Path
import os
hermes_home = Path(os.environ["HERMES_HOME"])
real_home = Path(os.environ.get("HERMES_REAL_HOME", os.environ["HOME"]))
У агента те же права на файловую систему, что и у вашей учётной записи. Через hermes tools отключите ненужные инструменты или переключитесь на Docker ради песочницы.
Бэкенд Docker
Выполняет команды внутри контейнера Docker с усиленной защитой (сброшены все capabilities, запрещено повышение привилегий, есть лимит PID).
Единый долгоживущий контейнер, общий для процессов Hermes. При первом обращении Hermes поднимает ОДИН долгоживущий контейнер и направляет каждый вызов терминала, файла и execute_code через docker exec в этот же контейнер — между сессиями, через /new, /reset и субагентов delegate_task. Смена рабочего каталога, установленные пакеты, файлы в /workspace и фоновые процессы переносятся из одного вызова инструмента в следующий и из одного процесса Hermes в другой. Когда вы закрываете сессию TUI, выполняете /quit или запускаете новый вызов hermes, контейнер продолжает работать, а следующий процесс Hermes переиспользует его по поиску метки. Точные правила сноса смотрите ниже в Жизненном цикле контейнера.
terminal:
backend: docker
docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
docker_mount_cwd_to_workspace: false # Монтировать каталог запуска в /workspace
docker_run_as_host_user: false # См. «Запуск контейнера от имени хост-пользователя» ниже
docker_forward_env: # Переменные окружения хоста для проброса в контейнер
- "GITHUB_TOKEN"
docker_env: # Литеральные переменные окружения для инъекции (KEY=value)
DEBUG: "1"
PYTHONUNBUFFERED: "1"
docker_volumes: # Монтирование каталогов хоста
- "/home/user/projects:/workspace/projects"
- "/home/user/data:/data:ro" # :ro для режима «только чтение»
docker_extra_args: # Дополнительные флаги, дословно добавляемые к `docker run`
- "--gpus=all"
- "--network=host"
# Ограничения ресурсов
container_cpu: 1 # Ядра CPU (0 = без ограничений)
container_memory: 5120 # МБ (0 = без ограничений)
container_disk: 51200 # МБ (требует overlay2 на XFS+pquota)
container_persistent: true # Сохранять каталоги bind-монтирования /workspace и /root
# Переиспользование контейнера между процессами (дефолты соответствуют контракту
# «один долгоживущий контейнер, общий для сессий» — см. Жизненный цикл контейнера).
docker_persist_across_processes: true # Переиспользовать контейнер между перезапусками Hermes
docker_orphan_reaper: true # Подчищать брошенные Exited-контейнеры при старте
# Настройки жизненного цикла на уровне всех бэкендов (применимы и к docker)
timeout: 180 # Тайм-аут на одну команду в секундах
lifetime_seconds: 300 # Окно сборщика по простою; также задаёт порог 2× для сборщика сирот
docker_env против docker_forward_env: первый внедряет литеральные пары KEY=value, которые вы указываете в конфиге (их значения лежат в config.yaml либо передаются JSON-словарём через TERMINAL_DOCKER_ENV='{"DEBUG":"1"}'). Второй пробрасывает значения из вашего шелла или ~/.hermes/.env, поэтому сам секрет в файле конфигурации не появляется. Для токенов используйте docker_forward_env, а для статичных параметров, нужных контейнеру, — docker_env.
terminal.docker_extra_args (его тоже можно переопределить через TERMINAL_DOCKER_EXTRA_ARGS='["--gpus=all"]') даёт передать произвольные флаги docker run, для которых у Hermes нет отдельных ключей: --gpus, --network, --add-host, альтернативные переопределения --security-opt и т.д. Каждый элемент должен быть строкой; список добавляется последним к собранной команде docker run, так что при необходимости он перебивает дефолты Hermes. Пользуйтесь умеренно — флаги, конфликтующие с усилением песочницы (сброс capabilities, --user, bind-монтирование воркспейса), тихо ослабляют изоляцию.
Требования: установленный и запущенный Docker Desktop или Docker Engine. Hermes проверяет $PATH плюс типичные места установки на macOS (/usr/local/bin/docker, /opt/homebrew/bin/docker, бандл приложения Docker Desktop). Podman поддерживается из коробки: задайте HERMES_DOCKER_BINARY=podman (или полный путь), чтобы принудительно использовать его, когда установлены оба.
Жизненный цикл контейнера
Каждому контейнеру под управлением Hermes присваиваются три метки, чтобы последующие процессы (и сборщик сирот) могли его опознать:
hermes-agent=1— помечает контейнер как управляемый Hermeshermes-task-id=<очищенный task_id>— ключ для проверки переиспользования по задачеhermes-profile=<очищенное имя профиля>— ограничивает переиспользование и сборку рамками активного профиля Hermes
При старте Hermes выполняет docker ps --filter label=hermes-task-id=<id> --filter label=hermes-profile=<profile> и подключается к существующему контейнеру, если находит его. Если контейнер в статусе exited (например, после перезапуска демона Docker), он поднимается через docker start и переиспользуется — состояние файловой системы и установленные пакеты сохраняются, а вот фоновые процессы внутри контейнера — нет.
Когда процесс Hermes завершается — /quit, закрытие сессии TUI, остановка шлюза, даже SIGKILL — путь очистки в режиме по умолчанию ничего не делает с контейнером. Контейнер продолжает работать. Следующий процесс Hermes подключается к нему за миллисекунды по поиску метки. Именно этого требует контракт «один долгоживущий контейнер, общий для сессий»: только так фоновые процессы (npm-вотчеры, dev-серверы, долгие прогоны pytest) переживают смену сессий.
Контейнер сносится (останавливается и удаляется через docker rm -f) только в этих случаях:
| Триггер | Когда срабатывает |
|---|---|
docker_persist_across_processes: false | Явная изоляция на каждый процесс. Каждый cleanup() делает stop + rm -f. Соответствует поведению до issue #20561. |
Сборщик по простою (lifetime_seconds, по умолчанию 300с) | Только когда у среды persist_across_processes=false. У сред в persist-режиме это no-op; контейнер переживает зачистку по простою. |
| Сборщик сирот при следующем старте | Подчищает Exited-контейнеры с метками hermes старше 2 × lifetime_seconds (по умолчанию 600с = 10 мин), в рамках текущего профиля. Работающие контейнеры не трогаются никогда — безопасность для соседних процессов. Чтобы отключить, задайте docker_orphan_reaper: false. |
| Прямое действие пользователя | docker rm -f, docker system prune, перезапуск Docker Desktop. Мы не задаём --restart=always, поэтому после перезагрузки хоста контейнер остаётся в статусе Exited (его CoW-слой выживает и переиспользуется при следующем старте, но фоновые процессы пропадают). |
Граничные случаи, о которых стоит знать:
- OOM-kill внутреннего PID 1 переводит контейнер в статус
Exited. При следующем переиспользовании он поднимется черезdocker start; состояние файловой системы выживает, фоновые процессы — нет. - Переключение профилей изолирует контейнеры друг от друга — контейнер с меткой
hermes-profile=workневидим для процесса Hermes, работающего подhermes-profile=research. Сборщик сирот тоже привязан к профилю, поэтому контейнеры из другого профиля случайно не сносятся, но и автоматически не подчищаются, пока вы снова не запустите Hermes под их исходным профилем.
Параллельные субагенты, порождённые через delegate_task(tasks=[...]), делят этот единственный контейнер — одновременные cd, мутации окружения и записи в один путь будут конфликтовать. Если субагенту нужна изолированная песочница, он должен зарегистрировать переопределение образа на свою задачу через register_task_env_overrides() — так автоматически делают среды RL и бенчмарков (TerminalBench2, HermesSweEnv и т.п.) для своих per-task Docker-образов.
Усиление безопасности:
--cap-drop ALL, обратно добавлены толькоDAC_OVERRIDE,CHOWN,FOWNER--security-opt no-new-privileges--pids-limit 256- Ограниченный по размеру tmpfs для
/tmp(512МБ),/var/tmp(256МБ),/run(64МБ)
Проброс учётных данных: Переменные окружения из docker_forward_env разрешаются сначала из вашего шелл-окружения, затем из ~/.hermes/.env. Навыки также могут объявлять required_environment_variables, которые подмешиваются автоматически.
Переопределение через переменные окружения
У каждого ключа под terminal: есть переопределение через переменную окружения вида TERMINAL_<КЛЮЧ_ЗАГЛАВНЫМИ>. Самые полезные для бэкенда Docker:
| Переменная окружения | Соответствует | Примечания |
|---|---|---|
TERMINAL_DOCKER_IMAGE | docker_image | Базовый образ |
TERMINAL_DOCKER_FORWARD_ENV | docker_forward_env | JSON-массив: '["GITHUB_TOKEN","OPENAI_API_KEY"]' |
TERMINAL_DOCKER_ENV | docker_env | JSON-словарь: '{"DEBUG":"1"}' |
TERMINAL_DOCKER_VOLUMES | docker_volumes | JSON-массив строк "host:container[:ro]" |
TERMINAL_DOCKER_EXTRA_ARGS | docker_extra_args | JSON-массив |
TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE | docker_mount_cwd_to_workspace | true / false |
TERMINAL_DOCKER_RUN_AS_HOST_USER | docker_run_as_host_user | true / false |
TERMINAL_DOCKER_PERSIST_ACROSS_PROCESSES | docker_persist_across_processes | true / false — по умолчанию true |
TERMINAL_DOCKER_ORPHAN_REAPER | docker_orphan_reaper | true / false — по умолчанию true |
TERMINAL_CONTAINER_CPU | container_cpu | Ядра CPU |
TERMINAL_CONTAINER_MEMORY | container_memory | МБ |
TERMINAL_CONTAINER_DISK | container_disk | МБ |
TERMINAL_CONTAINER_PERSISTENT | container_persistent | true / false — управляет каталогами bind-монтирования воркспейса, в отличие от docker_persist_across_processes |
TERMINAL_LIFETIME_SECONDS | lifetime_seconds | Окно сборщика по простою |
TERMINAL_TIMEOUT | timeout | Тайм-аут на одну команду |
HERMES_DOCKER_BINARY | нет | Принудительно задать путь к конкретному бинарю docker/podman |
Бэкенд SSH
Выполняет команды на удалённом сервере по SSH. Использует ControlMaster для переиспользования соединения (5-минутный keepalive по простою). Постоянный шелл включён по умолчанию — состояние (cwd, переменные окружения) переживает смену команд.
terminal:
backend: ssh
persistent_shell: true # Держать долгоживущую сессию bash (по умолчанию: true)
Обязательные переменные окружения:
TERMINAL_SSH_HOST=my-server.example.com
TERMINAL_SSH_USER=ubuntu
Необязательные:
| Переменная | По умолчанию | Описание |
|---|---|---|
TERMINAL_SSH_PORT | 22 | SSH-порт |
TERMINAL_SSH_KEY | (системный дефолт) | Путь к приватному SSH-ключу |
TERMINAL_SSH_PERSISTENT | true | Включить постоянный шелл |
Как это работает: Соединение устанавливается при инициализации с BatchMode=yes и StrictHostKeyChecking=accept-new. Постоянный шелл держит на удалённом хосте один живой процесс bash -l, общаясь с ним через временные файлы. Команды, которым нужен stdin_data или sudo, автоматически откатываются к разовому режиму.
Бэкенд Modal
Выполняет команды в облачной песочнице Modal. Каждая задача получает изолированную VM с настраиваемыми CPU, памятью и диском. Файловую систему можно снимать снапшотом и восстанавливать между сессиями.
terminal:
backend: modal
container_cpu: 1 # Ядра CPU
container_memory: 5120 # МБ (5ГБ)
container_disk: 51200 # МБ (50ГБ)
container_persistent: true # Снапшот/восстановление файловой системы
Обязательно: либо переменные окружения MODAL_TOKEN_ID + MODAL_TOKEN_SECRET, либо конфиг-файл ~/.modal.toml.
Сохранение состояния: Если включено, при очистке делается снапшот файловой системы песочницы, который восстанавливается в следующей сессии. Снапшоты отслеживаются в ~/.hermes/modal_snapshots.json. Сохраняется состояние файловой системы, но не живые процессы, PID-пространство или фоновые задачи.
Файлы с учётными данными: Автоматически монтируются из ~/.hermes/ (OAuth-токены и т.п.) и синхронизируются перед каждой командой.
Бэкенд Daytona
Выполняет команды в управляемом воркспейсе Daytona. Поддерживает stop/resume для сохранения состояния.
terminal:
backend: daytona
container_cpu: 1 # Ядра CPU
container_memory: 5120 # МБ → конвертируется в ГиБ
container_disk: 10240 # МБ → конвертируется в ГиБ (макс. 10 ГиБ)
container_persistent: true # Stop/resume вместо удаления
Обязательно: переменная окружения DAYTONA_API_KEY.
Сохранение состояния: Если включено, при очистке песочницы останавливаются (не удаляются) и возобновляются в следующей сессии. Имена песочниц следуют шаблону hermes-{task_id}.
Лимит диска: Daytona жёстко ограничивает максимум 10 ГиБ. Запросы сверх этого обрезаются с предупреждением.
Бэкенд Singularity/Apptainer
Выполняет команды в контейнере Singularity/Apptainer. Рассчитан на HPC-кластеры и общие машины, где Docker недоступен.
terminal:
backend: singularity
singularity_image: "docker://nikolaik/python-nodejs:python3.11-nodejs20"
container_cpu: 1 # Ядра CPU
container_memory: 5120 # МБ
container_persistent: true # Записываемый overlay сохраняется между сессиями
Требования: бинарь apptainer или singularity в $PATH.
Работа с образами: Docker-URL (docker://...) автоматически конвертируются в SIF-файлы и кэшируются. Существующие .sif-файлы используются напрямую.
Каталог для scratch: Разрешается по порядку: TERMINAL_SCRATCH_DIR → TERMINAL_SANDBOX_DIR/singularity → /scratch/$USER/hermes-agent (HPC-соглашение) → ~/.hermes/sandboxes/singularity.
Изоляция: Использует --containall --no-home для полной изоляции namespaces без монтирования домашнего каталога хоста.
Типичные проблемы с бэкендами терминала
Если команды терминала падают сразу же или инструмент терминала помечен как отключённый:
- Local — особых требований нет. Самый безопасный дефолт на старте.
- Docker — запустите
docker version, чтобы проверить, что Docker работает. Если падает, почините Docker или выполнитеhermes config set terminal.backend local. - SSH — должны быть заданы и
TERMINAL_SSH_HOST, иTERMINAL_SSH_USER. Если одной не хватает, Hermes пишет понятную ошибку. - Modal — нужна переменная окружения
MODAL_TOKEN_IDили~/.modal.toml. Для проверки запуститеhermes doctor. - Daytona — нужен
DAYTONA_API_KEY. Настройку URL сервера берёт на себя SDK Daytona. - Singularity — нужен
apptainerилиsingularityв$PATH. Обычное дело на HPC-кластерах.
Если сомневаетесь, верните terminal.backend на local и сначала убедитесь, что там команды выполняются.
Синхронизация файлов с удалённой машины на хост при сносе
Для бэкендов SSH, Modal и Daytona (везде, где рабочее дерево агента живёт на другой машине, чем хост с Hermes) Hermes отслеживает файлы, которые агент трогал внутри удалённой песочницы, и при сносе сессии / очистке песочницы синхронизирует изменённые файлы обратно на хост в каталог ~/.hermes/cache/remote-syncs/<session-id>/.
- Триггеры: закрытие сессии,
/new,/reset, тайм-аут сообщения шлюза, завершение субагентаdelegate_task, когда ребёнок использовал удалённый бэкенд. - Охватывает всё дерево, которое менял агент, а не только явно открытые файлы. Добавления, правки и удаления — всё попадает в синхронизацию.
- К моменту, когда вы соберётесь искать, удалённая песочница может быть уже снесена; локальная копия
~/.hermes/cache/remote-syncs/…— авторитетная запись того, что агент изменил. - Крупные бинарные выгрузки (чекпоинты моделей, сырые датасеты) ограничены по размеру — синхронизация пропускает файлы больше
file_sync_max_mb(по умолчанию100). Поднимите значение, если ждёте обратно более крупные артефакты.
terminal:
file_sync_max_mb: 100 # по умолчанию — синхронизировать файлы до 100 МБ каждый
file_sync_enabled: true # по умолчанию — поставьте false, чтобы вовсе пропустить синхронизацию
Так вы забираете результаты из эфемерных облачных песочниц, которые уничтожаются после окончания сессии, без необходимости просить агента вручную делать scp или modal volume put для каждого артефакта.
Монтирование томов Docker
При бэкенде Docker docker_volumes позволяет расшарить каталоги хоста с контейнером. Каждая запись использует стандартный синтаксис Docker -v: host_path:container_path[:options].
terminal:
backend: docker
docker_volumes:
- "/home/user/projects:/workspace/projects" # Чтение-запись (по умолчанию)
- "/home/user/datasets:/data:ro" # Только чтение
- "/home/user/.hermes/cache/documents:/output" # Экспорт, видимый шлюзу
Это полезно, чтобы:
- давать файлы агенту (датасеты, конфиги, эталонный код)
- получать файлы от агента (сгенерированный код, отчёты, экспорты)
- делить рабочие пространства, где и вы, и агент работаете с одними и теми же файлами
Если вы пользуетесь шлюзом сообщений и хотите, чтобы агент отправлял сгенерированные файлы через
MEDIA:/..., заведите отдельную видимую хосту точку монтирования для экспорта, например
/home/user/.hermes/cache/documents:/output.
- Пишите файлы внутри Docker в
/output/... - Указывайте путь хоста в
MEDIA:, например:MEDIA:/home/user/.hermes/cache/documents/report.txt - Не указывайте
/workspace/...или/output/..., если этот же путь не существует и для процесса шлюза на хосте
Дублирующиеся ключи в YAML тихо переопределяют предыдущие. Если у вас уже есть
блок docker_volumes:, добавляйте новые точки монтирования в тот же список,
а не заводите ещё один ключ docker_volumes: ниже в файле.
Можно задать и через переменную окружения: TERMINAL_DOCKER_VOLUMES='["/host:/container"]' (JSON-массив).
Проброс учётных данных в Docker
По умолчанию сессии терминала Docker не наследуют произвольные учётные данные хоста. Если внутри контейнера нужен конкретный токен, добавьте его в terminal.docker_forward_env.
terminal:
backend: docker
docker_forward_env:
- "GITHUB_TOKEN"
- "NPM_TOKEN"
Hermes разрешает каждую перечисленную переменную сначала из текущего шелла, затем откатывается к ~/.hermes/.env, если она была сохранена через hermes config set.
Всё, что перечислено в docker_forward_env, становится видимым командам внутри контейнера. Пробрасывайте только те учётные данные, которые не жалко открыть сессии терминала.
Запуск контейнера от имени хост-пользователя
По умолчанию контейнеры Docker работают от root (UID 0). Файлы, созданные внутри /workspace или других bind-монтирований, оказываются на хосте под root, так что после сессии приходится делать sudo chown, прежде чем редактировать их из хост-редактора. Флаг terminal.docker_run_as_host_user это исправляет:
terminal:
backend: docker
docker_run_as_host_user: true # по умолчанию: false
Когда включено, Hermes добавляет --user $(id -u):$(id -g) к команде docker run, и файлы, записанные в bind-монтированные каталоги (/workspace, /root, всё из docker_volumes), принадлежат вашему хост-пользователю, а не root. Цена компромисса: контейнер больше не может делать apt install или писать в принадлежащие root пути вроде /root/.npm — используйте базовый образ, чей HOME принадлежит не-root пользователю (либо добавьте нужный инструментарий на этапе сборки образа), если вам нужно и то, и другое.
Оставьте false (дефолт) для обратной совместимости. Включайте, когда ваш рабочий процесс — это в основном «редактировать смонтированные хост-файлы» и вы устали от sudo chown -R.
Опционально: смонтировать каталог запуска в /workspace
Песочницы Docker по умолчанию остаются изолированными. Hermes не пробрасывает ваш текущий рабочий каталог хоста в контейнер, пока вы явно это не разрешите.
Включается в config.yaml:
terminal:
backend: docker
docker_mount_cwd_to_workspace: true
Когда включено:
- если вы запускаете Hermes из
~/projects/my-app, этот каталог хоста монтируется (bind-mount) в/workspace - бэкенд Docker стартует в
/workspace - файловые инструменты и команды терминала видят один и тот же смонтированный проект
Когда выключено, /workspace остаётся за песочницей, пока вы явно не смонтируете что-нибудь через docker_volumes.
Компромисс по безопасности:
falseсохраняет границу песочницыtrueдаёт песочнице прямой доступ к каталогу, из которого вы запустили Hermes
Включайте этот опт-ин только тогда, когда осознанно хотите, чтобы контейнер работал с живыми файлами хоста.
Постоянный шелл
По умолчанию каждая команда терминала выполняется в своём подпроцессе — рабочий каталог, переменные окружения и shell-переменные сбрасываются между командами. Когда включён постоянный шелл, один долгоживущий процесс bash держится живым между вызовами execute(), и состояние переживает смену команд.
Полезнее всего это для бэкенда SSH, где вдобавок убирается накладной расход на установку соединения для каждой команды. Постоянный шелл включён по умолчанию для SSH и выключен для локального бэкенда.
terminal:
persistent_shell: true # по умолчанию — включает постоянный шелл для SSH
Чтобы отключить:
hermes config set terminal.persistent_shell false
Что переживает смену команд:
- Рабочий каталог (
cd /tmpдействует и для следующей команды) - Экспортированные переменные окружения (
export FOO=bar) - Shell-переменные (
MY_VAR=hello)
Приоритет:
| Уровень | Переменная | По умолчанию |
|---|---|---|
| Конфиг | terminal.persistent_shell | true |
| Переопределение SSH | TERMINAL_SSH_PERSISTENT | следует конфигу |
| Локальное переопределение | TERMINAL_LOCAL_PERSISTENT | false |
У переменных окружения на уровне бэкенда наивысший приоритет. Если хотите постоянный шелл и для локального бэкенда:
export TERMINAL_LOCAL_PERSISTENT=true
Команды, которым нужен stdin_data или sudo, автоматически откатываются к разовому режиму, поскольку stdin постоянного шелла уже занят IPC-протоколом.
Подробности по каждому бэкенду — в разделах Выполнение кода и Терминал в README.
Настройки навыков
Навыки могут объявлять собственные настройки конфигурации через frontmatter своего SKILL.md. Это несекретные значения (пути, предпочтения, доменные настройки), хранящиеся под пространством имён skills.config в config.yaml.
skills:
config:
myplugin:
path: ~/myplugin-data # Пример — каждый навык определяет свои ключи
Как работают настройки навыков:
hermes config migrateсканирует все включённые навыки, находит ненастроенные параметры и предлагает их заполнитьhermes config showпоказывает все настройки навыков под «Skill Settings» вместе с навыком, которому они принадлежат- При загрузке навыка его разрешённые значения конфигурации автоматически подставляются в контекст навыка
Задание значений вручную:
hermes config set skills.config.myplugin.path ~/myplugin-data
О том, как объявлять настройки конфигурации в собственных навыках, читайте в Создание навыков — Настройки конфигурации.
Защита при записи навыков, созданных агентом
Когда агент через skill_manage создаёт, редактирует, патчит или удаляет навык, Hermes может опционально сканировать новый/обновлённый контент на опасные паттерны ключевых слов (сбор учётных данных, явные промпт-инъекции, инструкции по эксфильтрации). Сканер по умолчанию выключен — реальные рабочие процессы агента, которые законно трогают ~/.ssh/ или упоминают $OPENAI_API_KEY, слишком часто срабатывали по этой эвристике. Включите обратно, если хотите, чтобы сканер спрашивал вас перед тем, как записи навыков от агента вступят в силу:
skills:
guard_agent_created: true # по умолчанию: false
Когда включено, любая помеченная запись skill_manage всплывает как запрос на подтверждение с обоснованием от сканера. Одобренные записи применяются; отклонённые возвращают агенту поясняющую ошибку.
Подтверждение записи навыков
Независимо от контентного сканера выше, skills.write_approval ставит каждую запись навыка агентом (создание / редактирование / патч / удаление / вспомогательные файлы) на ваше явное подтверждение — тот же механизм approve/deny, что и у опасных команд:
skills:
write_approval: false # false = писать свободно (по умолчанию) | true = выставлять каждую запись на ревью
Когда включено, записи навыков складываются в ~/.hermes/pending/skills/ и просматриваются через /skills pending, /skills diff <id>, /skills approve <id>, /skills reject <id> — из CLI или любой платформы сообщений. На лету переключается через /skills approval on|off. У памяти такой же затвор (memory.write_approval, ниже). Полный разбор — Затвор на запись навыков агентом.
Конфигурация памяти
memory:
memory_enabled: true
user_profile_enabled: true
memory_char_limit: 2200 # ~800 токенов
user_char_limit: 1375 # ~500 токенов
write_approval: false # true = требовать подтверждения перед любой записью в память
При memory.write_approval: true записи в память требуют вашего подтверждения, прежде чем вступят в силу: интерактивные ходы CLI спрашивают прямо на месте; сессии сообщений и фоновое ревью самоулучшения выставляют запись на просмотр через /memory pending → /memory approve <id> / /memory reject <id>. На лету переключается через /memory approval on|off. См. Контроль записей в память.
Обрезка контекстных файлов
Управляет тем, сколько контента Hermes загружает из каждого автоматического контекстного файла, прежде чем применить обрезку по началу/концу. Касается файлов, внедряемых в системный промпт: SOUL.md, .hermes.md, AGENTS.md, CLAUDE.md и .cursorrules. На инструмент read_file это не влияет.
context_file_max_chars: 20000 # по умолчанию
Поднимите, когда осознанно держите более крупные файлы идентичности или контекста проекта и работаете на моделях с контекстным окном, способным их вместить:
context_file_max_chars: 25000
Безопасность чтения файлов
Управляет тем, сколько контента может вернуть один вызов read_file. Чтения, превышающие лимит, отклоняются с ошибкой, в которой агенту предлагается использовать offset и limit для меньшего диапазона. Так одно чтение минифицированного JS-бандла или большого файла данных не зальёт контекстное окно.
file_read_max_chars: 100000 # по умолчанию — ~25–35К токенов
Поднимите значение, если работаете на модели с большим контекстным окном и часто читаете крупные файлы. Опустите для моделей с маленьким контекстом, чтобы чтения оставались экономными:
# Модель с большим контекстом (200К+)
file_read_max_chars: 200000
# Маленькая локальная модель (контекст 16К)
file_read_max_chars: 30000
Агент к тому же автоматически дедуплицирует чтения файлов — если один и тот же участок файла читается дважды, а файл не менялся, вместо повторной отправки контента возвращается лёгкая заглушка. Дедупликация сбрасывается при сжатии контекста, чтобы агент мог перечитать файлы после того, как их содержимое ушло в сводку.
Лимиты обрезки вывода инструментов
Три связанных ограничения управляют тем, сколько сырого вывода может вернуть инструмент, прежде чем Hermes его обрежет:
tool_output:
max_bytes: 50000 # лимит вывода терминала (символы)
max_lines: 2000 # лимит пагинации read_file
max_line_length: 2000 # лимит на строку в нумерованном виде read_file
max_bytes— когда командаterminalвыдаёт больше этого числа символов суммарного stdout/stderr, Hermes оставляет первые 40% и последние 60%, вставляя между ними пометку[OUTPUT TRUNCATED]. По умолчанию50000(≈12–15К токенов у типичных токенизаторов).max_lines— верхняя граница параметраlimitодного вызоваread_file. Запросы выше неё обрезаются, чтобы одно чтение не залило контекстное окно. По умолчанию2000.max_line_length— лимит на строку, применяемый, когдаread_fileвыдаёт нумерованный вид. Строки длиннее обрезаются до этого числа символов и завершаются... [truncated]. По умолчанию2000.
Поднимайте лимиты на моделях с большим контекстным окном, которые могут позволить больше сырого вывода на вызов. Опускайте для моделей с маленьким контекстом, чтобы результаты инструментов оставались компактными:
# Модель с большим контекстом (200К+)
tool_output:
max_bytes: 150000
max_lines: 5000
# Маленькая локальная модель (контекст 16К)
tool_output:
max_bytes: 20000
max_lines: 500
Глобальное отключение наборов инструментов
Чтобы погасить конкретные наборы инструментов сразу в CLI и на всех платформах шлюза в одном месте, перечислите их имена под agent.disabled_toolsets:
agent:
disabled_toolsets:
- memory # скрыть инструменты памяти + инъекцию MEMORY_GUIDANCE
- web # никаких web_search / web_extract нигде
Это применяется после конфигурации инструментов на платформу (platform_toolsets, записываемой hermes tools), так что перечисленный здесь набор инструментов всегда удаляется — даже если сохранённая конфигурация платформы всё ещё его указывает. Используйте, когда нужен один рубильник «выключить X везде», а не правка 15+ строк по платформам в интерфейсе hermes tools.
Пустой список или отсутствие ключа — это no-op.
Изоляция через git worktree
Включите изолированные git worktree для параллельного запуска нескольких агентов в одном репозитории:
worktree: true # Всегда создавать worktree (то же, что hermes -w)
# worktree: false # По умолчанию — только когда передан флаг -w
Когда включено, каждая CLI-сессия создаёт свежий worktree под .worktrees/ со своей веткой. Агенты могут редактировать файлы, коммитить, пушить и создавать PR, не мешая друг другу. Чистые worktree удаляются при выходе; грязные сохраняются для ручного восстановления.
Можно также перечислить gitignore-файлы для копирования в worktree через .worktreeinclude в корне репозитория:
# .worktreeinclude
.env
.venv/
node_modules/
Сжатие контекста
Hermes автоматически сжимает длинные диалоги, чтобы оставаться в пределах контекстного окна модели. Суммаризатор сжатия — это отдельный вызов LLM, и вы можете направить его на любой провайдер или эндпоинт.
Все настройки сжатия живут в config.yaml (без переменных окружения).
Полный справочник
compression:
enabled: true # Включить/выключить сжатие
threshold: 0.50 # Сжимать при этом % от лимита контекста
target_ratio: 0.20 # Доля порога, сохраняемая как недавний хвост
protect_last_n: 20 # Минимум недавних сообщений без сжатия
protect_first_n: 3 # Несистемные головные сообщения, закреплённые между компактификациями (0 = не закреплять)
hygiene_hard_message_limit: 400 # Аварийный клапан шлюза — см. ниже
# Модель/провайдер суммаризации настраивается под auxiliary:
auxiliary:
compression:
model: "" # Пусто = использовать основную чат-модель. Переопределите, например "google/gemini-3-flash-preview", ради более дешёвого/быстрого сжатия.
provider: "auto" # Провайдер: "auto", "openrouter", "nous", "codex", "main" и т.д.
base_url: null # Кастомный OpenAI-совместимый эндпоинт (перебивает провайдера)
Старые конфиги с compression.summary_model, compression.summary_provider и compression.summary_base_url автоматически мигрируют в auxiliary.compression.* при первой загрузке (версия конфига 17). Вручную ничего делать не нужно.
hygiene_hard_message_limit — это аварийный клапан перед сжатием, только для шлюза. Неуправляемые сессии с тысячами сообщений могут упереться в лимиты контекста модели раньше, чем сработает обычный порог в процентах от контекста; когда счётчик сообщений переваливает за этот потолок, Hermes принудительно запускает сжатие независимо от расхода токенов. По умолчанию 400 — поднимите для платформ, где очень длинные сессии в порядке вещей, опустите, чтобы форсировать более агрессивное сжатие. Правка этого значения на работающем шлюзе вступает в силу со следующим сообщением (см. ниже).
protect_first_n управляет тем, сколько несистемных головных сообщений закрепляется при каждой компактификации. По умолчанию 3 — открывающий обмен user/assistant переживает каждый проход суммаризатора, чтобы исходная цель оставалась на виду. На долгих сессиях со скользящей компактификацией, где открывающий ход уже не актуален, поставьте protect_first_n: 0, чтобы закреплять только системный промпт + сводку + хвост. Сам системный промпт сохраняется всегда, независимо от этой настройки.
Начиная с недавних релизов, правка model.context_length или любого ключа compression.* в config.yaml на работающем шлюзе вступает в силу со следующим сообщением — без перезапуска шлюза, без /reset, без ротации сессии. Сигнатура кэшированного агента включает эти ключи, поэтому шлюз прозрачно пересобирает агента, заметив изменение. API-ключам и конфигурации инструментов/навыков по-прежнему нужны обычные пути перезагрузки.
Типовые конфигурации
По умолчанию (автоопределение) — настраивать ничего не надо:
compression:
enabled: true
threshold: 0.50
Использует ваш основной провайдер и основную модель. Переопределите под задачу (например, auxiliary.compression.provider: openrouter + model: google/gemini-2.5-flash), если хотите сжимать на модели дешевле основной чат-модели.
Принудительно задать провайдера (на OAuth или API-ключе):
auxiliary:
compression:
provider: nous
model: gemini-3-flash
Работает с любым провайдером: nous, openrouter, codex, anthropic, main и т.д.
Кастомный эндпоинт (self-hosted, Ollama, zai, DeepSeek и т.д.):
auxiliary:
compression:
model: glm-4.7
base_url: https://api.z.ai/api/coding/paas/v4
Указывает на кастомный OpenAI-совместимый эндпоинт. Для аутентификации использует OPENAI_API_KEY.
Как взаимодействуют три параметра
auxiliary.compression.provider | auxiliary.compression.base_url | Результат |
|---|---|---|
auto (по умолчанию) | не задано | Автоопределение лучшего доступного провайдера |
nous / openrouter / и т.д. | не задано | Принудительно этот провайдер, его аутентификация |
| любой | задано | Использовать кастомный эндпоинт напрямую (провайдер игнорируется) |
У модели суммаризации обязательно контекстное окно не меньше, чем у основной модели агента. Компрессор отправляет модели суммаризации всю середину диалога — если её контекстное окно меньше, чем у основной модели, вызов суммаризации упадёт с ошибкой длины контекста. Когда это происходит, ходы из середины отбрасываются без сводки, и контекст диалога тихо теряется. Если переопределяете модель, проверьте, что её длина контекста не меньше, чем у вашей основной модели.
Движок контекста
Движок контекста управляет тем, как ведётся диалог при приближении к лимиту токенов модели. Встроенный движок compressor использует суммаризацию с потерями (см. Сжатие контекста). Движки-плагины могут заменить его альтернативными стратегиями.
context:
engine: "compressor" # по умолчанию — встроенная суммаризация с потерями
Чтобы использовать движок-плагин (например, LCM для управления контекстом без потерь):
context:
engine: "lcm" # должно совпадать с именем плагина
Движки-плагины никогда не активируются автоматически — нужно явно задать context.engine равным имени плагина. Доступные движки можно просмотреть и выбрать через hermes plugins → Provider Plugins → Context Engine.
Об аналогичной системе одиночного выбора для плагинов памяти см. Провайдеры памяти.
Давление лимита итераций
Когда агент работает над сложной задачей со множеством вызовов инструментов, он может выжечь свой лимит итераций (по умолчанию: 90 ходов), не осознавая, что подходит к концу. Давление лимита автоматически предупреждает модель по мере приближения к границе:
| Порог | Уровень | Что видит модель |
|---|---|---|
| 70% | Внимание | [BUDGET: 63/90. 27 iterations left. Start consolidating.] |
| 90% | Предупреждение | [BUDGET WARNING: 81/90. Only 9 left. Respond NOW.] |
Предупреждения внедряются в JSON последнего результата инструмента (как поле _budget_warning), а не как отдельные сообщения — так сохраняется кэширование промпта и не нарушается структура диалога.
agent:
max_turns: 90 # Макс. итераций на один ход диалога (по умолчанию: 90)
api_max_retries: 3 # Повторов на провайдера перед включением резервного (по умолчанию: 3)
Давление лимита включено по умолчанию. Агент видит предупреждения естественно, как часть результатов инструментов, и это подталкивает его консолидировать работу и выдать ответ, пока итерации не кончились.
Когда лимит итераций полностью исчерпан, CLI показывает пользователю уведомление: ⚠ Iteration budget reached (90/90) — response may be incomplete. Если лимит кончается во время активной работы, агент перед остановкой формирует сводку того, что успел сделать.
agent.api_max_retries управляет тем, сколько раз Hermes повторяет вызов API провайдера при временных ошибках (рейт-лимиты, обрывы соединения, 5xx), прежде чем включится переключение на резервного провайдера. По умолчанию 3 — итого четыре попытки. Если у вас настроены резервные провайдеры и вы хотите быстрее переключаться, опустите до 0, чтобы первая же временная ошибка на основном сразу передавала управление резервному, а не молотила повторами по нестабильному эндпоинту.
Тайм-ауты API
У Hermes есть отдельные слои тайм-аутов для потоковой передачи, плюс детектор зависаний для не-потоковых вызовов. Детекторы зависаний авто-подстраиваются под локальные провайдеры только тогда, когда вы оставляете их на неявных дефолтах.
| Тайм-аут | По умолчанию | Локальные провайдеры | Конфиг / env |
|---|---|---|---|
| Тайм-аут чтения сокета | 120с | Авто-поднят до 1800с | HERMES_STREAM_READ_TIMEOUT |
| Детект зависания потока | 180с | Авто-отключён | HERMES_STREAM_STALE_TIMEOUT |
| Детект зависания не-потока | 300с | Авто-отключён, если оставлен неявным | providers.<id>.stale_timeout_seconds или HERMES_API_CALL_STALE_TIMEOUT |
| Вызов API (не-потоковый) | 1800с | Без изменений | providers.<id>.request_timeout_seconds / timeout_seconds или HERMES_API_TIMEOUT |
Тайм-аут чтения сокета управляет тем, как долго httpx ждёт следующего куска данных от провайдера. Локальным LLM на больших контекстах префилл может занять минуты до первого токена, поэтому Hermes поднимает это до 30 минут, когда обнаруживает локальный эндпоинт. Если вы явно задаёте HERMES_STREAM_READ_TIMEOUT, это значение всегда используется независимо от определения эндпоинта.
Детект зависания потока убивает соединения, которые получают SSE keep-alive пинги, но не реальный контент. Для локальных провайдеров он полностью отключён, поскольку во время префилла они не шлют keep-alive пинги.
Детект зависания не-потока убивает не-потоковые вызовы, слишком долго не выдающие ответа. По умолчанию Hermes отключает его на локальных эндпоинтах, чтобы избежать ложных срабатываний при долгих префиллах. Если вы явно задаёте providers.<id>.stale_timeout_seconds, providers.<id>.models.<model>.stale_timeout_seconds или HERMES_API_CALL_STALE_TIMEOUT, это явное значение учитывается даже на локальных эндпоинтах.
Предупреждения о давлении контекста
Отдельно от давления лимита итераций давление контекста отслеживает, насколько диалог близок к порогу компактификации — точке, где срабатывает сжатие контекста и старые сообщения уходят в сводку. Это помогает и вам, и агенту понять, когда диалог разрастается.
| Прогресс | Уровень | Что происходит |
|---|---|---|
| ≥ 60% до порога | Инфо | CLI показывает голубую полосу прогресса; шлюз шлёт информационное уведомление |
| ≥ 85% до порога | Предупреждение | CLI показывает жирную жёлтую полосу; шлюз предупреждает, что компактификация близка |
В CLI давление контекста появляется как полоса прогресса в ленте вывода инструментов:
◐ context ████████████░░░░░░░░ 62% to compaction 48k threshold (50%) · approaching compaction
На платформах сообщений шлётся текстовое уведомление:
◐ Context: ████████████░░░░░░░░ 62% to compaction (threshold: 50% of window).
Если автосжатие отключено, предупреждение скажет вам, что контекст может вместо этого обрезаться.
Давление контекста работает автоматически — настраивать ничего не надо. Оно срабатывает чисто как уведомление для пользователя и не меняет поток сообщений и ничего не внедряет в контекст модели.
Стратегии пула учётных данных
Когда у вас несколько API-ключей или OAuth-токенов для одного провайдера, настройте стратегию ротации:
credential_pool_strategies:
openrouter: round_robin # ровно перебирать ключи по кругу
anthropic: least_used # всегда брать наименее использованный ключ
Варианты: fill_first (по умолчанию), round_robin, least_used, random. Полную документацию см. в Пулы учётных данных.
Кэширование промпта
Hermes автоматически включает межсессионное кэширование промпта, когда активный провайдер его поддерживает — пользовательской настройки не требуется.
Для Claude на нативном Anthropic, OpenRouter и Nous Portal Hermes навешивает точки cache_control с TTL в 1 час (ttl: "1h") на системный промпт и блоки навыков. Первая отправка внутри свежего часа оплачивается по полной входной ставке; последующие отправки в любой сессии в пределах того же часа берутся из кэша по сниженной ставке cached-read. Это значит, что системный промпт, загруженный контент навыков и начальная часть любого длинноконтекстного include переиспользуются между сессиями hermes и между разветвлёнными субагентами в течение первого часа.
Апстрим Qwen Cloud (Alibaba DashScope) ограничивает TTL кэша 5 минутами, поэтому там Hermes использует 5-минутный TTL точек кэша. Другие пути Claude-через-третью-сторону (AWS Bedrock, Azure Foundry) откатываются к собственным дефолтам кэширования провайдера. xAI Grok использует отдельный механизм с привязкой conversation-id к сессии — см. Кэширование промпта в xAI.
Отключить это нечем — кэширование всегда включено и экономит деньги даже на однораундовых диалогах, потому что один лишь системный промпт занимает заметную долю входных токенов.
Вспомогательные модели
Hermes использует «вспомогательные» (auxiliary) модели для побочных задач: анализ изображений, суммаризация веб-страниц, разбор скриншотов браузера, генерация заголовков сессий, сжатие контекста. По умолчанию (auxiliary.*.provider: "auto") Hermes направляет каждую вспомогательную задачу на вашу основную чат-модель — тот же провайдер/модель, что вы выбрали в hermes model. Чтобы начать, настраивать ничего не нужно, но учтите: на дорогих reasoning-моделях (Opus, MiniMax M2.7 и т.д.) вспомогательные задачи добавляют заметную стоимость. Если вы хотите дешёвые и быстрые побочные задачи независимо от основной модели, задайте auxiliary.<task>.provider и auxiliary.<task>.model явно (например, Gemini Flash на OpenRouter для зрения и веб-извлечения).
В ранних сборках пользователи агрегаторов (OpenRouter, Nous Portal) разводились на дешёвый дефолт со стороны провайдера. Это удивляло — люди, оплатившие подписку агрегатора, видели, что их вспомогательный трафик обрабатывает другая модель. Теперь auto использует основную модель для всех, а переопределения под задачу в config.yaml по-прежнему побеждают (см. Полный справочник вспомогательной конфигурации ниже).
Интерактивная настройка вспомогательных моделей
Вместо ручной правки YAML запустите hermes model и выберите в меню «Configure auxiliary models». Откроется интерактивный выбор по задачам:
$ hermes model
→ Configure auxiliary models
[ ] vision currently: auto / main model
[ ] web_extract currently: auto / main model
[ ] title_generation currently: openrouter / google/gemini-3-flash-preview
[ ] tts_audio_tags currently: auto / main model
[ ] compression currently: auto / main model
[ ] approval currently: auto / main model
[ ] triage_specifier currently: auto / main model
[ ] kanban_decomposer currently: auto / main model
[ ] profile_describer currently: auto / main model
Выберите задачу, выберите провайдера (OAuth-потоки открывают браузер; провайдеры на API-ключе спрашивают ключ), выберите модель. Изменение сохраняется в auxiliary.<task>.* в config.yaml. Та же механика, что и у выбора основной модели — никакого нового синтаксиса учить не надо.
Видеоурок
Универсальный паттерн конфигурации
Каждый слот модели в Hermes — вспомогательные задачи, сжатие, резерв — использует одни и те же три параметра:
| Ключ | Что делает | По умолчанию |
|---|---|---|
provider | Какой провайдер использовать для аутентификации и маршрутизации | "auto" |
model | Какую модель запрашивать | дефолт провайдера |
base_url | Кастомный OpenAI-совместимый эндпоинт (перебивает провайдера) | не задано |
Когда задан base_url, Hermes игнорирует провайдера и обращается к этому эндпоинту напрямую (используя api_key или OPENAI_API_KEY для аутентификации). Когда задан только provider, Hermes использует встроенную аутентификацию и базовый URL этого провайдера.
Доступные провайдеры для вспомогательных задач: auto, main, плюс любой провайдер из реестра провайдеров — openrouter, nous, openai-codex, copilot, copilot-acp, anthropic, gemini, google-gemini-cli, qwen-oauth, zai, kimi-coding, kimi-coding-cn, minimax, minimax-cn, minimax-oauth, deepseek, nvidia, xai, xai-oauth, ollama-cloud, alibaba, bedrock, huggingface, arcee, xiaomi, kilocode, opencode-zen, opencode-go, azure-foundry — либо любой именованный кастомный провайдер из вашего списка custom_providers (например, provider: "beans").
minimax-oauth входит через браузерный OAuth (API-ключ не нужен). Запустите hermes model и выберите MiniMax (OAuth) для аутентификации. Вспомогательные задачи автоматически используют MiniMax-M2.7-highspeed. См. руководство по MiniMax OAuth.
xai-oauth входит через браузерный OAuth для подписчиков SuperGrok и X Premium+ (API-ключ не нужен). Запустите hermes model и выберите xAI Grok OAuth (SuperGrok / Premium+) для аутентификации. Один и тот же OAuth-токен переиспользуется для всех прямых обращений к xAI (чат, вспомогательные задачи, TTS, генерация изображений, генерация видео, транскрипция). См. руководство по xAI Grok OAuth, а если Hermes на удалённом хосте — OAuth через SSH / удалённые хосты.
"main" — только для вспомогательных задач
Опция провайдера "main" означает «использовать тот провайдер, что использует мой основной агент» — она допустима только внутри auxiliary:, compression: и записей основного резерва (fallback_providers: или устаревший fallback_model:). Это не валидное значение для вашей верхнеуровневой настройки model.provider. Если используете кастомный OpenAI-совместимый эндпоинт, задайте provider: custom в секции model:. Все варианты провайдеров основной модели см. в Провайдеры ИИ.
Полный справочник вспомогательной конфигурации
auxiliary:
# Анализ изображений (инструмент vision_analyze + скриншоты браузера)
vision:
provider: "auto" # "auto", "openrouter", "nous", "codex", "main" и т.д.
model: "" # например "openai/gpt-4o", "google/gemini-2.5-flash"
base_url: "" # Кастомный OpenAI-совместимый эндпоинт (перебивает провайдера)
api_key: "" # API-ключ для base_url (откатывается к OPENAI_API_KEY)
timeout: 120 # секунды — тайм-аут вызова LLM API; vision-нагрузке нужен щедрый тайм-аут
download_timeout: 30 # секунды — HTTP-загрузка изображения; увеличьте для медленных соединений
# Суммаризация веб-страниц + извлечение текста страницы в браузере
web_extract:
provider: "auto"
model: "" # например "google/gemini-2.5-flash"
base_url: ""
api_key: ""
timeout: 360 # секунды (6 мин) — LLM-суммаризация на попытку
# Классификатор подтверждения опасных команд
approval:
provider: "auto"
model: ""
base_url: ""
api_key: ""
timeout: 30 # секунды
# Скрытая вставка аудио-тегов в Gemini 3.1 TTS
tts_audio_tags:
provider: "auto"
model: "" # пусто = основная чат-модель
base_url: ""
api_key: ""
timeout: 30
# Тайм-аут сжатия контекста (отдельно от конфигурации compression.*)
compression:
timeout: 120 # секунды — сжатие суммаризует длинные диалоги, нужно больше времени
# Skills hub — подбор и поиск навыков
skills_hub:
provider: "auto"
model: ""
base_url: ""
api_key: ""
timeout: 30
# Диспетчеризация инструментов MCP
mcp:
provider: "auto"
model: ""
base_url: ""
api_key: ""
timeout: 30
# Спецификатор триажа Kanban — `hermes kanban specify <id>` (или
# кнопка ✨ Specify на карточках колонки Triage в дашборде) использует
# этот слот, чтобы развернуть однострочник в конкретную спецификацию и
# продвинуть задачу в `todo`. Дешёвые быстрые модели тут хороши;
# разворот спецификации короткий и не требует глубины рассуждений.
triage_specifier:
provider: "auto"
model: ""
base_url: ""
api_key: ""
timeout: 120
У каждой вспомогательной задачи есть настраиваемый timeout (в секундах). Дефолты: vision 120с, web_extract 360с, approval 30с, compression 120с. Увеличьте их, если используете медленные локальные модели для вспомогательных задач. У vision есть и отдельный download_timeout (по умолчанию 30с) на HTTP-загрузку изображения — увеличьте его для медленных соединений или self-hosted серверов изображений.
У сжатия контекста есть собственный блок compression: для порогов и блок auxiliary.compression: для настроек модели/провайдера — см. Сжатие контекста выше. Основная цепочка резерва использует верхнеуровневый список fallback_providers: — см. Резервные провайдеры. Все три следуют одному паттерну provider/model/base_url.
Маршрутизация OpenRouter и Pareto Code для вспомогательных задач
Когда вспомогательная задача разрешается в OpenRouter (явно или через provider: "main", пока ваш основной агент на OpenRouter), настройки provider_routing и openrouter.min_coding_score основного агента не наследуются — так задумано, каждая вспомогательная задача независима. Чтобы задать предпочтения провайдеров OpenRouter или использовать роутер Pareto Code для конкретной вспомогательной задачи, задайте их на задачу через extra_body:
auxiliary:
compression:
provider: openrouter
model: openrouter/pareto-code # использовать роутер Pareto Code для этой задачи
extra_body:
provider: # предпочтения маршрутизации провайдеров OpenRouter
order: [anthropic, google] # пробовать этих провайдеров по порядку
sort: throughput # или "price" | "latency"
# only: [anthropic] # ограничить конкретным провайдером
# ignore: [deepinfra] # исключить конкретных провайдеров
plugins: # параметр роутера OpenRouter Pareto Code
- id: pareto-router
min_coding_score: 0.5 # 0.0–1.0; выше = более сильные кодеры
Форма повторяет то, что OpenRouter принимает в теле запроса chat completions. Hermes пробрасывает весь extra_body дословно, так что любое другое поле тела запроса OpenRouter, описанное на openrouter.ai/docs, работает так же.
Смена модели зрения
Чтобы для анализа изображений использовать GPT-4o вместо Gemini Flash:
auxiliary:
vision:
model: "openai/gpt-4o"
Или через переменную окружения (в ~/.hermes/.env):
AUXILIARY_VISION_MODEL=openai/gpt-4o
Варианты провайдеров
Эти варианты применяются к конфигурациям вспомогательных задач (auxiliary:, compression:) и записям основного резерва (fallback_providers: или устаревший fallback_model:), но не к вашей основной настройке model.provider.
| Провайдер | Описание | Требования |
|---|---|---|
"auto" | Лучший доступный (по умолчанию). Зрение пробует OpenRouter → Nous → Codex. | — |
"openrouter" | Принудительно OpenRouter — маршрутизирует к любой модели (Gemini, GPT-4o, Claude и т.д.) | OPENROUTER_API_KEY |
"nous" | Принудительно Nous Portal | hermes auth |
"codex" | Принудительно Codex OAuth (аккаунт ChatGPT). Поддерживает зрение (gpt-5.3-codex). | hermes model → Codex |
"minimax-oauth" | Принудительно MiniMax OAuth (вход через браузер, без API-ключа). Для вспомогательных задач использует MiniMax-M2.7-highspeed. | hermes model → MiniMax (OAuth) |
"xai-oauth" | Принудительно xAI Grok OAuth (вход через браузер для подписчиков SuperGrok или X Premium+, без API-ключа). Тот же OAuth-токен покрывает чат, TTS, изображения, видео и транскрипцию. | hermes model → xAI Grok OAuth (SuperGrok / Premium+) |
"main" | Использовать ваш активный кастомный/основной эндпоинт. Он может прийти из OPENAI_BASE_URL + OPENAI_API_KEY либо из кастомного эндпоинта, сохранённого через hermes model / config.yaml. Работает с OpenAI, локальными моделями или любым OpenAI-совместимым API. Только вспомогательные задачи — невалидно для model.provider. | Учётные данные кастомного эндпоинта + базовый URL |
Провайдеры на прямом API-ключе из основного каталога провайдеров тоже работают здесь, когда вы хотите, чтобы побочные задачи обходили ваш дефолтный роутер. gmi валиден, как только настроен GMI_API_KEY:
auxiliary:
compression:
provider: "gmi"
model: "anthropic/claude-opus-4.6"
Для маршрутизации вспомогательных задач через GMI используйте точный ID модели, который возвращает эндпоинт GMI /v1/models.
Типовые конфигурации
Использование прямого кастомного эндпоинта (понятнее, чем provider: "main", для локальных/self-hosted API):
auxiliary:
vision:
base_url: "http://localhost:1234/v1"
api_key: "local-key"
model: "qwen2.5-vl"
base_url имеет приоритет над provider, так что это самый явный способ направить вспомогательную задачу на конкретный эндпоинт. Для прямых переопределений эндпоинта Hermes использует заданный api_key либо откатывается к OPENAI_API_KEY; он не переиспользует OPENROUTER_API_KEY для этого кастомного эндпоинта.
Использование API-ключа OpenAI для зрения:
# В ~/.hermes/.env:
# OPENAI_BASE_URL=https://api.openai.com/v1
# OPENAI_API_KEY=sk-...
auxiliary:
vision:
provider: "main"
model: "gpt-4o" # или "gpt-4o-mini" подешевле
Использование OpenRouter для зрения (маршрут к любой модели):
auxiliary:
vision:
provider: "openrouter"
model: "openai/gpt-4o" # или "google/gemini-2.5-flash" и т.д.
Использование Codex OAuth (аккаунт ChatGPT Pro/Plus — API-ключ не нужен):
auxiliary:
vision:
provider: "codex" # использует ваш OAuth-токен ChatGPT
# модель по умолчанию gpt-5.3-codex (поддерживает зрение)
Использование MiniMax OAuth (вход через браузер, API-ключ не нужен):
model:
default: MiniMax-M2.7
provider: minimax-oauth
base_url: https://api.minimax.io/anthropic
Запустите hermes model и выберите MiniMax (OAuth), чтобы войти и задать это автоматически. Для региона Китая базовый URL будет https://api.minimaxi.com/anthropic. Полный разбор — в руководстве по MiniMax OAuth.
Использование локальной/self-hosted модели:
auxiliary:
vision:
provider: "main" # использует ваш активный кастомный эндпоинт
model: "my-local-model"
provider: "main" использует тот провайдер, что Hermes применяет для обычного чата — будь то именованный кастомный провайдер (например, beans), встроенный провайдер вроде openrouter или устаревший эндпоинт OPENAI_BASE_URL.
Если вы используете Codex OAuth как провайдера основной модели, зрение работает автоматически — дополнительной настройки не требуется. Codex входит в цепочку автоопределения для зрения.
Зрению нужна мультимодальная модель. Если задаёте provider: "main", убедитесь, что ваш эндпоинт поддерживает мультимодальность/зрение — иначе анализ изображений упадёт.
Переменные окружения (устаревшее)
Вспомогательные модели можно настроить и через переменные окружения. Однако config.yaml — предпочтительный метод: им проще управлять и он поддерживает все опции, включая base_url и api_key.
| Настройка | Переменная окружения |
|---|---|
| Провайдер зрения | AUXILIARY_VISION_PROVIDER |
| Модель зрения | AUXILIARY_VISION_MODEL |
| Эндпоинт зрения | AUXILIARY_VISION_BASE_URL |
| API-ключ зрения | AUXILIARY_VISION_API_KEY |
| Провайдер веб-извлечения | AUXILIARY_WEB_EXTRACT_PROVIDER |
| Модель веб-извлечения | AUXILIARY_WEB_EXTRACT_MODEL |
| Эндпоинт веб-извлечения | AUXILIARY_WEB_EXTRACT_BASE_URL |
| API-ключ веб-извлечения | AUXILIARY_WEB_EXTRACT_API_KEY |
Настройки сжатия и резервной модели задаются только в config.yaml.
Запустите hermes config, чтобы посмотреть текущие настройки вспомогательных моделей. Переопределения показываются, только когда отличаются от дефолтов.
Усилие рассуждений
Управляйте тем, сколько «думает» модель перед ответом:
agent:
reasoning_effort: "" # пусто = medium (по умолчанию). Опции: none, minimal, low, medium, high, xhigh (макс.)
Когда не задано (дефолт), усилие рассуждений равно «medium» — сбалансированный уровень, который хорошо подходит для большинства задач. Заданное значение его переопределяет: более высокое усилие даёт лучшие результаты на сложных задачах ценой большего числа токенов и задержки.
Эти модели используют адаптивное мышление и не принимают привычное поле
reasoning.effort — OpenRouter его для них игнорирует. Hermes прозрачно
направляет ваш reasoning_effort в параметр verbosity у OpenRouter (он
ложится на output_config.effort у Anthropic), так что тот же рычаг
low/medium/high/xhigh продолжает работать — никакой дополнительной
настройки не нужно. none (или незаданное) оставляет модель на её собственном
адаптивном дефолте. (max принимается на проводе, но не является выбираемым
значением reasoning_effort; настраиваемый потолок — xhigh.) Нативный
провайдер Anthropic и так управляет усилием напрямую, и его это не затрагивает.
Усилие рассуждений можно менять и на лету командой /reasoning:
/reasoning # Показать текущий уровень усилия и состояние отображения
/reasoning high # Задать усилие рассуждений high
/reasoning none # Отключить рассуждения
/reasoning show # Показывать размышления модели над каждым ответом
/reasoning hide # Скрыть размышления модели
Принуждение к использованию инструментов
Некоторые модели иногда описывают намеченные действия текстом вместо того, чтобы делать вызовы инструментов («Я бы запустил тесты…» вместо того, чтобы реально вызвать терминал). Принуждение к использованию инструментов внедряет в системный промпт указания, которые возвращают модель к реальным вызовам.
agent:
tool_use_enforcement: "auto" # "auto" | true | false | ["подстрока-модели", ...]
| Значение | Поведение |
|---|---|
"auto" (по умолчанию) | Включено для моделей, совпадающих с: gpt, codex, gemini, gemma, grok. Выключено для всех прочих (Claude, DeepSeek, Qwen и т.д.). |
true | Всегда включено, независимо от модели. Пригодится, если замечаете, что текущая модель описывает действия вместо их выполнения. |
false | Всегда выключено, независимо от модели. |
["gpt", "codex", "qwen", "llama"] | Включено, только когда имя модели содержит одну из перечисленных подстрок (без учёта регистра). |
Что именно внедряется
Когда включено, в системный промпт могут добавляться три слоя указаний:
-
Общее принуждение к использованию инструментов (все совпавшие модели) — велит модели делать вызовы инструментов сразу, а не описывать намерения, продолжать работу до завершения задачи и никогда не заканчивать ход обещанием будущего действия.
-
Дисциплина выполнения для OpenAI (только модели GPT и Codex) — дополнительные указания против специфичных для GPT сбоев: бросать работу на промежуточных результатах, пропускать предварительный поиск, галлюцинировать вместо использования инструментов и объявлять «готово» без проверки.
-
Операционные указания для Google (только модели Gemini и Gemma) — лаконичность, абсолютные пути, параллельные вызовы инструментов и паттерны «проверь перед правкой».
Это прозрачно для пользователя и затрагивает только системный промпт. Моделям, которые и так надёжно пользуются инструментами (вроде Claude), эти указания не нужны — потому "auto" их и исключает.
Когда стоит включить
Если вы используете модель не из дефолтного auto-списка и замечаете, что она часто описывает, что сделала бы, вместо того чтобы делать, поставьте tool_use_enforcement: true или добавьте подстроку модели в список:
agent:
tool_use_enforcement: ["gpt", "codex", "gemini", "grok", "my-custom-model"]
Конфигурация TTS
tts:
provider: "edge" # "edge" | "elevenlabs" | "openai" | "minimax" | "mistral" | "gemini" | "xai" | "neutts"
speed: 1.0 # Глобальный множитель скорости (запасной для всех провайдеров)
edge:
voice: "en-US-AriaNeural" # 322 голоса, 74 языка
speed: 1.0 # Множитель скорости (конвертируется в процент rate, например 1.5 → +50%)
elevenlabs:
voice_id: "pNInz6obpgDQGcFmaJgB"
model_id: "eleven_multilingual_v2"
openai:
model: "gpt-4o-mini-tts"
voice: "alloy" # alloy, echo, fable, onyx, nova, shimmer
speed: 1.0 # Множитель скорости (зажимается API в диапазон 0.25–4.0)
base_url: "https://api.openai.com/v1" # Переопределение для OpenAI-совместимых TTS-эндпоинтов
minimax:
speed: 1.0 # Множитель скорости речи
# base_url: "" # Опционально: переопределение для OpenAI-совместимых TTS-эндпоинтов
mistral:
model: "voxtral-mini-tts-2603"
voice_id: "c69964a6-ab8b-4f8a-9465-ec0925096ec8" # Paul - Neutral (по умолчанию)
gemini:
model: "gemini-2.5-flash-preview-tts" # или gemini-3.1-flash-tts-preview
voice: "Kore" # 30 готовых голосов: Zephyr, Puck, Kore, Enceladus и т.д.
audio_tags: false # Скрытая вставка аудио-тегов в Gemini 3.1 TTS
persona_prompt_file: "" # Опциональный Markdown/текстовый файл с указаниями для голоса Gemini
xai:
voice_id: "eve" # голос xAI TTS
language: "en" # ISO 639-1
sample_rate: 24000
bit_rate: 128000 # битрейт MP3
# base_url: "https://api.x.ai/v1"
neutts:
ref_audio: ''
ref_text: ''
model: neuphonic/neutts-air-q4-gguf
device: cpu
Это управляет и инструментом text_to_speech, и озвучкой ответов в голосовом режиме (/voice tts в CLI или шлюзе сообщений).
Иерархия запасной скорости: скорость конкретного провайдера (например, tts.edge.speed) → глобальная tts.speed → дефолт 1.0. Задайте глобальную tts.speed, чтобы применить единую скорость ко всем провайдерам, или переопределите на провайдера для тонкой настройки.
Настройки отображения
display:
tool_progress: all # off | new | all | verbose
tool_progress_command: false # Включить слэш-команду /verbose в шлюзе сообщений
platforms: {} # Переопределения отображения по платформам (см. ниже)
tool_progress_overrides: {} # УСТАРЕЛО — используйте display.platforms
interim_assistant_messages: true # Шлюз: слать естественные промежуточные обновления ассистента отдельными сообщениями
skin: default # Встроенный или кастомный скин CLI (см. user-guide/features/skins)
personality: "kawaii" # Устаревшее косметическое поле, всё ещё всплывающее в некоторых сводках
compact: false # Компактный режим вывода (меньше отступов)
resume_display: full # full (показать прошлые сообщения при возобновлении) | minimal (только однострочник)
bell_on_complete: false # Подать терминальный звонок по завершении агента (удобно для долгих задач)
show_reasoning: false # Показывать рассуждения/размышления модели над каждым ответом (переключается /reasoning show|hide)
streaming: false # Стримить токены в терминал по мере поступления (вывод в реальном времени)
show_cost: false # Показывать оценочную стоимость в $ в статус-баре CLI
timestamps: false # Когда true, перед метками user и assistant ставит таймстемпы [ЧЧ:ММ] в транскрипте CLI / TUI
tool_preview_length: 0 # Макс. символов для превью вызовов инструментов (0 = без лимита, показывать полные пути/команды)
runtime_footer: # Шлюз: добавлять футер с runtime-контекстом к финальным ответам
enabled: false
fields: ["model", "context_pct", "cwd"]
file_mutation_verifier: true # Добавлять предупреждающий футер, когда вызовы write_file/patch упали в этом ходе
credits_notices: true # Уведомления о статусе кредитов Nous в статус-баре (диапазоны расхода, грант потрачен, исчерпано). false = заглушить их; /usage всё равно работает
language: en # Язык UI для статических сообщений (запросы подтверждения, некоторые ответы шлюза). en | zh | zh-hant | ja | de | es | fr | tr | uk | af | ko | it | ga | pt | ru | hu
Верификатор мутации файлов
Когда display.file_mutation_verifier равно true (по умолчанию), Hermes добавляет к финальному ответу ассистента однострочное предупреждение, когда вызов write_file или patch упал в течение хода и не был перекрыт успешной записью по тому же пути. Это ловит класс завышенных заявлений «пачка параллельных патчей, половина тихо упала, модель отчиталась об успехе» без необходимости вручную запускать git status после каждой правки.
Пример футера:
⚠️ File-mutation verifier: 3 file(s) were NOT modified this turn despite any wording above that may suggest otherwise. Run `git status` or `read_file` to confirm.
• concepts/automatic-organization.md — [patch] Could not find match for old_string
• concepts/lora.md — [patch] Could not find match for old_string
• concepts/rag-pipeline.md — [patch] Could not find match for old_string
Задайте file_mutation_verifier: false (или HERMES_FILE_MUTATION_VERIFIER=0), чтобы погасить футер. Верификатор срабатывает, только когда к концу хода остаются реальные сбои — модель, которая повторяет упавший патч и в том же ходе добивается успеха, для этого файла его не вызовет.
Язык UI для статических сообщений
Настройка display.language переводит небольшой набор статических сообщений для пользователя — запрос подтверждения в CLI, горстку ответов на слэш-команды шлюза (например, уведомления о drain при перезапуске, «approval expired», «goal cleared»). Она не переводит ответы агента, строки логов, вывод инструментов, трейсбеки ошибок или описания слэш-команд — те остаются на английском. Если хотите, чтобы сам агент отвечал на другом языке, просто скажите об этом в промпте или системном сообщении.
Поддерживаемые значения: en (по умолчанию), zh (упрощённый китайский), zh-hant (традиционный китайский), ja (японский), de (немецкий), es (испанский), fr (французский), tr (турецкий), uk (украинский), af (африкаанс), ko (корейский), it (итальянский), ga (ирландский), pt (португальский), ru (русский), hu (венгерский). Неизвестные значения откатываются к английскому.
Это можно задать и на сессию через переменную окружения HERMES_LANGUAGE, которая перебивает значение конфига.
display:
language: zh # Запросы подтверждения CLI на китайском
| Режим | Что вы видите |
|---|---|
off | Тишина — только финальный ответ |
new | Индикатор инструмента, только когда инструмент меняется |
all | Каждый вызов инструмента с коротким превью (по умолчанию) |
verbose | Полные аргументы, результаты и отладочные логи |
В CLI переключайте эти режимы через /verbose. Чтобы пользоваться /verbose на платформах сообщений (Telegram, Discord, Slack и т.д.), задайте tool_progress_command: true в секции display выше. Команда будет переключать режим и сохранять его в конфиг.
Прогресс инструментов требует адаптера шлюза, способного безопасно показывать обновления прогресса. Платформы без поддержки редактирования сообщений, включая Signal, подавляют пузыри прогресса инструментов, даже если /verbose сохранил режим, отличный от off.
Футер с runtime-метаданными (только шлюз)
Когда display.runtime_footer.enabled: true, Hermes добавляет небольшой футер с runtime-контекстом к финальному сообщению каждого хода шлюза. Текущий футер умеет показывать модель, процент контекстного окна и текущий рабочий каталог. По умолчанию выключено; включайте на конкретный шлюз, если вашей команде нужно, чтобы каждый ответ содержал это происхождение.
display:
runtime_footer:
enabled: true
fields: ["model", "context_pct", "cwd"] # поддерживаемые поля: model, context_pct, cwd
Слэш-команда /footer переключает это на лету в любой сессии.
Пример футера, добавленного к ответу в Telegram/Discord/Slack:
— claude-opus-4.7 · 12 tool calls · 2m 14s · $0.042
Футер получает только финальное сообщение хода; промежуточные обновления остаются чистыми.
Переопределения прогресса по платформам
У разных платформ разные потребности в детализации. Используйте display.platforms, чтобы задать режимы по платформам:
display:
tool_progress: all # глобальный дефолт
platforms:
signal:
tool_progress: 'off' # Signal сейчас не умеет показывать пузыри прогресса инструментов
telegram:
tool_progress: verbose # подробный прогресс в Telegram
slack:
tool_progress: 'off' # тихо в общем воркспейсе Slack
Платформы без переопределения откатываются к глобальному значению tool_progress. Допустимые ключи платформ: telegram, discord, slack, signal, whatsapp, matrix, mattermost, email, sms, homeassistant, dingtalk, feishu, wecom, weixin, bluebubbles, qqbot. Устаревший ключ display.tool_progress_overrides всё ещё загружается ради обратной совместимости, но объявлен устаревшим и при первой загрузке мигрирует в display.platforms.
Signal указан как допустимый ключ платформы, потому что настройку можно сохранить на каждую платформу, но текущий адаптер Signal не умеет редактировать отправленные сообщения и не рисует пузыри прогресса инструментов. Держите tool_progress для Signal равным off; если нужно наблюдать за каждым вызовом инструмента вживую, используйте CLI или платформу сообщений с поддержкой редактирования.
interim_assistant_messages относится только к шлюзу. Когда включено, Hermes шлёт завершённые промежуточные обновления ассистента отдельными сообщениями чата. Это независимо от tool_progress и не требует стриминга шлюза.
Приватность
privacy:
redact_pii: false # Вычищать PII из контекста LLM (только шлюз)
Когда redact_pii равно true, шлюз вычищает персональные данные из системного промпта перед отправкой в LLM на поддерживаемых платформах:
| Поле | Обработка |
|---|---|
| Телефонные номера (ID пользователя в WhatsApp/Signal) | Хешируются в user_<12-символьный-sha256> |
| ID пользователей | Хешируются в user_<12-символьный-sha256> |
| ID чатов | Числовая часть хешируется, префикс платформы сохраняется (telegram:<hash>) |
| ID домашних каналов | Числовая часть хешируется |
| Имена / юзернеймы пользователей | Не затрагиваются (выбраны пользователем, публично видны) |
Поддержка платформ: Вычищение применяется к WhatsApp, Signal и Telegram. Discord и Slack исключены, потому что их системы упоминаний (<@user_id>) требуют реального ID в контексте LLM.
Хеши детерминированы — один и тот же пользователь всегда даёт один и тот же хеш, так что модель по-прежнему различает пользователей в групповых чатах. Маршрутизация и доставка внутри используют исходные значения.
Речь в текст (STT)
stt:
provider: "local" # "local" | "groq" | "openai" | "mistral"
local:
model: "base" # tiny, base, small, medium, large-v3
openai:
model: "whisper-1" # whisper-1 | gpt-4o-mini-transcribe | gpt-4o-transcribe
# model: "whisper-1" # Устаревший запасной ключ всё ещё учитывается
Поведение провайдеров:
localиспользуетfaster-whisper, работающий на вашей машине. Установите его отдельно:pip install faster-whisper.groqиспользует Whisper-совместимый эндпоинт Groq и читаетGROQ_API_KEY.openaiиспользует речевой API OpenAI и читаетVOICE_TOOLS_OPENAI_KEY.
Если запрошенный провайдер недоступен, Hermes откатывается автоматически в таком порядке: local → groq → openai.
Переопределения моделей Groq и OpenAI задаются через переменные окружения:
STT_GROQ_MODEL=whisper-large-v3-turbo
STT_OPENAI_MODEL=whisper-1
GROQ_BASE_URL=https://api.groq.com/openai/v1
STT_OPENAI_BASE_URL=https://api.openai.com/v1
Голосовой режим (CLI)
voice:
record_key: "ctrl+b" # Клавиша push-to-talk внутри CLI
max_recording_seconds: 120 # Жёсткий стоп для долгих записей
auto_tts: false # Автоматически включать озвучку ответов при /voice on
beep_enabled: true # Подавать сигналы старта/стопа записи в голосовом режиме CLI
silence_threshold: 200 # Порог RMS для детекции речи
silence_duration: 3.0 # Секунд тишины до автостопа
Используйте /voice on в CLI, чтобы включить режим микрофона, record_key — чтобы начать/остановить запись, и /voice tts — чтобы переключить озвучку ответов. Сквозную настройку и поведение по платформам см. в Голосовой режим.
Стриминг
Стримьте токены в терминал или на платформы сообщений по мере поступления, а не ждите полного ответа.
Стриминг в CLI
display:
streaming: true # Стримить токены в терминал в реальном времени
show_reasoning: true # Также стримить токены рассуждений/размышлений (опционально)
Когда включено, ответы появляются токен за токеном в окне стриминга. Вызовы инструментов по-прежнему фиксируются молча. Если провайдер не поддерживает стриминг, всё автоматически откатывается к обычному отображению.
Стриминг шлюза (Telegram, Discord, Slack)
streaming:
enabled: true # Включить прогрессивное редактирование сообщения
transport: edit # "edit" (прогрессивное редактирование сообщения) или "off"
edit_interval: 0.3 # Секунд между правками сообщения
buffer_threshold: 40 # Символов до принудительного сброса правки
cursor: " ▉" # Курсор, показываемый во время стриминга
fresh_final_after_seconds: 0 # Включить свежий финал (Telegram), когда превью настолько старое
Когда включено, бот шлёт сообщение по первому токену, затем прогрессивно редактирует его по мере поступления токенов. Платформы, не поддерживающие редактирование сообщений (Signal, Email, Home Assistant), определяются автоматически при первой попытке — стриминг для такой сессии аккуратно отключается без потока сообщений.
Для отдельных естественных промежуточных обновлений ассистента без прогрессивного редактирования токенов задайте display.interim_assistant_messages: true.
Обработка переполнения: Если стримящийся текст превышает лимит длины сообщения платформы (~4096 символов), текущее сообщение завершается, и автоматически начинается новое.
Свежий финал (Telegram): editMessageText в Telegram сохраняет исходный таймстемп сообщения, так что долгий стримящийся ответ удержал бы таймстемп первого токена даже после завершения. Задайте fresh_final_after_seconds > 0, чтобы включить доставку старых превью новыми финальными сообщениями с удалением превью по возможности. По умолчанию 0 — это всегда финализирует стримящиеся ответы на месте и избегает короткой связки «дубль сообщения + удаление» на клиентах, показывающих обе операции.
Главный рубильник streaming.enabled по умолчанию false — пока вы его не переключите, ничего не стримится. После включения стриминг решается на каждой платформе: Telegram идёт с display.platforms.telegram.streaming: true (стримит), а Discord — с display.platforms.discord.streaming: false (не стримит). Так что после включения стриминга Telegram стримит из коробки, а Discord остаётся на ответах целым сообщением, пока вы не поменяете его переключатель. Эти переключатели по платформам настраиваются из тумблеров Channels в дашборде или прямо в ~/.hermes/config.yaml.
Изоляция сессий в групповом чате
Ограничьте, сколько чат-сессий может быть активно открыто одновременно в CLI, TUI/дашборде и шлюзе сообщений:
max_concurrent_sessions: null # null/0 = без ограничений; целое положительное = лимит активных сессий
Когда лимит достигнут, Hermes отдаёт новым сессиям прямое сообщение о лимите. Уже активные сессии ведут себя как обычно.
Канонический ключ — верхнеуровневый max_concurrent_sessions. Hermes принимает
и gateway.max_concurrent_sessions как запасной вариант, но при заданных обоих
побеждает верхнеуровневый ключ.
Лимит держится через локальный runtime-файл аренды и работает по принципу
best-effort: если реестр не удаётся прочитать или заблокировать, Hermes
открывается (fail open), чтобы пользователи не застряли. Рассчитан на runtime
одного хоста/профиля, а не на общий $HERMES_HOME, смонтированный на нескольких
машинах.
Управляйте тем, держат ли общие чаты один диалог на комнату или один диалог на участника:
group_sessions_per_user: true # true = изоляция по пользователям в группах/каналах, false = одна общая сессия на чат
true— дефолт и рекомендуемая настройка. В каналах Discord, группах Telegram, каналах Slack и подобных общих контекстах каждый отправитель получает свою сессию, когда платформа предоставляет ID пользователя.falseвозвращает прежнее поведение «общая комната». Это может пригодиться, если вы осознанно хотите, чтобы Hermes относился к каналу как к одному совместному диалогу, но это также означает, что пользователи делят контекст, стоимость токенов и состояние прерывания.- Личные сообщения не затрагиваются. Hermes по-прежнему ключует DM по ID чата/DM как обычно.
- Треды в любом случае изолированы от родительского канала; при
trueкаждый участник внутри треда тоже получает свою сессию.
Детали поведения и примеры см. в Сессии и руководстве по Discord.
Поведение при неавторизованном DM
Управляйте тем, что Hermes делает, когда неизвестный пользователь шлёт личное сообщение:
unauthorized_dm_behavior: pair
whatsapp:
unauthorized_dm_behavior: ignore
pair— дефолт. Hermes отказывает в доступе, но отвечает в DM одноразовым кодом сопряжения.ignoreмолча отбрасывает неавторизованные DM.- Секции платформ перебивают глобальный дефолт, так что можно держать сопряжение включённым широко, при этом сделав одну платформу тише.
Быстрые команды
Определяйте кастомные команды, которые либо выполняют shell-команды без вызова LLM, либо превращают одну слэш-команду в алиас другой. Exec-быстрые команды нулевые по токенам и удобны с платформ сообщений (Telegram, Discord и т.д.) для быстрых проверок сервера или утилитных скриптов.
quick_commands:
status:
type: exec
command: systemctl status hermes-agent
disk:
type: exec
command: df -h /
update:
type: exec
command: cd ~/.hermes/hermes-agent && git pull && pip install -e .
gpu:
type: exec
command: nvidia-smi --query-gpu=name,utilization.gpu,memory.used,memory.total --format=csv,noheader
restart:
type: alias
target: /gateway restart
Использование: наберите /status, /disk, /update, /gpu или /restart в CLI или на любой платформе сообщений. Команды exec выполняются локально на хосте и возвращают вывод напрямую — без вызова LLM, без расхода токенов. Команды alias переписываются в настроенную целевую слэш-команду.
- Тайм-аут 30 секунд — долгие команды убиваются с сообщением об ошибке
- Приоритет — быстрые команды проверяются раньше команд навыков, так что можно переопределять имена навыков
- Автодополнение — быстрые команды разрешаются в момент диспетчеризации и не показываются во встроенных таблицах автодополнения слэш-команд
- Тип — поддерживаются типы
execиalias; другие типы показывают ошибку - Работает везде — CLI, Telegram, Discord, Slack, WhatsApp, Signal, Email, Home Assistant
Только-строковые промпт-сокращения не являются валидными быстрыми командами. Для переиспользуемых промпт-процессов создайте навык или алиас на существующую слэш-команду.
Человеческая задержка
Имитируйте человеческий темп ответов на платформах сообщений:
human_delay:
mode: "off" # off | natural | custom
min_ms: 800 # Минимальная задержка (режим custom)
max_ms: 2500 # Максимальная задержка (режим custom)
Выполнение кода
Настройка инструмента execute_code:
code_execution:
mode: project # project (по умолчанию) | strict
timeout: 300 # Макс. время выполнения в секундах
max_tool_calls: 50 # Макс. вызовов инструментов внутри выполнения кода
mode управляет рабочим каталогом и интерпретатором Python для скриптов:
project(по умолчанию) — скрипты выполняются в рабочем каталоге сессии с python из активного virtualenv/conda-окружения. Зависимости проекта (pandas,torch, пакеты проекта) и относительные пути (.env,./data.csv) разрешаются естественно, как их видитterminal().strict— скрипты выполняются во временном staging-каталоге сsys.executable(собственный python Hermes). Максимальная воспроизводимость, но зависимости проекта и относительные пути не разрешатся.
Чистка окружения (вырезает *_API_KEY, *_TOKEN, *_SECRET, *_PASSWORD, *_CREDENTIAL, *_PASSWD, *_AUTH) и белый список инструментов применяются одинаково в обоих режимах — смена режима не меняет уровень безопасности.
Бэкенды веб-поиска
Инструменты web_search и web_extract поддерживают пять бэкенд-провайдеров. Настройте бэкенд в config.yaml или через hermes tools:
web:
backend: firecrawl # firecrawl | searxng | parallel | tavily | exa
# Или используйте ключи на каждую способность, чтобы смешивать провайдеров (например, бесплатный поиск + платное извлечение):
search_backend: "searxng"
extract_backend: "firecrawl"
| Бэкенд | Переменная окружения | Поиск | Извлечение |
|---|---|---|---|
| Firecrawl (по умолчанию) | FIRECRAWL_API_KEY | ✔ | ✔ |
| SearXNG | SEARXNG_URL | ✔ | — |
| Parallel | PARALLEL_API_KEY | ✔ | ✔ |
| Tavily | TAVILY_API_KEY | ✔ | ✔ |
| Exa | EXA_API_KEY | ✔ | ✔ |
Выбор бэкенда: Если web.backend не задан, бэкенд автоопределяется по доступным API-ключам. Если задан только SEARXNG_URL, используется SearXNG. Если только EXA_API_KEY — Exa. Если только TAVILY_API_KEY — Tavily. Если только PARALLEL_API_KEY — Parallel. Иначе по умолчанию Firecrawl.
SearXNG — это бесплатный self-hosted метапоисковик, уважающий приватность, который опрашивает 70+ поисковых движков. API-ключ не нужен — просто задайте SEARXNG_URL на ваш инстанс (например, http://localhost:8080). SearXNG умеет только поиск; для web_extract нужен отдельный провайдер извлечения (задайте web.extract_backend). Инструкции по настройке Docker см. в руководстве по настройке веб-поиска.
Self-hosted Firecrawl: Задайте FIRECRAWL_API_URL, указав на свой инстанс. Когда задан кастомный URL, API-ключ становится необязательным (задайте `USE_DB_AUTHENTICATION=*** на сервере, чтобы отключить аутентификацию).
Режимы поиска Parallel: Задайте PARALLEL_SEARCH_MODE, чтобы управлять поведением поиска — fast, one-shot или agentic (по умолчанию: agentic).
Exa: Задайте EXA_API_KEY в ~/.hermes/.env. Поддерживает фильтрацию по category (company, research paper, news, people, personal site, pdf) и фильтры по домену/дате.
Браузер
Настройка поведения браузерной автоматизации:
browser:
inactivity_timeout: 120 # Секунд до автозакрытия простаивающих сессий
command_timeout: 30 # Тайм-аут в секундах для команд браузера (скриншот, навигация и т.д.)
record_sessions: false # Автозапись сессий браузера в WebM-видео в ~/.hermes/browser_recordings/
# Опциональное переопределение CDP — когда задано, Hermes подключается напрямую к вашему
# браузеру семейства Chromium (через /browser connect), а не запускает headless-браузер.
cdp_url: ""
# Супервизор диалогов — управляет тем, как обрабатываются нативные JS-диалоги (alert / confirm / prompt),
# когда подключён CDP-бэкенд (Browserbase, локальный браузер семейства Chromium
# через /browser connect). Игнорируется на Camofox и в локальном режиме agent-browser по умолчанию.
dialog_policy: must_respond # must_respond | auto_dismiss | auto_accept
dialog_timeout_s: 300 # Аварийный авто-dismiss при must_respond (секунды)
camofox:
managed_persistence: false # Когда true, сессии Camofox сохраняют cookie/логины между перезапусками
user_id: "" # Опциональный внешне управляемый userId для Camofox
session_key: "" # Опциональный session key, отправляемый при создании вкладки в Hermes
adopt_existing_tab: false # Переиспользовать существующую вкладку для этой идентичности перед созданием новой
Политики диалогов:
must_respond(по умолчанию) — захватить диалог, вывести его вbrowser_snapshot.pending_dialogsи ждать, пока агент вызоветbrowser_dialog(action=...). Послеdialog_timeout_sсекунд без ответа диалог авто-dismiss’ится, чтобы JS-поток страницы не завис навсегда.auto_dismiss— захватить, сразу закрыть. Агент всё равно увидит запись о диалоге вbrowser_snapshot.recent_dialogsсо значениемclosed_by="auto_policy"постфактум.auto_accept— захватить, сразу принять. Полезно для страниц с агрессивными запросамиbeforeunload.
Полный процесс работы с диалогами см. на странице о функции браузера.
Набор инструментов браузера поддерживает несколько провайдеров. Подробности о Browserbase, Browser Use и локальной настройке CDP для браузеров семейства Chromium см. на странице о функции браузера.
Часовой пояс
Переопределите серверный локальный часовой пояс строкой IANA-таймзоны. Влияет на таймстемпы в логах, планирование cron и инъекцию времени в системный промпт.
timezone: "America/New_York" # IANA-таймзона (по умолчанию: "" = серверное локальное время)
Поддерживаемые значения: любой идентификатор IANA-таймзоны (например, America/New_York, Europe/London, Asia/Kolkata, UTC). Оставьте пустым или опустите для серверного локального времени.
Discord
Настройка специфичного для Discord поведения шлюза сообщений:
discord:
require_mention: true # Требовать @mention для ответа в каналах сервера
free_response_channels: "" # ID каналов через запятую, где бот отвечает без @mention
auto_thread: true # Автосоздание тредов при @mention в каналах
require_mention— когдаtrue(по умолчанию), бот отвечает в каналах сервера, только когда упомянут через@BotName. DM всегда работают без упоминания.free_response_channels— список ID каналов через запятую, где бот отвечает на каждое сообщение без требования упоминания.auto_thread— когдаtrue(по умолчанию), упоминания в каналах автоматически создают тред для диалога, сохраняя каналы чистыми (похоже на тредирование в Slack).
Безопасность
Сканирование безопасности перед выполнением и затирание секретов:
security:
redact_secrets: true # Затирать паттерны API-ключей в выводе инструментов и логах (по умолчанию включено)
tirith_enabled: true # Включить сканирование безопасности Tirith для команд терминала
tirith_path: "tirith" # Путь к бинарю tirith (по умолчанию: "tirith" в $PATH)
tirith_timeout: 5 # Секунд ожидания сканирования tirith до тайм-аута
tirith_fail_open: true # Разрешать выполнение команды, если tirith недоступен
website_blocklist: # См. раздел «Чёрный список сайтов» ниже
enabled: false
domains: []
shared_files: []
redact_secrets— когдаtrue, автоматически обнаруживает и затирает паттерны, похожие на API-ключи, токены и пароли, в выводе инструментов, прежде чем он попадёт в контекст диалога и логи. По умолчанию включено. Ставьтеfalseявно только тогда, когда вам нужны сырые строки, похожие на учётные данные, для отладки или разработки редактора затирания.tirith_enabled— когдаtrue, команды терминала сканируются Tirith перед выполнением для обнаружения потенциально опасных операций.tirith_path— путь к бинарю tirith. Задайте, если tirith установлен в нестандартном месте.tirith_timeout— максимум секунд ожидания сканирования tirith. Команды продолжаются, если сканирование выходит за тайм-аут.tirith_fail_open— когдаtrue(по умолчанию), командам разрешается выполняться, если tirith недоступен или падает. Поставьтеfalse, чтобы блокировать команды, когда tirith не может их проверить.
Чёрный список сайтов
Блокируйте конкретные домены от доступа веб- и браузерными инструментами агента:
security:
website_blocklist:
enabled: false # Включить блокировку URL (по умолчанию: false)
domains: # Список заблокированных паттернов доменов
- "*.internal.company.com"
- "admin.example.com"
- "*.local"
shared_files: # Загружать дополнительные правила из внешних файлов
- "/etc/hermes/blocked-sites.txt"
Когда включено, любой URL, совпадающий с паттерном заблокированного домена, отклоняется до того, как сработает веб- или браузерный инструмент. Это применяется к web_search, web_extract, browser_navigate и любому инструменту, обращающемуся к URL.
Правила доменов поддерживают:
- Точные домены:
admin.example.com - Wildcard-поддомены:
*.internal.company.com(блокирует все поддомены) - Wildcard по TLD:
*.local
Общие файлы содержат по одному правилу домена на строку (пустые строки и комментарии # игнорируются). Отсутствующие или нечитаемые файлы пишут предупреждение, но не отключают остальные веб-инструменты.
Политика кэшируется на 30 секунд, поэтому изменения конфига вступают в силу быстро, без перезапуска.
Умные подтверждения
Управляйте тем, как Hermes обрабатывает потенциально опасные команды:
approvals:
mode: manual # manual | smart | off
| Режим | Поведение |
|---|---|
manual (по умолчанию) | Спрашивать пользователя перед выполнением любой помеченной команды. В CLI показывает интерактивный диалог подтверждения. В сообщениях ставит запрос подтверждения в очередь. |
smart | Использовать вспомогательную LLM для оценки, действительно ли помеченная команда опасна. Низкорисковые команды авто-одобряются с сохранением на уровне сессии. По-настоящему рискованные эскалируются пользователю. |
off | Пропускать все проверки подтверждения. Эквивалент HERMES_YOLO_MODE=true. Используйте с осторожностью. |
Режим smart особенно полезен для снижения усталости от подтверждений — он даёт агенту работать автономнее на безопасных операциях, по-прежнему отлавливая по-настоящему разрушительные команды.
Установка approvals.mode: off отключает все проверки безопасности для команд терминала. Используйте это только в доверенных, изолированных средах.
Контрольные точки
Автоматические снапшоты файловой системы перед разрушительными файловыми операциями. Подробности см. в Контрольные точки и откат.
checkpoints:
enabled: false # Включить автоматические контрольные точки (также: hermes chat --checkpoints). По умолчанию: false (opt-in).
max_snapshots: 20 # Макс. контрольных точек на каталог (по умолчанию: 20)
Делегирование
Настройка поведения субагентов для инструмента делегирования:
delegation:
# model: "google/gemini-3-flash-preview" # Переопределить модель (пусто = наследовать родителя)
# provider: "openrouter" # Переопределить провайдера (пусто = наследовать родителя)
# base_url: "http://localhost:1234/v1" # Прямой OpenAI-совместимый эндпоинт (приоритетнее провайдера)
# api_key: "local-key" # API-ключ для base_url (откатывается к OPENAI_API_KEY)
# api_mode: "" # Wire-протокол для base_url: "chat_completions", "codex_responses" или "anthropic_messages". Пусто = автоопределение по URL (например, суффикс /anthropic → anthropic_messages). Задайте явно для нестандартных эндпоинтов, которые эвристика не определяет.
max_concurrent_children: 3 # Параллельных детей на пакет (минимум 1, без потолка). Также через переменную DELEGATION_MAX_CONCURRENT_CHILDREN.
max_spawn_depth: 1 # Потолок глубины дерева делегирования (1–3, зажимается). 1 = плоско (по умолчанию): родитель порождает листья, которые не могут делегировать. 2 = дети-оркестраторы могут порождать листья-внуков. 3 = три уровня.
orchestrator_enabled: true # Глобальный рубильник. Когда false, role="orchestrator" игнорируется, и каждый ребёнок принудительно становится листом независимо от max_spawn_depth.
Переопределение provider:model для субагента: По умолчанию субагенты наследуют провайдера и модель родительского агента. Задайте delegation.provider и delegation.model, чтобы направить субагентов на другую пару provider:model — например, использовать дешёвую/быструю модель для узкоспециализированных подзадач, пока ваш основной агент работает на дорогой reasoning-модели.
Прямое переопределение эндпоинта: Если хотите очевидный путь к кастомному эндпоинту, задайте delegation.base_url, delegation.api_key и delegation.model. Это отправляет субагентов напрямую на этот OpenAI-совместимый эндпоинт и имеет приоритет над delegation.provider. Если delegation.api_key опущен, Hermes откатывается только к OPENAI_API_KEY.
Wire-протокол (api_mode): Hermes автоопределяет wire-протокол по delegation.base_url (например, пути, заканчивающиеся на /anthropic → anthropic_messages; хостнеймы Codex / нативный Anthropic / Kimi-coding сохраняют своё определение). Для эндпоинтов, которые эвристика не может классифицировать, — например, Azure AI Foundry, MiniMax, Zhipu GLM или прокси LiteLLM перед бэкендом в форме Anthropic — задайте delegation.api_mode явно одним из chat_completions, codex_responses или anthropic_messages. Оставьте пустым (дефолт), чтобы сохранить автоопределение.
Провайдер делегирования использует то же разрешение учётных данных, что и старт CLI/шлюза. Поддерживаются все настроенные провайдеры: openrouter, nous, copilot, zai, kimi-coding, minimax, minimax-cn. Когда провайдер задан, система автоматически разрешает правильный базовый URL, API-ключ и API-режим — ручная привязка учётных данных не нужна.
Приоритет: delegation.base_url в конфиге → delegation.provider в конфиге → провайдер родителя (унаследован). delegation.model в конфиге → модель родителя (унаследована). Задание только model без provider меняет лишь имя модели, сохраняя учётные данные родителя (удобно для переключения моделей внутри одного провайдера вроде OpenRouter).
Ширина и глубина: max_concurrent_children ограничивает, сколько субагентов работает параллельно в одном пакете (по умолчанию 3, минимум 1, без потолка). Можно задать и через переменную окружения DELEGATION_MAX_CONCURRENT_CHILDREN. Когда модель отправляет массив tasks длиннее лимита, delegate_task возвращает ошибку инструмента с пояснением лимита, а не тихо обрезает. max_spawn_depth управляет глубиной дерева делегирования (зажимается в 1–3). При дефолте 1 делегирование плоское: дети не могут порождать внуков, а передача role="orchestrator" тихо понижается до leaf. Поднимите до 2, чтобы дети-оркестраторы могли порождать листья-внуков; 3 — для трёхуровневых деревьев. Агент включает оркестрацию на каждый вызов через role="orchestrator"; orchestrator_enabled: false принудительно возвращает каждого ребёнка к листу. Стоимость растёт мультипликативно — при max_spawn_depth: 3 с max_concurrent_children: 3 дерево может достичь 3×3×3 = 27 одновременных листовых агентов. Паттерны использования см. в Делегирование субагентам → Лимит глубины и вложенная оркестрация.
Уточнение
Настройка поведения промпта уточнения:
clarify:
timeout: 120 # Секунд ожидания ответа пользователя на уточнение
Контекстные файлы (SOUL.md, AGENTS.md)
Hermes использует два разных контекстных охвата:
| Файл | Назначение | Охват |
|---|---|---|
SOUL.md | Основная идентичность агента — определяет, кто такой агент (слот №1 в системном промпте) | ~/.hermes/SOUL.md или $HERMES_HOME/SOUL.md |
.hermes.md / HERMES.md | Инструкции для конкретного проекта (наивысший приоритет) | Идёт вверх до корня git |
AGENTS.md | Инструкции для конкретного проекта, соглашения по коду | Рекурсивный обход каталогов |
CLAUDE.md | Контекстные файлы Claude Code (тоже обнаруживаются) | Только рабочий каталог |
.cursorrules | Правила Cursor IDE (тоже обнаруживаются) | Только рабочий каталог |
.cursor/rules/*.mdc | Файлы правил Cursor (тоже обнаруживаются) | Только рабочий каталог |
- SOUL.md — основная идентичность агента. Он занимает слот №1 в системном промпте, полностью заменяя встроенную идентичность по умолчанию. Отредактируйте его, чтобы полностью настроить, кто такой агент.
- Если SOUL.md отсутствует, пуст или не загружается, Hermes откатывается к встроенной идентичности по умолчанию.
- Проектные контекстные файлы используют систему приоритетов — загружается только ОДИН тип (побеждает первое совпадение):
.hermes.md→AGENTS.md→CLAUDE.md→.cursorrules. SOUL.md всегда загружается независимо. - AGENTS.md иерархичен: если в подкаталогах тоже есть AGENTS.md, все они объединяются.
- Hermes автоматически создаёт стартовый
SOUL.md, если его ещё нет. - Все загруженные контекстные файлы ограничены
context_file_max_charsсимволами (по умолчанию 20 000) с умной обрезкой.
См. также:
Рабочий каталог
| Контекст | По умолчанию |
|---|---|
CLI (hermes) | Текущий каталог, где вы запускаете команду |
| Шлюз сообщений | terminal.cwd из ~/.hermes/config.yaml; если не задан — домашний каталог ~ |
| Docker / Singularity / Modal / SSH | Домашний каталог пользователя внутри контейнера или на удалённой машине |
Переопределение рабочего каталога:
# В ~/.hermes/config.yaml:
terminal:
cwd: /home/myuser/projects
MESSAGING_CWD и прямые записи TERMINAL_CWD в ~/.hermes/.env — устаревшие запасные варианты для совместимости. Новые конфигурации должны использовать terminal.cwd.