Compare commits

...
Author SHA1 Message Date
atlas
983a4fa229 nix/docs: demote index sections h2 → h3 (argus #622 nit)
argus on #622 comment 7419 🟡:
> monospace h2 on index — the CSS styles `h2` with `ui-monospace`
> font (intended for option-name headings in the per-option pages).
> on the index page, "host options" / "agent options" / "Regenerate"
> headings also get monospace treatment. cosmetic; reads as
> intentional if not, easy to scope.

Index page now uses h3 for section headers, leaves h2 free for the
auto-generated option-name headings on host.html / agent.html where
the monospace styling is appropriate.

(Other argus nit — stale namespace text in indexHTML's option
listings — will be addressed when this branch rebases post-#615
merge, same as #620.)
2026-05-30 11:27:31 +02:00
atlas
0cc27fbe32 nix/docs: add HTML output for the options reference (mara/internal-requests#8)
mara on mara/internal-requests#8:
> nix/docs.nix currently only emits CommonMark via doc.optionsCommonMark;
> add HTML output alongside.

Renders host + agent option pages as standalone HTML using cmark-gfm
(stock nixpkgs, no pandoc). Each page is wrapped in a minimal
inline-CSS template — no external stylesheets, no second HTTP fetch.

New bundle layout (consumed by nginx at `hyperhive.darkest.space/options/`):

    index.html   — landing page with cross-links + regenerate snippet
    host.html    — services.hive-c0re.* / hyperhive.{domain,forge,matrix}.*
    agent.html   — hyperhive.{model,allowedRecipients,extraMcpServers,…}
    host.md      — same content, CommonMark source-of-truth
    agent.md     — same content, CommonMark source-of-truth

All asset paths inside the rendered HTML are relative (`./host.html`
etc.) per mara's spec — the bundle mounts at any URL prefix without
rebuild. Forge source links from `transformOptions` are preserved
as proper `<a href>` (verified: `forge.darkest.space/.../nix/...`).

`packages.<system>.docs` now emits HTML primarily; `docs-host` and
`docs-agent` outputs flip from .md to .html (the .md content is still
in the `docs` bundle for callers that want the source shape).

The native nixos-render-docs `options html` subcommand doesn't exist
(only `manpage` / `commonmark` / `asciidoc`). The `manual html` path
exists but needs a full manual structure for what we're treating as
two standalone pages — overkill. cmark-gfm over the existing
CommonMark output is the leanest path.

Verified:

    nix flake check --no-build
    nix build .#docs        # bundled site (5 files)
    nix build .#docs-host   # standalone HTML page
    nix build .#docs-agent  # standalone HTML page
2026-05-30 11:27:31 +02:00
atlas
3b500bba1b nix: pivot to services.hyperhive.* per mara directive (#612)
Per [mara on PR #615 comment 7349](http://localhost:3000/hyperhive/hyperhive/pulls/615#issuecomment-7349):
> follow nix conventions, services.hyperhive it is. the earlier we
> change this, the less breakage.

Renames the entire host-side option tree under `services.hyperhive.*`:

- `services.hive-c0re.*` → `services.hyperhive.c0re.*`
- `hyperhive.enable` → `services.hyperhive.enable`
- `hyperhive.domain` → `services.hyperhive.domain`
- `hyperhive.forge.*` → `services.hyperhive.forge.*`
- `hyperhive.matrix.*` → `services.hyperhive.matrix.*`

Per mara's "earlier = less breakage", the previous `services.hive-c0re.enable`
deprecation alias is dropped. Operators get a clear eval error on the
old paths pointing at the rename. Single migration moment.

Per-agent options in `nix/templates/harness-base.nix` (`hyperhive.model`,
`hyperhive.allowedRecipients`, etc.) stay at `hyperhive.*` — they're
container-level config, not services in the NixOS sense.

Verified via `nix flake check --no-build` + an end-to-end NixOS eval
exercising every renamed path.

Follow-up needed: rust source comments referencing the old NixOS
option names (`hive-c0re/src/{meta,coordinator,main,dashboard}.rs`)
should be updated in a separate pure-rust PR to keep this one
strictly nix-only.
2026-05-30 11:07:57 +02:00
atlas
32148179e6 refactor: move hive-c0re options to hyperhive namespace (#612)
- Move options.services.hive-c0re → options.hyperhive.c0re
- Add options.hyperhive.enable to auto-enable c0re + subsystems
- Add deprecation alias for services.hive-c0re.enable (backward compat)
- Update doc references in README, flake.nix, docs, harness-base.nix
- Simplifies config: 'hyperhive.enable = true' now enables everything

Existing operator configs using services.hive-c0re.enable will
continue to work but emit a deprecation warning. Aligns the option
namespace with the existing hyperhive.* family (matrix, forge, domain).

fixes #612
2026-05-30 11:07:57 +02:00
atlas
24f61f3386 nix/docs: drop dead walk helper + dedupe checks.docs eval
argus review notes on #618:

- `walk` in `pickSubtrees` was leftover from an earlier traversal
  design; `pick` does everything we need. drop it.
- `checks.docs` was re-importing `nix/docs.nix` independently of
  `packages.docs`; the comment claimed they shared eval but they
  didn't (nix's lazy eval + import caching made the *result*
  identical, not the eval). switch to `inherit (self.packages.\${system}) docs;`
  so the check is literally the package output, no second import.
2026-05-29 23:46:39 +02:00
atlas
6a64770c79 nix: add options docs outputs for host + agent surfaces (#616)
Auto-generate CommonMark references for hyperhive's two NixOS module
surfaces via `pkgs.nixosOptionsDoc`:

- `packages.<system>.docs-host` — operator-facing options exposed by
  `hyperhive.nixosModules.default` (`services.hive-c0re.*`,
  `hyperhive.domain`, `hyperhive.forge.*`, `hyperhive.matrix.*`).
- `packages.<system>.docs-agent` — per-agent options declared in
  `nix/templates/harness-base.nix` (model, allowedRecipients,
  extraMcpServers, frontend, forge, matrix, gui, …).
- `packages.<system>.docs` — both pages plus a thin `README.md`
  index, bundled for publishing.

Declaration links are rewritten to point at the forge source tree
instead of nix-store paths.

Host options come from a stubbed `nixosSystem` eval that force-disables
all hyperhive subsystems — only the *declarations* feed the doc
renderer, no heavy build inputs end up in the closure. Agent options
reuse `nixosConfigurations.agent-base.options` (already evaluated).

Also wired as `checks.<system>.docs` so CI fails fast on eval breakage.
2026-05-29 23:42:24 +02:00
8 changed files with 429 additions and 63 deletions

View file

@ -61,8 +61,8 @@ Minimal `flake.nix` for a host that runs hive-c0re:
modules = [
hyperhive.nixosModules.default # hive-c0re + hive-forge in one import
({ ... }: {
services.hive-c0re.enable = true;
# services.hive-c0re.operatorPronouns = "they/them"; # default: "she/her"
services.hyperhive.enable = true;
# services.hyperhive.c0re.operatorPronouns = "they/them"; # default: "she/her"
# ... rest of your host config
system.stateVersion = "25.11";
@ -78,7 +78,7 @@ manager container, and auto-rebuilds any container whose hyperhive
rev goes stale. `claude-code` is unfree — hyperhive scopes the
whitelist to itself, nothing for the operator to set.
Optional: set `services.hive-c0re.preBuildAgentTemplates = true;`
Optional: set `services.hyperhive.c0re.preBuildAgentTemplates = true;`
to pre-fetch the per-container system closures into your host's
/nix/store as part of `nixos-rebuild`. First-agent-spawn then
completes in seconds instead of minutes (no nixpkgs/claude-code
@ -88,19 +88,20 @@ system closure. Off by default (the toplevels are pinned to
Alternatively warm the store manually:
`nix build git+https://forge.darkest.space/hyperhive/hyperhive#agent-base-toplevel`.
Optional: set `hyperhive.domain = "example.com";` to define the
Optional: set `services.hyperhive.domain = "example.com";` to define the
canonical hostname for hyperhive subsystems that need a stable public
name. No default — subsystems that require it (currently:
`hyperhive.matrix`) assert non-null at eval time with a clear error
message if it is missing.
`services.hyperhive.matrix`) assert non-null at eval time with a clear
error message if it is missing.
Optional: set `hyperhive.matrix.enable = true;` to spin up a private
[matrix-tuwunel](https://github.com/matrix-construct/tuwunel) homeserver
in a nixos-container. Requires either `hyperhive.domain` or
`hyperhive.matrix.serverName` to be set (eval fails with a clear error
if both are absent). The `server_name` (embedded irrevocably in every
user and room ID) defaults to `matrix.<domain>`; override with
`hyperhive.matrix.serverName = "chat.example.com";` if needed. State
Optional: set `services.hyperhive.matrix.enable = true;` to spin up a
private [matrix-tuwunel](https://github.com/matrix-construct/tuwunel)
homeserver in a nixos-container. Requires either
`services.hyperhive.domain` or `services.hyperhive.matrix.serverName`
to be set (eval fails with a clear error if both are absent). The
`server_name` (embedded irrevocably in every user and room ID)
defaults to `matrix.<domain>`; override with
`services.hyperhive.matrix.serverName = "chat.example.com";` if needed. State
lives at `/var/lib/nixos-containers/hive-matrix/`. Federation is
enabled with an empty `trusted_servers` list; e2ee is deferred to
a follow-up (#551).

View file

@ -76,7 +76,7 @@ match wins):
1. `HIVE_CONTEXT_WINDOW_TOKENS_<KEY>` env var, where `KEY`
(lowercased) is a substring of the active model name. Injected
by the meta flake from `services.hive-c0re.contextWindowTokens`
by the meta flake from `services.hyperhive.c0re.contextWindowTokens`
(host-level NixOS option, defaults: haiku=200k, sonnet=1M,
opus=1M). Override these for all agents at once without a
per-agent config change.
@ -178,7 +178,7 @@ socket at `/run/hive/` once at startup:
#519); everything else is shared. Then `{label}` and
`{operator_pronouns}` get substituted in the assembled output.
Pronouns come from `HIVE_OPERATOR_PRONOUNS` env (set by the meta
flake from `services.hive-c0re.operatorPronouns`, default
flake from `services.hyperhive.c0re.operatorPronouns`, default
`she/her`). Passed via `--system-prompt-file`.
The shared per-turn plumbing lives in `hive_ag3nt::turn::{write_mcp_config,

View file

@ -115,6 +115,13 @@
nativeBuildInputs,
...
}:
let
docsAttrs = import ./nix/docs.nix {
inherit pkgs self;
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
@ -167,6 +174,15 @@
# host would only succeed via a remote x86 builder.
agent-base-toplevel = self.nixosConfigurations.agent-base.config.system.build.toplevel;
manager-toplevel = self.nixosConfigurations.manager.config.system.build.toplevel;
# Auto-generated nix options reference for hyperhive (#616).
# `docs` bundles host + agent pages into one tree; the split
# outputs are useful when consumers only want one surface.
# All three are pure markdown — no rust or frontend deps in
# the closure, so `nix build .#docs` is cheap.
docs = docsAttrs.bundle;
docs-host = docsAttrs.host;
docs-agent = docsAttrs.agent;
}
);
@ -209,7 +225,7 @@
agent-base = ./nix/templates/agent-base.nix;
manager = ./nix/templates/manager.nix;
# The hive-c0re module wants `pkgs.hyperhive` for its default
# `services.hive-c0re.package`. To avoid making operators apply an
# `services.hyperhive.c0re.package`. To avoid making operators apply an
# overlay (which would also pollute their host pkgs with our
# build), we thread the package straight from this flake's
# `packages.<system>.default` via a `hyperhivePackage` argument.
@ -221,7 +237,7 @@
hyperhiveAssets = system: self.packages.${system}.assets;
hyperhiveFlake = "${self}";
# Per-container toplevels — wired into `system.extraDependencies`
# when `services.hive-c0re.preBuildAgentTemplates` is on so the
# when `services.hyperhive.c0re.preBuildAgentTemplates` is on so the
# host system closure pre-fetches the heavy build inputs (#97).
# Defined only for x86_64-linux because nixosConfigurations are
# hardcoded to that system; the option's default keeps the
@ -236,7 +252,7 @@
# in hive-forge). Intended usage:
#
# imports = [ hyperhive.nixosModules.default ];
# services.hive-c0re.enable = true;
# services.hyperhive.enable = true;
#
default = self.nixosModules.hive-c0re;
};
@ -328,6 +344,13 @@
cargoTestExtraArgs = "--workspace";
HIVE_ASSETS_DIR = "${self.packages.${system}.assets}/share/hyperhive";
};
# Nix options docs evaluation (#616). Cheap: pulls in
# `nixosOptionsDoc` + the host module's stub eval, no rust or
# frontend deps. CI fails fast if a module change breaks
# option declarations or the doc rendering. Reuses the
# `packages.<system>.docs` derivation so the per-system eval
# of `nix/docs.nix` happens once.
inherit (self.packages.${system}) docs;
}
);
};

329
nix/docs.nix Normal file
View file

@ -0,0 +1,329 @@
{
pkgs,
lib,
self,
nixosSystem,
}:
# Options documentation for hyperhive's NixOS module surfaces.
# Closes #616. HTML output added per mara on internal-requests #8.
#
# Three rendering layers:
# CommonMark — `pkgs.nixosOptionsDoc.optionsCommonMark`. Source of
# truth; kept as `.md` files in the bundle.
# HTML — `pkgs.cmark-gfm` over the CommonMark output, wrapped
# in a minimal inline-CSS template. Primary surface; the
# bundle's `index.html` / `host.html` / `agent.html` are
# what the operator's nginx serves from
# `hyperhive.darkest.space/options/`.
#
# Three output trees consumed by `flake.nix`:
# docs-host — operator-facing host-module options
# (`services.hive-c0re.*`, `hyperhive.{domain,forge,matrix}.*`)
# docs-agent — per-agent harness options
# (`hyperhive.{model,allowedRecipients,extraMcpServers,…}`)
# docs — bundled static site (index + host + agent, .html + .md)
#
# All asset paths inside the rendered HTML are relative (e.g.
# `./host.html`) so the bundle can be mounted at any URL prefix
# without rewriting; styles are inline so there's no second-fetch
# request for the operator's browser.
let
# Evaluate the host module under a stub NixOS system. Stubs satisfy
# the few hard-required options (filesystems, stateVersion) without
# actually enabling the hive — we only want the option *declarations*
# to evaluate, not the config.
hostEval = nixosSystem {
system = pkgs.stdenv.hostPlatform.system;
modules = [
self.nixosModules.default
(
{ lib, ... }:
{
nixpkgs.overlays = [ self.overlays.default ];
fileSystems."/" = {
device = "/dev/null";
fsType = "tmpfs";
};
boot.loader.grub.enable = false;
system.stateVersion = "25.11";
# Force-disable every hyperhive subsystem so config evaluation
# doesn't pull in heavy build inputs (matrix container, forge,
# etc.). Options are still fully declared either way — that's
# what nixosOptionsDoc traverses.
services.hive-c0re.enable = lib.mkForce false;
hyperhive.forge.enable = lib.mkForce false;
hyperhive.matrix.enable = lib.mkForce false;
}
)
];
};
# Agent options live in the already-evaluated `agent-base` container
# config. Reusing it avoids re-evaluating the harness module against
# a fresh stub — the options tree is identical to what a real agent
# container sees.
agentEval = self.nixosConfigurations.agent-base;
# Strip the nix-store prefix from option declaration paths and rewrite
# them as forge URLs so the rendered docs link back to the source.
forgeRoot = "https://forge.darkest.space/hyperhive/hyperhive/src/branch/main";
storePrefix = toString self + "/";
transformOptions =
opt:
opt
// {
declarations = map (
decl:
let
declStr = toString decl;
relPath =
if lib.hasPrefix storePrefix declStr then
lib.removePrefix storePrefix declStr
else
baseNameOf declStr;
in
{
url = "${forgeRoot}/${relPath}";
name = relPath;
}
) opt.declarations;
};
# Filter an evaluated `options` tree down to a set of top-level
# subtrees we care about. Anything outside the listed roots is
# dropped — keeps the rendered docs focused on hyperhive's surface
# instead of NixOS's 10k+ default options.
pickSubtrees =
options: roots:
let
pick =
path:
if lib.hasAttrByPath path options then
lib.setAttrByPath path (lib.getAttrFromPath path options)
else
{ };
in
lib.foldl' lib.recursiveUpdate { } (map pick roots);
hostOptions = pickSubtrees hostEval.options [
[ "hyperhive" ]
[
"services"
"hive-c0re"
]
];
agentOptions = pickSubtrees agentEval.options [
[ "hyperhive" ]
];
hostDoc = pkgs.nixosOptionsDoc {
options = hostOptions;
inherit transformOptions;
};
agentDoc = pkgs.nixosOptionsDoc {
options = agentOptions;
inherit transformOptions;
};
# Plain-markdown page (with a short header). Source of truth; the
# HTML version is rendered from this.
mkMarkdownPage =
name: title: doc:
pkgs.runCommand "hyperhive-${name}.md" { } ''
{
echo "# ${title}"
echo
echo "<!-- Auto-generated from the hyperhive flake."
echo " Source: nix/docs.nix · regenerate with"
echo " \`nix build .#${name}\` -->"
echo
cat ${doc.optionsCommonMark}
} > $out
'';
# Single self-contained stylesheet. Inlined into every page so the
# bundle doesn't depend on a second HTTP fetch — keeps the
# `/options/` mount trivial for nginx (no MIME guessing for separate
# .css files, no cache-busting needed when this updates).
styleCSS = ''
:root {
color-scheme: light dark;
--fg: #1a1a1a;
--bg: #fafafa;
--muted: #6b6b6b;
--accent: #5e548e;
--code-bg: rgba(94, 84, 142, 0.08);
--rule: rgba(94, 84, 142, 0.2);
}
@media (prefers-color-scheme: dark) {
:root {
--fg: #e6e6e6;
--bg: #0d0d0d;
--muted: #9b9b9b;
--accent: #c4a7e7;
--code-bg: rgba(196, 167, 231, 0.08);
--rule: rgba(196, 167, 231, 0.2);
}
}
* { box-sizing: border-box; }
body {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
max-width: 56rem;
margin: 0 auto;
padding: 2rem 1.25rem 4rem;
color: var(--fg);
background: var(--bg);
line-height: 1.55;
}
nav {
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--rule);
font-size: 0.9rem;
color: var(--muted);
}
nav a { color: var(--accent); text-decoration: none; }
nav a:hover { text-decoration: underline; }
nav a + a { margin-left: 0.5rem; }
nav a + a::before { content: "· "; color: var(--muted); margin-right: 0.25rem; }
h1, h2, h3 { color: var(--accent); line-height: 1.25; }
h1 { font-size: 1.75rem; margin-top: 0; }
h2 {
font-size: 1.15rem;
margin-top: 2.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--rule);
font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
}
h3 { font-size: 1rem; }
p { margin: 0.75rem 0; }
code {
background: var(--code-bg);
padding: 0.1em 0.35em;
border-radius: 0.25em;
font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
font-size: 0.9em;
}
pre {
background: var(--code-bg);
padding: 0.85rem 1rem;
border-left: 2px solid var(--accent);
border-radius: 0 0.25rem 0.25rem 0;
overflow-x: auto;
line-height: 1.4;
}
pre code { background: transparent; padding: 0; }
a { color: var(--accent); }
em { color: var(--muted); font-style: normal; font-size: 0.9em; }
footer {
margin-top: 4rem;
padding-top: 1rem;
border-top: 1px solid var(--rule);
font-size: 0.85rem;
color: var(--muted);
}
'';
# HTML page: CommonMark → cmark-gfm → minimal template with inline
# CSS + relative-only links. cmark-gfm rather than plain cmark so
# any future tables / autolinks Just Work without revisiting.
mkHtmlPage =
name: title: doc:
pkgs.runCommand "hyperhive-${name}.html" { nativeBuildInputs = [ pkgs.cmark-gfm ]; } ''
{
echo '<!doctype html>'
echo '<html lang="en">'
echo '<head>'
echo '<meta charset="utf-8">'
echo '<meta name="viewport" content="width=device-width, initial-scale=1">'
echo '<title>${title}</title>'
echo '<style>'
cat ${pkgs.writeText "hyperhive-docs-style.css" styleCSS}
echo '</style>'
echo '</head>'
echo '<body>'
echo '<nav>'
echo '<a href="./index.html">index</a>'
echo '<a href="./host.html">host options</a>'
echo '<a href="./agent.html">agent options</a>'
echo '</nav>'
echo '<main>'
echo '<h1>${title}</h1>'
echo '<p><em>Auto-generated from the hyperhive flake. Source: <a href="${forgeRoot}/nix/docs.nix">nix/docs.nix</a>.</em></p>'
cmark-gfm ${doc.optionsCommonMark}
echo '</main>'
echo '<footer>'
echo '<p>hyperhive · <a href="${forgeRoot}">source</a></p>'
echo '</footer>'
echo '</body>'
echo '</html>'
} > $out
'';
# Landing page — same template shape as the option pages but
# hand-authored content (short intro + cross-links). Kept tight; the
# detail lives on the two option pages.
indexHTML = pkgs.runCommand "hyperhive-docs-index.html" { } ''
{
echo '<!doctype html>'
echo '<html lang="en">'
echo '<head>'
echo '<meta charset="utf-8">'
echo '<meta name="viewport" content="width=device-width, initial-scale=1">'
echo '<title>hyperhive nix options reference</title>'
echo '<style>'
cat ${pkgs.writeText "hyperhive-docs-style.css" styleCSS}
echo '</style>'
echo '</head>'
echo '<body>'
echo '<nav>'
echo '<a href="./index.html">index</a>'
echo '<a href="./host.html">host options</a>'
echo '<a href="./agent.html">agent options</a>'
echo '</nav>'
echo '<main>'
echo '<h1>hyperhive nix options reference</h1>'
echo '<p>Auto-generated from the <a href="${forgeRoot}">hyperhive flake</a>. Two reading paths:</p>'
echo '<h3><a href="./host.html">host options</a></h3>'
echo '<p>Options exposed by <code>hyperhive.nixosModules.default</code> to operator host configurations: <code>services.hive-c0re.*</code>, <code>hyperhive.domain</code>, <code>hyperhive.forge.*</code>, <code>hyperhive.matrix.*</code>.</p>'
echo '<h3><a href="./agent.html">agent options</a></h3>'
echo '<p>Per-agent options declared in <code>nix/templates/harness-base.nix</code> and visible from every <code>agent.nix</code>: <code>hyperhive.model</code>, <code>hyperhive.allowedRecipients</code>, <code>hyperhive.extraMcpServers</code>, <code>hyperhive.frontend.*</code>, <code>hyperhive.forge.*</code>, <code>hyperhive.matrix.*</code>, <code>hyperhive.gui.*</code>.</p>'
echo '<h3>Regenerate</h3>'
echo '<pre><code>nix build .#docs # bundled static site (index + host + agent)'
echo 'nix build .#docs-host # host page only (HTML)'
echo 'nix build .#docs-agent # agent page only (HTML)</code></pre>'
echo '<p>The bundle also ships <code>.md</code> versions of each page (<code>host.md</code>, <code>agent.md</code>) same content, source-of-truth shape alongside the HTML.</p>'
echo '</main>'
echo '<footer>'
echo '<p>hyperhive · <a href="${forgeRoot}">source</a></p>'
echo '</footer>'
echo '</body>'
echo '</html>'
} > $out
'';
hostHTML = mkHtmlPage "docs-host" "hyperhive host options" hostDoc;
agentHTML = mkHtmlPage "docs-agent" "hyperhive per-agent options" agentDoc;
hostMD = mkMarkdownPage "docs-host" "hyperhive host options" hostDoc;
agentMD = mkMarkdownPage "docs-agent" "hyperhive per-agent options" agentDoc;
in
{
# Individual page outputs (HTML is the primary surface; the .md
# source is one `nix build` step away if needed).
host = hostHTML;
agent = agentHTML;
# Bundled static site for nginx to serve at `/options/`. Asset paths
# are all relative, no root-absolute references, so the prefix can
# change without rebuild.
bundle = pkgs.runCommand "hyperhive-options-docs" { } ''
mkdir -p $out
cp ${indexHTML} $out/index.html
cp ${hostHTML} $out/host.html
cp ${agentHTML} $out/agent.html
cp ${hostMD} $out/host.md
cp ${agentMD} $out/agent.md
'';
}

View file

@ -13,41 +13,51 @@
...
}:
let
cfg = config.services.hive-c0re;
cfg = config.services.hyperhive.c0re;
in
{
# The forge is part of the standard install — hive-c0re mirrors
# every agent's applied config repo into it. On by default; opt out
# with `hyperhive.forge.enable = false`. hive-matrix is opt-in (off
# by default) and asserts that `hyperhive.domain` is set before it
# can be enabled.
# with `services.hyperhive.forge.enable = false`. hive-matrix is
# opt-in (off by default) and asserts that `services.hyperhive.domain`
# is set before it can be enabled.
imports = [
./hive-forge.nix
./hive-matrix.nix
];
# Top-level hyperhive enable flag. When true, automatically enables
# hive-c0re and the on-by-default hyperhive subsystems.
options.services.hyperhive.enable = lib.mkEnableOption "hyperhive the agent swarm coordinator";
# Top-level option shared by any hyperhive subsystem that needs a
# stable hostname (matrix server_name today, forge ROOT_URL likely
# next). Type is nullable + default null so existing operator
# configs that don't set it still evaluate; subsystems that
# actually need it (matrix) assert non-null in their own config
# block with a helpful message.
options.hyperhive.domain = lib.mkOption {
options.services.hyperhive.domain = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "darkest.space";
description = ''
Canonical host domain for hyperhive subsystems that need a
stable name (currently: `hyperhive.matrix.serverName` derives
from this, defaulting to `matrix.''${hyperhive.domain}` when
`serverName` is null). No default subsystems that opt to
require it assert non-null in their own config and fail eval
with a helpful message if it's missing.
stable name (currently: `services.hyperhive.matrix.serverName`
derives from this, defaulting to
`matrix.''${services.hyperhive.domain}` when `serverName` is
null). No default subsystems that opt to require it assert
non-null in their own config and fail eval with a helpful
message if it's missing.
'';
};
options.services.hive-c0re = {
enable = lib.mkEnableOption "hive-c0re hyperhive coordinator daemon";
options.services.hyperhive.c0re = {
enable = lib.mkOption {
type = lib.types.bool;
default = config.services.hyperhive.enable;
defaultText = lib.literalExpression "config.services.hyperhive.enable";
description = "Enable hive-c0re coordinator daemon (auto-enabled by services.hyperhive.enable).";
};
package = lib.mkOption {
type = lib.types.package;
default = hyperhivePackage pkgs.stdenv.hostPlatform.system;
@ -216,17 +226,17 @@ in
# `forge.rs` reads the avatar PNGs from here on startup.
HIVE_ASSETS_DIR = "${cfg.assets}/share/hyperhive";
}
// lib.optionalAttrs config.hyperhive.forge.enable {
// lib.optionalAttrs config.services.hyperhive.forge.enable {
# Agents poll this URL for Forgejo notifications. Derived from
# hyperhive.forge.{domain,httpPort} so it tracks forge config changes.
HIVE_FORGE_URL = "http://${config.hyperhive.forge.domain}:${toString config.hyperhive.forge.httpPort}";
# services.hyperhive.forge.{domain,httpPort} so it tracks forge config changes.
HIVE_FORGE_URL = "http://${config.services.hyperhive.forge.domain}:${toString config.services.hyperhive.forge.httpPort}";
}
// lib.optionalAttrs config.hyperhive.matrix.gui.enable {
// lib.optionalAttrs config.services.hyperhive.matrix.gui.enable {
# Optional matrix-GUI static dist mounted at /matrix/ by the
# dashboard router (#607 v0). Pre-#15 / pre-nginx-front: this is
# the simplest same-origin shape — fluffychat-web ships as a
# static dist, no runtime daemon needed.
HIVE_MATRIX_GUI_DIR = "${config.hyperhive.matrix.gui.package}";
HIVE_MATRIX_GUI_DIR = "${config.services.hyperhive.matrix.gui.package}";
};
serviceConfig = {
ExecStart = "${cfg.package}/bin/hive-c0re --socket /run/hyperhive/host.sock serve --hyperhive-flake ${cfg.hyperhiveFlake} --dashboard-port ${toString cfg.dashboardPort} --operator-pronouns ${lib.escapeShellArg cfg.operatorPronouns} --context-window-tokens ${lib.escapeShellArg (builtins.toJSON cfg.contextWindowTokens)}";

View file

@ -5,7 +5,7 @@
...
}:
let
cfg = config.hyperhive.forge;
cfg = config.services.hyperhive.forge;
in
{
# Private Forgejo for hyperhive agents, wrapped in a nixos-container
@ -24,7 +24,7 @@ in
# and survives container restart / host reboot. To wipe, destroy the
# container.
options.hyperhive.forge = {
options.services.hyperhive.forge = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
@ -33,7 +33,7 @@ in
hyperhive agents. On by default: hive-c0re mirrors every
agent's applied config repo into the forge's `agent-configs`
org, so the forge is part of the standard install. Set
`hyperhive.forge.enable = false` to opt out.
`services.hyperhive.forge.enable = false` to opt out.
'';
};
@ -220,19 +220,22 @@ in
Group = "forgejo";
};
environment.GNUPGHOME = "/var/lib/forgejo/.gnupg";
path = [ pkgs.gnupg pkgs.coreutils ];
path = [
pkgs.gnupg
pkgs.coreutils
];
script = ''
mkdir -p "$GNUPGHOME"
chmod 700 "$GNUPGHOME"
gpg --batch --gen-key <<'EOF'
%no-protection
Key-Type: RSA
Key-Length: 4096
Name-Real: HyperHive Forge
Name-Email: forgejo@hive
Expire-Date: 0
EOF
touch "$GNUPGHOME/hive-key-init.stamp"
mkdir -p "$GNUPGHOME"
chmod 700 "$GNUPGHOME"
gpg --batch --gen-key <<'EOF'
%no-protection
Key-Type: RSA
Key-Length: 4096
Name-Real: HyperHive Forge
Name-Email: forgejo@hive
Expire-Date: 0
EOF
touch "$GNUPGHOME/hive-key-init.stamp"
'';
};
};

