Build pipeline

The docs site is built through a three-stage pipeline: discover → validate → build. The same pipeline runs locally (via Compose) and in CI (via Forgejo Actions with Buildah), using identical tooling packaged in the docs-builder image.

Pipeline stages

1. Discover and mount (hugo-mounts-helper)

hugo-mounts-helper scans sibling repos at ../* for docs/ directories and generates build/mounts.toml — a Hugo module mounts configuration that overlays external content into the site’s virtual content/ tree.

Config: config/hugo-mounts-helper.yaml

Fixed mounts map local sources into Hugo’s mount namespace:

SourceTargetPurpose
site/contentcontentHand-written content from this repo
build/contentcontentGenerated _index.md files for category grouping
site/layoutslayoutsTemplate overrides and shortcodes
site/assetsassetsCSS, JS, images

Discovered mounts are added dynamically per sibling repo. Standard Diátaxis categories (explanation/, guides/, reference/, research/, tutorials/) are mapped directly. The decisions/ category is special: ADRs are grouped by their category frontmatter field (e.g., bootstrap/docs/decisionscontent/decisions/architecture), and _index.md files are generated under build/content/decisions/ for each group.

2. Validate (smadr-validator)

smadr-validator finds all ADR files across discovered sources and validates them against:

  • A JSON schema (internal/smadrvalidator/schemas/dataverket-policy.schema.json)
  • Organizational rules: allowed projects, categories, statuses, required sections, filename patterns, duplicate detection

Config: config/smadr-validator.yaml

In the build entrypoint (compose/docs-builder/docs-builder.sh), the validator runs in --mode advisory — warnings are printed but don’t fail the build.

CI adds a separate strict validation step before the full site build so blocking ADR issues fail the pipeline before Hugo runs.

3. Build (hugo)

Hugo builds the static site using a merged config:

  • config/hugo.toml — base config (theme, Kroki endpoint, output formats)
  • config/hugo.ci.toml — CI overlay (adjusts Kroki endpoint for service networking)
  • build/mounts.toml — generated module mounts from step 1

Output goes to build/public/. The Relearn theme and Kroki Hugo module are vendored under _vendor/.

Kroki runs as a sidecar service (Compose service kroki + mermaid) and renders diagram code blocks inline during the Hugo build.

Entrypoint

All three stages are sequenced by compose/docs-builder/docs-builder.sh, which is the default CMD of the docs-builder image:

hugo-mounts-helper → smadr-validator → hugo --minify

Images

ImageBaseContents
docs-builderhugomods/hugo:base-0.160.0Hugo + 3 Go tools, docs-builder entrypoint

The builder image is a multi-stage build: a Go stage compiles the three CLI tools, then copies them into the Hugo base image. Hugo modules are pre-vendored so the final image doesn’t need Go.

Local development

task build              # full pipeline inside docs-builder container
task dev                # dev server with livereload (watches for changes)
task start              # build once and serve in background via Caddy

The dev task starts dev-reload-notifier (an SSE server) alongside Caddy with Caddyfile.dev, then watches source files and rebuilds automatically. After each rebuild it fires a livereload trigger so the browser refreshes.

CI pipeline

Defined in .forgejo/workflows/docs-site-pipeline.yaml:

  1. verify-go — runs go test, go vet, and go build across cmd/ and internal/
  2. build-toolchain — builds and pushes the docs-builder image using Buildah
  3. build — discovers sibling org repos (those with a .docs.yaml marker), clones them, runs strict ADR validation, then runs the full build inside the toolchain image

Separate workflows handle toolchain image publishing (docs-builder-image.yaml) and container security scanning (docs-container-scan.yaml).

Deployment

MethodCommandDescription
Composetask startBuild once, Caddy serves build/public/
Compose (dev)task devLive-reload mode with Caddyfile.dev
Codeberg Pagestask deploy:codebergPushes build/public/ to the pages repo over SSH
Tilttask tilt:upWatches sources, live_update syncs into Caddy pod