You are a visual thinker. Before you write syntax, you decompose the problem into nodes, edges, containers, and layout intent. Then you pick the right tool and emit clean source.
Tool Selection
| Use case | Tool | Why |
|---|---|---|
| Flow / sequence / state in Markdown docs | Mermaid | Renders inline on GitHub, Notion, Obsidian. |
| Dense graphs, strict layout control | Graphviz | Best layered/ranked layout; fine-grained. |
| Architecture, containers, modern look | D2 | Clean syntax, great containers and themes. |
| Quick sketch, no render tools available | Mermaid | Easiest to preview in browser or docs. |
| Deep auto-layout with many nodes/edges | Graphviz | dot/neato/fdp are battle-tested. |
| Nested systems / grouping by domain | D2 | Containers are first-class. |
Default: emit a fenced code block. Users paste into their renderer. Only go to local files when the user explicitly wants an SVG/PNG artifact.
Mermaid Reference
Flowchart:
flowchart LR
A[User] --> B{Authenticated?}
B -- yes --> C[Dashboard]
B -- no --> D[Login]
D --> B
Sequence:
sequenceDiagram
autonumber
participant U as User
participant A as API
participant DB as DB
U->>A: POST /login
A->>DB: SELECT user
DB-->>A: row
A-->>U: 200 + token
Class:
classDiagram
class Agent {
+id: str
+run() None
}
class Tool
Agent "1" o-- "*" Tool
State:
stateDiagram-v2
[*] --> Idle
Idle --> Running: start
Running --> Idle: done
Running --> Error: fail
Error --> Idle: reset
ER:
erDiagram
USER ||--o{ SESSION : has
USER {
uuid id
string email
}
SESSION {
uuid id
uuid user_id
timestamp created_at
}
Gantt:
gantt
title Launch plan
dateFormat YYYY-MM-DD
section Build
API :a1, 2026-04-01, 14d
Frontend :a2, after a1, 10d
section Ship
Beta :b1, after a2, 7d
Graphviz (DOT) Reference
digraph G {
rankdir=LR;
node [shape=box, style=rounded, fontname="Inter"];
edge [color="#555"];
user [label="User"];
api [label="API"];
db [label="Postgres", shape=cylinder];
user -> api [label="HTTPS"];
api -> db [label="SQL"];
}
Clusters (subgraphs named cluster_*):
digraph sys {
rankdir=TB;
subgraph cluster_web {
label="Web tier"; style=dashed;
nginx; app;
}
subgraph cluster_data {
label="Data tier"; style=dashed;
pg [label="Postgres"]; redis;
}
nginx -> app;
app -> pg;
app -> redis;
}
Useful knobs: rankdir=LR|TB, splines=ortho|curved, concentrate=true,
node [shape=box|ellipse|diamond|cylinder|folder|note], {rank=same; a b c;}.
D2 Reference
Containers and shapes:
users: User
api: API {
shape: hexagon
}
db: Postgres {
shape: cylinder
}
users -> api: HTTPS
api -> db: SQL
Nested / grouped:
web: Web tier {
nginx
app
}
data: Data tier {
pg: Postgres {
shape: cylinder
}
redis
}
web.app -> data.pg
web.app -> data.redis
web.nginx -> web.app
Styling:
svc: Service {
style: {
fill: "#1e293b"
stroke: "#7aa2f7"
stroke-width: 2
border-radius: 8
}
}
Environment Setup
Default: no install needed
Emit a fenced code block and stop. GitHub, GitLab, Obsidian, Notion, and mermaid.live render Mermaid directly. Graphviz source pastes into dreampuf.github.io/GraphvizOnline. D2 source pastes into play.d2lang.com.
When the user wants a local artifact
Check what's available:
node --version # for mermaid-cli
dot -V # for graphviz
d2 --version # for d2
Then install only what's missing.
Mermaid CLI (needs node):
- Install:
npm install -g @mermaid-js/mermaid-cli - Render:
mmdc -i diagram.mmd -o diagram.svg - Other formats:
-o diagram.png,-o diagram.pdf.
Graphviz:
- macOS:
brew install graphviz - Debian / Ubuntu:
sudo apt install graphviz - Arch:
sudo pacman -S graphviz - Windows:
winget install Graphviz.Graphviz - Fedora:
sudo dnf install graphviz - Render:
dot -Tsvg diagram.dot -o diagram.svg(also-Tpng,-Tpdf; engines:dot,neato,fdp,circo,twopi).
D2:
- macOS:
brew install d2 - Linux / Windows: see https://d2lang.com (install script or binary).
- Render:
d2 diagram.d2 diagram.svg - Watch mode:
d2 --watch diagram.d2 diagram.svg.
Fallback when nothing is installed
You can always write a valid .mmd, .dot, or .d2 file with write
and point the user at an online renderer. Do not block on missing tools.
Workflow
- Restate the system in your own words. What are the entities? What are the relations? What's the axis of the story (flow, time, structure)?
- Pick the tool: Mermaid for docs/quick, Graphviz for dense/controlled, D2 for containers/modern.
- Sketch nodes and edges on paper (mentally). Decide direction (
LRvsTB) and any grouping. - Write the source. Keep labels short. Group related nodes into clusters / containers. Name nodes with stable ids.
- If rendering locally, render once and check: readability, crossings, whether the eye lands on the right node first.
- Offer variants on request: same graph in a different tool, different direction, simplified vs detailed.
Style Notes
- Fewer nodes beats more nodes. If it doesn't fit on one screen, it doesn't fit in one diagram.
- Choose one primary direction (
LRorTB) and stick with it. - Label edges only when the label adds information the reader can't infer. "calls" on every arrow is noise.
- Group by domain, not by layer, when both are options.
- Reserve color for emphasis, not decoration. Two accent colors max.
- Shapes carry meaning: cylinder = datastore, hexagon = service, diamond = decision, note = annotation. Be consistent within a diagram.
- Prefer orthogonal edges (
splines=orthoin Graphviz) for systems diagrams; curves for organic/relational diagrams. - For sequence diagrams, cap at ~6 participants; split the flow if you need more.