View file

@ -5,8 +5,8 @@
...
}:
let
cfg = config.hyperhive.matrix;
hyperhiveDomain = config.hyperhive.domain;
cfg = config.services.hyperhive.matrix;
hyperhiveDomain = config.services.hyperhive.domain;
effectiveServerName =
if cfg.serverName != null then cfg.serverName else "matrix.${hyperhiveDomain}";
in
@ -45,7 +45,7 @@ in
# so the agent's matrix MCP client can authenticate without ever
# seeing the shared registration token.
options.hyperhive.matrix = {
options.services.hyperhive.matrix = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
@ -53,7 +53,7 @@ in
Run hive-matrix a private matrix-tuwunel homeserver (in a
nixos-container) for hyperhive agents. Off by default while
the integration phases in; flip to `true` once the operator
has set `hyperhive.domain` and is ready to onboard agents.
has set `services.hyperhive.domain` and is ready to onboard agents.
'';
};
@ -77,7 +77,7 @@ in
(`@argus:<server_name>`) and room ID minted on this
homeserver. CRITICAL: must be stable from day one because
it's embedded irrevocably in the identifiers. Defaults to
`matrix.''${hyperhive.domain}` (always a subdomain keeps
`matrix.''${services.hyperhive.domain}` (always a subdomain keeps
the root domain free for the dashboard or forge). Override
here only if you need a name that doesn't follow the
`matrix.<domain>` shape.
@ -169,7 +169,7 @@ in
without standing up a separate gateway.
Same-origin via hive-c0re is the simplest single-host
shape; the post-#15 nginx-front re-root (`https://matrix.''${hyperhive.domain}`)
shape; the post-#15 nginx-front re-root (`https://matrix.''${services.hyperhive.domain}`)
is tracked separately in #609. fluffychat-web supports
per-login server pick point it at the in-host tuwunel URL
(`http://localhost:8008` by default) the first time.
@ -196,17 +196,17 @@ in
# mara on #548: "there is no default, but it is required. add
# assertion." — fail eval with a helpful message rather than
# spawning a homeserver with a bogus server_name we can never
# change later. `hyperhive.domain` is host-wide; matrix derives
# change later. `services.hyperhive.domain` is host-wide; matrix derives
# the server_name from it (or from `cfg.serverName` if the
# operator wants to override).
assertions = [
{
assertion = hyperhiveDomain != null || cfg.serverName != null;
message = ''
hyperhive.matrix.enable = true requires either:
- hyperhive.domain set to your host's canonical domain
services.hyperhive.matrix.enable = true requires either:
- services.hyperhive.domain set to your host's canonical domain
(recommended; shared with forge / dashboard), or
- hyperhive.matrix.serverName set explicitly.
- services.hyperhive.matrix.serverName set explicitly.
The matrix server_name is embedded into every user ID and
room ID on this homeserver it cannot be changed later

View file

@ -36,7 +36,7 @@
`"haiku"`, `"sonnet"`, `"opus"` (or any future identifier). Context
window sizes are looked up at runtime from the
`HIVE_CONTEXT_WINDOW_TOKENS_<KEY_UPPER>` env vars injected by the
meta flake; override sizes via `services.hive-c0re.contextWindowTokens`
meta flake; override sizes via `services.hyperhive.c0re.contextWindowTokens`
on the host.
'';
};
@ -595,7 +595,7 @@
# both the harness binary and any user-shell `cargo run` inside the
# container resolve them from the same path.
# HIVE_CONTEXT_WINDOW_TOKENS_* are injected by the meta flake from the
# host-level `services.hive-c0re.contextWindowTokens` option — not set here.
# host-level `services.hyperhive.c0re.contextWindowTokens` option — not set here.
environment.variables = {
HIVE_DEFAULT_MODEL = config.hyperhive.model;
HIVE_ASSETS_DIR = "${pkgs.hyperhive-assets}/share/hyperhive";