Skip to content

Internal Docs Site

The project docs (from docs/) are published as a static site using Zensical (successor to MkDocs Material), deployed to Cloudflare Pages at cslewis-docs.fueled.engineering, gated behind Cloudflare Access for @fueled.com SSO.

.context/ is internal working memory and is not published — it stays in the repo for agents and engineers, not the docs site.

Quick start (local)

# Preview locally (hot-reload)
./scripts/docs-build.sh serve

# One-off build → site/
./scripts/docs-build.sh build

Requires uv (install). Zensical runs via uvx — no global install needed.

How it works

  1. scripts/docs-build.sh assembles docs/ into docs/_build/
  2. Zensical reads zensical.toml (docs_dir = "docs/_build") and produces site/
  3. GH Action (.github/workflows/docs.yml) deploys site/ to Cloudflare Pages on every push to main
  4. Cloudflare Access gates the site with Google Workspace SSO (@fueled.com)

Both docs/_build/ and site/ are gitignored.

Adding pages

  1. Add your .md file under docs/
  2. Add a nav entry in zensical.toml (nav = [ … ]) under the appropriate section
  3. Push to main — auto-deploys

.context/ is internal-only and never published — keep working notes there, reader-facing docs under docs/.

One shelf per audience

The docs are split by who reads them, not by entity. Three shelves:

Shelf Audience Where
Editor guide The people working in the CMS docs/editor-guide.md, one file
API reference Mobile and client developers docs/api/ — index.md for the conventions, one page per entity
Reference, guides, ADRs Backend engineers docs/reference/, docs/guides/, docs/adr/, docs/architecture.md

Rules that follow from that split:

  • One entity, one API page. docs/api/passages.md carries the concept ("what a passage is") and its endpoints. Do not split the concept into a second file; a reader who wants the endpoints wants the concept on the way past.
  • All editor-facing content goes in docs/editor-guide.md. One file, so it exports as a single coherent PDF for the client's editors and nothing drifts between per-entity copies. Add a chapter, do not add a file.
  • Split the editor guide only when it passes roughly 1,500 lines, and then into docs/editor-guide/ with a build step that concatenates the chapters. Until then, keep it as one file.
  • Never nav an empty stub. A dead-end page is worse than none.
  • Reference pages are generated where they can be. docs/reference/data-model.md is rendered from the models by make data-model-doc, and a test fails when it drifts. Edit the prose above the generated marker; never edit the block below it.
  • Do not keep a design proposal as a reference page. Pre-build design that the code has moved past reads as fact and misleads. Put the decision in an ADR, the open questions in .context/, and delete the page; git keeps the text.

This replaced a per-entity folder layout (docs/<entity>/index.md + api-guide.md + editor-guide.md) on 2026-09-23. That layout put three audiences inside every folder and left five near-duplicate editor guides that could not be shared as one document.

Setup for a new Fueled project

Copy these files into any repo:

File Purpose
zensical.toml Site config — edit site_name, nav
scripts/docs-build.sh Build script — assembles docs/ → _build/
.github/workflows/docs.yml CI deploy to Cloudflare Pages

1. Cloudflare Pages project

CLOUDFLARE_ACCOUNT_ID=97e8452a103b40bfa5d44e08ceca38bb \
  wrangler pages project create <project-name> --production-branch main

Or create via Cloudflare dashboard → Pages → Create project → Direct upload.

2. GitHub secrets

Add to repo Settings → Secrets and variables → Actions:

Secret Value
CLOUDFLARE_API_TOKEN API token with Cloudflare Pages: Edit on Fueled account
CLOUDFLARE_ACCOUNT_ID 97e8452a103b40bfa5d44e08ceca38bb

Update --project-name in .github/workflows/docs.yml to match step 1.

3. Custom domain

  1. In Cloudflare Pages → your project → Custom domains → Add (e.g. <name>-docs.fueled.engineering)
  2. In Cloudflare DNS → fueled.engineering zone → Add CNAME: <name>-docs → <project-name>.pages.dev (proxied)

4. Cloudflare Access (auth gate)

Cloudflare Zero Trust → Access → Applications → Add:

  • Type: Self-hosted
  • Application domain: <name>-docs.fueled.engineering
  • Policy: Allow → Emails ending in @fueled.com

This gates the entire site behind Google Workspace SSO. Add specific email addresses for client stakeholders.

Zensical config reference

Config lives in zensical.toml (TOML, under [project]) — Zensical's replacement for mkdocs.yml. The file ships heavily commented; edit it directly. The load-bearing, non-obvious settings:

Setting Value Why it matters
docs_dir "docs/_build" Points at the assembled tree, not raw docs/ — building straight from docs/ breaks the ADR section index + glossary tooltips (see How it works).
nav explicit TOML array Section → page tree; add pages here (see Adding pages).
site_url https://cslewis-docs.fueled.engineering/ Canonical URL in the HTML head.
[[project.theme.palette]] default + slate Light/dark toggle.

Build-critical Markdown extensions ([project.markdown_extensions.*]):

  • pymdownx.superfences with a mermaid custom fence — renders the diagrams in the design docs.
  • pymdownx.snippets auto_appends the generated _build/_includes/abbreviations.md — this powers the glossary tooltips below.
  • admonition / pymdownx.details — the Status — Live/Planned boxes.
  • attr_list + md_in_html — the grid cards on section-landing pages.

Enabled nav/UX features include navigation.instant(.prefetch), navigation.sections, navigation.indexes, navigation.path, navigation.top, navigation.tracking, content.code.copy/annotate/select, content.tooltips, and search.highlight; the rest are toggled in the commented features array. zensical.toml is the source of truth — don't re-list the full config here (that just drifts). Full option catalogue: https://zensical.org/docs/setup/.

Glossary tooltips

Domain terms from docs/glossary.md automatically render as hover tooltips across all pages. The build script parses the glossary table and generates _build/_includes/abbreviations.md during assembly — no manual sync needed.

To add a tooltip: just add a row to docs/glossary.md. Next build picks it up.

Section index pages

Sections with navigation.indexes enabled use an index.md as the section landing page. These live at:

  • docs/reference/index.md — Reference section landing
  • docs/guides/index.md — Guides section landing
  • docs/api/index.md — API reference landing, which also carries the shared conventions

Use Material's grid cards for visual navigation on these pages.

Agent instructions

When updating published docs under docs/, remember: - Run ./scripts/docs-build.sh build to verify no build errors - Add new pages to nav in zensical.toml - docs/_build/ is ephemeral — never edit files there directly - HTML files in docs/ pass through as-is

.context/ is internal-only — it is not assembled into the site or deployed, so these steps (and the docs-deploy trigger) don't apply to it.