refactor: nix/host-modules + nix/agent-modules layout, update doc paths

This commit is contained in:
müde 2026-07-13 22:05:49 +02:00
commit 4a48ce5024
52 changed files with 48 additions and 44 deletions

View file

@ -63,12 +63,16 @@ hand-maintained per-file tree drifts out of sync with the code.
### Other top-level dirs
- **`frontend/`** — npm workspaces → static dashboard + per-agent UI
dist, built hermetically by `nix/frontend.nix`. Packages: `shared`
(terminal pane + Catppuccin palette), `dashboard` (the operator SPA),
`agent` (the default per-container UI).
- **`nix/`** — NixOS modules (`modules/hive-{c0re,forge,gateway,matrix,
ci,network}.nix`) + per-container templates (`templates/{harness-base,
agent-base,manager,weston-vnc}.nix`) + the options-doc derivation.
dist, built hermetically by `nix/packages/frontend.nix`. Packages:
`shared` (terminal pane + Catppuccin palette), `dashboard` (the
operator SPA), `agent` (the default per-container UI).
- **`nix/`** — `host-modules/` (the host stack: hyperhive core options,
`hive-{c0re,priv,forge,gateway,matrix,network,tls,ci}`, otel, swarm),
`agent-modules/` (the per-agent harness feature modules),
`templates/{agent,ruth}.nix` (container entry points), `packages/`
(flake package outputs), `docs/` (the options-doc derivation), plus
`sources.nix` / `rust.nix` / `checks.nix` / `devshell.nix` /
`treefmt.nix` behind the thin `flake.nix`.
- **`docs/`** — subsystem reference docs (see *Reading paths* below).
- **`branding/`**, **`scripts/`** — static assets + helper scripts.

View file

@ -166,7 +166,7 @@ Tree-shape version:
`HYPERHIVE_STATE_DIR` is now injected uniformly via
`systemd.globalEnvironment` in `meta.rs` for every container
(manager included), so all token/state paths resolve through
`$HYPERHIVE_STATE_DIR`. The harness-base shell scripts
`$HYPERHIVE_STATE_DIR`. The agent-module shell scripts
(tea-login, forge-avatar-sync) simplified from glob+for loops to a
direct `$HYPERHIVE_STATE_DIR/<token>` read.
@ -215,15 +215,15 @@ nspawn agent. Open questions, not yet wired:
## Harness systemd unit shape
One harness serve binary (`hive-agent`, with its `hive-agent-mcp` /
`hive-agent-wake` siblings), one `harness-base.nix` template, one
`hive-agent-wake` siblings), one shared `nix/agent-modules/` tree, one
service unit (`systemd.services.hive-ag3nt`) for all agents. There
is no longer a separate manager service name or role distinction in
the harness — privilege differences live server-side in the broker
socket (which tool groups and manager-surface calls each agent
receives).
`agent-base.nix` and `manager.nix` both import `harness-base.nix`.
`manager.nix` additionally sets forge defaults to suppress the
`agent.nix` and `ruth.nix` both import the shared `nix/agent-modules/`.
`ruth.nix` additionally sets forge defaults to suppress the
subscription/participation firehose so ruth's inbox stays focused
on direct mentions, reviews, and assignments.

View file

@ -181,6 +181,6 @@ GC on the coordinator host won't reclaim space on the builder.
## References
- `nix/modules/hive-ci.nix`: runner configuration, auto-registration script, container setup.
- `nix/host-modules/hive-ci.nix`: runner configuration, auto-registration script, container setup.
- `.forgejo/workflows/ci.yml`: workflow definition.
- `docs/gotchas.md`: nix sandboxing limitations in containers.

View file

