Setup
На этой странице
Hermes Agent распространяется как Nix-флейк с тремя уровнями интеграции:
Уровень| Для кого| Что вы получаете
---|---|---
nix run / nix profile install| Любой пользователь Nix (macOS, Linux)| Предварительно собранный бинарник со всеми зависимостями — далее используется стандартный CLI-процесс
Модуль NixOS (нативный)| Серверные развёртывания NixOS| Декларативная конфигурация, усиленный systemd-сервис, управляемые секреты
Модуль NixOS (контейнер)| Агенты, которым нужна самомодификация| Всё вышеперечисленное, плюс постоянный Ubuntu-контейнер, где агент может выполнять apt/pip/npm install
Чем отличается от стандартной установки
Установщик curl | bash сам управляет Python, Node и зависимостями. Nix-флейк заменяет всё это — каждая Python-зависимость является Nix-деривацией, собранной с помощью uv2nix, а инструменты времени выполнения (Node.js, git, ripgrep, ffmpeg) встроены в PATH бинарника. Нет runtime pip, нет активации venv, нет npm install.
Для пользователей не-NixOS это меняет только шаг установки. Всё остальное (hermes setup, hermes gateway install, редактирование конфигурации) работает идентично стандартной установке.
Для пользователей модуля NixOS весь жизненный цикл отличается: конфигурация находится в configuration.nix, секреты передаются через sops-nix/agenix, сервис является systemd-юнитом, а CLI-команды конфигурации заблокированы. Вы управляете hermes так же, как любым другим NixOS-сервисом.
Предварительные требования¶
- Nix с включёнными флейками — рекомендуется Determinate Nix (включает флейки по умолчанию)
- API-ключи для сервисов, которые вы планируете использовать (как минимум: ключ OpenRouter или Anthropic)
Быстрый старт (любой пользователь Nix)¶
Клонирование не требуется. Nix загружает, собирает и запускает всё:
[code]
# Запустить напрямую (сборка при первом использовании, далее кэшируется)
nix run github:NousResearch/hermes-agent -- setup
nix run github:NousResearch/hermes-agent -- chat
# Или установить постоянно
nix profile install github:NousResearch/hermes-agent
hermes setup
hermes chat
[/code]
После nix profile install команды hermes, hermes-agent и hermes-acp оказываются в вашем PATH. Отсюда процесс идентичен стандартной установке — hermes setup проведёт вас через выбор провайдера, hermes gateway install настраивает launchd (macOS) или systemd-сервис пользователя, а конфигурация хранится в ~/.hermes/.
Сборка из локального клона
[code]
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
nix build
./result/bin/hermes setup
[/code]
Модуль NixOS¶
Флейк экспортирует nixosModules.default — полноценный модуль NixOS-сервиса, который декларативно управляет созданием пользователя, директориями, генерацией конфигурации, секретами, документами и жизненным циклом сервиса.
note
Этот модуль требует NixOS. Для систем не-NixOS (macOS, другие дистрибутивы Linux) используйте nix profile install и стандартный CLI-процесс, описанный выше.
Добавление флейк-входа¶
[code]
# /etc/nixos/flake.nix (или ваш системный флейк)
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
hermes-agent.url = "github:NousResearch/hermes-agent";
};
outputs = { nixpkgs, hermes-agent, ... }: {
nixosConfigurations.your-host = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
hermes-agent.nixosModules.default
./configuration.nix
];
};
};
}
[/code]
Минимальная конфигурация¶
[code]
# configuration.nix
{ config, ... }: {
services.hermes-agent = {
enable = true;
settings.model.default = "anthropic/claude-sonnet-4";
environmentFiles = [ config.sops.secrets."hermes-env".path ];
addToSystemPackages = true;
};
}
[/code]
Вот и всё. nixos-rebuild switch создаёт пользователя hermes, генерирует config.yaml, подключает секреты и запускает шлюз — долгоживущий сервис, который соединяет агента с платформами обмена сообщениями (Telegram, Discord и т.д.) и слушает входящие сообщения.
Секреты обязательны
Строка environmentFiles выше предполагает, что у вас настроен sops-nix или agenix. Файл должен содержать как минимум один ключ LLM-провайдера (например, OPENROUTER_API_KEY=sk-or-...). Полную настройку см. в разделе Управление секретами. Если у вас ещё нет менеджера секретов, можете начать с обычного файла — просто убедитесь, что он не читается всеми:
[code]
echo "OPENROUTER_API_KEY=sk-or-your-key" | sudo install -m 0600 -o hermes /dev/stdin /var/lib/hermes/env
[/code] [code] services.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];
[/code]
addToSystemPackages
Установка addToSystemPackages = true делает две вещи: добавляет CLI hermes в системный PATH и устанавливает HERMES_HOME общесистемно, чтобы интерактивный CLI разделял состояние (сессии, навыки, cron) с сервисом шлюза. Без этого запуск hermes в вашей оболочке создаёт отдельную директорию ~/.hermes/.
CLI с поддержкой контейнера¶
info
Когда container.enable = true и addToSystemPackages = true, каждая команда hermes на хосте автоматически направляется в управляемый контейнер. Это означает, что ваша интерактивная CLI-сессия работает в том же окружении, что и сервис шлюза — с доступом ко всем установленным в контейнере пакетам и инструментам.
* Маршрутизация прозрачна: hermes chat, hermes sessions list, hermes version и т.д. все выполняются внутри контейнера под капотом
* Все CLI-флаги передаются как есть
* Если контейнер не запущен, CLI делает несколько попыток (5 с со спиннером для интерактивного использования, 10 с беззвучно для скриптов), затем завершается с понятной ошибкой — без беззвучного отката
* Для разработчиков, работающих над кодовой базой hermes, установите HERMES_DEV=1, чтобы обойти маршрутизацию в контейнер и запускать локальную копию напрямую
Установите container.hostUsers, чтобы создать символическую ссылку ~/.hermes на директорию состояния сервиса, тогда CLI на хосте и контейнер будут совместно использовать сессии, конфигурацию и воспоминания:
[code]
services.hermes-agent = {
container.enable = true;
container.hostUsers = [ "your-username" ];
addToSystemPackages = true;
};
[/code]
Пользователи, перечисленные в hostUsers, автоматически добавляются в группу hermes для доступа к файлам.
Пользователи Podman: Сервис NixOS запускает контейнер от root. Пользователи Docker получают доступ через сокет группы docker, но rootful-контейнеры Podman требуют sudo. Предоставьте sudo без пароля для вашей контейнерной среды выполнения:
[code]
security.sudo.extraRules = [{
users = [ "your-username" ];
commands = [{
command = "/run/current-system/sw/bin/podman";
options = [ "NOPASSWD" ];
}];
}];
[/code]
CLI автоматически определяет, когда нужен sudo, и использует его прозрачно. Без этого вам придётся запускать sudo hermes chat вручную.
Проверка работоспособности¶
После nixos-rebuild switch проверьте, что сервис запущен:
[code]
# Проверка статуса сервиса
systemctl status hermes-agent
# Просмотр логов (Ctrl+C для остановки)
journalctl -u hermes-agent -f
# Если addToSystemPackages true, протестируйте CLI
hermes version
hermes config # показывает сгенерированную конфигурацию
[/code]
Выбор режима развёртывания¶
Модуль поддерживает два режима, управляемых через container.enable:
| Нативный (по умолчанию)| Контейнерный
---|---|---
Как работает| Усиленный systemd-сервис на хосте| Постоянный Ubuntu-контейнер с bind-mount /nix/store
Безопасность| NoNewPrivileges, ProtectSystem=strict, PrivateTmp| Изоляция контейнера, запуск от непривилегированного пользователя внутри
Агент может самостоятельно устанавливать пакеты| Нет — только инструменты из Nix-пути PATH| Да — apt, pip, npm установки сохраняются после перезапуска
Поверхность конфигурации| Та же| Та же
Когда выбирать| Стандартные развёртывания, максимальная безопасность, воспроизводимость| Агенту требуется установка пакетов во время выполнения, изменяемое окружение, экспериментальные инструменты
Чтобы включить контейнерный режим, добавьте одну строку:
[code]
{
services.hermes-agent = {
enable = true;
container.enable = true;
# ... остальная конфигурация идентична
};
}
[/code]
info
Контейнерный режим автоматически включает virtualisation.docker.enable через mkDefault. Если вы используете Podman, установите container.backend = "podman" и virtualisation.docker.enable = false.
Конфигурация¶
Декларативные настройки¶
Опция settings принимает произвольный attrset, который преобразуется в config.yaml. Она поддерживает глубокое слияние (deep merge) между несколькими определениями модуля (через lib.recursiveUpdate), поэтому вы можете разделять конфигурацию по файлам:
[code]
# base.nix
services.hermes-agent.settings = {
model.default = "anthropic/claude-sonnet-4";
toolsets = [ "all" ];
terminal = { backend = "local"; timeout = 180; };
};
# personality.nix
services.hermes-agent.settings = {
display = { compact = false; personality = "kawaii"; };
memory = { memory_enabled = true; user_profile_enabled = true; };
};
[/code]
Оба объединяются глубоким слиянием на этапе оценки. Ключи, объявленные в Nix, всегда имеют приоритет над ключами в существующем config.yaml на диске, но ключи, добавленные пользователем, которые Nix не затрагивает, сохраняются. Это означает, что если агент или ручное редактирование добавляет ключи вроде skills.disabled или streaming.enabled, они переживают nixos-rebuild switch.
Именование моделей
settings.model.default использует идентификатор модели, который ожидает ваш провайдер. С OpenRouter (по умолчанию) они выглядят как "anthropic/claude-sonnet-4" или "google/gemini-3-flash". Если вы используете провайдера напрямую (Anthropic, OpenAI), установите settings.model.base_url для указания на их API и используйте их родные идентификаторы моделей (например, "claude-sonnet-4-20250514"). Когда base_url не задан, Hermes по умолчанию использует OpenRouter.
Поиск доступных ключей конфигурации
Выполните nix build .#configKeys && cat result, чтобы увидеть все конечные ключи конфигурации, извлечённые из DEFAULT_CONFIG в Python. Вы можете вставить существующий config.yaml в attrset settings — структура соответствует 1:1.
Полный пример: все часто настраиваемые параметры
[code]
{ config, ... }: {
services.hermes-agent = {
enable = true;
container.enable = true;
# ── Модель ──────────────────────────────────────────────────────────
settings = {
model = {
base_url = "https://openrouter.ai/api/v1";
default = "anthropic/claude-opus-4.6";
};
toolsets = [ "all" ];
max_turns = 100;
terminal = { backend = "local"; cwd = "."; timeout = 180; };
compression = {
enabled = true;
threshold = 0.85;
summary_model = "google/gemini-3-flash-preview";
};
memory = { memory_enabled = true; user_profile_enabled = true; };
display = { compact = false; personality = "kawaii"; };
agent = { max_turns = 60; verbose = false; };
};
# ── Секреты ────────────────────────────────────────────────────────
environmentFiles = [ config.sops.secrets."hermes-env".path ];
# ── Документы ──────────────────────────────────────────────────────
documents = {
"USER.md" = ./documents/USER.md;
};
# ── MCP-серверы ────────────────────────────────────────────────────
mcpServers.filesystem = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-filesystem" "/data/workspace" ];
};
# ── Параметры контейнера ───────────────────────────────────────────
container = {
image = "ubuntu:24.04";
backend = "docker";
hostUsers = [ "your-username" ];
extraVolumes = [ "/home/user/projects:/projects:rw" ];
extraOptions = [ "--gpus" "all" ];
};
# ── Тюнинг сервиса ─────────────────────────────────────────────────
addToSystemPackages = true;
extraArgs = [ "--verbose" ];
restart = "always";
restartSec = 5;
};
}
[/code]
Запасной вариант: собственная конфигурация¶
Если вы предпочитаете управлять config.yaml полностью вне Nix, используйте configFile:
[code]
services.hermes-agent.configFile = /etc/hermes/config.yaml;
[/code]
Это полностью обходит settings — никакого слияния, никакой генерации. Файл копируется как есть в $HERMES_HOME/config.yaml при каждой активации.
Шпаргалка по настройке¶
Быстрый справочник по самым частым вещам, которые пользователи Nix хотят настроить:
Я хочу...| Опция| Пример
---|---|---
Изменить LLM-модель| settings.model.default| "anthropic/claude-sonnet-4"
Использовать другую конечную точку провайдера| settings.model.base_url| "https://openrouter.ai/api/v1"
Добавить API-ключи| environmentFiles| [ config.sops.secrets."hermes-env".path ]
Наделить агента личностью| ${services.hermes-agent.stateDir}/.hermes/SOUL.md| управляйте файлом напрямую
Добавить MCP-серверы инструментов| mcpServers.<name>| См. MCP-серверы
Смонтировать хостовые директории в контейнер| container.extraVolumes| [ "/data:/data:rw" ]
Передать GPU в контейнер| container.extraOptions| [ "--gpus" "all" ]
Использовать Podman вместо Docker| container.backend| "podman"
Разделять состояние между хостовым CLI и контейнером| container.hostUsers| [ "sidbin" ]
Сделать дополнительные инструменты доступными агенту| extraPackages| [ pkgs.pandoc pkgs.imagemagick ]
Использовать собственный базовый образ| container.image| "ubuntu:24.04"
Переопределить пакет hermes| package| inputs.hermes-agent.packages.${system}.default.override { ... }
Изменить директорию состояния| stateDir| "/opt/hermes"
Установить рабочую директорию агента| workingDirectory| "/home/user/projects"
Управление секретами¶
Никогда не помещайте API-ключи в settings или environment
Значения в Nix-выражениях попадают в /nix/store, который доступен для чтения всем. Всегда используйте environmentFiles с менеджером секретов.
И environment (несекретные переменные), и environmentFiles (файлы с секретами) объединяются в $HERMES_HOME/.env при активации (nixos-rebuild switch). Hermes читает этот файл при каждом запуске, поэтому изменения вступают в силу после systemctl restart hermes-agent — пересоздание контейнера не требуется.
sops-nix¶
[code]
{
sops = {
defaultSopsFile = ./secrets/hermes.yaml;
age.keyFile = "/home/user/.config/sops/age/keys.txt";
secrets."hermes-env" = { format = "yaml"; };
};
services.hermes-agent.environmentFiles = [
config.sops.secrets."hermes-env".path
];
}
[/code]
Файл секретов содержит пары ключ-значение:
[code]
# secrets/hermes.yaml (зашифрован с помощью sops)
hermes-env: |
OPENROUTER_API_KEY=sk-or-...
TELEGRAM_BOT_TOKEN=123456:ABC...
ANTHROPIC_API_KEY=sk-ant-...
[/code]
agenix¶
[code]
{
age.secrets.hermes-env.file = ./secrets/hermes-env.age;
services.hermes-agent.environmentFiles = [
config.age.secrets.hermes-env.path
];
}
[/code]
OAuth / Предзагрузка аутентификации¶
Для платформ, требующих OAuth (например, Discord), используйте authFile для предзагрузки учётных данных при первом развёртывании:
[code]
{
services.hermes-agent = {
authFile = config.sops.secrets."hermes/auth.json".path;
# authFileForceOverwrite = true; # перезаписывать при каждой активации
};
}
[/code]
Файл копируется только если auth.json ещё не существует (если только authFileForceOverwrite = true). Обновления OAuth-токенов во время выполнения записываются в директорию состояния и сохраняются при пересборках.
Документы¶
Опция documents устанавливает файлы в рабочую директорию агента (значение workingDirectory, которую агент читает как своё рабочее пространство). Hermes ищет определённые имена файлов по соглашению:
* USER.md — контекст о пользователе, с которым взаимодействует агент.
* Любые другие файлы, которые вы сюда поместите, видны агенту как файлы рабочего пространства.
Файл личности агента находится отдельно: Hermes загружает свой основной SOUL.md из $HERMES_HOME/SOUL.md, который в модуле NixOS находится по пути ${services.hermes-agent.stateDir}/.hermes/SOUL.md. Помещение SOUL.md в documents создаст только файл рабочего пространства и не заменит основной файл личности.
[code]
{
services.hermes-agent.documents = {
"USER.md" = ./documents/USER.md; # ссылка на путь, копируется из Nix store
};
}
[/code]
Значениями могут быть строки напрямую или ссылки на пути. Файлы устанавливаются при каждом nixos-rebuild switch.
MCP-серверы¶
Опция mcpServers декларативно настраивает MCP-серверы (Model Context Protocol). Каждый сервер использует либо stdio (локальная команда), либо HTTP (удалённый URL) транспорт.
Stdio-транспорт (локальные серверы)¶
[code]
{
services.hermes-agent.mcpServers = {
filesystem = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-filesystem" "/data/workspace" ];
};
github = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-github" ];
env.GITHUB_PERSONAL_ACCESS_TOKEN = "${GITHUB_TOKEN}"; # извлекается из .env
};
};
}
[/code]
tip
Переменные окружения в значениях env извлекаются из $HERMES_HOME/.env во время выполнения. Используйте environmentFiles для внедрения секретов — никогда не помещайте токены напрямую в Nix-конфигурацию.
HTTP-транспорт (удалённые серверы)¶
[code]
{
services.hermes-agent.mcpServers.remote-api = {
url = "https://mcp.example.com/v1/mcp";
headers.Authorization = "Bearer ${MCP_REMOTE_API_KEY}";
timeout = 180;
};
}
[/code]
HTTP-транспорт с OAuth¶
Установите auth = "oauth" для серверов, использующих OAuth 2.1. Hermes реализует полный PKCE-процесс — обнаружение метаданных, динамическую регистрацию клиента, обмен токенами и автоматическое обновление.
[code]
{
services.hermes-agent.mcpServers.my-oauth-server = {
url = "https://mcp.example.com/mcp";
auth = "oauth";
};
}
[/code]
Токены хранятся в $HERMES_HOME/mcp-tokens/<имя-сервера>.json и сохраняются между перезапусками и пересборками.
Первоначальная OAuth-авторизация на серверах без головного интерфейса
Первая OAuth-авторизация требует браузерного процесса согласия. В развёртывании без головного интерфейса Hermes выводит URL авторизации в stdout/логи вместо открытия браузера.
Вариант А: Интерактивная начальная настройка — выполните процесс однократно через docker exec (контейнер) или sudo -u hermes (нативный режим):
[code]
# Контейнерный режим
docker exec -it hermes-agent \
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth
# Нативный режим
sudo -u hermes HERMES_HOME=/var/lib/hermes/.hermes \
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth
[/code]
Контейнер использует --network=host, поэтому слушатель OAuth-обратного вызова на 127.0.0.1 доступен из браузера на хосте.
Вариант Б: Предзагрузка токенов — выполните процесс на рабочей станции, затем скопируйте токены:
[code]
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth
scp ~/.hermes/mcp-tokens/my-oauth-server{,.client}.json \
server:/var/lib/hermes/.hermes/mcp-tokens/
# Убедитесь: chown hermes:hermes, chmod 0600
[/code]
Сэмплинг (запросы LLM, инициированные сервером)¶
Некоторые MCP-серверы могут запрашивать завершения LLM у агента:
[code]
{
services.hermes-agent.mcpServers.analysis = {
command = "npx";
args = [ "-y" "analysis-server" ];
sampling = {
enabled = true;
model = "google/gemini-3-flash";
max_tokens_cap = 4096;
timeout = 30;
max_rpm = 10;
};
};
}
[/code]
Управляемый режим¶
Когда hermes работает через модуль NixOS, следующие CLI-команды заблокированы с описательной ошибкой, указывающей на configuration.nix:
Заблокированная команда| Почему
---|---
hermes setup| Конфигурация декларативна — редактируйте settings в вашей Nix-конфигурации
hermes config edit| Конфигурация генерируется из settings
hermes config set <key> <value>| Конфигурация генерируется из settings
hermes gateway install| systemd-сервис управляется NixOS
hermes gateway uninstall| systemd-сервис управляется NixOS
Это предотвращает расхождение между тем, что объявляет Nix, и тем, что находится на диске. Обнаружение использует два сигнала:
1. Переменная окружения HERMES_MANAGED=true — устанавливается systemd-сервисом, видна процессу шлюза
2. Файл-маркер .managed в HERMES_HOME — устанавливается скриптом активации, виден интерактивным оболочкам (например, docker exec -it hermes-agent hermes config set ... также блокируется)
Чтобы изменить конфигурацию, отредактируйте вашу Nix-конфигурацию и выполните sudo nixos-rebuild switch.
Архитектура контейнера¶
info
Этот раздел актуален только если вы используете container.enable = true. Пропустите его для развёртываний в нативном режиме.
Когда контейнерный режим включён, hermes работает внутри постоянного Ubuntu-контейнера с Nix-собранным бинарником, примонтированным только для чтения с хоста:
[code]
Хост Контейнер
──── ─────────
/nix/store/...-hermes-agent-0.1.0 ──► /nix/store/... (ro)
~/.hermes -> /var/lib/hermes/.hermes (символьная ссылка-мост, по hostUsers)
/var/lib/hermes/ ──► /data/ (rw)
├── current-package -> /nix/store/... (символьная ссылка, обновляется при каждой пересборке)
├── .gc-root -> /nix/store/... (предотвращает nix-collect-garbage)
├── .container-identity (sha256-хэш, инициирует пересоздание)
├── .hermes/ (HERMES_HOME)
│ ├── .env (объединено из environment + environmentFiles)
│ ├── config.yaml (сгенерировано Nix, глубокое слияние при активации)
│ ├── .managed (файл-маркер)
│ ├── .container-mode (метаданные маршрутизации: backend, exec_user и т.д.)
│ ├── state.db, sessions/, memories/ (состояние времени выполнения)
│ └── mcp-tokens/ (OAuth-токены для MCP-серверов)
├── home/ ──► /home/hermes (rw)
└── workspace/ (MESSAGING_CWD)
├── SOUL.md (из опции documents)
└── (файлы, созданные агентом)
Записываемый слой контейнера (apt/pip/npm): /usr, /usr/local, /tmp
[/code]
Nix-собранный бинарник работает внутри Ubuntu-контейнера, потому что /nix/store примонтирован — он содержит собственный интерпретатор и все зависимости, поэтому нет зависимости от системных библиотек контейнера. Точка входа контейнера разрешается через символьную ссылку current-package: /data/current-package/bin/hermes gateway run --replace. При nixos-rebuild switch обновляется только символьная ссылка — контейнер продолжает работу.
Что сохраняется при каких событиях¶
| Событие | Контейнер пересоздаётся? | /data (состояние) |
/home/hermes |
Записываемый слой (apt/pip/npm) |
|---|---|---|---|---|
systemctl restart hermes-agent |
Нет | Сохраняется | Сохраняется | Сохраняется |
nixos-rebuild switch (изменение кода) |
Нет (символьная ссылка обновлена) | Сохраняется | Сохраняется | Сохраняется |
| Перезагрузка хоста | Нет | Сохраняется | Сохраняется | Сохраняется |
nix-collect-garbage |
Нет (GC root) | Сохраняется | Сохраняется | Сохраняется |
Изменение образа (container.image) |
Да | Сохраняется | Сохраняется | Потерян |
| Изменение томов/параметров | Да | Сохраняется | Сохраняется | Потерян |
Изменение environment/environmentFiles |
Нет | Сохраняется | Сохраняется | Сохраняется |
Контейнер пересоздаётся только когда изменяется его идентификационный хэш. Хэш включает: версию схемы, образ, extraVolumes, extraOptions и скрипт точки входа. Изменения переменных окружения, настроек, документов или самого пакета hermes не инициируют пересоздание. |
||||
| Потеря записываемого слоя | ||||
Когда идентификационный хэш изменяется (обновление образа, новые тома, новые параметры контейнера), контейнер уничтожается и пересоздаётся из свежего образа container.image. Любые пакеты, установленные через apt install, pip install или npm install в записываемом слое, теряются. Состояние в /data и /home/hermes сохраняется (это bind-монтирования). |
||||
Если агент полагается на определённые пакеты, рассмотрите возможность включения их в пользовательский образ (container.image = "my-registry/hermes-base:latest") или скриптовой установки в SOUL.md агента. |
||||
| ### Защита GC Root | ||||
Скрипт preStart создаёт GC root по пути ${stateDir}/.gc-root, указывающий на текущий пакет hermes. Это предотвращает удаление запущенного бинарника командой nix-collect-garbage. Если GC root по какой-то причине сломается, перезапуск сервиса воссоздаст его. |
||||
| * * * | ||||
| ## Плагины | ||||
Модуль NixOS поддерживает декларативную установку плагинов — без необходимости в императивном hermes plugins install. |
||||
### Директориальные плагины (extraPlugins) |
||||
Для плагинов, которые представляют собой просто дерево исходников с plugin.yaml + __init__.py (например, hermes-lcm): |
||||
| [code] | ||||
| services.hermes-agent.extraPlugins = [ | ||||
| (pkgs.fetchFromGitHub { | ||||
| owner = "stephenschoettler"; | ||||
| repo = "hermes-lcm"; | ||||
| rev = "v0.7.0"; | ||||
| hash = "sha256-..."; | ||||
| }) | ||||
| ]; |
[/code]
Плагины симлинкуются в $HERMES_HOME/plugins/ при активации. Hermes обнаруживает их через обычное сканирование директории. Удаление плагина из списка и выполнение nixos-rebuild switch удаляет символьную ссылку.
Плагины с точкой входа (extraPythonPackages)¶
Для плагинов, упакованных через pip, которые регистрируются через [project.entry-points."hermes_agent.plugins"] (например, rtk-hermes):
[code]
services.hermes-agent.extraPythonPackages = [
(pkgs.python312Packages.buildPythonPackage {
pname = "rtk-hermes";
version = "1.0.0";
src = pkgs.fetchFromGitHub {
owner = "ogallotti";
repo = "rtk-hermes";
rev = "v1.0.0";
hash = "sha256-...";
};
format = "pyproject";
build-system = [ pkgs.python312Packages.setuptools ];
})
];
[/code]
site-packages пакета добавляется в PYTHONPATH в обёртке hermes. importlib.metadata обнаруживает точку входа при запуске сессии.
Комбинирование обоих подходов¶
Директориальному плагину со сторонними Python-зависимостями нужны обе опции:
[code]
services.hermes-agent = {
extraPlugins = [ my-plugin-src ]; # исходник плагина
extraPythonPackages = [ pkgs.python312Packages.redis ]; # его Python-зависимость
extraPackages = [ pkgs.redis ]; # системный бинарник, который ему нужен
};
[/code]
Использование оверлея¶
Внешние флейки могут переопределять пакет напрямую:
[code]
{
inputs.hermes-agent.url = "github:NousResearch/hermes-agent";
outputs = { hermes-agent, nixpkgs, ... }: {
nixpkgs.overlays = [ hermes-agent.overlays.default ];
# Затем: pkgs.hermes-agent.override { extraPythonPackages = [...]; }
};
}
[/code]
Конфигурация плагинов¶
Плагины всё ещё нужно включать в config.yaml. Добавьте их через декларативные настройки:
[code]
services.hermes-agent.settings.plugins.enabled = [
"hermes-lcm"
"rtk-rewrite"
];
[/code]
note
Проверка коллизий на этапе сборки предотвращает перекрытие пакетами плагинов основных зависимостей hermes. Если плагин предоставляет пакет, уже существующий в изолированном venv, nixos-rebuild завершится ошибкой с понятным сообщением.
Разработка¶
Dev Shell¶
Флейк предоставляет оболочку для разработки с Python 3.11, uv, Node.js и всеми инструментами времени выполнения:
[code]
cd hermes-agent
nix develop
# Оболочка предоставляет:
# - Python 3.11 + uv (зависимости устанавливаются в .venv при первом входе)
# - Node.js 20, ripgrep, git, openssh, ffmpeg в PATH
# - Оптимизация через stamp-файл: повторный вход почти мгновенный, если зависимости не изменились
hermes setup
hermes chat
[/code]
direnv (рекомендуется)¶
Включённый .envrc активирует dev shell автоматически:
[code]
cd hermes-agent
direnv allow # однократно
# Последующие входы почти мгновенны (stamp-файл пропускает установку зависимостей)
[/code]
Проверки флейка¶
Флейк включает проверки на этапе сборки, которые выполняются в CI и локально:
[code]
# Запустить все проверки
nix flake check
# Отдельные проверки
nix build .#checks.x86_64-linux.package-contents # бинарники существуют + версия
nix build .#checks.x86_64-linux.entry-points-sync # синхронизация pyproject.toml ↔ Nix пакет
nix build .#checks.x86_64-linux.cli-commands # подкоманды gateway/config
nix build .#checks.x86_64-linux.managed-guard # HERMES_MANAGED блокирует мутацию
nix build .#checks.x86_64-linux.bundled-skills # навыки присутствуют в пакете
nix build .#checks.x86_64-linux.config-roundtrip # скрипт слияния сохраняет ключи пользователя
[/code]
Что проверяет каждая проверка
Проверка| Что тестирует
---|---
package-contents| Бинарники hermes и hermes-agent существуют и hermes version выполняется
entry-points-sync| Каждая запись [project.scripts] в pyproject.toml имеет обёрнутый бинарник в Nix-пакете
cli-commands| hermes --help отображает подкоманды gateway и config
managed-guard| HERMES_MANAGED=true hermes config set ... выводит ошибку NixOS
bundled-skills| Директория навыков существует, содержит SKILL.md, HERMES_BUNDLED_SKILLS установлена в обёртке
config-roundtrip| 7 сценариев слияния: чистая установка, переопределение Nix, сохранение ключей пользователя, смешанное слияние, аддитивное слияние MCP, вложенное глубокое слияние, идемпотентность
Справочник опций¶
Основные¶
| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
enable |
bool |
false |
Включить сервис hermes-agent |
package |
package |
hermes-agent |
Используемый пакет hermes-agent |
user |
str |
"hermes" |
Системный пользователь |
group |
str |
"hermes" |
Системная группа |
createUser |
bool |
true |
Автосоздание пользователя/группы |
stateDir |
str |
"/var/lib/hermes" |
Директория состояния (родительская для HERMES_HOME) |
workingDirectory |
str |
"${stateDir}/workspace" |
Рабочая директория агента (MESSAGING_CWD) |
addToSystemPackages |
bool |
false |
Добавить CLI hermes в системный PATH и установить HERMES_HOME общесистемно |
| ### Конфигурация | |||
| Опция | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
settings |
attrs (глубокое слияние) |
{} |
Декларативная конфигурация, преобразуемая в config.yaml. Поддерживает произвольную вложенность; несколько определений сливаются через lib.recursiveUpdate |
configFile |
null или path |
null |
Путь к существующему config.yaml. Полностью переопределяет settings, если задан |
| ### Секреты и окружение | |||
| Опция | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
environmentFiles |
listOf str |
[] |
Пути к файлам окружения с секретами. Объединяются в $HERMES_HOME/.env при активации |
environment |
attrsOf str |
{} |
Несекретные переменные окружения. Видимы в Nix store — не помещайте сюда секреты |
authFile |
null или path |
null |
Предзагрузка OAuth-учётных данных. Копируется только при первом развёртывании |
authFileForceOverwrite |
bool |
false |
Всегда перезаписывать auth.json из authFile при активации |
| ### Документы | |||
| Опция | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
documents |
attrsOf (either str path) |
{} |
Файлы рабочего пространства. Ключи — имена файлов, значения — строки напрямую или пути. Устанавливаются в workingDirectory при активации |
| ### MCP-серверы | |||
| Опция | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
mcpServers |
attrsOf submodule |
{} |
Определения MCP-серверов, объединяемые в settings.mcp_servers |
mcpServers.<name>.command |
null или str |
null |
Команда сервера (stdio-транспорт) |
mcpServers.<name>.args |
listOf str |
[] |
Аргументы команды |
mcpServers.<name>.env |
attrsOf str |
{} |
Переменные окружения для процесса сервера |
mcpServers.<name>.url |
null или str |
null |
URL конечной точки сервера (HTTP/StreamableHTTP транспорт) |
mcpServers.<name>.headers |
attrsOf str |
{} |
HTTP-заголовки, например Authorization |
mcpServers.<name>.auth |
null или "oauth" |
null |
Метод аутентификации. "oauth" включает OAuth 2.1 PKCE |
mcpServers.<name>.enabled |
bool |
true |
Включить или отключить этот сервер |
mcpServers.<name>.timeout |
null или int |
null |
Тайм-аут вызова инструмента в секундах (по умолчанию: 120) |
mcpServers.<name>.connect_timeout |
null или int |
null |
Тайм-аут подключения в секундах (по умолчанию: 60) |
mcpServers.<name>.tools |
null или submodule |
null |
Фильтрация инструментов (списки include/exclude) |
mcpServers.<name>.sampling |
null или submodule |
null |
Конфигурация сэмплинга для запросов LLM, инициированных сервером |
| ### Поведение сервиса | |||
| Опция | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
extraArgs |
listOf str |
[] |
Дополнительные аргументы для hermes gateway |
extraPackages |
listOf package |
[] |
Дополнительные пакеты, доступные агенту. Добавляются в per-user профиль пользователя hermes, так что терминальные команды, навыки и cron-задачи все их видят |
extraPlugins |
listOf package |
[] |
Пакеты директориальных плагинов для симлинкования в $HERMES_HOME/plugins/. Каждый должен содержать plugin.yaml |
extraPythonPackages |
listOf package |
[] |
Python-пакеты, добавляемые в PYTHONPATH для обнаружения плагинов с точкой входа. Собирайте с помощью python312Packages |
restart |
str |
"always" |
Политика systemd Restart= |
restartSec |
int |
5 |
Значение systemd RestartSec= |
| ### Контейнер | |||
| Опция | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
container.enable |
bool |
false |
Включить режим OCI-контейнера |
container.backend |
enum ["docker" "podman"] |
"docker" |
Среда выполнения контейнера |
container.image |
str |
"ubuntu:24.04" |
Базовый образ (загружается во время выполнения) |
container.extraVolumes |
listOf str |
[] |
Дополнительные монтирования томов (хост:контейнер:режим) |
container.extraOptions |
listOf str |
[] |
Дополнительные аргументы, передаваемые в docker create |
container.hostUsers |
listOf str |
[] |
Интерактивные пользователи, которые получают символьную ссылку ~/.hermes на stateDir сервиса и автоматически добавляются в группу hermes |
| * * * | |||
| ## Структура директорий | |||
| ### Нативный режим | |||
| [code] | |||
| /var/lib/hermes/ # stateDir (владелец hermes:hermes, 0750) | |||
| ├── .hermes/ # HERMES_HOME | |||
| │ ├── config.yaml # сгенерировано Nix (глубокое слияние при каждой пересборке) | |||
| │ ├── .managed # Маркер: мутация CLI-конфигурации заблокирована | |||
| │ ├── .env # Объединено из environment + environmentFiles | |||
| │ ├── auth.json # OAuth-учётные данные (предзагружены, затем самоуправляемы) | |||
| │ ├── gateway.pid | |||
| │ ├── state.db | |||
| │ ├── mcp-tokens/ # OAuth-токены для MCP-серверов | |||
| │ ├── sessions/ | |||
| │ ├── memories/ | |||
| │ ├── skills/ | |||
| │ ├── cron/ | |||
| │ └── logs/ | |||
| ├── home/ # HOME агента | |||
| └── workspace/ # MESSAGING_CWD | |||
| ├── SOUL.md # Из опции documents | |||
| └── (файлы, созданные агентом) |
[/code]
Контейнерный режим¶
Та же структура, смонтированная в контейнер:
Путь в контейнере| Путь на хосте| Режим| Примечания
---|---|---|---|---
/nix/store| /nix/store| ro| Бинарник Hermes + все Nix-зависимости
/data| /var/lib/hermes| rw| Всё состояние, конфигурация, рабочее пространство
/home/hermes| ${stateDir}/home| rw| Постоянный home агента — pip install --user, кэши инструментов
/usr, /usr/local, /tmp| (записываемый слой)| rw| Установки apt/pip/npm — сохраняются между перезапусками, теряются при пересоздании
Обновление¶
[code]
# Обновить вход флейка
nix flake update hermes-agent --flake /etc/nixos
# Пересобрать
sudo nixos-rebuild switch
[/code]
В контейнерном режиме символьная ссылка current-package обновляется, и агент подхватывает новый бинарник при перезапуске. Без пересоздания контейнера, без потери установленных пакетов.
Устранение неполадок¶
Пользователи Podman
Все команды docker ниже работают так же с podman. Заменяйте соответственно, если вы установили container.backend = "podman".
Логи сервиса¶
[code]
# Оба режима используют один и тот же systemd-юнит
journalctl -u hermes-agent -f
# Контейнерный режим: также доступно напрямую
docker logs -f hermes-agent
[/code]
Инспекция контейнера¶
[code]
systemctl status hermes-agent
docker ps -a --filter name=hermes-agent
docker inspect hermes-agent --format='{{.State.Status}}'
docker exec -it hermes-agent bash
docker exec hermes-agent readlink /data/current-package
docker exec hermes-agent cat /data/.container-identity
[/code]
Принудительное пересоздание контейнера¶
Если вам нужно сбросить записываемый слой (свежий Ubuntu):
[code]
sudo systemctl stop hermes-agent
docker rm -f hermes-agent
sudo rm /var/lib/hermes/.container-identity
sudo systemctl start hermes-agent
[/code]
Проверка загрузки секретов¶
Если агент запускается, но не может аутентифицироваться у LLM-провайдера, проверьте, что файл .env был объединён корректно:
[code]
# Нативный режим
sudo -u hermes cat /var/lib/hermes/.hermes/.env
# Контейнерный режим
docker exec hermes-agent cat /data/.hermes/.env
[/code]
Проверка GC Root¶
[code] nix-store --query --roots $(docker exec hermes-agent readlink /data/current-package)
[/code]
Частые проблемы¶
| Симптом | Причина | Исправление |
|---|---|---|
Cannot save configuration: managed by NixOS |
Активны CLI-ограничения | Отредактируйте configuration.nix и выполните nixos-rebuild switch |
| Контейнер неожиданно пересоздан | Изменились extraVolumes, extraOptions или image |
Ожидаемо — записываемый слой сбрасывается. Переустановите пакеты или используйте пользовательский образ |
hermes version показывает старую версию |
Контейнер не перезапущен | systemctl restart hermes-agent |
Отказано в доступе к /var/lib/hermes |
Директория состояния имеет 0750 hermes:hermes |
Используйте docker exec или sudo -u hermes |
nix-collect-garbage удалил hermes |
Отсутствует GC root | Перезапустите сервис (preStart воссоздаёт GC root) |
no container with name or ID "hermes-agent" (Podman) |
Rootful-контейнер Podman не виден обычному пользователю | Добавьте sudo без пароля для podman (см. раздел Контейнерный режим) |
unable to find user hermes |
Контейнер всё ещё запускается (точка входа ещё не создала пользователя) | Подождите несколько секунд и повторите — CLI повторяет попытку автоматически |
Инструмент, добавленный через extraPackages, не найден в терминале |
Требуется nixos-rebuild switch для обновления per-user профиля |
Пересоберите и перезапустите: nixos-rebuild switch && systemctl restart hermes-agent |
| * Предварительные требования | ||
| * Быстрый старт (любой пользователь Nix) | ||
| * Модуль NixOS | ||
| * Добавление флейк-входа | ||
| * Минимальная конфигурация | ||
| * CLI с поддержкой контейнера | ||
| * Проверка работоспособности | ||
| * Выбор режима развёртывания | ||
| * Конфигурация | ||
| * Декларативные настройки | ||
| * Запасной вариант: собственная конфигурация | ||
| * Шпаргалка по настройке | ||
| * Управление секретами | ||
| * sops-nix | ||
| * agenix | ||
| * OAuth / Предзагрузка аутентификации | ||
| * Документы | ||
| * MCP-серверы | ||
| * Stdio-транспорт (локальные серверы) | ||
| * HTTP-транспорт (удалённые серверы) | ||
| * HTTP-транспорт с OAuth | ||
| * Сэмплинг (запросы LLM, инициированные сервером) | ||
| * Управляемый режим | ||
| * Архитектура контейнера | ||
| * Что сохраняется при каких событиях | ||
| * Защита GC Root | ||
| * Плагины | ||
* Директориальные плагины (extraPlugins) |
||
* Плагины с точкой входа (extraPythonPackages) |
||
| * Комбинирование обоих подходов | ||
| * Использование оверлея | ||
| * Конфигурация плагинов | ||
| * Разработка | ||
| * Dev Shell | ||
| * direnv (рекомендуется) | ||
| * Проверки флейка | ||
| * Справочник опций | ||
| * Основные | ||
| * Конфигурация | ||
| * Секреты и окружение | ||
| * Документы | ||
| * MCP-серверы | ||
| * Поведение сервиса | ||
| * Контейнер | ||
| * Структура директорий | ||
| * Нативный режим | ||
| * Контейнерный режим | ||
| * Обновление | ||
| * Устранение неполадок | ||
| * Логи сервиса | ||
| * Инспекция контейнера | ||
| * Принудительное пересоздание контейнера | ||
| * Проверка загрузки секретов | ||
| * Проверка GC Root | ||
| * Частые проблемы |