Spec: developer docs, published as a site (from intent.md 2026-10-19)#
Status: draft (reviewed with its intent, plan and code in one PR, at the owner's request).
Requirements#
The docs (Markdown in the repo)
- R1. Developer documentation is written as Markdown files in the repo, next to what they describe: a README in each code folder (
cli/,app/,scripts/) for its internals, and guides underdocs/(a developer-docs home, the architecture today, contributing, testing). They describe the code as it is, and link to the design record and the generated command reference rather than repeating them. - R2. The root README points developers to the developer docs and the published site.
The site
- R3. One command,
npm run docs:site, builds a static site from the README files and the other docs intobuild/docs-site/: the root README is the home page, each folder's README is that folder's page, anddocs/cli.md, the guides,CLAUDE.mdand every change underdocs/intents/are pages too. It uses Node built-ins only (no new dependencies) and never writes to the docs it reads. - R4. Links work on the site as they do on GitHub: a link to another page's
.mdbecomes a link to that page; heading anchors use GitHub's ids, so#setup-for-claude-codeand#sceneplaceland where they do on GitHub; a link to a repo file that isn't a page (a source file, a workflow, a folder) goes to that file on GitHub; images are copied next to the pages that use them. - R5. The build fails, naming the file and the link, when a link to a page, an anchor or an image is broken, so a broken doc can't be published.
- R6. Every page has the same frame: the site title, a sidebar of every page in sections (Start, Guides, Code, Reference, Design record), the page's own contents (its h2 and h3), and a footer naming its source file with a link to it on GitHub. A search box finds pages and headings by title.
- R7. The look is board 03, "Field notebook": the app's tokens (
app/Sources/PixelLab/Theme/Theme.swift), night and day following the system, with a toggle that remembers the reader's choice. Sora for headings, Silkscreen only for short uppercase labels, a monospace face for code. It works at phone width (16 px gutters, no sideways page scroll; wide tables and code scroll in their own box), keyboard focus is visible, and nothing animates.
The deployment
- R8. A workflow builds the site on every pull request (without deploying, so a broken doc fails the PR) and on every push to
main, and deploys themainbuild to GitHub Pages; it can also be run by hand. It checks first thatdocs/cli.mdmatches the command registry, so the published reference is never stale. It asks for no more permissions than each job needs. - R9. The docs say how to build the site locally, how to add a page, and how the deployment works, including the one-time Pages setting.
Design#
- Docs. New:
docs/README.md(home: reading order, what's where),docs/architecture.md(the three doors, an edit's path from the app to disk, an agent's proposal, the state dir, the site as source of truth),docs/contributing.md(intent → spec → plan, branches, the checks a PR pastes, conventions),docs/testing.md(the CLI suites and their site copy, Swift tests, the script hook, snapshots, the acceptance pass, CI),cli/README.md(module map, a command's anatomy, adding a command, sessions, servers, errors),app/README.md(the model, the server connection and its events, views, theme, build constraints, adding a feature),scripts/README.md(every script). Changed:README.md(a Developer docs section),CLAUDE.md(the new command). - Generator.
scripts/docs-site/build.mjs(the page list and nav, link rewriting, the link check, the HTML frame),scripts/docs-site/markdown.mjs(a small CommonMark-style renderer for what the docs use: ATX headings, paragraphs, nested ordered and unordered lists, fenced code inside lists, block quotes, GFM tables with\|, thematic breaks, HTML comments dropped, inline code, emphasis, links, images, bare-URL autolinks),scripts/docs-site/style.cssandscripts/docs-site/site.js(theme toggle, search, copy buttons on code). Raw HTML in Markdown is escaped, not passed through. Pages land at their source path with.md→.html, aREADME.md→index.html, so every link is relative and the site works under any base path (/jlawcordova-lab/on Pages,file://locally). Search reads an index of page titles and headings fromassets/search-index.js, a script rather than JSON, so it also works fromfile://. - Workflow.
.github/workflows/docs.yml: jobbuild(Ubuntu, Node 22:node scripts/docs-cli.mjs --check,node --test cli/test/docs-site.test.mjs,npm run docs:site,actions/upload-pages-artifact), jobdeployonmainand manual runs only (actions/deploy-pages,pages: writeandid-token: write, thegithub-pagesenvironment).contents: readotherwise. Pages deploys don't cancel each other. - Tests.
cli/test/docs-site.test.mjs, run bynpm test, named after the requirements: the renderer's output for each construct, GitHub's heading ids, link rewriting, a full build into a temp folder with every link checked, and the build refusing a broken link.
Areas of concern#
- The site is public. GitHub Pages sites are public on every plan but Enterprise Cloud, and Pages for a private repo needs a paid plan. The docs hold no secrets;
docs/cli.mdnames the owner's home folder (/Users/jlawcordova/…), the same name as the GitHub account. Resolved 2026-10-19: the owner accepted public docs and made the repo public, since the account's plan doesn't allow Pages on a private repo. - It's served under the owner's domain. The user site (
jlawcordova.github.io) has the custom domainjlawcordova.com, so this project's Pages site is served athttps://jlawcordova.com/jlawcordova-lab/. The site has no page at that path today; one added later would be shadowed by Pages' project site. - One-time setting. Pages must be enabled for the repo with Source: GitHub Actions (Settings › Pages) before the first deploy; the workflow's
GITHUB_TOKENcan't enable it. Until then the deploy job fails and the build job still checks every PR. Done 2026-10-19. - Fonts from Google Fonts. Sora and Silkscreen load from
fonts.googleapis.com, so readers' browsers ask Google for them; without them it falls back to system faces.
Open questions#
- Public docs (from the intent): answered yes; the repo is now public.