From c4-skills
Create and evolve C4 architecture models with proper abstractions, diagram types, and notation. Use when adding elements to a C4 model, choosing diagram types, modeling relationships, or making architecture modeling decisions.
How this skill is triggered — by the user, by Claude, or both
Slash command
/c4-skills:c4-modelThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Create and evolve C4 architecture models with correct abstractions, diagram types, and notation.
Create and evolve C4 architecture models with correct abstractions, diagram types, and notation.
The C4 model defines four levels of abstraction. Each has a precise meaning — do not conflate them.
| Diagram | Scope | Shows | Audience | Recommended? |
|---|---|---|---|---|
| System Context | One software system | System + users + external systems | Everyone | Yes, always |
| Container | One software system | Containers inside the system | Technical staff | Yes, always |
| Component | One container | Components inside the container | Developers | Only if valuable |
| Code | One component | Classes/modules/tables | Developers | No, generate if needed |
| Diagram | Scope | Shows | When to Use |
|---|---|---|---|
| System Landscape | Enterprise/org | All systems and their connections | Large organizations, enterprise views |
| Dynamic | Feature/use case | Runtime interactions with numbered sequence | Complex interaction flows, specific scenarios |
| Deployment | One+ systems in one environment | Infrastructure, nodes, deployed instances | Infrastructure documentation, ops audience |
"Who is the audience?"
"What question does the diagram answer?"
Every C4 diagram must follow these rules:
Before adding anything, determine what you're modeling:
For each new element, determine:
For each relationship:
includestructurizr/structurizrSplit when:
Do NOT split when:
Add components when:
Skip components when:
Model as external software system when:
Model as a container within your system when:
The BEAM runtime has unique characteristics that affect C4 modeling decisions.
| OTP Concept | C4 Abstraction | Rationale |
|---|---|---|
| OTP Release | Container | A release is a standalone, deployable BEAM instance |
| OTP Application | Component | An application runs within a release, not separately |
| Umbrella app (single release) | Component per app | All apps share one BEAM VM, one deployment unit |
| Umbrella app (separate releases) | Container per release | Each release is a separate runtime boundary |
| GenServer / Agent | Code | Implementation detail, not architecturally significant |
| Supervisor tree | Code | Internal structure of an OTP application |
| Phoenix Endpoint | Component | The HTTP/WebSocket entry point within the release |
| Phoenix LiveView | Component or Container | Container if it's a separately served SPA; component if part of the Phoenix app |
| Ecto Repo | Component | Data access layer within the release |
| Oban | Component or Container | Component if embedded in the release; container if deployed as a separate worker release |
| Broadway | Component | A data pipeline within the release |
| Ash Domain | Component | A domain boundary grouping related resources |
| Ash Resource | Code | An individual resource within an Ash domain |
| Phoenix PubSub | Code | Internal messaging mechanism, not a separate container |
| Erlang Distribution | Relationship technology | Communication between BEAM nodes, label on deployment relationships |
| Mnesia / ETS | Code or Container | ETS is in-process (code); Mnesia across nodes could be modeled as a data store container if architecturally significant |
| Nerves firmware | Container | A deployed runtime on embedded hardware |
GenServers are NOT containers. A GenServer is a process within the BEAM VM. It doesn't have its own deployment boundary. It's a code-level construct — analogous to a class instance in OOP. Only model a GenServer as a component if it represents an architecturally significant subsystem (e.g., a connection pool, a rate limiter, a state machine for a core domain concept).
Supervisor trees are NOT components. They're an implementation mechanism for fault tolerance. The C4 component level should model functional groupings ("Authentication", "Order Processing"), not supervision hierarchies.
One release = one container. Even if a release contains multiple OTP applications, it's one container in C4 because it deploys as a single unit. Use components to show the internal applications if that structure matters.
LiveView can go either way. If Phoenix serves LiveView from the same endpoint, LiveView is a component within the Phoenix container. If you want to emphasize that LiveView provides a distinct real-time UI separate from traditional request/response, you can model it as a separate container — the key question is whether your audience needs to see them as separate building blocks.
Oban workers: embedded or separate? If Oban runs within your main Phoenix release (the common case), it's a component. If you deploy a separate release specifically for background job processing (e.g., a worker-only release), it's a separate container.
Ash domains are components, not containers. An Ash domain groups related resources and defines their API. It runs within the same BEAM process as everything else — it's a logical boundary, not a runtime one. Model each Ash domain as a component. Individual Ash resources are code-level constructs (like classes) and shouldn't appear in C4 diagrams. When using Ash, domains replace Phoenix contexts as the natural component grouping.
Ash and data access. With Ash, the application talks to the database through Ash's data layer, not directly through Ecto queries. The relationship from your container to the database should still say "reads from and writes to" with technology "Ash/Ecto/TCP" or simply "Ecto/TCP" — Ash wraps Ecto but the wire protocol is the same.
Typical Phoenix application:
Phoenix with real-time features:
Event-driven Elixir system:
Nerves IoT system:
When modeling the internals of a Phoenix release:
With Phoenix contexts:
| Component | Description | Technology |
|---|---|---|
| Web | HTTP endpoint, controllers, LiveView | Phoenix |
| API | REST/GraphQL API | Phoenix |
| Accounts | User authentication and authorization | Elixir |
| Core | Business logic and domain | Elixir |
| Workers | Background job processing | Oban |
| Ingestion | Data pipeline and ETL | Broadway |
| Notifications | Email, SMS, push notifications | Swoosh |
| Repo | Data access and queries | Ecto |
With Ash Framework:
| Component | Description | Technology |
|---|---|---|
| Web | HTTP endpoint, controllers, LiveView | Phoenix |
| API | REST/GraphQL API | AshJsonApi / AshGraphql |
| Accounts | User identity, authentication, authorization | Ash Domain |
| Helpdesk | Tickets, assignments, SLAs | Ash Domain |
| Notifications | Email, SMS, push notifications | Ash Domain / Swoosh |
| Workers | Background job processing | Oban |
With Ash, domains replace Phoenix contexts as the component grouping. The Repo/data-access component disappears — Ash resources handle persistence internally through the Ash data layer.
Use specific labels, not "uses":
| From → To | Good Label | Technology |
|---|---|---|
| User → Phoenix | "browses and interacts with" | "HTTPS, WebSocket" |
| Phoenix → Database | "reads from and writes to" | "Ecto/TCP" |
| Phoenix → Redis | "caches sessions in" | "Redix/TCP" |
| Phoenix → Queue | "publishes domain events to" | "AMQP" |
| Worker → Queue | "consumes jobs from" | "AMQP" or "Oban/PostgreSQL" |
| Phoenix → External API | "fetches exchange rates from" | "HTTP/JSON" |
| LiveView → Phoenix | "connects via" | "WebSocket" |
| Node A → Node B | "replicates state via" | "Erlang Distribution" |
| Level | Change Rate | Maintenance Effort |
|---|---|---|
| System Context | Slow | Low — create and maintain |
| Container | Moderate | Low — create and maintain |
| Component | Fast during development | Medium — create only if valuable |
| Code | Very fast | None — generate on demand, don't maintain |
structurizr-dsl — DSL syntax for implementing modelsc4-review — Review models for correctnessc4-deployment — Model deployment environmentsProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub jrjsmrtn/jrjsmrtn-skills --plugin c4-skills