Skip to content

feat(docs): serve core documentation at /docs, and llms.txt beside it - #20

Merged
keyurgolani merged 1 commit into
mainfrom
feature-docs-site
Jul 31, 2026
Merged

feat(docs): serve core documentation at /docs, and llms.txt beside it#20
keyurgolani merged 1 commit into
mainfrom
feature-docs-site

Conversation

@keyurgolani

Copy link
Copy Markdown
Contributor

The site advertised PersonalClaw without publishing its documentation. This adds /docs (Astro + Starlight) plus the machine-readable llms.txt pair — the LLM-recommendation discovery channel plan 36 names as half its rationale.

Closes the /docs half of Phase 2 (synchronized docs) and Discoverability & Launch T1.4 / T2.1 / T2.2.

What changed

Both surfaces are generated at build time from the pinned core commit — the same commit the release facts come from, so the docs corpus and the version claims cannot disagree.

Nothing is committed here. src/content/docs/ and public/llms*.txt are gitignored and produced by scripts/sync-docs.mjs, because one canonical source is the point and a committed copy is a copy that drifts. scripts/known-docs.mjs records which core docs are published, so a new one appears deliberately rather than silently.

Source resolution is reused from sync-sources.mjs (local checkout when it matches the pin, else the verified pinned remote) rather than duplicated — a second copy of the pin-verification logic is a second place for the contract to drift.

Relative links are rewritten rather than left to rot: cross-tree links resolve in-site, and links that leave the published corpus (CONTRIBUTING, SECURITY, the roadmap) go to GitHub at the pinned commit, so they match the docs being read. All four verified to return HTTP 200.

Three problems the gates caught, each fixed at the root

1. Starlight silently reflowed the marketing pages. Its integration sets scopedStyleStrategy: 'where' globally, rewriting every component's scoped selectors from [data-astro-cid-x] to :where(.astro-x) — zero specificity. The home page lost 56px of height and three visual baselines failed with no source change. Setting the strategy at the config root does not work (the integration's updateConfig wins); an integration ordered after Starlight restores it. No baseline was regenerated and no assertion weakened.

2. The docs were shipping with zero accessibility coverage. accessibility.spec.ts iterated only the five marketing routes, so a third of the site's pages had no axe check. Extending it surfaced 52 real WCAG violations: Starlight styles every table as its own scroll container (markdown.css:135), which axe rates scrollable-region-focusable / serious — a mouse can scroll it, a keyboard cannot reach it. Core's docs are table-heavy, so this is not hypothetical. Fixed with scripts/rehype-scrollable-tables.mjs (the tab stop must go on the table — a wrapper does not help when the inner element is what scrolls; a first attempt wrapped it and mobile still failed). A guard test fails if a new docs tree gains no axe sample.

3. Preview builds had no robots meta, so a throwaway branch URL would have competed with personalclaw.dev in search. Starlight does not use BaseLayout.astro, so the policy needed restating in its head. validate:preview caught the omission.

Security: clears a pre-existing high-severity advisory

npm had resolved sharp 0.34.5, which carries the libvips advisory GHSA-f88m-g3jw-g9cj (4 CVEs, high). Verified pre-existing by auditing the unmodified baseline in a clean install — it is a transitive dep of Astro, not of Starlight. Astro 7 already permits the patched ^0.35 line, so this pins the resolution up via overrides rather than adding sharp as a direct dependency the site does not import. Rationale recorded in package.json.

npm audit --audit-level=moderate: 0 vulnerabilities (was 1 high).

Route contract: two tiers, deliberately

site-contract.mjs keeps the 5 marketing routes (exact title + description contracted — hand-authored here) separate from the 18 docsRoutes (paths only). Docs titles are core's H1s, so pinning the strings would mean editing this repo every time core rewords a heading, and core owning the words is the whole design. What is contracted: the published path set, non-empty title/description on every page, and the /docs prefix so they never collide with a marketing route.

Gates — full test:ci green

  • 30 visual baselines across darwin and linux
  • 23 routes validated under both production and preview policy
  • 88 browser tests (up from 73 — includes the new docs a11y coverage)
  • Lighthouse budgets passed: accessibility 100 on every marketing route, performance 99–100
  • npm audit: 0 vulnerabilities

