docs(options): emit markdown only, render HTML in website

Per #1407 review: the options reference should be markdown here; the
HTML + CSS belongs in the website repo where the theme lives and the
stylesheet can be shared with /docs.

- nix/docs/default.nix: drop the cmark-gfm HTML rendering, the inline
  <style>, and the HTML index. Emit index.md + host.md + agent.md only
  (CommonMark from nixosOptionsDoc).
- Remove nix/docs/style.css.
- Update docs/gotchas.md + CLAUDE.md to describe the md-only output and
  point at the website for HTML rendering.

The website (hyperhive/website#26) renders these .md to themed HTML for
/options/, sharing one docs.css with the prose /docs/ tree.
This commit is contained in:
iris 2026-06-05 19:29:07 +02:00 committed by mara
commit 60042d877e
4 changed files with 48 additions and 186 deletions

View file

@ -348,10 +348,10 @@ nix/
— weston + VNC backend systemd unit; writes — weston + VNC backend systemd unit; writes
/etc/hyperhive/gui.json (vnc_port + auth) for /etc/hyperhive/gui.json (vnc_port + auth) for
the harness WebSocket relay (/screen/ws) the harness WebSocket relay (/screen/ws)
docs/ HTML+MD options reference (host + agent); built docs/ markdown options reference (host + agent);
default.nix via `nix build .#docs` → static site default.nix `nix build .#docs``index.md` + `host.md`
style.css (`index.html`, `host.html`, `agent.html`, + `agent.md` (CommonMark from nixosOptionsDoc).
`host.md`, `agent.md`); rendered by cmark-gfm HTML+CSS rendered downstream by the website repo
forge-theme/theme-catppuccin-vibec0re.css Catppuccin Mocha forge theme forge-theme/theme-catppuccin-vibec0re.css Catppuccin Mocha forge theme
docs/ docs/

View file

@ -286,29 +286,24 @@ inputs stay out of the eval) and `agentEval` (reuses the already-evaluated
`agent-base` container config so the per-agent options tree is `agent-base` container config so the per-agent options tree is
identical to what a real agent container sees). identical to what a real agent container sees).
Three output trees consumed by `flake.nix`: Three output trees consumed by `flake.nix`, all **markdown**:
- `docs-host` — operator-facing host module options - `docs-host` — operator-facing host module options
(`services.hyperhive.*`) (`services.hyperhive.*`)
- `docs-agent` — per-agent harness options (`hyperhive.*` - `docs-agent` — per-agent harness options (`hyperhive.*`
declared in `nix/templates/harness-base.nix`) declared in `nix/templates/harness-base.nix`)
- `docs` — bundled static site (`index.html` + `host.html` + - `docs` — bundle of `index.md` + `host.md` + `agent.md`
`agent.html`, plus `.md` source-of-truth versions of each
options page)
Rendering pipeline: Pipeline:
- CommonMark from `nixosOptionsDoc.optionsCommonMark` — source of - CommonMark from `nixosOptionsDoc.optionsCommonMark` is the only
truth, kept as `.md` in the bundle. output — the source of truth, emitted as `.md`.
- HTML via `pkgs.cmark-gfm` over the CommonMark, wrapped in a - **HTML + CSS is rendered downstream by the website repo**
minimal inline-CSS template. `cmark-gfm` (not plain `cmark`) so (`nix/options.nix` there), which consumes this bundle's `host.md` /
any future tables / autolinks Just Work without revisiting. `agent.md`, renders them with `cmark-gfm`, and shares one
- Inline `<style>` from `nix/docs/style.css` so the bundle is stylesheet (`docs.css`) across `/options/` and the prose `/docs/`
single-file-per-page and nginx's `/options/` mount needs no MIME tree. Keeping rendering in the website means the theme has a single
setup for separate `.css` files and no cache-busting. home and the colours are shared.
- Asset paths inside rendered HTML are all relative
(`./host.html`, etc.) so the bundle can mount at any URL prefix
without rewriting.
- `transformOptions` strips the nix-store prefix from option - `transformOptions` strips the nix-store prefix from option
declaration paths and rewrites them as forge URLs, so the declaration paths and rewrites them as forge URLs, so the
rendered docs link back to the source. rendered docs link back to the source.

View file

