Maintaining this site¶
This page explains how the documentation site is built and how to change the settings that are most likely to need adjusting.
How it works¶
The site is a MkDocs + Material
build, generated directly from the literate .lagda.md sources β there is no
separate copy of the documentation. The decision record is
ADR-007; the moving parts are:
mkdocs.yml(repo root) β the site configuration: theme, colours toggle, plugins, Markdown extensions, navigation behaviour. Most settings live here.scripts/python/mkdocs_gen_library.pyβ runs during every build and mounts the library: for eachsrc/**/*.lagda.mdit writes a site page at a clean URL (src/Setoid/Algebras/Basic.lagda.mdβ/Setoid/Algebras/Basic/), and it generatesSUMMARY.md, the file that becomes the whole navigation.agda --htmlβ when the highlighted build is requested, Agda renders each module's code blocks to classed, hyperlinked HTML.mkdocs_gen_library.pyembeds that; if it is absent, code blocks fall back to plain monospace.scripts/python/mkdocs_hooks.pyβ rewrites repo-relative prose links (src/β¦,docs/adr/β¦,CONTRIBUTING.md) into site URLs, and prints the per-page build log.docs/_links.mdβ a library of reference-style links ([Setoid.Algebras.Basic][]) appended to every page so cross-references resolve. Its module half is generated byscripts/python/gen_links.py; re-run that after adding modules.docs/stylesheets/custom.cssβ all the bespoke styling: the Agda token colours, the modern "Aurora" theme, and the landing-page components.docs/assets/js/agda-copy.jsβ adds a copy button to the highlighted<pre class="Agda">blocks (Material's own copy button only covers its.highlightblocks, which theagda --htmloutput is not).docs/assets/js/agda-toggle.jsβ the header's "Show more Agda" control (#431). Module sources wrap their leading OPTIONS/module/import scaffolding in<!-- β¦ -->comments;mkdocs_gen_library.pyre-surfaces those blocks taggedhidden-source, and this control shows or re-hides them all at once, with the choice persisted inlocalStoragelike the palette toggle.
Hiding a module's import scaffolding¶
Every module's leading scaffolding block β the OPTIONS pragma, the module β¦ where header, the imports, and the private variable declarations β is wrapped in an HTML comment in the .lagda.md source:
<!--
```agda
{-# OPTIONS --cubical-compatible --exact-split --safe #-}
module Setoid.Homomorphisms.Noether where
open import Level using ( Level )
-- β¦ the rest of the imports β¦
```
-->
Agda still type-checks the block (fenced agda code inside an HTML comment is still code), GitHub's Markdown renderer collapses it, and on the site it becomes a toggleable hidden-source block, revealed either by the header's "Show more Agda" control (all blocks, persisted) or by the small βΈ hidden code (n lines) note that agda-toggle.js places in front of each hidden block (that block only). When the scaffolding shares its fence with real definitions, split the fence and wrap only the scaffolding part. New modules should follow the same convention.
The wrapper must be an HTML comment rather than any indenting construct: Agda requires its code at column 0, so a block can never be indented into a ??? note admonition or a Markdown-nested <details> β indenting the fence breaks type-checking. The comment wrapper adds no indentation, which is exactly why issue #431 settled on this mechanism.
Two kinds of module are deliberate exceptions:
- Pedagogical modules whose scaffolding is the subject of the surrounding prose stay fully unwrapped:
Overture.Basic(which explains theOPTIONSpragma, modules, and imports) andDemos.HSP(the TYPES 2021 paper, which discusses its imports in the text). - Barrel modules stay unwrapped too: a barrel's annotated
open import β¦ publiclist is the page's content, and hiding its only block would leave a blank page that reads as unfinished.
As a tripwire against accidentally wrapping a barrel, the build logs a β <Module>: every code block on this page is hidden line for any page that would render code-free. Three prose-first pages hide their lone OPTIONS/module block by design and are exempt from that check: Overture.Preface, Demos.GeneralOperationsAndRelations, and Setoid.Complexity.Basic (PROSE_ONLY_MODULES in mkdocs_gen_library.py).
Build commands¶
Run these inside nix develop (the MkDocs toolchain is pinned in flake.nix):
| Command | What it does |
|---|---|
make site |
Fast build to ./site. Code blocks are plain (no Agda pass). |
make serve |
Fast live preview at http://127.0.0.1:8000. |
make site-full |
make html + make agda-md + make site β the published site, with token highlighting + the /classic/ site. This is what CI builds. |
make serve-full |
The full preview (highlighting + /classic/), live-reloading. |
make html |
Just the classic clickable-HTML site (Everything.html index) into ./html. |
make agda-md |
Just the highlighted-Markdown pass into .agda-html/md. |
Seeing the real thing locally
make serve is fast but renders plain code blocks (and /classic/ 404s),
because the agda --html passes are skipped. Use make serve-full to
preview exactly what gets deployed.
Recovering a stuck Pages deployment¶
Publishing is a two-repository chain: the Docs workflow here builds ./site and pushes it to the gh-pages branch of universalalgebra/agda-algebras, and GitHub's auto-generated pages-build-deployment workflow in that repository publishes the branch to the live site. The last hop occasionally fails with a transient Deployment failed, try again later, and a failed run can wedge in queued when re-run. Recovery steps, in escalating order:
- Check for a platform incident at githubstatus.com; this error is almost always GitHub-side, and waiting often suffices.
- Re-run the failed
pages-build-deploymentrun from the Actions tab ofuniversalalgebra/agda-algebras. - Re-run the Docs workflow here (Actions β Docs β Run workflow). Note this re-triggers publication only when the rebuilt site differs from what is already on
gh-pagesβ the publish action skips the push when nothing changed, so an unchanged same-day rebuild is a no-op. -
Force a fresh deployment with an empty commit, which always re-triggers the publisher:
git clone --branch gh-pages --depth 1 [email protected]:universalalgebra/agda-algebras.git ua-pages cd ua-pages git commit --allow-empty -m "retrigger Pages deployment" git push
Merging any content change to master also re-pushes gh-pages and re-triggers publication as a side effect. When checking what is actually live, remember the Pages CDN caches responses for up to ten minutes and your browser caches the HTML and CSS on top of that β hard-refresh, or probe a file headers-only with curl -sI https://agda-algebras.universalalgebra.org/assets/js/agda-copy.js.
The site's own CSS/JS are content-hashed so that a returning visitor never renders fresh HTML against a stale-cached stylesheet or script (the assets carry a multi-hour max-age, far longer than the HTML's ten minutes). on_config in scripts/python/mkdocs_hooks.py appends an eight-character hash of each extra_css / extra_javascript file to its URL (custom.css?h=β¦); a changed asset therefore gets a fresh URL, which the short-lived HTML picks up within minutes (#429). The copied file keeps its plain name β only the reference carries the query β so the headers-only probe above is unaffected.
Resist the temptation to add a deployment workflow to the gh-pages branch itself: that branch is disposable build output which the publish action overwrites, and keeping such a file alive would require keep_files: true, which never deletes anything and so leaks renamed or removed pages onto the live site forever.
Changing the settings¶
Colours and the theme¶
The active palette is Aurora (indigoβviolet chrome, orange accent), a set of
CSS variables in docs/stylesheets/custom.css under
Β§6. Each colour scheme (light default, dark slate) has its own block; the
--ualib-* aliases below the Material variables drive the bespoke components
(hero gradient, stat numbers, matrix header, the β marks). To shift the accent,
for example, edit:
[data-md-color-scheme="default"] {
--md-primary-fg-color: #4f46e5; /* header / chrome (indigo-violet) */
--md-accent-fg-color: #fb6a00; /* hover / accent (vivid orange) */
--md-typeset-a-color: #5b54e6; /* links */
--ualib-board: #201f4d; /* hero gradient, indigo base */
--ualib-board-2: #4a2f86; /* hero gradient, violet top */
}
Two alternate palettes ship ready to drop in β replace both scheme blocks in
Β§6 with one of these to retheme the whole site:
- Cobalt (blue-led, the calmest): light
--md-primary-fg-color: #2f37c9,--ualib-board: #1c2348/--ualib-board-2: #2b3470, accent#f97316, links#3055e6; dark navy surfaces#0e1322. - Ultraviolet (violet-led, the boldest): light
--md-primary-fg-color: #6d28d9,--ualib-board: #241a45/--ualib-board-2: #3a2570, accent#f97316, links#7c3aed; dark purple-black surfaces#120e1f.
The code-block palette¶
The Agda token colours (used by both code blocks and inline prose terms) are
in Β§2 of custom.css, with one block per scheme; the code-block background
is in Β§4. These are independent of the chrome palette above, so changing one
never disturbs the other.
- Light is the classic-vivid (formal-ledger) palette β it already matches Aurora's blue/purple/orange, so it is usually left alone.
- Dark is the bespoke Aurora Deep palette: a deep-indigo ground with orange keywords (echoing the hero accent) and indigo functions/modules (matching the links), so code reads as part of the theme.
To swap the dark palette, replace the [data-md-color-scheme="slate"] block in
Β§2 and the slate --md-code-bg-color in Β§4. Two cooler alternates are
ready to paste in (a user-facing in-page palette switcher would be possible but
is intentionally not built β it competes with the light/dark toggle for little
gain; a one-block edit here is the supported way to retheme):
/* TOKYO NIGHT β cool navy, violet keywords, cyan types. */
[data-md-color-scheme="slate"] { --md-code-bg-color: #1a1b2e; --code-accent: #7aa2f7;
.AgdaKeyword, pre.Agda .Keyword { color: #bb9af7; }
.AgdaComment, pre.Agda .Comment { color: #565f89; font-style: italic; }
.AgdaString, pre.Agda .String { color: #9ece6a; }
.AgdaNumber, pre.Agda .Number { color: #ff9e64; }
.AgdaSymbol, pre.Agda .Symbol { color: #89ddff; }
.AgdaArgument, pre.Agda .Argument, .AgdaMarkup, pre.Agda .Markup,
.AgdaBound, pre.Agda .Bound, .AgdaGeneralizable, pre.Agda .Generalizable { color: #c0caf5; }
.AgdaPrimitiveType, pre.Agda .PrimitiveType, .AgdaPrimitive, pre.Agda .Primitive,
.AgdaDatatype, pre.Agda .Datatype, .AgdaRecord, pre.Agda .Record { color: #2ac3de; }
.AgdaInductiveConstructor, pre.Agda .InductiveConstructor,
.AgdaCoinductiveConstructor, pre.Agda .CoinductiveConstructor { color: #ff9e64; }
.AgdaField, pre.Agda .Field { color: #73daca; }
.AgdaFunction, pre.Agda .Function, .AgdaMacro, pre.Agda .Macro,
.AgdaPostulate, pre.Agda .Postulate { color: #7aa2f7; }
.AgdaModule, pre.Agda .Module { color: #7dcfff; }
}
/* NORD β desaturated frost; the calmest. */
[data-md-color-scheme="slate"] { --md-code-bg-color: #242a3d; --code-accent: #88c0d0;
.AgdaKeyword, pre.Agda .Keyword { color: #81a1c1; }
.AgdaComment, pre.Agda .Comment { color: #667089; font-style: italic; }
.AgdaString, pre.Agda .String { color: #a3be8c; }
.AgdaNumber, pre.Agda .Number, .AgdaField, pre.Agda .Field { color: #b48ead; }
.AgdaSymbol, pre.Agda .Symbol { color: #9aa6c4; }
.AgdaArgument, pre.Agda .Argument, .AgdaMarkup, pre.Agda .Markup,
.AgdaBound, pre.Agda .Bound, .AgdaGeneralizable, pre.Agda .Generalizable { color: #d8dee9; }
.AgdaPrimitiveType, pre.Agda .PrimitiveType, .AgdaPrimitive, pre.Agda .Primitive,
.AgdaDatatype, pre.Agda .Datatype, .AgdaRecord, pre.Agda .Record { color: #8fbcbb; }
.AgdaInductiveConstructor, pre.Agda .InductiveConstructor,
.AgdaCoinductiveConstructor, pre.Agda .CoinductiveConstructor { color: #d08770; }
.AgdaFunction, pre.Agda .Function, .AgdaMacro, pre.Agda .Macro,
.AgdaPostulate, pre.Agda .Postulate, .AgdaModule, pre.Agda .Module { color: #88c0d0; }
}
Fonts¶
All three families are self-hosted under docs/assets/fonts/ (no font CDN),
declared as @font-face at the top of custom.css:
- headings β Space Grotesk (a geometric grotesque), via the single
--ualib-displayvariable in:root. Change every heading, the hero title, the stat numbers, and the matrix header in one line by setting--ualib-displayto"Geist"or"Sora"(both already self-hosted) β or add a new@font-faceand name it there. - body β Inter (
--md-text-font). - code β JuliaMono (
--md-code-font), the one font still CDN-loaded, for its complete mathematical-Unicode coverage.
The logo and favicon¶
Both point at docs/assets/lambda.png via theme.logo and theme.favicon in
mkdocs.yml. Drop a replacement PNG at that path (a transparent background
looks best on the coloured header).
Navigation¶
The nav is generated, not hand-written. The library tree comes from the module
hierarchy automatically. The fixed top-level entries (Home, the Project
section) are defined in scripts/python/mkdocs_gen_library.py in the
SUMMARY.md assembly near the bottom β add or reorder lines there.
The landing page¶
docs/index.md is plain Markdown plus a few HTML blocks whose styling lives in
custom.css (Β§8βΒ§11):
- the hero (
.ualib-hero) β title, tagline, the formula, the buttons; - the stat strip (
.ualib-stats) β edit the four numbers inline; - the Featured results gallery (
.ualib-figures) β each card is one<a class="ualib-figure">; swap a monogram for a photo by replacing the<span class="ualib-portrait">GB</span>with<span class="ualib-portrait"><img src="/assets/portraits/birkhoff.jpg" alt="β¦"></span>; - the coverage matrix (
table.ualib-matrix) β a plain HTML table; add a row for a new structure, or a<td class="yes">β</td>for a new axiom.
Adding a prose page¶
Drop a Markdown file under docs/ and add a line to the SUMMARY.md assembly in
mkdocs_gen_library.py so it appears in the nav. Repo-relative links in the
prose (src/β¦, docs/β¦) are rewritten to site URLs automatically by the hook.
Reference links¶
To make [Some Name][] resolve everywhere, add a definition to the External
links section of docs/_links.md (or, for module links, just re-run
python3 scripts/python/gen_links.py).
Where things live¶
mkdocs.yml site config (theme, plugins, nav behaviour)
docs/
index.md the landing page
site-guide.md this page
_links.md shared reference-link library (generated + external)
stylesheets/custom.css all bespoke styling
assets/ logo, favicon, portraits, vendored JS
adr/ architecture decision records
scripts/python/
mkdocs_gen_library.py mounts src/ as pages + builds the nav
mkdocs_hooks.py link rewriting + per-page build log
gen_links.py regenerates the module half of _links.md
.github/workflows/docs.yml build (make site-full) + deploy to gh-pages