Watch
0
0
Fork
You've already forked hyperhive
0

build every agent from the agent-base template

Delete nix/templates/ruth.nix, the ruth nixosConfiguration, module and
toplevel, the hive-c0re managerToplevel option, and the meta flake's
isManager switch with lifecycle::MANAGER_NAME. Every agent, ruth
included, now builds from nix/templates/agent.nix. The template's only
content beyond agent.nix was docs.enable = mkDefault true; docs.enable
is off by default for every agent and ruth's own agent.nix turns it on.

Refs #5377
This commit is contained in:
atlas 2026-10-17 00:12:01 +02:00 • committed by mara
commit 1b60084bf0
15 changed files with 85 additions and 95 deletions

View file

@ -174,8 +174,8 @@ Swarm-level:
`nix/packages/swarm-ui.nix`, not in `packages.default`'s closure). `nix/packages/swarm-ui.nix`, not in `packages.default`'s closure).
- **`nix/`** — `host-modules/` (the host stack), `agent-modules/` - **`nix/`** — `host-modules/` (the host stack), `agent-modules/`
(per-agent harness features), `container-modules/` (guest side of (per-agent harness features), `container-modules/` (guest side of
service containers), `templates/{agent,ruth}.nix` (container entry service containers), `templates/agent.nix` (the container entry
points), `packages/`, `docs/` (options doc), `module-eval/` (NixOS point), `packages/`, `docs/` (options doc), `module-eval/` (NixOS
module-eval tests), `builder/` (`check-flake`), `script-tests/`, plus module-eval tests), `builder/` (`check-flake`), `script-tests/`, plus
`sources.nix` / `rust.nix` / `checks.nix` / `devshell.nix` / `sources.nix` / `rust.nix` / `checks.nix` / `devshell.nix` /
`treefmt.nix` behind the thin `flake.nix`. `treefmt.nix` behind the thin `flake.nix`.

View file

@ -330,8 +330,10 @@ same as any other agent.
Differences from sub-agents: Differences from sub-agents:
- `flake.nix` extends `hyperhive.nixosConfigurations.ruth` - Reference docs: her `agent.nix` turns on `services.hyperhive.agent.docs.enable`.
(vs `agent-base`). Her container builds from `agent-base` like every agent, and the seeded
`agent.nix` is the same for every name, so a newly created ruth has no docs
until a config PR adds that line.
- Web UI port via `lifecycle::agent_web_port("ruth")` — same - Web UI port via `lifecycle::agent_web_port("ruth")` — same
FNV-1a hash as every other agent (8100..8999 range). FNV-1a hash as every other agent (8100..8999 range).
- The root agent holds `manage_root_agent` (the swarm UI's setup - The root agent holds `manage_root_agent` (the swarm UI's setup

View file

@ -183,11 +183,10 @@ sibling), one shared `nix/agent-modules/` tree, one service unit
differences live in the agent's swarm permissions and the broker socket (which tools differences live in the agent's swarm permissions and the broker socket (which tools
and manager-surface calls each agent receives). and manager-surface calls each agent receives).
`agent.nix` and `ruth.nix` both import the shared `nix/agent-modules/`. `nix/templates/agent.nix` is the one entry point every agent builds from, and
`ruth.nix` additionally defaults it imports the shared `nix/agent-modules/`.
`services.hyperhive.agent.docs.enable` to `true`, so the root/manager `services.hyperhive.agent.docs.enable` defaults to `false` for every agent,
gets the hyperhive reference docs readable at `$HIVE_DOCS_DIR` by ruth included; an agent opts in from its own `agent.nix` (see
default; other agents opt in per `agent.nix` (see
[config.md](config.md), "Reference docs"). [config.md](config.md), "Reference docs").
### Environment variables set on the unit ### Environment variables set on the unit

View file