@ -77,7 +77,7 @@ socket without needing a clean reinstall.
## `claude-code` is unfree
`claude-code` comes from the flake's main `nixpkgs` (nixos-26.05).
It's unfree, so `harness-base.nix` sets `config.allowUnfreePredicate`
It's unfree, so the agent modules set `config.allowUnfreePredicate`
at the container level to whitelist `claude-code` specifically —
scoped, only this one package. This is needed because each per-agent
`nixosConfiguration` evaluates its own nixpkgs instance and the
@ -204,7 +204,7 @@ containers don't get user-namespaces by default, so `nix build`
invocations _inside_ the container can't set up the build sandbox
and fail outright if the host daemon's
`nix.settings.sandbox-fallback` is `false` (nixpkgs default).
`nix/templates/harness-base.nix` does `lib.mkForce true` so builds
`nix/agent-modules/default.nix` does `lib.mkForce true` so builds
fall back to unsandboxed local builds rather than failing. Security
implications: `docs/security.md`.
@ -284,7 +284,7 @@ connects to the compositor at `127.0.0.1:<vnc_port>`.
inherit it.
- **Fixed Wayland socket name (`--socket=wayland-0`)**: weston is
launched with `--socket=wayland-0` so the socket path is
deterministic. `harness-base.nix` exports `WAYLAND_DISPLAY=wayland-0`
deterministic. `nix/agent-modules/weston-vnc.nix` exports `WAYLAND_DISPLAY=wayland-0`
and `XDG_RUNTIME_DIR=/run/gui` as global system environment
variables (gated on `hyperhive.gui.enable`) so every systemd service
in the container inherits them. Without this, services starting
@ -311,7 +311,7 @@ connects to the compositor at `127.0.0.1:<vnc_port>`.
must never block on weston signalling readiness. A misconfigured
weston degrades to a `Restart=on-failure` loop visible in
`journalctl`, it does not abort the `nixos-container update`.
Same reasoning as the `tea-login` unit in `harness-base.nix`.
Same reasoning as the `tea-login` unit in `nix/agent-modules/forge.nix`.
- **`[core] idle-time=0`**: disables weston's 300-second idle
timeout. Without it the VNC desktop fades to black and
desktop-shell shows its click-to-unlock screen — useless for an
@ -325,7 +325,7 @@ connects to the compositor at `127.0.0.1:<vnc_port>`.
`pkgs.nixosOptionsDoc` over two evaluated module trees:
`hostEval` (a stub NixOS system loading `hive-c0re.nix` with every
hyperhive subsystem `mkForce false` so heavy build inputs stay out of
the eval) and `agentEval` (evaluates `agent-base.nix` fresh for the
the eval) and `agentEval` (evaluates `agent.nix` fresh for the
per-agent options tree).
Three output trees consumed by `flake.nix`, all **markdown**:
@ -333,7 +333,7 @@ Three output trees consumed by `flake.nix`, all **markdown**:
- `docs-host` — operator-facing host module options
(`services.hyperhive.*`)
- `docs-agent` — per-agent harness options (`hyperhive.*`
declared in `nix/templates/harness-base.nix`)
declared in `nix/agent-modules/`)
- `docs` — bundle of `index.md` + `host.md` + `agent.md`
Pipeline:

View file

@ -214,7 +214,7 @@ which has two upstream gaps for fluffychat's web target:
- `native_imaging`'s C source isn't built — emscripten isn't a
flutter-builder native build input.
Both fixed in `nix/modules/hive-matrix.nix` via two derivations:
Both fixed in `nix/host-modules/hive-matrix.nix` via two derivations:
- **`fluffychat-web-imaging`** builds `Imaging.{js,wasm}` from the
`native_imaging` C source via `pkgs.emscripten`. Source comes

View file

@ -129,7 +129,7 @@ address arithmetic.
and `HOST_BRIDGE=<bridgeName>` via `lifecycle::set_nspawn_flags` when
creating or updating containers. `LOCAL_ADDRESS` is left empty so the
container's dhcpcd acquires an address from the bridge dnsmasq pool
(`networking.useDHCP = true` in `harness-base.nix`). This applies uniformly
(`networking.useDHCP = true` in `nix/agent-modules/network.nix`). This applies uniformly
to all containers — agents and service containers alike.
`HOST_ADDRESS` is the bridge gateway IP (the address part of
@ -154,7 +154,7 @@ wiring is runtime:
- `hive-priv` drops a marker file (`/etc/hyperhive-bridge-dns`, carrying the
gateway IP) into each container's `/etc`.
- the `hyperhive-isolated-dns` oneshot (harness-base.nix), gated on that
- the `hyperhive-isolated-dns` oneshot (`nix/agent-modules/network.nix`), gated on that
marker, rewrites `/etc/resolv.conf` to `nameserver <gateway-ip>` at boot.
It is ordered `before` the harness (`hive-ag3nt`), the matrix daemon, and
`tea-login` so the resolver is correct before the first DNS lookup.

View file

@ -369,7 +369,7 @@ state dirs need a one-time data shuffle so they don't lose their claude
session.
`system.activationScripts.hive-agent-user-migrate` (in
`nix/templates/harness-base.nix`) runs on every activation,
`nix/agent-modules/user.nix`) runs on every activation,
marker-guarded so the substantive moves only happen once per
container lifetime:

View file

@ -146,7 +146,7 @@ component can't traverse.
Agent containers bind-mount the host's `nix-daemon` socket. The host daemon may
have `sandbox-fallback = false` (strict NixOS defaults), which causes `nix build`
inside nspawn containers to fail — containers lack kernel user namespaces, so nix
cannot set up its build sandbox. `harness-base.nix` sets `sandbox-fallback = true`
cannot set up its build sandbox. the agent modules set `sandbox-fallback = true`
so that builds fall back to unsandboxed execution rather than failing outright.
### Threat model

