Skip to content

Mermaid Diagram Style Guide

Reference for anyone authoring a Mermaid diagram in pm-skills documentation, whether you are a human PM contributor or an agent (Claude, Codex, GPT, etc.) generating a diagram inline. Quick-scan headers + copy-pasteable code blocks + decision matrices.

Live HTML preview: a self-contained rendered version of all examples below is at mermaid-style-guide.html. Opens locally too (no docs site required).

When to use which diagram type

Pick the diagram type that matches the structure of what you are showing. Mismatched types are the most common source of confusing diagrams.

Diagram typeUse whenMermaid syntaxRenders as
Phase flowchartShowing ordered phases or steps with arrows between themgraph LR or graph TDBoxes with arrows
Phase block diagramShowing 6 phases as parallel columns with shared structureblock-betaGrid-aligned blocks
Workflow flowchartShowing branching logic (decisions, conditionals, loops)graph TD with {decision} shapesBranching tree
Sequence diagramShowing back-and-forth interaction between roles or systems over timesequenceDiagramLifeline + arrows
State diagramShowing transitions between named statesstateDiagram-v2States + transitions
GanttShowing timeline of overlapping workganttHorizontal bars
Mind mapShowing hierarchical idea expansionmindmapRadial tree
PieShowing percentage breakdown of a single totalpiePie chart

Heuristic for ambiguous cases:

  • “Show a process” -> graph LR (left-to-right) for short chains; graph TD (top-down) for branching
  • “Show roles working together” -> sequenceDiagram
  • “Show a feature’s lifecycle” -> stateDiagram-v2 (states) or gantt (durations)

The pm-skills brand palette

Two tiers: global brand (applies across all diagrams via themeVariables) and Triple Diamond palette (applies semantically to phase-aligned diagrams via classDef or style).

Global brand (automatic; M1 themeVariables)

These apply to every Mermaid diagram on the docs site without you needing to do anything. They are configured in astro.config.mjs.

VariableValueEffect
lineColor#5C7CFAIndigo edges (matches favicon Triple Diamond mark)
fontFamilysystem-ui, ...Matches Starlight body text for visual consistency
fontSize14pxSlightly tighter than Mermaid default 16px

Triple Diamond palette (opt-in; M3 classDef / style)

Apply these when your diagram nodes map onto the 6-phase Triple Diamond framework. Do NOT use them for diagrams with unrelated semantics (meeting lifecycle, behavioral contracts, release flows) where a different color meaning already applies.

PhaseFillStrokeTextHex copy-paste
Discoverlight bluemedium bluedark navyfill:#e7f5ff,stroke:#1971c2,color:#0c2d5e
Definelight tealmedium tealdark tealfill:#e6fcf5,stroke:#0ca678,color:#0a4f3c
Developlight purplemedium purpledark purplefill:#f3e8ff,stroke:#7048e8,color:#3a1d8a
Deliverlight amberdark orangedark brownfill:#fff4e1,stroke:#d9480f,color:#5e2200
Measurelight yellowmedium amberdark amberfill:#fff9db,stroke:#e8a317,color:#5e3e00
Iteratelight pinkdark pinkdark pinkfill:#ffe9ec,stroke:#c2255c,color:#5c0a25

The palette is designed for high contrast in light mode and acceptable readability in dark mode. Borders are at stroke-width:2px so they remain visible against either background.

How styling works (3 layers)

Layered model. Each layer composes with the others.

Layer 1: Global theme variables (M1)

Set once in astro.config.mjs. Applies on top of whichever base theme autoTheme picks (default for light, dark for dark). You do not author this in your diagram; it is already configured.

astro.config.mjs
mermaid({
theme: 'default',
autoTheme: true,
mermaidConfig: {
themeVariables: {
lineColor: '#5C7CFA',
fontFamily: 'system-ui, ...',
fontSize: '14px',
},
},
}),

Layer 2: CSS polish (M2)

Set once in src/styles/custom.css. Applies SVG-level rules (edge thickness, node corner radius, cluster fill opacity) across all diagrams. You do not author this in your diagram; it is already configured.

src/styles/custom.css
.mermaid svg { max-width: 100%; height: auto; }
.mermaid .edgePath path { stroke-width: 1.75px; }
.mermaid .node rect { rx: 6; ry: 6; }
.mermaid .cluster rect { fill-opacity: 0.4; }

Layer 3: Per-diagram class / style (M3)

You author this inside the Mermaid code block when you want phase-coded nodes. Two syntax variants depending on diagram type:

  • graph LR/TD/RL/BT/etc.: use classDef + class directives
  • block-beta: use style {block-id} ... directives
  • sequenceDiagram: limited styling; use note/rect blocks for grouping
  • stateDiagram-v2: use classDef + class

Concrete examples

Each example is copy-pasteable. The Mermaid source block is what you put in your Markdown; the Renders as line describes the expected output.

Phase flowchart with classDef (graph LR)

Triple Diamond phase flow. This is the canonical pm-skills home page diagram.

```mermaid
graph LR
subgraph "Problem Space"
D1["Discover<br/>3 skills"] --> D2["Define<br/>4 skills"]
end
subgraph "Solution Space"
D3["Develop<br/>4 skills"] --> D4["Deliver<br/>6 skills"]
end
subgraph "Learning Space"
D5["Measure<br/>5 skills"] --> D6["Iterate<br/>4 skills"]
end
D2 --> D3
D4 --> D5
D6 -.->|"next cycle"| D1
classDef discover fill:#e7f5ff,stroke:#1971c2,color:#0c2d5e,stroke-width:2px
classDef define fill:#e6fcf5,stroke:#0ca678,color:#0a4f3c,stroke-width:2px
classDef develop fill:#f3e8ff,stroke:#7048e8,color:#3a1d8a,stroke-width:2px
classDef deliver fill:#fff4e1,stroke:#d9480f,color:#5e2200,stroke-width:2px
classDef measure fill:#fff9db,stroke:#e8a317,color:#5e3e00,stroke-width:2px
classDef iterate fill:#ffe9ec,stroke:#c2255c,color:#5c0a25,stroke-width:2px
class D1 discover
class D2 define
class D3 develop
class D4 deliver
class D5 measure
class D6 iterate
```

Renders as: 6 color-coded phase boxes grouped into 3 subgraph diamonds with arrows between adjacent phases and a dotted “next cycle” arrow from Iterate back to Discover.

Phase block diagram with style directives (block-beta)

Use when you want a 6-column grid of phases with their constituent items inside each block. classDef does not work in block-beta; use inline style directives instead.

```mermaid
block-beta
columns 6
block:discover["Discover"]:1
d1["/competitive-analysis"]
d2["/interview-synthesis"]
end
block:define["Define"]:1
f1["/problem-statement"]
f2["/hypothesis"]
end
block:develop["Develop"]:1
v1["/solution-brief"]
v2["/adr"]
end
block:deliver["Deliver"]:1
l1["/prd"]
l2["/user-stories"]
end
block:measure["Measure"]:1
m1["/experiment-design"]
m2["/okr-grader"]
end
block:iterate["Iterate"]:1
i1["/retrospective"]
i2["/lessons-log"]
end
discover --> define --> develop --> deliver --> measure --> iterate
style discover fill:#e7f5ff,stroke:#1971c2,color:#0c2d5e,stroke-width:2px
style define fill:#e6fcf5,stroke:#0ca678,color:#0a4f3c,stroke-width:2px
style develop fill:#f3e8ff,stroke:#7048e8,color:#3a1d8a,stroke-width:2px
style deliver fill:#fff4e1,stroke:#d9480f,color:#5e2200,stroke-width:2px
style measure fill:#fff9db,stroke:#e8a317,color:#5e3e00,stroke-width:2px
style iterate fill:#ffe9ec,stroke:#c2255c,color:#5c0a25,stroke-width:2px
```

Renders as: 6 phase columns each containing slash-command leaves; arrows connecting phase-to-phase below the grid; phase blocks color-coded per Triple Diamond palette.

Workflow flowchart with semantic palette (graph TD)

Use when showing branching logic with decisions. Triple Diamond palette does NOT apply here; use semantic colors (green for success, yellow for warning, blue for branch) instead.

```mermaid
graph TD
A[Invoke skill] --> B{Inputs valid?}
B -->|yes| C[Run inference]
B -->|no| D[Return error]
C --> E{Confidence high?}
E -->|yes| F[Produce output]
E -->|low| G[Present summary with warnings]
G --> H{User confirms?}
H -->|go| F
H -->|correction| C
style F fill:#c8e6c9
style G fill:#fff9c4
style B fill:#e1f5ff
style E fill:#e1f5ff
style H fill:#e1f5ff
```

Renders as: branching tree with green output node, yellow warning node, blue decision diamonds.

Behavioral sequence (sequenceDiagram)

Use when showing back-and-forth between named participants. Limited styling; keep it clean.

```mermaid
sequenceDiagram
participant You
participant Brief as /meeting-brief
participant Agenda as /meeting-agenda
participant Recap as /meeting-recap
You->>Brief: Schedule strategic meeting
Brief-->>You: Stakeholder reads + asks
You->>Agenda: Draft attendee-facing structure
Agenda-->>You: Time-boxed topics
Note over You,Recap: The meeting happens
You->>Recap: Capture decisions + actions
Recap-->>You: Topic summary + actions
```

Renders as: 4 lifeline columns with solid + dashed arrows showing the meeting-skills hand-off pattern.

State diagram (stateDiagram-v2)

Use when showing named states and transitions, not phases or interactions.

```mermaid
stateDiagram-v2
[*] --> Drafted
Drafted --> Reviewed: pm submits for review
Reviewed --> Approved: stakeholder signoff
Reviewed --> Drafted: revision requested
Approved --> Shipped: feature flag flipped
Shipped --> Measured: instrumentation live
Measured --> [*]
Measured --> Drafted: pivot decision
```

Renders as: 5 named states + transitions; entry from [*] and exit to [*].

Gantt timeline

Use when showing overlapping work with durations.

