diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index f3027205..017f3c28 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -235,8 +235,9 @@ in auto-loads the file every session, so the docs are discoverable without any per-agent prompt injection. The docs themselves are always present at `$HIVE_ASSETS_DIR/docs/`; this option only controls - the auto-loaded pointer. Default-on for the root/manager agent (see - `manager.nix`), off elsewhere; any agent can flip it from its + the auto-loaded pointer. When enabled the managed symlink clobbers any + existing `~/.claude/CLAUDE.md`. Default-on for the root/manager agent + (see `manager.nix`), off elsewhere; any agent can flip it from its `agent.nix`. ''; @@ -1042,12 +1043,19 @@ in chown -hR "$userName:$userName" "$configDir" 2>/dev/null || true done ${lib.optionalString config.hyperhive.docs.enable '' - # hyperhive.docs.enable: point this agent at the hyperhive docs - # via a managed `~/.claude/CLAUDE.md` (claude auto-loads it every - # session). Symlink → always reflects the current flake; the + # hyperhive.docs.enable: point this agent at the hyperhive docs via + # a managed `~/.claude/CLAUDE.md` (claude auto-loads it every + # session). The link lives in the bind-mounted (persistent) home, so + # it must NOT target a bare `/nix/store` path — that path is only + # GC-rooted by the current generation, and a content change (new + # hash) plus `nix-collect-garbage` would leave the persistent link + # dangling. Instead it targets the STABLE `/etc/hyperhive/claude/ + # CLAUDE.md` path, which the `environment.etc` entry below + # regenerates declaratively every rebuild (and which holds the + # docs store-path reference that keeps the content GC-rooted). The # chown -h below sets the link's ownership. mkdir -p "$homeDir/.claude" - ln -sfn ${docsClaudeMd} "$homeDir/.claude/CLAUDE.md" + ln -sfn /etc/hyperhive/claude/CLAUDE.md "$homeDir/.claude/CLAUDE.md" ''} if [ -d "$homeDir/.claude" ]; then chown -hR "$userName:$userName" "$homeDir/.claude" 2>/dev/null || true @@ -1089,6 +1097,16 @@ in environment.etc."hyperhive/extra-mcp.json".text = builtins.toJSON config.hyperhive.extraMcpServers; + # hyperhive.docs.enable: the managed `~/.claude/CLAUDE.md` content, + # placed declaratively in /etc so it's regenerated every rebuild and + # GC-rooted by the system closure. The activation script above symlinks + # the agent's (bind-mounted, persistent) `~/.claude/CLAUDE.md` at this + # stable path rather than at the bare `${docsClaudeMd}` store path, so + # the persistent link can never dangle after a content change + GC. + environment.etc."hyperhive/claude/CLAUDE.md" = lib.mkIf config.hyperhive.docs.enable { + source = docsClaudeMd; + }; + # Operator-set per-agent icon (hyperhive.icon). When configured, the # SVG lands at /etc/hyperhive/icon.svg; the harness serves it at # GET /icon, falling back to the bundled hyperhive logo when absent.