Files
docs/publishing
inference-bot 62158c16cc docs site: add MkDocs publishing layer (build, deploy, push-to-main webhook)
Renders the repository's Markdown (which stays where it is) into a
member-readable static site with Material for MkDocs: co-op brand colours
and logo, self-hosted OFL Figtree, offline search, no external hosts.

- publishing/build.sh   stage .site-src, render .site-build (mkdocs --strict)
- publishing/deploy.sh  write the build into the Surfer app container
- publishing/webhook-receiver.py + .service   Gitea push hook on main
                        triggers pull -> build -> deploy (agent host, no new
                        Cloudron app)
2026-11-03 19:26:21 +00:00
..

Publishing the documentation site

The Markdown in this repository is the single source of truth. This directory is the publishing layer that turns it into a member-readable static site and puts it on the co-op's Surfer app. Documents are never edited here — a change to a document is a normal commit or pull request against the Markdown at the repository root.

What is built

File Purpose
../mkdocs.yml Site configuration (MkDocs + Material for MkDocs)
brand.css Co-op palette + self-hosted Figtree webfont (SIL OFL 1.1)
fonts/ Figtree woff2 files and the OFL licence text
logo.svg Co-op logo (shared with the website repo)
build.sh Stage the Markdown into .site-src/, render to .site-build/
deploy.sh Push the build into the Surfer app container
webhook-receiver.py Gitea webhook → pull → build → deploy (agent host)
webhook-receiver.service systemd unit for the receiver
requirements.txt Pinned Python build toolchain

Nothing external is loaded by the site: no CDN, no third-party font service. Fonts are served from this repository's own output.

Build

publishing/build.sh          # creates .venv-docs on first run

Output lands in .site-build/ (gitignored). mkdocs build --strict is what CI-style runs should use, so broken links fail the build.

Deploy

CLOUDRON_TOKEN=... publishing/deploy.sh

Writes the build into the Surfer app (Cloudron app inference.coop) at:

Both are written so the site stays reachable either way; the hostname is the canonical one.

Automatic rebuilds (push to main)

A push to main on co-op/docs fires a Gitea webhook (repo settings → webhooks) to the receiver on the agent host, which pulls, rebuilds and redeploys. On the agent host:

sudo cp publishing/webhook-receiver.service /etc/systemd/system/docs-deploy-webhook.service
sudo systemctl daemon-reload && sudo systemctl enable --now docs-deploy-webhook
tail -f /home/ubuntu/docs-deploy.log        # what the receiver is doing

The receiver authenticates webhooks with an HMAC-SHA256 shared secret (DEPLOY_WEBHOOK_SECRET in the agent host's env file) and only accepts pushes to main of co-op/docs from the Cloudron box. Woodpecker CI (Cloudron catalog) could do the same job inside Cloudron, at the cost of running another app; the receiver was chosen because it adds no new Cloudron app.

Each deploy writes meta.json into the site with the commit it was built from, so a deploy can be verified from the served site itself: https://docs.inference.coop/meta.json