From 4cdf96abd4cbf00937987ca629f5654d653fdac7 Mon Sep 17 00:00:00 2001 From: fizznix Date: Fri, 24 Apr 2026 13:00:30 +0530 Subject: [PATCH] add excalidraw-gen skill for structured diagram generation --- docs/README.skills.md | 1 + skills/excalidraw-gen/SKILL.md | 63 +++++ skills/excalidraw-gen/agent-workflow.md | 179 +++++++++++++ skills/excalidraw-gen/examples.md | 306 +++++++++++++++++++++++ skills/excalidraw-gen/node-types.md | 83 ++++++ skills/excalidraw-gen/schema.md | 125 +++++++++ skills/excalidraw-gen/style-overrides.md | 154 ++++++++++++ skills/excalidraw-gen/validation.md | 99 ++++++++ 8 files changed, 1010 insertions(+) create mode 100644 skills/excalidraw-gen/SKILL.md create mode 100644 skills/excalidraw-gen/agent-workflow.md create mode 100644 skills/excalidraw-gen/examples.md create mode 100644 skills/excalidraw-gen/node-types.md create mode 100644 skills/excalidraw-gen/schema.md create mode 100644 skills/excalidraw-gen/style-overrides.md create mode 100644 skills/excalidraw-gen/validation.md diff --git a/docs/README.skills.md b/docs/README.skills.md index 1f24d0b37..f86a474a8 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -137,6 +137,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [eval-driven-dev](../skills/eval-driven-dev/SKILL.md) | Set up eval-based QA for Python LLM applications: instrument the app, build golden datasets, write and run eval tests, and iterate on failures. ALWAYS USE THIS SKILL when the user asks to set up QA, add tests, add evals, evaluate, benchmark, fix wrong behaviors, improve quality, or do quality assurance for any Python project that calls an LLM model. | `references/1-a-entry-point.md`
`references/1-b-eval-criteria.md`
`references/2-wrap-and-trace.md`
`references/3-define-evaluators.md`
`references/4-build-dataset.md`
`references/5-run-tests.md`
`references/6-investigate.md`
`references/evaluators.md`
`references/testing-api.md`
`references/wrap-api.md`
`resources` | | [exam-ready](../skills/exam-ready/SKILL.md) | Activate this skill when a student provides study material (PDF or pasted notes) and a syllabus, and wants to prepare for an exam. Extracts key definitions, points, keywords, diagrams, exam-ready sentences, and practice questions strictly from the provided material. | None | | [excalidraw-diagram-generator](../skills/excalidraw-diagram-generator/SKILL.md) | Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw. | `references/element-types.md`
`references/excalidraw-schema.md`
`scripts/.gitignore`
`scripts/README.md`
`scripts/add-arrow.py`
`scripts/add-icon-to-diagram.py`
`scripts/split-excalidraw-library.py`
`templates` | +| [excalidraw-gen](../skills/excalidraw-gen/SKILL.md) | Generate Excalidraw diagram files from a structured JSON or YAML input spec. Use this skill whenever a user asks for a diagram, flowchart, architecture diagram, pipeline, or any visual graph that should open in Excalidraw. The skill covers authoring the input file and invoking the CLI. | `agent-workflow.md`
`examples.md`
`node-types.md`
`schema.md`
`style-overrides.md`
`validation.md` | | [fabric-lakehouse](../skills/fabric-lakehouse/SKILL.md) | Use this skill to get context about Fabric Lakehouse and its features for software systems and AI-powered functions. It offers descriptions of Lakehouse data components, organization with schemas and shortcuts, access control, and code examples. This skill supports users in designing, building, and optimizing Lakehouse solutions using best practices. | `references/getdata.md`
`references/pyspark.md` | | [fedora-linux-triage](../skills/fedora-linux-triage/SKILL.md) | Triage and resolve Fedora issues with dnf, systemd, and SELinux-aware guidance. | None | | [finalize-agent-prompt](../skills/finalize-agent-prompt/SKILL.md) | Finalize prompt file using the role of an AI agent to polish the prompt for the end user. | None | diff --git a/skills/excalidraw-gen/SKILL.md b/skills/excalidraw-gen/SKILL.md new file mode 100644 index 000000000..86c917ace --- /dev/null +++ b/skills/excalidraw-gen/SKILL.md @@ -0,0 +1,63 @@ +--- +name: excalidraw-gen +description: > + Generate Excalidraw diagram files from a structured JSON or YAML input spec. + Use this skill whenever a user asks for a diagram, flowchart, architecture + diagram, pipeline, or any visual graph that should open in Excalidraw. + The skill covers authoring the input file and invoking the CLI. +--- + +# excalidraw-gen — Diagram Generation Skill + +`excalidraw-gen` converts a structured JSON or YAML description into a fully +laid-out `.excalidraw` file that opens directly in [excalidraw.com](https://excalidraw.com) +or the Excalidraw desktop app. + +**Your job as an agent**: produce the correct input file. The CLI handles all layout, routing, and rendering automatically. + +--- + +## Skill files + +This skill is split across focused reference files. Read the ones relevant to your current task: + +| File | Contents | +| ---------------------------------------- | -------------------------------------------------------------------------- | +| [schema.md](schema.md) | Full input file schema — top-level fields, node fields, edge fields | +| [node-types.md](node-types.md) | All node `type` values for the `flowchart` and `architecture` templates | +| [style-overrides.md](style-overrides.md) | Per-node and per-edge `style` fields + recommended colour palette | +| [validation.md](validation.md) | Validation rules — what causes errors vs warnings | +| [examples.md](examples.md) | Annotated JSON and YAML examples (minimal, styled, architecture, pipeline) | +| [agent-workflow.md](agent-workflow.md) | Step-by-step agent checklist + common diagram patterns | + +--- + +## CLI invocation + +```bash +# Using npx (no install required) +npx excalidraw-gen generate [options] + +# Options +--template flowchart | architecture (default: flowchart) +--theme default | pastel | dark (default: default) +--layout dag | grid (default: dag) +--out path/to/output.excalidraw (default: stdout) +--max-nodes (default: 200) +``` + +**Template choice rule**: + +- Use `--template flowchart` for processes, workflows, decision trees, pipelines, sequences. +- Use `--template architecture` for system diagrams, infrastructure, service maps, data flows between components. + +**Layout choice rule**: + +- `dag` — hierarchical top-to-bottom layout. Best for almost everything. +- `grid` — equal-spaced grid. Use only when nodes have no meaningful hierarchy (e.g. a legend or component catalogue). + +**Theme choice rule**: + +- `default` — clean white background, vivid colours. General purpose. +- `pastel` — lightened fills, same strokes. Presentations, documentation. +- `dark` — dark fills, brightened strokes, dark canvas. Dark-mode contexts. diff --git a/skills/excalidraw-gen/agent-workflow.md b/skills/excalidraw-gen/agent-workflow.md new file mode 100644 index 000000000..b95f9d4c4 --- /dev/null +++ b/skills/excalidraw-gen/agent-workflow.md @@ -0,0 +1,179 @@ +# Agent Workflow + +Use this file as your step-by-step checklist when generating a diagram from +a user request. Follow the steps in order. + +--- + +## Step 1 — Identify the diagram type + +Ask: is this a **process/flow** or a **system/infrastructure** diagram? + +| User asks for... | Use | +|-----------------|-----| +| Workflow, process, flowchart, decision tree, pipeline, sequence, state machine | `"type": "flowchart"` + `--template flowchart` | +| Architecture, system diagram, service map, infrastructure, data flow between services | `"type": "architecture"` + `--template architecture` | + +--- + +## Step 2 — Identify the layout + +| Situation | Use | +|-----------|-----| +| Nodes have a clear top-to-bottom order (almost always) | `--layout dag` (default) | +| Nodes are an unordered set with no hierarchy (e.g. a catalogue) | `--layout grid` | + +> **DAG layout warning**: The `dag` layout requires a directed acyclic graph. Any cycle (e.g. `response → user` where `user` is also a source) will cause the cycle nodes to be collapsed into a single horizontal row, breaking the visual hierarchy. **Never create edges that point back toward a source node when using `--layout dag`.** + +--- + +## Step 3 — Enumerate all nodes + +For each distinct entity, component, or step in the diagram: + +1. Assign a short `snake_case` **id** (e.g. `auth_service`, `validate_card`) +2. Write a concise **label** (what appears inside the shape) +3. Pick the most specific **type** from [node-types.md](node-types.md) +4. Note if any node needs **style overrides** (see Step 5) + +**Tips**: +- Start/entry nodes → `start` (flowchart) or `user` (architecture) +- Terminal/result nodes → `end` (flowchart) +- Branch points → `decision` +- Do not skip nodes. Every visible box in the intended diagram must be in `nodes`. + +--- + +## Step 4 — Define all edges + +For each connection between nodes: + +1. Set `from` to the source node's `id` +2. Set `to` to the target node's `id` +3. Add a `label` if the transition has a meaningful name (Submit, Approved, Fail, Cache hit, etc.) +4. Always label outbound edges from `decision` nodes — unlabelled branches are ambiguous +5. Set `"bidirectional": true` for two-way relationships (read/write, sync, mutual dependency) + +**Check**: +- Every `from` and `to` value must exactly match an `id` in `nodes` (case-sensitive) +- No `from === to` (self-loops are invalid — use an intermediate node instead) +- No two edges with the same `from`/`to` pair (duplicates are dropped) +- **No cycles when using `--layout dag`** — do not create an edge that points back to any ancestor node. Cycles cause the layout engine to flatten all involved nodes into a single horizontal line, producing an unreadable diagram. If a "reply" or "return" relationship is needed, represent it with a `label` on the terminal node (e.g. label `"Response to User"`) instead of drawing a back-edge. + +--- + +## Step 5 — Apply semantic styling (optional but recommended) + +Use colours to convey meaning at a glance. Consistency within a diagram matters more than any specific colour. + +### Standard conventions + +| Meaning | Node style | Edge style | +|---------|-----------|------------| +| Success / ok / go | `backgroundColor: "#b2f2bb"`, `strokeColor: "#2f9e44"` | `strokeColor: "#2f9e44"` | +| Failure / error / stop | `backgroundColor: "#ffc9c9"`, `strokeColor: "#c92a2a"`, `strokeStyle: "dashed"` | `strokeColor: "#c92a2a"`, `strokeStyle: "dashed"` | +| Warning / manual / wait | `backgroundColor: "#ffe8cc"`, `strokeColor: "#fd7e14"` | `strokeColor: "#fd7e14"` | +| User / actor | `backgroundColor: "#a5d8ff"`, `strokeColor: "#1971c2"`, `shape: "ellipse"` | — | +| External / third-party | `backgroundColor: "#ffc9c9"`, `strokeColor: "#e03131"` | — | +| Async / queue | `backgroundColor: "#fff3bf"`, `strokeColor: "#fab005"` | — | + +### When to use `strokeStyle: "dashed"` +- On `decision` node borders → emphasises it's a branch point +- On failure/rejection paths → visually distinguishes from success paths +- On external or optional connections → shows they're not guaranteed + +--- + +## Step 6 — Choose the theme (optional) + +| Theme | When to use | +|-------|-------------| +| `default` | General purpose — clean white background, vivid colours | +| `pastel` | Presentations, documentation, light/friendly aesthetic | +| `dark` | Dark-mode contexts, technical dashboards | + +--- + +## Step 7 — Write the input file + +Choose JSON or YAML — both are equivalent. YAML is often cleaner for diagrams +with many style overrides. JSON is better when the data is already programmatic. + +Validate your file mentally against the rules in [validation.md](validation.md) +before running the CLI. + +--- + +## Step 8 — Run the CLI + +```bash +# Flowchart (default theme, DAG layout) +npx excalidraw-gen generate diagram.json --template flowchart --out diagram.excalidraw + +# Architecture with dark theme +npx excalidraw-gen generate arch.json --template architecture --theme dark --out arch.excalidraw + +# YAML input +npx excalidraw-gen generate pipeline.yaml --out pipeline.excalidraw + +# Print to stdout (for piping or inspection) +npx excalidraw-gen generate diagram.json +``` + +--- + +## Step 9 — Open the output + +Open the `.excalidraw` file at [excalidraw.com](https://excalidraw.com) via **Open** → select file, +or in the Excalidraw desktop app. + +--- + +## Common patterns reference + +### Decision fan-out +A `decision` node routes to 2+ targets. Always label every outbound edge. + +``` +decision ──"Yes"──► success_node + └──"No"───► error_node +``` + +### Retry loop +Self-loops are invalid. Use an intermediate retry node instead. + +``` +process ──"Error"──► retry ──"Retry"──► process + └──"Give up"──► fail +``` + +### Parallel branches that converge +Route through a join/merge node. + +``` +split ──► branch_a ──► join ──► continue + └──► branch_b ──►┘ +``` + +### Bidirectional data flow +Use `"bidirectional": true` for read/write or two-way sync relationships. + +```json +{ "from": "app", "to": "db", "label": "read/write", "bidirectional": true } +``` + +### Very long node labels +Set `width` in the node's `style` to control line wrapping. + +```json +{ "style": { "width": 260 } } +``` + +### Pastel-themed diagrams +Add `--theme pastel` to the CLI command — no changes to the input file needed. +All template colours automatically lighten. + +### Isolating a sub-diagram +If a small set of nodes is logically separate (e.g. an inset legend), group them +by using consistent style overrides and placing them with a common node `type`. +The layout engine places nodes by their graph connectivity. diff --git a/skills/excalidraw-gen/examples.md b/skills/excalidraw-gen/examples.md new file mode 100644 index 000000000..43eeef2a4 --- /dev/null +++ b/skills/excalidraw-gen/examples.md @@ -0,0 +1,306 @@ +# Examples + +Copy-paste ready examples covering the most common diagram types. +All examples are valid input files ready to pass to the CLI. + +--- + +## 1 — Minimal flowchart (JSON) + +The simplest valid diagram. + +```bash +npx excalidraw-gen generate login.json --template flowchart --out login.excalidraw +``` + +```json +{ + "type": "flowchart", + "title": "Login Flow", + "nodes": [ + { "id": "user", "label": "User", "type": "start" }, + { "id": "form", "label": "Login Form", "type": "process" }, + { "id": "check", "label": "Valid credentials?", "type": "decision" }, + { "id": "dashboard", "label": "Dashboard", "type": "end" }, + { "id": "error", "label": "Error Page", "type": "end" } + ], + "edges": [ + { "from": "user", "to": "form" }, + { "from": "form", "to": "check", "label": "Submit" }, + { "from": "check", "to": "dashboard", "label": "Valid" }, + { "from": "check", "to": "error", "label": "Invalid" } + ] +} +``` + +--- + +## 2 — Styled flowchart with semantic colours (JSON) + +Uses green/red colour coding for success and failure paths. + +```bash +npx excalidraw-gen generate payment.json --template flowchart --out payment.excalidraw +``` + +```json +{ + "type": "flowchart", + "title": "Payment Processing", + "nodes": [ + { + "id": "customer", + "label": "Customer", + "type": "start", + "style": { "backgroundColor": "#a5d8ff", "strokeColor": "#1971c2", "shape": "ellipse" } + }, + { "id": "checkout", "label": "Checkout Form", "type": "process" }, + { + "id": "validate", + "label": "Card Valid?", + "type": "decision", + "style": { "strokeWidth": 3 } + }, + { + "id": "charge", + "label": "Charge Gateway", + "type": "process", + "style": { "backgroundColor": "#fff3bf", "strokeColor": "#f08c00", "width": 200 } + }, + { + "id": "success", + "label": "Order Confirmed", + "type": "end", + "style": { "backgroundColor": "#b2f2bb", "strokeColor": "#2f9e44", "strokeWidth": 3 } + }, + { + "id": "fail", + "label": "Payment Failed", + "type": "end", + "style": { "backgroundColor": "#ffc9c9", "strokeColor": "#c92a2a", "strokeStyle": "dashed" } + } + ], + "edges": [ + { "from": "customer", "to": "checkout" }, + { "from": "checkout", "to": "validate", "label": "Submit" }, + { "from": "validate", "to": "charge", "label": "Valid", "style": { "strokeColor": "#2f9e44" } }, + { "from": "validate", "to": "fail", "label": "Invalid", "style": { "strokeColor": "#c92a2a", "strokeStyle": "dashed" } }, + { "from": "charge", "to": "success", "label": "Approved","style": { "strokeColor": "#2f9e44" } }, + { "from": "charge", "to": "fail", "label": "Declined","style": { "strokeColor": "#c92a2a", "strokeStyle": "dashed" } } + ] +} +``` + +--- + +## 3 — Architecture diagram (JSON) + +Service map for a 3-tier web application. + +```bash +npx excalidraw-gen generate arch.json --template architecture --out arch.excalidraw +``` + +```json +{ + "type": "architecture", + "title": "3-Tier Web App", + "nodes": [ + { "id": "browser", "label": "Browser", "type": "user" }, + { "id": "cdn", "label": "CDN", "type": "external" }, + { "id": "gateway", "label": "API Gateway", "type": "gateway" }, + { "id": "auth", "label": "Auth Service", "type": "service" }, + { "id": "app", "label": "App Service", "type": "service" }, + { "id": "redis", "label": "Redis Cache", "type": "cache" }, + { "id": "postgres", "label": "PostgreSQL", "type": "db" }, + { "id": "s3", "label": "S3 Storage", "type": "storage" } + ], + "edges": [ + { "from": "browser", "to": "cdn", "label": "static assets" }, + { "from": "browser", "to": "gateway", "label": "HTTPS" }, + { "from": "gateway", "to": "auth", "label": "auth" }, + { "from": "gateway", "to": "app", "label": "route" }, + { "from": "app", "to": "redis", "label": "cache" }, + { "from": "app", "to": "postgres", "label": "query" }, + { "from": "app", "to": "s3", "label": "files" } + ] +} +``` + +--- + +## 4 — CI/CD pipeline (YAML) + +Demonstrates YAML input format and conditional branching. + +```bash +npx excalidraw-gen generate pipeline.yaml --out pipeline.excalidraw +``` + +```yaml +type: flowchart +title: CI/CD Pipeline + +nodes: + - id: dev + label: Developer + type: start + style: + backgroundColor: "#a5d8ff" + strokeColor: "#1971c2" + shape: ellipse + + - id: push + label: Git Push + type: process + + - id: ci + label: CI Build & Test + type: process + style: + backgroundColor: "#d0bfff" + strokeColor: "#7048e8" + width: 200 + + - id: gate + label: Quality Gate + type: decision + style: + strokeStyle: dashed + strokeWidth: 3 + + - id: staging + label: Deploy to Staging + type: process + style: + backgroundColor: "#fff3bf" + strokeColor: "#f08c00" + + - id: approve + label: Manual Approval + type: decision + style: + backgroundColor: "#ffe8cc" + strokeColor: "#fd7e14" + strokeStyle: dashed + + - id: prod + label: Deploy to Production + type: end + style: + backgroundColor: "#b2f2bb" + strokeColor: "#2f9e44" + strokeWidth: 3 + + - id: fail + label: Notify & Fail + type: end + style: + backgroundColor: "#ffc9c9" + strokeColor: "#c92a2a" + strokeStyle: dashed + +edges: + - from: dev + to: push + + - from: push + to: ci + label: trigger + + - from: ci + to: gate + label: results + + - from: gate + to: staging + label: Pass + style: + strokeColor: "#2f9e44" + + - from: gate + to: fail + label: Fail + style: + strokeColor: "#c92a2a" + strokeStyle: dashed + + - from: staging + to: approve + + - from: approve + to: prod + label: Approved + style: + strokeColor: "#2f9e44" + strokeWidth: 2 + + - from: approve + to: fail + label: Rejected + style: + strokeColor: "#c92a2a" + strokeStyle: dashed +``` + +--- + +## 5 — ML inference architecture (JSON + dark theme) + +```bash +npx excalidraw-gen generate ml.json --template architecture --theme dark --out ml.excalidraw +``` + +```json +{ + "type": "architecture", + "title": "ML Inference Platform", + "nodes": [ + { "id": "client", "label": "Client App", "type": "frontend" }, + { "id": "gateway", "label": "API Gateway", "type": "gateway" }, + { "id": "router", "label": "Request Router", "type": "service" }, + { "id": "model_a", "label": "Model A (v2)", "type": "ml" }, + { "id": "model_b", "label": "Model B (v3-beta)", "type": "ml" }, + { "id": "cache", "label": "Result Cache", "type": "cache" }, + { "id": "store", "label": "Model Registry", "type": "storage" }, + { "id": "monitor", "label": "Metrics & Logging", "type": "monitor" } + ], + "edges": [ + { "from": "client", "to": "gateway", "label": "predict" }, + { "from": "gateway", "to": "router", "label": "route" }, + { "from": "router", "to": "cache", "label": "check cache" }, + { "from": "router", "to": "model_a", "label": "stable" }, + { "from": "router", "to": "model_b", "label": "canary 10%" }, + { "from": "model_a", "to": "monitor", "label": "metrics" }, + { "from": "model_b", "to": "monitor", "label": "metrics" }, + { "from": "store", "to": "model_a", "label": "weights", "bidirectional": true }, + { "from": "store", "to": "model_b", "label": "weights", "bidirectional": true } + ] +} +``` + +--- + +## 6 — Grid layout (JSON) + +Grid layout is best for unordered collections with no hierarchy. + +```bash +npx excalidraw-gen generate components.json --layout grid --out components.excalidraw +``` + +```json +{ + "type": "architecture", + "title": "Service Inventory", + "nodes": [ + { "id": "auth", "label": "Auth Service", "type": "service" }, + { "id": "billing", "label": "Billing Service", "type": "service" }, + { "id": "notify", "label": "Notification Svc", "type": "service" }, + { "id": "search", "label": "Search Service", "type": "service" }, + { "id": "profile", "label": "Profile Service", "type": "service" }, + { "id": "upload", "label": "Upload Service", "type": "service" } + ], + "edges": [] +} +``` diff --git a/skills/excalidraw-gen/node-types.md b/skills/excalidraw-gen/node-types.md new file mode 100644 index 000000000..e6b1a99a3 --- /dev/null +++ b/skills/excalidraw-gen/node-types.md @@ -0,0 +1,83 @@ +# Node Types Reference + +The `type` field on a node selects its default shape and colour from the active template. +Style overrides in the node's `style` object always win over template defaults. + +Choose between `--template flowchart` and `--template architecture` when running the CLI. +The node types available depend on the template selected. + +--- + +## Flowchart template (`--template flowchart`) + +Use for: processes, workflows, decision trees, pipelines, sequences, state machines. + +| `type` | Shape | Fill colour | Stroke colour | Use when | +|--------------|----------------------------|---------------|---------------|----------| +| `start` | Ellipse | `#e7f5ff` | `#1971c2` | Entry point, trigger, user, actor, system that initiates the flow | +| `end` | Ellipse | `#fff0f6` | `#c2255c` | Terminal state, result, final output, error termination | +| `process` | Rectangle (rounded) | `#d0bfff` | `#7048e8` | Task, action, step, operation, computation | +| `decision` | Rectangle (dashed, orange) | `#ffd8a8` | `#e8590c` | Branch point, condition check, yes/no gate, switch | +| `io` | Rectangle (rounded) | `#e3fafc` | `#0c8599` | Input/output operation — reading a file, API call, user prompt | +| `subprocess` | Rectangle (rounded) | `#d3f9d8` | `#40c057` | Encapsulated sub-process, called function, external routine | + +> **No diamond shape**: Excalidraw raw JSON has no working `diamond` element type. +> `decision` nodes render as dashed orange rectangles — this is the standard approach. + +**Default** (unknown or omitted `type`): plain purple rectangle — same appearance as `process`. + +--- + +## Architecture template (`--template architecture`) + +Use for: system diagrams, infrastructure maps, service topology, data flow between components. + +| `type` | Shape | Fill colour | Stroke colour | Use when | +|---------------|-----------------------------|---------------|---------------|----------| +| `service` | Rectangle (rounded) | `#d0bfff` | `#7048e8` | Microservice, backend application, internal service | +| `api` | Rectangle (rounded) | `#d0bfff` | `#7048e8` | REST API, GraphQL server, gRPC endpoint | +| `db` | Rectangle (rounded) | `#b2f2bb` | `#2f9e44` | Relational database (PostgreSQL, MySQL, SQLite) | +| `database` | Rectangle (rounded) | `#b2f2bb` | `#2f9e44` | Alias for `db` | +| `queue` | Rectangle (rounded) | `#fff3bf` | `#fab005` | Message queue or broker (Kafka, RabbitMQ, SQS, PubSub) | +| `cache` | Rectangle (rounded) | `#ffe8cc` | `#fd7e14` | Cache layer (Redis, Memcached, CDN edge cache) | +| `storage` | Rectangle (rounded) | `#ffec99` | `#f08c00` | Object/blob/file storage (S3, GCS, Azure Blob) | +| `frontend` | Rectangle (rounded) | `#a5d8ff` | `#1971c2` | Web app, SPA, mobile client, desktop app | +| `gateway` | Rectangle (bold, rounded) | `#ffa8a8` | `#c92a2a` | API gateway, load balancer, reverse proxy, ingress | +| `orchestrator`| Rectangle (bold, rounded) | `#ffa8a8` | `#c92a2a` | Container orchestrator (Kubernetes, Nomad, Docker Swarm) | +| `user` | Ellipse | `#e7f5ff` | `#1971c2` | Human actor, end user, client operator | +| `actor` | Ellipse | `#e7f5ff` | `#1971c2` | Alias for `user` | +| `external` | Rectangle (rounded) | `#ffc9c9` | `#e03131` | Third-party service, external SaaS, outside system boundary | +| `monitor` | Rectangle (rounded) | `#d3f9d8` | `#40c057` | Monitoring, logging, alerting, observability (Datadog, Prometheus) | +| `ml` | Rectangle (rounded) | `#e599f7` | `#9c36b5` | ML model, training pipeline, inference service | +| `ai` | Rectangle (rounded) | `#e599f7` | `#9c36b5` | Alias for `ml` | + +**Default** (unknown or omitted `type`): pale grey rectangle (`#f8f9fa` / `#495057`). + +--- + +## Cross-template type compatibility + +Both templates accept any `type` string. If the type is not in the template's +registry, the default node style is used. This means: + +- You can use `start`/`end` on an architecture diagram — they'll render with the + architecture template's default style. +- You can use `service` on a flowchart — it'll render as a plain purple rectangle. + +When in doubt, pick the template that matches the majority of your node types. + +--- + +## Quick-pick guide + +| What you're modelling | Recommended type | +|-----------------------|-----------------| +| User / human actor | `start` (flowchart) or `user` (architecture) | +| API call / service | `io` (flowchart) or `api` / `service` (architecture) | +| Database | `subprocess` (flowchart) or `db` (architecture) | +| Cache | `subprocess` (flowchart) or `cache` (architecture) | +| Condition / branch | `decision` (both templates) | +| Success terminal | `end` with green style override | +| Failure terminal | `end` with red + dashed style override | +| External dependency | `external` (architecture) | +| Queue / async step | `queue` (architecture) or `io` (flowchart) | diff --git a/skills/excalidraw-gen/schema.md b/skills/excalidraw-gen/schema.md new file mode 100644 index 000000000..0b9d4a588 --- /dev/null +++ b/skills/excalidraw-gen/schema.md @@ -0,0 +1,125 @@ +# Input File Schema + +Both JSON and YAML are accepted. Use whichever is more readable for the content. +The parser auto-detects the format — no flag needed. + +--- + +## Top-level fields + +| Field | Type | Required | Description | +|---------|--------|----------|-------------| +| `type` | string | ✅ | `"flowchart"` or `"architecture"` | +| `nodes` | array | ✅ | List of node objects (at least one required) | +| `edges` | array | ✅ | List of edge objects (can be empty) | +| `title` | string | optional | Diagram title — metadata only, not rendered | + +--- + +## Node object fields + +| Field | Type | Required | Description | +|------------|--------|----------|-------------| +| `id` | string | ✅ | Unique identifier. Use `snake_case`. No spaces. Must be unique across all nodes. | +| `label` | string | ✅ | Display text shown inside the node shape. Supports multi-line wrapping. | +| `type` | string | optional | Node type key — controls default shape and colour. See [node-types.md](node-types.md). Defaults to `process` if omitted. | +| `metadata` | object | optional | Arbitrary key-value data attached to the node. Not rendered in the diagram. | +| `style` | object | optional | Per-node visual overrides. See [style-overrides.md](style-overrides.md). | + +### Node `id` rules +- Must be unique across the entire `nodes` array — duplicates cause a validation error. +- Whitespace is stripped automatically. +- Use descriptive ids: `auth_service`, `validate_card`, `error_page`. +- Avoid special characters other than `_` and `-`. + +### Node `label` rules +- Required and must be non-empty. +- Long labels auto-wrap. Node width auto-adjusts from 180px to 260px based on label length; height expands to fit. +- To force a specific width beyond the auto range, set `width` in `style`. + +--- + +## Edge object fields + +| Field | Type | Required | Description | +|-----------------|---------|----------|-------------| +| `from` | string | ✅ | Source node `id` | +| `to` | string | ✅ | Target node `id` | +| `label` | string | optional | Text shown along the arrow at its geometric midpoint | +| `bidirectional` | boolean | optional | `true` renders arrowheads at both ends. Default: `false` | +| `style` | object | optional | Per-edge visual overrides. See [style-overrides.md](style-overrides.md). | + +### Edge rules +- `from` and `to` must both reference existing node `id` values — unknown ids cause a validation error. +- `from` and `to` must not be equal — self-loops cause a validation error. +- Duplicate edges (same `from`/`to` pair) are silently dropped (only the first is kept). + +--- + +## Minimal valid JSON skeleton + +```json +{ + "type": "flowchart", + "nodes": [ + { "id": "a", "label": "Start" }, + { "id": "b", "label": "End" } + ], + "edges": [ + { "from": "a", "to": "b" } + ] +} +``` + +## Minimal valid YAML skeleton + +```yaml +type: flowchart +nodes: + - id: a + label: Start + - id: b + label: End +edges: + - from: a + to: b +``` + +--- + +## Full node example (all fields) + +```json +{ + "id": "payment_gateway", + "label": "Charge Payment Gateway", + "type": "process", + "metadata": { "owner": "payments-team", "sla": "99.9%" }, + "style": { + "backgroundColor": "#fff3bf", + "strokeColor": "#f08c00", + "strokeWidth": 2, + "strokeStyle": "solid", + "fillStyle": "solid", + "width": 240, + "opacity": 100 + } +} +``` + +## Full edge example (all fields) + +```json +{ + "from": "validate", + "to": "payment_gateway", + "label": "Valid", + "bidirectional": false, + "style": { + "strokeColor": "#2f9e44", + "strokeStyle": "solid", + "strokeWidth": 2, + "opacity": 100 + } +} +``` diff --git a/skills/excalidraw-gen/style-overrides.md b/skills/excalidraw-gen/style-overrides.md new file mode 100644 index 000000000..1daf90f34 --- /dev/null +++ b/skills/excalidraw-gen/style-overrides.md @@ -0,0 +1,154 @@ +# Style Overrides + +Both nodes and edges accept an optional `style` object. +Any field you provide overrides only that specific property — +all other properties fall back to the template default. +You can override none, some, or all fields independently. + +--- + +## Node `style` fields + +| Field | Type | Accepted values | Default (template) | Description | +|-------------------|--------|-----------------|--------------------|-------------| +| `backgroundColor` | string | hex colour, `"transparent"` | Template fill | Shape fill colour | +| `strokeColor` | string | hex colour | Template stroke | Border/outline colour | +| `strokeWidth` | number | `1` – `5` | `2` | Border thickness in px | +| `strokeStyle` | string | `"solid"`, `"dashed"`, `"dotted"` | `"solid"` | Border line style | +| `fillStyle` | string | `"solid"`, `"hachure"`, `"cross-hatch"`, `"zigzag"` | `"solid"` | Fill pattern | +| `shape` | string | `"rectangle"`, `"ellipse"` | Template shape | Override the template shape | +| `width` | number | pixels | `180–260` (auto) | Node width. Auto-adjusts from 180px to 260px based on label length. Set explicitly to override. | +| `height` | number | pixels | auto | Node height. Auto-computed from label wrap if omitted. | +| `opacity` | number | `0` – `100` | `100` | Node opacity | + +### `fillStyle` visual guide + +| Value | Appearance | +|---------------|------------| +| `"solid"` | Flat, filled colour (default) | +| `"hachure"` | Diagonal hatching pattern over the fill colour | +| `"cross-hatch"` | Cross-hatching pattern | +| `"zigzag"` | Zigzag line pattern | + +--- + +## Edge `style` fields + +| Field | Type | Accepted values | Default | Description | +|---------------|--------|-----------------|---------|-------------| +| `strokeColor` | string | hex colour | `"#1e1e1e"` (dark) | Arrow line colour | +| `strokeStyle` | string | `"solid"`, `"dashed"`, `"dotted"` | `"solid"` | Arrow line style | +| `strokeWidth` | number | `1` – `5` | `2` | Arrow thickness in px | +| `opacity` | number | `0` – `100` | `100` | Arrow opacity | + +--- + +## Recommended colour palette + +These pairs are designed to work together. Use consistently across a diagram +to establish semantic meaning. + +| Semantic meaning | `backgroundColor` | `strokeColor` | +|--------------------------|-------------------|---------------| +| Blue — information, user | `#a5d8ff` | `#1971c2` | +| Green — success, ok, go | `#b2f2bb` | `#2f9e44` | +| Red — error, failure | `#ffc9c9` | `#c92a2a` | +| Orange — warning, manual | `#ffe8cc` | `#fd7e14` | +| Purple — process, service| `#d0bfff` | `#7048e8` | +| Yellow — queue, async | `#fff3bf` | `#fab005` | +| Teal — I/O, data | `#e3fafc` | `#0c8599` | +| Pink-red — gateway | `#ffa8a8` | `#c92a2a` | +| Purple-haze — ML/AI | `#e599f7` | `#9c36b5` | + +### Edge colour conventions in diagrams +- **Green edge** (`#2f9e44`) — success path, approval, valid condition +- **Red edge** (`#c92a2a`) — failure path, rejection, invalid condition +- **Dashed red edge** — failure + visual emphasis (most noticeable for errors) +- **Orange edge** (`#fd7e14`) — manual step, wait state, external dependency + +--- + +## Node style examples + +### Success terminal node +```json +{ + "id": "success", + "label": "Order Confirmed", + "type": "end", + "style": { + "backgroundColor": "#b2f2bb", + "strokeColor": "#2f9e44", + "strokeWidth": 3 + } +} +``` + +### Failure terminal node +```json +{ + "id": "fail", + "label": "Payment Failed", + "type": "end", + "style": { + "backgroundColor": "#ffc9c9", + "strokeColor": "#c92a2a", + "strokeStyle": "dashed", + "opacity": 90 + } +} +``` + +### Wide process node with hachure fill +```json +{ + "id": "batch_job", + "label": "Nightly Batch Processing", + "type": "process", + "style": { + "backgroundColor": "#fff3bf", + "strokeColor": "#f08c00", + "fillStyle": "hachure", + "width": 260 + } +} +``` + +### Manual approval (ellipse override) +```json +{ + "id": "approve", + "label": "Manual Approval", + "type": "decision", + "style": { + "backgroundColor": "#ffe8cc", + "strokeColor": "#fd7e14", + "strokeStyle": "dashed", + "shape": "ellipse" + } +} +``` + +--- + +## Edge style examples + +### Success path edge +```json +{ "from": "gate", "to": "deploy", "label": "Pass", "style": { "strokeColor": "#2f9e44" } } +``` + +### Failure path edge (dashed red) +```json +{ "from": "gate", "to": "fail", "label": "Fail", "style": { "strokeColor": "#c92a2a", "strokeStyle": "dashed" } } +``` + +### Thick highlighted edge +```json +{ "from": "client", "to": "gateway", "label": "HTTPS", "style": { "strokeWidth": 3, "strokeColor": "#1971c2" } } +``` + +### Faded background edge +```json +{ "from": "worker", "to": "db", "label": "write", "style": { "opacity": 60 } } +``` diff --git a/skills/excalidraw-gen/validation.md b/skills/excalidraw-gen/validation.md new file mode 100644 index 000000000..a6f34d5b4 --- /dev/null +++ b/skills/excalidraw-gen/validation.md @@ -0,0 +1,99 @@ +# Validation Rules + +The CLI validates the input file before rendering. Validation produces **errors** +(which abort rendering) and **warnings** (which print to stderr but still produce output). + +--- + +## Errors — these abort generation + +Fix all errors before the CLI will produce an output file. + +| Rule | Example of violation | +|------|---------------------| +| `nodes` must not be empty | `"nodes": []` | +| `type` must be `"flowchart"` or `"architecture"` | `"type": "sequence"` | +| All node `id` values must be unique | Two nodes both have `"id": "start"` | +| All `id` values must be non-empty strings | `"id": ""` | +| All `label` values must be non-empty strings | `"label": ""` | +| Edge `from` must reference an existing node `id` | `"from": "typo_id"` (no such node) | +| Edge `to` must reference an existing node `id` | `"to": "deleted_node"` (no such node) | +| Self-loops are not allowed | `{ "from": "a", "to": "a" }` | +| Node count must not exceed `--max-nodes` (default: 200) | 250 nodes without raising the limit | + +--- + +## Warnings — output is still generated + +Warnings are printed to stderr. The `.excalidraw` file is still written. + +| Condition | Warning message pattern | Effect on layout | +|-----------|------------------------|------------------| +| Cycle detected in the graph | `Cycle detected: X → Y` | Nodes in the cycle are placed at the end of the DAG layout | +| Disconnected node | `Node "X" is disconnected` | The node is placed by the layout engine but may float away from the main diagram | +| Duplicate edge | `Duplicate edge "X" → "Y" dropped` | Only the first occurrence of a duplicate `from`/`to` pair is kept | + +--- + +## How cycles are handled + +Cycles (e.g. A → B → C → A) are **not errors** — the layout engine uses +Kahn's topological sort, which places cyclic nodes at the end of the layout +rather than hanging indefinitely. The diagram will still generate correctly. + +If you intentionally have cycles (e.g. a retry loop), the layout may look slightly +unusual for the cyclic portion, but the rest of the diagram is unaffected. + +--- + +## How to avoid common errors + +### Unknown node references +Always define every node in `nodes` before referencing it in an edge. +Copy-paste the `id` exactly — the validator is case-sensitive (`Auth` ≠ `auth`). + +### Self-loops +To represent a recursive or retry action, use a separate node: + +```json +// Instead of: { "from": "process", "to": "process" } + +// Do this: +{ "from": "process", "to": "retry", "label": "Retry" }, +{ "from": "retry", "to": "process" } +``` + +### Disconnected nodes +Every node should have at least one edge connecting it to the rest of the diagram. +If you need an isolated annotation, consider adding a dummy edge with `"opacity": 0` +on the edge style, or remove the node entirely. + +### Duplicate edges +If you need two labelled branches between the same two nodes (e.g. A → B labelled +"cache hit" and A → B labelled "cache miss"), these are considered duplicate edges +and the second will be dropped. Route via an intermediate node instead: + +```json +// Instead of two A → B edges: +{ "from": "a", "to": "hit", "label": "Cache hit" }, +{ "from": "a", "to": "miss", "label": "Cache miss" }, +{ "from": "hit", "to": "b" }, +{ "from": "miss", "to": "b" } +``` + +--- + +## Checking output warnings + +Run the CLI and check stderr for warnings: + +```bash +npx excalidraw-gen generate diagram.json --out out.excalidraw 2>warnings.txt +cat warnings.txt +``` + +Or pipe stderr inline: + +```bash +npx excalidraw-gen generate diagram.json --out out.excalidraw 2>&1 | grep -i warn +```