C4 Architecture Diagrams skill for Codex
Context, container and component views as code. Codex builds C4 diagrams from evidence in the codebase (entry points, compose files, Terraform, connection strings) rather than from memory, then writes them as Structurizr DSL or Mermaid C4 so they live in the repo. Each element states its technology and responsibility, every arrow carries a verb and protocol, and views stay at one zoom level within a readable element budget.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- c4-architecture-diagrams Installs to ~/.agents/skills/c4-architecture-diagrams/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install c4-architecture-diagrams The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project c4-architecture-diagrams Installs to .agents/skills/c4-architecture-diagrams/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/c4-architecture-diagrams.zipunzip -o c4-architecture-diagrams.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) c4-architecture-diagrams PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $c4-architecture-diagrams, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Produces C4 model architecture diagrams as code - System Context, Container, Component, dynamic and deployment views - in Structurizr DSL or Mermaid C4, derived from the actual codebase and infrastructure, with consistent notation, labelled relationships and a legend. Use when asked to diagram a system, document architecture for onboarding, draw a context or container diagram, convert a whiteboard sketch to diagrams-as-code, or keep architecture diagrams in sync with the repo.
Use it when
- A system needs architecture diagrams for onboarding, reviews or audits
- Diagrams exist only as images or whiteboard photos and keep going stale
- You want several consistent views generated from one model
- A design proposal needs current-state and target-state pictures
Use something else when
- You need sequence, ER, state or flowchart diagrams rather than C4 views: use mermaid-diagrams
- You need a critique of the architecture rather than a picture of it: use system-design-review
How to check the result
Every deployable found in the repo or infrastructure code appears as a container (or is excluded with a note), every arrow is labelled with a verb and protocol, and the source renders without errors.
The mistake it prevents
Mixing abstraction levels in one diagram and leaving relationships unlabelled, which produces a box-and-line picture nobody can read.
A good C4 diagram answers one question for one audience at one zoom level, every box says what it is and what it does, every arrow says what flows and how, and the source lives in the repo as text so it changes in the same PR as the system.
The four levels, and which to draw
| Level | Shows | Audience | Draw it? |
|---|---|---|---|
| 1. System Context | Your system as one box, its users and the external systems it talks to | Everyone, including non-engineers | Always |
| 2. Container | Deployable/runnable units: apps, APIs, databases, queues, functions | Engineers, ops, security | Almost always |
| 3. Component | Major modules inside one container | Engineers working in that container | Only for complex containers |
| 4. Code | Classes | Rarely useful | Generate from IDE if ever |
Supplementary views worth drawing: a dynamic view for one important flow (checkout, login) and a deployment view showing containers mapped to infrastructure.
“Container” in C4 means a separately running thing (a web app, a database, a Lambda), not a Docker container. Say this in the legend if the audience might confuse them.
Discover the system before drawing
Derive the model from evidence, not memory:
cat AGENTS.md 2>/dev/null; ls
rg -l "listen\(|createServer|app.run|http.ListenAndServe|@SpringBootApplication" --type-add 'src:*.{ts,js,py,go,java,kt}' -t src
ls docker-compose*.yml compose*.yaml k8s helm terraform infra 2>/dev/null
rg -n "DATABASE_URL|REDIS_URL|KAFKA|AMQP|S3_BUCKET|https://api\." --glob '!*.lock' -g '!node_modules'
From this, list: people/roles, external systems (payment, email, identity providers), containers (each runnable plus each datastore and broker), and the relationships between them with protocol. Ask the user about anything you cannot see in code (human users, upstream systems that call you).
Choose the tool
| Tool | Use when |
|---|---|
| Structurizr DSL | Several views of one model; you want views to stay consistent automatically |
Mermaid C4 (C4Context, C4Container) | Diagrams must render inline on GitHub/GitLab Markdown; one or two views |
| C4-PlantUML | Team already uses PlantUML |
Default: Structurizr DSL as the source of truth when there are three or more views; Mermaid when the diagram lives in a README. Do not maintain the same model by hand in two tools; export instead.
Structurizr DSL
One model, many views. Store as docs/architecture/workspace.dsl.
workspace "Shop" "Online shop architecture" {
!identifiers hierarchical
model {
customer = person "Customer" "Browses and buys products"
stripe = softwareSystem "Stripe" "Card payments" {
tags "External"
}
email = softwareSystem "Postmark" "Transactional email" {
tags "External"
}
shop = softwareSystem "Shop" "Lets customers buy products online" {
web = container "Storefront" "Server-rendered product pages and checkout" "Next.js"
api = container "Orders API" "Places orders, tracks fulfilment" "Go"
worker = container "Order Worker" "Sends confirmations, syncs stock" "Go"
db = container "Orders DB" "Orders, line items, outbox" "PostgreSQL" {
tags "Database"
}
queue = container "Order Events" "Order lifecycle events" "Amazon SQS" {
tags "Queue"
}
}
customer -> shop.web "Browses and checks out using" "HTTPS"
shop.web -> shop.api "Places orders via" "JSON/HTTPS"
shop.api -> shop.db "Reads and writes" "SQL/TLS"
shop.api -> stripe "Creates payment intents" "HTTPS"
shop.api -> shop.queue "Publishes OrderPlaced to" "SQS"
shop.worker -> shop.queue "Consumes events from" "SQS"
shop.worker -> email "Sends order emails via" "HTTPS"
}
views {
systemContext shop "context" {
include *
autolayout lr
}
container shop "containers" {
include *
autolayout lr
}
dynamic shop "checkout" "Placing an order" {
customer -> shop.web "Submits checkout form"
shop.web -> shop.api "POST /orders"
shop.api -> stripe "Create payment intent"
shop.api -> shop.db "Insert order + outbox row"
autolayout lr
}
styles {
element "Person" {
shape person
}
element "Database" {
shape cylinder
}
element "Queue" {
shape pipe
}
element "External" {
background #8a8a8a
color #ffffff
}
}
theme default
}
}
Render and export (needs Docker or Java, and network to pull images on first use):
# Local browser view of the workspace in the current folder
docker run -it --rm -p 8080:8080 -v "$PWD/docs/architecture:/usr/local/structurizr" structurizr/lite
# Export views to Mermaid or PlantUML text for docs that cannot embed Structurizr
docker run --rm -v "$PWD/docs/architecture:/usr/local/structurizr" structurizr/cli \
export -workspace /usr/local/structurizr/workspace.dsl -format mermaid
Structurizr has been consolidating its Lite, CLI and server products into one tool during 2025-2026; if these image names fail, check docs.structurizr.com for the current packaging rather than guessing flags.
Mermaid C4
Renders natively in GitHub Markdown. Mermaid’s C4 support is marked experimental: keep diagrams small and avoid styling beyond the basics.
```mermaid
C4Container
title Container diagram: Shop
Person(customer, "Customer", "Browses and buys products")
System_Ext(stripe, "Stripe", "Card payments")
System_Boundary(shop, "Shop") {
Container(web, "Storefront", "Next.js", "Product pages and checkout")
Container(api, "Orders API", "Go", "Places orders, tracks fulfilment")
ContainerDb(db, "Orders DB", "PostgreSQL", "Orders, line items, outbox")
ContainerQueue(queue, "Order Events", "Amazon SQS", "Order lifecycle events")
}
Rel(customer, web, "Checks out using", "HTTPS")
Rel(web, api, "Places orders via", "JSON/HTTPS")
Rel(api, db, "Reads and writes", "SQL")
Rel(api, stripe, "Creates payment intents", "HTTPS")
Rel(api, queue, "Publishes OrderPlaced to", "SQS")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
```
Use C4Context with Person, System, System_Ext for level 1, and C4Component
with Component inside a Container_Boundary for level 3.
Notation rules
- Every element: name, type/technology (for containers and components), one-line responsibility. “Orders API [Go] - Places orders, tracks fulfilment”, not “Backend”.
- Every relationship: a verb phrase from the source’s point of view plus the protocol. Unlabelled arrows are the most common C4 defect.
- Prefer one-directional arrows showing the dependency or data flow; say which in the legend.
- External systems are visibly different (grey) and outside the system boundary.
- Keep a diagram to roughly 15-20 elements. Beyond that, split by subsystem or flow.
- Title every view with level and scope: “Container diagram: Shop”.
- Queues and topics are containers, not arrows; show who publishes and who consumes.
Workflow
- [ ] 1. Identify audience and the question each diagram answers
- [ ] 2. Discover people, external systems, containers and relationships from the repo
- [ ] 3. Confirm unknowns with the user (human actors, upstream callers)
- [ ] 4. Write the model once (Structurizr) or the single view (Mermaid)
- [ ] 5. Render it; check layout, labels and the 15-20 element budget
- [ ] 6. Commit next to the code; link from README or AGENTS.md
Gotchas
- Mixing levels in one diagram (a class next to a database next to an external SaaS) makes it unreadable. One level per view.
- Drawing the intended architecture as if it were current. Label target-state diagrams “Proposed” in the title and keep the current-state one too.
- Shared libraries are not containers. Show them, if at all, as components.
- A database shared by two services must appear once with both arrows to it; that coupling is exactly what the diagram should reveal.
- Autolayout produces crossings on dense views; reduce elements before hand-tuning positions, which then rot.
Verification
- Every container in the diagram maps to a deployable in the repo or infra code, and every deployable appears in the diagram (or is deliberately excluded with a note).
- Every arrow has a label and protocol; every element has a description.
- The DSL or Mermaid source renders without errors (Structurizr view or GitHub preview).
- A teammate unfamiliar with the system can explain the main request path from the container diagram alone.
Output contract
**Files:** docs/architecture/workspace.dsl (context, containers, checkout dynamic view)
**Embedded:** README.md "Architecture" section (Mermaid export of the container view)
**Sources used:** docker-compose.yml, infra/terraform/*.tf, services/*/main.go
**Assumed / to confirm:** <actors or flows not visible in code> What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "C4 Architecture Diagrams"
short_description: "Context, container and component views as code"
default_prompt: "$c4-architecture-diagrams Draw a C4 context and container diagram for this repo in Structurizr DSL" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.