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
-
Consume
night-compileras a published npm package. Eachapps/docsdepends on@volpestyle/night-compilerby semver (^0.1.0) like any other package; a fresh clone builds with a plainpnpm install, no submodule. The theme also ships the public-docs guard tooling as executable bins (night-compiler-guard-inputs,night-compiler-guard-artifact); theDocsworkflow declares the theme as a root devDependency and runs those bins viapnpm 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. -
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.mdand non-privatedocs/**/*.mdfrom 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 anapps/docssite consuming the same theme; the deploy assembles them under one domain, with theclankieoverview site mounted at the domain root as the landing page (empty slug indocs/ecosystem.json) andclankie-agent,clankvox, andclankie-contractat/<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. -
Deploy to Clankie's own AWS static hosting at
docs.clankie.bot. TheDocsworkflow builds each package site, runs the input and artifact guards, assembles the overview site at the publish root pluspublish/<slug>/per package, and deploys the tree to a private S3 bucket (clankie-bot-docs) fronted by CloudFront and a sharedclankie.bot/*.clankie.botACM 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 assumesarn:aws:iam::842434829012:role/clankie-docs-deploy, whose trust is pinned torepo:Volpestyle/clankie:ref:refs/heads/master, so no long-lived AWS keys live in the repo;aws s3 sync --deletereconciles the bucket and a CloudFront/*invalidation publishes the change. AWS hosts docs beside theclankie.botlanding 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).clankiekeeps one submodule,herdr. - Theme changes ship by publishing a new
@volpestyle/night-compilerversion 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 distributionE2SL4SXV9RAPNU, the shared ACM cert, theclankie-index-rewriteCloudFront Function, theclankie-docs-deployOIDC role, and the Route53 alias records — live in account842434829012and are provisioned out-of-band from this repo. The build job runs on PRs and gates them; the deploy job runs onmasterandworkflow_dispatchonly. - Cross-site links and the ecosystem base URL are consumer-owned data in
docs/ecosystem.json; the theme carries no product-specific registry.
