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¶
scripts/docs-build.shassemblesdocs/intodocs/_build/- Zensical reads
zensical.toml(docs_dir = "docs/_build") and producessite/ - GH Action (
.github/workflows/docs.yml) deployssite/to Cloudflare Pages on every push tomain - Cloudflare Access gates the site with Google Workspace SSO (
@fueled.com)
Both docs/_build/ and site/ are gitignored.
Adding pages¶
- Add your
.mdfile underdocs/ - Add a nav entry in
zensical.toml(nav = [ … ]) under the appropriate section - 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.mdconcept overview always exists; it is the entity's nav leaf. - Add
api-guide.md/editor-guide.mdonly 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.mdsignposts it (a one-liner: "API/editor docs land here asships — 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¶
- In Cloudflare Pages → your project → Custom domains → Add (e.g.
<name>-docs.fueled.engineering) - In Cloudflare DNS →
fueled.engineeringzone → 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.superfenceswith amermaidcustom fence — renders the diagrams in the design docs.pymdownx.snippetsauto_appends the generated_build/_includes/abbreviations.md— this powers the glossary tooltips below.admonition/pymdownx.details— theStatus — Live/Plannedboxes.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 landingdocs/design/index.md— Data Model & API section landingdocs/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.