From c1ffa12a993cd222d391c252846ff0cff505e8da Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 10 Jul 2026 14:24:57 +0200 Subject: [PATCH 1/4] =?UTF-8?q?feat(#2280):=20packages.hivectl=20and=20pac?= =?UTF-8?q?kages.hive-forge=20=E2=80=94=20single-bin=20splits?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operators who only want hivectl or hive-forge can now add: inputs.hyperhive.packages.${system}.hivectl inputs.hyperhive.packages.${system}.hive-forge to their environment.systemPackages without pulling the full workspace (hive-c0re daemon, hive-ag3nt harness, etc.) into PATH. Both reuse the shared cargoArtifacts so there is no extra compile cost when both packages and the default workspace are built together. packages.hivectl carries the shell completions and the wireguard-tools wrapper identical to what packages.default ships for hivectl. packages.hive-forge is a lean CLI-only build. --- flake.nix | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/flake.nix b/flake.nix index a4b9e0e7..c27254ee 100644 --- a/flake.nix +++ b/flake.nix @@ -221,6 +221,49 @@ --prefix PATH : ${pkgs.wireguard-tools}/bin ''; }; + # Operator CLI only — ships `hivectl` (with shell completions + # and the `wg` wrapper) without the daemon binaries. Suitable + # for `nix profile install .#hivectl` / `environment.systemPackages + # = [ inputs.hyperhive.packages.${system}.hivectl ]` when the + # operator only wants the admin CLI on their workstation and + # does not want `hive-c0re` or `hive-ag3nt` in PATH. + # Shares `cargoArtifacts` with `packages.default` so there is no + # double-compile cost when both are in the same `nix build` + # invocation. + hivectl = craneLib.buildPackage { + src = cleanSrc; + inherit cargoArtifacts; + cargoExtraArgs = "--bin hivectl"; + pname = "hivectl"; + version = "0.1.0"; + meta.description = "hyperhive operator CLI"; + doCheck = false; + nativeBuildInputs = nativeBuildInputs ++ [ + pkgs.installShellFiles + pkgs.makeWrapper + ]; + postInstall = '' + installShellCompletion --cmd hivectl \ + --bash <("$out/bin/hivectl" completions bash) \ + --zsh <("$out/bin/hivectl" completions zsh) \ + --fish <("$out/bin/hivectl" completions fish) + wrapProgram "$out/bin/hivectl" \ + --prefix PATH : ${pkgs.wireguard-tools}/bin + ''; + }; + # Forgejo CLI only — ships `hive-forge` without the rest of + # the workspace. Useful for operator workstations / CI + # environments that only need forge access. Shares + # `cargoArtifacts` with `packages.default`. + hive-forge = craneLib.buildPackage { + src = cleanSrc; + inherit cargoArtifacts; + cargoExtraArgs = "--bin hive-forge"; + pname = "hive-forge"; + version = "0.1.0"; + meta.description = "hyperhive Forgejo CLI"; + doCheck = false; + }; # Bundled browser assets — see ./nix/frontend.nix. Output is # $out/{dashboard,agent}/ which the Rust binaries serve via # tower_http::ServeDir. From 4a9aff584ec09b4eaad0b86abf3cf65926ab6f60 Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 10 Jul 2026 20:38:26 +0200 Subject: [PATCH 2/4] =?UTF-8?q?refactor(#2280):=20packages.default=20=3D?= =?UTF-8?q?=20symlinkJoin=20=E2=80=94=20one=20rustc=20per=20bin,=20no=20do?= =?UTF-8?q?uble=20builds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each binary now has its own derivation (daemonBins for hive-c0re/hive-ag3nt/MCP servers, hivectlPkg, hiveForgePkg), all sharing cargoArtifacts for a single rustc compilation. packages.default = pkgs.symlinkJoin assembles them without any additional compilation — no rustc is invoked more than once regardless of which packages the operator builds together. NixOS module consumers (pkgs.hyperhive = packages.default) are unaffected: symlinkJoin exposes all binaries at the same /bin/ paths. --- flake.nix | 111 +++++++++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 59 deletions(-) diff --git a/flake.nix b/flake.nix index c27254ee..f8a32275 100644 --- a/flake.nix +++ b/flake.nix @@ -171,66 +171,32 @@ inherit (nixpkgs) lib; inherit (nixpkgs.lib) nixosSystem; }; - in - { - # Build the workspace binaries without running tests. Tests - # are run as a separate check (`checks.cargo-test`) that - # carries the `hyperhive-assets` build input — `hive-ag3nt:: - # prompt::tests` reads the production prompt template at test - # runtime through `$HIVE_ASSETS_DIR`, so wiring the env var - # into the build phase here would make the prompt's hash a - # build input of `default` (defeats the asset-split cache goal: a - # prompt edit would still bust the binary derivation, even - # though no .rs file changed). Keeping tests in a separate - # check derivation localises the asset-rebuild blast radius - # to that one check — `nix flake check` still exercises them. - default = craneLib.buildPackage { + # Daemon + harness + MCP server binaries. Excludes hivectl and + # hive-forge which are their own derivations below — so each bin + # is compiled exactly once. `packages.default` joins all three + # via symlinkJoin; no binary is compiled more than once regardless + # of which packages the operator builds together. + # + # Tests are kept in the separate `checks.cargo-test` derivation + # (carries the hyperhive-assets build input for the prompt-template + # assertions in hive-ag3nt::prompt::tests). Keeping them out of the + # binary derivations means a prompt edit doesn't bust the cargo cache. + daemonBins = craneLib.buildPackage { src = cleanSrc; inherit cargoArtifacts; - # `installShellFiles` provides `installShellCompletion` and - # `makeWrapper` provides `wrapProgram` for the postInstall below; - # appended (not in the shared set) so they're build inputs only of - # this binary derivation. - nativeBuildInputs = nativeBuildInputs ++ [ - pkgs.installShellFiles - pkgs.makeWrapper - ]; - pname = "hyperhive-workspace"; + cargoExtraArgs = "--bin hive-c0re --bin hive-agent --bin hive-agent-mcp --bin hive-agent-wake --bin hive-bash-daemon --bin hive-bash-mcp --bin hive-matrix-daemon --bin hive-matrix-mcp"; + pname = "hyperhive-daemon"; version = "0.1.0"; - meta.description = "hyperhive workspace (hive-c0re, hive-ag3nt, hive-root)"; + meta.description = "hyperhive daemon + agent harness + bash/matrix MCP servers"; doCheck = false; - # Ship hivectl shell completions in the package (the binary's own - # `completions ` verb is the single source of truth, so they - # never drift from the actual verbs). Lands at - # `$out/share/{zsh/site-functions,bash-completion,fish}/…`; an - # operator gets working completion as soon as hivectl is in their - # system/user profile with the shell's completion enabled. - # - # Then wrap hivectl with `wireguard-tools` on PATH so its `wg` - # subcommands (`wg init`/`peer`/`status`) work even before the - # WireGuard mesh is configured — `wg init` is the *first* setup - # step, run before `swarm.wireguard.enable` (which would otherwise - # be what pulls wireguard-tools onto the system). Completion - # generation runs first since wrapProgram renames the real binary. - postInstall = '' - installShellCompletion --cmd hivectl \ - --bash <("$out/bin/hivectl" completions bash) \ - --zsh <("$out/bin/hivectl" completions zsh) \ - --fish <("$out/bin/hivectl" completions fish) - wrapProgram "$out/bin/hivectl" \ - --prefix PATH : ${pkgs.wireguard-tools}/bin - ''; }; - # Operator CLI only — ships `hivectl` (with shell completions - # and the `wg` wrapper) without the daemon binaries. Suitable - # for `nix profile install .#hivectl` / `environment.systemPackages + # Operator CLI — ships `hivectl` (with shell completions and the + # `wg` wrapper) without the daemon binaries. Suitable for + # `nix profile install .#hivectl` / `environment.systemPackages # = [ inputs.hyperhive.packages.${system}.hivectl ]` when the - # operator only wants the admin CLI on their workstation and - # does not want `hive-c0re` or `hive-ag3nt` in PATH. - # Shares `cargoArtifacts` with `packages.default` so there is no - # double-compile cost when both are in the same `nix build` - # invocation. - hivectl = craneLib.buildPackage { + # operator only wants the admin CLI. Shares `cargoArtifacts` with + # `daemonBins` so there is no double-rustc cost. + hivectlPkg = craneLib.buildPackage { src = cleanSrc; inherit cargoArtifacts; cargoExtraArgs = "--bin hivectl"; @@ -238,10 +204,18 @@ version = "0.1.0"; meta.description = "hyperhive operator CLI"; doCheck = false; + # `installShellFiles` + `makeWrapper` scoped to this derivation + # only — daemon bins don't need them. nativeBuildInputs = nativeBuildInputs ++ [ pkgs.installShellFiles pkgs.makeWrapper ]; + # Ship shell completions (the binary's own `completions ` + # verb is the single source of truth, so they never drift from + # the actual verbs). Wrap with wireguard-tools so `hivectl wg` + # subcommands work before `swarm.wireguard.enable` is set (wg + # init is the very first setup step). Completion generation runs + # before wrapProgram since wrapProgram renames the real binary. postInstall = '' installShellCompletion --cmd hivectl \ --bash <("$out/bin/hivectl" completions bash) \ @@ -251,11 +225,11 @@ --prefix PATH : ${pkgs.wireguard-tools}/bin ''; }; - # Forgejo CLI only — ships `hive-forge` without the rest of - # the workspace. Useful for operator workstations / CI - # environments that only need forge access. Shares - # `cargoArtifacts` with `packages.default`. - hive-forge = craneLib.buildPackage { + # Forgejo CLI — ships `hive-forge` without the rest of the + # workspace. Useful for operator workstations / CI environments + # that only need forge access. Shares `cargoArtifacts` with + # `daemonBins`. + hiveForgePkg = craneLib.buildPackage { src = cleanSrc; inherit cargoArtifacts; cargoExtraArgs = "--bin hive-forge"; @@ -264,6 +238,25 @@ meta.description = "hyperhive Forgejo CLI"; doCheck = false; }; + in + { + # All workspace binaries in one derivation via symlinkJoin. + # Each binary is compiled exactly once (one rustc per bin, all + # sharing `cargoArtifacts`); symlinkJoin assembles the outputs + # without any additional compilation. The NixOS module's + # `pkgs.hyperhive` (= this) and `nix build .#` both land here. + default = pkgs.symlinkJoin { + name = "hyperhive"; + paths = [ + daemonBins + hivectlPkg + hiveForgePkg + ]; + }; + # Per-bin split packages — useful for operator workstations that + # only want the CLI(s) without the daemon binaries. + hivectl = hivectlPkg; + hive-forge = hiveForgePkg; # Bundled browser assets — see ./nix/frontend.nix. Output is # $out/{dashboard,agent}/ which the Rust binaries serve via # tower_http::ServeDir. From 2f16f0e438ee70bcc717e003682d46d1b716d074 Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 10 Jul 2026 20:52:29 +0200 Subject: [PATCH 3/4] =?UTF-8?q?fix(#2280):=20add=20nativeBuildInputs=20to?= =?UTF-8?q?=20daemonBins=20+=20hiveForgePkg=20=E2=80=94=20sqlite/pkg-confi?= =?UTF-8?q?g?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index f8a32275..7f60f0fe 100644 --- a/flake.nix +++ b/flake.nix @@ -183,7 +183,7 @@ # binary derivations means a prompt edit doesn't bust the cargo cache. daemonBins = craneLib.buildPackage { src = cleanSrc; - inherit cargoArtifacts; + inherit cargoArtifacts nativeBuildInputs; cargoExtraArgs = "--bin hive-c0re --bin hive-agent --bin hive-agent-mcp --bin hive-agent-wake --bin hive-bash-daemon --bin hive-bash-mcp --bin hive-matrix-daemon --bin hive-matrix-mcp"; pname = "hyperhive-daemon"; version = "0.1.0"; @@ -231,7 +231,7 @@ # `daemonBins`. hiveForgePkg = craneLib.buildPackage { src = cleanSrc; - inherit cargoArtifacts; + inherit cargoArtifacts nativeBuildInputs; cargoExtraArgs = "--bin hive-forge"; pname = "hive-forge"; version = "0.1.0"; From 01db1af346aa10a507bff4e49d15683bacd3c310 Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 10 Jul 2026 21:32:12 +0200 Subject: [PATCH 4/4] =?UTF-8?q?feat(#2280):=20add=20--bin=20hive-metric=20?= =?UTF-8?q?to=20daemonBins=20=E2=80=94=20hive-metric=20now=20on=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 7f60f0fe..ff5e149e 100644 --- a/flake.nix +++ b/flake.nix @@ -184,7 +184,7 @@ daemonBins = craneLib.buildPackage { src = cleanSrc; inherit cargoArtifacts nativeBuildInputs; - cargoExtraArgs = "--bin hive-c0re --bin hive-agent --bin hive-agent-mcp --bin hive-agent-wake --bin hive-bash-daemon --bin hive-bash-mcp --bin hive-matrix-daemon --bin hive-matrix-mcp"; + cargoExtraArgs = "--bin hive-c0re --bin hive-agent --bin hive-agent-mcp --bin hive-agent-wake --bin hive-bash-daemon --bin hive-bash-mcp --bin hive-matrix-daemon --bin hive-matrix-mcp --bin hive-metric"; pname = "hyperhive-daemon"; version = "0.1.0"; meta.description = "hyperhive daemon + agent harness + bash/matrix MCP servers";