From 8de91ce9d22fd979f6ab61a4e5ff9da5e1c69647 Mon Sep 17 00:00:00 2001 From: Siddharth Balyan <52913345+alt-glitch@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:39:53 -0700 Subject: [PATCH] fix(nix): make addToSystemPackages fully functional for interactive CLI (#6317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(nix): export HERMES_HOME system-wide when addToSystemPackages is true The `addToSystemPackages` option's documentation (and the `:::tip` block in `website/docs/getting-started/nix-setup.md`) promises that enabling it both puts the `hermes` CLI on PATH and sets `HERMES_HOME` system-wide so interactive shells share state with the gateway service. The module only did the former, so running `hermes` in a user shell silently created a separate `~/.hermes/` directory instead of the managed `${stateDir}/.hermes`. Implement the documented behavior by also setting `environment.variables.HERMES_HOME = "${cfg.stateDir}/.hermes"` in the same mkIf block, and update the option description to match. Fixes #6044 * fix(nix): preserve group-readable permissions in managed mode The NixOS module sets HERMES_HOME directories to 0750 and files to 0640 so interactive users in the hermes group can share state with the gateway service. Two issues prevented this from working: 1. hermes_cli/config.py: _secure_dir() unconditionally chmod'd HERMES_HOME to 0700 on every startup, overwriting the NixOS module's 0750. Similarly, _secure_file() forced 0600 on config files. Both now skip in managed mode (detected via .managed marker or HERMES_MANAGED env var). 2. nix/nixosModules.nix: the .env file was created with 0600 (owner-only), while config.yaml was already 0640 (group-readable). Changed to 0640 for consistency — users granted hermes group membership should be able to read the managed .env. Verified with a NixOS VM integration test: a normal user in the hermes group can now run `hermes version` and `hermes config` against the managed HERMES_HOME without PermissionError. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: zerone0x Co-authored-by: Claude Opus 4.6 (1M context) --- hermes_cli/config.py | 17 +++++++++++++++-- nix/nixosModules.nix | 12 ++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/hermes_cli/config.py b/hermes_cli/config.py index 350d99cf8..6e86886be 100644 --- a/hermes_cli/config.py +++ b/hermes_cli/config.py @@ -157,7 +157,14 @@ def get_project_root() -> Path: return Path(__file__).parent.parent.resolve() def _secure_dir(path): - """Set directory to owner-only access (0700). No-op on Windows.""" + """Set directory to owner-only access (0700). No-op on Windows. + + Skipped in managed mode — the NixOS module sets group-readable + permissions (0750) so interactive users in the hermes group can + share state with the gateway service. + """ + if is_managed(): + return try: os.chmod(path, 0o700) except (OSError, NotImplementedError): @@ -165,7 +172,13 @@ def _secure_dir(path): def _secure_file(path): - """Set file to owner-only read/write (0600). No-op on Windows.""" + """Set file to owner-only read/write (0600). No-op on Windows. + + Skipped in managed mode — the NixOS activation script sets + group-readable permissions (0640) on config files. + """ + if is_managed(): + return try: if os.path.exists(str(path)): os.chmod(path, 0o600) diff --git a/nix/nixosModules.nix b/nix/nixosModules.nix index acf9a6e9d..c961aa616 100644 --- a/nix/nixosModules.nix +++ b/nix/nixosModules.nix @@ -464,7 +464,11 @@ addToSystemPackages = mkOption { type = types.bool; default = false; - description = "Add hermes CLI to environment.systemPackages."; + description = '' + Add the hermes CLI to environment.systemPackages and export + HERMES_HOME system-wide (via environment.variables) so interactive + shells share state with the gateway service. + ''; }; # ── OCI Container (opt-in) ────────────────────────────────────────── @@ -545,8 +549,12 @@ }) # ── Host CLI ────────────────────────────────────────────────────── + # Add the hermes CLI to system PATH and export HERMES_HOME system-wide + # so interactive shells share state (sessions, skills, cron) with the + # gateway service instead of creating a separate ~/.hermes/. (lib.mkIf cfg.addToSystemPackages { environment.systemPackages = [ cfg.package ]; + environment.variables.HERMES_HOME = "${cfg.stateDir}/.hermes"; }) # ── Directories ─────────────────────────────────────────────────── @@ -601,7 +609,7 @@ # so this is the single source of truth for both native and container mode. ${lib.optionalString (cfg.environment != {} || cfg.environmentFiles != []) '' ENV_FILE="${cfg.stateDir}/.hermes/.env" - install -o ${cfg.user} -g ${cfg.group} -m 0600 /dev/null "$ENV_FILE" + install -o ${cfg.user} -g ${cfg.group} -m 0640 /dev/null "$ENV_FILE" cat > "$ENV_FILE" <<'HERMES_NIX_ENV_EOF' ${envFileContent} HERMES_NIX_ENV_EOF