Shipped in 2.5.1 (2026-10-26); @startsalt and @startnwdiag were added in 2.5.2. The repo spec is docs/superpowers/specs/2026-10-25-plantuml-fences-design.md; this page is the as-built summary. It is the second renderer on the hook described in RenderedFencesDesign, and the first one that draws on the server. For a live example, see the agent feature-delivery activity diagram on About.
Mermaid has no real UML activity notation and only shallow class diagrams. Wikantik pages need two things it cannot give:
People and content agents write and edit these diagrams by hand. Deriving diagrams from code is left to the agent; the wiki does not do it.
The spike used plantuml-mit 1.2026.9; the release pins 1.2026.8.
fork / fork again / end fork, split, swimlanes, while, notes) render correctly with PlantUML's own layout. No Graphviz is needed.SANDBOX security mode, file and URL includes, environment variables and images are all refused. The bundled C4 standard library still works.@startuml diagrams are accepted, plus @startsalt wireframes and @startnwdiag network diagrams, which PlantUML 1.2026.8 only recognises under their own start line. A browser test per type proves these draw in the reader, in light and dark:
| Draws | Refused as unsupported-diagram |
|---|---|
class, object, component, deployment, sequence, activity (new and legacy syntax), state, use case, timing, C4 (!include <C4/…>), ArchiMate, json objects, creole text, sprites, entity; salt wireframes (@startsalt); network diagrams (@startnwdiag) | any other @start… kind: mindmap, gantt, WBS, YAML, regex, EBNF, Chen ER, ditaa; info commands (version, license, help, crash) |
Salt and nwdiag lay themselves out without Graphviz, so the engine does not add the Smetana pragma to them. A salt wireframe:
@startsalt
{
Login | "agent@example.com "
Password | "**** "
[Cancel] | [ Sign in ]
}
@endsalt
A network diagram:
@startnwdiag
nwdiag {
network dmz {
address = "203.0.113.0/24"
proxy [address = "203.0.113.10"];
}
network internal {
address = "10.0.0.0/24"
proxy [address = "10.0.0.1"];
wiki [address = "10.0.0.20"];
db [address = "10.0.0.30"];
}
}
@endnwdiag
| Part | License | Decision |
|---|---|---|
| PlantUML core | MIT | Shaded into wikantik-plantuml, with the MIT text in META-INF/LICENSE-plantuml.txt. |
| Smetana (Graphviz port) | EPL-1.0, file-level weak copyleft | Kept, with META-INF/NOTICE-plantuml.txt stating the licence and where its source is. |
| Ditaa | LGPL-3.0 | Stripped from the shipped jar at build time. PlantUmlLicenseArchTest fails the build if it returns. |
| Standard-library icon sets | Various | Stripped to C4; !include <…> is refused except for the C4 allow-list. |
Wikantik never shows a PlantUML-generated error or welcome image, which is where PlantUML may place sponsored messages.
flowchart LR
MD[Page markdown] --> Parse[Flexmark node renderer]
Parse --> Check{Fail-closed policy}
Check -->|refused| Refusal[Source plus reason]
Check -->|allowed| Ph[Signed placeholder]
Ph --> Cache[HTML and embed caches]
Cache --> Resolve[Resolve at HTML exit]
Resolve --> Pool[Bounded PlantUML pool]
Pool --> Scrub[SVG scrub and id prefix]
Scrub --> Out[Light and dark SVG]
click Out "/wiki/RenderedFencesDesign"
textToHTML (nesting is counted by RenderDepth). Embeds and parses never draw, so a save never renders diagrams it would throw away.<svg> in a page is still stripped. Only PlantUML output, run through Wikantik's own allow-list SVG scrub, reaches the page. Tag scans in the resolver are length-capped, so hostile HTML cannot make resolution quadratic.check()). Refuses includes (except C4), file and environment built-ins, indirect calls (%call_user_func, %invoke_procedure, %eval), <img: labels, unsafe link targets, help/crash and oversized sources. A literal {{ }} sub-diagram is refused as a first line of defence. These rules apply to salt and nwdiag exactly as to @startuml.GRAPHVIZ_DOT points at a path that does not exist, so dot can never run, even for a sub-diagram built through the preprocessor. Any nested image is scrubbed, and every render is time-bounded.too-complex. A timeout is cached as too-slow for 10 minutes, then retried once. A PlantUML crash is render-crashed (a malformed salt wireframe lands here: salt has no parse-error diagram). Concurrent requests for one diagram share a single render, and the outcome cache is capped by bytes.page-limit), within a total of 10 s (page-budget).wikantik.fences.plantuml.enabled replaces drawings with a notice. Diagram links still count as references, so flipping it never changes the Page Graph.POST /api/fences/render, which requires an authenticated user and passes the same Origin-based cross-site check as the other /api posts. The previews debounce, keep the previous drawing dimmed until its replacement arrives, and show PlantUML's error with its line number.[[/wiki/Page]] links inside a diagram feed backlinks, the Page Graph and broken links, exactly as Mermaid click links do.bin/check-plantuml.sh [--json] <files|dir|-> draws every PlantUML diagram it finds through the same policy and engine. It exits 0 when all diagrams draw, 1 when some fail, and 2 when the checker itself fails — the same contract as check-mermaid.mjs.
@start… line, other than salt and nwdiag (see the table above).See WikantikDevelopmentHub for the rest of the platform designs.