原始内容
name: plantuml description: Turn natural language into uml-diagrams.org style PlantUML diagrams (sequence, class, activity, use case, component, state…) and render to SVG/PNG/PDF. Use when the user asks to draw a UML diagram. version: 1.7.2 emoji: "📐" homepage: https://github.com/samonysh/plantuml-skill metadata: openclaw: # The render script is local-first: it tries Docker, then a local plantuml.jar. # The Kroki public server is OPT-IN ONLY (--use-public-server) # because it uploads diagram source to a third-party service (kroki.io by default, # overridable to a self-hosted Kroki via PLANTUML_PUBLIC_SERVER). requires: anyBins: - docker - java - curl # This skill reads no environment variables and writes no secrets; nothing to # declare under primaryEnv / envVars / requires.env.
PlantUML Diagram Generator
Generate professional PlantUML diagrams from natural language descriptions. This skill handles the full pipeline: requirement analysis → PlantUML code generation → image rendering.
Trigger Phrases
Use this skill when the user asks to:
- "Generate/draw/create a PlantUML diagram for..."
- "Create a sequence/class/activity/... diagram showing..."
- "Visualize this flow/architecture/process as..."
- "Turn this description into a UML diagram"
- "Make a flowchart / ERD / Gantt chart from..."
- Any request involving diagram generation from text descriptions
Mandatory Style Requirements
ALL diagrams generated by this skill MUST adhere to the uml-diagrams.org reference style — strict OMG UML 2.x rendered with Visio UML 2.x stencils (black-and-white, no decoration). This is the canonical style used throughout https://www.uml-diagrams.org and serves as the authoritative visual reference for every diagram this skill produces. No exceptions unless the user explicitly requests otherwise.
- Black and white only: Pure black lines (
#000000) on a pure white background (#FFFFFF). No colors, no grayscale fills, no gradients, no themed accents. - Thin uniform line weight: All borders, arrows and connectors use the default hair-line stroke (≈0.75pt). Never thicken or stylize lines.
- No circle visibility icons: Class attributes MUST NOT show colored circle icons (● public / ◐ protected / ○ private). Enforced via
skinparam classAttributeIconSize 0. Use+ - # ~text markers only. - No circle stereotype icons: Class and interface headers MUST NOT show circle-with-letter icons (Ⓒ / Ⓘ / Ⓐ / Ⓔ). Instead of relying on
skinparam style strictuml(which degrades actors into plain text and use cases into rectangles — see Common Failure Patterns), we suppress the circle adornments purely at the syntax level: always declare interfaces / abstract classes / enumerations via aclass <<interface>>/class <<abstract>>/class <<enumeration>>text stereotype — never use theinterface/abstract class/enumkeywords, which are what trigger the circle icons in the first place. - Abstract classifiers in italics: Per UML 2.5 §9 and uml-diagrams.org "Name of an abstract classifier is shown in italics" — the
<<abstract>>text stereotype combined with{abstract}method markers renders correctly without needingstrictuml. - No 3D effects: Drop shadows MUST be disabled (
skinparam shadowing false). - Clean typography: Sans-serif font (Helvetica, equivalent to the Arial used by Visio stencils on uml-diagrams.org), 12pt default. No colored or bold text except diagram titles. When CJK characters are present, use
--cjkflag to switch to a CJK-compatible font (see CJK Font Support). - Aspect ratio: Generated diagrams are automatically validated for an aspect-ratio band. By default the renderer tries to keep width/height between 0.7 and 1.4 (a comfortable page-like shape), re-rendering with layout corrections when the output falls outside that band. Diagrams that cannot be fixed safely after a few attempts are kept with a warning, so unusual diagrams are not destroyed. Use
--no-fixto disable this behavior (see Step 3). - A4 paper fit: After aspect-ratio validation passes, the diagram is checked against A4 paper (210×297 mm). At the 96 DPI CSS standard, this works out to 794×1123 px portrait and 1123×794 px landscape. The renderer accepts the diagram if it fits in EITHER orientation; otherwise it injects a computed PlantUML
scale Ndirective and re-renders up to once. The default body font of 12 px (from the mandatory preamble) shrinks proportionally; if the estimated on-paper font drops below--min-font-pt(default 8 pt), the script prints a legibility warning — at that point no further down-scaling helps and the user must split the diagram or abbreviate labels. A4 fit is ON by default; disable with--no-a4-check. - Standard UML shapes:
- Actors are stick figures (never Visio icons or images).
- Classes / components / nodes are plain rectangles; activities are round-cornered rectangles with the activity name in the upper-left.
- Dependencies and realizations use dashed lines; lifelines use dashed vertical lines (uml-diagrams.org explicitly: "a rectangle forming its head followed by a vertical line (which may be dashed) that represents the lifetime of the participant").
- Notes are white folded-corner rectangles; no shading.
- Sequence diagram specifics (matching uml-diagrams.org figures exactly):
- Lifeline head is a white rectangle; the vertical lifeline is a dashed black line.
- Execution specification / activation bar is a "thin grey or white rectangle on the lifeline" — this skill renders it as a thin white rectangle with a black border (no yellow PlantUML default).
- Destruction occurrence is shown as an
Xat the bottom of the lifeline (PlantUML<participant> !syntax). - Synchronous messages use a filled solid triangle arrowhead on a solid line.
- Asynchronous messages use an open stick arrowhead on a solid line.
- Reply / return messages use an open stick arrowhead on a dashed line.
- Activity diagram specifics: round-cornered action rectangles, solid arrows with open arrowheads for control flow, diamond decisions/merges, thick horizontal/vertical bar for forks/joins, filled black dot for initial node, bull's-eye for activity final.
- Use case diagram specifics: stick-figure actor on the left, ellipses for use cases inside a rectangle subject boundary,
«include»/«extend»as dashed open arrows. - Class diagram specifics: associations are plain solid lines, aggregation = hollow diamond, composition = filled diamond, generalization = hollow triangle arrowhead on solid line, realization = hollow triangle arrowhead on dashed line, dependency = open arrow on dashed line.
Every .puml file MUST include the mandatory uml-diagrams.org-style preamble as its first lines after @startuml (see Style Configuration).
Workflow
Step 1: Parse and Confirm Requirements
Extract from the user's description:
- Diagram type — which PlantUML diagram fits best
- Actors/participants — who/what is involved
- Relationships/flows — how they interact
- Constraints/rules — conditions, ordering, cardinality
- Output format — svg (default), png, pdf, or txt (ASCII art)
If the diagram type is not explicitly stated, infer it from the description:
| Description signals | Recommended diagram |
|---|---|
| "A sends X to B", "request/response", "handshake" | Sequence |
| "inherits from", "has many", "belongs to", entities & fields | Class |
| "if/then", "approve/reject", workflow, pipeline | Activity |
| "user can", "admin manages", roles & permissions | Use Case |
| "depends on", "connects to", services & interfaces | Component |
| "deployed on", "hosted on", nodes & servers | Deployment |
| "transitions from", "changes state", lifecycle | State |
| timeline, milestones, phases, schedule | Gantt |
| hierarchy, brainstorming, tree structure | Mind Map |
If ambiguous, ask the user to clarify the diagram type before proceeding.
Step 2: Generate PlantUML Code
Write the PlantUML source following these rules:
- Start EVERY file with one of the two mandatory uml-diagrams.org-style preambles
immediately after
@startuml:- Default: the
skinparampreamble — see OMG-UML / uml-diagrams.org Style Configuration. Maximum backward compatibility, used by every example except #07. (Example #07 is a legacy alias of #01_css — same OAuth2 sequence diagram, same CSS preamble.) - Backup option: the CSS-style
<style>preamble — see Alternative — CSS-style Preamble. Recommended on PlantUML ≥ 1.2019.9 whereskinparamis being phased out. Pick ONE per file — never mix both inside the same.puml.
- Default: the
- Use
@startuml/@endumldelimiters - Include a descriptive
title - Use proper PlantUML syntax for the chosen diagram type (see Reference below)
- Keep the diagram focused — don't add unnecessary elements
- NEVER add color, themed backgrounds, or decorative styling — strict black and white
Save the PlantUML source to a .puml file in the working directory.
Step 3: Render to Image
Use the bundled conversion script. It is a single, unified Python 3.8+ script
that works identically on Linux, macOS, and Windows (native PowerShell, cmd,
Git Bash, WSL — anywhere python is on PATH):
python skills/plantuml/scripts/generate_plantuml.py <input.puml> <output_dir> --format <svg|png|pdf|txt>
On Windows PowerShell / cmd the invocation is identical (use backslashes if you prefer):
python skills\plantuml\scripts\generate_plantuml.py <input.puml> <output_dir> --format <svg|png|pdf|txt>
Historical note — earlier versions shipped a
generate-plantuml.sh/generate-plantuml.ps1pair. Those have been consolidated into this single Python script. All flags use the same--kebab-casenames on every OS; the previous PowerShell-style-CamelCaseflag names are no longer used.
The script tries three backends in strict priority order — local-first. Docker and the local JAR are tried first; the Kroki public server is OPT-IN ONLY because it uploads your diagram source to a third-party service (kroki.io by default):
- Docker (
plantuml/plantuml:latest) — preferred default, fully local - Local
plantuml.jar(requires Java) — offline fallback - Kroki public server (https://kroki.io by default) — OPT-IN
via
--use-public-server. Override the host with thePLANTUML_PUBLIC_SERVER=<url>environment variable to point at a self-hosted Kroki instance.
⚠ Privacy notice — passing
--use-public-serverPOSTs the entire.pumlsource tokroki.io(or your override host). Never enable this flag for diagrams containing confidential architecture, credentials, customer data, or proprietary business logic. When in doubt, stay with the default (Docker / local JAR). See the Privacy & Backend Selection section below for the full data-flow contract.
CJK font support: When the .puml contains Chinese, Japanese, or Korean characters, add the --cjk flag:
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --format svg --cjk
The --cjk flag:
- Replaces
HelveticawithWenQuanYi Micro Hei(a CJK-compatible font) - For Docker: mounts host font directories (
/usr/share/fonts,/usr/local/share/fonts) into the container and refreshes the font cache before rendering - For local JAR: uses system-installed CJK fonts
- If CJK fonts are not installed on the system, characters will not render correctly. Install them via:
- Debian/Ubuntu:
sudo apt install fonts-wqy-zenhei - Fedora:
sudo dnf install wqy-zenhei-fonts - macOS: CJK fonts are pre-installed (PingFang SC)
- Debian/Ubuntu:
Aspect ratio validation: After rendering (SVG or PNG), the script measures width/height and checks whether it sits inside the configured band. The default band is 0.7–1.4 (width/height), i.e. diagrams should be neither extremely tall nor extremely wide. If the output falls outside the band, the script injects layout corrections and re-renders:
- Too tall (width/height <
--min-aspect): appliesleft to right directionand adds spacing guards so labels do not crowd. - Too wide (width/height >
--max-aspect): appliestop to bottom directionand adds spacing guards. - Sequence, activity, and state diagrams skip the direction directive because it is either unsupported or counter-productive for those diagram types; only spacing guards are applied.
- Up to 3 correction attempts are made. If a diagram still cannot be brought into the band (for example a very narrow use-case or state machine), the script keeps the best output and prints a warning rather than forcing an unusable layout.
Spacing guards added during auto-fix include Padding, BoxPadding, ParticipantPadding, MinClassWidth, WrapWidth, NodeSep, and RankSep. These prevent text from becoming cramped when the layout is re-directed.
To disable automatic correction:
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --no-fix
To set a custom band:
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --min-aspect 0.6 --max-aspect 1.5
Dark mode (opt-in): The default output follows the strict uml-diagrams.org black-and-white style. When the user explicitly asks for a dark variant, add --dark-mode. This emits both the regular light output and a dark companion named <basename>.dark.<fmt>:
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --format svg --dark-mode
Behaviour:
- Light output is rendered normally with the monochrome preamble.
- The dark companion is produced by injecting a CSS
@media (prefers-color-scheme: dark)block into the SVG, which automatically adapts to the user's system theme. - SVG is fully supported. PNG is supported when ImageMagick
convertis available. PDF/TXT dark companions are not generated because there is no reliable local post-processor. - The dark palette uses
#1e1e2ecanvas,#c9d1d9text/strokes,#f0f6fcbold text, and#6e7681lifelines. - Bare-stroke injection: PlantUML's CSS mode may render some elements (use case ellipses, component rects, actor paths) with
fill="none"and nostrokeattribute. The script injects CSS rules to add strokes to these elements in both light (#000000) and dark (#c9d1d9) variants. skinparam style strictumlis FORBIDDEN — despite past documentation claiming it was "essential",strictumlactively degrades key UML shapes: actors collapse into plain-text labels, use cases collapse from ellipses into rectangles, and classes lose their header separator. The correct fix is a complete per-element skinparam block (see OMG-UML Style Configuration) that explicitly setsBackgroundColor/BorderColor/FontColorfor every element category. The render script also defensively strips any leftoverskinparam style strictumlline before dispatching to the backend, so even if a diagram source accidentally re-introduces it, the rendering pipeline will remove it.
A4 paper fit validation: After the aspect-ratio check passes, the render script validates the diagram's pixel dimensions against A4 paper. PlantUML writes SVG in CSS pixels at the 96 DPI standard, so A4 (210×297 mm = 8.27×11.69 in) maps to 794×1123 px portrait or 1123×794 px landscape. The check is ON by default and runs right after the aspect check.
Behaviour:
- If the rendered image already fits within EITHER A4 box — nothing changes, the diagram is reported as A4-ready.
- If the image exceeds both boxes, the script computes the smallest scale factor that lets it fit either orientation, clamps to
≤1.0and a hard floor of0.15, injects ascale Ndirective into a working copy of the.puml, then re-renders once. - After re-rendering the script estimates the effective on-paper font size:
scale × 12 px × 0.75 ≈ pt(the 0.75 factor converts px to pt at 96 DPI). If this is below--min-font-ptit prints a legibility warning — at that point further down-scaling cannot help; the user must split the diagram, shorten labels, or switch to a smaller font.
Flags:
| Flag | Purpose | Default |
|---|---|---|
--no-fix |
Disable automatic aspect-ratio correction | off (correction ON) |
--min-aspect N |
Lower bound of acceptable width/height band | 0.7 |
--max-aspect N |
Upper bound of acceptable width/height band | 1.4 |
--no-a4-check |
Disable A4 fit validation entirely | off (check ON) |
--min-font-pt N |
Minimum legible on-paper font size in pt | 8.0 |
--dark-mode |
Also emit a dark companion (<basename>.dark.<fmt>) with CSS @media theme |
off |
Examples:
# Disable A4 fit
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --no-a4-check
# Tighten legibility threshold (warn if effective font drops below 10 pt)
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --min-font-pt 10
# Allow narrower diagrams and also emit a dark SVG companion
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --format svg --min-aspect 0.5 --dark-mode
On Windows the same commands work verbatim in PowerShell / cmd — just swap forward slashes for backslashes if you prefer native path style. There is no longer a separate PowerShell flag namespace.
A4 fit is skipped automatically for txt and pdf output (TXT has no image dimensions; PDF is already a print-oriented format the PlantUML renderer pages itself). The check shares the same 3-attempt auto-fix budget as aspect-ratio correction — running both does not double the cap.
After rendering, show the user the output. If SVG is generated, read and display it inline. If PNG/PDF is generated, tell the user where the file is saved.
Privacy & Backend Selection
This skill is local-first. By default, all rendering happens on the user's own machine — diagram source code never leaves the host.
Default behaviour (no flags)
.puml ──► Docker (plantuml/plantuml) ──► output.svg [LOCAL, preferred]
└────► local plantuml.jar (Java) ──► output.svg [LOCAL, fallback]
No network calls are made; nothing is uploaded.
Opt-in remote rendering
The Kroki public server (https://kroki.io) can render diagrams without any
local installation, but doing so POSTs the full .puml source to a third
party. To use it you must explicitly opt in:
# Explicit opt-in required (same flag on every OS)
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --use-public-server
When opt-in is active, the script:
- Prints a runtime privacy warning identifying the destination URL and operator
- POSTs the full
.pumlcontents tokroki.io(or your override host) - Saves the returned SVG/PNG/PDF/TXT locally
Self-hosted Kroki override
Kroki is open source and self-hostable
(github.com/yuzutech/kroki). To route
opt-in traffic to your own instance instead of the public kroki.io, set the
PLANTUML_PUBLIC_SERVER env var to your base URL:
# Linux / macOS / Git Bash / WSL
PLANTUML_PUBLIC_SERVER=https://kroki.internal.example.com \
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --use-public-server
# Windows PowerShell
$env:PLANTUML_PUBLIC_SERVER = 'https://kroki.internal.example.com'
python skills\plantuml\scripts\generate_plantuml.py diagram.puml .\output --use-public-server
The runtime privacy warning surfaces the resolved host name so you can confirm
the traffic destination before any data leaves the machine. Custom hosts must
expose the standard Kroki endpoint shape <base>/plantuml/<format>.
Why Kroki replaced the legacy plantuml.com backend (v1.4.1)
Earlier versions of this script POSTed to
https://www.plantuml.com/plantuml/<format>. That endpoint now sits behind a
Cloudflare + Ezoic consent wall: a POST returns 302 redirecting to a
JavaScript-only HTML consent page, making non-browser automation impossible.
Kroki replaces it because:
- It re-runs the official upstream PlantUML JAR server-side, so the output is byte-for-byte the same family of SVG/PNG/PDF/TXT.
- It is open source and trivially self-hostable in Docker, restoring the "render off-host but in your trust boundary" option that the plantuml.com default once provided.
- The Yuzu Tech operated public instance is EU-hosted, which moves the default jurisdiction closer to GDPR-style baseline expectations than the prior US-CDN-fronted plantuml.com path.
When NOT to use --use-public-server
Never enable remote rendering for diagrams that contain any of the following:
- Internal system / service / hostname identifiers
- Credentials, tokens, API keys, connection strings (even as placeholders)
- Customer data, PII, or any regulated content
- Proprietary architecture, design IP, or trade-secret business logic
- Source code excerpts or unreleased features
If you are unsure whether the diagram is safe to upload, don't opt in —
install Docker (one command: docker pull plantuml/plantuml:latest) or
download plantuml.jar and render locally.
CJK Docker mode and host font directories
When --cjk is combined with the Docker backend, the script mounts
host font directories read-only into the container so PlantUML can
discover system-installed CJK fonts. The mounts are:
- Linux/macOS:
/usr/share/fonts,/usr/local/share/fonts,/System/Library/Fonts - Windows (Git Bash/WSL):
/c/Windows/Fontsor/mnt/c/Windows/Fonts - Windows (PowerShell):
%WINDIR%\Fonts
These mounts are read-only (:ro), are scoped to font directories only, and
are used only inside the throwaway PlantUML container. No font data is
written back to the host. If you do not need CJK rendering, omit the flag
and no host directories are mounted.
Step 4: Iterate on Feedback
If the user requests changes:
- Modify the
.pumlfile - Re-run the conversion script
- Show the updated result
PlantUML Syntax Reference
Note: All examples below omit the mandatory monochrome preamble for brevity. In actual generated code, EVERY file MUST include the OMG-UML style preamble immediately after
@startuml. The class diagram example shows the full preamble inline as a reference.
Sequence Diagram
@startuml
title Authentication Flow
actor User
participant "Web App" as App
participant "Auth Service" as Auth
database "User DB" as DB
User -> App: Login (email, password)
App -> Auth: POST /auth/login
Auth -> DB: SELECT user WHERE email
DB --> Auth: user record
Auth -> Auth: Verify password hash
alt Success
Auth --> App: JWT token
App --> User: Dashboard
else Failure
Auth --> App: 401 Unauthorized
App --> User: Error message
end
@enduml
Key syntax: -> sync message, --> async/return, ->> async, alt/else/end branching,
loop/end loops, opt/end optional, activate/deactivate lifeline, note left/right
Class Diagram
@startuml
' OMG-UML Monochrome Style — CSS variant
<style>
root {
FontName Helvetica
FontSize 12
FontColor #000000
BackGroundColor #FFFFFF
LineColor #000000
LineThickness 0.75
RoundCorner 0
Shadowing 0
}
title {
FontSize 14
FontStyle bold
FontColor #000000
BackGroundColor transparent
LineColor transparent
LineThickness 0
}
note {
BackGroundColor #FFFFFF
LineColor #000000
FontColor #000000
}
classDiagram {
class { BackGroundColor #FFFFFF; LineColor #000000; FontColor #000000 }
arrow { LineColor #000000; LineThickness 0.75 }
}
</style>
skinparam classAttributeIconSize 0
title Payment System
class User {
+id: UUID
+email: String
+name: String
+register()
}
class Order {
+id: UUID
+total: Decimal
+status: OrderStatus
+calculateTotal()
}
class PaymentProcessor <<interface>> {
+processPayment(amount: Decimal): Boolean
+refund(transactionId: UUID): Boolean
}
class NotificationService <<abstract>> {
#enabled: Boolean
+{abstract} send(to: String, body: String)
}
enum OrderStatus {
PENDING
CONFIRMED
SHIPPED
DELIVERED
}
User "1" -- "*" Order : places
Order ..|> PaymentProcessor
NotificationService <|-- EmailNotifier
@enduml
Key syntax: + public, - private, # protected, {abstract} abstract method,
class Foo <<interface>> (interface via text stereotype — NOT interface Foo),
class Bar <<abstract>> (abstract class — NOT abstract class Bar),
enum, relationships: -- association, *-- composition, o-- aggregation,
<|-- inheritance, ..|> realization
Activity Diagram
@startuml
title Order Processing
start
:Receive Order;
if (Payment Valid?) then (yes)
:Reserve Inventory;
if (Inventory Available?) then (yes)
:Confirm Order;
:Ship Order;
stop
else (no)
:Notify Customer;
:Cancel Order;
stop
endif
else (no)
:Reject Order;
stop
endif
@enduml
Key syntax: start/stop/end, if/then/else/endif, repeat/repeat while,
fork/fork again/end fork (parallel), split/split again/end split,
partition "name" { ... } (swimlane), :Text; action
Use Case Diagram
@startuml
title E-Commerce System
left to right direction
actor Customer
actor Admin
rectangle "E-Commerce" {
usecase "Browse Products" as UC1
usecase "Place Order" as UC2
usecase "Manage Inventory" as UC3
usecase "Process Returns" as UC4
}
Customer --> UC1
Customer --> UC2
Admin --> UC3
Admin --> UC4
UC2 ..> UC1 : <<include>>
@enduml
Key syntax: actor, usecase, rectangle/package for system boundary,
--> association, ..> dependency, <<include>> / <<extend>> stereotypes
Component Diagram
@startuml
title Microservice Architecture
package "Frontend" {
[Web App]
[Mobile App]
}
package "API Gateway" {
[Gateway]
}
package "Services" {
[User Service]
[Order Service]
[Payment Service]
}
database "PostgreSQL" as DB
cloud "Message Queue" as MQ
[Web App] --> [Gateway]
[Mobile App] --> [Gateway]
[Gateway] --> [User Service]
[Gateway] --> [Order Service]
[Order Service] --> [Payment Service]
[User Service] --> DB
[Order Service] --> DB
[Order Service] --> MQ
@enduml
Key syntax: [Component], package "name" { }, database, cloud, node,
frame, interface, ()-- required interface, --() provided interface
Deployment Diagram
@startuml
title Production Deployment
node "AWS us-east-1" {
node "VPC" {
node "Public Subnet" {
[Load Balancer]
[Bastion Host]
}
node "Private Subnet" {
node "App Server 1" {
[Application]
}
node "App Server 2" {
[Application]
}
database "RDS Primary"
}
}
cloud "CDN"
}
@enduml
Key syntax: node "name" { }, nested node, database, cloud, actor
State Diagram
@startuml
title Order Lifecycle
[*] --> Draft
Draft --> Submitted : submit()
Submitted --> Paid : processPayment()
Submitted --> Cancelled : cancel()
Paid --> Shipped : ship()
Shipped --> Delivered : confirmDelivery()
Delivered --> [*]
Cancelled --> [*]
state Paid {
[*] --> Authorizing
Authorizing --> Captured : success
Authorizing --> Failed : decline
Captured --> [*]
}
@enduml
Key syntax: [*] start/end, --> transition with optional : label,
state Name { } composite state, state "Name" as Alias
Gantt Chart
@startuml
title Project Roadmap
project starts 2025-01-06
[Design] lasts 10 days
[Development] lasts 20 days
[Development] starts at [Design]'s end
[Testing] lasts 10 days
[Testing] starts at [Development]'s end
[Deployment] lasts 3 days
[Deployment] starts at [Testing]'s end
[Frontend] lasts 12 days
[Frontend] starts at [Design]'s end
[Backend] lasts 15 days
[Backend] starts at [Design]'s end
@enduml
Key syntax: project starts YYYY-MM-DD, [Task] lasts N days,
[Task] starts at [Other]'s end, -- separator for dependency,
printscale weekly/monthly, @dailymail, @weeklymail
Mind Map
@startmindmap
title System Architecture
* Root Node
** Level 1 A
*** Level 2 A1
*** Level 2 A2
** Level 1 B
*** Level 2 B1
**** Level 3 B1a
**** Level 3 B1b
** Level 1 C
@endmindmap
Key syntax: * root, ** level 1, *** level 2, etc.
Use @startmindmap / @endmindmap (not @startuml).
Affix _ to markdown-style side notation, e.g., ***_ Right side node.
Colors: <style> * { BackgroundColor lightblue } </style>
OMG-UML / uml-diagrams.org Style Configuration (MANDATORY)
Every generated .puml file MUST include this CSS-style preamble immediately after @startuml.
It locks PlantUML's rendering to the uml-diagrams.org reference style (strict OMG UML 2.x,
black-and-white Visio stencils).
Since PlantUML 1.2019.9 the project officially recommends the CSS-like <style> block
(plantuml.com/style-evolution) as the preferred
styling mechanism — "skinparam is being phased out … users should migrate to style".
Do NOT mix both inside the same .puml file. Pick one preamble per diagram.
Primary — CSS <style> Preamble (recommended)
@startuml
<style>
root {
FontName Helvetica
FontSize 12
FontColor #000000
BackGroundColor #FFFFFF
LineColor #000000
LineThickness 0.75
RoundCorner 0
Shadowing 0
}
title {
FontSize 14
FontStyle bold
FontColor #000000
BackGroundColor transparent
LineColor transparent
LineThickness 0
}
note {
BackGroundColor #FFFFFF
LineColor #000000
FontColor #000000
}
sequenceDiagram {
actor { BackGroundColor #FFFFFF; LineColor #000000; FontColor #000000 }
participant { BackGroundColor #FFFFFF; LineColor #000000; FontColor #000000 }
lifeLine { BackGroundColor #FFFFFF; LineColor #000000; LineStyle 5-5; LineThickness 0.75 }
reference { BackGroundColor #FFFFFF; LineColor #000000 }
group { BackGroundColor #FFFFFF; LineColor #000000 }
arrow { LineColor #000000; LineThickness 0.75; FontColor #000000 }
}
classDiagram {
class { BackGroundColor #FFFFFF; LineColor #000000; FontColor #000000 }
arrow { LineColor #000000; LineThickness 0.75 }
}
activityDiagram {
activity { BackGroundColor #FFFFFF; LineColor #000000; FontColor #000000; RoundCorner 10 }
arrow { LineColor #000000; LineThickness 0.75 }
diamond { BackGroundColor #FFFFFF; LineColor #000000 }
}
useCaseDiagram {
actor { BackGroundColor #FFFFFF; LineColor #000000 }
usecase { BackGroundColor #FFFFFF; LineColor #000000 }
rectangle { BackGroundColor #FFFFFF; LineColor #000000 }
}
componentDiagram {
component { BackGroundColor #FFFFFF; LineColor #000000 }
package { BackGroundColor #FFFFFF; LineColor #000000 }
}
stateDiagram {
state { BackGroundColor #FFFFFF; LineColor #000000; FontColor #000000 }
arrow { LineColor #000000 }
}
</style>
' ── Per-element skinparam fallback (mandatory) ─────────────────────────────
' The CSS <style> block above does NOT cover every PlantUML element category.
' Without the following block, some shapes fall back to PlantUML defaults
' (yellow activation bars, coloured actors, grey component fills, etc.).
' NEVER add `skinparam style strictuml` — it degrades actors into plain text
' and use cases into rectangles.
skinparam classAttributeIconSize 0
skinparam shadowing false
skinparam backgroundColor #FFFFFF
skinparam defaultFontColor #000000
skinparam actor { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam usecase { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam rectangle { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam class { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam object { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam component { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam interface { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam package { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam node { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam database { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam cloud { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam state { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam activity { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
skinparam sequence { ArrowColor #000000; LifeLineBorderColor #000000; LifeLineBackgroundColor #FFFFFF; ParticipantBackgroundColor #FFFFFF; ParticipantBorderColor #000000; ActorBackgroundColor #FFFFFF; ActorBorderColor #000000; BoxBackgroundColor #FFFFFF; BoxBorderColor #000000 }
skinparam note { BackgroundColor #FFFFFF; BorderColor #000000; FontColor #000000 }
What each CSS block does (mapped to uml-diagrams.org figures):
| CSS Block | Effect / uml-diagrams.org reference |
|---|---|
root |
Global defaults: Helvetica 12px black-on-white, 0.75pt lines, no shadows, square corners. Matches Visio UML 2.x stencil look. |
root > Shadowing 0 |
Disables drop shadows — uml-diagrams.org figures never have shadows. |
root > RoundCorner 0 |
Square corners on rectangles (matches Visio stencils). activityDiagram.activity overrides to 10 for round-cornered actions. |
title |
Bold 14px black text, transparent background/border. |
note |
White fill, black border, black text — matches uml-diagrams.org note style. |
sequenceDiagram.lifeLine |
Dashed black lines (LineStyle 5-5) — exactly the lifeline notation on uml-diagrams.org/sequence-diagrams.html. |
sequenceDiagram.arrow |
Thin black arrows (0.75pt) — matches Visio stencil hair-line strokes. |
classDiagram.class |
White fill, black border — no grey fills. |
activityDiagram.activity |
White fill with round corners (RoundCorner 10) — matches uml-diagrams.org activity shape. |
activityDiagram.diamond |
White fill, black border for decision/merge diamonds. |
useCaseDiagram |
White actors, use cases, and rectangles — no colored fills. |
componentDiagram |
White components and packages — no colored fills. |
stateDiagram.state |
White fill, black border — no grey fills. |
STYLING POLICY — keep the FULL preamble, NEVER use strictuml
The CSS <style> block above tells PlantUML how to render CSS-aware elements
(sequence lifelines, class boxes, activity nodes, notes). It does NOT cover
every PlantUML element category — actor stick-figures, use case ellipses,
component silhouettes, database cylinders and cloud shapes still fall back to
PlantUML's built-in defaults (colored fills, yellow activation bars, missing
borders on white canvas) when only a <style> block is present.
The per-element skinparam block immediately after </style> is therefore
mandatory — treat CSS and skinparam as complementary layers, not
alternatives. Together they guarantee black borders + white fills for actor /
usecase / rectangle / class / component / interface / package / node / database
/ cloud / state / activity / sequence / note across every diagram type and both
light and dark backgrounds.
The only allowed skinparam ... style value is the default — do NOT add
skinparam style strictuml. Even though strictuml sounds like a "make it
more UML-compliant" flag, in practice it:
- collapses
actor Foofrom a stick figure into a plain text label - collapses
usecase "X" as UCfrom an ellipse into a plain rectangle - removes the class-header separator line so name/attribute/method sections merge
The render script also defensively strips any leftover
skinparam style strictuml line before dispatching to the backend, so
accidental re-introductions from user edits or LLM output are neutralized at
the pipeline level.
skinparam classAttributeIconSize 0 is retained separately because it only
removes the colored visibility dots (●/◐/○) and has no side effects on shapes.
Common Failure Patterns
Symptoms and their root cause — check this list first if a rendered diagram looks visually wrong:
| Symptom | Root cause | Fix |
|---|---|---|
| Actor rendered as bare text, no stick figure | skinparam style strictuml in the source |
Remove the line; rely on the per-element skinparam fallback (the render script also auto-strips it). |
| Use case rendered as a plain rectangle instead of an ellipse | Same as above (strictuml) |
Same as above. |
| Class header separator line missing / name+attributes merged | Same as above (strictuml) |
Same as above. |
| Ellipses / actor paths lose their black border on light background | CSS <style> alone is used; the per-element skinparam actor/usecase block is missing |
Restore the full preamble including the per-element skinparam fallback block. |
| Sequence activation bar rendered yellow instead of white | Missing skinparam sequence { ActorBackgroundColor #FFFFFF ... } |
Restore the full preamble. |
Class attributes show ● / ◐ / ○ visibility icons |
Missing skinparam classAttributeIconSize 0 |
Add the line. |
Header header sub-elements show Ⓒ/Ⓘ/Ⓐ/Ⓔ circle icons |
Diagram used interface Foo / abstract class Foo / enum Foo keywords |
Rewrite as class Foo <<interface>> / class Foo <<abstract>> / class Foo <<enumeration>>. |
| Any decorative color / gradient / drop shadow appears | A !theme directive or extra skinparam ...Color overrides sneaked in |
Remove them; the mandatory preamble is the single source of styling truth. |
Backup - skinparam Preamble (backward-compatible)
Use this preamble only when you need maximum backward compatibility with PlantUML < 1.2019.9. Both preambles produce the same uml-diagrams.org reference look.
' uml-diagrams.org reference style — strict OMG UML 2.x, monochrome
skinparam monochrome true
skinparam backgroundColor #FFFFFF
skinparam defaultFontName Helvetica
skinparam defaultFontSize 12
skinparam shadowing false
skinparam classAttributeIconSize 0
skinparam sequenceMessageAlign center
skinparam roundCorner 0
' Force every fill to white so monochrome never falls back to grey
skinparam ActorBackgroundColor #FFFFFF
skinparam ParticipantBackgroundColor #FFFFFF
skinparam NoteBackgroundColor #FFFFFF
skinparam SequenceGroupBackgroundColor #FFFFFF
skinparam PackageBackgroundColor #FFFFFF
skinparam ClassBackgroundColor #FFFFFF
skinparam ObjectBackgroundColor #FFFFFF
skinparam StateBackgroundColor #FFFFFF
skinparam UsecaseBackgroundColor #FFFFFF
skinparam ComponentBackgroundColor #FFFFFF
skinparam ActivityBackgroundColor #FFFFFF
skinparam NodeBackgroundColor #FFFFFF
skinparam DatabaseBackgroundColor #FFFFFF
skinparam StereotypeCBackgroundColor #FFFFFF
skinparam StereotypeIBackgroundColor #FFFFFF
skinparam StereotypeABackgroundColor #FFFFFF
skinparam StereotypeEBackgroundColor #FFFFFF
' Sequence diagrams — match the lifeline / activation look on uml-diagrams.org:
' * lifeline = dashed black vertical line
' * activation bar = thin WHITE rectangle with black border (NOT yellow)
skinparam SequenceLifeLineBorderColor #000000
skinparam SequenceLifeLineBackgroundColor #FFFFFF
skinparam SequenceLifeLineBorderThickness 0.75
skinparam SequenceActivationBackgroundColor #FFFFFF
skinparam SequenceActivationBorderColor #000000
skinparam SequenceArrowColor #000000
skinparam SequenceArrowThickness 0.75
skinparam SequenceBoxBackgroundColor #FFFFFF
' Default arrow / border colour everywhere
skinparam ArrowColor #000000
skinparam ArrowThickness 0.75
skinparam DefaultTextColor #000000
NEVER apply colored themes (!theme blueprint, !theme cerulean, etc.), custom colors,
gradients, shadows, or decorative styling — doing so breaks compliance with the
uml-diagrams.org reference style. If a user explicitly and unambiguously requests colour,
add it on top of this preamble rather than removing the preamble.
CJK (Chinese/Japanese/Korean) Font Support
When diagrams contain CJK characters, Helvetica cannot render them — characters will appear as empty boxes (□) or tofu (▯).
In .puml files: Replace FontName Helvetica in the CSS <style> block with a CJK-compatible font:
root {
FontName "WenQuanYi Micro Hei"
}
For the skinparam preamble (backward-compatible):
skinparam defaultFontName "WenQuanYi Micro Hei"
When rendering: Use the --cjk flag, which automatically applies the font substitution and configures Docker font mounting if needed:
python skills/plantuml/scripts/generate_plantuml.py diagram.puml ./output --cjk
Host prerequisites for CJK rendering:
- Docker method: CJK fonts must exist on the host at
/usr/share/fonts(or/usr/local/share/fonts,/System/Library/Fonts). The script mounts these into the container. - Local JAR method: CJK fonts must be installed system-wide (Java uses system fontconfig).
- Public server method: The server handles font rendering automatically.
Common CJK font packages:
| OS | Package |
|---|---|
| Debian/Ubuntu | fonts-wqy-zenhei |
| Fedora/RHEL | wqy-zenhei-fonts |
| Arch | wqy-zenhei |
| Alpine | font-wqy-zenhei |
| macOS | Built-in (PingFang SC / Hiragino Sans) |
Error Recovery
If the PlantUML server returns an error:
- Check for syntax errors in the
.pumlfile - Validate that
@startuml/@endumlare properly paired - Ensure diagram-type-specific syntax is correct (e.g.,
@startmindmapfor mind maps) - Try the Docker fallback:
docker pull plantuml/plantuml:latest && python skills/plantuml/scripts/generate_plantuml.py ... - If all else fails, offer to install Java + plantuml.jar
If CJK characters render as empty boxes (□):
- Ensure the
--cjkflag was passed when rendering - Verify CJK fonts are installed on the host:
fc-list :lang=zh - If using Docker, check that font directories are mounted (the script handles this automatically with
--cjk)
If aspect ratio warnings appear:
- The script applies up to 3 automatic corrections (direction toggle + scale)
- If warnings persist, manually adjust the
.puml:- For too-wide diagrams: add
top to bottom directionand reduceskinparam BoxPadding - For too-tall diagrams: add
left to right directionand reduceskinparam ParticipantPadding - Try
scale 0.75orscale 0.5for extreme cases
- For too-wide diagrams: add
- For sequence diagrams with many participants: consider splitting into multiple diagrams or abbreviating participant names
If A4 fit warnings appear (the script prints 📄 A4 fit: ... exceeds A4 ...):
- The script has already re-rendered once with a
scale Ndirective computed from the smaller required factor. Check the loop output for "A4 fit ✓" on the second render — if present, the diagram now fits within A4. - If "Estimated font ≈ Npt on A4" message shows a value BELOW your
--min-font-ptthreshold (default 8 pt), further down-scaling will not make the diagram readable on print. To fix manually:- Split the diagram at a natural boundary (per use case, per subsystem, per actor).
- Shorten long labels — e.g. replace
client_id, redirect_uriwith shortened param names. - For sequence diagrams with many participants: group messages into sub-diagrams, or abbreviate participant display names.
- If you do not need A4 conformance for the current output, re-run with
--no-a4-checkto keep the larger original. - To let the diagram stretch across multiple A4 sheets, set
--min-font-pt 6(or lower) and accept reduced legibility — the script will warn but still emit the smaller-than-A4 final image.
Output Expectations
After successful generation:
- Show the generated PlantUML source (collapsed if long)
- Show the rendered output (SVG inline if possible)
- Report the saved file paths for both
.pumland the rendered image - Note any aspect ratio corrections that were applied (with dimensions before/after)
- Note whether A4 fit was met natively, applied a re-scale (report the
scale Nfactor and the post-fix dimensions), or skipped due to legibility threshold; if the legibility warning fired, surface it and propose splitting the diagram - Offer to make adjustments