Validated as a user

Served dist/ and drove both surfaces in a real browser: /docs/reference/cli renders with the full sidebar, a 19-entry "On this page" TOC, styled tables, inline code and working local search (Pagefind — no external service, so zero-telemetry holds); / still renders the coral-branded marketing hero unchanged. /security (marketing) and /docs/security/threat-model (doc) coexist with distinct titles.

Docs are brand-themed to match the site, colour only — Starlight's layout, type scale and contrast work is left intact rather than re-derived. Contrast measured, not assumed: an earlier draft used a darker coral that came in at 4.33:1 (below AA); the brand token #ff6b5b itself is 7.00:1 on the dark surface, so the brand colour was already the right answer.

Known limitation, recorded not hidden

markdown.rehypePlugins is deprecated in Astro 7, and the documented replacement does not work: the exported unified from @astrojs/markdown-remark has no .use(), so unified().use(plugin) throws at config load. Kept the supported-and-working form with a comment; the notice is a warning, not a failure. Using rehype plugins at all requires @astrojs/markdown-remark pinned to 7.2.1 — Astro 7.1.4 peer-wants exactly that while Starlight's mdx pulls 7.2.2.

skill-format.md is absent from the synced set on purpose: it does not exist at v0.1.3. It appears on the next release, which is the projection rule working.

Notes

ARCC was not queried — the MCP server is unavailable in this session. Standard practice applied: no telemetry added, search stays local, preview builds fail closed to noindex, and the dependency change reduces the advisory count rather than raising it.

The site advertised PersonalClaw without publishing its documentation. This adds
/docs (Astro + Starlight) plus the machine-readable llms.txt pair, both generated
at build time from the pinned core commit — the same commit the release facts come
from, so the docs corpus and the version claims cannot disagree.

Nothing is committed here. src/content/docs/ and public/llms*.txt are gitignored
and produced by scripts/sync-docs.mjs, because one canonical source is the point
and a committed copy is a copy that drifts. scripts/known-docs.mjs records which
core docs are published, so a new one appears deliberately rather than silently.

Relative links are rewritten rather than left to rot: cross-tree links resolve
in-site, and links that leave the published corpus (CONTRIBUTING, SECURITY, the
roadmap) go to GitHub at the pinned commit, so they match the docs being read.

Three problems found by the gates, each fixed at the root rather than absorbed:

Starlight sets `scopedStyleStrategy: 'where'` globally, which rewrote every
component's scoped selectors to zero specificity and silently reflowed the
MARKETING pages — the home page lost 56px and three visual baselines failed with
no source change. An integration ordered after Starlight restores the attribute
strategy. No baseline was regenerated.

The docs pages were shipping with no axe coverage: accessibility.spec.ts iterated
only the five marketing routes. Extending it surfaced 52 real WCAG violations —
Starlight styles every table as its own scroll container, which a mouse can scroll
and a keyboard cannot reach. A rehype plugin makes each table a labelled, focusable
region; a guard test fails if a new docs tree gains no sample.

Preview builds had no robots meta, so a throwaway branch URL would have been
indexable. Starlight does not use BaseLayout, so it needed the policy stated.

Also clears a pre-existing high-severity advisory: npm had resolved sharp 0.34.5
(libvips, GHSA-f88m-g3jw-g9cj, 4 CVEs) while Astro already permitted the patched
0.35 line. Pinned up via overrides rather than adding a direct dependency.

npm audit: 0 vulnerabilities. test:ci green — 30 visual baselines, 23 routes in
both production and preview policy, 88 browser tests, Lighthouse budgets with
accessibility 100 on every marketing route.

Signed-off-by: Keyur Golani <keyurrgolani@gmail.com>
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
personalclaw Ready Ready Preview Jul 31, 2026 11:17pm

@keyurgolani
keyurgolani merged commit b67b162 into main Jul 31, 2026
6 checks passed
@keyurgolani
keyurgolani deleted the feature-docs-site branch July 31, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant