agentsclimarketplace

Generate diagram

Skill edmondop/diagram-claude-plugin/skills/generate-diagram

Use when generating diagrams, charts, or technical illustrations. Triggers on "create a diagram", "draw a flowchart", "generate an ERD", "make an architecture diagram", "sequence diagram", "state machine diagram", "block diagram", "pyramid diagram", "DAG", "C4 diagram", "context map", "use case diagram", "activity diagram", "subdomain decomposition", "excalidraw", "hand-drawn diagram", "sketch diagram", or any request for visual/graphical output in SVG or PNG format.From its SKILL.md

Install
npx -y skills add edmondop/diagram-claude-plugin --skill generate-diagram

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

19.5 KB, as published. Nobody here has run it

Diagram Generation

Generate professional diagrams by routing each request to the best-fit tool. For UML, C4, and DDD diagram types, use PlantUML (text-based, standard notation). For everything else, use Python libraries via uv inline scripts. For editable hand-drawn diagrams, use Excalidraw JSON.

Interaction Protocol

  1. Classify the diagram type. If ambiguous, ask:

    What kind of diagram?

    • C4 (Context / Container / Component)
    • UML Use Case
    • UML Activity / BPMN-style workflow
    • UML State Machine
    • DDD Context Map
    • Subdomain Decomposition (WBS)
    • ERD (Conceptual or Logical)
    • Flowchart / pipeline
    • Architecture (generic boxes + arrows)
    • Cloud/infra architecture (AWS, GCP, K8s icons)
    • Pyramid / stacked layers
    • Sequence diagram
    • Network / DAG
    • Block diagram
    • Excalidraw (editable, hand-drawn sketch style)
  2. Pick the tool from the routing table. For PlantUML types, do NOT offer Python alternatives — PlantUML is the only correct choice for standard notation. Skip to step 3.

  3. Ask output path: "Where should I save the diagram?" Default to current directory if the user doesn't specify.

  4. Check prerequisites based on the tool:

    For PlantUML:

    plantuml -version 2>/dev/null || docker image inspect plantuml/plantuml-cli:plantuml-cli-v1.0.1 >/dev/null 2>&1
    

    If neither is available, show:

    • macOS: brew install plantuml
    • Docker: docker pull plantuml/plantuml-cli:plantuml-cli-v1.0.1
    • Do NOT fall back to a Python approximation. Stop and ask the user to install one of the above.

    For Graphviz-dependent Python libraries:

    dot -V
    
  5. Load the relevant reference for the tool you picked (see below). Generate the diagram following that reference.

    • PlantUML: write a .puml file, render with plantuml -tsvg or Docker. Open the SVG.
    • Python: write a uv run-compatible inline script. Run it. Open the SVG.
    • Excalidraw: write a .excalidraw JSON file. Open it.
  6. MANDATORY: Run quality validation on every Graphviz-generated SVG before showing the result to the user. See Quality Validation below. Do NOT skip this step. Do NOT present a diagram as finished until it passes validation.

  7. Iterate on user feedback.

Routing Table

PlantUML (standard notation — no alternatives)

Diagram typeTemplate
C4 Context Diagramtemplates/c4-context.puml
C4 Container Diagramtemplates/c4-container.puml
UML Use Casetemplates/use-case.puml
UML Use Case (detailed)templates/use-case-detailed.puml
UML Activity Diagramtemplates/activity-diagram.puml
UML Activity (with decisions)templates/activity-diagram-decision.puml
UML State Machinetemplates/state-machine.puml
DDD Context Maptemplates/context-map.puml
Subdomain Decomposition (WBS)templates/subdomain-decomposition.puml
Conceptual ERDtemplates/conceptual-erd.puml
Logical ERDtemplates/logical-erd.puml
Logical ERD (changelog pattern)templates/logical-erd-changelog.puml
Logical ERD (users/roles)templates/logical-erd-users.puml

Reference: @references/plantuml.md

Python libraries (custom diagrams)

