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

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