Skill
Clean architecture and system-design diagrams as SVG — designed to be authored by LLMs. Single-spine arrow routing, 16:9 aspect-ratio-aware, zero deps. Includes a Claude Code skill bundle.
npx -y skills add wasulajr/spinediagrams --skill skillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 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.
What its author says it does
Copied from the file, not written here
Generate clean architecture and system-design diagrams as SVG files. Use this skill whenever the user wants to visualise how services, systems, or components connect: migration diagrams, current-state vs target-state architectures, integration maps, data-flow diagrams, platform overviews, or any diagram that shows technology boxes with arrows between them. Triggers on phrases like: "draw a diagram", "make an architecture diagram", "show me how X connects to Y", "create a system diagram", "architecture SVG", "visualise the stack", "diagram this", or whenever the conversation has produced a list of components and integrations that would benefit from a visual. Always use this skill rather than trying to write SVG by hand.
SKILL.md
13.5 KB, as published. Nobody here has run it
Architecture Diagram SVG Skill
Produces fixed-width (1600 px) SVG architecture diagrams with:
- A title / subtitle header band at the top
- A 6-column grid with up to 3 rows of technology containers (each container holds colour-coded component nodes)
- Orthogonal single-spine edge routing. All connection lines travel through the spine zone(s) between adjacent rows so they never pass through container bodies.
- A status-colour legend at the bottom
Workflow
- Understand the diagram. Identify the technology containers (lanes), the components inside each, and the connections between them.
- Build the config dict (see format below).
- Run the engine and save the SVG.
- Icon gate (MANDATORY). Every render prints an icon check report. If it
says
ICON CHECK FAILED, the diagram is NOT done: resolve every listed node (run/get-icon <technology>, set an explicit icon key, or rename the node to the canonical technology name), re-render, and repeat until the report saysIcon check: OK. Suppress an icon (spine: 5th node field""; flow:"icon": ""on the node) only for genuinely non-technology nodes: people, teams, abstract concepts. Never present an SVG whose last render reported missing icons. (If you rendered viaimportinstead of the CLI, print the check yourself:from svg_engine import icon_report; print(icon_report(d)).) - Present the file to the user.
Engine location
<skill_dir>/scripts/svg_engine.py
Import or call it directly:
# Option A: import
import sys
sys.path.insert(0, "<skill_dir>/scripts")
from svg_engine import Diagram
d = Diagram(config) # config is a dict (see format below)
svg = d.render()
with open("output.svg", "w") as f:
f.write(svg)
# Option B: CLI (config must be written to a JSON file first)
# python <skill_dir>/scripts/svg_engine.py config.json output.svg
Config format
config = {
"title": "Main Title — Optional subtitle", # " — " (em dash) splits title from subtitle
"num_cols": 6, # optional, default 6; increase for more lanes per row
"aspect": "16:9", # optional, default "16:9". Also accepts "4:3" or a
# numeric width/height ratio. Canvas pads to this
# ratio by growing the spine, which spaces arrow
# labels further apart.
# ── Lanes (containers) ──────────────────────────────────────────────────
# Each key becomes the lane identifier used in nodes/connections.
# For well-known vendors, just use the preset key (no colours needed).
# For custom lanes, supply bg / border / header_bg.
"lanes": {
"sf": { # preset key -> colours auto-filled
"label": "Salesforce",
"col": 0, "colspan": 2, "row": 0
},
"gcp": {
"label": "GCP Platform",
"col": 0, "colspan": 2, "row": 1
},
"custom": { # custom lane -> supply colours
"label": "My Service",
"col": 2, "colspan": 1, "row": 0,
"bg": "#f0fdf4", "border": "#16a34a", "header_bg": "#bbf7d0"
}
},
# ── Nodes ───────────────────────────────────────────────────────────────
# Each list entry: ["label", "status"] or with optional fields:
# ["label", "status"]
# ["label", "status", "category"]
# ["label", "status", "category", True] # primary (bold + border ring)
# ["label", "status", "category", True, "icon"] # explicit icon key override
# Status values: existing | new | transitioning | retiring | operational | readonly
"nodes": {
"sf": [["CRM", "existing"], ["Billing", "transitioning"]],
"gcp": [["Cloud SQL", "new"], ["API Gateway", "new"]],
"custom": [["Auth Service", "new"]]
},
# ── Connections ─────────────────────────────────────────────────────────
# Each entry: [src_lane, src_node_label, dst_lane, dst_node_label, edge_label]
# src/dst_node_label must exactly match a node label in that lane.
# Edge label is shown inline on the routing line.
"connections": [
["sf", "Billing", "gcp", "Cloud SQL", "Pub/Sub sync"],
["gcp", "API Gateway", "sf", "CRM", "Write-back"]
]
}
The em dash inside the title string is API syntax, not prose. The engine literally splits the title field on — to separate title from subtitle.
Grid layout rules
The diagram has up to 3 rows and up to num_cols columns (default 6).
Assign each lane a col (0-based), colspan, and row (0 = top, 1 = middle, 2 = bottom). Lane widths in a row must not overlap: col + colspan for each lane must stay within num_cols. Row 2 is optional; omit it for a classic 2-row diagram.
Suggested 2-row layout:
| Row | Col 0-1 (span 2) | Col 2 | Col 3 | Col 4 | Col 5 |
|---|---|---|---|---|---|
| 0 | Large source (e.g. SF) | Mid-tier A | Mid-tier B | Mid-tier C | (empty) |
| 1 | Large target (e.g. GCP) | Ext A | Ext B | Ext C | Ext D |
3-row layout (classic 3-tier: frontend / backend / data + externals):
| Row | Use it for |
|---|---|
| 0 | User-facing surfaces (browser, mobile, public APIs) |
| 1 | Backend services / orchestration / business logic |
| 2 | Data stores + external SaaS dependencies |
Routing rules (important for 3-row diagrams)
Connections route through one of two spines, or, for skip-row connections, through a margin-sidestep channel:
- Spine 0↔1 (between rows 0 and 1) carries: row 0↔0, row 0↔1, row 1↔1 (different lanes).
- Spine 1↔2 (between rows 1 and 2) carries: row 1↔2, row 2↔2 (different lanes).
- Margin sidestep carries: row 0↔2 (skip-row). The line drops to spine 0↔1, runs out to the canvas margin, drops through the margin past row 1, re-enters spine 1↔2, and drops to the destination. Six segments instead of three, but stays out of all container bodies.
- Intra-lane channel carries: connections between two nodes in the SAME lane. The line exits the source node's side, runs vertically in a thin channel just inside the lane border, and enters the destination node's side. Channels alternate sides (right, left, right, ...) per lane and each same-side channel gets its own X; nodes shrink slightly to clear the channels. Edge labels render on the vertical segment. Same-lane connections are fully supported; you do not need to restructure rows or merge nodes to avoid them.
Sidestep side (left vs right) is chosen automatically by the midpoint of the source/destination columns: connections living mostly on the left half of the canvas route through the left margin, the rest through the right. Each sidestep gets its own X channel inside the margin; the margin widens automatically to accommodate multiple sidesteps per side.
Use sidestep connections sparingly. They look visually distinct (longer paths, longer journey for the eye) which honestly conveys "this skips the middle layer." If you have many row 0↔2 connections, consider whether row 1 should mediate them in reality.
Preset lane keys (colours auto-applied)
| Key | Label default | Colour theme |
|---|---|---|
sf | Salesforce | Indigo |
bench | Bench App | Green |
hubspot | HubSpot | Orange |
zapier | Zapier | Purple |
gcp | GCP Platform | Sky blue |
aws | AWS | Amber |
azure | Azure | Blue |
stripe | Stripe | Pink |
qbo | QuickBooks Online | Yellow |
postgres | PostgreSQL | Steel blue |
redis | Redis | Red |
kafka | Kafka | Deep purple |
okta | Okta | Amber |
slack | Slack | Violet |
twilio | Twilio | Rose |
ses | Amazon SES | Deep orange |
docusign | DocuSign | Slate |
saas | Third-Party SaaS | Cool grey |
generic | (any) | Neutral grey |
For any key not in this list, supply explicit bg / border / header_bg.
Node styling
By default, all nodes use a consistent light gray background (#f1f5f9) regardless of status. This keeps focus on the structure and connections rather than lifecycle state.
To enable legacy per-status node coloring, set "node_status_colors": true:
config = {
"node_status_colors": true, # nodes colored by status (cyan=new, amber=transitioning, etc.)
# ...
}
Status values
| Status | Meaning | Legacy colour |
|---|---|---|
existing | Unchanged, currently live | Slate |
new | Being built / not yet live | Cyan |
transitioning | Partially moved / dual-write | Amber |
retiring | Being decommissioned | Red |
operational | Fully live on new platform | Green |
readonly | Still present but no writes | Light grey |
Legend
The bottom legend is hidden by default (since node colors are uniform). Configure it with the legend key:
# Hide legend (default when node_status_colors=false)
"legend": false
# Show legacy status legend (automatic when node_status_colors=true)
"legend": "default"
# Custom legend for diagram-specific meanings
"legend": [
("#0891B2", "API endpoint"),
("#B45309", "Background job"),
("#15803D", "Database", "Stores persistent state"), # optional tooltip
]
Custom legend entries: (color, label) or (color, label, tooltip_description).
Technology icons
Nodes automatically display technology icons when the engine detects a known technology in the label. Icons appear to the left of each node label in both the node itself and the lane header strip.
Auto-detection
The engine auto-detects icons from node labels using:
- File extensions:
.py→ Python,.js→ JavaScript,.ts→ TypeScript,.sh→ Bash - Keywords: "postgres" → PostgreSQL, "redis" → Redis, "kafka" → Kafka, "slack" → Slack
- Exact matches: "Docker", "Kubernetes", "React", "Vue.js", etc.
- Slug derivation: lowercased label with non-alphanumeric chars stripped, matched against 221 built-in icons
Disabling icons
Set "show_icons": false in the config to hide all icons:
config = {
"title": "My Diagram",
"show_icons": false,
# ... rest of config
}
Explicit icon override
To force a specific icon (or suppress auto-detection for one node), use the 5-element node format:
["My Service", "new", "", True, "docker"] # force Docker icon
["Legacy App", "retiring", "", False, ""] # suppress icon for this node
Adding missing icons
If a technology icon is missing, use /get-icon <technology> to find and add it. The skill searches Simple Icons, Iconify, and the web, then outputs ready-to-paste entries for svg_engine.py.
Common built-in icons
| Category | Examples |
|---|---|
| Languages | python, javascript, typescript, go, rust, java, ruby, swift, kotlin |
| Frameworks | react, vuedotjs, angular, nextdotjs, django, rails, spring, flask |
| Databases | postgresql, mysql, mongodb, redis, elasticsearch, sqlite, cockroachdb |
| Cloud | googlecloud, amazonaws, microsoftazure, vercel, netlify, heroku |
| DevOps | docker, kubernetes, terraform, ansible, jenkins, gitlab, github |
| Messaging | slack, discord, twilio, telegram |
| Analytics | amplitude, segment, datadog, newrelic, sentry |
The full list is in svg_engine.py under TECH_ICONS (221 icons).
Tips
- Keep edge labels short (3-5 words). They render at 9 px inside a white pill.
- Connections with no meaningful label can pass an empty string
"". - If you need more than 6 columns, set
"num_cols": 8(or higher); column widths shrink proportionally. - The engine handles the routing automatically; you only need to specify which node connects to which.
- When creating diagrams, prefer using technology names that match built-in icons (e.g., "PostgreSQL" not "Main DB") for visual consistency.
- Save the final SVG to the user's workspace folder, then present it with
mcp__cowork__present_files(Cowork) or tell the user the file path (Claude Code).