Nix & NixOS Setup

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 бинарника. Нет pip во время выполнения, нет активации venv, нет npm install.

Для пользователей не-NixOS это меняет только шаг установки. Всё остальное (hermes setup, hermes gateway install, редактирование конфигурации) работает идентично стандартной установке.

Для пользователей NixOS-модуля весь жизненный цикл отличается: конфигурация находится в configuration.nix, секреты проходят через sops-nix/agenix, сервис является systemd-юнитом, а CLI-команды конфигурации заблокированы. Вы управляете hermes так же, как управляете любым другим NixOS-сервисом.

Предварительные требования


Быстрый старт (любой пользователь Nix)

Клонирование не требуется. Nix загружает, собирает и запускает всё:

# Запуск напрямую (сборка при первом использовании, затем кэшируется)
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

После nix profile install, hermes, hermes-agent и hermes-acp оказываются в вашем PATH. Отсюда воркфлоу идентичен стандартной установкеhermes setup проведёт вас через выбор провайдера, hermes gateway install настраивает launchd (macOS) или systemd user-сервис, а конфигурация хранится в ~/.hermes/.

Сборка из локального клона
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
nix build
./result/bin/hermes setup

NixOS-модуль

Flake экспортирует nixosModules.default — полноценный NixOS-сервисный модуль, который декларативно управляет созданием пользователя, каталогами, генерацией конфигурации, секретами, документами и жизненным циклом сервиса.

Этот модуль требует NixOS. Для систем без NixOS (macOS, другие дистрибутивы Linux) используйте `nix profile install` и стандартный CLI-воркфлоу, описанный выше.

Добавление Flake Input

# /etc/nixos/flake.nix (или ваш системный 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
      ];
    };
  };
}

Минимальная конфигурация

# 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=***" | sudo install -m 0600 -o hermes /dev/stdin /var/lib/hermes/env
services.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];

tip addToSystemPackages Установка addToSystemPackages = true делает две вещи: помещает CLI hermes в системный PATH и устанавливает HERMES_HOME общесистемно, чтобы интерактивный CLI разделял состояние (сессии, навыки, cron) с gateway-сервисом. Без этого запуск hermes в вашей оболочке создаст отдельный каталог ~/.hermes/.

CLI с поддержкой контейнера

