Watch
0
0
Fork
You've already forked hyperhive
0

hand agents the dashboard port, pinned claude and otel labels at container start

The three values that differ per host (deploy.hive-controller.dashboardPort,
claudeCodePackage and otel.extraResourceAttributes) no longer go into the
meta flake. hive-priv writes them into the container's
/etc/hyperhive-hive-facts with the hive name and domain, and the agent
reads them at boot:

- HIVE_DASHBOARD_PORT reaches every unit through the hive-facts generator;
  the web UI still defaults to 7000 without it.
- `claude` on PATH is a wrapper that runs HYPERHIVE_CLAUDE_CODE_PATH's
  claude when it is there, and the container's own claude-code otherwise.
  The host's serve.json keeps gc-rooting the pinned build.
- OTEL_RESOURCE_ATTRIBUTES moves out of the units' Environment= into a
  boot-time generator, which appends HYPERHIVE_OTEL_EXTRA_RESOURCE_ATTRIBUTES.

The agent options services.hyperhive.agent.claudeCodePath (now a removed
option) and otel.extraResourceAttributes go; only the meta render set them.
render_flake takes no HiveEnv any more, so the memory-cap render test and
render_hive_flake_at, which only existed to vary HiveEnv into the render,
go with it.

Refs #4857
This commit is contained in:
atlas 2026-10-21 23:47:35 +02:00 • committed by mara
commit 9113651c10
23 changed files with 408 additions and 335 deletions

View file

@ -118,7 +118,10 @@ declares one flake input per agent (`agent-<n>.url =
"git+<forge>/agent-configs/<n>.git?rev=<sha>"`) and one
`nixosConfigurations.<n>` output per agent. Each output wraps
`inputs.agent-<n>.nixosModules.default` with the identity +
`HIVE_PORT` / `HIVE_LABEL` / `HIVE_DASHBOARD_PORT` injection module.
`HIVE_PORT` / `HIVE_LABEL` injection module. Values that differ per host
(the dashboard port, the pinned claude-code, extra OTEL labels) aren't in it:
`hive-priv` writes them to the container's `/etc/hyperhive-hive-facts` at
start (see `docs/process/conventions.md`).
Containers run against `--flake /var/lib/hyperhive/meta#<n>`.
The declared input url is the head of `main` on the agent's forge config repo
@ -195,8 +198,7 @@ The container's `--flake` ref is `/var/lib/hyperhive/meta#<name>`
(see "Meta flake" above). The agent's own `applied/<n>/flake.nix`
is a fixed boilerplate that exports `nixosModules.default =
import ./agent.nix`; the meta flake imports that module and
wraps it with identity + `HIVE_PORT` / `HIVE_LABEL` /
`HIVE_DASHBOARD_PORT`.
wraps it with identity + `HIVE_PORT` / `HIVE_LABEL`.
### Tag state machine

View file

@ -39,11 +39,15 @@ Four env vars cover the identity surface, read by
name.
Inside an agent container, the hive's name and domain don't come from the
agent's build. `hive-priv` writes them to `/etc/hyperhive-hive-facts` before
every container start. The agent's environment generator
(`nix/agent-modules/hive-facts.nix`) passes them to every unit, including
`hivectl choom` sessions, and `/etc/set-environment` exports them in login
shells that no unit starts (`nixos-container root-login`). Neither is part of
agent's build, and neither do the hive's other per-host values: the dashboard
port (`HIVE_DASHBOARD_PORT`), the pinned claude-code
(`HYPERHIVE_CLAUDE_CODE_PATH`) and extra OTEL labels
(`HYPERHIVE_OTEL_EXTRA_RESOURCE_ATTRIBUTES`). `hive-priv` writes them to
`/etc/hyperhive-hive-facts` before every container start, leaving out any the
hive doesn't set; the agent then uses its own default. The agent's environment
generator (`nix/agent-modules/hive-facts.nix`) passes them to every unit,
including `hivectl choom` sessions, and `/etc/set-environment` exports them in login
shells that no unit starts (`nixos-container root-login`). None is part of
an agent's closure, and an agent started on another hive reports that hive.
`hive_name` + `swarm_name` are **distinct** from

