Skip to main content

Nix 与 NixOS 配置

Hermes Agent 提供了一个 Nix flake,包含三个层级的集成:

层级适用对象你将获得
nix run / nix profile install所有 Nix 用户(macOS、Linux)带有所有依赖项的预构建二进制文件 —— 然后使用标准 CLI 工作流
NixOS 模块(原生)NixOS 服务器部署声明式配置、强化的 systemd 服务、受管理的密钥
NixOS 模块(容器)需要自我修改的代理上述全部功能,外加一个持久化的 Ubuntu 容器,代理可在其中进行 apt/pip/npm install
与标准安装的不同之处

curl | bash 安装程序自行管理 Python、Node 和依赖项。而 Nix flake 取代了这一切——每个 Python 依赖都是由 uv2nix 构建的 Nix 衍生品,运行时工具(Node.js、git、ripgrep、ffmpeg)也被打包进二进制文件的 PATH 中。无需运行时 pip,无需虚拟环境激活,也无需 npm install

对于非 NixOS 用户,这仅改变了安装步骤。之后的所有操作(hermes setuphermes gateway install、配置编辑)与标准安装完全相同。

对于 NixOS 模块用户,整个生命周期完全不同:配置位于 configuration.nix,密钥通过 sops-nix/agenix 管理,服务为 systemd 单元,CLI 配置命令被禁用。你管理 hermes 的方式与其他任何 NixOS 服务一致。

先决条件

  • 启用 flakes 的 Nix —— 推荐使用 Determinate Nix(默认启用 flakes)
  • 使用的服务所需的 API 密钥(至少需要一个 OpenRouter 或 Anthropic 的密钥)

快速入门(任意 Nix 用户)

无需克隆仓库。Nix 会自动获取、构建并运行所有内容:

# Run directly (builds on first use, cached after)
nix run github:NousResearch/hermes-agent -- setup
nix run github:NousResearch/hermes-agent -- chat

# Or install persistently
nix profile install github:NousResearch/hermes-agent
hermes setup
hermes chat

nix profile install 后,hermeshermes-agenthermes-acp 将出现在你的 PATH 中。从此时起,工作流程与 标准安装 完全相同——hermes setup 引导你完成提供者选择,hermes gateway install 设置 launchd(macOS)或 systemd 用户服务,配置文件位于 ~/.hermes/

从本地克隆构建
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
nix build
./result/bin/hermes setup

NixOS 模块

该 flake 导出 nixosModules.default —— 一个完整的 NixOS 服务模块,可声明式地管理用户创建、目录、配置生成、密钥、文档和服务生命周期。

note

此模块需要 NixOS。对于非 NixOS 系统(macOS、其他 Linux 发行版),请使用 nix profile install 和上述标准 CLI 工作流。

添加 Flakes 输入

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

最小化配置

# 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,连接密钥,并启动网关——一个长期运行的服务,用于连接代理至消息平台(Telegram、Discord 等),并监听传入消息。

必须提供密钥

上文中的 environmentFiles 行假定你已配置 sops-nixagenix。该文件应至少包含一个 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/env
services.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];
addToSystemPackages

设置 addToSystemPackages = true 有两点作用:将 hermes CLI 放入系统 PATH 在系统范围内设置 HERMES_HOME,使交互式 CLI 与网关服务共享状态(会话、技能、定时任务)。若不设置,你在 shell 中运行 hermes 会创建一个独立的 ~/.hermes/ 目录。

容器感知 CLI

container.enable = trueaddToSystemPackages = true 启用时,主机上的每一个 hermes 命令都会自动路由到托管容器中。这意味着你的交互式 CLI 会话运行在与网关服务相同的环境中——可访问容器内安装的所有包和工具。

  • 路由是透明的:hermes chathermes sessions listhermes version 等命令均在后台执行进入容器
  • 所有 CLI 标志都原样转发
  • 若容器未运行,CLI 会短暂重试(交互式使用为 5 秒带旋转动画,脚本为 10 秒静默),然后以清晰错误失败——无静默回退
  • 对于开发人员,若想绕过容器路由并直接运行本地代码库,可设置 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 组套接字获得访问权限,但 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 后,检查服务是否正在运行:

