Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/docs/default.nix
atlas c490c72413 docs: per-agent options page picks services.hyperhive.agent, and fails the eval if it goes empty
the page picked the top-level hyperhive attr, which stopped existing when the
agent namespace moved under services.hyperhive.agent, so it rendered no
options. the pick now uses the new root and asserts model, user.privateUsers
and nixBuilds are present. the acp preset submodule options get the
descriptions the now-rendered page requires.

Closes #6136
2026-11-06 20:58:13 +01:00

271 lines
9.4 KiB
Nix

{
pkgs,
lib,
self,
nixosSystem,
}:
# Nix options reference: `pkgs.nixosOptionsDoc` over two evaluated
# module trees, emitted as CommonMark (`host.md` + `agent.md` +
# `swarm.md` + `deploy.md`). The HTML + CSS for `/options/` is rendered
# downstream by the website repo, which owns the presentation and
# shares one stylesheet with the prose `/docs/` tree. Full pipeline +
# subtree-pick / output-tree rationale: docs/5-project/process/gotchas.md::Nix options
# reference.
#
# `swarm.md`/`deploy.md` are separate pages from `host.md`:
# `services.hyperhive.swarm.*` holds swarm-wide facts (name, domain,
# hives, ca) only, and the "does THIS host run it" toggles live in the
# flat `services.hyperhive.deploy.*` namespace (see deploy.nix's file-top
# comment), so each namespace gets its own page.
let
# Content-addressed narrow source covering only the nix/ directory.
# `builtins.unsafeDiscardStringContext` strips `self`'s store-path
# context so `builtins.path` hashes only the nix/ file content, not
# the full flake source (Rust, frontend, markdown, …). Result: the
# docs drvs only change when a .nix file changes, not on every
# commit — a remote builder can reuse its cached result for any commit
# that doesn't touch nix/. (Named no machine: which builders are
# reachable depends on the network the deployer is on.)
nixSrc = builtins.path {
path = builtins.unsafeDiscardStringContext (toString self + "/nix");
name = "hyperhive-nix-src";
};
# Stub host system: every hyperhive subsystem `mkForce false` so
# heavy build inputs (matrix container, forge, etc.) stay out of
# the eval — only option *declarations* matter for the doc walk.
# Import the host-module aggregator from the content-addressed
# nixSrc; the package options (`services.hyperhive.deploy.hive-controller.package`
# etc.) carry no in-module defaults, but with hyperhive disabled
# nothing reads them, so no stubs are needed.
hostEval = nixosSystem {
system = pkgs.stdenv.hostPlatform.system;
modules = [
"${nixSrc}/host-modules"
(
{ lib, ... }:
{
fileSystems."/" = {
device = "/dev/null";
fsType = "tmpfs";
};
boot.loader.grub.enable = false;
system.stateVersion = "25.11";
services.hyperhive.deploy.hive-controller.enable = lib.mkForce false;
services.hyperhive.deploy.matrix.enable = lib.mkForce false;
}
)
];
};
# Agent module eval from the content-addressed nixSrc. Relative
# imports inside agent.nix (the ../agent-modules dir) resolve
# correctly against the nixSrc directory tree. `hyperhive.packages`
# stays unset — every option default that references it carries a
# `defaultText`, so the doc walk never forces the packages.
agentEval = nixosSystem {
system = pkgs.stdenv.hostPlatform.system;
modules = [
"${nixSrc}/templates/agent.nix"
];
};
# Rewrite option declaration paths from nix-store absolute paths to
# forge URLs so rendered docs link back to source.
# nixSrc is a content-addressed copy of nix/; strip its store prefix
# and prepend nix/ to recover the repo-relative path.
forgeRoot = "https://forge.darkest.space/hyperhive/hyperhive/src/branch/main";
nixSrcPrefix = builtins.unsafeDiscardStringContext (toString nixSrc + "/");
transformOptions =
opt:
opt
// {
declarations = map (
decl:
let
declStr = toString decl;
relPath =
if lib.hasPrefix nixSrcPrefix declStr then
"nix/" + lib.removePrefix nixSrcPrefix declStr
else
baseNameOf declStr;
in
{
url = "${forgeRoot}/${relPath}";
name = relPath;
}
) opt.declarations;
};
# Filter to a set of top-level subtree roots — keeps the rendered docs
# focused on hyperhive's surface instead of NixOS's 10k+ default
# options. Root choice matters: see docs/5-project/process/gotchas.md::Nix options
# reference for the services.hyperhive consolidation history.
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);
hostOptionsFull = pickSubtrees hostEval.options [
[
"services"
"hyperhive"
]
];
# `swarm.*` and `deploy.*` get their own pages below — drop them from
# the host tree rather than duplicating them here too. `pickSubtrees`
# only ever picked `services.hyperhive` for `hostOptionsFull` (nothing
# else lives under `services` in this tree), so a direct replacement
# is correct here — NOT `lib.recursiveUpdate`, which merges rather
# than deletes: a key present on the left and absent on the right
# survives the "update," which would silently keep `swarm`/`deploy`
# on `host.md` instead of dropping them.
hostOptions = {
services.hyperhive = builtins.removeAttrs hostOptionsFull.services.hyperhive [
"swarm"
"deploy"
];
};
swarmOptions = pickSubtrees hostEval.options [
[
"services"
"hyperhive"
"swarm"
]
];
deployOptions = pickSubtrees hostEval.options [
[
"services"
"hyperhive"
"deploy"
]
];
# Options live under `services.hyperhive.agent`. The page must keep
# listing known options from different agent modules; an empty page
# fails the eval instead of publishing.
agentRoot = [
"services"
"hyperhive"
"agent"
];
agentRequired = [
(agentRoot ++ [ "model" ])
(
agentRoot
++ [
"user"
"privateUsers"
]
)
(agentRoot ++ [ "nixBuilds" ])
];
agentPicked = pickSubtrees agentEval.options [ agentRoot ];
agentOptions =
assert lib.assertMsg (lib.all (p: lib.hasAttrByPath p agentPicked) agentRequired)
"per-agent options page lost required options: ${
lib.concatMapStringsSep ", " (lib.concatStringsSep ".") (
lib.filter (p: !lib.hasAttrByPath p agentPicked) agentRequired
)
}";
agentPicked;
hostDoc = pkgs.nixosOptionsDoc {
options = hostOptions;
inherit transformOptions;
};
swarmDoc = pkgs.nixosOptionsDoc {
options = swarmOptions;
inherit transformOptions;
};
deployDoc = pkgs.nixosOptionsDoc {
options = deployOptions;
inherit transformOptions;
};
agentDoc = pkgs.nixosOptionsDoc {
options = agentOptions;
inherit transformOptions;
};
# CommonMark `.md` is the source of truth and the only output. HTML
# rendering + theming lives in the website repo (it owns the
# presentation + shares one stylesheet across `/options/` and
# `/docs/`); this flake just emits the option reference as markdown.
mkMarkdownPage =
name: title: doc:
pkgs.runCommand "hyperhive-${name}.md" { } ''
{
echo "# ${title}"
echo
echo "<!-- Auto-generated from the hyperhive flake."
echo " Source: nix/docs/default.nix · regenerate with"
echo " \`nix build .#${name}\` -->"
echo
cat ${doc.optionsCommonMark}
} > $out
'';
# Bundle landing page — a short markdown index pointing at the four
# reference pages.
indexMD = pkgs.writeText "hyperhive-options-index.md" ''
# hyperhive — nix options reference
Auto-generated from the hyperhive flake. Four reading paths:
- [host options](host.md) — options exposed by
`hyperhive.nixosModules.default` to operator host configurations
(`services.hyperhive.{enable,domain,c0re,gateway,tls,network}.*`).
- [swarm options](swarm.md) — swarm-wide facts, identical on every
host in the swarm (`services.hyperhive.swarm.{name,domain,hives,
ca,forge,matrix}.*`).
- [deploy options](deploy.md) — this host's own deployment
decisions, necessarily different per host
(`services.hyperhive.deploy.*` — does *this* machine run
grafana, the swarm controller, authelia, …).
- [per-agent options](agent.md) — options declared in
`nix/agent-modules/`, visible from every `agent.nix`
(`services.hyperhive.agent.model`, `services.hyperhive.agent.allowedRecipients`,
`services.hyperhive.agent.extraMcpServers`, `services.hyperhive.agent.frontend.*`,
`services.hyperhive.agent.forge.*`, `services.hyperhive.agent.matrix.*`, `services.hyperhive.agent.gui.*`).
Regenerate with `nix build .#docs` (bundle), `.#docs-host`,
`.#docs-swarm`, `.#docs-deploy`, or `.#docs-agent`. Consumed by the
website repo to render `/options/`.
'';
hostMD = mkMarkdownPage "docs-host" "hyperhive — host options" hostDoc;
swarmMD = mkMarkdownPage "docs-swarm" "hyperhive — swarm options" swarmDoc;
deployMD = mkMarkdownPage "docs-deploy" "hyperhive — deploy options" deployDoc;
agentMD = mkMarkdownPage "docs-agent" "hyperhive — per-agent options" agentDoc;
in
{
host = hostMD;
swarm = swarmMD;
deploy = deployMD;
agent = agentMD;
# Bundle of the option reference as markdown. The website renders
# these `.md` to themed HTML for `/options/`; standalone consumers
# get the CommonMark source directly.
bundle = pkgs.runCommand "hyperhive-options-docs" { } ''
mkdir -p $out
cp ${indexMD} $out/index.md
cp ${hostMD} $out/host.md
cp ${swarmMD} $out/swarm.md
cp ${deployMD} $out/deploy.md
cp ${agentMD} $out/agent.md
'';
}