@ -5,10 +5,11 @@
nixosSystem, nixosSystem,
}: }:
# Nix options reference: `pkgs.nixosOptionsDoc` over two evaluated # Nix options reference: `pkgs.nixosOptionsDoc` over two evaluated
# module trees, rendered as CommonMark + HTML + bundled static site # module trees, emitted as CommonMark (`host.md` + `agent.md`). The
# the operator's nginx serves from `/options/`. Full pipeline + # HTML + CSS for `/options/` is rendered downstream by the website
# subtree-pick / output-tree rationale: docs/gotchas.md::Nix options # repo, which owns the presentation and shares one stylesheet with the
# reference. # prose `/docs/` tree. Full pipeline + subtree-pick / output-tree
# rationale: docs/gotchas.md::Nix options reference.
let let
# Stub host system: every hyperhive subsystem `mkForce false` so # Stub host system: every hyperhive subsystem `mkForce false` so
# heavy build inputs (matrix container, forge, etc.) stay out of # heavy build inputs (matrix container, forge, etc.) stay out of
@ -102,7 +103,10 @@ let
inherit transformOptions; inherit transformOptions;
}; };
# CommonMark .md = source of truth; HTML is rendered from this. # 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 = mkMarkdownPage =
name: title: doc: name: title: doc:
pkgs.runCommand "hyperhive-${name}.md" { } '' pkgs.runCommand "hyperhive-${name}.md" { } ''
@ -117,100 +121,39 @@ let
} > $out } > $out
''; '';
# Loaded as text so it's editable with normal CSS tooling and # Bundle landing page — a short markdown index pointing at the two
# inlined into every page (no second-fetch dependency). # reference pages.
styleCSS = builtins.readFile ./style.css; indexMD = pkgs.writeText "hyperhive-options-index.md" ''
# hyperhive — nix options reference
# CommonMark → cmark-gfm → minimal template, inline CSS, relative links. Auto-generated from the hyperhive flake. Two reading paths:
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/default.nix">nix/docs/default.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, hand-authored intro + cross-links. - [host options](host.md) options exposed by
indexHTML = pkgs.runCommand "hyperhive-docs-index.html" { } '' `hyperhive.nixosModules.default` to operator host configurations
{ (`services.hyperhive.{enable,domain,c0re,forge,matrix,gateway}.*`).
echo '<!doctype html>' - [per-agent options](agent.md) options declared in
echo '<html lang="en">' `nix/templates/harness-base.nix`, visible from every `agent.nix`
echo '<head>' (`hyperhive.model`, `hyperhive.allowedRecipients`,
echo '<meta charset="utf-8">' `hyperhive.extraMcpServers`, `hyperhive.frontend.*`,
echo '<meta name="viewport" content="width=device-width, initial-scale=1">' `hyperhive.forge.*`, `hyperhive.matrix.*`, `hyperhive.gui.*`).
echo '<title>hyperhive nix options reference</title>'
echo '<style>' Regenerate with `nix build .#docs` (bundle), `.#docs-host`, or
cat ${pkgs.writeText "hyperhive-docs-style.css" styleCSS} `.#docs-agent`.
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.hyperhive.{enable,domain,c0re,forge,matrix,gateway}.*</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; hostMD = mkMarkdownPage "docs-host" "hyperhive host options" hostDoc;
agentMD = mkMarkdownPage "docs-agent" "hyperhive per-agent options" agentDoc; agentMD = mkMarkdownPage "docs-agent" "hyperhive per-agent options" agentDoc;
in in
{ {
host = hostHTML; host = hostMD;
agent = agentHTML; agent = agentMD;
# Bundled static site nginx serves at `/options/`. Asset paths are # Bundle of the option reference as markdown. The website renders
# all relative so the prefix can change without rebuild. # these `.md` to themed HTML for `/options/`; standalone consumers
# get the CommonMark source directly.
bundle = pkgs.runCommand "hyperhive-options-docs" { } '' bundle = pkgs.runCommand "hyperhive-options-docs" { } ''
mkdir -p $out mkdir -p $out
cp ${indexHTML} $out/index.html cp ${indexMD} $out/index.md
cp ${hostHTML} $out/host.html
cp ${agentHTML} $out/agent.html
cp ${hostMD} $out/host.md cp ${hostMD} $out/host.md
cp ${agentMD} $out/agent.md cp ${agentMD} $out/agent.md
''; '';

View file

@ -1,76 +0,0 @@
: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);
}