字节笔记本
2026年6月21日
hermes教程-Nix 和 NixOS 设置
Nix 和 NixOS 设置
Hermes Agent 提供了一个 Nix flake,包含三个集成级别:
| 级别 | 适用对象 | 功能 |
|---|---|---|
nix run / nix profile install | 任何 Nix 用户(macOS、Linux) | 预构建的二进制文件,包含所有依赖项 — 然后使用标准 CLI 工作流程 |
| NixOS 模块(原生) | NixOS 服务器部署 | 声明式配置、加固的 systemd 服务、托管密钥 |
| NixOS 模块(容器) | 需要自我修改的 Agent | 以上所有功能,外加一个持久的 Ubuntu 容器,Agent 可以在其中执行 apt/pip/npm install |
信息 — 与标准安装的区别
curl | bash安装程序自行管理 Python、Node 和依赖项。Nix flake 取代了所有这些 — 每个 Python 依赖项都是由 uv2nix 构建的 Nix 派生,运行时工具(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 服务相同。
先决条件
- 启用 flake 的 Nix — 推荐使用 Determinate Nix(默认启用 flake)
- API 密钥,用于你想要使用的服务(至少:一个 OpenRouter 或 Anthropic 密钥)
快速入门(任何 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 用户服务,配置位于 ~/.hermes/。
警告 — 消息平台(Discord、Telegram、Slack)
默认包不包含消息平台库 — 它们已被移至按需安装,这在 Nix 的只读环境中无法工作。如果你计划将 Agent 连接到 Discord、Telegram 或 Slack,请安装
messaging变体:bashnix profile install github:NousResearch/hermes-agent#messaging对于所有可选附加功能(语音、所有提供商、所有平台):
bashnix profile install github:NousResearch/hermes-agent#full
full变体会在闭包中增加约 700 MB。如果你只需要消息平台,#messaging仅增加约 33 MB。
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
nix build
./result/bin/hermes setupNixOS 模块
该 flake 导出 nixosModules.default — 一个完整的 NixOS 服务模块,声明式地管理用户创建、目录、配置生成、密钥、文档和服务生命周期。
注意
此模块需要 NixOS。对于非 NixOS 系统(macOS、其他 Linux 发行版),请使用
nix profile install和上面的标准 CLI 工作流程。
添加 Flake 输入
## /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,连接密钥,并启动网关 — 一个长期运行的服务,将 Agent 连接到消息平台(Telegram、Discord 等)并监听传入消息。
警告 — 密钥是必需的
上面的
environmentFiles行假设你已经配置了 sops-nix 或 agenix。该文件应至少包含一个 LLM 提供商密钥(例如OPENROUTER_API_KEY=sk-or-...)。有关完整设置,请参阅密钥管理。如果你还没有密钥管理器,可以使用一个普通文件作为起点 — 只需确保它不是世界可读的:bashecho "OPENROUTER_API_KEY=sk-or-your-key" | sudo install -m 0600 -o hermes /dev/stdin /var/lib/hermes/envnixservices.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];
提示 — addToSystemPackages
设置
addToSystemPackages = true会做两件事:将hermesCLI 放入系统 PATH 并 系统范围设置HERMES_HOME,以便交互式 CLI 与网关服务共享状态(会话、技能、cron)。如果没有它,在 shell 中运行hermes会创建一个单独的~/.hermes/目录。
容器感知的 CLI
信息
当
container.enable = true且addToSystemPackages = true时,主机上的每个hermes命令都会自动路由到受管容器中。这意味着你的交互式 CLI 会话在与网关服务相同的环境中运行 — 可以访问所有容器安装的包和工具。
- 路由是透明的:
hermes chat、hermes sessions list、hermes version等都在底层 exec 到容器中- 所有 CLI 标志都会原样转发
- 如果容器未运行,CLI 会短暂重试(交互式使用 5 秒带旋转指示器,脚本使用 10 秒静默),然后失败并显示清晰的错误 — 没有静默回退
- 对于在 hermes 代码库上工作的开发者,设置
HERMES_DEV=1以绕过容器路由并直接运行本地检出设置
container.hostUsers以创建指向服务状态目录的~/.hermes符号链接,以便主机 CLI 和容器共享会话、配置和记忆:nixservices.hermes-agent = { container.enable = true; container.hostUsers = [ "your-username" ]; addToSystemPackages = true; };
hostUsers中列出的用户会自动添加到hermes组以获取文件权限访问。Podman 用户: NixOS 服务以 root 身份运行容器。Docker 用户通过
docker组套接字获得访问权限,但 Podman 的 rootful 容器需要 sudo。为你的容器运行时授予无密码 sudo:nixsecurity.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 |
| 安全性 | NoNewPrivileges、ProtectSystem=strict、PrivateTmp | 容器隔离,内部以非特权用户身份运行 |
| Agent 可以自行安装包 | 否 — 仅限 Nix 提供的 PATH 上的工具 | 是 — apt、pip、npm install 在重启后持久化 |
| 配置面 | 相同 | 相同 |
| 何时选择 | 标准部署、最大安全性、可重现性 | Agent 需要运行时包安装、可变环境、实验性工具 |
要启用容器模式,添加一行:
{
services.hermes-agent = {
enable = true;
container.enable = true;
## ... 其余配置相同
};
}信息
容器模式通过
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使用你的提供商期望的模型标识符。使用 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粘贴到settingsattrset 中 — 结构是一一对应的。
{ 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;
};
}逃生舱:自带配置
如果你希望完全在 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 ] |
| 给 Agent 一个个性 | ${services.hermes-agent.stateDir}/.hermes/SOUL.md | 直接管理文件 |
| 添加 MCP 工具服务器 | mcpServers.<name> | 参见 MCP 服务器 |
| 启用 Discord/Telegram/Slack | extraDependencyGroups | [ "messaging" ] |
| 将主机目录挂载到容器中 | container.extraVolumes | [ "/data:/data:rw" ] |
| 将 GPU 访问传递给容器 | container.extraOptions | [ "--gpus" "all" ] |
| 使用 Podman 而不是 Docker | container.backend | "podman" |
| 在主机 CLI 和容器之间共享状态 | container.hostUsers | [ "sidbin" ] |
| 使额外工具对 Agent 可用 | extraPackages | [ pkgs.pandoc pkgs.imagemagick ] |
| 使用自定义基础镜像 | container.image | "ubuntu:24.04" |
| 覆盖 hermes 包 | package | inputs.hermes-agent.packages.${system}.default.override { ... } |
| 更改状态目录 | stateDir | "/opt/hermes" |
| 设置 Agent 的工作目录 | workingDirectory | "/home/user/projects" |
密钥管理
危险 — 切勿将 API 密钥放在
settings或environment中Nix 表达式中的值最终会出现在
/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(使用 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 选项将文件安装到 Agent 的工作目录(workingDirectory,Agent 将其读取为工作空间)。Hermes 按约定查找特定文件名:
USER.md— 关于 Agent 正在交互的用户上下文。- 你放在这里的任何其他文件对 Agent 来说都是工作空间文件。
Agent 身份文件是独立的:Hermes 从 $HERMES_HOME/SOUL.md 加载其主要 SOUL.md,在 NixOS 模块中为 ${services.hermes-agent.stateDir}/.hermes/SOUL.md。将 SOUL.md 放在 documents 中只会创建一个工作空间文件,不会替换主要角色文件。
{
services.hermes-agent.documents = {
"USER.md" = ./documents/USER.md; # 路径引用,从 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}"; # 从 .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 授权需要基于浏览器的同意流程。在无头部署中,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,因此主机浏览器可以访问 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/
## 确保:chown hermes:hermes, chmod 0600采样(服务器发起的 LLM 请求)
某些 MCP 服务器可以从 Agent 请求 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 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 构建的二进制文件以只读方式从主机绑定挂载:
主机 容器
──── ─────────
/nix/store/...-hermes-agent-0.1.0 ──► /nix/store/... (ro)
~/.hermes -> /var/lib/hermes/.hermes (符号链接桥,每个 hostUsers)
/var/lib/hermes/ ──► /data/ (rw)
├── current-package -> /nix/store/... (符号链接,每次重建更新)
├── .gc-root -> /nix/store/... (防止 nix-collect-garbage)
├── .container-identity (sha256 哈希,触发重新创建)
├── .hermes/ (HERMES_HOME)
│ ├── .env (从 environment + environmentFiles 合并)
│ ├── config.yaml (Nix 生成,由激活深度合并)
│ ├── .managed (标记文件)
│ ├── .container-mode (路由元数据:backend, exec_user 等)
│ ├── state.db, sessions/, memories/ (运行时状态)
│ └── mcp-tokens/ (MCP 服务器的 OAuth 令牌)
├── home/ ──► /home/hermes (rw)
└── workspace/ (Agent 工作目录)
├── SOUL.md (来自 documents 选项)
└── (Agent 创建的文件)
容器可写层 (apt/pip/npm): /usr, /usr/local, /tmpNix 构建的二进制文件在 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中的状态会保留(这些是绑定挂载)。如果 Agent 依赖特定包,考虑将它们烘焙到自定义镜像中(
container.image = "my-registry/hermes-base:latest")或在 Agent 的 SOUL.md 中编写安装脚本。
GC 根保护
preStart 脚本在 ${stateDir}/.gc-root 创建一个指向当前 hermes 包的 GC 根。这可以防止 nix-collect-garbage 删除正在运行的二进制文件。如果 GC 根意外损坏,重启服务会重新创建它。
插件
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 会移除符号链接。
入口点插件(extraPythonPackages)
对于通过 [project.entry-points."hermes_agent.plugins"] 注册的 pip 打包插件(例如 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 会被添加到 hermes 包装器中的 PYTHONPATH。importlib.metadata 在会话启动时发现入口点。
可选依赖组(extraDependencyGroups)
对于 hermes-agent 的 pyproject.toml 中声明的可选附加功能,使用 extraDependencyGroups 在构建时将它们包含在密封的 venv 中。对于不在默认 [all] 集中的任何附加功能,这是必需的 — 在 Nix 上,运行时安装到只读 store 是不可能的。
## 启用 Discord、Telegram、Slack
services.hermes-agent.extraDependencyGroups = [ "messaging" ];## 启用记忆提供者
services.hermes-agent = {
extraDependencyGroups = [ "hindsight" ];
settings.memory.provider = "hindsight";
};这由 uv 与核心依赖项一起解析 — 无需 PYTHONPATH 修补,无冲突风险。可用组:
| 组 | 启用内容 |
|---|---|
messaging | Discord、Telegram、Slack |
matrix | Matrix/Element(带加密的 mautrix;仅限 Linux) |
dingtalk | 钉钉 |
feishu | 飞书/Lark |
voice | 本地语音转文本(faster-whisper) |
edge-tts | Edge TTS 提供者 |
tts-premium | ElevenLabs TTS |
anthropic | 原生 Anthropic SDK(通过 OpenRouter 不需要) |
bedrock | AWS Bedrock(boto3) |
azure-identity | Azure Entra ID 认证 |
honcho | Honcho 记忆提供者 |
hindsight | Hindsight 记忆提供者 |
modal | Modal 终端后端 |
daytona | Daytona 终端后端 |
exa | Exa 网络搜索 |
firecrawl | Firecrawl 网络搜索 |
fal | FAL 图像生成 |
或者使用预构建的 #messaging 或 #full flake 包,而不是逐个附加配置(参见快速入门)。
何时使用哪个:
| 需求 | 选项 |
|---|---|
| 启用 pyproject.toml 中的可选附加功能 | extraDependencyGroups |
| 添加不在 pyproject.toml 中的外部 Python 插件 | extraPythonPackages |
| 添加系统二进制文件(pandoc、jq 等) | extraPackages |
| 添加基于目录的插件源代码树 | extraPlugins |
组合两者
一个带有第三方 Python 依赖项的目录插件需要两个选项:
services.hermes-agent = {
extraPlugins = [ my-plugin-src ]; # 插件源代码
extraPythonPackages = [ pkgs.python312Packages.redis ]; # 其 Python 依赖项
extraPackages = [ pkgs.redis ]; # 其需要的系统二进制文件
};使用 Overlay
外部 flake 可以直接覆盖包:
{
inputs.hermes-agent.url = "github:NousResearch/hermes-agent";
outputs = { hermes-agent, nixpkgs, ... }: {
nixpkgs.overlays = [ hermes-agent.overlays.default ];
## 然后:
## pkgs.hermes-agent.override { extraPythonPackages = [...]; }
## pkgs.hermes-agent.override { extraDependencyGroups = [ "hindsight" ]; }
};
}插件配置
插件仍然需要在 config.yaml 中启用。通过声明式设置添加它们:
services.hermes-agent.settings.plugins.enabled = [
"hermes-lcm"
"rtk-rewrite"
];注意
构建时的冲突检查可防止插件包遮蔽核心 hermes 依赖项。如果插件提供了密封 venv 中已有的包,
nixos-rebuild会失败并显示清晰的错误。
开发
开发 Shell
该 flake 提供了一个开发 shell,包含 Python 3.12、uv、Node.js 和所有运行时工具:
cd hermes-agent
nix develop
## Shell 提供:
## - Python 3.12 + uv(首次进入时依赖项安装到 .venv)
## - Node.js 22、ripgrep、git、openssh、ffmpeg 在 PATH 上
## - 戳文件优化:如果依赖项未更改,重新进入几乎是即时的
hermes setup
hermes chatdirenv(推荐)
包含的 .envrc 会自动激活开发 shell:
cd hermes-agent
direnv allow # 一次性
## 后续进入几乎是即时的(戳文件跳过依赖项安装)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 包同步
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 | 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" | Agent 工作目录 |
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 store 中可见 — 不要在此处放置密钥 |
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 | 服务器命令(stdio 传输) |
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 | [] | 对 Agent 可用的额外包。添加到 hermes 用户的用户配置文件中,因此终端命令、技能和 cron 作业都能看到它们 |
extraPlugins | listOf package | [] | 要符号链接到 $HERMES_HOME/plugins/ 的目录插件包。每个必须包含 plugin.yaml |
extraPythonPackages | listOf package | [] | 添加到 PYTHONPATH 以发现入口点插件的 Python 包。使用 python312Packages 构建 |
extraDependencyGroups | listOf str | [] | pyproject.toml 中的可选附加功能,包含在密封 venv 中(例如 ["hindsight"])。由 uv 解析 — 无冲突 |
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 组 |
目录布局
原生模式
/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/ # MCP 服务器的 OAuth 令牌
│ ├── sessions/
│ ├── memories/
│ ├── skills/
│ ├── cron/
│ └── logs/
├── home/ # Agent HOME
└── workspace/ # Agent 工作目录
├── SOUL.md # 来自 documents 选项
└── (Agent 创建的文件)容器模式
相同布局,挂载到容器中:
| 容器路径 | 主机路径 | 模式 | 备注 |
|---|---|---|---|
/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 | (可写层) | rw | apt/pip/npm install — 重启后持久化,重新创建时丢失 |
更新
## 更新 flake 输入(从包含 flake.nix 的目录运行)
cd /etc/nixos && nix flake update hermes-agent
## 重建
sudo nixos-rebuild switch在容器模式下,current-package 符号链接会更新,Agent 在重启时获取新的二进制文件。无需重新创建容器,不会丢失已安装的包。
故障排除
提示 — 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验证密钥是否已加载
如果 Agent 启动但无法与 LLM 提供商认证,请检查 .env 文件是否正确合并:
## 原生模式
sudo -u hermes cat /var/lib/hermes/.hermes/.env
## 容器模式
docker exec hermes-agent cat /data/.hermes/.envGC 根验证
nix-store --query --roots $(docker exec hermes-agent readlink /data/current-package)常见问题
| 症状 | 原因 | 修复 |
|---|---|---|
Cannot save configuration: managed by NixOS | CLI 保护激活 | 编辑 configuration.nix 并运行 nixos-rebuild switch |
No adapter available for discord(或 telegram/slack) | 密封 Nix venv 中缺少消息传递依赖项 | 安装 #messaging 变体:nix profile install ...#messaging。对于 NixOS 模块:extraDependencyGroups = [ "messaging" ]。检查 journalctl -u hermes-agent 以获取 FeatureUnavailable 或 requirements not met 以了解底层错误。 |
| 容器意外重新创建 | 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 根) |
no container with name or ID "hermes-agent"(Podman) | Podman rootful 容器对普通用户不可见 | 为 podman 添加无密码 sudo(参见容器模式部分) |
unable to find user hermes | 容器仍在启动(入口点尚未创建用户) | 等待几秒后重试 — CLI 会自动重试 |
通过 extraPackages 添加的工具在终端中找不到 | 需要 nixos-rebuild switch 来更新用户配置文件 | 重建并重启:nixos-rebuild switch && systemctl restart hermes-agent |