{ stdenv, lib, self, }: # The repo `docs/` markdown tree, shipped as a standalone derivation so # agents can read the reference docs in-container (added as a claude # additional directory by the harness) WITHOUT pulling the branding + # prompt assets they don't need, and so the `hyperhive/website` repo can # reuse the exact same tree as a flake input. # # The docs/ tree is copied verbatim (never transformed). On top of that, # `$out/crates/.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/crates/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/crates/.md — one per workspace crate README, plus the # hand-written docs/crates/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 crates/.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 the *base tree*'s input hash decoupled # from the rest of the workspace — a doc edit only re-hashes this half. # The crates/ 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; dontBuild = true; dontConfigure = true; installPhase = '' runHook preInstall mkdir -p $out cp -r ./* $out/ mkdir -p "$out/crates" ${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 # (crates/ -> 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 # crates page every crate README lives flat beside it. sed -E \ -e 's,\]\(\.\./docs/,](../,g' \ ${siblingLinkFixups member} \ "$self/${member}/README.md" \ > "$out/crates/${member}.md" fi '') members} runHook postInstall ''; dontFixup = true; meta = { description = "hyperhive reference docs (the repo docs/ tree, plus a virtual crates/.md per workspace crate README)"; homepage = "https://forge.darkest.space/hyperhive/hyperhive"; }; }