fix(nix): make extraPackages actually work via per-user profile (#17047)

* fix(nix): make extraPackages actually work — wire into per-user profile

#17030 deprecated extraPackages because it only set the systemd service
PATH, which the terminal backend's login-shell snapshot discards.

Instead of deprecating, fix it: set users.users.${cfg.user}.packages
so NixOS builds a per-user profile at /etc/profiles/per-user/hermes/bin.
This path is included in PATH by /etc/set-environment, which the login
shell sources, so the terminal backend's snapshot picks it up.

One line of actual logic:
  users.users.${cfg.user}.packages = cfg.extraPackages;

Verified in a NixOS VM test: su - hermes -c 'which hello' resolves
to /etc/profiles/per-user/hermes/bin/hello.

Reverts the deprecation warning and docs changes from #17030, restores
extraPackages as the recommended way to give the agent extra tools.

Container mode is unaffected — extraPackages was always native-only
(the systemd path line is inside !cfg.container.enable).

* nix: clarify additive merge semantics for extraPackages user profile

---------

Co-authored-by: Siddharth Balyan <daimon@noreply.github.com>
This commit is contained in:
Siddharth Balyan 2026-04-28 23:50:32 +05:30 committed by GitHub
parent a3c27b5cd1
commit 4bf0e75ae9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 18 additions and 28 deletions

View File

@ -456,14 +456,13 @@
type = types.listOf types.package;
default = [ ];
description = ''
**Deprecated.** Extra packages on the systemd service PATH.
Extra packages available to the agent terminal commands, skills,
cron jobs, and the service process all see them.
This option does NOT make packages available to terminal commands
or skills the terminal backend's login shell rebuilds PATH from
NixOS system profiles, discarding the service PATH.
Use `environment.systemPackages` instead, which works everywhere:
service process, terminal commands, skills, cron jobs.
Implemented via the hermes user's per-user profile
(`/etc/profiles/per-user/${cfg.user}/bin`), which NixOS includes
in PATH for login shells. The packages are also added to the
systemd service PATH for direct process access.
'';
};
@ -649,21 +648,15 @@
}
# ── Warnings ──────────────────────────────────────────────────────
# ── Per-user profile for extraPackages ───────────────────────────
# Wire extraPackages into the hermes user's per-user profile so the
# login-shell snapshot (which rebuilds PATH from NixOS profiles) sees
# them. The systemd service PATH also includes them for direct access.
(lib.mkIf (cfg.extraPackages != []) {
warnings = [
''
services.hermes-agent: `extraPackages` is deprecated and will be removed in a future release.
Packages added via `extraPackages` are only visible to the systemd
service process itself. Terminal commands, skills, and cron jobs do
NOT see them because the terminal backend starts a login shell whose
PATH is rebuilt from NixOS system profiles, discarding the service PATH.
Migrate to `environment.systemPackages`, which works everywhere:
environment.systemPackages = [ ${lib.concatMapStringsSep " " (p: "pkgs.${p.pname or (lib.getName p)}") cfg.extraPackages} ];
''
];
# listOf options are merged by the NixOS module system — this appends to
# any packages the operator assigned to this user externally (e.g. when
# createUser = false and the user definition lives elsewhere in the config).
users.users.${cfg.user}.packages = cfg.extraPackages;
})
(lib.mkIf (cfg.container.enable && !cfg.addToSystemPackages && cfg.container.hostUsers != []) {

View File

@ -321,7 +321,7 @@ Quick reference for the most common things Nix users want to customize:
| 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" ]` |
| Make extra tools available to the agent | `environment.systemPackages` (top-level NixOS) | `[ pkgs.pandoc pkgs.imagemagick ]` |
| Make extra tools available to the agent | `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"` |
@ -648,14 +648,11 @@ The package's `site-packages` is added to PYTHONPATH in the hermes wrapper. `imp
A directory plugin with third-party Python dependencies needs both options:
```nix
# Plugin config
services.hermes-agent = {
extraPlugins = [ my-plugin-src ]; # plugin source
extraPythonPackages = [ pkgs.python312Packages.redis ]; # its Python dep
extraPackages = [ pkgs.redis ]; # system binary it needs
};
# System binaries the plugin needs — available to terminal, skills, cron
environment.systemPackages = [ pkgs.redis ];
```
### Using the Overlay
@ -810,7 +807,7 @@ nix build .#checks.x86_64-linux.config-roundtrip # merge script preserves use
| Option | Type | Default | Description |
|---|---|---|---|
| `extraArgs` | `listOf str` | `[]` | Extra args for `hermes gateway` |
| `extraPackages` | `listOf package` | `[]` | **Deprecated.** Use `environment.systemPackages` instead. Only affects the systemd service process — terminal commands, skills, and cron jobs do not see these packages |
| `extraPackages` | `listOf package` | `[]` | Extra packages available to the agent. Added to the hermes user's per-user profile so terminal commands, skills, and cron jobs all see them |
| `extraPlugins` | `listOf package` | `[]` | Directory plugin packages to symlink into `$HERMES_HOME/plugins/`. Each must contain `plugin.yaml` |
| `extraPythonPackages` | `listOf package` | `[]` | Python packages added to PYTHONPATH for entry-point plugin discovery. Build with `python312Packages` |
| `restart` | `str` | `"always"` | systemd `Restart=` policy |
@ -948,4 +945,4 @@ nix-store --query --roots $(docker exec hermes-agent readlink /data/current-pack
| `nix-collect-garbage` removed hermes | GC root missing | Restart the service (preStart recreates the GC root) |
| `no container with name or ID "hermes-agent"` (Podman) | Podman rootful container not visible to regular user | Add passwordless sudo for podman (see [Container-aware CLI](#container-aware-cli) section) |
| `unable to find user hermes` | Container still starting (entrypoint hasn't created user yet) | Wait a few seconds and retry — the CLI retries automatically |
| Tool added via `extraPackages` not found in terminal | `extraPackages` only sets the systemd service PATH, not the terminal backend's | Move to `environment.systemPackages` — see deprecation warning at build time |
| Tool added via `extraPackages` not found in terminal | Requires `nixos-rebuild switch` to update the per-user profile | Rebuild and restart: `nixos-rebuild switch && systemctl restart hermes-agent` |