View file

@ -145,9 +145,9 @@ and every agent runs that build.
What crosses is the **store path**, not the derivation. Containers
share the host's `/nix/store`, so the binary is already reachable
inside them with its whole closure; hive-c0re writes the path into each
agent's flake as a string literal and the agent module symlinks
`bin/claude` onto PATH. Two things rule out the natural-seeming alternatives: a
inside them with its whole closure. `hive-priv` writes the path into each
container's `/etc/hyperhive-hive-facts` at start, and the agent's `claude`
wrapper on PATH runs its `bin/claude`. Two things rule out the natural-seeming alternatives: a
`path:/nix/store/<pkg>` flake input is re-copied into the store as a
reference-less `-source` (so the runtime closure never arrives), and
`lib.types.package` fed a bare path runs `builtins.storePath`, which
@ -171,7 +171,7 @@ expected.
<!-- vale write-good.Passive = NO -->
The catch is that a path written into a generated flake is text, not a
The catch is that a path handed to the container at start is text, not a
reference — the container's closure doesn't keep the binary alive.
The **host** does: it interpolates the package into
`/etc/hyperhive/serve.json`, so it lands in the host's system closure
@ -180,7 +180,7 @@ string context, which is the load-bearing detail; discard the context
anywhere on that path and `nix-collect-garbage` will eventually take
the hive's `claude` out from under it. The price of the root is that
`nix-collect-garbage` can't reclaim an old `claude-code` until every
agent has rebuilt past it and the old generations are gone.
agent has restarted past it and the old generations are gone.
<!-- vale write-good.Passive = YES -->

View file

@ -190,7 +190,7 @@ two-tier architecture, the security model, and how the options interact.
The harness sets the OTLP variables (`OTEL_EXPORTER_OTLP_ENDPOINT`, `_PROTOCOL`,
`OTEL_RESOURCE_ATTRIBUTES`, the temporality preference) **container
wide** — in systemd's `DefaultEnvironment` and in `/etc/profile` — so every
wide**, for every unit and in `/etc/profile`, so every
process in an agent container exports to the hive's collector without any
per-tool wiring. That covers Claude Code, `hive-metric`, and anything you run
yourself from a tool call or a shell you open in the container.
@ -209,8 +209,9 @@ the push (see [Authenticated ingest](#authenticated-ingest)). The container
doesn't set it.
Append additional labels for one hive via `extraResourceAttributes` (see
option reference above); pass custom per-data-point labels with
`hive-metric --labels` (see below).
option reference above). Agents get them at container start, so a change
reaches an agent at its next start, not through a rebuild. Pass custom
per-data-point labels with `hive-metric --labels` (see below).
## Log severity

View file

@ -33,11 +33,13 @@ harness unit's PATH. By default that's the `claude-code` in the agent's
own nixpkgs (the meta flake's `nixpkgs` input) via
`environment.systemPackages`. Since that's typically a release channel and
this package moves fast, the operator can pin one per hive with
`services.hyperhive.deploy.hive-controller.claudeCodePackage`: hive-c0re writes its
store path into each agent's flake, and `claude` on PATH becomes a symlink to it
instead of the container's own `claude-code` — so there's only ever one
`claude` in the container. Agents pick up a new build on their
next rebuild, not live. See docs/process/gotchas.md::`claude-code` is unfree.
`services.hyperhive.deploy.hive-controller.claudeCodePackage`. `hive-priv`
writes its store path into the container's `/etc/hyperhive-hive-facts` as
`HYPERHIVE_CLAUDE_CODE_PATH` before every start. `claude` on PATH is a wrapper
that runs that build when the path exists, and the container's own
`claude-code` when the variable is unset or the path no longer exists, saying
so on stderr in the second case. A bump reaches an agent at its next container
start, not at a rebuild. See docs/process/gotchas.md::`claude-code` is unfree.
Hive-enforced settings ship at `/etc/claude-code/managed-settings.json`
(claude-code's canonical managed-settings path — precedence #1,