```mermaid
gantt
title v2.14.0 Migration Cycle
dateFormat YYYY-MM-DD
section Phase 0
Spike + decision :2026-05-06, 1d
section Phase 1
Foundation :2026-05-07, 2d
section Phase 2
Parity :2026-05-08, 2d
section Phase 3
Cutover :2026-05-09, 1d
section Phase 4
Material retirement :2026-05-10, 1d
Final validation :2026-05-10, 1d
```

Renders as: horizontal timeline with phase sections; bars sized to duration.

Dark mode considerations

Starlight switches the site between light and dark mode based on the user’s system preference or manual toggle. Mermaid’s autoTheme: true follows this via the data-theme attribute on <html> or <body>.

What changes automatically:

  • The base Mermaid theme switches between default (light) and dark (dark).
  • Edge labels, axis text, and other “framework” elements adapt.

What stays static:

  • classDef fills, strokes, and text colors are inline !important styles. They render the same in both modes.
  • style directive values stay static the same way.

Implication for your authoring:

  • Pick fills + strokes that work in both backgrounds. Light pastels with medium-saturation strokes work well because the high-contrast border preserves visibility on dark backgrounds.
  • Use the Triple Diamond palette as your default; it has been tested in both modes.
  • If you author a diagram where dark mode is jarring, prefer rgba() with an alpha < 1 so the background partially shows through. Example: fill:rgba(231,245,255,0.4) instead of fill:#e7f5ff. Caveat: rgba() with low alpha (below ~0.6) on dark backgrounds reduces the fill-text contrast and can make dark text unreadable. Stick with solid hex unless you have audited dark-mode text readability.

Audit 2026-05-10 (v2.14.x V1): the current Triple Diamond palette (solid hex pastels + 2px strokes + dark text) was audited via Playwright DOM eval on the home page in dark mode (forced via data-theme="dark"). Result: light pastel islands sit on the dark canvas with high-contrast borders; dark text remains readable on the light pastel fills (the inside-the-node contrast is preserved regardless of canvas color). Aesthetic verdict: functional but visually “bright islands on dark canvas.” A more harmonious dark-mode appearance would require a JS theme-listener that re-renders Mermaid with a different classDef palette on data-theme="dark" (deferred; v2.15+ scope). For now, the solid-hex palette is the accepted posture.

Common mistakes

MistakeSymptomFix
Using style in graph LR/TD for many nodesRepetitive declarations; hard to updateUse classDef + class instead
Using classDef in block-betaStyle directive ignored; nodes default-coloredUse inline style {block-id} ...
Triple Diamond palette on non-phase diagramsColor meaning conflicts with contentUse semantic colors (green/yellow/blue)
mermaid block in source SKILL.md uses ../../docs/... pathsPaths break when generator copies to docs/skills/{phase}/Generator’s rewrite_internal_paths() handles this; do not “fix”
Em-dash characters in diagram textHook blocks the file writeUse - (space-hyphen-space) instead
Missing subgraph titles in quotesParser fails on titles with special charactersAlways quote: subgraph "My Title"

Validation

Before committing a diagram:

  1. Em-dash discipline: zero U+2014 or U+2013 characters anywhere in the diagram source. Use python -c "with open('your-file.md','rb') as f: print(f.read().count(b'\xe2\x80\x94'))" to verify.
  2. Build PASS: npm run build should complete without warnings about your diagram.
  3. Visual smoke: navigate to the rendered page in a browser; confirm all blocks have rendered as SVG (not raw <pre class="mermaid"> text).
  4. DOM check: in the browser console: document.querySelectorAll('pre.mermaid svg').length should equal the number of mermaid blocks on the page; document.querySelectorAll('pre.mermaid:not(:has(svg))').length should be 0.

For agents: machine-readable summary

brand_palette:
global_edge_color: "#5C7CFA"
global_font_family: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif"
global_font_size: "14px"
triple_diamond_palette:
- phase: discover
fill: "#e7f5ff"
stroke: "#1971c2"
color: "#0c2d5e"
- phase: define
fill: "#e6fcf5"
stroke: "#0ca678"
color: "#0a4f3c"
- phase: develop
fill: "#f3e8ff"
stroke: "#7048e8"
color: "#3a1d8a"
- phase: deliver
fill: "#fff4e1"
stroke: "#d9480f"
color: "#5e2200"
- phase: measure
fill: "#fff9db"
stroke: "#e8a317"
color: "#5e3e00"
- phase: iterate
fill: "#ffe9ec"
stroke: "#c2255c"
color: "#5c0a25"
stroke_width_default: "2px"
syntax_by_diagram_type:
graph_lr_td: "classDef + class"
block_beta: "style {block-id}"
sequence_diagram: "note + rect (limited styling)"
state_diagram_v2: "classDef + class"
gantt: "section + class"
constraints:
no_em_dashes: true
no_en_dashes: true
prefer_dash_substitute: " - "
quote_subgraph_titles: true
generator_path_rewrite: "../../docs/ -> ../../"
rendering:
client_side: true
bundle: "code-split via astro-mermaid 2.0.1"
loads_only_on_pages_with: 'pre class="mermaid" elements'
auto_theme: true
data_theme_attribute_source: "Starlight html or body"