mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-02 02:01:47 +00:00
feat(nix): container-aware CLI — auto-route all subcommands into managed container
When container.enable = true, the host `hermes` CLI transparently execs every subcommand into the managed Docker/Podman container. A symlink bridge (~/.hermes -> /var/lib/hermes/.hermes) unifies state between host and container so sessions, config, and memories are shared. CLI changes: - Global routing before subcommand dispatch (all commands forwarded) - docker exec with -u exec_user, env passthrough (TERM, COLORTERM, LANG, LC_ALL), TTY-aware flags - Retry with spinner on failure (TTY: 5s, non-TTY: 10s silent) - Hard fail instead of silent fallback - HERMES_DEV=1 env var bypasses routing for development - No routing messages (invisible to user) NixOS module changes: - container.hostUsers option: lists users who get ~/.hermes symlink and automatic hermes group membership - Activation script creates symlink bridge (with backup of existing ~/.hermes dirs), writes exec_user to .container-mode - Cleanup on disable: removes symlinks + .container-mode + stops service - Warning when hostUsers set without addToSystemPackages
This commit is contained in:
parent
3065e69dc5
commit
79e8cd1233
5 changed files with 695 additions and 1 deletions
|
|
@ -122,6 +122,41 @@ services.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];
|
|||
Setting `addToSystemPackages = true` does two things: puts the `hermes` CLI on your system PATH **and** sets `HERMES_HOME` system-wide so the interactive CLI shares state (sessions, skills, cron) with the gateway service. Without it, running `hermes` in your shell creates a separate `~/.hermes/` directory.
|
||||
:::
|
||||
|
||||
:::info Container-aware CLI
|
||||
When `container.enable = true` and `addToSystemPackages = true`, **every** `hermes` command on the host automatically routes into the managed container. This means your interactive CLI session runs inside the same environment as the gateway service — with access to all container-installed packages and tools.
|
||||
|
||||
- The routing is transparent: `hermes chat`, `hermes sessions list`, `hermes version`, etc. all exec into the container under the hood
|
||||
- All CLI flags are forwarded as-is
|
||||
- If the container isn't running, the CLI retries briefly (5s with a spinner for interactive use, 10s silently for scripts) then fails with a clear error — no silent fallback
|
||||
- For developers working on the hermes codebase, set `HERMES_DEV=1` to bypass container routing and run the local checkout directly
|
||||
|
||||
Set `container.hostUsers` to create a `~/.hermes` symlink to the service state directory, so the host CLI and the container share sessions, config, and memories:
|
||||
|
||||
```nix
|
||||
services.hermes-agent = {
|
||||
container.enable = true;
|
||||
container.hostUsers = [ "your-username" ];
|
||||
addToSystemPackages = true;
|
||||
};
|
||||
```
|
||||
|
||||
Users listed in `hostUsers` are automatically added to the `hermes` group for file permission access.
|
||||
|
||||
**Podman users:** The NixOS service runs the container as root. Docker users get access via the `docker` group socket, but Podman's rootful containers require sudo. Grant passwordless sudo for your container runtime:
|
||||
|
||||
```nix
|
||||
security.sudo.extraRules = [{
|
||||
users = [ "your-username" ];
|
||||
commands = [{
|
||||
command = "/run/current-system/sw/bin/podman";
|
||||
options = [ "NOPASSWD" ];
|
||||
}];
|
||||
}];
|
||||
```
|
||||
|
||||
The CLI auto-detects when sudo is needed and uses it transparently. Without this, you'll need to run `sudo hermes chat` manually.
|
||||
:::
|
||||
|
||||
### Verify It Works
|
||||
|
||||
After `nixos-rebuild switch`, check that the service is running:
|
||||
|
|
@ -246,6 +281,7 @@ Run `nix build .#configKeys && cat result` to see every leaf config key extracte
|
|||
container = {
|
||||
image = "ubuntu:24.04";
|
||||
backend = "docker";
|
||||
hostUsers = [ "your-username" ];
|
||||
extraVolumes = [ "/home/user/projects:/projects:rw" ];
|
||||
extraOptions = [ "--gpus" "all" ];
|
||||
};
|
||||
|
|
@ -285,6 +321,7 @@ Quick reference for the most common things Nix users want to customize:
|
|||
| 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 { ... }` |
|
||||
|
|
@ -518,6 +555,7 @@ When container mode is enabled, hermes runs inside a persistent Ubuntu container
|
|||
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)
|
||||
|
|
@ -526,6 +564,7 @@ Host Container
|
|||
│ ├── .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)
|
||||
|
|
@ -698,6 +737,7 @@ nix build .#checks.x86_64-linux.config-roundtrip # merge script preserves use
|
|||
| `container.image` | `str` | `"ubuntu:24.04"` | Base image (pulled at runtime) |
|
||||
| `container.extraVolumes` | `listOf str` | `[]` | Extra volume mounts (`host:container:mode`) |
|
||||
| `container.extraOptions` | `listOf str` | `[]` | Extra args passed to `docker create` |
|
||||
| `container.hostUsers` | `listOf str` | `[]` | Interactive users who get a `~/.hermes` symlink to the service stateDir and are auto-added to the `hermes` group |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -818,3 +858,5 @@ nix-store --query --roots $(docker exec hermes-agent readlink /data/current-pack
|
|||
| `hermes version` shows old version | Container not restarted | `systemctl restart hermes-agent` |
|
||||
| Permission denied on `/var/lib/hermes` | State dir is `0750 hermes:hermes` | Use `docker exec` or `sudo -u hermes` |
|
||||
| `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 |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue