DEV Community

Cover image for Generate OCI Architecture Diagrams from Terraform with One Claude Code Command
Sergio Farfan Cardenete
Sergio Farfan Cardenete

Posted on Edited on

Generate OCI Architecture Diagrams from Terraform with One Claude Code Command

Update (Sep 2026): v1.5.0 is out — one diagram model, many views. Six purpose presets — network topology, application / data flow, security, inventory, dependency and high availability — compose detail levels, label modes, draw.io layers and filters behind a single flag, and the new network label mode renders a resource’s name, private IP and ports from the model’s metadata. Routes, security, IAM and the connector kinds can be emitted as real draw.io layers on request, and filtering by tag, compartment, VCN, subnet, resource type and environment — plus a participating mode that draws only what takes part in the architecture and an optional tenancy-scoped global-services bucket — keeps a large tenancy readable. See "What's new in v1.5.0" below, or jump straight to the release notes.

The problem

Manually drawing OCI diagrams in draw.io is tedious...
If you have ever had to document an OCI architecture, the process is familiar. You open draw.io, locate the correct Oracle icon set, drag shapes onto the canvas, manually wire up VCNs and subnets, nudge elements into alignment — then spend another 30 minutes reconciling colors against Oracle's official template, only to discover that the Terraform configuration changed the previous week and the diagram is already out of date.

For cloud architects working with OCI, this is a recurring overhead on every project:

Diagrams drift from reality

Terraform is the source of truth, but draw.io has no awareness of it. Every infrastructure change requires a manual diagram update — one that typically does not occur until someone requests it during a review.

The OCI icon set is not native to draw.io

It must be located, imported, and mapped to the correct services across a dozen categories and 150+ icons — a non-trivial exercise before any actual diagramming begins.

Layout is time-consuming

Correctly representing the Region → VCN → Subnet → Service hierarchy, with proper spacing, non-overlapping containers, and Oracle's color scheme, requires significant effort even for experienced practitioners.

Hub-and-spoke topologies are especially difficult

Arranging 10–15 spoke VCNs connected through a DRG in a clean, readable layout is an hour-long exercise in manual positioning.

Diagrams are created once and abandoned

Because updates are costly, teams stop maintaining them. By the time a new team member onboards or an audit is conducted, the diagram reflects an architecture from two sprints prior.


The root cause is that architecture diagrams are treated as design artifacts — something produced manually — rather than something derived directly from the infrastructure definition.


What I built

https://github.com/sergio-farfan/OCI-draw.io-Architect

A Claude Code plugin — type /drawio-architect in any project...

How it works

The plugin accepts a Terraform directory, a terraform show -json plan or state file, a VCN name resolved against your .tfvars, or a plain-text description of the target architecture. An experimental mode can also read a live tenancy through the OCI CLI topology API.

From any of these inputs it builds a small model of the architecture — VCNs, subnets with their tier, the resources in each subnet, regional services, gateways, the on-premises side and the connections — and hands it to a deterministic layout recipe. The recipe places subnets in traffic order, puts the OCI Services panel beside them, stretches the data tier underneath, lines up the gateways, centres the hub on the VCN, and routes every connector through the gutters so lines never cross an icon or a caption. The result is a .drawio file styled with Oracle's Redwood palette backed by 159 bundled OCI SVG icons, validated for overlaps, containment and collisions before it is written, and rendered to PNG when draw.io desktop is installed.

The entire workflow is invoked within Claude Code via a single /drawio-architect command.

Step by Step Installation

Prerequisites

  • Claude Code (CLI) installed and working
  • Python 3.9+ (standard library only)
  • draw.io desktop for viewing generated .drawio files and for the PNG export

Pillow is optional and only needed to embed PNG logos; SVG logos need nothing.

Installation

Step 1 - Download, Extract and Install

One command:

curl -fsSL https://github.com/sergio-farfan/OCI-draw.io-Architect/releases/download/v1.5.0/oci-drawio-architect-v1.5.0.tar.gz | tar -xz && ./oci-drawio-architect/install.sh

Enter fullscreen mode Exit fullscreen mode

This will:

  • Download, extract and execute the installer script
  • Check prerequisites (Python 3; tries to install Pillow, but continues without it)
  • Create or update the local marketplace at ~/.claude/plugins/marketplaces/local/ (other plugins in it are preserved)
  • Copy the plugin files into the marketplace
  • Verify all components (8 checks, including a smoke test that builds and validates a demo diagram)

Step 2 - Register in Claude Code

Open Claude Code and run these two commands:

/plugin marketplace add ~/.claude/plugins/marketplaces/local
/plugin install oci-drawio-architect@local

Exit Claude Code and reopen it for the plugin to load.

Step 3 - Verify

Run inside Claude Code:

/drawio-architect
Enter fullscreen mode Exit fullscreen mode

The command should prompt you for what to diagram.

Example Snippet:

What's new in v1.5.0

v1.4.0 settled where a thing goes; v1.5.0 answers what goes in, and how much of it — one discovered topology, several readable views. The controls implement the team's diagram guidelines — the sections on filters, connector semantics, label modes and layers — and reviewer feedback that a full-detail hybrid diagram is unreadable as a management artefact.

The reference diagram as v1.5.0 renders it: captions rendered from the model's metadata, the load balancer carrying HTTPS/443 and the Autonomous Database 1522

One Terraform stack, six diagrams. --purpose names the view — network topology, application / data flow, security architecture, resource / inventory, dependency / relationship, deployment / high availability — the six the guidelines list. Each composes a detail level, a label mode, a layer set and a mode; any explicit flag still beats the preset.

An executive-to-engineering detail ladder. --detail executive|application|network|engineering gates content and sets the rest of the view's defaults. network is today's output; executive drops the badges, the CIDRs and the connector labels and reduces captions to names; engineering shows everything. One model, both the one-page overview and the engineering drawing.

Captions are a rendered field list. --label-mode minimal|network|detailed follows the guidelines' label-mode table over a documented vocabulary: name, type, private and public IP, CIDR, FQDN, port / protocol, compartment, AD / FD, lifecycle and tags. An OCID is never rendered in a caption, in any mode.

Layers you toggle in draw.io. With --layers auto, route, security, IAM, data-flow, management and association content goes onto real draw.io layers above a base layer named Network, switched in the layer panel (Cmd/Ctrl+Shift+L) without regenerating the file. The pass only re-parents cells, so enabling it cannot move a pixel.

Filters for large tenancies. One predicate over tags, compartment, region, VCN, subnet, resource type, environment and application, applied identically by the parser, the live-tenancy reader and the layout CLI. --mode participating draws only what takes part in the architecture — the live-tenancy default; Terraform stays on all — and --global-services bucket moves IAM, Policies, Audit and public DNS into a tenancy-scoped box below the region.

What changes if you change nothing is the caption of a parsed model: the shape line moves into the metadata, and a private IP and a port list appear when the input has them. A hand-written label is untouched, --label-mode minimal --label-fields display_name,shape brings the 1.4 caption back exactly, the geometry is identical, and the schema stays at 2.

One caveat: a purpose's hidden layers only take effect with --layers auto (or an explicit list). Layers are off by default, and with them off a "hidden" layer's content is simply not drawn rather than emitted and hidden.

Full release notes: https://github.com/sergio-farfan/OCI-draw.io-Architect/releases/tag/v1.5.0


What's new in v1.4.0

v1.3.0 made placement topology-aware inside the region box; v1.4.0 takes it outside. Everything here is about where a thing goes, and the rules come from Oracle's Architecture Diagram Toolkit deck and its published reference architectures, read alongside the team's diagram guidelines and reviewer feedback.

The reference diagram as v1.4.0 renders it: On-Premises left of the OCI Region, Internet and 3rd Party Cloud stacked on its right, Internet and NAT gateways on the VCN border facing the Internet box, and the Oracle Services Network as a band below the VCN stack

The location boxes leave the region. On-Premises, Internet and 3rd Party Cloud are page-level siblings of the OCI Region — On-Premises left, Internet and 3rd Party stacked right — the arrangement Oracle's Location Canvas defines. The Site-to-Site VPN / FastConnect / Remote Peering label sits in the gap between the on-premises box and the region, and a CPE or virtual circuit straddles that box's region-facing border the way a gateway straddles a VCN border. For a hybrid architecture the whole chain — CPE, hybrid link, attachment, DRG, VCN — now reads across the page.

Gateways face what they connect to. The Internet Gateway and the NAT Gateway take the VCN border facing the Internet box: the right border for the rightmost VCN column, the top border with captions above the glyphs for every other column, since a left-hand column's right border faces the next VCN. Each Internet Gateway gets an attachment connector to the Internet box, mirroring the Service Gateway's to the Oracle Services Network. Within a border the order is always IGW, NAT, Service Gateway, LPG — never model order.

The Oracle Services Network is a band below the VCN stack, fed by the Service Gateway on the VCN's bottom border — the right-hand column is where the Internet box went, and a services panel there would have every Internet-bound connector crossing it.

Compartments and grouping boxes become drawable. A compartment can wrap the VCNs it holds, nested, with an optional tenancy wrapper — opt-in, because a view with every compartment drawn is unreadable. Grouping boxes cover an OKE cluster inside a subnet (the Terraform parser emits one when a cluster and its node pools share a subnet) plus Oracle's tier and user-group boxes. A box is a real container: members are re-parented into it, the router avoids it, and a connector may terminate on it.

Smaller things: the DRG carries up to two route-table badges — the pair Oracle creates by default — subnet labels are two lines with a (Public) / (Private) token, the legend gains a row per badge kind drawn, and the attachment connector can be solid or dotted.

The old canvas is one flag away: --locations nested restores the 1.3.x layout exactly. Five new flags on oci_layout.py--locations, --gateway-edge, --subnet-label, --attachment-style and --show-compartments — have matching model keys. The schema stays at 2, new keys are optional, and a 1.3.x model renders unchanged apart from the two default flips.

Full release notes: https://github.com/sergio-farfan/OCI-draw.io-Architect/releases/tag/v1.4.0


What's new in v1.3.0

v1.2.0 made the layout deterministic; v1.3.0 makes it topology-aware, which matters most if what you document is hub-and-spoke or hybrid. The placement rules come from Oracle's Architecture Diagram Toolkit deck and Oracle's published reference architectures, read alongside the team's diagram guidelines and reviewer feedback on what the plugin was producing.

The reference diagram as v1.3.0 renders it: a region-level DRG with its VCN attachment, gateways on the VCN border, the Oracle Services Network panel, and NSG shields on the protected resources

The DRG is regional connectivity infrastructure, so it is drawn outside every VCN, centred on the VCN stack, with one labelled box per attachment beside it — VCN attachments facing the VCNs, Site-to-Site VPN, FastConnect and Remote Peering attachments facing the on-premises side. Before, the DRG arrived as an item in the on-premises panel or as a gateway icon inside the VCN; now the chain VCN — attachment — DRG — remote network is explicit on the canvas.

Gateways sit on the VCN border. Internet and NAT gateways straddle the bottom edge, the Service Gateway the right edge facing the services, and a Local Peering Gateway the edge facing its peer VCN.

Regional services share one Oracle Services Network panel. Logging, Vault, Notifications, IAM, Object Storage, Generative AI and the like are region-level rather than VCN-resident, so they are drawn once, right of the VCN columns, and reached through the Service Gateway.

Connector style carries meaning: a solid arrow is application or data flow, a dashed arrow is management traffic, a dotted line is an association or dependency, and a plain line without an arrowhead is a structural attachment. The legend names all four.

Route tables, security lists and NSGs are badges, not icons. A subnet carries its route table and security lists as small badges on its top-right corner, and an NSG is a shield on the resource it protects, with the names in the tooltip.

A classifier picks the presentation from the model — single VCN, multi-VCN, VCN with a DRG, hub-and-spoke, hybrid — and --drg-style icon|box overrides it. The validator refuses a DRG drawn inside a VCN, and any icon sitting in a VCN or subnet it does not belong to. Models written for 1.2.0 still build; they are migrated to schema 2 with a warning.

One thing v1.3.0 deliberately does not do is use draw.io's MCP connector: draw.io's built-in shape libraries carry no OCI icons, local generation keeps diagram content — VCN names, CIDRs, OCIDs — on your machine, and the connector's inline preview needs an MCP Apps host, which Claude Code is not.

Full release notes: https://github.com/sergio-farfan/OCI-draw.io-Architect/releases/tag/v1.3.0


What's new in v1.2.0

v1.1.0 fixed rendering fidelity; v1.2.0 fixes consistency. I went back to the diagram I had published as the reference and asked why newly generated diagrams kept drifting from it. The answer was a mix of tooling bugs and under-specified instructions, and v1.2.0 addresses both.

The reference diagram as v1.2.0 renders it: uniform icons, left-aligned labels, connectors routed through the gutters

Diagrams are data now. Instead of asking Claude to compute coordinates, the command fills in a model dict — subnets with a tier, the icons in each, the services panel, the gateways, the hub, the edges — and oci_layout.py lays it out with the same recipe every time. The reference diagram itself is now just a model (examples/generate_reference_layout.py), and it rebuilds pixel-for-pixel in the same structure.

import sys
sys.path.insert(0, "/path/to/oci-drawio-architect/scripts")
from oci_layout import write_diagram

MODEL = {
    "subject": "app-prod", "region": "eu-frankfurt-1", "region_label": "Frankfurt",
    "vcns": [{"name": "app-vcn", "cidr": "10.0.0.0/16", "subnets": [
        {"name": "sn-lb", "cidr": "10.0.0.0/24", "tier": "lb",
         "items": [{"icon": "load_balancer", "label": "Load Balancer\n10.0.0.7", "address": "lb"}]},
        {"name": "sn-app", "cidr": "10.0.1.0/24", "tier": "app",
         "items": [{"icon": "vm", "label": "App VM\n10.0.1.5\n4 OCPU / 32 GB", "address": "app"}]},
        {"name": "sn-db", "cidr": "10.0.2.0/24", "tier": "data",
         "items": [{"icon": "autonomous_db", "label": "ADB prod\napp-db", "address": "adb"}]}],
        "gateways": [{"icon": "service_gateway", "label": "Service\nGateway", "address": "sgw"}]}],
    "edges": [{"source": "lb", "target": "app", "label": "8080", "kind": "data"},
              {"source": "app", "target": "adb", "label": "1522", "kind": "data"}],
}
write_diagram(MODEL, "app-prod_Architecture.drawio", render_fmt="png")
Enter fullscreen mode Exit fullscreen mode

Terraform in, model out. parse_terraform.py reads HCL (with var. and local. resolution, cidrsubnet() included) or terraform show -json plan and state files and produces that model, so count, for_each and computed CIDRs are handled by Terraform rather than by regexes. An experimental query_tenancy.py does the same from a live tenancy via oci network vcn-topology get.

Connectors that route themselves. v1.1.0 handed edges to draw.io's orthogonal router, which does not avoid anything. v1.2.0 routes each connector on a lattice of container margins and gutters, penalising icons, captions, container titles and foreign containers, spreading parallel edges across corridors and placing labels where they collide with nothing. On the reference diagram the estimated crossings went from six (my hand-routed original) to zero. route="direct" and pinned ports are still there when you want them.

Icons finally look alike. Sixteen of the most common icons — VM, Functions, Block Volume, Object Storage among them — carried a leftover caption-placeholder rectangle from the original stencil conversion. It drew a faint box under the glyph and made those glyphs about a third smaller than their neighbours. The rectangle is gone, every viewBox is cropped to the glyph, and each glyph is fitted into the same 70×70 box. Fifty-five empty stencil shells that rendered as invisible cells were removed; the set is now 159 real icons, every one addressable by its file name or one of 206 short aliases.

