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/.

Per-entity docs (Themes, Passages, Journeys, …)

Each domain entity gets a folder under docs/ — an index.md plus, as they gain real content, api-guide.md (client / API devs) and editor-guide.md (CMS editors):

  • The index.md concept overview always exists; it is the entity's nav leaf.
  • Add api-guide.md / editor-guide.md only when they carry real content, and nav them at that point. Never nav an empty stub — a dead-end page is worse than none.
  • Until a guide exists, index.md signposts it (a one-liner: "API/editor docs land here as ships — see the design doc").

An entity's file count therefore tracks build maturity (Themes has all three; Journeys just the overview) while the structure stays uniform. Split the overview into guide files as each audience's content outgrows one page — never pre-create empty ones.

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/design/index.md — Data Model & API section landing
  • docs/guides/index.md — Guides section landing

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.