Generate architecture diagrams, sequence diagrams, and ERDs from codebases or through guided conceptual exploration. Renders JSON definitions as crisp PNGs via ELK layout and resvg.
You are an expert at analyzing codebases and producing clear architecture diagrams, as well as guiding users through conceptual diagram creation.
<skill-dir> refers to the directory containing this SKILL.md file. All file paths below are relative to it.
This skill generates PNG diagrams from JSON definitions. Three diagram types are supported:
You write a .json file, run the build script, and open the resulting PNG. The type field in the JSON selects the diagram type (default: "flow").
Adapt your approach based on the user's request:
Write a .json file to <skill-dir>/diagram.json. The type field selects the diagram type.
interface FlowDefinition {
type?: "flow"; // default if omitted
direction?: "DOWN" | "RIGHT"; // default: "DOWN"
groups?: GroupDef[];
nodes: NodeDef[];
edges?: EdgeDef[];
}
interface GroupDef {
id: string;
label: string;
children: string[]; // node IDs belonging to this group
}
interface NodeDef {
id: string;
label: string;
shape?: "rect" | "cylinder" | "diamond" | "ellipse" | "hexagon" | "document";
}
interface EdgeDef {
from: string;
to: string;
label?: string;
}
Flow example:
{
"direction": "DOWN",
"groups": [
{ "id": "backend", "label": "Backend Services", "children": ["api", "auth", "handler"] },
{ "id": "storage", "label": "Storage Layer", "children": ["db", "cache"] }
],
"nodes": [
{ "id": "app", "label": "Frontend App" },
{ "id": "api", "label": "API Gateway" },
{ "id": "auth", "label": "Auth Check" },
{ "id": "handler", "label": "Handler" },
{ "id": "db", "label": "Database" },
{ "id": "cache", "label": "Redis Cache" },
{ "id": "queue", "label": "Message Queue" }
],
"edges": [
{ "from": "app", "to": "api" },
{ "from": "api", "to": "auth" },
{ "from": "auth", "to": "handler", "label": "authorized" },
{ "from": "handler", "to": "db" },
{ "from": "handler", "to": "cache", "label": "optional" },
{ "from": "handler", "to": "queue", "label": "critical" }
]
}
Flow best practices:
"DOWN" for layered architectures, "RIGHT" for pipelines/sequencesapi, db, authSvc)nodes arrayshape to convey node purpose: "cylinder" for databases/storage, "diamond" for decisions, "ellipse" for start/end states, "hexagon" for workers/processes, "document" for files. Default is "rect"interface SequenceDefinition {
type: "sequence";
participants: ParticipantDef[];
messages: MessageDef[];
}
interface ParticipantDef {
id: string;
label: string;
}
interface MessageDef {
from: string; // participant ID
to: string; // participant ID (can equal `from` for self-messages)
label?: string;
type?: "solid" | "dashed"; // solid = request (default), dashed = response
}
Sequence example:
{
"type": "sequence",
"participants": [
{ "id": "user", "label": "Browser" },
{ "id": "api", "label": "API Server" },
{ "id": "auth", "label": "Auth Service" },
{ "id": "db", "label": "Database" }
],
"messages": [
{ "from": "user", "to": "api", "label": "POST /login" },
{ "from": "api", "to": "auth", "label": "validate token" },
{ "from": "auth", "to": "db", "label": "SELECT user" },
{ "from": "db", "to": "auth", "label": "user row", "type": "dashed" },
{ "from": "auth", "to": "api", "label": "{ valid: true }", "type": "dashed" },
{ "from": "api", "to": "user", "label": "200 OK + JWT", "type": "dashed" }
]
}
Sequence best practices:
"solid" for requests/calls and "dashed" for responses/returnsfrom === to) render as a loop and are useful for internal processing stepsinterface ErdDefinition {
type: "erd";
entities: EntityDef[];
relationships: RelationshipDef[];
}
interface EntityDef {
id: string;
label: string;
fields: FieldDef[];
}
interface FieldDef {
name: string;
type: string; // e.g., "INT", "VARCHAR(255)", "TIMESTAMPTZ"
pk?: boolean; // primary key indicator
fk?: boolean; // foreign key indicator
}
type Cardinality = "1" | "N" | "0..1" | "0..N" | "1..N";
interface RelationshipDef {
from: string; // entity ID
to: string; // entity ID
label?: string; // optional relationship label
fromCardinality?: Cardinality;
toCardinality?: Cardinality;
}
ERD example:
{
"type": "erd",
"entities": [
{
"id": "users",
"label": "Users",
"fields": [
{ "name": "id", "type": "SERIAL", "pk": true },
{ "name": "email", "type": "VARCHAR(255)" },
{ "name": "name", "type": "VARCHAR(100)" },
{ "name": "created_at", "type": "TIMESTAMP" }
]
},
{
"id": "orders",
"label": "Orders",
"fields": [
{ "name": "id", "type": "SERIAL", "pk": true },
{ "name": "user_id", "type": "INT", "fk": true },
{ "name": "total", "type": "DECIMAL(10,2)" },
{ "name": "status", "type": "VARCHAR(20)" }
]
},
{
"id": "items",
"label": "Order Items",
"fields": [
{ "name": "id", "type": "SERIAL", "pk": true },
{ "name": "order_id", "type": "INT", "fk": true },
{ "name": "product", "type": "VARCHAR(200)" },
{ "name": "qty", "type": "INT" },
{ "name": "price", "type": "DECIMAL(10,2)" }
]
}
],
"relationships": [
{ "from": "users", "to": "orders", "fromCardinality": "1", "toCardinality": "N" },
{ "from": "orders", "to": "items", "fromCardinality": "1", "toCardinality": "N" }
]
}
ERD best practices:
"pk": true and foreign keys with "fk": true — they render as colored PK/FK badges"1", "N", "0..1", "0..N", "1..N") to show relationship multiplicitiesfrom/to must reference valid entity IDsThree themes are available. Pick the best fit for the diagram's purpose, or let the user specify with -t.
| Theme | Look | Best for |
|---|---|---|
| slate | Clean blue nodes, grey lines | Technical docs, architecture reviews |
| sandstone | Warm earth tones, cream/gold | Presentations, reports |
| figjam | Bright sticky-note colors, playful | Workshops, collaborative sessions |
Default is slate if not specified.
cd <skill-dir> && npm install && npm run build:png -- -d <diagram-path> -o <output-path> -t <theme>
Options:
| Option | Default | Description |
|---|---|---|
-d, --diagram | diagram.json | Path to .json diagram file |
-o, --output | diagram.png | Output PNG path |
-t, --theme | slate | sandstone, slate, or figjam |
-s, --scale | 3 | DPI multiplier (higher = more pixels) |
--background | white | Background color or transparent |
open <output-path>
Tell the user: "Your diagram has been generated. I've opened it for you."
To update the diagram, modify the .json file and re-run:
cd <skill-dir> && npm run build:png -- -d <diagram-path> -o <output-path> -t <theme>
open <output-path>
If the user asks for changes, update the .json file accordingly. Ask what the user wants to change rather than starting over.
| Want to show... | Use |
|---|---|
| System architecture, data flow, component relationships | Flow (type: "flow" or omit) |
| Request/response interactions between services over time | Sequence (type: "sequence") |
| Database schema with tables, columns, and foreign keys | ERD (type: "erd") |
.json file has at least one node/participant/entity{
"direction": "DOWN",
"groups": [
{ "id": "client", "label": "Client Layer", "children": ["ui", "state"] },
{ "id": "api", "label": "API Layer", "children": ["router", "auth", "handlers"] },
{ "id": "data", "label": "Data Layer", "children": ["db", "cache"] }
],
"nodes": [
{ "id": "ui", "label": "React App" },
{ "id": "state", "label": "State Mgmt" },
{ "id": "router", "label": "API Router" },
{ "id": "auth", "label": "Auth Middleware" },
{ "id": "handlers", "label": "Handlers" },
{ "id": "db", "label": "Database" },
{ "id": "cache", "label": "Cache" }
],
"edges": [
{ "from": "ui", "to": "state" },
{ "from": "state", "to": "router" },
{ "from": "router", "to": "auth" },
{ "from": "auth", "to": "handlers" },
{ "from": "handlers", "to": "db" },
{ "from": "handlers", "to": "cache" }
]
}
{
"direction": "RIGHT",
"nodes": [
{ "id": "gw", "label": "API Gateway" },
{ "id": "svcA", "label": "Service A" },
{ "id": "svcB", "label": "Service B" },
{ "id": "queue", "label": "Message Queue" },
{ "id": "dbA", "label": "DB A", "shape": "cylinder" },
{ "id": "dbB", "label": "DB B", "shape": "cylinder" }
],
"edges": [
{ "from": "gw", "to": "svcA" },
{ "from": "gw", "to": "svcB" },
{ "from": "svcA", "to": "queue", "label": "publish" },
{ "from": "queue", "to": "svcB", "label": "consume" },
{ "from": "svcA", "to": "dbA" },
{ "from": "svcB", "to": "dbB" }
]
}
{
"direction": "DOWN",
"nodes": [
{ "id": "req", "label": "Incoming Request", "shape": "ellipse" },
{ "id": "auth", "label": "Authenticated?", "shape": "diamond" },
{ "id": "role", "label": "Check Role", "shape": "diamond" },
{ "id": "allow", "label": "Allow Access" },
{ "id": "deny", "label": "Deny 403" },
{ "id": "login", "label": "Redirect to Login" }
],
"edges": [
{ "from": "req", "to": "auth" },
{ "from": "auth", "to": "role", "label": "yes" },
{ "from": "auth", "to": "login", "label": "no" },
{ "from": "role", "to": "allow", "label": "admin" },
{ "from": "role", "to": "deny", "label": "guest" }
]
}
{
"type": "sequence",
"participants": [
{ "id": "client", "label": "Mobile App" },
{ "id": "gateway", "label": "API Gateway" },
{ "id": "auth", "label": "Auth Service" },
{ "id": "db", "label": "User DB" }
],
"messages": [
{ "from": "client", "to": "gateway", "label": "POST /login" },
{ "from": "gateway", "to": "auth", "label": "authenticate()" },
{ "from": "auth", "to": "db", "label": "SELECT user" },
{ "from": "db", "to": "auth", "label": "user record", "type": "dashed" },
{ "from": "auth", "to": "auth", "label": "generate JWT" },
{ "from": "auth", "to": "gateway", "label": "token", "type": "dashed" },
{ "from": "gateway", "to": "client", "label": "200 + JWT", "type": "dashed" }
]
}
{
"type": "erd",
"entities": [
{
"id": "customers",
"label": "Customers",
"fields": [
{ "name": "id", "type": "UUID", "pk": true },
{ "name": "email", "type": "VARCHAR(255)" },
{ "name": "name", "type": "VARCHAR(200)" }
]
},
{
"id": "orders",
"label": "Orders",
"fields": [
{ "name": "id", "type": "UUID", "pk": true },
{ "name": "customer_id", "type": "UUID", "fk": true },
{ "name": "total", "type": "DECIMAL(10,2)" },
{ "name": "status", "type": "VARCHAR(20)" }
]
},
{
"id": "products",
"label": "Products",
"fields": [
{ "name": "id", "type": "UUID", "pk": true },
{ "name": "name", "type": "VARCHAR(200)" },
{ "name": "price", "type": "DECIMAL(10,2)" },
{ "name": "stock", "type": "INT" }
]
},
{
"id": "order_items",
"label": "Order Items",
"fields": [
{ "name": "id", "type": "UUID", "pk": true },
{ "name": "order_id", "type": "UUID", "fk": true },
{ "name": "product_id", "type": "UUID", "fk": true },
{ "name": "qty", "type": "INT" },
{ "name": "unit_price", "type": "DECIMAL(10,2)" }
]
}
],
"relationships": [
{ "from": "customers", "to": "orders", "fromCardinality": "1", "toCardinality": "N" },
{ "from": "orders", "to": "order_items", "fromCardinality": "1", "toCardinality": "N" },
{ "from": "products", "to": "order_items", "fromCardinality": "1", "toCardinality": "0..N" }
]
}