The look you expect, with an official escape hatch. Region and compartment labels are back at the top-left, the services panel is charcoal again, dashed connectors have a proper dash pattern, and every style carries a font stack so machines without Oracle Sans get a sans-serif face instead of Times. Three profiles: default (the reference look with Oracle's 12 px labels), official (strict toolkit values: 1 pt sharp connectors, open arrowheads) and v1.0 (byte-for-byte the old sample).

A validator instead of an overlap checker. check_overlaps.py now reports overlaps between any two containers, shapes that leave their parent, icon and caption collisions, unknown parent or endpoint ids (which used to make draw.io silently drop the whole diagram), captions that need more lines than they have, and estimated edge crossings. Exit 0 means clean; --strict makes crossings blocking. render_drawio.py exports a PNG through draw.io desktop so the command can look at its own output before reporting.

Bugs you might have hit. Copying drawio_builder.py into a project, as the old docs said to do, broke icon lookup — the builder now finds its icons from the plugin location and the docs say to import instead. region = var.region is resolved. eu-london-1 never existed; London is uk-london-1. The installer no longer dies when pip is missing, no longer rewrites other plugins' marketplace entries, and falls back to cp when rsync is absent. The settings file is really gitignored now.

Also: legends, HTML rule tables, multi-page files, deterministic cell ids (key=), metadata/tooltips/links, a reproducible pack.sh, an Oracle attribution notice for the icons, and 954 unit tests.

Compatibility

v1.0 and v1.1 scripts keep running: check_overlaps(), pinned ports, waypoints and the hub alias are all preserved, and write() now also accepts plain strings. Regenerated diagrams will look different — uniform icons, left-aligned location labels, routed edges — which is the point. The one thing to change is the import: point sys.path at the plugin's scripts/ directory instead of copying the builder.

Full release notes: https://github.com/sergio-farfan/OCI-draw.io-Architect/releases/tag/v1.2.0


What's new in v1.1.0 (July 2026)

I've kept using this plugin since I posted this, and v1.1.0 is a big step up in rendering fidelity and workflow safety. Here's what changed.

Aspect-correct icons. v1.0.0 forced every icon into a fixed 75x95 slot, which stretched non-square icons by 15-20% on one axis. v1.1.0 reads each SVG's native aspect ratio and derives the cell size from it — fixed 95px height, width computed from the icon's own proportions (or the other way around if you only pass w or h to add_icon()). Icons render true to their actual shape now.

Styles aligned to Oracle's official v24.2 toolkit, plus 5 new container types. The color palette and every container style are now extracted directly from Oracle's official OCI Architecture Diagram Toolkit (v24.2): dotted-Sienna compartments with Bark labels, a #9E9892 2pt services-panel border, centered region labels, plain dashed connectors. Five new group types fill out the container vocabulary: tenancy, availability_domain, fault_domain, oracle_services_network, and onprem (the old hub type still works — it's now a deprecated alias of onprem).

Orthogonal edge routing by default. Port-less add_edge() calls now hand routing to draw.io's own orthogonal router instead of pinning a fixed exit/entry side. You get cleaner, auto-routed connectors without touching your script.

Before (v1.0.0, pinned ports on every edge):

d.add_edge(lb, vm, "443", parent=vcn,
           exit_x=1.0, exit_y=0.5, entry_x=0.0, entry_y=0.5)
Enter fullscreen mode Exit fullscreen mode

After (v1.1.0, default — let draw.io route it):

d.add_edge(lb, vm, "443", parent=vcn)
Enter fullscreen mode Exit fullscreen mode

Scripts that still pass exit_x/exit_y/entry_x/entry_y or waypoints keep their exact v1.0.0 pinned behavior — nothing breaks.

A shipped overlap checker, now a workflow gate. scripts/check_overlaps.py is a standalone CLI (exit 0 clean, 1 overlaps found, 2 usage/parse error), backed by DrawioBuilder.check_overlaps(). The /drawio-architect command now runs it as a mandatory gate before handing you the .drawio file, so overlapping containers get caught before you open draw.io, not after.

Metadata and tooltips. add_icon() and add_group() take optional metadata= and tooltip= arguments now, stored as draw.io <object> attributes. Hover a shape in draw.io to see the tooltip, or open Edit Data to see the metadata — useful for attaching OCIDs, workload tags, or anything else you want to keep with a shape.

detect_settings hardening. The Terraform-directory and tenancy-detection logic got a pass: the tenancy-OCID regex is now bounded (no more cross-variable false matches), Terraform-directory discovery is deterministic, OCI CLI JSON handling is more robust, and there's an optional plugin-local logos/ directory for embedding your own logo in a diagram.

A real demo. examples/generate_demo_diagram.py builds a full sample architecture — tenancy → on-prem + region → availability/fault domains, compartment → VCN → subnets, a services panel, an Oracle Services Network panel — exercising every container type, the main icon-sizing and edge modes, metadata/tooltips, and the overlap gate in one script. It doubles as a post-install smoke test.

Python 3.9 is now the floor (was 3.8).

Compatibility

Existing v1.0.0 scripts run unchanged — positional arguments, keyword ports plus waypoints, and the hub group type are all preserved. Regenerated diagrams will pick up the refreshed v24.2 styling and aspect-correct icons automatically.

Full release notes: https://github.com/sergio-farfan/OCI-draw.io-Architect/releases/tag/v1.1.0

Top comments (0)