Update Documentation
How to publish documentation changes to https://docs.eblu.me.
Quick Release
After merging documentation changes to main:
- Go to Actions > Build BlumeOps > Run workflow
- Select version bump type (patch/minor/major) or enter a specific version
- The workflow builds, releases, and deploys automatically
Direct link: https://forge.eblu.me/eblume/blumeops/actions?workflow=build-blumeops.yaml
What the Workflow Does
The build-blumeops workflow (.forgejo/workflows/build-blumeops.yaml):
- Resolves version — Uses input or auto-increments from latest release
- Builds changelog — Runs towncrier on the runner to update
CHANGELOG.md - Builds docs — Calls
dagger call build-docs(Quartz build in a container) - Creates release — Uploads
docs-<version>.tar.gzto Forgejo releases
The workflow ends at the release. Deploying is a manual step (docs are served
natively by Caddy on indri since retire-minikube — no ArgoCD app): bump
docs_version in ansible/roles/docs/defaults/main.yml, then
mise run provision-indri -- --tags docs, and purge the flyio-proxy nginx
cache (fly ssh console -a blumeops-proxy -C "sh -c 'rm -rf /tmp/cache && nginx -s reload'")
so the new docs are served immediately.
Changelog Fragments (Towncrier)
When making changes, add a changelog fragment to docs/changelog.d/:
# Format: <identifier>.<type>.md
# Types: feature, bugfix, infra, doc, ai, misc
# Using branch name (preferred)
echo "Add new feature X" > docs/changelog.d/my-feature.feature.md
# Orphan fragment (when no branch fits)
echo "Fix bug Y" > docs/changelog.d/+fix-bug.bugfix.mdFragments are automatically collected into CHANGELOG.md (at repo root) during release.
Fragment types:
| Type | Description |
|---|---|
feature | New features |
bugfix | Bug fixes |
infra | Infrastructure changes |
doc | Documentation updates |
ai | AI assistance changes |
misc | Other changes |
Runner Environment
The workflow runs on the indri label, served since retire-minikube phase 6
by the host-mode forgejo-runner on indri (configure-launchd-runner):
- Runner: native LaunchAgent on indri, managed by the
forgejo_runneransible role (no Kubernetes, no job container) - Toolchain: jobs run directly with indri’s mise toolchain (Node.js, uv/Python, dagger, …); the
k8scompat label was dropped once workflows repo-wide moved toruns-on: indri - Build engine: the dagger CLI (mise-pinned in the
forgejo_runnerrole) drives the Dagger engine container in indri’s Docker Desktop
Quartz Static Site Generator
Quartz builds the documentation into a static site with:
- Wiki-link support (
[[page]]syntax) - Backlinks panel showing what references each page
- Graph view of document connections
- Full-text search
Configuration files (in docs/):
quartz.config.ts- Site metadata, plugins, themequartz.layout.ts- Page layout components
Quartz is cloned fresh during each build (not vendored) to use the latest version.
Manual Build (Local)
To test docs locally without triggering a release:
# Build docs tarball (identical to CI)
dagger call build-docs --src=. --version=dev export --path=./docs-dev.tar.gz
# Inspect the output
tar tf docs-dev.tar.gz | head -20
# Debug a Quartz build failure interactively
dagger call --interactive build-docs --src=. --version=devTroubleshooting
Workflow fails on “Resolve version”:
- Check if the version already exists as a release
- Ensure version format is
vX.Y.Z
Docs not updating after deploy:
- Confirm
docs_versionwas bumped inansible/roles/docs/defaults/main.ymland the provision ran - Check the installed version sentinel:
ssh indri 'cat ~/blumeops/docs/.installed-version' - If stale content is served publicly, purge the flyio-proxy cache (see above)
Towncrier not finding fragments:
- Fragments must be in
docs/changelog.d/ - Must have
.mdextension - Must match pattern
<name>.<type>.md