@ -8,7 +8,7 @@ Absent means the default. (The claude spawn + compaction themselves live in
## Reference docs (`services.hyperhive.agent.docs.enable`) ## Reference docs (`services.hyperhive.agent.docs.enable`)
```nix ```nix
services.hyperhive.agent.docs.enable = true; # default: false (true for the manager agent) services.hyperhive.agent.docs.enable = true; # default: false
``` ```
Makes the hyperhive `docs/` tree available inside the container at a nix Makes the hyperhive `docs/` tree available inside the container at a nix
@ -17,8 +17,8 @@ sentence into the agent's system prompt so it knows the docs exist and
where to find them. `claude --add-dir` serves the tree so the full where to find them. `claude --add-dir` serves the tree so the full
markdown is readable during every turn. markdown is readable during every turn.
Enabled by default only for the root/manager agent (`nix/templates/ruth.nix`). Any Off by default for every agent, ruth included. An agent opts in by adding the
agent can opt in by adding the line above to its `agent.nix`. line above to its `agent.nix`.
The `docs/` source is a narrow flake input (`hyperhive-docs`) tracked The `docs/` source is a narrow flake input (`hyperhive-docs`) tracked
separately from the main `hyperhive` flake so editing docs re-locks only separately from the main `hyperhive` flake so editing docs re-locks only

View file

@ -109,10 +109,6 @@
./nix/templates/agent.nix ./nix/templates/agent.nix
agentPackages agentPackages
]; ];
ruth.imports = [
./nix/templates/ruth.nix
agentPackages
];
# The full host stack (nix/host-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 # the package/source wiring from this flake. The wiring is a
# plain config module setting the `services.hyperhive.c0re.*` # plain config module setting the `services.hyperhive.c0re.*`
@ -135,7 +131,7 @@
# Narrow docs/ source, threaded as its own meta-flake input # Narrow docs/ source, threaded as its own meta-flake input
# so doc edits don't re-hash the whole flake source. # so doc edits don't re-hash the whole flake source.
hyperhiveDocs = lib.mkDefault "${sources.hyperhiveDocsSource}"; hyperhiveDocs = lib.mkDefault "${sources.hyperhiveDocsSource}";
# Per-container toplevels — wired into # The agent-base toplevel every container builds from — wired into
# `system.extraDependencies` when # `system.extraDependencies` when
# `services.hyperhive.c0re.preBuildAgentTemplates` is on so # `services.hyperhive.c0re.preBuildAgentTemplates` is on so
# the host system closure pre-fetches the heavy build # the host system closure pre-fetches the heavy build
@ -143,7 +139,6 @@
# hardcoded to that system); the gate keeps aarch64 hosts # hardcoded to that system); the gate keeps aarch64 hosts
# from pulling them in via cross-build. # from pulling them in via cross-build.
agentBaseToplevel = lib.mkDefault self.packages.x86_64-linux.agent-base-toplevel; agentBaseToplevel = lib.mkDefault self.packages.x86_64-linux.agent-base-toplevel;
managerToplevel = lib.mkDefault self.packages.x86_64-linux.ruth-toplevel;
}; };
services.hyperhive.deploy.swarm-controller.package = services.hyperhive.deploy.swarm-controller.package =
lib.mkDefault lib.mkDefault
@ -208,7 +203,6 @@
in in
{ {
agent-base = mkContainer self.nixosModules.agent-base; agent-base = mkContainer self.nixosModules.agent-base;
ruth = mkContainer self.nixosModules.ruth;
}; };
devShells = forAllSystems ({ pkgs, rust, ... }: import ./nix/devshell.nix { inherit pkgs rust; }); devShells = forAllSystems ({ pkgs, rust, ... }: import ./nix/devshell.nix { inherit pkgs rust; });

View file