# Check service status
systemctl status hermes-agent

# Watch logs (Ctrl+C to stop)
journalctl -u hermes-agent -f

# If addToSystemPackages is true, test the CLI
hermes version
hermes config # shows the generated config

选择部署模式

该模块支持两种模式,由 container.enable 控制:

原生(默认)容器
运行方式主机上的强化 systemd 服务持久化的 Ubuntu 容器,/nix/store 被挂载
安全性NoNewPrivilegesProtectSystem=strictPrivateTmp容器隔离,以非特权用户身份运行
代理能否自安装包否 —— 仅限 Nix 提供的 PATH 中的工具是 —— aptpipnpm 的安装在重启后仍保留
配置表面相同相同
何时选择标准部署、最高安全性、可复现性代理需要运行时包安装、可变环境、实验性工具

要启用容器模式,只需添加一行:

{
services.hermes-agent = {
enable = true;
container.enable = true;
# ... rest of config is identical
};
}
info

容器模式会通过 mkDefault 自动启用 virtualisation.docker.enable。若使用 Podman,请设置 container.backend = "podman"virtualisation.docker.enable = false


配置

声明式设置

settings 选项接受任意 attrset,将其渲染为 config.yaml。它支持跨多个模块定义的深度合并(通过 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.disabledstreaming.enabled 的键,它们将在 nixos-rebuild switch 后依然存在。

模型命名

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。

查看可用配置键

运行 nix build .#configKeys && cat result 以查看从 Python 的 DEFAULT_CONFIG 提取的所有叶级配置键。你可以将现有的 config.yaml 粘贴到 settings attrset 中,结构完全一一对应。

完整示例:所有常见可自定义设置
{ config, ... }: {
services.hermes-agent = {
enable = true;
container.enable = true;

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

# ── Secrets ────────────────────────────────────────────────────────
environmentFiles = [ config.sops.secrets."hermes-env".path ];

# ── Documents ──────────────────────────────────────────────────────
documents = {
"SOUL.md" = builtins.readFile /home/user/.hermes/SOUL.md;
"USER.md" = ./documents/USER.md;
};

# ── MCP Servers ────────────────────────────────────────────────────
mcpServers.filesystem = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-filesystem" "/data/workspace" ];
};

# ── Container options ──────────────────────────────────────────────
container = {
image = "ubuntu:24.04";
backend = "docker";
hostUsers = [ "your-username" ];
extraVolumes = [ "/home/user/projects:/projects:rw" ];
extraOptions = [ "--gpus" "all" ];
};

# ── Service tuning ─────────────────────────────────────────────────
addToSystemPackages = true;
extraArgs = [ "--verbose" ];
restart = "always";
restartSec = 5;
};
}

逃生通道:使用你自己的配置

如果你更希望完全在 Nix 之外管理 config.yaml,可以使用 configFile

services.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 ]
给代理赋予个性documents."SOUL.md"builtins.readFile ./my-soul.md
添加 MCP 工具服务器mcpServers.<name>参见 MCP 服务器
将主机目录挂载到容器中container.extraVolumes[ "/data:/data:rw" ]
向容器传递 GPU 访问权限container.extraOptions[ "--gpus" "all" ]
使用 Podman 而非 Dockercontainer.backend"podman"
在主机 CLI 与容器之间共享状态container.hostUsers[ "sidbin" ]
向服务 PATH 添加工具(仅原生模式)extraPackages[ pkgs.pandoc pkgs.imagemagick ]
使用自定义基础镜像container.image"ubuntu:24.04"
覆盖 hermes 包packageinputs.hermes-agent.packages.${system}.default.override { ... }
更改状态目录stateDir"/opt/hermes"
设置代理的工作目录workingDirectory"/home/user/projects"

密钥管理

千万不要将 API 密钥放入 settingsenvironment

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 (encrypted with 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; # overwrite on every activation
};
}

该文件仅在 auth.json 不存在时才会被复制(除非设置了 authFileForceOverwrite = true)。运行时的 OAuth token 刷新会写入状态目录,并在重建之间持久保留。


文档管理

