d2-diagrams/SKILL.md
Create, modify, and render D2 diagrams using the d2 CLI. Use when the user asks for diagrams, architecture visuals, ERDs, sequence diagrams, flowcharts, grid layouts, or any declarative diagramming task. Trigger phrases include "d2 diagram", "create a diagram", "architecture diagram", "sequence diagram", "ERD", "flowchart", "draw", "visualize".
npx skillsauth add stympy/skills d2-diagramsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create, modify, and render diagrams using the D2 declarative diagramming language.
D2 (Declarative Diagramming) is a text-to-diagram scripting language. You write what you want diagrammed, and the D2 CLI generates SVG or PNG images. This skill covers:
.d2)Before creating diagrams, verify D2 is installed:
d2 version
If not installed, install using one of these methods:
brew install d2
curl -fsSL https://d2lang.com/install.sh | sh -s --
go install oss.terrastruct.com/d2@latest
d2 version
Create a .d2 file with the diagram definition. Use the language reference in references/D2_LANGUAGE_REFERENCE.md for syntax details.
# Render to SVG (default, with padding)
d2 --pad=40 input.d2 output.svg
# Verify width is reasonable (<1400px for laptops)
rg -o 'viewBox="0 0 ([0-9]+)' -r '$1' output.svg
# Render to PNG
d2 --pad=40 input.d2 output.png
# With a specific theme (0-based IDs, use `d2 themes` to list)
d2 --theme=200 input.d2 output.svg
# With dark theme support
d2 --dark-theme=200 input.d2 output.svg
# With sketch/hand-drawn style
d2 --sketch input.d2 output.svg
# With a specific layout engine (dagre, elk, tala)
d2 --layout=elk input.d2 output.svg
# With custom padding (default recommendation is 40)
d2 --pad=60 input.d2 output.svg
# Watch mode (opens browser with live reload)
d2 --watch input.d2 output.svg
Modify the .d2 file and re-render. Use --watch for interactive development.
# Basic shapes (default is rectangle)
my_shape
labeled_shape: My Label
# Specific shape types
db: Database {shape: cylinder}
user: User {shape: person}
decision: Choice {shape: diamond}
q: Queue {shape: queue}
pg: Package {shape: package}
doc: Document {shape: document}
oval_shape: Oval {shape: oval}
circle_shape: Circle {shape: circle}
hexagon_shape: Hex {shape: hexagon}
cloud_shape: Cloud {shape: cloud}
# Arrow types
a -> b: forward
b <- a: backward
a <-> b: bidirectional
a -- b: undirected
# Chaining
a -> b -> c -> d
# Repeated connections create parallel edges
a -> b: first
a -> b: second
server: Backend Server {
api: REST API
db: Database {shape: cylinder}
api -> db: queries
}
x: Shape {
style: {
fill: "#f0f0f0"
stroke: "#333333"
stroke-width: 2
stroke-dash: 5
border-radius: 8
shadow: true
opacity: 0.9
font-size: 16
font-color: "#000"
bold: true
italic: false
animated: true
3d: true
multiple: true
double-border: true
fill-pattern: dots
}
}
server: Backend {
icon: https://icons.terrastruct.com/essentials%2F112-server.svg
}
# Standalone icon shape
github: GitHub {
shape: image
icon: https://icons.terrastruct.com/dev%2Fgithub.svg
}
users: {
shape: sql_table
id: int {constraint: primary_key}
name: varchar(255)
email: varchar(255) {constraint: unique}
created_at: timestamp
}
shape: sequence_diagram
alice -> bob: Hello
bob -> alice: Hi back
alice -> bob: How are you?
bob -> alice: Good, thanks!
grid: {
grid-rows: 2
grid-columns: 3
cell1: A
cell2: B
cell3: C
cell4: D
cell5: E
cell6: F
}
vars: {
primary-color: "#4A90D9"
server-icon: https://icons.terrastruct.com/essentials%2F112-server.svg
}
server: Backend {
icon: ${server-icon}
style.fill: ${primary-color}
}
# Style all shapes
*.style.fill: "#f0f0f0"
*.style.border-radius: 8
# Style all connections
(* -> *)[*].style.stroke-dash: 3
# Recursive glob
**.style.font-size: 14
direction: down # Recommended default — narrower diagrams
# Options: up, down, left, right
# Use 'right' only for explicitly horizontal flows (timelines, pipelines)
a -> b -> c
Use d2 themes to list available themes. Common theme IDs:
0 - Default1 - Neutral default3 - Mixed berry blue4 - Grape soda5 - Aubergine6 - Colorblind clear8 - Vanilla nitro cola100 - Origami200 - Dark Mauve (terminal-style)300 - Terminal (dark, monospace, caps)301 - Terminal Grayscale302 - RetroDark themes:
200 - Dark Mauve201-208 - Various dark themes# Root board
a -> b
# Layers (independent boards)
layers: {
detail: {
x -> y -> z
}
}
# Scenarios (inherit from base)
scenarios: {
error: {
a.style.fill: red
a -> c: error path
}
}
# Steps (each inherits from previous)
steps: {
step1: {
a -> b
}
step2: {
b -> c
}
}
classes: {
server: {
shape: rectangle
style: {
fill: "#dceefb"
stroke: "#4A90D9"
border-radius: 8
}
}
database: {
shape: cylinder
style: {
fill: "#e8f5e9"
stroke: "#66bb6a"
}
}
}
api: API Server {class: server}
db: PostgreSQL {class: database}
api -> db
a -> b: {
source-arrowhead: {
shape: diamond
}
target-arrowhead: {
shape: arrow
label: "1..*"
}
}
# Arrowhead shapes: triangle, arrow, diamond, circle, cf-one, cf-one-required, cf-many, cf-many-required
explanation: |md
# Architecture Overview
- **Frontend**: React SPA
- **Backend**: Go microservices
- **Database**: PostgreSQL
|
code_block: |go
func main() {
fmt.Println("Hello")
}
|
Diagram width is the most common problem. D2's dagre layout places sibling nodes side-by-side, so diagrams easily exceed screen width. Always target <1400px wide for laptop readability.
direction: down (not right) as the default. Vertical stacking is narrower.a -> b -> c) instead of declaring them as siblings.# Check viewBox width (first number after "0 0" is width)
rg -o 'viewBox="0 0 ([0-9]+)' -r '$1' output.svg
Nested containers with multiple children are the #1 source of width explosion. Dagre lays out children horizontally within a container, so a container with 4 children produces 4 columns of width.
Bad — 4 children side-by-side, very wide:
services: Backend {
api: API Gateway
auth: Auth Service
core: Core API
worker: Worker
}
Better — use the "titled container + transparent markdown child" pattern. The container label acts as the heading with proper border-radius, and a single invisible child holds markdown body text:
services: Backend Services {
style.fill: "#e8f5e9"
style.stroke: "#4caf50"
style.border-radius: 10
details: |md
- API Gateway (:3000)
- Auth Service (JWT)
- Core API (business logic)
- Background Worker (cron)
| {
style.fill: transparent
style.stroke: transparent
}
}
This pattern keeps the rounded-corner container visual while collapsing all content into a single narrow box.
Gotcha: When a node's label is markdown (|md ... |), D2 renders the content inside a foreignObject and the SVG <rect> gets rx="0" — meaning border-radius is ignored on the outer shape even if set via class or inline style. Plain-text labels render border-radius correctly.
Workaround: Use the titled container pattern above. The parent container uses a plain-text label (which gets proper border-radius), and the markdown goes in a transparent child node inside it.
Sequence diagram width is proportional to actor count and cannot be controlled by direction or layout. The only way to reduce width is to merge related actors:
# Wide — 5 actors
shape: sequence_diagram
user: User
ios: iOS App
llm: On-Device LLM
server: Server
db: Database
# Narrower — 3 actors (merge ios+llm, server+db)
shape: sequence_diagram
user: User
ios: iOS (App + LLM)
server: Server (+ DB)
--pad=40 to add breathing room without changing layout width.a -> b -> c) to force dagre to stack them vertically rather than placing them side-by-side.@ prefix is D2 import syntax. Labels like @github/copilot-sdk or @MainActor will be interpreted as imports. Wrap in quotes or rephrase: "@github/copilot-sdk" or just Copilot SDK.style blocks on connections. Unlike regular diagrams, you cannot style individual arrows in a sequence diagram — the render will fail. Remove any style.stroke, style.stroke-width, etc. from sequence diagram connections.border-radius on the outer SVG rect (see Width Control above)..d2 file can produce slightly different widths. Always verify after re-rendering.api_server not box1. Keys become default labels.direction: down: Vertical layouts fit screens better. Only use right for explicitly horizontal flows (timelines, pipelines).classes:.*.style.border-radius: 8 instead of styling each shape.vars: for easy theme changes.dagre (default) for hierarchical, elk for complex graphs.--pad=40: Gives diagrams breathing room. Default padding is too tight.--pad=40 for comfortable whitespace around diagrams. The default is too tight.d2 --pad=40 input.d2 output.svg
rg -o 'viewBox="0 0 ([0-9]+)' -r '$1' output.svg # should be <1400
--theme for professional presentation-ready output.--sketch for informal, hand-drawn appearance.--animate-interval=1200 with composition for animated diagrams.--layout=elk or --layout=tala).font-size, or use a different layout.border-radius doesn't apply to |md ... | labels. Use the titled container + transparent md child pattern instead.style blocks on connections. Remove them.@ interpreted as import: Quote or rephrase labels containing @ (e.g., "@MainActor").references/D2_LANGUAGE_REFERENCE.md - Complete language syntax referencereferences/D2_PATTERNS.md - Common diagram patterns and templatesassets/ - Example .d2 template files ready to usedevelopment
Deep research before planning. Launches parallel agents to search docs, web, and codebase, then synthesizes findings into actionable context.
development
This skill will be invoked when the user wants to create a PRD. You should go through the steps below. You may skip steps if you don't consider them necessary. 1. Ask the user for a long, detailed description of the problem they want to solve and any potential ideas for solutions. 2. Explore the repo to verify their assertions and understand the current state of the codebase. 3. Interview the user relentlessly about every aspect of this plan until you reach a shared understanding. Walk down e
development
Extract and format Slack huddle transcripts for analysis. Use this skill when processing Slack huddle transcript files (.vtt), when user mentions huddle transcript or Slack transcript, when user uploads a VTT file from Slack, or when user asks to summarize or analyze a Slack meeting/huddle. Handles VTT format transcripts with speaker identification, timestamps, and conversation merging.
development
--- name: refactor-pass description: Perform a refactor pass focused on simplicity after recent changes. Use when the user asks for a refactor/cleanup pass, simplification, or dead-code removal and expects build/tests to verify behavior. --- # Refactor Pass ## Workflow 1. Review the changes just made and identify simplification opportunities. 2. Apply refactors to: - Remove dead code and dead paths. - Straighten logic flows. - Remove excessive parameters. - Remove premature optimizati