- name
- drawio-skill
- version
- 2.1.0
- description
- Use when the user requests diagrams, flowcharts, architecture diagrams, ER diagrams, UML / sequence / class diagrams, SysML / MBSE diagrams (block definition, internal block, requirement, parametric), BPMN business process diagrams, swimlane / cross-functional flowcharts, network topology, cloud architecture from Terraform or Kubernetes manifests, ML/DL model figures (Transformer/CNN/LSTM), mind maps, or any visualization. Also use proactively when explaining systems with 3+ components, complex data flows, or relationships that benefit from visual representation. Best suited when the diagram needs custom styling, rich shape vocabulary, swimlanes, or exportable images (PNG/SVG/PDF/JPG). Generates .drawio XML and exports locally via the native draw.io desktop CLI.
- license
- MIT
- homepage
- https://github.com/Agents365-ai/drawio-skill
- compatibility
- Requires draw.io desktop app CLI on PATH (macOS/Linux/Windows). Self-check step requires a vision-enabled model (e.g., Claude Sonnet/Opus); gracefully skipped if unavailable. Optional auto-layout (scripts/autolayout.py) needs Graphviz (dot).
- platforms
- ["macos","linux","windows"]
- metadata
- {"openclaw":{"requires":{"anyBins":"[Truncated]"},"emoji":"📐","os":["darwin","linux","win32"],"install":["[Truncated]","[Truncated]"]},"hermes":{"tags":["drawio","diagram","flowchart","architecture","visualization","uml"],"category":"design","requires_tools":["drawio","draw.io"],"related_skills":["mermaid","excalidraw","plantuml"]},"author":"Agents365-ai","version":"2.1.0"}
# Draw.io Diagrams
## Overview
Generate `.drawio` XML files and export to PNG/SVG/PDF/JPG locally using the native draw.io desktop app CLI.
**Supported formats:** PNG, SVG, PDF, JPG — no browser automation needed.
PNG, SVG, and PDF exports support `--embed-diagram` (`-e`) — the exported file contains the full diagram XML, so opening it in draw.io recovers the editable diagram. Use double extensions (`name.drawio.png`) to signal embedded XML.
## When to use / when NOT to use
**Use this skill for:** polished, precise diagrams (architecture, network, strict UML, ERD), anything needing solid opaque fills, 10,000+ stock/branded shapes, swimlanes, or custom geometry, exported as editable PNG/SVG/PDF.
**Do NOT use it — route elsewhere — for:**
- A casual hand-drawn / whiteboard look → **excalidraw** or **tldraw**.
- Diagrams-as-code that live in git / render in Markdown → **mermaid** (general) or **plantuml** (UML).
- Freeform infinite-canvas sketching or freehand strokes → **tldraw**.
## Bundled resources
When the workflow references one of these, read it on demand — none of them need to be in context up front.
| File | Read it when |
| --- | --- |
| `references/toolbox.md` | You're **not sure which bundled script fits** a request, or want to chain several — a map of all 31 scripts grouped by use-case (author / import code / import IaC / import API spec / live infra / compare / annotate / reverse-export / utilities) with an "I have X, I want Y → use Z" guide |
| `references/xml-authoring.md` | You're about to **hand-write `.drawio` XML** (workflow step 3) — file skeleton, shape/edge cells, containers, connection distribution, palette, spacing/grid rules. Not needed when a bundled generator writes the XML |
| `references/mermaid-authoring.md` | The diagram is a **standard type with no custom styling/icon needs** (flowchart, state, gantt, mindmap, timeline, journey, pie, …) and the CLI is **≥ v30** — author it as Mermaid text and let the CLI convert to native `.drawio` (structure only, layout free). Also documents the CLI's ELK `--layout` pass for XML |
| `references/diagram-types.md` | The user names a specific diagram type (ERD, UML class, sequence, C4, architecture, ML/DL, flowchart, SysML, BPMN, network topology, swimlane) |
| `references/shapes.md` + `scripts/shapesearch.py` | The diagram needs a **specific shape** — a cloud icon (AWS/Azure/GCP), Cisco/Kubernetes/network symbol, UML/BPMN/ER/electrical/P&ID element — or any time you'd otherwise guess a `style=` string. `shapesearch.py "<keywords>"` returns the exact official style for 10k+ shapes |
| `scripts/aiicons.py` | The diagram involves an **AI/LLM brand** (OpenAI, Claude, Gemini, Mistral, Llama, HuggingFace, Ollama, LangChain, …) — `aiicons.py "<brand>"` returns a draw.io `image` style for the brand logo (lobe-icons via CDN; `--embed` to inline). draw.io has no built-in AI logos. See `references/shapes.md` → "AI / LLM brand logos" |
| `references/style-presets.md` | The user asks to learn / save / list / set-default / delete a style preset, or you've resolved an active preset and need the application rules |
| `references/style-extraction.md` | You're inside the Learn flow and need the extraction procedure (called from `style-presets.md`) |
| `references/troubleshooting.md` | An export fails, vision rejects a PNG, or a rendering looks wrong |
| `scripts/repair_png.py` | After every `-e` PNG export — fixes draw.io's truncated IEND chunk (issue #8) |
| `scripts/encode_drawio_url.py` | The CLI is unavailable and you need a browser-fallback diagrams.net URL (`--edit` for an editable editor URL) |
| `references/autolayout.md` | The diagram is large or layout-heavy (dependency/call graph, code structure, >~15 nodes) and you want Graphviz to place nodes + route edges instead of hand-placing coordinates |
| `scripts/pyimports.py` · `jsimports.py` · `goimports.py` · `rustimports.py` | The user wants to visualize a **Python, JS/TS, Go, or Rust project** structure — extracts the import graph (transitive-reduced, optional `--group` containers, nested by sub-package) for autolayout |
| `scripts/pyclasses.py` | The user wants a **Python class hierarchy / class diagram** — extracts classes + inheritance edges (boxed by module with `--group`) for autolayout |
| `scripts/tfimports.py` · `k8simports.py` · `composeimports.py` | The user wants to visualize **declared** infrastructure (**Terraform** `.tf`, **Kubernetes** manifests, or **docker-compose**) — extracts the resource/service reference graph (official AWS/Azure/GCP/K8s icons for tf/k8s; service boxes + volume cylinders for compose) for autolayout |
| `scripts/tfstate.py` · `dockerimports.py` (+ `k8simports.py`) | The user wants to draw **what is ACTUALLY running / deployed** — pipe `terraform show -json` (deployed state), `docker inspect $(docker ps -q)` (live containers), or `kubectl get all,ing,cm,secret,pvc -o json` (live cluster, via k8simports) and get the real topology with the same official icons. See `references/live-infra.md` |
| `scripts/drawiodiff.py` | The user wants to **compare / diff two diagrams or two snapshots** ("what changed", infra drift) — `drawiodiff.py old.drawio new.drawio -o diff.json` emits a colour-coded graph (added=green, removed=red, changed=orange, same=grey) for autolayout. Matches by cell id (importer/live-snapshot output) or `--by-label` (hand-drawn) |
| `scripts/timelapse.py` | The user wants an **architecture time-lapse / to see how a codebase's structure evolved over git history** — `timelapse.py <dir> --importer pyimports` re-runs an importer at each sampled commit and assembles a self-contained HTML player (embedded frames, play/step controls). Best on a package with real import edges (point `<dir>` at the module root) |
| `scripts/explain.py` | The user wants to **describe / document / summarize an existing `.drawio` in words** (reverse of generating one) — `explain.py diagram.drawio` emits structured Markdown: components grouped by container/tier, relations (`A —label→ B`), per-page sections for multi-page/C4. Good for a README/PR summary or a text-only read-out |
| `scripts/drawio2pptx.py` | The user wants a **PowerPoint deck / slides from a diagram** — `drawio2pptx.py diagram.drawio -o deck.pptx` puts each page on its own 16:9 slide (page name as title), so a multi-page **C4 model** becomes a ready-to-present deck. Needs `python-pptx` (`pip install python-pptx`) + the draw.io CLI |
| `scripts/drawiohtml.py` | The user wants a **shareable interactive viewer** for a diagram (pan / zoom / search, no draw.io needed) — `drawiohtml.py diagram.drawio -o viewer.html` inlines every page's SVG into ONE self-contained HTML with page tabs, drag-pan, wheel-zoom, node search (Enter cycles + centres matches) and **working drill-down links** (a C4 model's `data:page/id` links switch tabs). No server, no external requests — send the file to anyone |
| `scripts/svgflow.py` | The user wants an **animated / "flowing" diagram** (data-flow, moving edges) — `svgflow.py diagram.drawio -o flow.svg` exports to SVG and makes every edge a marching-ants animation (dashes travel along the arrows). Self-contained looping `.svg` that renders on GitHub / any browser; `--speed` / `--dash` / `--reverse` |
| `scripts/drawio2mermaid.py` | The user wants to **convert a `.drawio` into Mermaid text** (diagrams-as-code for a Markdown file that GitHub renders) — `drawio2mermaid.py diagram.drawio` emits a `flowchart` (containers → `subgraph`s, edge labels kept, cylinder/rhombus shapes mapped); `--fenced` wraps in ```mermaid, multi-page → one graph per page. Structural only (styling/icons don't survive) |
| `scripts/sqlerd.py` | The user wants an **ER diagram from SQL DDL** — parses `CREATE TABLE` statements into per-table nodes (columns with PK/FK markers) and crow's-foot FK edges for autolayout |
| `scripts/ciimports.py` | The user wants a **CI pipeline diagram** (GitHub Actions workflows or GitLab CI) — `ciimports.py <repo-root>` reads `.github/workflows/*.yml` + `.gitlab-ci.yml` and emits jobs (runner, matrix size, reusable-workflow calls), `needs:` dependency edges, per-workflow trigger nodes, and stage/workflow containers for autolayout. Needs PyYAML |
| `scripts/openapiimports.py` | The user wants an **API diagram from an OpenAPI / Swagger spec** — `openapiimports.py spec.yaml` maps each operation to a node **coloured by HTTP method** (GET blue, POST green, PUT/PATCH orange, DELETE red) plus one node per component schema, with edges from operations to the schemas they use and between nested schemas. `--group` boxes by tag, `--no-schemas` shows just the endpoint surface; feeds autolayout |
| `scripts/heatmap.py` | The user wants to **colour an existing `.drawio` by data** (a cost / latency / traffic / error-rate heat map) — `heatmap.py diagram.drawio -m metrics.csv` matches each metric (CSV `key,value` or JSON `{key:value}`) to a node by id or label and recolours it along a gradient (`--palette heat\|cool\|warm`, `--reverse`), optionally scaling node size (`--size`) and adding a legend. Post-processes any diagram; export as usual |
| `scripts/seqlayout.py` | The user wants a **sequence diagram** — describe participants + messages as JSON and the script computes all lifeline/activation/arrow geometry deterministically (no hand-placed coordinates, no Graphviz needed) |
| `scripts/c4.py` | The user wants a **C4 model** (System Context / Container / Component) — levels JSON in, one multi-page `.drawio` out with official C4 shapes/colors and **click-to-drill-down** links between levels |
| `scripts/relabel.py` | The user wants a **language variant or bulk text swap of an existing `.drawio`** (e.g. an EN diagram re-labelled in Chinese for a bilingual README) — `relabel.py diagram.drawio --extract -o labels.json` dumps every label as an identity JSON map; translate the values (keep the keys), then `relabel.py diagram.drawio --map labels.json -o diagram_cn.drawio` swaps them with layout/styles/ids untouched |
| `scripts/restyle.py` | The user wants to **re-theme an EXISTING `.drawio`** ("make this dark", "apply my corporate style to this diagram") — `restyle.py diagram.drawio --preset <name>` remaps every vertex fill/stroke to the preset palette by hue, applies font/extras (dark fontColor, edge color, background), and leaves layout, shapes, and edge routing untouched. Presets resolve like Step 0 (user dir, then built-ins) |
| `scripts/edgeports.py` | Edges **stack on top of each other where they meet a shape** — the usual swimlane/cross-functional complaint, and anywhere a node has several connections leaving the same side. `edgeports.py diagram.drawio` pins `exitX/exitY`+`entryX/entryY`: it picks the side of each node facing the other endpoint, then spreads that side's edges over evenly-spaced slots **ordered by the far endpoint's position**, so they keep their relative order instead of crossing. Resolves absolute coordinates through swimlane parents, skips ends you already pinned, and is idempotent. It is a **port assigner, not a router** — it separates lines at the shape boundary, it will not stop an edge crossing an unrelated shape mid-run (add waypoints for that) |
| `scripts/validate.py` | You generated a `.drawio` (especially via autolayout or for a large hand-placed diagram) and want a fast deterministic structural lint (dangling edges, dup/reserved ids, broken parents, overlaps) before the vision self-check. `--score` prints a readability score for comparing layout variants |
| `scripts/raster2drawio.py` | The user has an **image of a diagram** (whiteboard photo, legacy PNG, Visio screenshot) and wants an **editable `.drawio`** — read the image with your own vision, extract nodes/edges as JSON (schema + full workflow in `references/derasterize.md`), then `raster2drawio.py graph.json -o out.drawio` honours those coordinates/labels/shapes; nodes missing `x`/`y` fall back to `autolayout.py` placement |
| `scripts/buildup.py` | The user wants a diagram to **build itself node-by-node** as a video/GIF (a construction time-lapse of ONE static diagram — distinct from `timelapse.py`'s git-history animation) — `buildup.py diagram.drawio` reveals cells in topological (dependency) order into a self-contained HTML player (play/pause/step/scrub); `--gif` also exports an animated GIF (needs Pillow). Needs the draw.io CLI |
| `scripts/compress.py` | The user wants an **executive / boardroom summary of a big diagram** — collapses clusters (pure-Python label propagation, no networkx) into one labeled node each with aggregated inter-cluster edges, emitting a 2-page `.drawio` (exec view + click-to-drill-down into the full original). Claude can rename clusters semantically afterward. Needs Graphviz `dot` |
| `scripts/runbook.py` | The user wants a flowchart/decision-tree `.drawio` turned into a **click-through triage app** (on-call runbook) — `runbook.py flow.drawio` reads the XML (no draw.io CLI needed) and emits a self-contained HTML runbook: current-step text, per-edge choice buttons, breadcrumb trail, Back/Restart, end-state on terminal nodes |
| `scripts/prdiff.py` | You're setting up **automated PR diagram review** in CI — for every `.drawio` changed between two git refs it renders base/head/diff PNGs and emits a Markdown report; ships with a composite GitHub Action (`.github/actions/drawio-diff/`) that posts a sticky PR comment. See `references/pr-bot.md` |
| `scripts/tubemap.py` | The user wants a **metro / subway / tube map** — a system, pipeline, or journey drawn as coloured transit lines with octilinear (H/V/45°) routing, white interchange circles, and station stops. Compose a metro JSON (lines = ordered stations on an integer grid, shared stations = interchanges), then `tubemap.py metro.json -o metro.drawio`. Stdlib-only; schema + the one grid rule in `references/tubemap.md` |
## Prerequisites
The draw.io desktop app must be installed and the CLI accessible:
**macOS sandbox / sandbox isolation note (e.g., codex.app):** In some sandboxed macOS environments, invoking the draw.io desktop CLI (even `drawio --version`) can crash the draw.io process or produce no output. If that happens, treat the CLI as **unavailable in this sandbox isolation** — do not keep retrying inside the sandbox. Prefer a **non-sandboxed host environment** (outside sandbox isolation) for any CLI export work, or use the browser fallback / XML-only outputs.
```bash
# macOS (Homebrew — recommended; CLI binary is `drawio`, not `draw.io`)
brew install --cask drawio
drawio --version
# macOS (full path if not in PATH)
/Applications/draw.io.app/Contents/MacOS/draw.io --version
# Windows
"C:\Program Files\draw.io\draw.io.exe" --version
# Linux
drawio --version
```
Install draw.io desktop if missing:
- macOS: `brew install --cask drawio` or download from <https://github.com/jgraph/drawio-desktop/releases>
- Windows: download installer from <https://github.com/jgraph/drawio-desktop/releases>
- Linux: download `.deb`/`.rpm` from <https://github.com/jgraph/drawio-desktop/releases> — **do not use snap** (AppArmor sandbox denies secrets/keyring on servers, causes crash)
## Workflow
Before starting the workflow, assess whether the user's request is specific enough. If key details are missing, ask 1-3 focused questions:
- **Diagram type** — which preset? (ERD, UML, Sequence, Architecture, ML/DL, Flowchart, SysML, BPMN, Network, Swimlane, or general)
- **Output format** — PNG (default), SVG, PDF, or JPG?
- **Output location** — default is the user's working dir; honor any explicit path the user gives (e.g. "put it in `./artifacts/`"). Don't ask if they didn't mention one.
- **Scope/fidelity** — how many components? Any specific technologies or labels?
Skip clarification if the request already specifies these details or is clearly simple (e.g., "draw a flowchart of X").
**Step 0 — Resolve active preset.** Determine which (if any) user-defined style preset applies to this generation.
- Scan the user's message for a phrase that clearly names a style preset: "use my `<name>` style", "with my `<name>` style", "in `<name>` mode", "in the style of `<name>`". A bare `with <name>` does **not** count — "draw a diagram with redis" names a component, not a style. If a clear match is found → active preset = `<name>`.
- Else, check `~/.drawio-skill/styles/` for any file with `"default": true`. If found → active preset = that one.
- Else → no preset active; fall through to the built-in color/shape/edge conventions for the rest of the workflow.
Load the preset JSON from `~/.drawio-skill/styles/<name>.json`, falling back to `<this-skill-dir>/styles/built-in/<name>.json`. If the named preset exists in neither location, tell the user the name is unknown, list the available presets (user dir + built-in), and stop — do **not** silently fall back to defaults.
When a preset loads successfully, mention it in the first line of the reply: *"Using preset `<name>` (confidence: `<level>`)."* See `references/style-presets.md` → "Applying a preset" for how the preset changes color/shape/edge/font decisions.
View on GitHub