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
271 lines
9.4 KiB
Nix
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
|
|
'';
|
|
}
|