documents 选项会将文件安装到代理的工作目录(即 workingDirectory,代理将其作为工作区读取)。Hermes 会按约定查找特定文件名:

  • SOUL.md — 代理的系统提示 / 个性设定。Hermes 在启动时读取此文件,并将其作为持久指令,持续影响其行为。
  • USER.md — 关于代理正在交互的用户的信息。
  • 其他放置在此处的文件也会被代理视为工作区文件可见。
{
services.hermes-agent.documents = {
"SOUL.md" = ''
You are a helpful research assistant specializing in NixOS packaging.
Always cite sources and prefer reproducible solutions.
'';
"USER.md" = ./documents/USER.md; # path reference, copied from Nix store
};
}

值可以是内联字符串或路径引用。这些文件会在每次 nixos-rebuild switch 时重新安装。


MCP 服务器

mcpServers 选项以声明方式配置 MCP(模型上下文协议) 服务器。每个服务器使用 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}"; # resolved from .env
};
};
}
tip

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

带 OAuth 的 HTTP 传输

为使用 OAuth 2.1 的服务器设置 auth = "oauth"。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 授权

首次 OAuth 授权需要浏览器式的同意流程。在无头部署中,Hermes 会将授权 URL 输出到 stdout/logs,而不是打开浏览器。

方案 A:交互式引导 —— 通过 docker exec(容器)或 sudo -u hermes(原生)运行一次流程:

# Container mode
docker exec -it hermes-agent \
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth

# Native mode
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,因此 127.0.0.1 上的 OAuth 回调监听器可以从主机浏览器访问。

方案 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/
# Ensure: 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配置是声明式的——请在你的 Nix 配置中编辑 settings
hermes config edit配置由 settings 生成
hermes config set <key> <value>配置由 settings 生成
hermes gateway installsystemd 服务由 NixOS 管理
hermes gateway uninstallsystemd 服务由 NixOS 管理

这防止了 Nix 声明与磁盘上实际配置之间的偏差。检测机制依赖两个信号:

  1. HERMES_MANAGED=true 环境变量 —— 由 systemd 服务设置,对网关进程可见
  2. .managed 标记文件 —— 由激活脚本设置,对交互式 shell 可见(例如 docker exec -it hermes-agent hermes config set ... 也被阻止)

要更改配置,请编辑你的 Nix 配置并运行 sudo nixos-rebuild switch


容器架构

info

