docs/adr/0009-docs-in-monorepo-night-compiler-npm.md

ADR 0009: Public docs in the monorepo, night-compiler from npm

  • Status: Accepted
  • Date: 2026-07-07 (updated 2026-07-08: theme moved from a git submodule to a published npm package; the overview site replaced the generated landing index as the domain root)

Context

Clankie's public docs content lives in the monorepo, co-located with each package: a package's apps/docs is a Vite + React 19 + Tailwind v4 site that imports that package's own README.md and docs/** markdown. Only the theme, @volpestyle/night-compiler, is external — it is a generic docs design system reused beyond Clankie, so it must not be forked or copied into this repo.

The theme was first consumed via a filesystem link: to a sibling ~/dev/docs checkout, which broke "clone and build" (a fresh clone had no sibling). A git submodule at repo-root docs-shell/ fixed the clone problem but added its own friction: fresh clones needed git submodule update --init, and every theme change meant a manual pin bump. Once the theme was generalized into a standalone design system, publishing it to npm became the natural distribution.

Decision

  1. Consume night-compiler as a published npm package. Each apps/docs depends on @volpestyle/night-compiler by semver (^0.1.0) like any other package; a fresh clone builds with a plain pnpm install, no submodule. The theme also ships the public-docs guard tooling as executable bins (night-compiler-guard-inputs, night-compiler-guard-artifact); the Docs workflow declares the theme as a root devDependency and runs those bins via pnpm exec. The theme is a source package (it ships its .tsx + styles.css) because its Tailwind v4 @source "./**/*.{ts,tsx}" self-scan must find the component source at build time in every consumer.

  2. Per-package docs apps, aggregated at the host — not a single monolith app. The public-docs guard only allows a docs app to import README.md and non-private docs/**/*.md from its own package root. An aggregated app that pulled markdown across packages would be rejected by that guard by design. The whole infrastructure — per-app input guard and per-artifact output guard — is built for one docs app per package, stitched together at the host. Each package that grows docs adds an apps/docs site consuming the same theme; the deploy assembles them under one domain, with the clankie overview site mounted at the domain root as the landing page (empty slug in docs/ecosystem.json) and clankie-agent, clankvox, and clankie-contract at /<slug>/. The site list in the workflow is a one-line-per-site array, and a redirect stub at /clankie/ preserves the overview site's original path.

  3. Deploy to Clankie's own AWS static hosting at docs.clankie.bot. The Docs workflow builds each package site, runs the input and artifact guards, assembles the overview site at the publish root plus publish/<slug>/ per package, and deploys the tree to a private S3 bucket (clankie-bot-docs) fronted by CloudFront and a shared clankie.bot/*.clankie.bot ACM certificate. CloudFront reaches the bucket through Origin Access Control (the bucket stays private, no website endpoint), and a CloudFront Function rewrites extensionless or /-suffixed URIs to …/index.html, since OAC has none of S3 website hosting's index resolution. Deploy authenticates with GitHub OIDC — the job assumes arn:aws:iam::842434829012:role/clankie-docs-deploy, whose trust is pinned to repo:Volpestyle/clankie:ref:refs/heads/master, so no long-lived AWS keys live in the repo; aws s3 sync --delete reconciles the bucket and a CloudFront /* invalidation publishes the change. AWS hosts docs beside the clankie.bot landing page (which must live on AWS anyway), keeping one provider, one account, and one CloudFront/ACM setup.

Consequences

  • A fresh clone builds the docs with a plain pnpm install (no submodule, no sibling checkout, no build-time clone). clankie keeps one submodule, herdr.
  • Theme changes ship by publishing a new @volpestyle/night-compiler version and bumping the semver range; the theme's own tag-based release workflow publishes it (Volpestyle/docs). No pin-bump-and-commit dance in this repo.
  • The AWS resources — S3 bucket clankie-bot-docs, CloudFront distribution E2SL4SXV9RAPNU, the shared ACM cert, the clankie-index-rewrite CloudFront Function, the clankie-docs-deploy OIDC role, and the Route53 alias records — live in account 842434829012 and are provisioned out-of-band from this repo. The build job runs on PRs and gates them; the deploy job runs on master and workflow_dispatch only.
  • Cross-site links and the ecosystem base URL are consumer-owned data in docs/ecosystem.json; the theme carries no product-specific registry.