Architecture Diagram Generator
Produces standalone, fully editable .svg files: real inlined vector icons (AWS/Azure/GCP official architecture icons, or a hand-drawn generic set for everything else), deterministic zone-aware layout, orthogonal connection routing, and real <text> labels. deliver --emit drawio additionally produces a self-contained editable .drawio mxGraph companion. SVG output uses zero raster images and zero <use> clones; draw.io output uses independently editable cells with local vector icon data and no remote image, external URL, or provider stencil dependency.
When to use this
| Situation |
Use this skill? |
| "Draw our AWS/Azure/GCP architecture" |
Yes |
| "System topology diagram for docs" |
Yes |
| "I need to edit this diagram afterward in Figma" |
Yes — this is the differentiator vs. every raster-output alternative |
| Multi-cloud or hybrid (cloud + on-prem) diagram |
Yes — mix provider: per node freely |
| Interactive, click-through, or animated diagram |
No — use static-web-artifacts-builder |
| Hand-drawn / whiteboard-style sketch |
No — use tldraw |
| Data chart, plot, or dashboard |
No — use chart-clarity |
| Reviewing or critiquing an existing architecture |
No — use architecture-reviewer |
| Single-frame concept illustration with no components/connections |
No — use concept-to-image |
Prerequisites
Run the following commands from this skill directory (skills/architecture-diagram in a checkout).
python3 with pyyaml installed (uv run --with pyyaml python3 -m engine ... if not already available).
Cloud-provider icons need a one-time, per-machine network fetch. Icons are never bundled in this skill; their providers publish diagram-use terms, so architecture-diagram records each provider's source and terms in the local cache rather than redistributing icon assets. The first time a diagram needs a given provider's icons, run:
python3 -m engine.fetch_icons --provider aws # ~5s, 1037 icons
python3 -m engine.fetch_icons --provider gcp # ~5s, 297 icons
python3 -m engine.fetch_icons --provider azure # ~60s, 704 icons
# or: --provider all
This builds a local cache (default ~/.cache/armory/cloud-icons, override with --cache-dir or $XDG_CACHE_HOME) pinned to a specific jgraph/drawio commit, so output is reproducible. Each rendered cloud icon is verified against its manifest SHA-256 digest; icon/digest-mismatch fails closed and requires the provider cache to be rebuilt with python3 -m engine.fetch_icons --provider <provider> --force. Subsequent renders reuse the verified cache — no network needed after the first fetch per provider. provider: generic needs no fetch at all; it uses the bundled hand-drawn icon set in references/icons-generic.md.
Workflow
- Parse the user's request: components (with descriptions), containment hierarchy (zones — VPC/Region/Resource Group/Subnet), connections (with semantic types if specified), and cloud provider(s).
- Resolve services to icons. For each cloud component, read
references/services-aws.yaml, references/services-azure.yaml, or references/services-gcp.yaml (whichever matches its provider) — or references/icons-generic.md for non-cloud — and note the exact slug to use as that node's service field. If a service genuinely has no icon in that provider's set (documented per-provider in each table), either pick the closest sibling category or leave service unset — the renderer falls back to a labeled placeholder rather than a wrong icon.
- Ensure the icon cache is warm for every provider used (see Prerequisites). Skip this for
provider: generic.
- Author the spec — a small YAML file per
references/spec-format.md: title, direction (LR/TB), zones (with parent for nesting), nodes (id, label, service, zone, color), edges (id, from, to, label, type).
- Validate without writing an artifact:
python3 -m engine validate spec.yaml --quality showcase --json
The receipt contains exact spec and candidate-artifact SHA-256 digests, validation counts, quality profile, composition status, and coded diagnostics. validate never touches an output path.
For declared sources, add --verify-sources; it fail-closes against local Git commits, blobs, and inclusive line ranges from the spec's checkout. It requires an origin remote and never copies source content or contacts a remote service.
Use --layout-json instead of --json when an agent needs the exact emitted node boxes, zone membership and boxes, routed edge waypoints, and edge-label rectangles for review. It also never writes SVG output.
- Deliver only a clean candidate:
python3 -m engine deliver spec.yaml -o diagram.svg --quality showcase --emit drawio --json
deliver stages the exact spec and candidate SVG beside the target, then atomically replaces every requested output only after every check passes. --emit drawio also delivers diagram.drawio; the JSON receipt's top-level artifacts list records the path, SHA-256, and byte count for each committed file. With --verify-sources, it atomically delivers diagram.svg, diagram.drawio, and diagram.sources.json; the SVG and draw.io output carry local VERIFIED SRC n badges, while the sidecar binds verified references to the delivered SVG digest. Caught write or replacement failures restore the prior bundle; process termination between replacements is outside that rollback contract.
- Review a draw.io companion before handoff:
- Open
diagram.drawio in draw.io.
- Confirm that a zone, node container, icon, node label, edge, and edge label select independently.
- Move a node label and save. The output preserves authored structure and initial computed placement; it does not promise round-trip SVG bytes or manual-route preservation.
- Compare authored revisions when needed:
python3 -m engine compare base.yaml head.yaml
compare emits a JSON receipt keyed only by authored node and edge ids. It reports added, removed, changed, moved, and rerouted entities with exact field paths. Its mandatory limitation is: Authored specification only; no runtime impact, causality, risk, or merge safety is inferred.
- Output the final
.svg and requested .drawio companion to the working directory or user-specified path. Mention the icon-cache prerequisite only if this was the first render for a given provider.
Spec fields at a glance
Full schema and worked examples: references/spec-format.md. Summary:
title: string
direction: LR | TB # default LR
provider: aws | azure | gcp | generic # default provider for nodes that omit it
profile: deployment-ownership # opt-in blocking deployment checks
sources:
- id: string # unique authored reference id
revision: 40-char hex # declared Git object id
path: relative POSIX path
lines: [start, end] # positive inclusive range
zones:
- id: string
label: string
parent: string | null # nesting — omit for a top-level zone
kind: generic | region | security # default generic
nodes:
- id: string # unique
label: string
sublabel: string # optional secondary line
service: string # icon cache slug — see services-aws.yaml / services-azure.yaml / services-gcp.yaml
provider: string # overrides the top-level provider for this node
zone: string | null # zone id this node belongs to
color: "#RRGGBB" # icon fill color
owner: string # required for non-external nodes under deployment-ownership
external: boolean # default false
storage: boolean # true requires a security zone under deployment-ownership
sources: [source-id] # optional declared source ids
edges:
- id: string # required and stable when using compare
from: string # node id
to: string # node id
label: string # required for security-boundary crossings under deployment-ownership
type: realtime | batch | event | control | default
sources: [source-id] # optional declared source ids
Deployment ownership validation
Set profile: deployment-ownership only when the spec is a deployment ownership record rather than a visual-only diagram. The profile fails closed: every node must resolve to exactly one kind: region, every non-external node needs a non-blank owner, every storage: true node must be inside kind: security, and a cross-security-zone edge needs a non-blank label naming its mechanism. It never infers those facts from labels, icons, service slugs, or layout. Omit profile to preserve existing behavior.
Connection type semantics
| type |
color |
style |
use for |
realtime |
blue |
solid |
REST, gRPC, synchronous requests |
batch |
red |
dashed |
SFTP, file transfer, scheduled jobs |
event |
green |
solid |
pub-sub, webhooks, event-driven triggers |
control |
orange |
solid |
management plane, monitoring, config push |
default |
gray |
solid |
when semantics are unspecified or only one flow type exists |
A legend renders automatically whenever more than one connection type is used in a diagram; it's omitted entirely when every edge is default.
Unsupported / partial coverage
- Kubernetes and on-premises providers have no dedicated icon set yet — model them with
provider: generic (server, container, database, queue, and 31 other hand-drawn glyphs in references/icons-generic.md, 35 total) until a future milestone adds native K8s/on-prem icon coverage.
- GCP and Azure icon coverage is narrower than AWS's (297 and ~700 icons vs. 1037).
references/services-aws.yaml, references/services-azure.yaml, and references/services-gcp.yaml each document that provider's specific gaps (e.g. GCP has no dedicated Vertex AI or Artifact Registry icon; Azure has no dedicated Pipelines/Boards/Artifacts icon) rather than silently substituting a misleading icon.
- Interactive elements (click-through, animation, mode toggles) are out of scope — this skill produces one static SVG. Use
static-web-artifacts-builder for that.
- PNG/PDF export isn't built in. Pipe the SVG through a converter afterward if a raster format is needed:
rsvg-convert diagram.svg -o diagram.png or cairosvg diagram.svg -o diagram.pdf.
Common patterns
AWS serverless API
title: Serverless API — us-east-1
provider: aws
direction: LR
zones:
- id: vpc
label: VPC 10.0.0.0/16
nodes:
- id: cf
label: CloudFront
service: cloudfront
color: "#8C4FFF"
- id: apigw
label: API Gateway
service: api-gateway
zone: vpc
color: "#E7157B"
- id: fn
label: Lambda
service: lambda
zone: vpc
color: "#ED7100"
- id: ddb
label: DynamoDB
zone: vpc
service: dynamodb
color: "#C925D1"
edges:
- {from: cf, to: apigw, label: HTTPS, type: realtime}
- {from: apigw, to: fn, label: invoke, type: realtime}
- {from: fn, to: ddb, label: query, type: realtime}
Azure web app (top-to-bottom)
title: Azure Web App
provider: azure
direction: TB
nodes:
- {id: user, label: User, color: "#6B7280"}
- {id: gw, label: App Gateway, service: application-gateways, color: "#0078D4"}
- {id: app, label: App Service, service: app-services, color: "#0078D4"}
- {id: db, label: SQL Database, service: sql-database, color: "#0078D4"}
edges:
- {from: user, to: gw, label: HTTPS}
- {from: gw, to: app}
- {from: app, to: db, label: TDS}
Multi-cloud pipeline
Mix providers freely — set provider per node instead of at the top level:
title: Multi-Cloud Data Pipeline
direction: LR
nodes:
- {id: ingest, label: Kinesis, provider: aws, service: kinesis, color: "#8C4FFF"}
- {id: transform, label: Dataflow, provider: gcp, service: cloud-dataflow, color: "#4285F4"}
- {id: notify, label: Logic Apps, provider: azure, service: logic-apps, color: "#0078D4"}
edges:
- {from: ingest, to: transform, label: stream, type: event}
- {from: transform, to: notify, label: alert, type: event}
Vendor-neutral / on-prem
Omit service (or set provider: generic) for nodes with no cloud icon — they render as a colored placeholder with the label's first letter:
title: On-Prem 3-Tier
provider: generic
direction: LR
nodes:
- {id: lb, label: Nginx, color: "#3A3A3A"}
- {id: app, label: App Servers, color: "#3A3A3A"}
- {id: db, label: PostgreSQL, color: "#3A3A3A"}
edges:
- {from: lb, to: app}
- {from: app, to: db}
Handling ambiguity
- Infer zone nesting from naming conventions (Region > VPC > Subnet, Resource Group > VNet > Subnet).
- Default to
default connection type and no legend when the user doesn't specify flow semantics.
- Default to
LR direction for request/data-flow diagrams, TB for hierarchical or layered ones.
- Use
provider: generic and the hand-drawn icon set when no cloud provider is specified or the architecture is vendor-neutral.
- Ask for clarification only when the component list or topology is fundamentally unclear — never when a single icon is missing (fall back per Unsupported above).
Exit codes and diagnostics
Every finding is a coded diagnostic carrying code, severity, message, subject (what it is about), evidence (the numbers that locate it), supported_fixes (spec-level moves), and sometimes suppresses. The exit code is the verdict:
| Exit |
Meaning |
Action |
| 0 |
validate completed with no error findings, or deliver atomically committed a validated SVG bundle |
Hand off the receipt and requested artifacts; any warnings are deliberate, explainable tradeoffs |
| 1 |
A blocking finding or operational delivery failure |
Apply a diagnostic's supported_fixes, or correct the output path or filesystem permissions |
| 2 |
Usage error — missing subcommand, unreadable spec path, unknown flag or profile value |
Correct the command |
--json prints the receipt and nothing else on stdout. It contains input and primary-SVG artifact SHA-256/byte records, output.written, validation.checks_passed/checks_total, quality, composition status, severity counts, and diagnostics. When --emit drawio is present, artifacts lists every committed output with its path, SHA-256, and byte count. --quality showcase raises composition/* route-geometry findings to errors; the default standard keeps them as warnings.
| Code |
Meaning |
Fix |
spec/* |
The spec is unanswerable: no nodes, duplicate or missing ids, unknown zone/parent/edge endpoint, zone cycle, empty zone |
Each diagnostic's supported_fixes names the field to change |
icon/not-found |
The service slug is absent from that provider's cache, or the cache was never fetched |
Use the exact slug from that provider's reference service map, or run fetch_icons.py --provider <name>; drop service to take the labeled placeholder deliberately |
layout/node-overlap |
Two node boxes collide |
Separate the nodes across ranks, or remove the duplicate |
layout/zone-overlap |
Two unrelated zone boxes collide because their member nodes are interleaved |
List each zone's members contiguously in nodes, or fix the zone assignments |
layout/label-overflow |
A label or sublabel cannot fit in its node box at the hard 6px minimum (blocking) |
Shorten it, or move detail into sublabel |
editability/* |
The output contains raster, <use>, or an external reference |
Renderer bug — a spec cannot cause this; report it |
usage/spec-unreadable |
The spec path does not exist or cannot be read |
Pass an existing, readable YAML path |
A fetch failure (could not fetch <provider> icons) is a network problem, not a spec problem: rerun fetch_icons.py for that provider, which skips already-cached icons.
Output
Report the SVG path, requested draw.io companion path, and any warning-severity findings left unresolved and why. Mention the icon-cache fetch cost only on the first render for a given provider.
Reference table
| File |
Contents |
Read when |
references/spec-format.md |
Full YAML spec schema, field-by-field, with edge cases |
Always, before authoring a spec |
references/services-aws.yaml |
AWS service name → icon slug + color, ~70 entries, documented gaps |
Diagramming AWS components |
references/services-azure.yaml |
Azure service name → icon slug + color, ~45 entries, documented gaps |
Diagramming Azure components |
references/services-gcp.yaml |
GCP service name → icon slug + color, ~35 entries, documented gaps |
Diagramming GCP components |
references/icons-generic.md |
35 hand-drawn generic icons (server, database, queue, user, …) for non-cloud diagrams |
provider: generic, or any node with no cloud equivalent |
references/editability.md |
Why the output never uses <use>/raster/outlined text, and what "editable" actually verifies |
Understanding or modifying the renderer's output contract |
Engine
| File |
Purpose |
engine/__main__.py |
python3 -m engine entry point for validate, deliver, and compare. |
engine/pipeline.py |
Deterministic spec → SVG composition and render result. |
engine/commands.py |
Validation, delivery, comparison receipts, staging, and CLI dispatch. |
engine/fetch_icons.py |
Local icon-cache builder; invoke with python3 -m engine.fetch_icons. |
engine/stencil2svg.py |
AWS/GCP stencil-to-SVG converter — internal. |
engine/svg_inline.py |
Azure real-SVG inliner/namespacer — internal. |
engine/data.py |
Single resolver for bundled assets and reference data. |
Assets
| File |
Contents |
assets/example-serverless.yaml |
A complete, real spec (AWS, zones, mixed connection types) — copy as a starting point |
assets/example-serverless.svg |
That spec's actual rendered output, committed for reference |
assets/generic-icons.json |
The data BundledGenericIconLookup reads; references/icons-generic.md is this same content in agent-readable form |
1---2name: architecture-diagram3description: Generate architecture diagrams as fully editable SVG with native AWS, Azure, and GCP icons for cloud diagrams, or hand-drawn generic icons for everything else. Optionally deliver a self-contained editable draw.io mxGraph companion. Deterministic layout computes zone nesting and orthogonal routing instead of hand-placed coordinates. Triggers on: "architecture diagram", "infra diagram", "system diagram", "deployment diagram", "topology diagram", "draw architecture", "AWS diagram", "Azure diagram", "GCP diagram", "cloud infrastructure diagram", "VPC diagram", "draw my AWS setup". Use when a user wants a static architecture diagram they can still edit afterward in Figma, Illustrator, Inkscape, or draw.io. NOT for architecture reviews, use architecture-reviewer.4---56# Architecture Diagram Generator78Produces standalone, fully editable `.svg` files: real inlined vector icons (AWS/Azure/GCP official architecture icons, or a hand-drawn generic set for everything else), deterministic zone-aware layout, orthogonal connection routing, and real `<text>` labels. `deliver --emit drawio` additionally produces a self-contained editable `.drawio` mxGraph companion. SVG output uses zero raster images and zero `<use>` clones; draw.io output uses independently editable cells with local vector icon data and no remote image, external URL, or provider stencil dependency.910## When to use this1112| Situation | Use this skill? |13|---|---|14| "Draw our AWS/Azure/GCP architecture" | **Yes** |15| "System topology diagram for docs" | **Yes** |16| "I need to edit this diagram afterward in Figma" | **Yes** — this is the differentiator vs. every raster-output alternative |17| Multi-cloud or hybrid (cloud + on-prem) diagram | **Yes** — mix `provider:` per node freely |18| Interactive, click-through, or animated diagram | No — use `static-web-artifacts-builder` |19| Hand-drawn / whiteboard-style sketch | No — use `tldraw` |20| Data chart, plot, or dashboard | No — use `chart-clarity` |21| Reviewing or critiquing an existing architecture | No — use `architecture-reviewer` |22| Single-frame concept illustration with no components/connections | No — use `concept-to-image` |2324## Prerequisites2526Run the following commands from this skill directory (`skills/architecture-diagram` in a checkout).2728- `python3` with `pyyaml` installed (`uv run --with pyyaml python3 -m engine ...` if not already available).29- **Cloud-provider icons need a one-time, per-machine network fetch.** Icons are never bundled in this skill; their providers publish diagram-use terms, so `architecture-diagram` records each provider's source and terms in the local cache rather than redistributing icon assets. The first time a diagram needs a given provider's icons, run:3031 ```bash32 python3 -m engine.fetch_icons --provider aws # ~5s, 1037 icons33 python3 -m engine.fetch_icons --provider gcp # ~5s, 297 icons34 python3 -m engine.fetch_icons --provider azure # ~60s, 704 icons35 # or: --provider all36 ```3738 This builds a local cache (default `~/.cache/armory/cloud-icons`, override with `--cache-dir` or `$XDG_CACHE_HOME`) pinned to a specific `jgraph/drawio` commit, so output is reproducible. Each rendered cloud icon is verified against its manifest SHA-256 digest; `icon/digest-mismatch` fails closed and requires the provider cache to be rebuilt with `python3 -m engine.fetch_icons --provider <provider> --force`. Subsequent renders reuse the verified cache — no network needed after the first fetch per provider. `provider: generic` needs no fetch at all; it uses the bundled hand-drawn icon set in `references/icons-generic.md`.3940## Workflow41421. **Parse** the user's request: components (with descriptions), containment hierarchy (zones — VPC/Region/Resource Group/Subnet), connections (with semantic types if specified), and cloud provider(s).432. **Resolve services to icons.** For each cloud component, read `references/services-aws.yaml`, `references/services-azure.yaml`, or `references/services-gcp.yaml` (whichever matches its provider) — or `references/icons-generic.md` for non-cloud — and note the exact slug to use as that node's `service` field. If a service genuinely has no icon in that provider's set (documented per-provider in each table), either pick the closest sibling category or leave `service` unset — the renderer falls back to a labeled placeholder rather than a wrong icon.443. **Ensure the icon cache is warm** for every provider used (see Prerequisites). Skip this for `provider: generic`.454. **Author the spec** — a small YAML file per `references/spec-format.md`: `title`, `direction` (`LR`/`TB`), `zones` (with `parent` for nesting), `nodes` (`id`, `label`, `service`, `zone`, `color`), `edges` (`id`, `from`, `to`, `label`, `type`).465. **Validate without writing an artifact:**47 ```bash48 python3 -m engine validate spec.yaml --quality showcase --json49 ```50 The receipt contains exact spec and candidate-artifact SHA-256 digests, validation counts, quality profile, composition status, and coded diagnostics. `validate` never touches an output path.51 For declared `sources`, add `--verify-sources`; it fail-closes against local Git commits, blobs, and inclusive line ranges from the spec's checkout. It requires an `origin` remote and never copies source content or contacts a remote service.52 Use `--layout-json` instead of `--json` when an agent needs the exact emitted node boxes, zone membership and boxes, routed edge waypoints, and edge-label rectangles for review. It also never writes SVG output.536. **Deliver only a clean candidate:**54 ```bash55 python3 -m engine deliver spec.yaml -o diagram.svg --quality showcase --emit drawio --json56 ```57 `deliver` stages the exact spec and candidate SVG beside the target, then atomically replaces every requested output only after every check passes. `--emit drawio` also delivers `diagram.drawio`; the JSON receipt's top-level `artifacts` list records the path, SHA-256, and byte count for each committed file. With `--verify-sources`, it atomically delivers `diagram.svg`, `diagram.drawio`, and `diagram.sources.json`; the SVG and draw.io output carry local `VERIFIED SRC n` badges, while the sidecar binds verified references to the delivered SVG digest. Caught write or replacement failures restore the prior bundle; process termination between replacements is outside that rollback contract.587. **Review a draw.io companion before handoff:**59 1. Open `diagram.drawio` in draw.io.60 2. Confirm that a zone, node container, icon, node label, edge, and edge label select independently.61 3. Move a node label and save. The output preserves authored structure and initial computed placement; it does not promise round-trip SVG bytes or manual-route preservation.628. **Compare authored revisions when needed:**63 ```bash64 python3 -m engine compare base.yaml head.yaml65 ```66 `compare` emits a JSON receipt keyed only by authored node and edge ids. It reports added, removed, changed, moved, and rerouted entities with exact field paths. Its mandatory limitation is: `Authored specification only; no runtime impact, causality, risk, or merge safety is inferred.`679. **Output** the final `.svg` and requested `.drawio` companion to the working directory or user-specified path. Mention the icon-cache prerequisite only if this was the first render for a given provider.6869## Spec fields at a glance7071Full schema and worked examples: `references/spec-format.md`. Summary:7273```yaml74title: string75direction: LR | TB # default LR76provider: aws | azure | gcp | generic # default provider for nodes that omit it77profile: deployment-ownership # opt-in blocking deployment checks78sources:79 - id: string # unique authored reference id80 revision: 40-char hex # declared Git object id81 path: relative POSIX path82 lines: [start, end] # positive inclusive range83zones:84 - id: string85 label: string86 parent: string | null # nesting — omit for a top-level zone87 kind: generic | region | security # default generic88nodes:89 - id: string # unique90 label: string91 sublabel: string # optional secondary line92 service: string # icon cache slug — see services-aws.yaml / services-azure.yaml / services-gcp.yaml93 provider: string # overrides the top-level provider for this node94 zone: string | null # zone id this node belongs to95 color: "#RRGGBB" # icon fill color96 owner: string # required for non-external nodes under deployment-ownership97 external: boolean # default false98 storage: boolean # true requires a security zone under deployment-ownership99 sources: [source-id] # optional declared source ids100edges:101 - id: string # required and stable when using compare102 from: string # node id103 to: string # node id104 label: string # required for security-boundary crossings under deployment-ownership105 type: realtime | batch | event | control | default106 sources: [source-id] # optional declared source ids107```108109### Deployment ownership validation110111Set `profile: deployment-ownership` only when the spec is a deployment ownership record rather than a visual-only diagram. The profile fails closed: every node must resolve to exactly one `kind: region`, every non-external node needs a non-blank `owner`, every `storage: true` node must be inside `kind: security`, and a cross-security-zone edge needs a non-blank label naming its mechanism. It never infers those facts from labels, icons, service slugs, or layout. Omit `profile` to preserve existing behavior.112113## Connection type semantics114115| type | color | style | use for |116|---|---|---|---|117| `realtime` | blue | solid | REST, gRPC, synchronous requests |118| `batch` | red | dashed | SFTP, file transfer, scheduled jobs |119| `event` | green | solid | pub-sub, webhooks, event-driven triggers |120| `control` | orange | solid | management plane, monitoring, config push |121| `default` | gray | solid | when semantics are unspecified or only one flow type exists |122123A legend renders automatically whenever more than one connection type is used in a diagram; it's omitted entirely when every edge is `default`.124125## Unsupported / partial coverage126127- **Kubernetes and on-premises providers** have no dedicated icon set yet — model them with `provider: generic` (server, container, database, queue, and 31 other hand-drawn glyphs in `references/icons-generic.md`, 35 total) until a future milestone adds native K8s/on-prem icon coverage.128- **GCP and Azure icon coverage is narrower than AWS's** (297 and ~700 icons vs. 1037). `references/services-aws.yaml`, `references/services-azure.yaml`, and `references/services-gcp.yaml` each document that provider's specific gaps (e.g. GCP has no dedicated Vertex AI or Artifact Registry icon; Azure has no dedicated Pipelines/Boards/Artifacts icon) rather than silently substituting a misleading icon.129- **Interactive elements** (click-through, animation, mode toggles) are out of scope — this skill produces one static SVG. Use `static-web-artifacts-builder` for that.130- **PNG/PDF export** isn't built in. Pipe the SVG through a converter afterward if a raster format is needed: `rsvg-convert diagram.svg -o diagram.png` or `cairosvg diagram.svg -o diagram.pdf`.131132## Common patterns133134### AWS serverless API135136```yaml137title: Serverless API — us-east-1138provider: aws139direction: LR140zones:141 - id: vpc142 label: VPC 10.0.0.0/16143nodes:144 - id: cf145 label: CloudFront146 service: cloudfront147 color: "#8C4FFF"148 - id: apigw149 label: API Gateway150 service: api-gateway151 zone: vpc152 color: "#E7157B"153 - id: fn154 label: Lambda155 service: lambda156 zone: vpc157 color: "#ED7100"158 - id: ddb159 label: DynamoDB160 zone: vpc161 service: dynamodb162 color: "#C925D1"163edges:164 - {from: cf, to: apigw, label: HTTPS, type: realtime}165 - {from: apigw, to: fn, label: invoke, type: realtime}166 - {from: fn, to: ddb, label: query, type: realtime}167```168169### Azure web app (top-to-bottom)170171```yaml172title: Azure Web App173provider: azure174direction: TB175nodes:176 - {id: user, label: User, color: "#6B7280"}177 - {id: gw, label: App Gateway, service: application-gateways, color: "#0078D4"}178 - {id: app, label: App Service, service: app-services, color: "#0078D4"}179 - {id: db, label: SQL Database, service: sql-database, color: "#0078D4"}180edges:181 - {from: user, to: gw, label: HTTPS}182 - {from: gw, to: app}183 - {from: app, to: db, label: TDS}184```185186### Multi-cloud pipeline187188Mix providers freely — set `provider` per node instead of at the top level:189190```yaml191title: Multi-Cloud Data Pipeline192direction: LR193nodes:194 - {id: ingest, label: Kinesis, provider: aws, service: kinesis, color: "#8C4FFF"}195 - {id: transform, label: Dataflow, provider: gcp, service: cloud-dataflow, color: "#4285F4"}196 - {id: notify, label: Logic Apps, provider: azure, service: logic-apps, color: "#0078D4"}197edges:198 - {from: ingest, to: transform, label: stream, type: event}199 - {from: transform, to: notify, label: alert, type: event}200```201202### Vendor-neutral / on-prem203204Omit `service` (or set `provider: generic`) for nodes with no cloud icon — they render as a colored placeholder with the label's first letter:205206```yaml207title: On-Prem 3-Tier208provider: generic209direction: LR210nodes:211 - {id: lb, label: Nginx, color: "#3A3A3A"}212 - {id: app, label: App Servers, color: "#3A3A3A"}213 - {id: db, label: PostgreSQL, color: "#3A3A3A"}214edges:215 - {from: lb, to: app}216 - {from: app, to: db}217```218219## Handling ambiguity220221- Infer zone nesting from naming conventions (Region > VPC > Subnet, Resource Group > VNet > Subnet).222- Default to `default` connection type and no legend when the user doesn't specify flow semantics.223- Default to `LR` direction for request/data-flow diagrams, `TB` for hierarchical or layered ones.224- Use `provider: generic` and the hand-drawn icon set when no cloud provider is specified or the architecture is vendor-neutral.225- Ask for clarification only when the component list or topology is fundamentally unclear — never when a single icon is missing (fall back per Unsupported above).226227## Exit codes and diagnostics228229Every finding is a coded diagnostic carrying `code`, `severity`, `message`, `subject` (what it is about), `evidence` (the numbers that locate it), `supported_fixes` (spec-level moves), and sometimes `suppresses`. The exit code is the verdict:230231| Exit | Meaning | Action |232|---|---|---|233| 0 | `validate` completed with no error findings, or `deliver` atomically committed a validated SVG bundle | Hand off the receipt and requested artifacts; any warnings are deliberate, explainable tradeoffs |234| 1 | A blocking finding or operational delivery failure | Apply a diagnostic's `supported_fixes`, or correct the output path or filesystem permissions |235| 2 | Usage error — missing subcommand, unreadable spec path, unknown flag or profile value | Correct the command |236237`--json` prints the receipt and nothing else on stdout. It contains `input` and primary-SVG `artifact` SHA-256/byte records, `output.written`, `validation.checks_passed`/`checks_total`, quality, composition status, severity counts, and diagnostics. When `--emit drawio` is present, `artifacts` lists every committed output with its path, SHA-256, and byte count. `--quality showcase` raises `composition/*` route-geometry findings to errors; the default `standard` keeps them as warnings.238239| Code | Meaning | Fix |240|---|---|---|241| `spec/*` | The spec is unanswerable: no nodes, duplicate or missing ids, unknown zone/parent/edge endpoint, zone cycle, empty zone | Each diagnostic's `supported_fixes` names the field to change |242| `icon/not-found` | The `service` slug is absent from that provider's cache, or the cache was never fetched | Use the exact slug from that provider's reference service map, or run `fetch_icons.py --provider <name>`; drop `service` to take the labeled placeholder deliberately |243| `layout/node-overlap` | Two node boxes collide | Separate the nodes across ranks, or remove the duplicate |244| `layout/zone-overlap` | Two unrelated zone boxes collide because their member nodes are interleaved | List each zone's members contiguously in `nodes`, or fix the `zone` assignments |245| `layout/label-overflow` | A `label` or `sublabel` cannot fit in its node box at the hard 6px minimum (blocking) | Shorten it, or move detail into `sublabel` |246| `editability/*` | The output contains raster, `<use>`, or an external reference | Renderer bug — a spec cannot cause this; report it |247| `usage/spec-unreadable` | The spec path does not exist or cannot be read | Pass an existing, readable YAML path |248249A fetch failure (`could not fetch <provider> icons`) is a network problem, not a spec problem: rerun `fetch_icons.py` for that provider, which skips already-cached icons.250251## Output252253Report the SVG path, requested draw.io companion path, and any warning-severity findings left unresolved and why. Mention the icon-cache fetch cost only on the first render for a given provider.254255## Reference table256257| File | Contents | Read when |258|---|---|---|259| `references/spec-format.md` | Full YAML spec schema, field-by-field, with edge cases | Always, before authoring a spec |260| `references/services-aws.yaml` | AWS service name → icon slug + color, ~70 entries, documented gaps | Diagramming AWS components |261| `references/services-azure.yaml` | Azure service name → icon slug + color, ~45 entries, documented gaps | Diagramming Azure components |262| `references/services-gcp.yaml` | GCP service name → icon slug + color, ~35 entries, documented gaps | Diagramming GCP components |263| `references/icons-generic.md` | 35 hand-drawn generic icons (server, database, queue, user, …) for non-cloud diagrams | `provider: generic`, or any node with no cloud equivalent |264| `references/editability.md` | Why the output never uses `<use>`/raster/outlined text, and what "editable" actually verifies | Understanding or modifying the renderer's output contract |265266## Engine267268| File | Purpose |269|---|---|270| `engine/__main__.py` | `python3 -m engine` entry point for validate, deliver, and compare. |271| `engine/pipeline.py` | Deterministic spec → SVG composition and render result. |272| `engine/commands.py` | Validation, delivery, comparison receipts, staging, and CLI dispatch. |273| `engine/fetch_icons.py` | Local icon-cache builder; invoke with `python3 -m engine.fetch_icons`. |274| `engine/stencil2svg.py` | AWS/GCP stencil-to-SVG converter — internal. |275| `engine/svg_inline.py` | Azure real-SVG inliner/namespacer — internal. |276| `engine/data.py` | Single resolver for bundled assets and reference data. |277278## Assets279280| File | Contents |281|---|---|282| `assets/example-serverless.yaml` | A complete, real spec (AWS, zones, mixed connection types) — copy as a starting point |283| `assets/example-serverless.svg` | That spec's actual rendered output, committed for reference |284| `assets/generic-icons.json` | The data `BundledGenericIconLookup` reads; `references/icons-generic.md` is this same content in agent-readable form |