{ 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.hyperhive.enable = lib.mkForce false; services.hyperhive.forge.enable = lib.mkForce false; services.hyperhive.matrix.enable = lib.mkForce false; services.hyperhive.gateway.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); # Post-#615, host options live entirely under `services.hyperhive.*` # (closes #630). Pre-#615 had a mix of `hyperhive.*` (forge, matrix, # domain) and `services.hive-c0re.*` — picking against those roots # silently produced an empty options tree on current main, so the # rendered host page was just the template chrome with no `

` # option headers underneath. hostOptions = pickSubtrees hostEval.options [ [ "services" "hyperhive" ] ]; 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 "" echo cat ${doc.optionsCommonMark} } > $out ''; # Inline-stylesheet, loaded as plain text from `./style.css` so it's # editable with normal CSS tooling (#625). 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 = builtins.readFile ./style.css; # 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 '' echo '' echo '' echo '' echo '' echo '${title}' echo '' echo '' echo '' echo '' echo '
' echo '

${title}

' echo '

Auto-generated from the hyperhive flake. Source: nix/docs/default.nix.

' cmark-gfm ${doc.optionsCommonMark} echo '
' echo '' echo '' echo '' } > $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 '' echo '' echo '' echo '' echo '' echo 'hyperhive — nix options reference' echo '' echo '' echo '' echo '' echo '
' echo '

hyperhive — nix options reference

' echo '

Auto-generated from the hyperhive flake. Two reading paths:

' echo '

host options

' echo '

Options exposed by hyperhive.nixosModules.default to operator host configurations: services.hyperhive.{enable,domain,c0re,forge,matrix,gateway}.*.

' echo '

agent options

' echo '

Per-agent options declared in nix/templates/harness-base.nix and visible from every agent.nix: hyperhive.model, hyperhive.allowedRecipients, hyperhive.extraMcpServers, hyperhive.frontend.*, hyperhive.forge.*, hyperhive.matrix.*, hyperhive.gui.*.

' echo '

Regenerate

' echo '
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)
' echo '

The bundle also ships .md versions of each page (host.md, agent.md) — same content, source-of-truth shape — alongside the HTML.

' echo '
' echo '' echo '' echo '' } > $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 ''; }