Build-time and content capabilities that ship with every scaffolded site — as opposed to UI Bundle's site chrome, or Custom AsciiDoc components's authoring blocks. Grouped by what they’re for.
Authoring & content
Diagrams — Kroki
[mermaid], [plantuml], [graphviz], [bpmn], [excalidraw] and over a dozen more
diagram languages (see @inditextech/docouture-asciidoc-extensions’
`lib/kroki-config.js for the full, live-verified list) render as real diagrams via a
self-hosted Kroki service, enabled by default (kroki-enabled: true,
kroki-diagram-types in antora-playbook.yml — see
Antora Playbook). The service starts itself
automatically the first time a build needs it (Docker
required); docouture teardown kroki stops it, docouture eject kroki copies its
compose definition out for customization. Mermaid diagrams get this site’s own
theming baked in server-side.
The classic asciidoctor-diagram/asciidoctor-kroki positional shorthand works —
[plantuml,architecture,png] resolves target/format from position, same as
[plantuml,format=png] — alongside jpeg/pdf/base64 raster formats and a
txt/atxt/utxt text-rendering family (Kroki’s own ASCII-art-style output, no image
at all), each gated per diagram type against what Kroki’s own server actually accepts.
Any named attribute beyond the built-in set is forwarded to Kroki as a diagram-specific
option (e.g. [structurizr,view-key=SystemContext]). Without Docker, or with the
feature disabled, a diagram block renders as its own literal source text rather than
failing the build. role=zoom-in (also honored on a plain image:: block) adds a
click-to-zoom fullscreen overlay. Full syntax: Custom AsciiDoc components.
Syntax highlighting — Shiki
source-highlighter: shiki in antora-playbook.yml switches every code block from
Antora's own client-side default (highlight.js)
to build-time, static highlighting. `@inditextech/docouture-antora-extensions’
Shiki prewarm step builds the highlighter once up front rather
than per-block.
Changelog pages
Changelog's per-version sections are generated at build time from
code/CHANGELOG.md, not hand-copied: @inditextech/docouture-antora-extensions parses
every cut [x.y.z] section, converts its # Section headings and - [#PR](url)
text bullets to AsciiDoc, and appends each one as a == vX.Y.Z section directly onto
whatever page already lives at changelog/index.adoc — only on a site that has one; a
site with no changelog page is left untouched.
## [Unreleased] is handled differently from a real cut release: it never becomes a
== vX.Y.Z section (Keep a Changelog doesn’t consider "unreleased" a version either),
but its content still renders as a plain == Unreleased section — and only on the
component version Antora resolved as prerelease (the version built from main,
never itself tagged). Any real, tagged release’s own changelog page never shows it: a
tag is an immutable snapshot, and [Unreleased] is by definition whatever has landed
on main since. An empty [Unreleased] heading (nothing merged since the last cut)
renders no section at all rather than an empty one.
The file is read once per build, off disk, applied identically to every component
version being built — not resolved per-ref through git, so a real release tag’s own
changelog page reflects whatever code/CHANGELOG.md says on disk right now, not that
tag’s own historical copy of the file. In practice this only matters for the cut
releases: a tagged version’s page shows every ## [x.y.z] section on disk, no more and
no less, regardless of which ref cut it. Override the default code/CHANGELOG.md
location (resolved relative to the playbook’s own directory) with changelog_path on
the extension’s registration entry:
antora:
extensions:
- require: '@inditextech/docouture-antora-extensions'
changelog_path: ../code/CHANGELOG.md
Discovery & search
Full-text search
@inditextech/docouture-antora-extensions builds a search index at build time,
published per component version, that the UI bundle’s search dialog reads directly
(UI Bundle). No manual wiring — registering the extension is enough.
AI ingestion — llms.txt
Every build publishes llms.txt (a Markdown index) and llms-full.txt (a full
aggregated Markdown dump) at the site root, alongside sitemap.xml — the
llms.txt convention, letting an agent read the site without
scraping rendered HTML. Configured under docs/src/antora.yml’s `llms key (see
Antora Descriptor) — summary becomes the blockquote under
the site title; exclude leaves specific pages out of both files. See also
AI-First approach for the broader philosophy this feeds into.
Site reliability & URLs
External link checking
A scaffolded site ships scripts/check-links.mjs (via
linkinator) and a check-links
npm script. package.json’s own `docouture.checkLinks.ignore
is a list of URL globs to skip — pre-seeded with this repository’s own URL, so a build
doesn’t fail checking a link to itself before it’s ever been published.
URL routing: the /latest/ alias
Rather than Antora’s own urls.latest_version_segment (whose default replace
strategy turns one real version segment into a permanent redirect stub the moment a
release exists — see Versioning modes), duplicate_latest_version:
true on the antora.extensions registration entry republishes whichever version
Antora computes as latest a second time, under /latest/…, as a genuinely
independent copy — so both the real version segment and /latest/ stay real content.
Legacy URL redirects
For a site migrated from another documentation tool, arbitrary literal legacy URLs can
redirect to whatever real page now answers the equivalent URL — configured as
from/to URL templates on the @inditextech/docouture-antora-extensions
registration entry itself (not antora.yml, since these apply across every ref a
build aggregates, not per-version):
antora:
extensions:
- require: '@inditextech/docouture-antora-extensions'
redirects:
- from: '/docs/main/old-page'
to: '/main/new-page'
- from: '/docs/**'
to: '/main/**'
* captures one path segment, captures the remainder. Rules are first-match-wins
in authoring order — an exact override belongs ahead of a broad catch-all.