Install
$ agentstack add skill-vanducng-skills-diagram ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
vd:diagram
Turn natural-language descriptions into reviewable diagram images and version-controlled diagram artifacts. Two render paths:
- PNG (default): generates the image. Default image provider is codex (
gpt-image-2via your ChatGPT subscription — cost-optimized, no per-image API spend), with automatic fallback to OpenRoutergpt-5.4-image-2when codex is unavailable and an OpenRouter key is set. Force the API path with--provider openrouter. With--provider codexand an explicit--type, noOPEN_ROUTER_KEY/OPENROUTER_API_KEYis required. - SVG (
--format svg): the LLM emits the SVG markup directly. Cheaper, crisper labels, hand-editable.
Use --versioned only when the diagram source, variants, and manifest are themselves review artifacts for an ADR/spec/PR. It writes a stable folder under docs/diagrams// with:
diagram.spec.yaml— reviewable source intent (type, preset, engine, description, latest variant)manifest.json— deterministic metadata for automationv1.svg,v2.svg, ... orv1.png,v2.png, ... — rendered variants
For a diagram that merely illustrates a docs page, keep the generation session in the injected Visuals: path, copy the final rendered image into the docs' local assets folder (for example docs/design/assets/.svg), and link that one asset from Markdown. Do not create docs/diagrams/ just because a docs page references an image.
Quick Start
# Resolve the Python interpreter: shared venv when present, else plain python3 (`pip install --user requests`)
PY="$([ -x "$HOME/.claude/skills/.venv/bin/python3" ] && echo "$HOME/.claude/skills/.venv/bin/python3" || echo python3)"
# Auto-detect type, default PNG
$PY $HOME/skills/skills/diagram/scripts/generate.py \
"system architecture for an OAuth signup flow with FastAPI backend"
# Explicit type, SVG output
$PY $HOME/skills/skills/diagram/scripts/generate.py \
--type sequence --format svg \
"user logs in: User → App → Auth Provider → callback"
# Version-controlled workflow artifact for docs/diagrams/
$PY $HOME/skills/skills/diagram/scripts/generate.py \
--type workflow --format svg --versioned --slug checkout-fulfillment \
"checkout workflow from cart review through payment, fraud check, warehouse pick, and shipment"
# Iterate on the latest diagram with feedback
$PY $HOME/skills/skills/diagram/scripts/generate.py \
--regen "make the auth box use the warning color"
# Pick a different visual style preset (cyberpunk for talk slides)
$PY $HOME/skills/skills/diagram/scripts/generate.py \
--preset cyberpunk \
"data flow: Kafka → Spark → ClickHouse → Grafana"
# Use a clear draft/screenshot as layout guidance for Codex PNG generation
$PY $HOME/skills/skills/diagram/scripts/generate.py \
--format png --provider codex --reference-image draft.png \
"polished cloud architecture diagram; follow the reference layout exactly"
Interactive HTML ERD (er_html.py)
For database ER diagrams that need to be explored, not just viewed, use the deterministic er_html.py generator (no LLM, no API key). It emits one self-contained HTML file built on Cytoscape.js with a fully interactive graph:
- HTML ER cards (header band in domain-group colour,
◆PK /→FK glyphs, column types) drawn inside the graph via cytoscape-node-html-label - draggable nodes (edges follow), curved edges, pan/zoom, re-layout
- single-click a table → spotlight it + its relationship chain; the participating FK columns are highlighted inside the cards (not as text on the lines)
- click a relationship line → spotlight just its two joined tables, mark the join columns, and open a relationship summary (cardinality +
ON DELETE+ both columns) - selectable highlight depth (1 / 2 / 3 / All hops; default 1) for the chain
- hide/show individual entities (card
×to hide; sidebar eye or "show N hidden" to restore) - find-path between two tables (shortest FK chain, highlighted with join columns)
- schema insights panel (missing PK, FK type mismatch, unindexed FK, orphan tables — click to jump to the table)
- shareable URL (filters/selection encoded in the link) + saved layout (dragged positions persist per schema in localStorage)
- group hulls (colored regions behind domain groups) + a minimap (click/drag to navigate)
- double-click a table → details drawer (columns, types, PK/FK/audit badges, FK targets +
ON DELETErules, incoming references, indexes, row counts) - crow's-foot cardinality at edge ends (
1/N,1:1when the FK is unique); edge colour encodesON DELETE(CASCADE/SET NULL/NO ACTION) - per-entity "show all columns" expander (header
⊕or the "+N more" row) - live search (tables + columns), domain-group filters, show/hide audit columns, show/hide framework tables, columns-on-nodes toggle
- collapsible left (filters) + right (details) sidebars
- keyboard shortcuts + a
?help overlay (/search,a/t/c/ntoggles,[/]panels,ffit,gre-layout,+/-zoom,sclear,rreset,Esc)
By default it inlines Cytoscape (~450 KB total) so the file works fully offline; pass --cdn for a ~75 KB file that loads Cytoscape from jsdelivr.
# 1a. introspect a Postgres DB into schema.json (psql; no python DB deps)
psql "$DSN" -t -A -c "$(python3 $HOME/skills/skills/diagram/scripts/er_html.py --print-sql)" > schema.json
# 1b. OR a MySQL DB (8.0+ / MariaDB 10.5+). --raw is REQUIRED (default --batch escaping corrupts JSON);
# -D selects the DB so DATABASE() resolves; pass the password via MYSQL_PWD, never on the cmdline.
MYSQL_PWD="$DB_PASS" mysql -N --raw -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USER" -D "$DB_NAME" \
-e "$(python3 $HOME/skills/skills/diagram/scripts/er_html.py --print-sql --dialect mysql)" > schema.json
# 2. (optional) write meta.json — domain groups, classifications, descriptions, framework_tables, audit_columns
# (add "database_type": "MySQL" so --emit-dbml labels the Project correctly)
# see the docstring in er_html.py for the shape
# 3. generate the interactive ERD
python3 $HOME/skills/skills/diagram/scripts/er_html.py \
--schema schema.json --meta meta.json -o erd.html # self-contained (offline)
# add --cdn for a ~140 KB file that pulls Mermaid/svg-pan-zoom from jsdelivr
DBML interop (dbdocs.io / dbdiagram.io)
The generator round-trips with DBML:
# export our schema → DBML (no deps) — publish with `dbdocs build`, or paste into dbdiagram.io
er_html.py --schema schema.json --meta meta.json --emit-dbml schema.dbml
# import a .dbml → our schema JSON → interactive HTML (needs @dbml/core: npm i @dbml/core)
node $HOME/skills/skills/diagram/scripts/dbml_to_schema.mjs schema.dbml > schema.json
er_html.py --schema schema.json -o erd.html
# extract a live DB straight to DBML with the official tool (alternative to our --print-sql):
# npm i -g @dbml/cli && db2dbml postgres '?schemas=public' -o schema.dbml
So: DB → DBML via our --emit-dbml (from introspected JSON) or db2dbml; DBML → our HTML via dbml_to_schema.mjs. The DBML carries tables, columns (pk/not null), Ref … [delete: …], and domain TableGroups.
Schema JSON is DB-agnostic (any source that emits the documented shape works). meta.json is optional but recommended — it drives the colored domain groups, the write-pattern classification shown in the docs drawer, and which tables are hidden as "framework" by default. When to use this vs the image/SVG er type: HTML for living schema docs you click through and filter; SVG (--type er --format svg --versioned) for a static, diffable diagram in a PR/RFC.
Setup
export OPEN_ROUTER_KEY="sk-or-v1-..." # or OPENROUTER_API_KEY; required for SVG, auto-type classification, or --provider openrouter
# one-time: ensure file-browser viewer deps are installed
cd $HOME/skills/skills/file-browser && npm install
Get an OpenRouter key at . Codex PNG generation uses the Codex CLI ChatGPT login instead.
How it works
- Parse args — description + flags.
- Resolve session dir —
VD_VISUALS_PATHwhen set, else the current repo's resolved workbench visuals path, else/.diagrams/-/. Outside a git repo:~/Documents/llm-diagrams/-/. - Classify type — if
--typenot provided, OpenRouter classifies into one of 8 types. - Load refs — preset style tokens,
references/style-foundations.md,references/composition-rules.md,references/types/.md, plusreferences/svg-contract.mdfor SVG runs. - Prompt OR emit — PNG: build a Codex prompt locally, or refine through OpenRouter when using
--provider openrouter. SVG: LLM emits markup directly. - Save — scratch mode writes
v1.png/v1.svg+prompt.md+meta.json; versioned mode also writesdiagram.spec.yaml+manifest.json. Spawn the file-browser gallery.
Diagram types
| Type | Alias | When prompt mentions… | | --- | --- | --- | | system-architecture | arch | services, components, deployment, infrastructure | | data-flow | flow | data flows, transformations, sources/sinks, pipeline | | workflow | wf, process | steps, approvals, handoffs, swimlanes, business process | | sequence | seq | "user does X then Y", interactions over time, API calls | | er-diagram | er | entities, tables, relationships, schema | | state-machine | state | states, transitions, lifecycle, status | | c4-context | c4 | system in its environment, external users + systems | | c4-container | — | internal containers (web, api, db, queue) inside a system |
Flags
| Flag | Default | Notes | | --- | --- | --- | | description (positional) | — | Free-text. Required unless --regen. | | --type | auto-classify | One of the 8 types or an alias. | | --preset | warm | Visual style: warm, mono, pastel, cyberpunk. See "Style presets" below. | | --format | png | png or svg. | | --provider | codex | PNG image backend. codex: gpt-image-2 via ChatGPT subscription — cost-optimized, OpenRouter fallback. openrouter: gpt-5.4-image-2 via API. | | --quality | medium | low, medium, high. PNG only; OpenRouter passes through. | | --aspect-ratio | 16:9 | PNG only. | | --reference-image | none | Attach a draft/screenshot to Codex PNG generation; repeat for multiple images. Ignored by SVG and OpenRouter fallback. | | --regen "" | — | Iterate on the most recent session. Inherits preset/type/format from prior session. | | --new | off | Force a fresh session even when a recent one exists. | | --no-open | off | Skip auto-opening the browser tab. | | --slug | derived | Override the slug in the session dir name. | | --versioned | off | Write git-trackable artifacts under docs/diagrams// instead of ignored scratch output. |
Capability Matrix
| Need | Recommended mode | Why | | --- | --- | --- | | Architecture or C4 diagrams for PR/RFC review | --format png --provider codex --reference-image draft.png | Use a simple draft to lock layout, then let gpt-image-2 render a cleaner cloud diagram. | | Diffable architecture specs | --format svg --versioned --engine skeleton | Stable coordinates, crisp labels, deterministic spec + manifest. | | Workflow/process maps | --type workflow --format svg --versioned | Swimlane/stage-friendly layout with decision and handoff conventions. | | ERD/database design (static, diffable) | --type er --format svg --versioned | Entities and relationships stay hand-editable and diffable. | | Explorable/living DB docs (filter, search, per-table docs) | er_html.py --schema … --meta … | Self-contained interactive HTML ERD; no LLM/API key. | | Explanatory image embedded in docs | scratch output, then copy final asset to docs/**/assets/ | Keeps specs/manifests out of project docs when only the image matters. | | Presentation or executive visuals | --format png --preset pastel | Higher visual richness; keep as scratch unless the image belongs in docs. | | Fast iteration on a draft | default scratch output or --regen | Avoids polluting docs until the shape stabilizes. |
Engines
vd:diagram is moving toward a two-pass architecture for structurally-rich diagram types: pass-1 LLM emits a YAML skeleton (structure only); Python computes coordinates; pass-2 LLM paints the SVG with positions locked.
--engine selects between free (pure-LLM SVG path, kept as the escape hatch) and skeleton (YAML → layout → paint). SVG defaults to skeleton for system-architecture, data-flow, workflow, c4-context, c4-container, and er-diagram; sequence and state-machine still default to free. See references/skeleton-contract.md and references/painter-contract.md for the contracts.
Workflow skeleton layouts use horizontal swimlane rows: groups become ownership lanes top-to-bottom, and steps flow left-to-right inside each row. Other skeleton types keep the group-column layout.
Style presets
All presets share the same iconography, line weights, density limits, and label-placement rules. Only the palette and aesthetic feel differ.
| Preset | Surface | Primary | Accent | When to pick it | | --- | --- | --- | --- | --- | | warm (default) | cream #faf8f3 | deep slate | warm amber | Pitch decks, design docs, blog hero images, internal architecture write-ups | | mono | white #ffffff | near-black | none — uses 3.5px border + [Subject] tag for highlight | PR-diffable engineering docs, B&W print, technical specs, RFCs | | pastel | slate-50 #f8fafc | slate-800 | sky-600 | PowerPoint, executive presentations, customer-facing docs, marketing | | cyberpunk | near-black #0a0e1a | slate-200 | neon cyan + glow | Conference slides, demo videos, dev-tool launch graphics, OG/social |
Customizing a preset: edit references/presets//style-tokens.md. Palette + aesthetic + CSS-vars block live there. Iconography and rules live in shared style-foundations.md and composition-rules.md.
Adding a new preset: create references/presets//style-tokens.md following the warm template, then add the name to SUPPORTED_PRESETS in scripts/generate.py. No other code changes needed — type refs are preset-agnostic.
Output location
Scratch (non-versioned) output: write to VD_VISUALS_PATH when set; otherwise use the repo workbench resolver. In feature-first repos this is usually the injected Visuals: path, falling back to the global scratch visuals path when there is no feature signal. Each session gets a -/ subdir. Treat this as the home for brainstorming, reports, and review iterations; promote only the final rendered image to a docs assets folder when a docs page needs a visual.
- Outside a git repo →
~/Documents/llm-diagrams/--/ - With
--versioned→/docs/diagrams//(always; versioned diagrams stay indocs/)
Inside a git repo, scratch output is auto-ignored by the .gitignore managed in the resolved visuals/session parent. Your repo's root .gitignore is never touched.
Each session dir contains:
v1.,v2., … — the variantsprompt.md— original description, refined prompt, iteration historymeta.json— type, format, models, original description, list of variant filenamesdiagram.spec.yaml— versioned mode only; source intent for code reviewmanifest.json— versioned mode only; latest variant + deterministic metadata
See references/versioned-artifacts.md for artifact conventions and review workflow.
Final output handoff
When reporting a finished diagram, give the user an openable location, not just v1.svg or a session folder name:
- Primary rendered file as a clickable absolute file link:
[v2.svg](/absolute/path/to/v2.svg) - Plain browser URI when useful:
file:///absolute/path/to/v2.svg - Session directory path, so they can find
prompt.md,meta.json, and prior variants - For
--versioned, includediagram.spec.yamlandmanifest.jsonalongside th
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: vanducng
- Source: vanducng/skills
- License: MIT
- Homepage: https://skills.vanducng.dev
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.