Nix 与 NixOS 设置
Hermes Agent 提供了一个 Nix flake,支持三种集成层级:
| Level | Who it's for | What you get |
|---|---|---|
nix run / nix profile install | 任意 Nix 用户(macOS、Linux) | 含全部依赖的预构建二进制,然后直接走标准 CLI 工作流 |
| NixOS module (native) | NixOS 服务器部署 | 声明式配置、加固的 systemd 服务、托管式密钥 |
| NixOS module (container) | 需要自我修改环境的 agent | 包含以上全部能力,外加一个持久化 Ubuntu 容器,让 agent 可以在里面执行 apt/pip/npm install |
curl | bash 安装器会自行管理 Python、Node 和依赖。Nix flake 则完全替代这套机制:所有 Python 依赖都会作为 Nix derivation 通过 uv2nix 构建,运行时工具(Node.js、git、ripgrep、ffmpeg)也会被打包进二进制的 PATH。这里没有运行时 pip、没有 venv 激活,也没有 npm install。
对于非 NixOS 用户,变化只发生在安装环节。后续流程(hermes setup、hermes gateway install、编辑配置)与标准安装完全一致。
对于 NixOS module 用户,整个生命周期都不同:配置放在 configuration.nix 中,密钥通过 sops-nix / agenix 管理,服务以 systemd unit 形式运行,CLI 配置命令会被阻止。你需要像管理其他 NixOS 服务一样管理 Hermes。
前置要求
- 启用了 flakes 的 Nix — 推荐 Determinate Nix(默认启用 flakes)
- API keys,用于你想接入的服务(至少准备一个 OpenRouter 或 Anthropic key)
快速开始(适用于任意 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 之后,hermes、hermes-agent 和 hermes-acp 都会出现在你的 PATH 中。之后的流程与 standard installation 完全一致:hermes setup 会带你完成大模型提供商(provider)选择,hermes gateway install 会安装 launchd(macOS)或 systemd user service,而配置则保存在 ~/.hermes/ 中。
Building from a local clone
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
nix build
./result/bin/hermes setup
NixOS Module
这个 flake 导出了 nixosModules.default:它是一个完整的 NixOS 服务模块,可用声明式方式管理用户创建、目录、配置生成、密钥、文档和服务生命周期。
这个模块要求运行在 NixOS 上。如果你不是 NixOS(例如 macOS 或其他 Linux 发行版),请使用 nix profile install,然后走上面的标准 CLI 工作流。
添加 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
];
};
};
}
最小配置
# 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、接入密钥,并启动网关。这个网关是一个长时间运行的服务,用来把 agent 连接到消息平台(Telegram、Discord 等),并监听传入消息。
上面的 environmentFiles 假设你已经配置好了 sops-nix 或 agenix。该文件至少需要包含一个 LLM 大模型提供商(provider)密钥(例如 OPENROUTER_API_KEY=sk-or-...)。完整配置请参阅 Secrets Management。如果你还没有密钥管理器,也可以先用一个普通文件起步,但请务必确保它不是全员可读的:
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 = true 会同时完成两件事:把 hermes CLI 加入系统 PATH,并在系统范围内设置 HERMES_HOME,这样交互式 CLI 就能与网关服务共享状态(sessions、技能、cron)。如果不这样做,在 shell 里运行 hermes 会额外创建一个单独的 ~/.hermes/ 目录。
当 container.enable = true 且 addToSystemPackages = true 时,主机上的所有 hermes 命令都会自动路由进受管容器。这意味着你的交互式 CLI 会话会运行在与网关服务完全相同的环境中,并能访问容器内安装的全部软件包和工具。
- 路由是透明的:
hermes chat、hermes sessions list、hermes version等命令底层都会自动 exec 进容器 - 所有 CLI 参数都会原样转发
- 如果容器没在运行,CLI 会短暂重试(交互式使用时带 spinner 重试 5 秒;脚本场景下静默重试 10 秒),随后明确报错,而不是悄悄回退
- 如果你是在开发 Hermes 仓库本身,可设置
HERMES_DEV=1跳过容器路由,直接运行本地 checkout
设置 container.hostUsers 后,会自动创建一个指向服务状态目录的 ~/.hermes 符号链接,让主机 CLI 与容器共享 sessions、config 和 memories:
services.hermes-agent = {
container.enable = true;
container.hostUsers = [ "your-username" ];
addToSystemPackages = true;
};
出现在 hostUsers 中的用户会被自动加入 hermes 组,以获取相应文件权限。
Podman users: NixOS 服务会以 root 身份运行容器。Docker 用户可以通过 docker 组 socket 使用容器,但 Podman 的 rootful 容器需要 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 控制:
| Native (default) | Container | |
|---|---|---|
| How it runs | 在宿主机上作为加固的 systemd 服务运行 | 持久化 Ubuntu 容器,绑定挂载 /nix/store |
| Security | NoNewPrivileges、ProtectSystem=strict、PrivateTmp | 容器隔离,内部以非特权用户运行 |
| Agent can self-install packages | 否,只能使用 Nix 提供到 PATH 上的工具 | 可以,apt、pip、npm 安装在重启后仍保留 |
| Config surface | Same | Same |
| When to choose | 标准部署、最高安全性、强可复现性 | agent 需要运行时安装软件包、可变环境或实验性工具 |
启用容器模式只需要加一行:
{
services.hermes-agent = {
enable = true;
container.enable = true;
# ... rest of config is identical
};
}
容器模式会通过 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 没有覆盖的键会被保留。也就是说,如果 agent 或手动编辑增加了像 skills.disabled、streaming.enabled 这样的键,它们在 nixos-rebuild switch 之后仍会存在。
settings.model.default 使用的是你的大模型提供商(provider)所期望的模型标识符。以默认的 OpenRouter 为例,通常长这样:"anthropic/claude-sonnet-4" 或 "google/gemini-3-flash"。如果你是直接使用某个大模型提供商(provider)(如 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,结构是一一对应的。
Full example: all commonly customized settings
{ 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 = {
"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;
};
}
Escape Hatch: Bring Your Own Config
如果你更希望完全在 Nix 之外维护 config.yaml,可以使用 configFile:
services.hermes-agent.configFile = /etc/hermes/config.yaml;
这样就会完全绕过 settings:不做合并,也不做自动生成。每次 activation 时,这个文件都会被原样复制到 $HERMES_HOME/config.yaml。
自定义速查表
下面是 Nix 用户最常调整项的快速参考:
| I want to... | Option | Example |
|---|---|---|
| Change the LLM model | settings.model.default | "anthropic/claude-sonnet-4" |
| Use a different provider endpoint | settings.model.base_url | "https://openrouter.ai/api/v1" |
| Add API keys | environmentFiles | [ config.sops.secrets."hermes-env".path ] |
| Give the agent a personality | ${services.hermes-agent.stateDir}/.hermes/SOUL.md | 直接管理这个文件 |
| Add MCP tool servers | mcpServers.<name> | 参见 MCP Servers |
| Mount host directories into container | container.extraVolumes | [ "/data:/data:rw" ] |
| Pass GPU access to container | container.extraOptions | [ "--gpus" "all" ] |
| Use Podman instead of Docker | container.backend | "podman" |
| Share state between host CLI and container | container.hostUsers | [ "sidbin" ] |
| Add tools to the service PATH (native only) | extraPackages | [ pkgs.pandoc pkgs.imagemagick ] |
| Use a custom base image | container.image | "ubuntu:24.04" |
| Override the hermes package | package | inputs.hermes-agent.packages.${system}.default.override { ... } |
| Change state directory | stateDir | "/opt/hermes" |
| Set the agent's working directory | workingDirectory | "/home/user/projects" |
Secrets Management
settings or environmentNix 表达式中的值最终会进入 /nix/store,而那里是所有用户可读的。密钥请始终通过 environmentFiles 搭配密钥管理器来处理。
environment(非敏感环境变量)和 environmentFiles(密钥文件)都会在 activation(nixos-rebuild switch)时合并进 $HERMES_HOME/.env。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 / Auth Seeding
对于需要 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 会写入状态目录,并在后续 rebuild 中保留。
Documents
documents 选项会把文件安装到 agent 的工作目录中(也就是 workingDirectory,agent 会把它视作 workspace)。Hermes 会按约定查找特定文件名:
USER.md— agent 当前正在交互的用户相关上下文- 你放在这里的其他文件也都会作为工作区文件暴露给 agent
agent 的身份文件是分开的:Hermes 的主 SOUL.md 来自 $HERMES_HOME/SOUL.md,在 NixOS module 中对应 ${services.hermes-agent.stateDir}/.hermes/SOUL.md。把 SOUL.md 放进 documents 只会生成一个工作区文件,并不会替代主 persona 文件。
{
services.hermes-agent.documents = {
"USER.md" = ./documents/USER.md; # path reference, copied from Nix store
};
}
这里的值既可以是内联字符串,也可以是路径引用。每次 nixos-rebuild switch 时都会重新安装这些文件。
MCP Servers
mcpServers 选项可以用声明式方式配置 MCP (Model Context Protocol) 服务器。每台服务器都可以使用 stdio(本地命令)或 HTTP(远程 URL)传输。
Stdio Transport (Local Servers)
{
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
};
};
}
env 中的环境变量会在运行时从 $HERMES_HOME/.env 里解析。密钥请通过 environmentFiles 注入,不要把 token 直接写进 Nix 配置。
HTTP Transport (Remote Servers)
{
services.hermes-agent.mcpServers.remote-api = {
url = "https://mcp.example.com/v1/mcp";
headers.Authorization = "Bearer \${MCP_REMOTE_API_KEY}";
timeout = 180;
};
}
HTTP Transport with OAuth
对于使用 OAuth 2.1 的服务器,请设置 auth = "oauth"。Hermes 实现了完整的 PKCE 流程:元数据发现、动态客户端注册、token 交换以及自动刷新。
{
services.hermes-agent.mcpServers.my-oauth-server = {
url = "https://mcp.example.com/mcp";
auth = "oauth";
};
}
token 会保存在 $HERMES_HOME/mcp-tokens/<server-name>.json 中,并在重启和 rebuild 之后继续保留。
Initial OAuth authorization on headless servers
首次 OAuth 授权需要经过浏览器授权同意流程。在无头部署环境中,Hermes 不会尝试直接打开浏览器,而是把授权 URL 打印到 stdout / logs 中。
Option A: Interactive bootstrap — 通过 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 回调端口。
Option B: Pre-seed tokens — 先在工作站上完成授权流程,再把 token 拷过去:
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
Sampling (Server-Initiated LLM Requests)
某些 MCP 服务器可以向 agent 发起 LLM completion 请求:
{
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;
};
};
}
Managed Mode
当 Hermes 通过 NixOS module 运行时,下面这些 CLI 命令会被拦截并报错,提示你改去编辑 configuration.nix:
| Blocked command | Why |
|---|---|
hermes setup | 配置是声明式的,应在 Nix 配置里编辑 settings |
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 服务设置,对网关进程可见.managedmarker file inHERMES_HOME— 由 activation script 创建,对交互式 shell 可见(例如docker exec -it hermes-agent hermes config set ...也会被阻止)
要修改配置,请编辑 Nix 配置后执行 sudo nixos-rebuild switch。
Container Architecture
只有当你启用了 container.enable = true 时,这一节才相关。原生模式部署可以跳过。
启用容器模式后,Hermes 会运行在一个持久化 Ubuntu 容器中,而 Nix 构建出的二进制会以只读方式从宿主机 bind mount 进来:
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 进去了。它会自带解释器和全部依赖,因此不依赖容器自己的系统库。容器入口点通过 current-package 符号链接解析到 /data/current-package/bin/hermes gateway run --replace。在 nixos-rebuild switch 时,只会更新这个符号链接,容器本身不会被重建。
什么会在什么情况下保留
| Event | Container recreated? | /data (state) | /home/hermes | Writable layer (apt/pip/npm) |
|---|---|---|---|---|
systemctl restart hermes-agent | No | Persists | Persists | Persists |
nixos-rebuild switch (code change) | No (symlink updated) | Persists | Persists | Persists |
| Host reboot | No | Persists | Persists | Persists |
nix-collect-garbage | No (GC root) | Persists | Persists | Persists |
Image change (container.image) | Yes | Persists | Persists | Lost |
| Volume/options change | Yes | Persists | Persists | Lost |
environment/environmentFiles change | No | Persists | Persists | Persists |
只有当容器的identity hash 变化时,容器才会被重新创建。这个哈希覆盖的内容包括:schema version、image、extraVolumes、extraOptions 以及 entrypoint script。环境变量、settings、documents 或 Hermes 软件包本身的变化,都不会触发重建。
当 identity hash 发生变化时(例如镜像升级、新增 volume、新增容器选项),容器会被销毁并基于新的 container.image 重新创建。写在可写层里的 apt install、pip install 或 npm install 软件包都会丢失。/data 与 /home/hermes 里的状态则会被保留,因为它们是 bind mount。
如果 agent 依赖某些特定软件包,建议把它们烘焙进自定义镜像(例如 container.image = "my-registry/hermes-base:latest"),或在 agent 的 SOUL.md 中写好安装脚本。
GC Root Protection
preStart 脚本会在 ${stateDir}/.gc-root 创建一个指向当前 Hermes 软件包的 GC root,防止 nix-collect-garbage 清掉正在运行的二进制。如果 GC root 不知为何损坏了,重启服务就会重新创建它。
Development
Dev Shell
这个 flake 提供了一个开发 shell,内置 Python 3.11、uv、Node.js 和全部运行时工具:
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 (Recommended)
仓库自带的 .envrc 会自动激活 dev shell:
cd hermes-agent
direnv allow # one-time
# Subsequent entries are near-instant (stamp file skips dep install)
Flake Checks
这个 flake 还包含会在 CI 和本地运行的构建期校验:
# 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
What each check verifies
| Check | What it tests |
|---|---|
package-contents | 验证 hermes 和 hermes-agent 二进制存在,且 hermes version 可运行 |
entry-points-sync | 验证 pyproject.toml 中每个 [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 附加合并、嵌套深度合并和幂等性 |
Options Reference
Core
| Option | Type | Default | Description |
|---|---|---|---|
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" | agent 工作目录(MESSAGING_CWD) |
addToSystemPackages | bool | false | 将 hermes CLI 加入系统 PATH,并在系统范围内设置 HERMES_HOME |
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
settings | attrs (deep-merged) | {} | 声明式配置,会渲染为 config.yaml。支持任意嵌套;多个定义通过 lib.recursiveUpdate 合并 |
configFile | null or path | null | 现有 config.yaml 的路径;设置后会完全覆盖 settings |
Secrets & Environment
| Option | Type | Default | Description |
|---|---|---|---|
environmentFiles | listOf str | [] | 保存密钥的 env 文件路径;activation 时会合并进 $HERMES_HOME/.env |
environment | attrsOf str | {} | 非敏感环境变量。会暴露在 Nix store 中,请勿放密钥 |
authFile | null or path | null | OAuth 凭据种子文件,仅在首次部署时复制 |
authFileForceOverwrite | bool | false | 每次 activation 都用 authFile 覆盖 auth.json |
Documents
| Option | Type | Default | Description |
|---|---|---|---|
documents | attrsOf (either str path) | {} | 工作区文件。键是文件名,值是内联字符串或路径;activation 时安装到 workingDirectory |
MCP Servers
| Option | Type | Default | Description |
|---|---|---|---|
mcpServers | attrsOf submodule | {} | MCP 服务器定义,会合并进 settings.mcp_servers |
mcpServers.<name>.command | null or str | null | 服务器命令(stdio transport) |
mcpServers.<name>.args | listOf str | [] | 命令参数 |
mcpServers.<name>.env | attrsOf str | {} | 服务器进程使用的环境变量 |
mcpServers.<name>.url | null or str | null | 服务器端点 URL(HTTP / StreamableHTTP transport) |
mcpServers.<name>.headers | attrsOf str | {} | HTTP headers,例如 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 | 供服务器发起 LLM 请求时使用的 sampling 配置 |
Service Behavior
| Option | Type | Default | Description |
|---|---|---|---|
extraArgs | listOf str | [] | 传给 hermes gateway 的额外参数 |
extraPackages | listOf package | [] | 额外加入服务 PATH 的软件包(仅原生模式) |
restart | str | "always" | systemd Restart= 策略 |
restartSec | int | 5 | systemd RestartSec= 值 |
Container
| Option | Type | Default | Description |
|---|---|---|---|
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 | [] | 会获得 ~/.hermes 符号链接并自动加入 hermes 组的交互用户 |
Directory Layout
Native Mode
/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)
Container Mode
同样的目录布局,只是它们会被挂载进容器:
| Container path | Host path | Mode | Notes |
|---|---|---|---|
/nix/store | /nix/store | ro | Hermes 二进制和全部 Nix 依赖 |
/data | /var/lib/hermes | rw | 全部状态、配置和工作区 |
/home/hermes | ${stateDir}/home | rw | 持久化 agent home,用于 pip install --user、工具缓存等 |
/usr, /usr/local, /tmp | (writable layer) | rw | apt/pip/npm 安装内容;重启保留,重建丢失 |
Updating
# Update the flake input
nix flake update hermes-agent --flake /etc/nixos
# Rebuild
sudo nixos-rebuild switch
在容器模式下,current-package 符号链接会被更新,agent 在重启后就会用到新的二进制。无需重建容器,也不会丢失后来安装的软件包。
Troubleshooting
下面所有 docker 命令都可以用 podman 等价替代。如果你设置了 container.backend = "podman",请自行替换。
Service Logs
# Both modes use the same systemd unit
journalctl -u hermes-agent -f
# Container mode: also available directly
docker logs -f hermes-agent
Container Inspection
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
Force Container Recreation
如果你需要重置可写层(获得一个全新的 Ubuntu 容器):
sudo systemctl stop hermes-agent
docker rm -f hermes-agent
sudo rm /var/lib/hermes/.container-identity
sudo systemctl start hermes-agent
Verify Secrets Are Loaded
如果 agent 能启动,但无法向 LLM 大模型提供商(provider)认证,请检查 .env 是否已正确合并:
# Native mode
sudo -u hermes cat /var/lib/hermes/.hermes/.env
# Container mode
docker exec hermes-agent cat /data/.hermes/.env
GC Root Verification
nix-store --query --roots $(docker exec hermes-agent readlink /data/current-package)
Common Issues
| Symptom | Cause | Fix |
|---|---|---|
Cannot save configuration: managed by NixOS | CLI 守卫已启用 | 编辑 configuration.nix 后执行 nixos-rebuild switch |
| Container recreated unexpectedly | extraVolumes、extraOptions 或 image 发生变化 | 这是预期行为。可写层会重置,请重新安装软件包或使用自定义镜像 |
hermes version shows old version | 容器尚未重启 | 执行 systemctl restart hermes-agent |
Permission denied on /var/lib/hermes | 状态目录权限是 0750 hermes:hermes | 使用 docker exec 或 sudo -u hermes |
nix-collect-garbage removed hermes | GC root 丢失 | 重启服务(preStart 会重新创建 GC root) |
no container with name or ID "hermes-agent" (Podman) | Podman rootful 容器对普通用户不可见 | 为 podman 配置免密码 sudo(见 Container-aware CLI) |
unable to find user hermes | 容器仍在启动中(entrypoint 还没创建用户) | 等几秒再试,CLI 本身也会自动重试 |