Generate a draw.io architecture diagram (or PNG) from an Architecture YAML file. Produces .drawio XML following the official Company template style: DC containers with double-border, network zones with dashed borders, correct shapes for each component type (hexagon for F5/FW, parallelogram for API gateway, cylinder for DB, etc.), edges labeled with shared protocol/auth codes (P-* / AU-*), and a code legend. Optionally exports PNG. Use when: you have an arch YAML and need a visual diagram to r...
Installs into .claude/skills of the current project.
Are you the author of Arch Diagram?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/axisvela-arch-diagram)
---
name: arch-diagram
description: >
Generate a draw.io architecture diagram (or PNG) from an Architecture YAML file.
Produces .drawio XML following the official Company template style: DC containers
with double-border, network zones with dashed borders, correct shapes for each
component type (hexagon for F5/FW, parallelogram for API gateway, cylinder for DB,
etc.), edges labeled with shared protocol/auth codes (P-* / AU-*), and a code
legend. Optionally exports PNG.
Use when: you have an arch YAML and need a visual diagram to review or share.
---
> **Locating shared resources.** References in this file to `standards/`,
> `tools/`, `config.yaml`, and `templates/` are relative to the ArchHarness
> resource root. Determine the root, in order: (1) the `ARCHHARNESS_HOME`
> environment variable, (2) the output of `python -m archharness root` (the
> pip-installed package bundles these resources under its `data` directory),
> (3) the current working directory when it already contains `config.yaml` and
> `tools/` (the repository checkout). Prefix shared paths with that root
> whenever the working directory is not the resource root.
You are a **diagram generation assistant**. When invoked, the user provides an
Architecture YAML file (or a path to one). Your job is to run the diagram
generator and report the result. Never hand-draw architecture XML — always
use the deterministic generator, which fail-closes on unresolved references
and duplicate IDs.
## What the tool produces
The generator (`archharness diagram`) reads an Architecture YAML and produces:
1. **`.drawio` file** — draw.io XML you can open in draw.io desktop or Confluence.
Layout: regions in a 2-column grid, zones stacked inside each DC, components
arranged in rows inside zones.
2. **`.png` image** (optional, `--png` flag) — rendered by the **D2 CLI** by
default, with matplotlib as a fallback when D2 is absent. The `.drawio` file is
the **editable source**, not the image renderer; `--png-engine drawio` opts
back into a draw.io render.
3. **`.d2` / `.puml` files** (optional, `--d2` / `--puml` flags) — text
interchange formats for developer workflows.
For a one-shot diagram from a `A -> B` description without a YAML file,
use `archharness sketch "Browser -> API -> DB" -o diagram.drawio` instead.
## Shape mapping (matches Company template)
| YAML type/shape | draw.io shape |
|----------------|---------------|
| `type: LB` / `shape: hexagon` | Hexagon (F5, ALB, FW) |
| `type: IP` / `shape: parallelogram` | Parallelogram (WSO2, APIH, Nginx) |
| `type: MQ` / `shape: message_queue` | Rounded parallelogram (Kafka) |
| `type: DB` / `shape: cylinder` | Cylinder (databases) |
| `type: BE` (default) | Dashed rectangle (Company internal app) |
| `type: BE`, `owner: biz_owned` | Purple filled rectangle |
| `type: BE`, `owner: third_party` | Orange filled rectangle |
| DC container | `shape=ext;double=1` (double border) |
| Network zone | `shape=ext;double=1;dashed=1` |
| AWS group | `shape=mxgraph.aws4.group` with cloud icon |
| Internet | `shape=mxgraph.aws4.internet` |
Sensitivity markers:
- Components with `Company Confidential` or `Company Restricted` get a ⚠ prefix on their label.
## Edge labels — shared code vocabulary
Edge labels are **codes**, not prose. The vocabulary lives in
`standards/diagram-codes.yaml` and is shared by every example, renderer and
reviewer, so the same relation always renders the same code.
| Kind | Form | Examples |
|---|---|---|
| Protocol | `P-<code>` | `P-HTTPS`, `P-KAFKA`, `P-JDBC`, `P-RFC`, `P-IDOC`, `P-OPCUA`, `P-MQTT` |
| Authentication | `AU-<minor>` | `AU-T1`, `AU-C1`, `AU-P4`, `AU-S1`, `AU-K1`, `AU-N0` |
A combination joins with `+` and the prefix is written once: `mTLS + SASL/SCRAM`
→ `AU-C1+S1`. Codes are collected in taxonomy order, so the result is stable
regardless of how the source text is phrased.
**Authentication classes** (supplement as needed in `standards/diagram-codes.yaml`):
| Class | Codes | Meaning |
|---|---|---|
| Token / federation | `T1`–`T6` | OAuth2 client credentials · OAuth2/OIDC user login · SAML2 · session token · JWT/bearer · personal access token |
| Certificate / key | `C1` `C2` | mTLS / client certificate · SSH public key |
| SASL | `S1`–`S4` | SCRAM · PLAIN · GSSAPI · OAUTHBEARER |
| Kerberos / OS | `K1` `K2` | Kerberos / logon ticket · NTLM / Windows integrated |
| Password / credential | `P1`–`P6` | user ID/password · HTTP Basic · API key · service account/secret · LDAP bind · RADIUS/TACACS+ |
| Cloud identity | `I1`–`I3` | IAM role · managed identity · service principal / workload identity |
| User factor | `M1` `M2` | MFA/OTP · FIDO2 / WebAuthn / passkey |
| Other | `X1`–`X4` | internal access auth · service auth (unspecified) · IP allowlist · anonymous |
| Authorization | `Z1`–`Z4` | topic ACL / least privilege · RBAC · ABAC/policy engine · OAuth2 scope |
| None | `N0` | no service authentication |
Each diagram renders a legend listing only the codes it actually uses.
**Edge colour = interface status** (the `[STATUS: …]` marker is never printed):
| Status | Colour |
|---|---|
| `EXISTING` | blue `#1565C0` |
| `NEW`, `CHANGE` | red `#C62828` |
| `REMOVE` | grey `#9E9E9E` |
| `TBD` / unspecified | blue-grey `#78909C` |
**Semantic roles are declared by the model, not guessed by the renderer.** When
you write or review an Architecture YAML, mark the nodes that carry meaning and
let the renderer apply it deterministically:
| Role | Declaration | Effect |
|---|---|---|
| Zone-boundary firewall | `role: zone_boundary` | In a region whose policy enables boundary roles, the node is not drawn and the zone is marked `· FW`; flows must be declared directly between the components that talk (rule R-INF-4 in `standards/requirements-model-v2.yaml`). Elsewhere (public cloud) the node stays explicit. |
| Service provider | `role: service_provider` | Every edge touching it points **into** it; an edge leaving it is reversed, because producers and consumers both call the broker. |
| Logical group | `group: "<name>"` | Forces the members into one named dashed frame instead of a derived title. |
Recognition is policy-driven, in this order: the explicit attribute above, then
**structural** signals (`component_role`, `type`, `shape`, `node_kind`), then
optional name patterns. Name patterns are **empty by default** — matching on
words like "firewall" or "Kafka" is not portable across vendors, languages, or
renamed nodes, so do not enable them unless a model genuinely cannot be
annotated. The policy, the region container rules (`network_zones` vs
`subnets`, where boundary roles apply) and the layout tuning all live in
`standards/diagram-roles.yaml`, so no architecture-specific rule is hardcoded in
the renderers.
**Logical groups.** Sibling components in the same zone that are interchangeable
— same technology signature *and* identical edge signatures (same peers, same
protocols, same direction) — are folded into one dashed box, and their fan-out
edges collapse to one edge per peer. This is automatic; a component with even
one extra relation stays standalone. Set `group: "<name>"` on components to force
a named grouping (and to keep a human-readable box title) instead of the derived
`<type> group ×N`. The renderers use the same pass, so `.drawio` and `.png` agree.
**Font hierarchy.** Component labels use `fontSize=14`, edge labels `fontSize=9`.
Component technology stacks are lower-cased and compressed (`Java (version TBD)`
→ `java`, `Internal K8s Platform` → `K8s`).
## How to invoke
```bash
# Generate .drawio only
archharness diagram -i arch.yaml -o diagram.drawio
# Generate .drawio (editable) + .d2 + PNG (the PNG is rendered by D2)
archharness diagram -i arch.yaml -o diagram.drawio --d2 diagram.d2 --png diagram.png
# One-shot sketch without a YAML file
archharness sketch "Browser -> API -> DB" -o diagram.drawio
```
(The legacy path `python tools/arch-diagram-gen/arch_diagram_gen.py`
still works via a compatibility shim; prefer the CLI above.)
## Requirements
```
pip install pyyaml # required
pip install matplotlib # optional, PNG fallback
```
For the PNG image, install the **D2 CLI** (`d2 --version`). draw.io desktop is
only needed to edit the `.drawio` source, not to produce an image. For a very
large diagram, pass `--d2-scale 0.2` (d2's raster backend can fail at full size).
## When asked to generate a diagram
1. Check if the user has provided a YAML file path or YAML content.
2. If YAML content is provided inline, write it to a temp file first.
3. Run the tool and report what was generated.
4. If the output .drawio path is in the project, confirm it's ready to open.
5. If PNG was requested but the D2 CLI is unavailable, note that the matplotlib
fallback was used and recommend installing D2 for the routed, higher-fidelity
image. `--png-engine drawio` is available when a draw.io render is explicitly
wanted.