Generalize the docs mount past umbra, so a second project can mount at all #136
Labels
No labels
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
burndown-2026-06
burndown-2026-08
icebox
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilysiren/website#136
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Design Engineer lane. Handoff from coilysiren/website#135, which built the sync and left the render layer umbra-shaped.
The sync half is done and is config-driven: adding a project is one entry in
src/data/docs-mounts.json, andscripts/sync-project-docs.pyvendors it with no code change. The render half cannot take a second project without work.The five places that name umbra
eleventy.config.js- themountedDocLinkstransform returns early unless the URL starts with/projects/umbra/docs/, resolves against a hardcodedUMBRA_SOURCE, and builds itsmountedset fromumbraDocsFlat. A second mount needs project, source URL, and slug set resolved per page rather than closed over once.src/_includes/layouts/docs.njk- reads theumbraDocsglobal directly for the sidebar, the shelves, and the snapshot stamp, and hardcodesdocs--umbraas the layout class.src/data/umbra-docs.jsandsrc/_data/umbraDocs.js- the manifest and the data join, both named for the project.src/projects/umbra-docs-index.njk- the front door, a bespoke template.src/build-output.test.tsandsrc/docs-mount.test.ts-DOCS_ROUTESderives from umbra's manifest, and the mount test asserts umbra by name.None of it is hard. It is one project's worth of naming that wants to become a parameter.
What good looks like
Adding agent-compose or mcp-beaver should be: one entry in
docs-mounts.json, one manifest file, and nothing else. The transform, the layout, the front door, and the tests should all read the project from data.Worth preserving while doing it: the stamp is generated into
src/data/docs-mount-source.jsonand keyed by project already, so that part generalizes for free.src/docs-mount.test.tsfails when the vendored files and the manifest disagree, and that check should survive as a per-project loop rather than being dropped.What this does not cover
The manifests themselves. Neither agent-compose nor mcp-beaver has a
docs/index.md, which is where umbra's titles and blurbs were lifted from, so 62 pages need copy written before either can mount. That is the sibling issue in the Developer Advocate lane, and it is the longer pole. This issue is the code that makes the copy usable when it exists.Why it is worth doing
coilysiren/website#133opens on the defect that every project card sends readers togithub.comat the moment of highest interest. The agent-compose and mcp-beaver project pages still link their docs off-domain. Mounting is what fixes that, and this is the half that has to exist first.Done, on
mainat602180b. Nothing in the render layer names a project.Adding a mount is now three steps: an entry in
docs-mounts.json, adocs-manifest-<project>.js, and one import line indocs-mount-routes.js.src/docs-mount.test.tsfails if a declared mount has no manifest, so a missed step is a test failure rather than a broken page.The five, plus a sixth
eleventy.config.js- the transform reads the project out of the page URL, then resolves source repo, branch, docs dir, and slug set from that mount.docs.njk- readsmountfrom data, and the layout class isdocs--{{ project }}.src/data/docs-manifest-umbra.js, resolved by name from config throughdocs-mount-loader.js. No registry to update on the Node side._includes/components/docs-front.njk. Its written copy moved into the manifest as afrontblock, since a template cannot derive a headline.config.mounts. Routes derive from the manifests, socypress/routes.tscannot fall behind a sync.src/llms.njk- not on the list, and it hardcoded umbra's shelves. A second mount would have built fine and been silently absent fromllms.txt.The vendored trees moved under
src/projects/docs/<project>/, so one directory data file serves every mount and reads the project from the path. Eleventy cascades directory data into subdirectories, which is what removes the per-project boilerplate.Two things the build found that reading would not
I mounted mcp-beaver in a scratch copy to check the three steps were really the three steps. 23 routes emitted correctly, and two defects surfaced that would otherwise have landed on whoever mounted the second project.
Pagination for the front doors was the obvious shape and the wrong one. Only its first page reaches
collections.all, so mcp-beaver's front door built correctly, carried the right canonical, and was missing from the sitemap. Virtual templates viaaddTemplatehave no such gap.The route module cannot use top-level await.
cypress/routes.tspulls it into a browser bundle whose bundler rejects it, so manifests there are imported statically rather than resolved by name. That is the one line of code per mount, and it is why the count is three steps rather than two.Both are written up in the new
docs/project-docs-render.md.Verification
89 Cypress specs, 15 unit tests, typecheck, and the full hook suite are green. The umbra pages render pixel-identically, and
just sync-project-docsstill reproduces the vendored tree byte-for-byte.The stamp moved to umbra
1935291as a side effect of that check: upstream HEAD advanced without touching docs content.Not covered, as the issue says
The manifests for agent-compose and mcp-beaver. Neither repo has a
docs/index.md, so 62 pages need titles and blurbs written before either can mount for real. That is the Developer Advocate lane and the longer pole.