Diagram typePrimaryAlternative(s)When to pick alternative
Flowchart / pipelinegraphvizschemdrawNo Graphviz installed; simple linear flow
Generic architecturegraphvizgrandalf + drawsvgNo Graphviz installed; pure Python
Cloud/infra architecturediagrams (mingrammer)graphvizDon't need cloud provider icons
Pyramid / stacked layerssvgwritedrawsvgPrefer cleaner API, less precise control needed
Sequence diagramseqdiagsvgwriteseqdiag for speed; svgwrite for full control
Network / graph (cyclic)networkx + matplotlibgrandalf + drawsvgPure Python auto-layout without matplotlib
DAG (acyclic pipeline)svgwritegraphvizgraphviz for auto-layout; svgwrite for precision
Block diagramgrandalf + drawsvgblockdiag, schemdraw, draw.ioblockdiag for DSL; schemdraw for flow; draw.io for editable
Subdomain -> BC mappingdrawsvg--@references/examples/subdomain-bc-mapping.py — bipartite layout

References:

  • @references/graphviz.md — graphviz Python wrapper + layout tips
  • @references/python-svg-libraries.md — svgwrite, drawsvg, schemdraw + coordinate patterns
  • @references/python-diagram-libraries.md — diagrams, seqdiag, blockdiag, networkx, erdantic, grandalf, draw.io

Excalidraw (editable, hand-drawn sketch)

Diagram typeTool
Any (editable, sketch)Excalidraw JSON

Reference: @references/excalidraw.md

Draw.io (editable, precise)

Diagram typeTool
Any (editable, precise)draw.io (drawio skill)

Example Scripts

Working examples for each diagram type are in @references/examples/. Read the relevant example before generating a new diagram:

Diagram typeExample script
Architecture (generic)@references/examples/architecture-graphviz.py
Block diagram (blockdiag)@references/examples/block-blockdiag.py
Block diagram (schemdraw)@references/examples/block-schemdraw.py
Cloud/infra architecture@references/examples/cloud-arch-diagrams.py
ERD@references/examples/erd-graphviz.py
Flowchart (graphviz)@references/examples/flowchart-graphviz.py
Flowchart (schemdraw)@references/examples/flowchart-schemdraw.py
FSM / state machine@references/examples/fsm-graphviz.py
Network (graphviz)@references/examples/network-graphviz.py
Network (networkx)@references/examples/network-networkx.py
Pyramid (drawsvg)@references/examples/pyramid-drawsvg.py
Pyramid (svgwrite)@references/examples/pyramid-svgwrite.py
Sequence (seqdiag)@references/examples/sequence-seqdiag.py
Sequence (svgwrite)@references/examples/sequence-svgwrite.py
Subdomain -> BC mapping@references/examples/subdomain-bc-mapping.py

Script Template (Python libraries only)

All Python scripts use uv inline metadata:

# /// script
# requires-python = ">=3.10"
# dependencies = ["library-name"]
# ///
"""Description of what this diagram shows."""
from pathlib import Path
# ... imports ...

def main() -> None:
    Path("output").mkdir(exist_ok=True)
    # ... build diagram ...
    # ... save to output/ ...
    print(f"Saved: output/filename.svg")

if __name__ == "__main__":
    main()

Quality Validation

This is a hard requirement, not a suggestion. Every Graphviz-generated SVG must pass test_svg_quality.py before the diagram is considered done. Graphviz auto-layout frequently produces overlapping text, arrows crossing labels, and nodes bleeding outside cluster borders — problems that are invisible when you only look at the DOT source but immediately visible in the rendered SVG.

What the validator checks

CheckWhat it detects
Arrow crosses textAn edge path (Bezier curve) intersects a cluster label, edge label, or node label that does not belong to that edge
Text crosses borderA text label overlaps a cluster border path
Label overlapsTwo text labels occupy the same bounding box
Layout centeringClusters that should be centered are not drifting off-axis

How to run

# Validate a single SVG (CLI mode — no pytest needed at runtime)
uv run @references/examples/test_svg_quality.py output/my-diagram.svg

Output on success:

Parsed: 3 clusters, 12 nodes, 5 edge labels
✓ All checks passed!

Output on failure:

Parsed: 3 clusters, 12 nodes, 5 edge labels

ERRORS (2):
  ✘ Arrow apply->target_token crosses node 'target_token'
  ✘ node 'enc_secrets' crosses cluster_repo border

When validation fails — how to fix

ErrorCommon fix
Arrow crosses cluster/node labelIncrease ranksep, nodesep, or add minlen on the offending edge. Move annotation nodes to a different rank.
Node crosses cluster borderAdd margin="16" or margin="20" to the cluster c.attr().
Arrow crosses destination node textIncrease node margin (e.g., "0.3,0.2") so the text bounding box is well inside the node border.
Edge label too close to edgeUse midpoint label nodes (see Midpoint label nodes).
Labels overlapShorten labels, increase nodesep, or use rank="same" constraints.