View file

@ -2,7 +2,7 @@
Background shell execution via `hive-bash-mcp`. Tools land as
`mcp__bash__<tool>` (the MCP server name is `bash`, not `hyperhive`).
Available on every agent unconditionally — `harness-base.nix` always
Available on every agent unconditionally — `nix/agent-modules/mcp.nix` always
injects bash into `hyperhive.extraMcpServers` (with `allowedTools =
["*"]`), so `mcp__bash__*` is in `--allowedTools` for every claude
invocation regardless of tool groups.
@ -96,7 +96,7 @@ The bash tooling follows the same daemon + stdio-bridge pattern as the
matrix MCP:
- **`hive-bash-daemon`** — long-running process (one per agent container,
systemd service in `harness-base.nix`). Owns subprocess management,
systemd service in `nix/agent-modules/mcp.nix`). Owns subprocess management,
output file writing, `mcp-loose-ends/` state, and wake signal delivery.
Listens on `/run/hive-bash/socket` inside the container.

View file

@ -1,7 +1,7 @@
# hive-forge CLI
`hive-forge` is the Forgejo API wrapper available in every agent
container (installed via `harness-base.nix`; lives in `/hive-forge`
container (installed via `nix/agent-modules/forge.nix`; lives in `/hive-forge`
as a proper Rust binary). Use it instead of ad-hoc curl pipelines.
## Credentials and repo defaults

View file

@ -23,7 +23,7 @@ parsed from a turn (usage, cost, context window, resolved model) as
Hive-enforced settings ship at `/etc/claude-code/managed-settings.json`
(claude-code's canonical managed-settings path — precedence #1,
read-only, un-overridable), wired in `nix/templates/harness-base.nix`
read-only, un-overridable), wired in `nix/agent-modules/claude-settings.nix`
from the `prompts/claude-settings.json` asset. `effortLevel` is
deliberately not in that file — effort is controlled live via the
`--effort` flag (`HIVE_DEFAULT_EFFORT` / the per-agent UI slider), which

View file

@ -17,7 +17,7 @@ sentence into the agent's system prompt so it knows the docs exist and
where to find them. The tree is served by `claude --add-dir` so the full
markdown is readable during every turn.
Enabled by default only for the root/manager agent (`manager.nix`). Any
Enabled by default only for the root/manager agent (`nix/templates/ruth.nix`). Any
agent can opt in by adding the line above to its `agent.nix`.
The `docs/` source is a narrow flake input (`hyperhive-docs`) tracked

View file

@ -20,7 +20,7 @@
# nix/checks.nix flake checks
# nix/devshell.nix dev shell
# nix/treefmt.nix formatter config
# nix/modules/, nix/templates/ the NixOS module + container trees
# nix/host-modules/, nix/agent-modules/, nix/templates/ the NixOS module trees
outputs =
inputs@{
self,
@ -71,7 +71,7 @@
let
# Package wiring for agent containers — the harness modules
# consume hyperhive's own packages via the `hyperhive.packages`
# option (see nix/templates/harness/packages.nix); no overlay.
# option (see nix/agent-modules/packages.nix); no overlay.
# `mkDefault` so a per-agent override of an individual key wins.
agentPackages =
{ lib, pkgs, ... }:
@ -103,7 +103,7 @@
./nix/templates/ruth.nix
agentPackages
];
# The full host stack (nix/modules/default.nix aggregator) plus
# The full host stack (nix/host-modules/default.nix aggregator) plus
# the package/source wiring from this flake. The wiring is a
# plain config module setting the `services.hyperhive.c0re.*`
# package options via `lib.mkDefault` — no overlay involved, and
@ -115,7 +115,7 @@
default =
{ lib, pkgs, ... }:
{
imports = [ ./nix/modules ];
imports = [ ./nix/host-modules ];
services.hyperhive.c0re = {
package = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.default;
frontend = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.frontend;
@ -136,8 +136,8 @@
managerToplevel = lib.mkDefault self.packages.x86_64-linux.ruth-toplevel;
};
};
hive-ci = ./nix/modules/hive-ci.nix;
hive-forge = ./nix/modules/hive-forge;
hive-ci = ./nix/host-modules/hive-ci.nix;
hive-forge = ./nix/host-modules/hive-forge;
};
nixosConfigurations =

View file

