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 setup、hermes 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 之后,hermes、hermes-agent 和 hermes-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 服务模块,声明式地管理用户创建、目录、配置生成、密钥、文档和服务生命周期。
此模块需要 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,连接密钥,并启动网关 —— 一个长时间运行的服务,将代理连接到消息平台(Telegram、Discord 等)并监听传入消息。
上面的 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/env
services.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];
设置 addToSystemPackages = true 有两点作用:将 hermes CLI 添加到系统 PATH 并且 全局设置 HERMES_HOME,使交互式 CLI 与网关服务共享状态(会话、技能、cron)。若不设置,你在 shell 中运行 hermes 会创建一个独立的 ~/.hermes/ 目录。
验证是否正常工作
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 绑定挂载 |
| 安全性 | NoNewPrivileges、ProtectSystem=strict、PrivateTmp | 容器隔离,以非特权用户运行 |
| 代理能否在运行时安装包 | 否 —— 仅限 Nix 提供的 PATH 中的工具 | 是 —— apt、pip、npm 安装在重启后仍持久存在 |
| 配置面 | 相同 | 相同 |
| 何时选择 | 标准部署、最大安全性、可复现性 | 代理需要运行时包安装、可变环境、实验性工具 |
要启用容器模式,只需添加一行:
{
services.hermes-agent = {
enable = true;
container.enable = true;
# ... rest of config is identical
};
}
容器模式会通过 mkDefault 自动启用 virtualisation.docker.enable。如果你使用 Podman 而非 Docker,请设置 container.backend = "podman" 并将 virtualisation.docker.enable = false。
配置
声明式设置
settings 选项接受一个任意的 attrset,该 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.disabled 或 streaming.enabled 这样的键,它们在执行 nixos-rebuild switch 后依然会保留。
settings.model.default 使用的是你的提供商所期望的模型标识符。使用 OpenRouter(默认)时,这些标识符看起来像 "anthropic/claude-sonnet-4" 或 "google/gemini-3-flash"。如果你直接使用提供商(如 Anthropic、OpenAI),请将 settings.model.base_url 设置为指向其 API,并使用其原生模型 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";
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 而非 Docker | container.backend | "podman" |
| 向服务 PATH 添加工具(仅原生) | 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" |
密钥管理
settings 或 environmentNix 表达式中的值最终会出现在 /nix/store 中,而该目录对世界可读。请始终使用 environmentFiles 配合密钥管理器。
environment(非敏感变量)和 environmentFiles(密钥文件)会在激活时(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 / 认证种子
对于需要 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 会按约定查找特定文件名:
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
};
};
}
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;
};
};
}
管理模式
当通过 NixOS 模块运行 hermes 时,以下 CLI 命令将被阻止,并返回描述性错误,提示您前往 configuration.nix:
| 被阻止的命令 | 原因 |
|---|---|
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 服务设置,对网关进程可见.managed标记文件 在HERMES_HOME中 —— 由激活脚本设置,对交互式 shell 可见(例如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)
/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)
│ ├── 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 变更 | 否 | 持久化 | 持久化 | 持久化 |
容器仅在它的身份哈希发生变化时才会被重新创建。该哈希涵盖:模式版本、镜像、extraVolumes、extraOptions 和入口脚本。对环境变量、设置、文档或 hermes 包本身的更改不会触发重建。
当身份哈希发生变化时(镜像升级、新增卷、新增容器选项),容器会被销毁并从 container.image 的新镜像中重新创建。可写层中的任何 apt install、pip install 或 npm 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 提供了一个开发 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(推荐)
包含的 .envrc 会自动激活开发 shell:
cd hermes-agent
direnv allow # one-time
# Subsequent entries are near-instant (stamp file skips dep install)
Flake 检查
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
每个检查项验证的内容
| 检查项 | 验证内容 |
|---|---|
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 增量合并、嵌套深度合并、幂等性 |
选项参考
核心配置
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
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 的额外参数 |
目录结构
原生模式
/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 符号链接会被更新,代理在重启时会自动加载新二进制文件。无需重建容器,也不会丢失已安装的包。
故障排除
下面所有的 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 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 根缺失 | 重启服务(preStart 会重新创建 GC 根) |