Re-generate the SVG and re-run validation after every fix. Do not guess — the validator uses proper Bezier curve sampling and Shapely geometric intersection, which is more accurate than visual inspection.

Scope

The validator parses Graphviz SVG structure (it looks for a graph0 group element). It does not apply to:

  • svgwrite / drawsvg diagrams (no graph0 group)
  • PlantUML diagrams
  • Excalidraw files

For non-Graphviz diagrams, visual inspection is the only verification.

Source linting (edge label padding)

Also a hard requirement. Every graphviz diagram script must pass lint_diagram_source.py before the diagram is considered done.

On vertical edges, graphviz places label text flush against the arrow line — making it hard to read. Every edge label, xlabel, headlabel, and taillabel must have at least 2 spaces of padding on each side of every line. For multi-line labels, each line must be padded independently.

# Lint a single script
uv run @references/examples/lint_diagram_source.py my-diagram.py

# Lint all scripts in a directory
uv run @references/examples/lint_diagram_source.py docs/diagrams/

The linter uses Python's AST to find .edge() calls and check string literal arguments. It only scans files that import graphviz.

# BAD — label hugs the arrow line
dot.edge("a", "b", label="shared\nsecret")

# GOOD — padded with spaces (works for dot engine)
dot.edge("a", "b", label="  shared  \n  secret  ")

Exception for neato/fdp/sfdp engines: Space padding only helps with the dot engine (vertical/horizontal edges). For force-directed layouts (neato, fdp, sfdp), edges are at arbitrary angles so horizontal padding doesn't move text away from the line. Use the midpoint label node technique instead (see below).

Midpoint label nodes (edge label placement fix)

Graphviz places edge label and xlabel text directly on or very close to the edge path — especially with neato/fdp/sfdp, but also with dot on vertical edges. This makes labels hard to read.

Fix: Replace edge labels with invisible midpoint nodes. Split each labeled edge into two segments with a shape="none" node in between that carries the label text. The layout engine positions these nodes with natural spacing, keeping text readable.

# BAD — label sits on the edge path
dot.edge("a", "b", label="shared secret")

# GOOD — midpoint node carries the label, offset from the path
dot.node("_lbl_0", label="shared secret", shape="none", style="",
         fillcolor="none", fontsize="9", fontcolor="#555",
         width="0", height="0")
dot.edge("a", "_lbl_0", arrowhead="none")
dot.edge("_lbl_0", "b")

For multiple labeled edges, use a loop:

edges = [
    ("src1", "dst1", "label one", "#555"),
    ("src2", "dst2", "label two", "#555"),
]
for i, (src, dst, lbl, fc) in enumerate(edges):
    mid = f"_lbl_{i}"
    dot.node(mid, label=lbl, shape="none", style="", fillcolor="none",
             fontsize="9", fontcolor=fc, width="0", height="0")
    dot.edge(src, mid, arrowhead="none")
    dot.edge(mid, dst)