@ -530,7 +530,7 @@ async fn set_nspawn_flags(
// Claude credentials land at `/home/<agent>/.claude` so the // Claude credentials land at `/home/<agent>/.claude` so the
// `claude` CLI (which reads `$HOME/.claude`) finds them. The // `claude` CLI (which reads `$HOME/.claude`) finds them. The
// harness service's environment sets `HOME` to the same path // harness service's environment sets `HOME` to the same path
// (`agent.nix` / `ruth.nix` templates), so no `--setenv` plumbing // (`agent.nix` template), so no `--setenv` plumbing
// is needed here — the bind alone is enough. // is needed here — the bind alone is enough.
let claude_mount = container_claude_mount(agent_name); let claude_mount = container_claude_mount(agent_name);

View file

@ -31,9 +31,6 @@ pub use hive_host_sock::{AGENT_PREFIX, container_name};
/// 11 chars (it gets encoded into network interface names) and `AGENT_PREFIX` /// 11 chars (it gets encoded into network interface names) and `AGENT_PREFIX`
/// (`h-`) takes 2, so the agent name itself is at most `MAX_AGENT_NAME` chars. /// (`h-`) takes 2, so the agent name itself is at most `MAX_AGENT_NAME` chars.
pub const MAX_AGENT_NAME: usize = 9; pub const MAX_AGENT_NAME: usize = 9;
/// Logical name of the manager agent (broker recipient, state-dir key,
/// meta flake attribute). All persistent state lives under `ruth/`.
pub const MANAGER_NAME: &str = "ruth";
/// Mount point of the per-agent runtime directory inside the container. /// Mount point of the per-agent runtime directory inside the container.
pub const CONTAINER_RUNTIME_MOUNT: &str = "/run/hive"; pub const CONTAINER_RUNTIME_MOUNT: &str = "/run/hive";
@ -327,7 +324,6 @@ async fn agents_for_meta(name_to_add: Option<&str>) -> Result<Vec<crate::meta::A
.filter_map(|c| { .filter_map(|c| {
let name = c.strip_prefix(AGENT_PREFIX)?.to_owned(); let name = c.strip_prefix(AGENT_PREFIX)?.to_owned();
Some(crate::meta::AgentSpec { Some(crate::meta::AgentSpec {
is_manager: name == MANAGER_NAME,
port: agent_web_port(&name), port: agent_web_port(&name),
name, name,
}) })
@ -337,7 +333,6 @@ async fn agents_for_meta(name_to_add: Option<&str>) -> Result<Vec<crate::meta::A
&& !out.iter().any(|a| a.name == extra) && !out.iter().any(|a| a.name == extra)
{ {
out.push(crate::meta::AgentSpec { out.push(crate::meta::AgentSpec {
is_manager: extra == MANAGER_NAME,
port: agent_web_port(extra), port: agent_web_port(extra),
name: extra.to_owned(), name: extra.to_owned(),
}); });

View file

@ -41,7 +41,6 @@ pub const CONTAINER_MANAGER_META_MOUNT: &str = "/meta";
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AgentSpec { pub struct AgentSpec {
pub name: String, pub name: String,
pub is_manager: bool,
pub port: u16, pub port: u16,
} }
@ -804,13 +803,11 @@ where
out.push_str(" };\n outputs =\n { self, hyperhive, ... }@inputs:\n let\n"); out.push_str(" };\n outputs =\n { self, hyperhive, ... }@inputs:\n let\n");
let _ = writeln!( let _ = writeln!(
out, out,
" dashboardPort = {dashboard_port};\n mkAgent = {{ name, isManager, port }}:" " dashboardPort = {dashboard_port};\n mkAgent = {{ name, port }}:"
); );
out.push_str( out.push_str(
r#" let r#" let
base = if isManager base = hyperhive.nixosConfigurations.agent-base;
then hyperhive.nixosConfigurations.ruth
else hyperhive.nixosConfigurations.agent-base;
input = inputs."agent-${name}"; input = inputs."agent-${name}";
service = "hive-agent"; service = "hive-agent";
in in
@ -1013,11 +1010,8 @@ where
for spec in agents { for spec in agents {
let _ = writeln!( let _ = writeln!(
out, out,
" {} = mkAgent {{ name = \"{}\"; isManager = {}; port = {}; }};", " {} = mkAgent {{ name = \"{}\"; port = {}; }};",
spec.name, spec.name, spec.name, spec.port,
spec.name,
if spec.is_manager { "true" } else { "false" },
spec.port,
); );
} }
out.push_str(" };\n };\n}\n"); out.push_str(" };\n };\n}\n");
@ -1229,10 +1223,9 @@ mod tests {
); );
} }
fn sample_spec(name: &str, is_manager: bool, port: u16) -> AgentSpec { fn sample_spec(name: &str, port: u16) -> AgentSpec {
AgentSpec { AgentSpec {
name: name.to_owned(), name: name.to_owned(),
is_manager,
port, port,
} }
} }
@ -1259,7 +1252,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
// nixpkgs is a top-level input with an explicit URL; hyperhive // nixpkgs is a top-level input with an explicit URL; hyperhive
// follows it. // follows it.
@ -1303,7 +1296,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
assert!( assert!(
!out.contains("hyperhive-docs"), !out.contains("hyperhive-docs"),
@ -1319,7 +1312,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
assert!( assert!(
out.contains(r#"networking.hostName = "h-${name}";"#), out.contains(r#"networking.hostName = "h-${name}";"#),
@ -1357,7 +1350,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
Some("/nix/store/cccc-claude-code-2.1.220"), Some("/nix/store/cccc-claude-code-2.1.220"),
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
assert!( assert!(
out.contains( out.contains(
@ -1383,7 +1376,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
assert!( assert!(
!out.contains("claudeCodePath"), !out.contains("claudeCodePath"),
@ -1401,7 +1394,7 @@ mod tests {
"", "",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
assert!( assert!(
out.contains("nixpkgs.follows = \"hyperhive/nixpkgs\""), out.contains("nixpkgs.follows = \"hyperhive/nixpkgs\""),
@ -1430,9 +1423,9 @@ mod tests {
None, None,
8000, 8000,
&[ &[
sample_spec("argus", false, 9001), sample_spec("argus", 9001),
sample_spec("bitburner", false, 9002), sample_spec("bitburner", 9002),
sample_spec("dmatrix", false, 9003), sample_spec("dmatrix", 9003),
], ],
lookup, lookup,
); );
@ -1452,6 +1445,33 @@ mod tests {
); );
} }
#[test]
fn render_flake_builds_every_agent_from_agent_base() {
let out = render_flake(
"github:example/hyperhive",
"path:/nix/store/bbbb-hyperhive-docs-source",
"path:/nix/store/aaaa-nixpkgs-source",
None,
8000,
&[sample_spec("alice", 9001), sample_spec("ruth", 9002)],
);
assert_eq!(
out.matches("hyperhive.nixosConfigurations.").count(),
1,
"one base for every agent:\n{out}"
);
assert!(
out.contains("base = hyperhive.nixosConfigurations.agent-base;"),
"{out}"
);
for line in [
"alice = mkAgent { name = \"alice\"; port = 9001; };",
"ruth = mkAgent { name = \"ruth\"; port = 9002; };",
] {
assert!(out.contains(line), "missing `{line}`:\n{out}");
}
}
#[test] #[test]
fn render_flake_skips_canonical_follows_when_lookup_returns_empty() { fn render_flake_skips_canonical_follows_when_lookup_returns_empty() {
let out = render_flake_with_lookup( let out = render_flake_with_lookup(
@ -1460,7 +1480,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
|_| Vec::new(), |_| Vec::new(),
); );
// No agent-side follows when the lookup reports nothing // No agent-side follows when the lookup reports nothing
@ -1496,7 +1516,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
unsafe { unsafe {
std::env::remove_var("HIVE_FORGE_URL"); std::env::remove_var("HIVE_FORGE_URL");
@ -1539,7 +1559,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
) )
}; };
let alpha = render_on("alpha-hive", "alpha-hive.example.test"); let alpha = render_on("alpha-hive", "alpha-hive.example.test");
@ -1717,7 +1737,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
unsafe { unsafe {
std::env::remove_var("HIVE_FORGE_URL"); std::env::remove_var("HIVE_FORGE_URL");
@ -1751,7 +1771,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
); );
let want = format!( let want = format!(
"agent-alice.url = \"git+file://{}\"", "agent-alice.url = \"git+file://{}\"",
@ -1793,7 +1813,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
) )
}; };
@ -1883,7 +1903,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
) )
}; };
unsafe { unsafe {
@ -1955,7 +1975,7 @@ mod tests {
"path:/nix/store/aaaa-nixpkgs-source", "path:/nix/store/aaaa-nixpkgs-source",
None, None,
8000, 8000,
&[sample_spec("alice", false, 9001)], &[sample_spec("alice", 9001)],
) )
}; };
unsafe { unsafe {
@ -1987,7 +2007,7 @@ mod tests {
agent_memory_max: cap.to_owned(), agent_memory_max: cap.to_owned(),
..HiveEnv::default() ..HiveEnv::default()
}; };
let agents = [sample_spec("alice", false, 9001)]; let agents = [sample_spec("alice", 9001)];
let small = render_hive_flake(&hive("4G"), &agents); let small = render_hive_flake(&hive("4G"), &agents);
let large = render_hive_flake(&hive("16G"), &agents); let large = render_hive_flake(&hive("16G"), &agents);
assert_eq!( assert_eq!(

View file

@ -1,7 +1,6 @@
# Shared scaffolding for every hyperhive harness container. # Shared scaffolding for every hyperhive harness container.
# `../templates/agent.nix` and `../templates/ruth.nix` both import # `../templates/agent.nix`, the one entry point every agent builds from,
# agents use the same service unit regardless of which entry-point # imports it.
# they came from.
# #
# This is the core module: container plumbing (boot/nix/nixpkgs), # This is the core module: container plumbing (boot/nix/nixpkgs),
# base tooling, and the cross-cutting `services.hyperhive.agent.icon` option. Each # base tooling, and the cross-cutting `services.hyperhive.agent.icon` option. Each

View file

@ -14,9 +14,8 @@
via `claude --add-dir`, so the markdown is readable at via `claude --add-dir`, so the markdown is readable at
`$HIVE_DOCS_DIR/`, and appends a single pointer sentence to the agent's `$HIVE_DOCS_DIR/`, and appends a single pointer sentence to the agent's
system prompt so it knows the docs exist (see system prompt so it knows the docs exist (see
`hive-agent::prompt::render`). Default-on for the root/manager agent `hive-agent::prompt::render`). Off by default for every agent; an agent
(see `../templates/ruth.nix`), off elsewhere; any agent can flip it from its turns it on from its `agent.nix`.
`agent.nix`.
''; '';
options.services.hyperhive.agent.docs.source = lib.mkOption { options.services.hyperhive.agent.docs.source = lib.mkOption {

View file

@ -1,6 +1,6 @@
# The hyperhive-built packages the harness modules consume, threaded # The hyperhive-built packages the harness modules consume, threaded
# in explicitly as an option — no overlay. The flake's # in explicitly as an option — no overlay. The flake's
# `nixosModules.{agent-base,ruth}` set this to the flake's own package # `nixosModules.agent-base` sets this to the flake's own package
# outputs via `lib.mkDefault`, so a per-agent override of an # outputs via `lib.mkDefault`, so a per-agent override of an
# individual key still wins. # individual key still wins.
{ lib, ... }: { lib, ... }:
@ -15,8 +15,8 @@
`hive-forge`, `hive-forge-notify`, `hive-github-notify`, `hive-forge`, `hive-forge-notify`, `hive-github-notify`,
`hive-matrix-daemon`, `hive-matrix-daemon`,
`hive-metric`, `hive-screen-mcp`) plus the `assets`, `frontend`, `hive-metric`, `hive-screen-mcp`) plus the `assets`, `frontend`,
`reference-docs` and `claude-plugins` trees. Wired by the flake's agent-base/ruth `reference-docs` and `claude-plugins` trees. Wired by the flake's agent-base
nixosModules to `hyperhive.packages.<system>.*`; override an nixosModule to `hyperhive.packages.<system>.*`; override an
individual key per-agent to swap in a patched binary. individual key per-agent to swap in a patched binary.
''; '';
}; };

View file

@ -189,7 +189,7 @@ in
# above for the rationale. # above for the rationale.
environment.etc."hyperhive/serve.json".text = serveConfigJson; environment.etc."hyperhive/serve.json".text = serveConfigJson;
# Pull the per-container toplevels into the host system closure. # Pull the agent-base toplevel into the host system closure.
# `system.extraDependencies` adds paths to the system build # `system.extraDependencies` adds paths to the system build
# without referencing them at runtime — nixos-rebuild fetches / # without referencing them at runtime — nixos-rebuild fetches /
# builds them, they end up in /nix/store, and the first # builds them, they end up in /nix/store, and the first
@ -197,7 +197,6 @@ in
# do. Gated because the closure is sizeable and pinned to x86_64. # do. Gated because the closure is sizeable and pinned to x86_64.
system.extraDependencies = lib.optionals cfg.preBuildAgentTemplates [ system.extraDependencies = lib.optionals cfg.preBuildAgentTemplates [
cfg.agentBaseToplevel cfg.agentBaseToplevel
cfg.managerToplevel
]; ];
# Unprivileged coordinator user. hive-c0re runs as this user; # Unprivileged coordinator user. hive-c0re runs as this user;

View file

@ -10,6 +10,12 @@
... ...
}: }:
{ {
imports = [
(lib.mkRemovedOptionModule [ "services" "hyperhive" "c0re" "managerToplevel" ] ''
Every agent, ruth included, builds from `agentBaseToplevel`. Remove this definition.
'')
];
options.services.hyperhive.c0re = { options.services.hyperhive.c0re = {
package = lib.mkOption { package = lib.mkOption {
type = lib.types.package; type = lib.types.package;
@ -92,14 +98,6 @@
enabled. enabled.
''; '';
}; };
managerToplevel = lib.mkOption {
type = lib.types.package;
defaultText = lib.literalExpression "hyperhive.packages.x86_64-linux.ruth-toplevel";
description = ''
Pre-built manager (ruth) container system closure — see
`agentBaseToplevel`.
'';
};
nixpkgsFlake = lib.mkOption { nixpkgsFlake = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "path:${pkgs.path}"; default = "path:${pkgs.path}";
@ -176,8 +174,8 @@
default = false; default = false;
example = true; example = true;
description = '' description = ''
Pre-fetch the per-container system closures (agent-base + Pre-fetch the agent-base container system closure, which every
manager toplevels) into the host's /nix/store as part of this agent builds from, into the host's /nix/store as part of this
host's NixOS build, instead of letting the first agent spawn host's NixOS build, instead of letting the first agent spawn
do all the work. do all the work.

View file

@ -273,7 +273,7 @@ in
# is exposed too since it's independently useful/inspectable. # is exposed too since it's independently useful/inspectable.
inherit swagger-ui-dist swagger-ui-theme; inherit swagger-ui-dist swagger-ui-theme;
# Pre-built per-container system closures. Exposed as packages # Pre-built system closure every agent container builds from. Exposed as a package
# so operators can `nix build .#agent-base-toplevel` (or wire # so operators can `nix build .#agent-base-toplevel` (or wire
# them into their host system closure via the # them into their host system closure via the
# `preBuildAgentTemplates` option on the hive-c0re module — # `preBuildAgentTemplates` option on the hive-c0re module —
@ -283,13 +283,12 @@ in
# when the meta evaluator goes to build the container. # when the meta evaluator goes to build the container.
# #
# nixosConfigurations are pinned to x86_64-linux (nixos- # nixosConfigurations are pinned to x86_64-linux (nixos-
# containers only run native arch), so these toplevels are # containers only run native arch), so this toplevel is
# only useful on an x86_64-linux host — flake check across # only useful on an x86_64-linux host — flake check across
# systems still tolerates evaluating them on aarch64 because # systems still tolerates evaluating it on aarch64 because
# they're plain derivations, but `nix build` from a non-x86 # it's a plain derivation, but `nix build` from a non-x86
# host would only succeed via a remote x86 builder. # host would only succeed via a remote x86 builder.
agent-base-toplevel = self.nixosConfigurations.agent-base.config.system.build.toplevel; agent-base-toplevel = self.nixosConfigurations.agent-base.config.system.build.toplevel;
ruth-toplevel = self.nixosConfigurations.ruth.config.system.build.toplevel;
# Auto-generated nix options reference for hyperhive. # Auto-generated nix options reference for hyperhive.
# `docs` bundles host + swarm + deploy + agent pages into one tree; # `docs` bundles host + swarm + deploy + agent pages into one tree;

View file

@ -1,14 +0,0 @@
{ lib, ... }:
{
# Entry-point for the privileged root agent (ruth). Referenced from
# `flake.nix` (`nixosConfigurations.ruth`) and the meta-flake's
# `applied/ruth/flake.nix`.
imports = [ ../agent-modules ];
# The root/manager bootstraps a fresh hive, so it gets the hyperhive
# reference docs made available by default (readable at
# `$HIVE_DOCS_DIR/`, added via `claude --add-dir`). `mkDefault` so a
# manager's own `agent.nix` can still turn it off. Other agents default
# off.
services.hyperhive.agent.docs.enable = lib.mkDefault true;
}