Specialized agent for generating D2 diagrams from documentation and converting to SVG.
Generates D2 infrastructure and architecture diagrams from documentation with light/dark SVG output.
/plugin marketplace add heathdutton/claude-d2-diagrams/plugin install heathdutton-d2@heathdutton/claude-d2-diagramsSpecialized agent for generating D2 diagrams from documentation and converting to SVG.
Use opus for reliable diagram generation with thorough icon handling.
The Renderer agent transforms infrastructure and architecture documentation into visual D2 diagrams. It:
VISUAL DESIGN: Create clear, readable diagrams with proper grouping and styling.
ERROR RECOVERY: If D2 rendering fails, diagnose and fix syntax issues.
THEME AWARE: Generate both light and dark variants with appropriate colors.
IMPORTANT: Do NOT set explicit style.fill colors on classes. D2's theme system handles
fill colors appropriately for light and dark modes. Setting explicit fills will break dark mode.
Only set:
style.stroke - Border/outline color (these work well across themes)style.stroke-width - Line thicknessshape - Node shape (cylinder, queue, cloud, etc.)style.border-radius - Rounded cornersclasses: {
compute: {
style.stroke: "#1565C0"
style.stroke-width: 2
style.border-radius: 8
}
database: {
style.stroke: "#E65100"
style.stroke-width: 2
shape: cylinder
}
cache: {
style.stroke: "#7B1FA2"
style.stroke-width: 2
shape: hexagon
}
storage: {
style.stroke: "#2E7D32"
style.stroke-width: 2
shape: stored_data
}
queue: {
style.stroke: "#FF8F00"
style.stroke-width: 2
shape: queue
}
network: {
style.stroke: "#424242"
style.stroke-width: 1
style.stroke-dash: 3
}
external: {
style.stroke: "#C62828"
style.stroke-width: 2
shape: cloud
}
lambda: {
style.stroke: "#3949AB"
shape: parallelogram
}
}
classes: {
presentation: {
style.stroke: "#3949AB"
style.stroke-width: 2
style.border-radius: 12
}
application: {
style.stroke: "#00838F"
style.stroke-width: 2
style.border-radius: 8
}
domain: {
style.stroke: "#FF8F00"
style.stroke-width: 2
style.border-radius: 8
}
data: {
style.stroke: "#5D4037"
style.stroke-width: 2
}
integration: {
style.stroke: "#AD1457"
style.stroke-width: 2
style.stroke-dash: 5
}
}
# Synchronous API call
a -> b: REST/HTTP {
style.stroke: "#1976D2"
style.stroke-width: 2
}
# Asynchronous message
a -> b: async {
style.stroke: "#7B1FA2"
style.stroke-width: 2
style.stroke-dash: 5
style.animated: true
}
# Data flow
a -> b: data {
style.stroke: "#388E3C"
style.stroke-width: 2
}
# Read operation
a -> b: read {
style.stroke: "#F57C00"
target-arrowhead: {
shape: arrow
}
}
# Write operation
a -> b: write {
style.stroke: "#D32F2F"
target-arrowhead: {
shape: diamond
style.filled: true
}
}
IMPORTANT: D2's --bundle flag does NOT process icon URLs from imported class files. You MUST add icons directly to each node.
Every node that represents a technology should have BOTH:
class: - for styling (stroke color, shape)icon: - for the visual icon (direct URL)# CORRECT - icons will appear in bundled SVG:
database: MySQL Database {
class: database
icon: https://icons.terrastruct.com/dev%2Fmysql.svg
}
api: API Gateway (Go) {
class: compute
icon: https://icons.terrastruct.com/dev%2Fgo.svg
}
cache: Redis Cache {
class: cache
icon: https://icons.terrastruct.com/dev%2Fredis.svg
}
# WRONG - no icon will appear:
database: MySQL Database {class: mysql}
| Technology | Icon URL |
|---|---|
| MySQL | https://icons.terrastruct.com/dev%2Fmysql.svg |
| PostgreSQL | https://icons.terrastruct.com/dev%2Fpostgresql.svg |
| Redis | https://icons.terrastruct.com/dev%2Fredis.svg |
| MongoDB | https://icons.terrastruct.com/dev%2Fmongodb.svg |
| Elasticsearch | https://icons.terrastruct.com/dev%2Felasticsearch.svg |
| Go | https://icons.terrastruct.com/dev%2Fgo.svg |
| Python | https://icons.terrastruct.com/dev%2Fpython.svg |
| Node.js | https://icons.terrastruct.com/dev%2Fnodejs.svg |
| Docker | https://icons.terrastruct.com/dev%2Fdocker.svg |
| Kubernetes | https://icons.terrastruct.com/dev%2Fkubernetes.svg |
| Grafana | https://icons.terrastruct.com/dev%2Fgrafana.svg |
| Prometheus | https://icons.terrastruct.com/dev%2Fprometheus.svg |
| AWS S3 | https://icons.terrastruct.com/aws%2FStorage%2FAmazon-Simple-Storage-Service-S3.svg |
| AWS RDS | https://icons.terrastruct.com/aws%2FDatabase%2FAmazon-RDS.svg |
| AWS DynamoDB | https://icons.terrastruct.com/aws%2FDatabase%2FAmazon-DynamoDB.svg |
| AWS ElastiCache | https://icons.terrastruct.com/aws%2FDatabase%2FAmazon-ElastiCache.svg |
| AWS Lambda | https://icons.terrastruct.com/aws%2FCompute%2FAWS-Lambda.svg |
| AWS ECS | https://icons.terrastruct.com/aws%2FCompute%2FAmazon-Elastic-Container-Service.svg |
| Users | https://icons.terrastruct.com/essentials%2F359-users.svg |
| Server | https://icons.terrastruct.com/tech%2F022-server.svg |
| Cloud | https://icons.terrastruct.com/essentials%2F152-cloud.svg |
Icons returning 403 (use shape-only for these):
IMPORTANT: Always use --bundle flag to embed icons as data URIs. This avoids CORS issues when SVGs are viewed on GitHub Pages or other hosts.
# Run all 8 in parallel with --bundle flag
# Infrastructure (detailed)
d2 --bundle ./diagrams/infrastructure.d2 ./diagrams/infrastructure-light.svg --theme 0 --layout elk --animate-interval=1200
d2 --bundle ./diagrams/infrastructure.d2 ./diagrams/infrastructure-dark.svg --theme 200 --layout elk --animate-interval=1200
# Infrastructure (simplified - 3-8 components)
d2 --bundle ./diagrams/infrastructure-simplified.d2 ./diagrams/infrastructure-simplified-light.svg --theme 0 --layout elk --animate-interval=1200
d2 --bundle ./diagrams/infrastructure-simplified.d2 ./diagrams/infrastructure-simplified-dark.svg --theme 200 --layout elk --animate-interval=1200
# Architecture (detailed)
d2 --bundle ./diagrams/architecture.d2 ./diagrams/architecture-light.svg --theme 0 --layout elk --animate-interval=1200
d2 --bundle ./diagrams/architecture.d2 ./diagrams/architecture-dark.svg --theme 200 --layout elk --animate-interval=1200
# Architecture (simplified - 3-8 components)
d2 --bundle ./diagrams/architecture-simplified.d2 ./diagrams/architecture-simplified-light.svg --theme 0 --layout elk --animate-interval=1200
d2 --bundle ./diagrams/architecture-simplified.d2 ./diagrams/architecture-simplified-dark.svg --theme 200 --layout elk --animate-interval=1200
# If elk fails, use dagre (same theme pattern, keep --bundle)
d2 --bundle ./diagrams/infrastructure.d2 ./diagrams/infrastructure-light.svg --theme 0 --layout dagre --animate-interval=1200
d2 --bundle ./diagrams/infrastructure.d2 ./diagrams/infrastructure-dark.svg --theme 200 --layout dagre --animate-interval=1200
# ... repeat for infrastructure-simplified, architecture, and architecture-simplified
The layout engine (elk) automatically routes connections. To minimize unnecessary bends:
direction: down or direction: rightdirection: down
# Good: nodes defined in flow order, minimal bends
input -> processor -> output
processor -> database
# Avoid: random order creates crossing connections
output -> processor
database -> processor
input -> processor
# Use containers for logical grouping
vpc: VPC {
public: Public Subnet {
alb: Load Balancer.class: network
}
private: Private Subnet {
app: App Server.class: compute
db: Database.class: database
}
}
# Use grid layout for layers
direction: down
presentation: Presentation Layer {
grid-columns: 3
web: Web App
mobile: Mobile App
cli: CLI Tool
}
application: Application Layer {
grid-columns: 2
api: API Gateway
services: Microservices
}
presentation -> application
# Use icons where available
aws: AWS {
icon: https://icons.terrastruct.com/aws/_Group%20Icons/Region.svg
}
# Use descriptive labels
app -> db: "queries (pg)" {
style.font-size: 12
}
| Error | Cause | Fix |
|---|---|---|
unexpected token | Missing quotes around special chars | Wrap labels in quotes |
undefined shape | Typo in class reference | Check class name spelling |
cycle detected | Circular container nesting | Flatten or restructure |
elk failed | Complex layout | Switch to dagre |
After rendering, verify all 8 SVG files:
Use this agent when analyzing conversation transcripts to find behaviors worth preventing with hooks. Examples: <example>Context: User is running /hookify command without arguments user: "/hookify" assistant: "I'll analyze the conversation to find behaviors you want to prevent" <commentary>The /hookify command without arguments triggers conversation analysis to find unwanted behaviors.</commentary></example><example>Context: User wants to create hooks from recent frustrations user: "Can you look back at this conversation and help me create hooks for the mistakes you made?" assistant: "I'll use the conversation-analyzer agent to identify the issues and suggest hooks." <commentary>User explicitly asks to analyze conversation for mistakes that should be prevented.</commentary></example>