@ -82,7 +82,7 @@ let
in
{
# OTEL stats export is configured ONCE at host level via
# `services.hyperhive.otel.*` (see nix/modules/hive-c0re.nix) and
# `services.hyperhive.otel.*` (see nix/host-modules/hive-c0re.nix) and
# injected into every agent's build by the meta-flake renderer
# (`hive-c0re/src/meta.rs::otel_config`). These per-agent options are
# the build-time implementation surface that injection writes into;

View file

@ -1,5 +1,5 @@
# Shared scaffolding for every hyperhive harness container.
# `../agent.nix` and `../ruth.nix` both import this; all
# `../templates/agent.nix` and `../templates/ruth.nix` both import
# agents use the same service unit regardless of which entry-point
# they came from.
#

View file

@ -15,7 +15,7 @@
`$HIVE_DOCS_DIR/`, and appends a single pointer sentence to the agent's
system prompt so it knows the docs exist (see
`hive-ag3nt::prompt::render`). Default-on for the root/manager agent
(see `../ruth.nix`), off elsewhere; any agent can flip it from its
(see `../templates/ruth.nix`), off elsewhere; any agent can flip it from its
`agent.nix`.
'';

View file

@ -37,7 +37,7 @@ in
- runs `hive-matrix-daemon` as a systemd unit that holds a
matrix-sdk Client + sync against the homeserver at
`HIVE_MATRIX_URL` (default `http://localhost:8008` the
in-host tuwunel from `nix/modules/hive-matrix.nix`). The
in-host tuwunel from `nix/host-modules/hive-matrix.nix`). The
daemon auto-skips when `<state>/matrix-token` is missing,
and a `systemd.paths` watcher restarts it the moment
hive-c0re provisions the token (same path-trigger shape

View file

@ -19,7 +19,7 @@
# the hyperhive-isolated-dns oneshot owns resolv.conf. (Same "take
# resolvconf out of the loop" approach the matrix container uses.)
# All agent containers receive their bridge IP via DHCP from the hive
# dnsmasq pool (see nix/modules/hive-gateway.nix). useDHCP runs dhcpcd
# dnsmasq pool (see nix/host-modules/hive-gateway.nix). useDHCP runs dhcpcd
# on every interface (just eth0 in practice — the nspawn bridge veth).
config = {
networking.useDHCP = true;

View file

@ -33,7 +33,7 @@ let
hostEval = nixosSystem {
system = pkgs.stdenv.hostPlatform.system;
modules = [
"${nixSrc}/modules"
"${nixSrc}/host-modules"
(
{ lib, ... }:
{
@ -51,7 +51,7 @@ let
};
# Agent module eval from the content-addressed nixSrc. Relative
# imports inside agent.nix (the ./harness module dir) resolve
# imports inside agent.nix (the ../agent-modules dir) resolve
# correctly against the nixSrc directory tree. `hyperhive.packages`
# stays unset — every option default that references it carries a
# `defaultText`, so the doc walk never forces the packages.
@ -155,7 +155,7 @@ let
`hyperhive.nixosModules.default` to operator host configurations
(`services.hyperhive.{enable,domain,c0re,forge,matrix,gateway}.*`).
- [per-agent options](agent.md) options declared in
`nix/templates/harness/`, visible from every `agent.nix`
`nix/agent-modules/`, visible from every `agent.nix`
(`hyperhive.model`, `hyperhive.allowedRecipients`,
`hyperhive.extraMcpServers`, `hyperhive.frontend.*`,
`hyperhive.forge.*`, `hyperhive.matrix.*`, `hyperhive.gui.*`).

View file

@ -158,7 +158,7 @@ in
# so operators can `nix build .#agent-base-toplevel` (or wire
# them into their host system closure via the
# `preBuildAgentTemplates` option on the hive-c0re module —
# see nix/modules/hive-c0re.nix). Speeds up the first agent
# see nix/host-modules/hive-c0re.nix). Speeds up the first agent
# spawn dramatically because the heavy lifting (nixpkgs +
# claude-code + hive-ag3nt binary) is already in the store
# when the meta evaluator goes to build the container.

View file

@ -1,6 +1,6 @@
{ ... }:
{
imports = [ ./harness ];
imports = [ ../agent-modules ];
# Entry-point for sub-agent containers. Referenced from `flake.nix`
# (`nixosConfigurations.agent-base`) and the meta-flake's
# `applied/<name>/flake.nix`.

View file

@ -3,7 +3,7 @@
# Entry-point for the privileged root agent (ruth). Referenced from
# `flake.nix` (`nixosConfigurations.ruth`) and the meta-flake's
# `applied/ruth/flake.nix`.
imports = [ ./harness ];
imports = [ ../agent-modules ];
# The root/manager bootstraps a fresh hive, so it gets the hyperhive
# reference docs made available by default (readable at