Когда `container.enable = true` и `addToSystemPackages = true`, **каждая** команда `hermes` на хосте автоматически направляется в управляемый контейнер. Это означает, что ваша интерактивная CLI-сессия работает внутри того же окружения, что и gateway-сервис — с доступом ко всем установленным в контейнере пакетам и инструментам. - Маршрутизация прозрачна: `hermes chat`, `hermes sessions list`, `hermes version` и т.д. все выполняются внутри контейнера - Все CLI-флаги передаются как есть - Если контейнер не запущен, CLI делает несколько попыток (5 с со спиннером для интерактивного использования, 10 с без вывода для скриптов), затем завершается с понятной ошибкой — без скрытого отката - Для разработчиков, работающих над кодом hermes, установите `HERMES_DEV=1`, чтобы обойти маршрутизацию в контейнер и запускать локальную копию напрямую Установите `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. Предоставьте sudo без пароля для вашей среды выполнения контейнеров:
security.sudo.extraRules = [{
  users = [ "your-username" ];
  commands = [{
    command = "/run/current-system/sw/bin/podman";
    options = [ "NOPASSWD" ];
  }];
}];
CLI автоматически определяет, когда нужен sudo, и использует его прозрачно. Без этого вам придётся запускать `sudo hermes chat` вручную.

Проверка работоспособности

После nixos-rebuild switch проверьте, что сервис работает:

# Проверка статуса сервиса
systemctl status hermes-agent

# Просмотр логов (Ctrl+C для остановки)
journalctl -u hermes-agent -f

# Если addToSystemPackages = true, проверьте CLI
hermes version
hermes config       # показывает сгенерированную конфигурацию

Выбор режима развёртывания

Модуль поддерживает два режима, управляемых через container.enable:

Нативный (по умолчанию) Контейнер
Как работает Защищённый systemd-сервис на хосте Постоянный Ubuntu-контейнер с /nix/store примонтированным bind-mount
Безопасность NoNewPrivileges, ProtectSystem=strict, PrivateTmp Изоляция контейнера, запуск от непривилегированного пользователя внутри
Агент может сам устанавливать пакеты Нет — только инструменты на PATH, предоставленном Nix Да — установки apt, pip, npm сохраняются между перезапусками
Поверхность конфигурации Одинаковая Одинаковая
Когда выбирать Стандартные развёртывания, максимальная безопасность, воспроизводимость Агенту требуется установка пакетов во время выполнения, изменяемое окружение, экспериментальные инструменты

Чтобы включить режим контейнера, добавьте одну строку:

{
  services.hermes-agent = {
    enable = true;
    container.enable = true;
    # ... остальная конфигурация идентична
  };
}
Режим контейнера автоматически включает `virtualisation.docker.enable` через `mkDefault`. Если вы используете Podman, установите `container.backend = "podman"` и `virtualisation.docker.enable = false`.

Конфигурация

Декларативные настройки

Опция settings принимает произвольный attrset, который преобразуется в config.yaml. Она поддерживает глубокое слияние (deep merge) между несколькими определениями модулей (через lib.recursiveUpdate), так что вы можете разделять конфигурацию по файлам:

# 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; };
};

Оба объединяются глубоким слиянием на этапе оценки. Ключи, объявленные в 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 и используйте их нативные идентификаторы моделей (например, "claude-sonnet-4-20250514"). Если base_url не установлен, Hermes по умолчанию использует OpenRouter.

tip Обнаружение доступных ключей конфигурации Запустите nix build .#configKeys && cat result, чтобы увидеть каждый листовой ключ конфигурации, извлечённый из Python-DEFAULT_CONFIG. Вы можете вставить ваш существующий config.yaml в attrset settings — структура отображается 1:1.

Полный пример: все часто настраиваемые параметры
{ 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;
  };
}

Запасной выход: собственная конфигурация

Если вы предпочитаете управлять config.yaml полностью вне Nix, используйте configFile:

services.hermes-agent.configFile = /etc/hermes/config.yaml;

Это полностью обходит settings — никакого слияния, никакой генерации. Файл копируется как есть в $HERMES_HOME/config.yaml при каждой активации.

Шпаргалка по настройке

Краткая справка по самым распространённым вещам, которые пользователи Nix хотят настроить:

Я хочу... Опция Пример
Сменить модель LLM settings.model.default "anthropic/claude-sonnet-4"
Использовать другой endpoint провайдера 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 = {
    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 (зашифрован с помощью sops)
hermes-env: |
    OPENROUTER_API_KEY=sk-or-...
    TELEGRAM_BOT_TOKEN=123456:ABC...
    ANTHROPIC_API_KEY=sk-ant-...

agenix

{
  age.secrets.hermes-env.file = ./secrets/hermes-env.age;

  services.hermes-agent.environmentFiles = [
    config.age.secrets.hermes-env.path
  ];
}

OAuth / начальное внесение аутентификации

Для платформ, требующих OAuth (например, Discord), используйте authFile для начального внесения учётных данных при первом развёртывании:

{
  services.hermes-agent = {
    authFile = config.sops.secrets."hermes/auth.json".path;
    # authFileForceOverwrite = true;  # перезаписывать при каждой активации
  };
}

Файл копируется только если auth.json ещё не существует (если authFileForceOverwrite = true не установлен). Обновления OAuth-токенов во время выполнения записываются в каталог состояния и сохраняются между пересборками.


Документы

Опция documents устанавливает файлы в рабочую директорию агента (рабочая директория, которую агент читает как своё рабочее пространство). Hermes ищет определённые имена файлов по соглашению:

Файл идентичности агента отдельный: 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;  # ссылка на путь, копируется из Nix store
  };
}

Значения могут быть inline-строками или ссылками на пути. Файлы устанавливаются при каждом nixos-rebuild switch.


MCP-серверы

Опция mcpServers декларативно настраивает MCP (Model Context Protocol) серверы. Каждый сервер использует либо stdio (локальная команда), либо HTTP (удалённый URL) транспорт.

Транспорт 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}"; # берётся из .env
    };
  };
}
Переменные окружения в значениях `env` извлекаются из `$HERMES_HOME/.env` во время выполнения. Используйте `environmentFiles` для внесения секретов — никогда не помещайте токены напрямую в Nix-конфигурацию.

HTTP-транспорт (удалённые серверы)

{
  services.hermes-agent.mcpServers.remote-api = {
    url = "https://mcp.example.com/v1/mcp";
    headers.Authorization = "Bearer \\${MCP_REMOTE_API_KEY}";
    timeout = 180;
  };
}

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/<имя-сервера>.json и сохраняются между перезапусками и пересборками.

Первоначальная OAuth-авторизация на серверах без головы (headless) Первая OAuth-авторизация требует браузерного потока согласия. При headless-развёртывании Hermes выводит URL авторизации в stdout/логи вместо открытия браузера. **Вариант A: Интерактивная начальная настройка** — выполните поток один раз через `docker exec` (контейнер) или `sudo -u hermes` (нативный режим):
# Режим контейнера
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
Контейнер использует `--network=host`, поэтому OAuth callback-слушатель на `127.0.0.1` доступен из браузера хоста. **Вариант B: Предварительное внесение токенов** — выполните поток на рабочей станции, затем скопируйте токены:
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

Сэмплинг (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, и тем, что находится на диске. Обнаружение использует два сигнала:

  1. HERMES_MANAGED=true переменная окружения — устанавливается systemd-сервисом, видна процессу gateway

  2. Файл-маркер .managed в HERMES_HOME — устанавливается скриптом активации, виден интерактивным оболочкам (например, docker exec -it hermes-agent hermes config set ... тоже заблокирован)

Чтобы изменить конфигурацию, отредактируйте вашу Nix-конфигурацию и выполните sudo nixos-rebuild switch.


Архитектура контейнера

Этот раздел актуален только если вы используете `container.enable = true`. Пропустите его для развёртываний в нативном режиме.

Когда режим контейнера включён, hermes работает внутри постоянного Ubuntu-контейнера, при этом бинарник, собранный Nix, примонтирован read-only с хоста:

Хост                                    Контейнер
────                                    ─────────
/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 — он несёт собственный интерпретатор и все зависимости, поэтому нет зависимости от системных библиотек контейнера. Точка входа контейнера разрешается через симлинк 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 Нет Сохраняется Сохраняется Сохраняется

Контейнер пересоздаётся только когда изменяется его identity hash. Хеш включает: версию схемы, образ, extraVolumes, extraOptions и скрипт entrypoint. Изменения переменных окружения, настроек, документов или самого пакета hermes не вызывают пересоздание.

warning Потеря слоя записи Когда изменяется identity hash (апгрейд образа, новые тома, новые опции контейнера), контейнер уничтожается и создаётся заново из свежего образа container.image. Все пакеты apt install, pip install или npm install в слое записи теряются. Состояние в /data и /home/hermes сохраняется (это bind-mounts).

Если агент полагается на определённые пакеты, рассмотрите возможность включения их в пользовательский образ (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):

services.hermes-agent.extraPlugins = [
  (pkgs.fetchFromGitHub {
    owner = "stephenschoettler";
    repo = "hermes-lcm";
    rev = "v0.7.0";
    hash = "sha256-...";
  })
];

Плагины симлинкуются в $HERMES_HOME/plugins/ во время активации. Hermes обнаруживает их через обычное сканирование каталогов. Удаление плагина из списка и запуск nixos-rebuild switch удаляет симлинк.

Entry-point плагины (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 ];          # исходники плагина
  extraPythonPackages = [ pkgs.python312Packages.redis ];  # его Python-зависимость
  extraPackages = [ pkgs.redis ];            # системный бинарник, который ему нужен
};

Использование Overlay

Внешние flakes могут переопределить пакет напрямую:

{
  inputs.hermes-agent.url = "github:NousResearch/hermes-agent";
  outputs = { hermes-agent, nixpkgs, ... }: {
    nixpkgs.overlays = [ hermes-agent.overlays.default ];
    # Затем: pkgs.hermes-agent.override { extraPythonPackages = [...]; }
  };
}

Конфигурация плагинов

Плагины всё ещё нужно включить в config.yaml. Добавьте их через декларативные настройки:

services.hermes-agent.settings.plugins.enabled = [
  "hermes-lcm"
  "rtk-rewrite"
];
Проверка коллизий во время сборки предотвращает перекрытие пакетов плагинов с основными зависимостями hermes. Если плагин предоставляет пакет, который уже есть в изолированном venv, `nixos-rebuild` завершится с понятной ошибкой.

Разработка

Dev Shell (оболочка разработчика)

Flake предоставляет оболочку разработчика с Python 3.12, uv, Node.js и всеми инструментами времени выполнения:

cd hermes-agent
nix develop

# Оболочка предоставляет:
#   - Python 3.12 + uv (зависимости устанавливаются в .venv при первом входе)
#   - Node.js 22, ripgrep, git, openssh, ffmpeg на PATH
#   - Stamp-file оптимизация: повторный вход почти мгновенный, если зависимости не изменились

hermes setup
hermes chat

Включённый .envrc активирует оболочку разработчика автоматически:

cd hermes-agent
direnv allow    # однократно
# Последующие входы почти мгновенные (stamp file пропускает установку зависимостей)

Проверки Flake

Flake включает проверки во время сборки, которые выполняются в CI и локально:

# Запустить все проверки
nix flake check

# Отдельные проверки
nix build .#checks.x86_64-linux.package-contents   # бинарники существуют + версия
nix build .#checks.x86_64-linux.entry-points-sync  # синхронизация pyproject.toml ↔ Nix package
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    # скрипт слияния сохраняет ключи пользователя
Что проверяет каждая проверка | Проверка | Что тестирует | |---|---| | `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) {} Файлы рабочего пространства. Ключи — имена файлов, значения — inline-строки или пути. Устанавливаются в 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 endpoint сервера (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 для обнаружения 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 [] Дополнительные монтирования томов (хост:контейнер:режим)
container.extraOptions listOf str [] Дополнительные аргументы, передаваемые в docker create
container.hostUsers listOf str [] Интерактивные пользователи, получающие симлинк ~/.hermes на служебный stateDir и автоматически добавляемые в группу hermes

Структура каталогов

Нативный режим

/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
    └── (файлы созданные агентом)

Режим контейнера

Та же структура, смонтированная в контейнер:

Путь в контейнере Путь на хосте Режим Примечания
/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 — сохраняются между перезапусками, теряются при пересоздании

Обновление

# Обновление flake input (запускается из каталога, содержащего flake.nix)
cd /etc/nixos && nix flake update hermes-agent

# Пересборка
sudo nixos-rebuild switch

В режиме контейнера симлинк current-package обновляется, и агент подхватывает новый бинарник при перезапуске. Без пересоздания контейнера, без потери установленных пакетов.


Устранение неполадок

tip Пользователи Podman Все команды docker ниже работают так же с podman. Заменяйте соответствующим образом, если вы установили container.backend = "podman".

Логи сервиса

# Оба режима используют один и тот же systemd-юнит
journalctl -u hermes-agent -f

# Режим контейнера: также доступно напрямую
docker logs -f hermes-agent

Инспекция контейнера

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

Принудительное пересоздание контейнера

Если нужно сбросить слой записи (свежий Ubuntu):

sudo systemctl stop hermes-agent
docker rm -f hermes-agent
sudo rm /var/lib/hermes/.container-identity
sudo systemctl start hermes-agent

Проверка загрузки секретов

Если агент запускается, но не может аутентифицироваться у LLM-провайдера, проверьте, что файл .env был корректно объединён:

# Нативный режим
sudo -u hermes cat /var/lib/hermes/.hermes/.env

# Режим контейнера
docker exec hermes-agent cat /data/.hermes/.env

Проверка GC Root

nix-store --query --roots $(docker exec hermes-agent readlink /data/current-package)

Частые проблемы

Симптом Причина Решение
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 Контейнер всё ещё запускается (entrypoint ещё не создал пользователя) Подождите несколько секунд и повторите — CLI повторяет попытку автоматически
Инструмент, добавленный через extraPackages, не найден в терминале Требуется nixos-rebuild switch для обновления per-user профиля Пересоберите и перезапустите: nixos-rebuild switch && systemctl restart hermes-agent