Documentation site¶
Every project has a documentation site: Markdown in docs/, built with Material for MkDocs, published to GitHub Pages from main, with its own design. The README stays short (what it is, how to install, a link to the site); how to use it lives in docs/, once. Decided 2026-10-30.
Why¶
Docs split between a long README and a site drift apart. One place, built with --strict, catches broken links before they ship, and the site gives the values page, the roadmap and the ADRs a home that people actually read.
How¶
mkdocs.ymlat the root:site_name,site_description,site_url: https://<repo>.marceltov.de/,repo_url,edit_uri: edit/main/docs/, the license incopyright.- Theme:
material, fonts Atkinson Hyperlegible Next (text) and Atkinson Hyperlegible Mono (code), a light and a dark palette with a toggle, and the featuresnavigation.instant,navigation.footer,navigation.top,toc.follow,search.suggest,search.highlight,content.code.copy,content.action.edit. Its own colours and icon are required, see Design below. - Markdown extensions:
admonition,attr_list,md_in_html,tables,tocwith permalinks,pymdownx.details,highlight,inlinehilite,superfences(with amermaidfence where diagrams are used),tabbed. - Pinned:
mkdocs-material==9.7.7withmkdocs<2. MkDocs 2.0 drops the plugin and theme system, and Material 9 doesn't work with it. - Preview:
uvx --with mkdocs-material==9.7.7 --with 'mkdocs<2' mkdocs serve. Addsite/to.gitignore. -
Publish:
.github/workflows/pages.ymlbuilds withmkdocs build --stricton every pull request that touchesdocs/**ormkdocs.yml, and onmaindeploys withactions/upload-pages-artifactandactions/deploy-pages(permissionspages: write,id-token: write). Once per repository: Settings → Pages → Source: GitHub Actions, and the custom domain<repo>.marceltov.deunder Settings → Pages → Custom domain (a DNSCNAMEtomarceltov.github.io, then Enforce HTTPS). With the Actions deploy, the domain lives in the settings; noCNAMEfile is needed. -
Its own domain: every site is served at
<repo>.marceltov.de, and links to it use that address, nevermarceltov.github.io/<repo>, which only redirects. - README links are absolute (the docs site or GitHub), because the README is also shown on PyPI and npm, where links into the repository lead nowhere.
- The menu is grouped, as in passageway: Home and the values page, then sections such as Start, Guides, Reference, Contributing (development, roadmap) and Decisions (the ADRs). Each page's heading matches its menu entry. No flat list of every page.
Design¶
Each project's site has its own identity, drawn from what the project is about, not Material's default indigo. A reader should know which project they are in from the colour and the icon alone. Designed with the process of Anthropic's frontend-design skill: ground the design in the subject, plan tokens first, check the plan against generic defaults, then build and check screenshots.
- A small palette in
docs/stylesheets/extra.css, as CSS variables with a project prefix (--pw-*,--ml-*): an accent for links and the active page, a second colour for hover and focus, an ink for text and a mist for code, tables and the search field, each defined for light and dark. Material'sprimaryandaccentarecustom. - White pages and a hairline header: the header is the page colour with a 1px line, not a coloured bar. Dark mode has its own hue (
--md-hue) and backgrounds from the same family, not plain grey. - Its own icon as
docs/assets/icon.svg(ordocs/logo.svg), used aslogoandfavicon: a simple mark from the subject (passageway's archway, mcp-login-oauth's cobalt keyhole, freundebuch's orbit), checked on both the light and the dark header. - A home page that opens with what the project does: a short heading that says it, one paragraph, and one or two buttons to the first step. No feature grid, no stats.
- Atkinson Hyperlegible for text and code on every site, a touch larger and looser (
font-size: 0.82rem; line-height: 1.65). - One bold thing per site, everything else quiet: no gradients, card grids, shadows or animations as decoration.
- Check it before merging: build, serve and take screenshots in light mode, dark mode and at phone width.
- Diagrams follow Diagrams.
.github/workflows/pages.yml
name: Publish docs
on:
push:
branches: [main]
paths: ["docs/**", mkdocs.yml, .github/workflows/pages.yml]
pull_request:
paths: ["docs/**", mkdocs.yml, .github/workflows/pages.yml]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
# mkdocs<2: Material 9 isn't compatible with MkDocs 2.0.
- run: uvx --with mkdocs-material==9.7.7 --with 'mkdocs<2' mkdocs build --strict
- uses: actions/upload-pages-artifact@v3
with:
path: site
deploy:
if: github.event_name != 'pull_request'
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
Claude cloud sessions can't push workflow files (their GitHub connection lacks the workflow scope), so a session puts the workflow in the pull request description and a person adds it.
Rules out¶
- Usage docs in the README as well as on the site.
- Relative links in a README that ships to a package registry.
- A flat menu, or menu entries that don't match the page headings.
- A docs build without
--strict. - Unpinned MkDocs or Material.
- Material's default palette and icon, or one project's palette copied to another.
- Decoration that carries no information: gradients, card grids, shadows, entrance animations.
- Merging a design change without screenshots in light and dark mode.
Reference¶
passageway (palette, archway logo, hero, header links for agents); freundebuch (its own colours and orbit icon); mcp-login-oauth (cobalt keyhole); this repository.