Trade-off: This makes diagrams slightly larger because each labeled edge becomes two edges with an intermediate node. Use it when:

  • Edge labels fail the check_edge_label_distance quality test
  • The diagram uses neato/fdp/sfdp (where xlabel doesn't help)
  • Labels on vertical dot edges remain unreadable despite space padding

For simple dot diagrams where space-padded labels pass validation, plain label=" text " is still preferred (simpler source).

Style Defaults

Unless the user specifies otherwise:

  • Font: Helvetica, Arial, sans-serif
  • Stroke: #333-#555, 1.2-2px
  • Fills: material-design 300/400 weight tones (soft, easy on the eyes). Avoid 700-900 weight fills (#C62828, #1a5ad7, #2E7D32, #6A1B9A) — they are too saturated for large node/cluster fills and strain the reader's eyes. Use lighter variants instead:
    • Red: #E57373 (300) instead of #C62828 (800)
    • Blue: #5C6BC0 (400) or #90CAF9 (200) instead of #1a5ad7
    • Green: #66BB6A (400) or #81C784 (300) instead of #2E7D32
    • Purple: #BA68C8 (300) instead of #6A1B9A
    • Reserve 700+ weights only for small accents (thin borders, edge colors)
  • Text: #333 for labels on light fills, white for labels on 400+ weight fills. #555 for annotations
  • No gradients, no decorative elements
  • PlantUML theme: transparent background, #5C6BC0 borders, #0b2147 text

Cluster Labels and Borders (Graphviz)

Always set labeljust="l" on every cluster. Centered labels (the default) sit in the path of vertical arrows entering the container from above. Left-aligning moves the label to the top-left corner, out of the arrow path. This should be applied unconditionally to all clusters.

When edges cross cluster borders, add minlen="2" to give the arrow, xlabel, and border enough vertical space. Do NOT increase cluster margin for this — margin adds internal padding, which pushes the border closer to external nodes and makes the problem worse.

Color Restraint

Limit each diagram to black + one accent color. Multiple accent colors (e.g., blue boxes, orange borders, green highlights, red warnings) create visual noise that distracts from the content. When comparing two states (bug vs fix, before vs after), use separate diagrams with different single accents (e.g., red for the bug, green for the fix) rather than mixing both colors in one diagram.

Font Sizing for Documentation

Default font sizes in diagram libraries are often too small when the diagram is embedded in documentation. Bump all text up ~2px from library defaults for readability:

  • Titles: 14-16px, bold
  • Node / participant labels: 11-12px, bold
  • Arrow / edge labels: 11px, bold (especially monospace labels like function calls — normal weight monospace is hard to read at small sizes)
  • Callout / annotation text: 10px, weight 500
  • Secondary text (separators, hints): 10px, use #555 not #888 for sufficient contrast

Complexity Reduction

When a diagram has repeated similar elements (e.g., multiple workers, multiple servers), show one expanded example with full detail and collapse the rest into a single placeholder node (e.g., "Worker 2 ... Worker N" with dashed style). This conveys the pattern without cluttering the diagram.

Split Over Combine

When comparing two states or scenarios (bug vs fix, before vs after), prefer two separate diagrams over one combined side-by-side diagram. Combined diagrams double the visual complexity and force the reader to parse both scenarios simultaneously.

SVG Quality Validation (Graphviz)

After generating a Graphviz diagram, validate the SVG with the quality test suite. The tests use svgpathtools for proper Bezier curve sampling and shapely for geometric intersection tests.

# Run all quality checks against a rendered SVG
uv run --with svgpathtools --with shapely --with pytest -- \
  pytest references/examples/test_svg_quality.py -v

# Quick CLI check against a specific SVG
uv run --with svgpathtools --with shapely --with pytest -- \
  python references/examples/test_svg_quality.py path/to/diagram.svg

Critical rules enforced:

  1. No arrow crosses any text — arrow Bezier curves must not pass through cluster labels, edge labels, or node labels
  2. No text crosses any border — no text element may overlap a cluster border line
  3. No label overlaps — no two text elements may overlap each other

Anti-pattern fixtures in packages/diagram-testkit/tests/fixtures/ show common layout problems that the tests catch:

FixtureAnti-pattern
architecture-arrow-crosses-label.svgArrows through cluster labels (naive regex missed these)
architecture-arrow-crosses-data-layer.svgBezier curve crosses label (only caught by svgpathtools)
architecture-centered-labels.svgCentered labels + rainbow colors + off-center data layer
labels-overlap.svgMultiple edge labels overlapping each other
text-on-border.svgEdge label sitting on a cluster border
rainbow-colors.svgMulti-color clusters with centered labels colliding with arrows
data-layer-off-center.svgData cluster positioned far from backend

When iterating on diagram layout, use the test suite as an objective function — keep adjusting the Graphviz source until all checks pass.

Fix patterns for common failures:

  • Arrow crosses cluster label → add invisible spacer node to widen cluster, pushing the left-justified label away from arrow entry points
  • Text crosses border → remove xlabel from cross-connection edges, or add minlen to create clearance
  • Labels overlap → increase nodesep, use constraint="false" on cross-connections, or remove redundant labels
  • Edge label too close to edge path → use midpoint label nodes (split edge into two segments with invisible shape="none" node carrying the label text). Required for neato/fdp/sfdp; recommended for dot when space padding alone doesn't pass validation

Additional References

  • @references/bounded-context-naming.md — rules for naming bounded contexts in DDD diagrams

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.