Docs site¶
This page is the meta-doc — how the docs site itself is built, hosted, and kept in sync between repos.
What you're looking at¶
The site at https://docs.tomoda.life is a federated MkDocs build pulling from two repos:
tomoda-labs/tomoda(this repo) — app + architecture + frontend + backend + style guide docstomoda-labs/devops— infrastructure, operations, observability, security docs (rendered under/devops/)
The federation uses mkdocs-monorepo-plugin configured in mkdocs.yml:
plugins:
- monorepo
nav:
# ... tomoda nav entries ...
- DevOps: '!include devops/mkdocs.yml'
The plugin reads devops/mkdocs.yml at build time, merges its nav into the parent site, and resolves all the linked pages.
How devops/ lives in this repo — submodule + sparse checkout¶
devops/ is a git submodule tracking tomoda-labs/devops main:
# .gitmodules
[submodule "devops"]
path = devops
url = git@github.com:tomoda-labs/devops.git
branch = main
But we only need the docs from devops, not the whole repo (which also contains infrastructure/, k8s/, scripts/, etc.). The submodule uses sparse checkout to materialise only docs/ + mkdocs.yml on disk. The rest lives in .git/objects but never appears in the working tree.
Sparse-checkout config (set automatically by task docs:update):
docs/*
/mkdocs.yml
If you ever want to see the full devops repo in your local checkout (e.g., to debug a build issue):
git -C devops sparse-checkout disable
# devops/infrastructure/, k8s/, scripts/, etc. appear
git -C devops sparse-checkout reapply
# back to docs-only
Local workflow¶
After cloning fresh:
# First time only — clones the submodule + installs Python toolchain
task docs:install
# Daily: serve docs locally with hot reload at http://localhost:8000
task docs
# Or: build the static site into ./site/
task docs:build
Both task docs and task docs:build run task docs:update as a dependency, which:
- Runs
git submodule update --init --remote --recursive devops— pulls the latest commit fromtomoda-labs/devopsmaininto the submodule. - Re-applies sparse checkout (in case
mkdocs.ymlreferences a new top-level file you haven't synced yet). - Prints the short SHA of the synced devops commit so you know what you're previewing.
If you've been editing devops docs locally in a sibling ~/workspace/devops/ checkout, those edits won't appear in the federated build until you git push them to main. The submodule pulls from GitHub, not from a sibling directory. To preview unpushed devops docs:
- Option A: push to a feature branch in devops, temporarily point the submodule at that branch (
git -C devops checkout feature/foo), then runtask docs. Don't commit the submodule pointer change unless you actually want the docs site to track that branch. - Option B: run
task docsinside the devops repo itself — that uses devops's localtask docs:build, which previews just the devops docs without federation.
Hosting¶
The federated site is hosted on Cloudflare Pages with Cloudflare Access gating via GitHub OAuth:
git push to either repo's main
│
├─► tomoda push: Pages auto-rebuilds (native git webhook)
└─► devops push: GitHub Action POSTs to Pages deploy hook → rebuild
│
▼
Cloudflare Pages
├─► git clone tomoda (with submodule update --init --remote)
├─► sparse-checkout devops to docs/* + /mkdocs.yml
├─► pip install -r docs/requirements.txt
├─► mkdocs build
└─► publish site/ → docs.tomoda.life
│
▼
Cloudflare Access (GitHub OAuth IdP, restricted to tomoda-labs org)
│
▼
User in a browser
End-to-end deploy time after a push is ~1-2 minutes.
Auto-deploy on devops push¶
Cloudflare Pages rebuilds on any push to the tomoda repo's main natively. To also rebuild when devops main changes, the devops repo has a workflow at .github/workflows/notify-docs-pages.yml that POSTs to a Cloudflare Pages deploy hook URL. The hook URL is stored as a repo secret (PAGES_DEPLOY_HOOK) in devops.
Workflow runs on the self-hosted ARC runners (runs-on: tomoda-arc). One curl POST, ~5s of compute. If ARC runners are offline, the workflow queues but the actual Pages rebuild doesn't fire — devops pushes won't refresh the live site until ARC is reachable. Tomoda pushes are unaffected.
Cloudflare Pages build configuration¶
In the Pages project settings:
| Setting | Value |
|---|---|
| Production branch | main |
| Build command | git submodule update --init --remote --recursive && git -C devops sparse-checkout set --no-cone 'docs/*' '/mkdocs.yml' && pip install -r docs/requirements.txt && mkdocs build --strict |
| Build output directory | site |
| Root directory | / |
| Environment variables | PYTHON_VERSION=3.12 |
The submodule clone uses the GitHub access token Cloudflare Pages provisions when you connect the project (Pages is granted read access to private repos in the same org).
Auth — Cloudflare Access¶
Access policy on docs.tomoda.life:
- Identity provider: GitHub (Cloudflare Access has GitHub as a built-in IdP; one-time OAuth setup)
- Include rule:
GitHub organizations → tomoda-labs - Action: Allow
- Session: 24h
External contributors who need access just need to be added to the tomoda-labs GitHub org (or to specific teams within it, if you ever want tighter scoping).
Troubleshooting¶
"devops dir is empty after clone" — run task docs:update (or git submodule update --init --remote --recursive). Submodules don't auto-clone on a plain git clone.
"my devops doc change isn't appearing in task docs" — the submodule pulls from devops/main on GitHub, not a local sibling. Push your devops change to a branch + point the submodule at that branch temporarily, or run task docs inside the devops repo for an isolated preview.
"mkdocs complains about missing files in devops/" — sparse checkout may be hiding something. Run git -C devops sparse-checkout list to see what's materialised. If devops's mkdocs.yml was updated to reference a new top-level file (other than docs/* or /mkdocs.yml), add it to the sparse-checkout pattern in Taskfile.yml::docs:update.
"Pages build fails on the submodule clone" — usually means Pages doesn't have permission to read the devops repo. Verify the Pages project is connected to the tomoda-labs GitHub org with read access to both repos.
Related¶
mkdocs.yml— federation config (!include devops/mkdocs.yml)Taskfile.yml—docs,docs:build,docs:update,docs:install,docs:cleantasks.gitmodules— submodule definition fordevops/trackingmain- DevOps repo's
docs/operations/bootstrap.md— Cloudflare account setup that the Pages project lives under