Настройка Nix и NixOS
Hermes Agent поставляется как Nix-flake с тремя уровнями интеграции:
| Уровень | Для кого | Что вы получаете |
|---|---|---|
nix run / nix profile install | Любой пользователь Nix (macOS, Linux) | Предварительно собранный бинарный файл со всеми зависимостями — затем используйте стандартный процесс CLI |
| NixOS module (native) | Развёртывание на серверах NixOS | Декларативная конфигурация, защищённый systemd-сервис, управляемые секреты |
| NixOS module (container) | Агентам, которым нужна самодоработка среды | Всё вышеперечисленное плюс постоянный контейнер Ubuntu, где агент может выполнять apt/pip/npm install |
:::info Чем это отличается от стандартной установки
Установщик curl | bash сам управляет Python, Node и зависимостями. Nix-flake заменяет всю эту схему: каждая Python-зависимость собирается как Nix-деривация через uv2nix, а инструменты времени выполнения — Node.js, git, ripgrep, ffmpeg — уже обёрнуты в PATH бинарника. Никакого runtime pip, активации venv или npm install здесь нет.
Для пользователей не-NixOS это меняет только шаг установки. Всё после этого (hermes setup, hermes gateway install, редактирование конфигурации) работает точно так же, как при стандартной установке.
Для пользователей NixOS module весь жизненный цикл отличается: конфигурация находится в configuration.nix, секреты проходят через sops-nix/agenix, сервис представляет собой unit systemd, а команды конфигурации CLI заблокированы. Вы управляете hermes так же, как любым другим сервисом NixOS.
:::
Предварительные требования
Заголовок раздела «Предварительные требования»- Nix с включёнными flakes — рекомендуется Determinate Nix (по умолчанию включает flakes)
- Ключи API для сервисов, которые вы хотите использовать (как минимум: ключ OpenRouter или Anthropic)
Быстрый старт (любой пользователь Nix)
Заголовок раздела «Быстрый старт (любой пользователь Nix)»Клонирование не требуется. Nix сам получает, собирает и запускает всё:
# Run directly (builds on first use, cached after)nix run github:NousResearch/hermes-agent -- setupnix run github:NousResearch/hermes-agent -- chat
# Or install persistentlynix profile install github:NousResearch/hermes-agenthermes setuphermes chatПосле nix profile install команды hermes, hermes-agent и hermes-acp появятся в вашем PATH. Дальше рабочий процесс совпадает со стандартной установкой: hermes setup проводит через выбор провайдера, hermes gateway install настраивает пользовательский сервис launchd на macOS или systemd на Linux, а конфигурация хранится в ~/.hermes/.
Сборка из локального клона
git clone https://github.com/NousResearch/hermes-agent.gitcd hermes-agentnix build./result/bin/hermes setupМодуль NixOS
Заголовок раздела «Модуль NixOS»Flake экспортирует nixosModules.default — полноценный сервисный модуль NixOS, который декларативно управляет созданием пользователя, директориями, генерацией конфигурации, секретами, документами и жизненным циклом сервиса.
Добавьте вход flake
Заголовок раздела «Добавьте вход flake»# /etc/nixos/flake.nix (or your system flake){ 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 ]; }; };}Минимальная конфигурация
Заголовок раздела «Минимальная конфигурация»{ config, ... }: { services.hermes-agent = { enable = true; settings.model.default = "anthropic/claude-sonnet-4"; environmentFiles = [ config.sops.secrets."hermes-env".path ]; addToSystemPackages = true; };}Вот и всё. nixos-rebuild switch создаёт пользователя hermes, генерирует config.yaml, подключает секреты и запускает gateway — долгоживущий сервис, который соединяет агента с платформами обмена сообщениями (Telegram, Discord и т. д.) и принимает входящие сообщения.
:::warning Секреты обязательны
Строка environmentFiles выше предполагает, что у вас настроен sops-nix или agenix. Файл должен содержать как минимум один ключ провайдера LLM (например, OPENROUTER_API_KEY=sk-or-...). Полную настройку см. в разделе Управление секретами. Если у вас пока нет менеджера секретов, для начала можно использовать обычный файл — просто убедитесь, что он не доступен на чтение всем:
echo "OPENROUTER_API_KEY=sk-or-your-key" | sudo install -m 0600 -o hermes /dev/stdin /var/lib/hermes/envservices.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];:::
:::tip addToSystemPackages
Параметр addToSystemPackages = true делает две вещи: помещает hermes CLI в ваш системный PATH и задаёт HERMES_HOME на уровне всей системы, чтобы интерактивная сессия CLI разделяла состояние (сессии, навыки, cron) с сервисом gateway. Без этого запуск hermes в вашей shell создаёт отдельный каталог ~/.hermes/.
:::
CLI с контейнерным режимом
Заголовок раздела «CLI с контейнерным режимом»Когда включены container.enable = true и addToSystemPackages = true, каждая команда hermes на хосте автоматически перенаправляется в управляемый контейнер. Это означает, что ваша интерактивная сессия CLI выполняется в той же среде, что и сервис gateway, — с доступом ко всем пакетам и инструментам, установленным в контейнере.
- Перенаправление прозрачно:
hermes chat,hermes sessions list,hermes versionи т. д. все под капотом выполняются в контейнере через exec - Все флаги CLI передаются как есть
- Если контейнер не запущен, CLI ненадолго повторяет попытки (5 с со спиннером для интерактивного использования, 10 с без вывода для скриптов), а затем завершается с понятной ошибкой — без тихого отката
- Для разработчиков, работающих над кодовой базой hermes, установите
HERMES_DEV=1, чтобы обойти перенаправление в контейнер и запускать локальный checkout напрямую
Установите container.hostUsers, чтобы создать символическую ссылку ~/.hermes на каталог состояния сервиса, чтобы хостовый CLI и контейнер совместно использовали сессии, конфигурацию и память:
services.hermes-agent = { container.enable = true; container.hostUsers = [ "your-username" ]; addToSystemPackages = true;};```Пользователи, перечисленные в `hostUsers`, автоматически добавляются в группу `hermes` для доступа к правам файлов.
**Пользователи Podman:** Сервис NixOS запускает контейнер от root. Пользователи Docker получают доступ через сокет группы `docker`, но rootful-контейнеры Podman требуют sudo. Предоставьте passwordless sudo для вашего runtime контейнеров:
```nixsecurity.sudo.extraRules = [{ users = [ "your-username" ]; commands = [{ command = "/run/current-system/sw/bin/podman"; options = [ "NOPASSWD" ]; }];}];CLI автоматически определяет, когда требуется sudo, и прозрачно использует его. Без этого вам потребуется запускать sudo hermes chat вручную.
Проверьте, что всё работает
Заголовок раздела «Проверьте, что всё работает»После nixos-rebuild switch проверьте, что сервис запущен:
# Check service statussystemctl status hermes-agent
# Watch logs (Ctrl+C to stop)journalctl -u hermes-agent -f
# If addToSystemPackages is true, test the CLIhermes versionhermes config
# shows the generated configВыбор режима развертывания
Заголовок раздела «Выбор режима развертывания»Модуль поддерживает два режима, управляемых через container.enable:
| Нативный (по умолчанию) | Контейнер | |
|---|---|---|
| Как запускается | Защищённый сервис systemd на хосте | Постоянный контейнер Ubuntu с bind mount для /nix/store |
| Безопасность | NoNewPrivileges, ProtectSystem=strict, PrivateTmp | Изоляция контейнера, запуск от непривилегированного пользователя внутри |
| Агент может сам устанавливать пакеты | Нет — только инструменты в PATH, предоставленном Nix | Да — установки apt, pip, npm сохраняются после перезапусков |
| Поверхность конфигурации | Одинаковая | Одинаковая |
| Когда выбирать | Стандартные развертывания, максимальная безопасность, воспроизводимость | Агенту нужна установка пакетов во время выполнения, изменяемая среда, экспериментальные инструменты |
Чтобы включить контейнерный режим, добавьте одну строку:
{ services.hermes-agent = { enable = true; container.enable = true;
# ... rest of config is identical };}Контейнерный режим автоматически включает virtualisation.docker.enable через mkDefault. Если вы используете Podman вместо этого, задайте container.backend = "podman" и virtualisation.docker.enable = false.
Конфигурация
Заголовок раздела «Конфигурация»Декларативные настройки
Заголовок раздела «Декларативные настройки»Опция settings принимает произвольный attrset, который рендерится в config.yaml. Поддерживается глубокое слияние между несколькими определениями модуля через lib.recursiveUpdate, поэтому конфигурацию можно спокойно разносить по разным файлам:
services.hermes-agent.settings = { model.default = "anthropic/claude-sonnet-4"; toolsets = [ "all" ]; terminal = { backend = "local"; timeout = 180; };};
# personality.nixservices.hermes-agent.settings = { display = { compact = false; personality = "kawaii"; }; memory = { memory_enabled = true; user_profile_enabled = true; };};Оба варианта глубоко объединяются во время вычисления. Ключи, объявленные в Nix, всегда имеют приоритет над ключами в существующем config.yaml на диске, но добавленные пользователем ключи, которых Nix не касается, сохраняются. Это означает, что если агент или ручное редактирование добавляет ключи вроде skills.disabled или streaming.enabled, они сохранятся после nixos-rebuild switch.
:::note Именование моделей
settings.model.default использует идентификатор модели, который ожидает ваш провайдер. С OpenRouter (по умолчанию) они выглядят как "anthropic/claude-sonnet-4" или "google/gemini-3-flash". Если вы используете провайдера напрямую (Anthropic, OpenAI), задайте settings.model.base_url, чтобы он указывал на их API, и используйте их нативные ID моделей (например, "claude-sonnet-4-20250514"). Если base_url не задан, Hermes по умолчанию использует OpenRouter.
:::
:::tip Как найти доступные ключи конфигурации
Выполните nix build .#configKeys && cat result, чтобы увидеть каждый конечный ключ конфигурации, извлечённый из Python DEFAULT_CONFIG. Вы можете вставить существующий config.yaml в attrset settings — структура совпадает 1:1.
:::
Полный пример: все часто настраиваемые параметры
nix{ 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; };}Escape Hatch: Bring Your Own Config
Заголовок раздела «Escape Hatch: Bring Your Own Config»If you’d rather manage config.yaml entirely outside Nix, use configFile:
nixservices.hermes-agent.configFile = /etc/hermes/config.yaml;Это полностью обходит 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" |
Управление секретами
Заголовок раздела «Управление секретами»:::danger Никогда не помещайте ключи API в settings или environment
Значения в выражениях Nix попадают в /nix/store, который доступен для чтения всем. Всегда используйте environmentFiles вместе с менеджером секретов.
:::
И environment (несекретные переменные), и environmentFiles (секретные файлы) объединяются в $HERMES_HOME/.env во время активации (nixos-rebuild switch). Hermes читает этот файл при каждом запуске, поэтому изменения вступают в силу после systemctl restart hermes-agent — пересоздавать контейнер не нужно.
sops-nix
Заголовок раздела «sops-nix»{ 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 ];}Файл секретов содержит пары ключ-значение:
# secrets/hermes.yaml (encrypted with sops)hermes-env: | OPENROUTER_API_KEY=sk-or-... TELEGRAM_BOT_TOKEN=123456:ABC... ANTHROPIC_API_KEY=sk-ant-...{ age.secrets.hermes-env.file = ./secrets/hermes-env.age;
services.hermes-agent.environmentFiles = [ config.age.secrets.hermes-env.path ];}Инициализация OAuth / Auth
Заголовок раздела «Инициализация OAuth / Auth»Для платформ, требующих OAuth (например, Discord), используйте authFile, чтобы инициализировать учетные данные при первом развертывании:
{ services.hermes-agent = { authFile = config.sops.secrets."hermes/auth.json".path;
# authFileForceOverwrite = true;
# overwrite on every activation };}Файл копируется только если 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 только создает файл рабочего пространства и не заменит основной файл персоны.
{ services.hermes-agent.documents = { "USER.md" = ./documents/USER.md;
# path reference, copied from Nix store };}Значения могут быть встроенными строками или ссылками на пути. Файлы устанавливаются при каждом nixos-rebuild switch.
Серверы MCP
Заголовок раздела «Серверы MCP»Параметр mcpServers декларативно настраивает серверы MCP (Model Context Protocol). Каждый сервер использует транспорт либо stdio (локальная команда), либо HTTP (удаленный URL).
Транспорт Stdio (локальные серверы)
Заголовок раздела «Транспорт Stdio (локальные серверы)»{ 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}";
# resolved from .env }; };}Transport HTTP (Удалённые серверы)
Заголовок раздела «Transport HTTP (Удалённые серверы)»{ services.hermes-agent.mcpServers.remote-api = { url = "https://mcp.example.com/v1/mcp"; headers.Authorization = "Bearer \${MCP_REMOTE_API_KEY}"; timeout = 180; };}Transport HTTP с OAuth
Заголовок раздела «Transport HTTP с OAuth»Установите auth = "oauth" для серверов, использующих OAuth 2.1. Hermes реализует полный поток PKCE — обнаружение метаданных, динамическую регистрацию клиента, обмен токенами и автоматическое обновление.
{ services.hermes-agent.mcpServers.my-oauth-server = { url = "https://mcp.example.com/mcp"; auth = "oauth"; };}Токены хранятся в $HERMES_HOME/mcp-tokens/<server-name>.json и сохраняются между перезапусками и пересборками.
Первичная OAuth-авторизация на headless-серверах
Для первой OAuth-авторизации требуется поток согласия через браузер. В headless-развёртывании Hermes выводит URL авторизации URL в stdout/logs, вместо того чтобы открывать браузер.
Вариант A: Интерактивный bootstrap — запустите поток один раз через docker exec (container) или sudo -u hermes (native):
# Container modedocker exec -it hermes-agent \ hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth
# Native modesudo -u hermes HERMES_HOME=/var/lib/hermes/.hermes \ hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauthContainer использует --network=host, поэтому слушатель callback OAuth на 127.0.0.1 доступен из браузера на хосте.
Вариант B: Предварительно заполнить токены — завершите поток на рабочей станции, затем скопируйте токены:
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauthscp ~/.hermes/mcp-tokens/my-oauth-server{,.client}.json \ server:/var/lib/hermes/.hermes/mcp-tokens/# Ensure: chown hermes:hermes, chmod 0600Сэмплирование (инициируемые сервером запросы LLM)
Заголовок раздела «Сэмплирование (инициируемые сервером запросы LLM)»Некоторые серверы MCP могут запрашивать у агента завершения LLM:
{ 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; }; };}Управляемый режим
Заголовок раздела «Управляемый режим»Когда 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, и тем, что находится на диске. Для обнаружения используются два сигнала:
- Переменная окружения
HERMES_MANAGED=true— задаётся сервисом systemd, видна процессу gateway - Файл-маркер
.managedвHERMES_HOME— задаётся скриптом активации, виден интерактивным оболочкам (например,docker exec -it hermes-agent hermes config set ...также блокируется)
Чтобы изменить конфигурацию, отредактируйте вашу конфигурацию Nix и выполните sudo nixos-rebuild switch.
Архитектура контейнера
Заголовок раздела «Архитектура контейнера»Этот раздел актуален только если вы используете container.enable = true. Для развёртываний в нативном режиме его можно пропустить.
Когда режим контейнера включён, hermes работает внутри постоянного контейнера Ubuntu, а собранный Nix бинарный файл монтируется из хоста только для чтения:
Host Container──── ─────────/nix/store/...-hermes-agent-0.1.0 ──► /nix/store/... (ro)~/.hermes -> /var/lib/hermes/.hermes (symlink bridge, per hostUsers)/var/lib/hermes/ ──► /data/ (rw) ├── current-package -> /nix/store/... (symlink, updated each rebuild) ├── .gc-root -> /nix/store/... (prevents nix-collect-garbage) ├── .container-identity (sha256 hash, triggers recreation) ├── .hermes/ (HERMES_HOME) │ ├── .env (merged from environment + environmentFiles) │ ├── config.yaml (Nix-generated, deep-merged by activation) │ ├── .managed (marker file) │ ├── .container-mode (routing metadata: backend, exec_user, etc.) │ ├── state.db, sessions/, memories/ (runtime state) │ └── mcp-tokens/ (OAuth tokens for MCP servers) ├── home/ ──► /home/hermes (rw) └── workspace/ (MESSAGING_CWD) ├── SOUL.md (from documents option) └── (agent-created files)
Container writable layer (apt/pip/npm): /usr, /usr/local, /tmpБинарный файл, собранный с помощью Nix, работает внутри контейнера Ubuntu, потому что /nix/store монтируется через bind mount — он приносит собственный интерпретатор и все зависимости, поэтому нет зависимости от системных библиотек контейнера. Entry point контейнера разрешается через символьную ссылку current-package: /data/current-package/bin/hermes gateway run --replace. На nixos-rebuild switch обновляется только символьная ссылка — контейнер продолжает работать.
Что сохраняется при каких условиях| Событие | Контейнер пересоздаётся? | /data (состояние) | /home/hermes | Записываемый слой (apt/pip/npm) |
Заголовок раздела «Что сохраняется при каких условиях| Событие | Контейнер пересоздаётся? | /data (состояние) | /home/hermes | Записываемый слой (apt/pip/npm) |»|---|---|---|---|---|
| systemctl restart hermes-agent | Нет | Сохраняется | Сохраняется | Сохраняется |
| nixos-rebuild switch (изменение кода) | Нет (symlink обновлён) | Сохраняется | Сохраняется | Сохраняется |
| Перезагрузка хоста | Нет | Сохраняется | Сохраняется | Сохраняется |
| nix-collect-garbage | Нет (GC root) | Сохраняется | Сохраняется | Сохраняется |
| Изменение образа (container.image) | Да | Сохраняется | Сохраняется | Теряется |
| Изменение Volume/options | Да | Сохраняется | Сохраняется | Теряется |
| Изменение environment/environmentFiles | Нет | Сохраняется | Сохраняется | Сохраняется |
Контейнер пересоздаётся только при изменении его identity hash. Хеш включает: версию схемы, образ, extraVolumes, extraOptions и entrypoint script. Изменения переменных окружения, настроек, документов или самого пакета hermes не вызывают пересоздание.
:::warning Потеря записываемого слоя
Когда identity hash меняется (обновление образа, новые volumes, новые параметры контейнера), контейнер уничтожается и пересоздаётся из свежего pull container.image. Все пакеты apt install, pip install или npm install в записываемом слое теряются. Состояние в /data и /home/hermes сохраняется (это bind mounts).
Если агент зависит от конкретных пакетов, подумайте о том, чтобы встроить их в пользовательский образ (container.image = "my-registry/hermes-base:latest") или прописать их установку в SOUL.md агента.
:::
Защита GC Root
Заголовок раздела «Защита GC Root»Скрипт preStart создаёт GC root в ${stateDir}/.gc-root, указывающий на текущий пакет hermes. Это не позволяет nix-collect-garbage удалить запущенный бинарник. Если GC root по какой-то причине сломается, перезапуск сервиса создаст его заново.
Плагины
Заголовок раздела «Плагины»Модуль NixOS поддерживает декларативную установку плагинов — без необходимости в императивном hermes plugins install.
Плагины-каталоги (extraPlugins)
Заголовок раздела «Плагины-каталоги (extraPlugins)»Для плагинов, которые представляют собой просто дерево исходников с plugin.yaml + __init__.py (например, hermes-lcm):
services.hermes-agent.extraPlugins = [ (pkgs.fetchFromGitHub { owner = "stephenschoettler"; repo = "hermes-lcm"; rev = "v0.7.0"; hash = "sha256-..."; })];Плагины симлинкуются в $HERMES_HOME/plugins/ во время активации. Hermes обнаруживает их через своё обычное сканирование директории. Удаление плагина из списка и запуск nixos-rebuild switch удаляет симлинк.
Плагины точки входа (extraPythonPackages)
Заголовок раздела «Плагины точки входа (extraPythonPackages)»Для упакованных через pip плагинов, которые регистрируются через [project.entry-points."hermes_agent.plugins"] (например, rtk-hermes):
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 ]; })];Пакетный site-packages добавляется в PYTHONPATH в обёртке hermes. importlib.metadata обнаруживает точку входа при запуске сессии.
Комбинирование обоих
Заголовок раздела «Комбинирование обоих»Плагину директории со сторонними зависимостями Python нужны оба варианта:
services.hermes-agent = { extraPlugins = [ my-plugin-src ];
# plugin source extraPythonPackages = [ pkgs.python312Packages.redis ];
# its Python dep extraPackages = [ pkgs.redis ];
# system binary it needs};Использование overlay
Заголовок раздела «Использование overlay»Внешние flakes могут переопределять пакет напрямую:
{ inputs.hermes-agent.url = "github:NousResearch/hermes-agent"; outputs = { hermes-agent, nixpkgs, ... }: { nixpkgs.overlays = [ hermes-agent.overlays.default ];
# Then: pkgs.hermes-agent.override { extraPythonPackages = [...]; } };}Конфигурация плагинов
Заголовок раздела «Конфигурация плагинов»Плагины всё ещё нужно включать в config.yaml. Добавьте их через декларативные настройки:
services.hermes-agent.settings.plugins.enabled = [ "hermes-lcm" "rtk-rewrite"];Разработка
Заголовок раздела «Разработка»Dev Shell
Заголовок раздела «Dev Shell»Flake предоставляет среду разработки с Python 3.12, uv, Node.js и всеми runtime-инструментами:
cd hermes-agentnix develop
# Shell provides:#
- Python 3.12 + uv (deps installed into .venv on first entry)#
- Node.js 22, ripgrep, git, openssh, ffmpeg on PATH#
- Stamp-file optimization: re-entry is near-instant if deps haven't changed
hermes setuphermes chatdirenv (рекомендуется)
Заголовок раздела «direnv (рекомендуется)»Включённый .envrc автоматически активирует dev shell:
cd hermes-agentdirenv allow
# one-time# Subsequent entries are near-instant (stamp file skips dep install)Проверки flake
Заголовок раздела «Проверки flake»Flake включает проверку на этапе сборки, которая запускается в CI и локально:
# Run all checksnix flake check
# Individual checksnix build .#checks.x86_64-linux.package-contents
# binaries exist + versionnix build .#checks.x86_64-linux.entry-points-sync
# pyproject.toml ↔ Nix package syncnix build .#checks.x86_64-linux.cli-commands
# gateway/config subcommandsnix build .#checks.x86_64-linux.managed-guard
# HERMES_MANAGED blocks mutationnix build .#checks.x86_64-linux.bundled-skills
# skills present in packagenix build .#checks.x86_64-linux.config-roundtrip
# merge script preserves user keysЧто проверяет каждая проверка
| Проверка | Что она проверяет | |---|---| | `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, в wrapper задан `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 | Автоматически создавать user/group |
stateDir | str | "/var/lib/hermes" | Каталог состояния (родительский для HERMES_HOME) |
workingDirectory | str | "${stateDir}/workspace" | Рабочий каталог агента (MESSAGING_CWD) |
addToSystemPackages | bool | false | Добавить hermes CLI в системный PATH и задать HERMES_HOME на уровне системы |
Конфигурация
Заголовок раздела «Конфигурация»| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
settings | attrs (глубокое слияние) | {} | Декларативная конфигурация, отображаемая как config.yaml. Поддерживает произвольную вложенность; несколько определений объединяются через lib.recursiveUpdate |
configFile | null или path | null | Путь к существующему config.yaml. Полностью переопределяет settings, если задан |
Секреты и окружение| Option | Type | Default | Описание |
Заголовок раздела «Секреты и окружение| Option | Type | Default | Описание |»|---|---|---|---|
| environmentFiles | listOf str | [] | Пути к env-файлам с секретами. Объединяются в $HERMES_HOME/.env во время активации |
| environment | attrsOf str | {} | Несекретные env-переменные. Видимы в Nix store — не помещайте сюда секреты |
| authFile | null or path | null | Начальные OAuth credentials. Копируются только при первом развертывании |
| authFileForceOverwrite | bool | false | Всегда перезаписывать auth.json из authFile при активации |
Документы
Заголовок раздела «Документы»| Option | Type | Default | Описание |
|---|---|---|---|
documents | attrsOf (either str path) | {} | Файлы workspace. Ключи — это имена файлов, значения — встроенные строки или пути. Устанавливаются в workingDirectory при активации |
Серверы MCP
Заголовок раздела «Серверы MCP»| Option | Type | Default | Описание |
|---|---|---|---|
mcpServers | attrsOf submodule | {} | Определения серверов MCP, объединяются в settings.mcp_servers |
mcpServers.<name>.command | null or str | null | Команда сервера (транспорт stdio) |
mcpServers.<name>.args | listOf str | [] | Аргументы команды |
mcpServers.<name>.env | attrsOf str | {} | Переменные окружения для процесса сервера |
mcpServers.<name>.url | null or str | null | Endpoint сервера URL (транспорт HTTP/StreamableHTTP) |
mcpServers.<name>.headers | attrsOf str | {} | Заголовки HTTP, например Authorization |
mcpServers.<name>.auth | null or "oauth" | null | Метод аутентификации. "oauth" включает OAuth 2.1 PKCE |
mcpServers.<name>.enabled | bool | true | Включить или отключить этот сервер |
mcpServers.<name>.timeout | null or int | null | Таймаут вызова инструмента в секундах (по умолчанию: 120) |
mcpServers.<name>.connect_timeout | null or int | null | Таймаут соединения в секундах (по умолчанию: 60) |
mcpServers.<name>.tools | null or submodule | null | Фильтрация инструментов (списки include/exclude) |
mcpServers.<name>.sampling | null or submodule | null | Конфигурация sampling для инициируемых сервером запросов LLM |
Поведение сервиса| Опция | Тип | По умолчанию | Описание |
Заголовок раздела «Поведение сервиса| Опция | Тип | По умолчанию | Описание |»|---|---|---|---|
| extraArgs | listOf str | [] | Дополнительные аргументы для hermes gateway |
| extraPackages | listOf package | [] | Дополнительные пакеты, доступные агенту. Добавляются в профиль пользователя hermes на уровне пользователя, чтобы команды терминала, навыки и cron jobs все их видели |
| extraPlugins | listOf package | [] | Пакеты плагинов-каталогов для создания symlink в $HERMES_HOME/plugins/. Каждый должен содержать plugin.yaml |
| extraPythonPackages | listOf package | [] | Python-пакеты, добавляемые в PYTHONPATH для обнаружения плагинов через entry point. Сборка с помощью 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 | [] | Дополнительные монтирования томов (host:container:mode) |
container.extraOptions | listOf str | [] | Дополнительные аргументы, передаваемые в docker create |
container.hostUsers | listOf str | [] | Интерактивные пользователи, которые получают symlink ~/.hermes на stateDir сервиса и автоматически добавляются в группу hermes |
Структура каталогов
Заголовок раздела «Структура каталогов»Нативный режим
Заголовок раздела «Нативный режим»/var/lib/hermes/
# stateDir (owned by hermes:hermes, 0750)├── .hermes/
# HERMES_HOME│ ├── config.yaml
# Nix-generated (deep-merged each rebuild)│ ├── .managed
# Marker: CLI config mutation blocked│ ├── .env
# Merged from environment + environmentFiles│ ├── auth.json
# OAuth credentials (seeded, then self-managed)│ ├── gateway.pid│ ├── state.db│ ├── mcp-tokens/
# OAuth tokens for MCP servers│ ├── sessions/│ ├── memories/│ ├── skills/│ ├── cron/│ └── logs/├── home/
# Agent HOME└── workspace/
# MESSAGING_CWD ├── SOUL.md
# From documents option └── (agent-created files)Режим контейнера
Заголовок раздела «Режим контейнера»Та же структура, смонтированная в контейнер:
| Путь в контейнере | Путь на хосте | Режим | Примечания |
|---|---|---|---|
/nix/store | /nix/store | ro | Бинарный файл Hermes + все зависимости Nix |
/data | /var/lib/hermes | rw | Всё состояние, конфиг, рабочее пространство |
/home/hermes | ${stateDir}/home | rw | Постоянный домашний каталог агента — pip install --user, кэши инструментов |
/usr, /usr/local, /tmp | (записываемый слой) | rw | Установки apt/pip/npm — сохраняются между перезапусками, теряются при пересоздании |
Обновление
Заголовок раздела «Обновление»# Update the flake input (run from the directory containing flake.nix)cd /etc/nixos && nix flake update hermes-agent
# Rebuildsudo nixos-rebuild switchВ режиме контейнера обновляется символическая ссылка current-package, и после перезапуска агент подхватывает новый бинарный файл. Пересоздание контейнера не требуется, потери установленных пакетов нет.
Устранение неполадок
Заголовок раздела «Устранение неполадок»:::tip Пользователи Podman
Все команды docker ниже работают так же с podman. При необходимости замените их соответствующим образом, если вы задали container.backend = "podman".
:::
Логи сервиса
Заголовок раздела «Логи сервиса»# Both modes use the same systemd unitjournalctl -u hermes-agent -f
# Container mode: also available directlydocker logs -f hermes-agentПроверка контейнера
Заголовок раздела «Проверка контейнера»systemctl status hermes-agentdocker ps -a --filter name=hermes-agentdocker inspect hermes-agent --format='{{.State.Status}}'docker exec -it hermes-agent bashdocker exec hermes-agent readlink /data/current-packagedocker exec hermes-agent cat /data/.container-identityПринудительное пересоздание контейнера
Заголовок раздела «Принудительное пересоздание контейнера»Если нужно сбросить writable layer (чистый Ubuntu):
sudo systemctl stop hermes-agentdocker rm -f hermes-agentsudo rm /var/lib/hermes/.container-identitysudo systemctl start hermes-agentПроверка, что секреты загружены
Заголовок раздела «Проверка, что секреты загружены»Если агент запускается, но не может пройти аутентификацию у провайдера LLM, проверьте, что файл .env был объединён корректно:
# Native modesudo -u hermes cat /var/lib/hermes/.hermes/.env
# Container modedocker exec hermes-agent cat /data/.hermes/.envПроверка GC root
Заголовок раздела «Проверка GC root»nix-store --query --roots $(docker exec hermes-agent readlink /data/current-package)Частые проблемы
Заголовок раздела «Частые проблемы»| Симптом | Причина | Решение |
|---|---|---|
Cannot save configuration: managed by NixOS | guards CLI активны | Отредактируйте configuration.nix и nixos-rebuild switch |
| Контейнер неожиданно пересоздался | Изменились extraVolumes, extraOptions или image | Это ожидаемо — writable layer сбрасывается. Переустановите пакеты или используйте пользовательский образ |
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 (см. раздел Container Mode) |
unable to find user hermes | Контейнер всё ещё запускается (entrypoint ещё не создал пользователя) | Подождите несколько секунд и повторите попытку — CLI автоматически выполняет повторные попытки |
Инструмент, добавленный через extraPackages, не найден в терминале | Требуется nixos-rebuild switch для обновления профиля пользователя | Пересоберите и перезапустите: nixos-rebuild switch && systemctl restart hermes-agent |