Shared documentation tooling for cloudboss project docs. It keeps the look in one place so every project's docs match, and publishes them the same way: versioned, with a version dropdown, served from S3 behind CloudFront.
The tooling uses Material for MkDocs and mike. Search is Material's builtin offline index, so there is no external search service to depend on.
cloudboss_docs/theme/: A MkDocs theme namedcloudbossthat extendsmaterialand bakes in the look: Cantarell, the cloudboss palette, the header logo size, callout treatment, and optional Google Analytics. The CSS is injected by the theme itself, so a project needs no styling of its own.unobin/: A Go module withcmd/docgen, a generator for Unobin library reference pages.pyproject.toml: Packages the theme and declares its direct dependencies.requirements.txt: Every dependency, direct and transitive, pinned to an exact version for reproducible builds..github/workflows/docs.yml: A reusable workflow a project's release job calls to build and publish.
Install the pinned toolchain and the theme straight from git -- the lockfile is fetched by URL, and --no-deps on the theme keeps the pinned versions intact:
pip install -r https://raw.githubusercontent.com/cloudboss/cloudboss-docs/main/requirements.txt
pip install --no-deps "git+https://github.com/cloudboss/cloudboss-docs"Give the project a mkdocs.yml that selects the theme. A theme can't set top level config, so the Markdown extensions, plugins, and the mike version provider live here.
Copy this block verbatim and fill in the project's own site_name, site_url, repo_url, nav, and logo:
site_name: myproject
site_url: https://cloudboss.co/docs/myproject/ # Served from S3/CloudFront under /docs/<repo>/.
repo_url: https://github.com/cloudboss/myproject
repo_name: cloudboss/myproject
copyright: Copyright (c) 2026 cloudboss
theme:
name: cloudboss
logo: assets/logo.svg # A transparent-background SVG under docs/assets/.
favicon: assets/logo.svg
markdown_extensions:
- admonition
- tables
- toc:
permalink: true
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.inlinehilite
- pymdownx.superfences
plugins:
- search
extra:
google_analytics_property: G-XXXXXXXXXX
version:
provider: mike
default: latest
nav:
- Introduction:
- Overview: index.mdSet extra.google_analytics_property to a GA4 measurement ID when the docs should report analytics. Omit it for docs that should not use analytics.
Put handwritten prose under the project's docs/. Reference pages can be generated from the project's own code (see below) and stored alongside.
From the project directory, install the pinned toolchain and serve:
pip install -r https://raw.githubusercontent.com/cloudboss/cloudboss-docs/main/requirements.txt
pip install --no-deps "git+https://github.com/cloudboss/cloudboss-docs"
mkdocs servemkdocs serve watches the project's docs/ and mkdocs.yml, but not the installed theme package, so edits to the shared theme need a server restart to show up.
Handwritten guides live in docs/. Reference pages, like CLI options or API references, are generated from the program itself, so they never drift from the build that produced them. For every project, it should expose one command that writes Markdown into its docs tree, and the build runs that for each release.
The generator is the project's own program, in whatever language and tooling is suitable for the project. Its job is to write Markdown into the docs tree, usually under docs/reference/. How it produces that Markdown is up to the project.
As one example, a Go project can walk its own command tree for a CLI reference and read its package comments through go/doc for an API reference. A project in another language does the equivalent with its own tools; nothing here assumes Go or any particular CLI library.
Unobin libraries can use the shared generator from the unobin/ Go module:
go run github.com/cloudboss/cloudboss-docs/unobin/cmd/docgen@unobin/v0.1.0 \
--root . \
--out docs/referenceUse --alias only when the default alias derived from the module path is not
what the examples should show. For example, github.com/cloudboss/unobin-library-aws
defaults to aws. Use --package when the Library() function is in a package
below the repository root:
go run github.com/cloudboss/cloudboss-docs/unobin/cmd/docgen@unobin/v0.1.0 \
--root . \
--package s3 \
--module github.com/cloudboss/unobin-library-aws//s3 \
--alias aws-s3 \
--out docs/reference/s3A repository that publishes several Unobin libraries can generate one grouped
reference with --collection. The collection file is JSON:
{
"libraries": [
{
"title": "S3",
"package": "s3",
"module": "github.com/cloudboss/unobin-library-aws//s3",
"alias": "aws-s3"
},
{
"title": "EC2",
"package": "ec2",
"module": "github.com/cloudboss/unobin-library-aws//ec2",
"alias": "aws-ec2"
}
]
}go run github.com/cloudboss/cloudboss-docs/unobin/cmd/docgen@unobin/v0.1.0 \
--root . \
--collection docs-libraries.json \
--out docs/referenceThe grouped output writes reference/SUMMARY.md for mkdocs-literate-nav, with
one heading per library and nested resource, data source, action, and function
pages.
Enable the reference-page CSS only for Unobin library sites:
extra:
unobin_reference: true
version:
provider: mike
default: latestThe generator writes SUMMARY.md files for mkdocs-literate-nav, so keep the
plugin enabled when generated reference directories are listed in nav:.
When using the reusable workflow for a Unobin library, request Go setup before the generate step:
with:
setup-go: true
generate: go run github.com/cloudboss/cloudboss-docs/unobin/cmd/docgen@unobin/v0.1.0 --root . --out docs/referenceThe reusable GitHub workflow runs whatever shell command you pass as its generate input before the site is built, so use whatever the project already has: a Make target, a shell script, a language's own build runner. Run that same command locally before mkdocs serve so the generated pages are present.
with:
version: ${{ github.ref_name }}
generate: make docs-genList them in nav: by hand, or let them build themselves: have the generator also write a reference/SUMMARY.md, add the literate-nav plugin, and the section assembles from that. Generated output under docs/reference/ can be git-ignored, since the build recreates it.
If you would rather nothing generated ever lives in the tree, use the mkdocs-gen-files plugin: a small Python hook shells out to the program (for example myapp schema --json) and writes the pages virtually at build time. That needs mkdocs-gen-files added to the cloudboss-docs dependencies -- not included yet (mkdocs-literate-nav already is).
The docs serve at https://cloudboss.co/docs/<repo>/ from an S3 bucket behind CloudFront. mike builds the versioned tree on the project's gh-pages branch -- its version store -- and the workflow syncs that tree into the bucket under docs/<repo>/, then invalidates the CDN. Call the reusable workflow from the project's release job:
jobs:
docs:
permissions:
contents: write # mike pushes the gh-pages branch
id-token: write # assume the publisher role via OIDC
uses: cloudboss/cloudboss-docs/.github/workflows/docs.yml@main
with:
version: ${{ github.ref_name }}
generate: make docs-genThe workflow assumes an AWS role with GitHub OIDC, so no keys live in the repo. Three organization variables point it at the stack the github-docs factory provisions:
DOCS_PUBLISH_ROLE_ARN-- the publisher role (the factory'spublisher-role-arnoutput)DOCS_BUCKET-- the origin bucket (origin-bucket)DOCS_DISTRIBUTION_ID-- the distribution to invalidate (distribution-id)
mike adds the tag to the version dropdown and moves latest onto it. The site root redirects to latest.