From 765bea2022647ae22bd2774023aba4b3765476d1 Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 11 Aug 2026 17:10:23 +0200 Subject: [PATCH] docs: virtualize crate READMEs under docs/components/ Each workspace crate's own README.md now also shows up as docs/components/.md via nix/packages/reference-docs.nix, so it renders on the docs site alongside the rest of docs/ without a second hand-copied file to keep in sync. Relative links that were correct from the crate's own position in the tree are rewritten for their new virtual position (../docs/x.md -> ../x.md, ../ -> ./.md). Landing page at docs/components/README.md, nav bullet added to docs/README.md. No changes needed in the website repo's docs.nix - it already walks every subdirectory generically. --- docs/README.md | 7 ++++ docs/components/README.md | 13 ++++++ nix/packages/default.nix | 6 ++- nix/packages/reference-docs.nix | 73 +++++++++++++++++++++++++++++---- 4 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 docs/components/README.md diff --git a/docs/README.md b/docs/README.md index c0203307..f33fd28b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -86,6 +86,13 @@ declarations. - **How do I export Claude Code metrics (tokens, cost, tool calls) to Prometheus/Grafana?** → [`observability.md`](observability.md). +## Crate reference + +- **What does a specific Rust crate do, on its own terms?** → + [`components/`](components/README.md) — every workspace crate's own + `README.md`, one level up from source (hyperhive#3051); the crate + itself is still the source of truth, this is just a walkable mirror. + ## Process & conventions - **Naming, commit style, wire protocol, the `data-async` pattern?** → diff --git a/docs/components/README.md b/docs/components/README.md new file mode 100644 index 00000000..75348807 --- /dev/null +++ b/docs/components/README.md @@ -0,0 +1,13 @@ +# Crate reference + +One page per Rust workspace crate — its own `README.md`, unchanged, served +here for browsing alongside the rest of the docs site. **The crate's own +`README.md` is the source of truth; nothing here is hand-maintained.** +Every page is generated at build time (`nix/packages/reference-docs.nix`, +hyperhive#3051) straight from the crate's real `README.md`, so it can never +drift out of sync the way a hand-copied mirror would — edit the crate's +own README to change what shows up here. + +For the one-line-per-crate index (which crate does what, at a glance) +see the main [`CLAUDE.md`](../../CLAUDE.md#repo-map) repo map instead; +this section is each crate's own, longer word on itself. diff --git a/nix/packages/default.nix b/nix/packages/default.nix index cb121b0c..e8e234cd 100644 --- a/nix/packages/default.nix +++ b/nix/packages/default.nix @@ -174,8 +174,10 @@ in # directory) and the website repo reuses it as a flake input, # neither of which needs the branding/prompt assets. See # ./reference-docs.nix. (`docs` below is the auto-generated - # nix-options reference, a different artifact.) - reference-docs = pkgs.callPackage ./reference-docs.nix { }; + # nix-options reference, a different artifact.) `self` is needed to + # read each workspace crate's own README.md into the virtual + # `components/` subdir. + reference-docs = pkgs.callPackage ./reference-docs.nix { inherit self; }; # XDG icon set + .desktop entries for hyperhive processes. # Narrow input: only the branding SVG, so unrelated source changes # don't bust this derivation's cache. diff --git a/nix/packages/reference-docs.nix b/nix/packages/reference-docs.nix index 216a398d..eac1fc36 100644 --- a/nix/packages/reference-docs.nix +++ b/nix/packages/reference-docs.nix @@ -1,5 +1,7 @@ { stdenv, + lib, + self, }: # The repo `docs/` markdown tree, shipped as a standalone derivation so @@ -8,20 +10,56 @@ # prompt assets they don't need, and so the `hyperhive/website` repo can # reuse the exact same tree as a flake input. # -# Pure data: the docs are copied verbatim (never transformed), so there -# is no writable/build step — `$out` is the docs tree as-is. +# The docs/ tree is copied verbatim (never transformed). On top of that, +# `$out/components/.md` is synthesized — one per workspace crate +# with a README.md, virtualized under docs/ (mara's ask: "behaves as if +# hive-core/README.md lives at docs/components/hive-core.md"). The +# crate's own README stays the single source of truth; this derivation +# only projects it into the docs tree, so there is no second copy to keep +# in sync by hand. `docs.nix` (website repo) needs no changes to pick these +# up — it already walks every subdirectory + `.md` file generically. # # Output layout: -# $out/ — the repo `docs/` tree verbatim (e.g. `$out/setup.md`) +# $out/ — the repo docs/ tree verbatim (e.g. $out/setup.md) +# $out/components/.md — one per workspace crate README, plus the +# hand-written docs/components/README.md +# landing page (copied verbatim like any +# other docs/ file, not generated here) +let + cargoToml = builtins.fromTOML (builtins.readFile ../../Cargo.toml); + members = cargoToml.workspace.members; + + # A member-name relative link (`../`, no specific file — + # forge's browser renders that as a directory listing today) becomes a + # sibling components/.md link once every crate README + # lives flat in the same directory. Built once, applied per file below, + # rather than a fresh `lib.concatMapStrings` per crate's own transform — + # every crate needs the exact same substitution list (every *other* + # member), so this only differs on the `member != other` filter. + siblingLinkFixups = + member: + lib.concatMapStrings ( + other: + lib.optionalString (other != member) '' + -e 's,\]\(\.\./${other}(/)?\),](./${other}.md),g' \ + '' + ) members; +in stdenv.mkDerivation { pname = "hyperhive-docs"; version = "0.1.0"; - # Narrow src (just docs/) keeps this derivation's input hash decoupled - # from the rest of the tree — a doc edit only re-hashes this. + # Narrow src (just docs/) keeps the *base tree*'s input hash decoupled + # from the rest of the workspace — a doc edit only re-hashes this half. + # The components/ generation below necessarily widens that: it reads + # each crate's own README.md via `self`, so this derivation's hash now + # also tracks the whole repo tree (Nix has no cheaper way to depend on + # "just these few files" out of a flake `self`). Accepted trade-off — + # the alternative is hand-copying READMEs into docs/ and letting them + # drift, which is the exact duplication this issue exists to avoid. src = ../../docs; + inherit self; - # No build: pure markdown, nothing to compile or render. dontBuild = true; dontConfigure = true; @@ -29,13 +67,34 @@ stdenv.mkDerivation { runHook preInstall mkdir -p $out cp -r ./* $out/ + mkdir -p "$out/components" + + ${lib.concatMapStrings (member: '' + if [ -f "$self/${member}/README.md" ]; then + # Rewrite relative links that were correct from the crate's own + # position in the repo tree but aren't once the file is + # virtually one level under docs/ instead: + # ../docs/x.md (crate root -> repo docs/) -> ../x.md + # (components/ -> docs/ is one directory shallower than + # / -> docs/ was, so the leading docs/ segment drops) + # ../ (that crate's own directory, no file) + # -> ./.md, once that sibling also has a + # components page every crate README lives flat beside it. + sed -E \ + -e 's,\]\(\.\./docs/,](../,g' \ + ${siblingLinkFixups member} \ + "$self/${member}/README.md" \ + > "$out/components/${member}.md" + fi + '') members} + runHook postInstall ''; dontFixup = true; meta = { - description = "hyperhive reference docs (the repo docs/ tree)"; + description = "hyperhive reference docs (the repo docs/ tree, plus a virtual components/.md per workspace crate README)"; homepage = "https://forge.darkest.space/hyperhive/hyperhive"; }; }