Shipped in 2.5.0 (2026-10-25). The repo spec is docs/superpowers/specs/2026-10-24-rendered-fences-design.md; this page is the as-built summary.
Second renderer: server-rendered PlantUML for UML class, activity and other
@startumldiagrams shipped in 2.5.1 — see PlantUmlFencesDesign.
Before 2.5.0 the production corpus held 63 ```mermaid fences on 43 pages, and none of them drew. The server's Flexmark setup turned GitLab's Mermaid rendering off, and the frontend had no diagram library, so every diagram showed as a plain code block. The content agent requires a diagram on every non-hub page, so the count kept growing.
The goal was to draw those diagrams for human readers, keep the source text for every machine consumer, and build the mechanism as a general hook: a rendered fence is any fenced block whose language a registered renderer claims. Mermaid was the first renderer and PlantUML the second; Vega-Lite is a possible next one.
flowchart LR
MD[Page markdown] --> Flex[Flexmark node renderer]
Flex --> Policy{Server safety policy}
Policy -->|allowed| Env[figure.wk-fence envelope with source]
Policy -->|refused| Ref[envelope plus refusal reason]
Env --> Browser{Browser policy and Mermaid}
Browser -->|ok| SVG[Drawn SVG plus Show source]
Browser -->|error| Err[Source plus parse error]
MD --> Scan[RenderedFenceScanner]
Scan --> Refs[ReferenceManager links]
click Refs "/wiki/PageGraphVsKnowledgeGraph"
The source text always reaches the served HTML (SSR /wiki/{slug} and contentHtml). ?format=md, the for-agent projection, chunking, embeddings and export all carry raw markdown and are unchanged.
example means "show this as ordinary code". It is handled once, for every rendered-fence language, so no renderer implements it.flowchart LR
Draft --> Review
click Review "/wiki/EditPageHelp"
The block above is written with the example modifier, so it shows its syntax instead of drawing.
Every rendered fence is emitted in one fixed shape: <figure class="wk-fence" data-fence data-fence-kind> wrapping <pre class="wk-fence-source"><code class="language-mermaid">, with the source HTML-escaped.
To add a renderer, read the RenderedFenceRenderer Javadoc in com.wikantik.markdown.extensions.fences and the header of wikantik-frontend/src/utils/fences/registry.js. Both are written as the how-to guide.
The policy refuses whole categories rather than mirroring Mermaid's lexers. Four review rounds showed that a deny-list of specific patterns never converges. A Mermaid fence is refused if it contains any of these:
%%{ … }%% directive;--- front-matter block;javascript: anywhere;click line that calls a function;http(s) or site-relative;click tooltip.HTML entities are decoded before link targets are checked, and the checks also run on statement fragments split at ;.
The same rules exist in Java (MermaidStatementPolicy, MermaidUrlRules, MermaidTextRules) and in JavaScript (mermaidPolicy.js), because the editor previews never call the server. One shared fixture, wikantik-frontend/src/utils/__fixtures__/renderedFences.json, drives both test suites, so the two cannot drift. A refused fence shows its source and the reason, never a blank space.
As a second layer, Mermaid runs at securityLevel: antiscript. Its secure key list covers dompurifyConfig and htmlLabels, and a hardened dompurifyConfig strips forms, inputs and inline styles from labels. In review, labels were found able to carry working off-site forms, which this closes.
A line click Node "/wiki/PageName" makes the node a link, and the page link counts as a real reference. RenderedFenceScanner is a raw-text scanner, so no Flexmark parse is needed. It finds rendered fences, including ~~~, indented, list-nested and blockquote-nested ones, skips example fences, and feeds each renderer's link extractor into DefaultReferenceManager.scanWikiLinks. Bumping the reference manager's cache version made 2.5.0's first startup rescan every page, which took 4.5 seconds on prod.
External http(s) targets are clickable but not tracked. Renaming a page does not yet rewrite diagram links. The rename would have to touch only the renderer's own link syntax, only inside rendered fences and never in example fences.
![[embeds]].node wikantik-frontend/scripts/check-mermaid.mjs [--json] <files|dir|-> parses every diagram it finds. It exits 0 when all diagrams parse, 1 when some are broken, and 2 when the checker itself fails. The content agent's linter calls it and reports a broken diagram as a required fix. Before the release, the three prod diagrams that did not parse (RecommendationSystems, SimpleAgilityAttributionRFC, SimpleAgilityCommerceDataFlow) were repaired, and all 63 prod diagrams draw. PlantUML has the matching bin/check-plantuml.sh.
```math onto the hook.See WikantikDevelopmentHub for the rest of the platform designs.