本节仅适用于使用 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 被绑定挂载——它自带解释器和所有依赖项,不依赖容器的系统库。容器入口点通过一个 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 根)持久化持久化持久化
镜像变更(container.image持久化持久化丢失
卷/选项变更持久化持久化丢失
environment/environmentFiles 变更持久化持久化持久化

容器仅在它的身份哈希发生变化时才被重建。该哈希涵盖:模式版本、镜像、extraVolumesextraOptions 和入口脚本。对环境变量、设置、文档或 hermes 包本身的更改不会触发重建。:::warning 可写层数据丢失 当身份哈希发生变化时(如镜像升级、新增卷或容器选项),容器将被销毁并从全新的 container.image 拉取重建。任何存在于可写层中的 apt installpip installnpm install 包都将丢失。而 /data/home/hermes 中的状态会被保留(这些是绑定挂载)。

如果代理依赖特定的包,请考虑将其烘焙进自定义镜像(container.image = "my-registry/hermes-base:latest")中,或在代理的 SOUL.md 中编写脚本进行安装。 :::

GC 根保护

preStart 脚本会在 ${stateDir}/.gc-root 处创建一个 GC 根,指向当前运行的 hermes 包。这可以防止 nix-collect-garbage 删除正在运行的二进制文件。如果该 GC 根意外失效,重启服务后会自动重建。


开发

开发环境 Shell

该 flake 提供了一个包含 Python 3.11、uv、Node.js 以及所有运行时工具的开发环境:

```bash
cd hermes-agent
nix develop

# Shell provides:
# - Python 3.11 + uv (deps installed into .venv on first entry)
# - Node.js 20, ripgrep, git, openssh, ffmpeg on PATH
# - Stamp-file optimization: re-entry is near-instant if deps haven't changed

hermes setup
hermes chat

### direnv(推荐)

项目中包含的 ``.envrc`` 可以自动激活开发环境:

```bash
```bash
cd hermes-agent
direnv allow # one-time
# Subsequent entries are near-instant (stamp file skips dep install)

### Flake 检查

该 flake 包含构建时验证,可在 CI 和本地运行:

```bash
```bash
# Run all checks
nix flake check

# Individual checks
nix build .#checks.x86_64-linux.package-contents # binaries exist + version
nix build .#checks.x86_64-linux.entry-points-sync # pyproject.toml ↔ Nix package sync
nix build .#checks.x86_64-linux.cli-commands # gateway/config subcommands
nix build .#checks.x86_64-linux.managed-guard # HERMES_MANAGED blocks mutation
nix build .#checks.x86_64-linux.bundled-skills # skills present in package
nix build .#checks.x86_64-linux.config-roundtrip # merge script preserves user keys

<details>
<summary><strong>每项检查所验证的内容</strong></summary>

| 检查 | 测试内容 |
|---|---|
| ``package-contents`` | 确保 ``hermes`` 和 ``hermes-agent`` 二进制文件存在,并且 ``hermes version`` 能正常运行 |
| ``entry-points-sync`` | 确保 ``[project.scripts]`` 列表中的每个条目,在 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 增量合并、嵌套深层合并、幂等性 |

</details>

---

## 选项参考

### 核心配置

| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| ``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`` | 将 ``hermes`` CLI 添加到系统 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 存储** —— 请勿在此处放置密钥 |
| ``authFile`` | ``null`` 或 ``path`` | ``null`` | OAuth 凭据种子。仅在首次部署时复制 |
| ``authFileForceOverwrite`` | ``bool`` | ``false`` | 总是使用 ``authFile`` 中的内容覆盖 ``auth.json`` |

### 文档

| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| ``documents`` | ``attrsOf (either str path)`` | ``{}`` | 工作区文件。键为文件名,值为内联字符串或路径。在激活时安装至 ``workingDirectory`` |

### MCP 服务器

| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| ``mcpServers`` | ``attrsOf submodule`` | ``{}`` | MCP 服务器定义,合并至 ``settings.mcp_servers`` |
| ``mcpServers.<name>.command`` | ``null`` 或 ``str`` | ``null`` | 服务器命令(标准输入输出传输) |
| ``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`` | ``[]`` | 服务 PATH 上的额外包(仅原生模式) |
| ``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`` | ``[]`` | 交互式用户,会获得指向服务 `stateDir` 的 ``~/.hermes`` 符号链接,并自动加入 ``hermes`` 组 |

---

## 目录结构

### 原生模式

```bash

/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
nix flake update hermes-agent --flake /etc/nixos

# Rebuild
sudo nixos-rebuild switch

在容器模式下,current-package 符号链接会被更新,代理在下次重启时自动加载新二进制文件。无需重新创建容器,也不会丢失已安装的包。


故障排查

Podman 用户

以下所有 docker 命令在使用 podman 时行为相同。若你设置了 container.backend = "podman",请相应替换。

服务日志

# Both modes use the same systemd unit
journalctl -u hermes-agent -f

# Container mode: also available directly
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 文件是否已正确合并:

# Native mode
sudo -u hermes cat /var/lib/hermes/.hermes/.env

# Container mode
docker exec hermes-agent cat /data/.hermes/.env

GC 根验证

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

常见问题

现象原因解决方法
Cannot save configuration: managed by NixOSCLI 保护机制启用编辑 configuration.nixnixos-rebuild switch
容器意外被重新创建extraVolumesextraOptionsimage 发生变化属于正常行为 — 可写层将重置。请重新安装包或使用自定义镜像
hermes version 显示旧版本容器未重启执行 systemctl restart hermes-agent
/var/lib/hermes 上权限拒绝状态目录为 0750 hermes:hermes使用 docker execsudo -u hermes
nix-collect-garbage 移除了 hermesGC 根缺失重启服务(preStart 会重新创建 GC 根)
no container with name or ID "hermes-agent"(Podman)Podman rootful 容器对普通用户不可见为 podman 添加无密码 sudo 权限(参见 容器感知 CLI 章节)
unable to find user hermes容器仍在启动中(入口脚本尚未创建用户)等待几秒后重试 — CLI 会自动重试