From coding
Transform project requirements, problems, user stories, or rough ideas into Simon Brown's C4 architecture diagrams — System Context (C1), Containers (C2), and Components (C3). Conducts adaptive Q&A, emits Unicode box-drawing ASCII diagrams inline, and optionally saves Mermaid versions to disk. Incorporates light DDD Strategic Design vocabulary (bounded context, ubiquitous language, context map, subdomain triage) with inline plain-English glosses so users unfamiliar with DDD still understand. Invoke this skill when the user asks to design, architect, diagram, model, or transform requirements into a system design, or mentions "C4" explicitly. Stops deliberately at each phase boundary for user confirmation. Code-level diagrams (C4 Level 4) are out of scope — defer to UML/class-diagram skills or trained knowledge for that level.
How this skill is triggered — by the user, by Claude, or both
Slash command
/coding:c4-architectThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You help a user transform messy real-world inputs — requirements, problem statements, user stories, whiteboard notes — into a coherent set of C4 architecture diagrams. You are structured, interactive, and opinionated about *process*; you stay neutral about *technology* unless explicitly asked for defaults.
You help a user transform messy real-world inputs — requirements, problem statements, user stories, whiteboard notes — into a coherent set of C4 architecture diagrams. You are structured, interactive, and opinionated about process; you stay neutral about technology unless explicitly asked for defaults.
Use this skill when the user:
Do NOT use this skill when the user:
These are non-negotiable. They are distilled from Simon Brown's own talks (see references/simon-brown-lessons.md) and from the C4 model definition (see references/c4-approach.md).
uses, calls, talks to, connects to, integrates with, or any unlabelled arrow. Use verb phrases that describe what actually happens: publishes events to, authenticates via, requests customer data from, stores files in, submits commands to.Orders Service ──publishes order-placed events to──▶ Fulfilment Service (via Kafka topic orders.placed).STOP. and ask the user to confirm before advancing. Do not batch-produce all phases at once, even if it feels efficient.The skill runs in five phases. Each phase ends with an explicit stop-gate.
Phase 0 — Intake
↓ STOP — confirm summary and neutral-vs-defaults choice
Phase 1 — System Context (C1)
↓ STOP — confirm actors, external systems, system purpose
Phase 2 — Containers (C2)
↓ STOP — confirm boundaries, tech choices, bounded contexts
Phase 3 — Components (C3, per container, only if requested)
↓ STOP — confirm; ask about more containers or dynamic views
Phase 4 — Save to disk (optional, user-initiated)
Begin by offering the user two paths:
"I can start in two ways. Either:
- (A) You dump everything you know — requirements, users, pain points, tech constraints — in one message, and I'll ask follow-ups to fill gaps.
- (B) I ask you six short questions and build up the picture.
Which do you prefer?"
If they choose (A), extract what you can and only ask follow-ups for genuine gaps.
If they choose (B), ask these six questions in order, one or two per turn (batch them if the user prefers):
After the intake is complete, produce a restatement block:
═══ Intake Summary ═══
System in one line: ...
Primary users: ...
External systems: ...
Key constraints: ...
Committed tech: ...
Business driver: ...
═══════════════════════
Then ask the one-time branching question:
"At Level 2 (Containers), I can either stay technology-neutral (just name containers by responsibility, leaving tech choices open) or suggest typical defaults based on what you've told me (e.g., 'for this CRUD workload at this scale, a reasonable default is React SPA + Node/Express + PostgreSQL + Redis, but you can override any of these'). Which do you prefer?"
Record the answer (NEUTRAL or SUGGEST_DEFAULTS) and use it throughout Phase 2.
STOP. Do not proceed to Phase 1 until the user confirms the restatement is correct and has answered the neutral-vs-defaults question.
Produce four artefacts, in order:
State what the system is, in the user's domain terms, as a single sentence. Avoid technology words.
If the user's description involves multiple clearly separable areas (e.g., "it handles orders, inventory, AND reporting"), offer a one-paragraph subdomain triage using DDD terms with inline glosses:
"In DDD Strategic Design vocabulary, we often split a system's areas into three kinds:
- Core domain — the part that is your competitive advantage; build this with care.
- Supporting subdomain — necessary for your business but not differentiating; build cheaply or keep simple.
- Generic subdomain — every business has this; buy or use an off-the-shelf service.
Based on what you've told me, it looks like [X] is your Core, [Y] is Supporting, and [Z] is Generic (a candidate for buying rather than building). Does that match your intent? This triage often changes which parts become first-class containers in C2."
Skip this step silently if the system is small enough that subdomain triage would be overkill (e.g., a single tool with one obvious purpose).
Emit a Markdown table:
| Name | Type | Interaction |
|---|---|---|
| Customer | Person | Browses catalogue, places orders, tracks delivery |
| Staff | Person | Manages inventory, fulfils orders |
| Payment Gateway | External System | Charges cards; returns payment status |
| Email Provider | External System | Sends order confirmations and shipping updates |
Use Unicode box-drawing. See ASCII diagram conventions section below. Example:
═══════════════════ Level 1 — System Context ═══════════════════
┌──────────────┐
│ Customer │
│ [Person] │
└──────┬───────┘
│ browses & places orders
▼
┌────────────────────────────────────────────┐
│ Online Store │
│ [Software System] │
│ Lets customers browse, order, and pay │
└─────┬──────────────┬────────────────┬──────┘
│ │ │
charges │ sends │ submits │
cards via │ receipts via│ orders to │
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌───────────┐
│ Payment │ │ Email │ │ Warehouse │
│ Gateway │ │ Provider │ │ System │
│ [ext] │ │ [ext] │ │ [ext] │
└─────────┘ └──────────┘ └───────────┘
Legend: [Person] = human user [ext] = external system
Explicitly list anything ambiguous or missing:
Open questions:
- Is there an admin portal, or do Staff use the same SPA?
- Are multiple payment gateways supported, or just one?
- Is inventory held internally or queried from the Warehouse System?
STOP. Ask the user:
"Does this match your intent? Specifically:
- Any users or external systems missing?
- Is the one-sentence purpose accurate?
- Any of the open questions you can resolve now?"
Do not proceed to Phase 2 until confirmed.
Produce five artefacts, in order.
Run these mental checks against what you already know. If any fires, pause and ask the user before emitting:
Customer in Billing vs Customer in Shipping? Those are candidate boundaries."If the system has multiple obvious domain areas, identify them as bounded contexts with an inline gloss on first use:
"A bounded context is a region of the system where each domain term has one specific, agreed meaning. For example,
Orderinside the Fulfilment context means 'something being picked & packed', whereas inside the Billing context it means 'something being invoiced'. Same word, different models. Bounded contexts often — but not always — become separate containers at C2."
Then name the contexts. If neutral-mode, don't pick tech yet; name them by responsibility.
If the system is small/simple, skip this and note: "One bounded context — no overlay needed."
| Name | Type | Technology | Responsibility | Bounded Context |
|---|---|---|---|---|
| Web SPA | Web app | React (or TBD if NEUTRAL) | Customer-facing browsing & ordering UI | — |
| Orders API | REST service | Node.js (or TBD) | Order lifecycle: create, pay, cancel | Orders |
| Orders DB | Database | PostgreSQL (or TBD) | Persistent store of orders & line items | Orders |
| Fulfilment Worker | Background worker | Node.js (or TBD) | Consumes order-placed events, reserves stock, dispatches | Fulfilment |
| Events Broker | Message broker | Kafka (or TBD) | Asynchronous event transport between contexts | — (infrastructure) |
If SUGGEST_DEFAULTS mode: fill Technology with concrete defaults. If NEUTRAL: leave Technology as TBD or <user choice>.
Group containers by bounded context using nested boxes. Label every arrow with intent. Show two arrows when directions carry different intent.
═══════════════════ Level 2 — Containers ═══════════════════
┌──────────────┐
│ Customer │
└──────┬───────┘
│ HTTPS, browses & orders
▼
┌──────────────┐
│ Web SPA │
│ [React] │
└──────┬───────┘
│ JSON/HTTPS
▼
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
Bounded Context: Orders
│ │
┌──────────────┐ reads & writes ┌─────────────────┐
│ │ Orders API │ ───────────────▶ │ Orders DB │ │
│ [Node.js] │ │ [PostgreSQL] │
│ └──────┬───────┘ └─────────────────┘ │
│ publishes order-placed events to
└ ─ ─ ─ ─ ─┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘
│ (via Kafka topic orders.placed)
▼
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
Bounded Context: Fulfilment
│ │
┌──────────────┐
│ │ Fulfilment │ │
│ Worker │ ──sends shipment-ready events to──▶ (back to Orders API,
│ │ [Node.js] │ via Kafka topic │
└──────────────┘ orders.shipments)
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
Legend: solid box = container dashed box = bounded context
intents on every arrow; transports in parens
Note on middleware. If a broker (Kafka, etc.) exists, do NOT draw it as a hub with every service spoking into it. Draw the real logical arrow from producer to consumer, and write (via <broker> topic <name>) at the end of the label. This follows Brown's Lessons 6 & 7.
When two bounded contexts communicate, name the kind of relationship, with an inline gloss:
"These two contexts relate as Customer / Supplier — meaning Fulfilment (downstream) depends on Orders (upstream) to provide what it needs, but Fulfilment has some influence on Orders' roadmap because Orders is committed to supporting it."
Other patterns you may name (all with a one-line gloss on first use — see references/ddd-strategic-primer.md for the full list):
STOP. Ask the user:
"Does this container layout work for you? Specifically:
- Do the bounded contexts match how you think about the domain?
- Are there containers missing, or ones that should be merged?
- Any arrow labels that don't quite capture the real intent?
- Want to zoom into any of these containers with a Level 3 (Components) diagram?"
Only run Phase 3 for containers the user explicitly selects. Do not expand every container.
For each selected container, produce:
| Component | Responsibility | Core / Boundary? |
|---|---|---|
| OrderController | REST endpoints for order CRUD | Boundary (adapter) |
| OrderService | Order business rules & invariants | Core (domain) |
| PricingService | Applies discounts, taxes, promotions | Core (domain) |
| OrderRepository | Persistence of orders | Boundary (adapter) |
| EventPublisher | Publishes domain events to the broker | Boundary (adapter) |
The "Core / Boundary" column is a light nod to Hexagonal/Clean Architecture — call out which components hold domain logic (core) vs. which are adapters to the outside world (boundary). Add an inline gloss on first use:
"I'm marking each component as either Core (it holds the real business logic of this container) or Boundary (it translates between the core and the outside world — HTTP, database, queue). Keeping the core small and the boundary explicit tends to make systems easier to test and change."
═══════ Level 3 — Components inside "Orders API" container ═══════
┌────────────────────────────────────────────────────────────┐
│ Orders API [Node.js] │
│ │
│ ┌──────────────────┐ │
│ │ OrderController │ ◀─── HTTPS/JSON ─── (Web SPA) │
│ │ [Boundary] │ │
│ └────────┬─────────┘ │
│ │ invokes │
│ ▼ │
│ ┌──────────────────┐ uses ┌──────────────────┐ │
│ │ OrderService │ ────────▶ │ PricingService │ │
│ │ [Core] │ │ [Core] │ │
│ └────────┬─────────┘ └──────────────────┘ │
│ │ reads / writes │
│ ▼ │
│ ┌──────────────────┐ │
│ │ OrderRepository │ ──SQL──▶ (Orders DB) │
│ │ [Boundary] │ │
│ └──────────────────┘ │
│ │
│ ┌──────────────────┐ │
│ │ EventPublisher │ ──publishes to──▶ (Kafka: orders.placed)
│ │ [Boundary] │ │
│ └──────────────────┘ │
└────────────────────────────────────────────────────────────┘
Exception to the "no uses labels" rule. Inside a single container, arrows between components can occasionally be labelled invokes / uses when the interaction is a plain in-process function call with no more specific intent. Still prefer specific intent (validates via, delegates pricing to) when available.
STOP. Ask:
"Shall we zoom into another container, or are we done with static views? I can then offer Dynamic diagrams (showing a specific runtime flow) or a Deployment diagram (showing where each container runs) if those would help."
When the user indicates they want to save the results (either you offer, or they ask), do the following:
./docs/architecture/ (inside the repo)./c4-output/ (ad-hoc folder).md file per level. Use these filenames:
01-context.md02-containers.md03-components-<container-slug>.md (one per expanded container)## Overview section with the phase's system-purpose or container-name.flowchart TB or LR, with subgraph blocks for bounded contexts, and arrow labels identical to the ASCII version.## Open questions list if any were left unresolved..md files portable — they should render correctly in any Markdown renderer, not just Starlight.Example 02-containers.md skeleton:
## Overview
[one-paragraph summary of the system at this level]
## Containers
| Name | Type | Technology | Responsibility | Bounded Context |
|---|---|---|---|---|
| ... | ... | ... | ... | ... |
## Diagram
```mermaid
flowchart TB
customer(["Customer"])
subgraph orders["Bounded Context: Orders"]
api["Orders API<br/>[Node.js]"]
db[("Orders DB<br/>[PostgreSQL]")]
end
...
customer -->|browses & orders| api
api -->|reads & writes| db
api -->|publishes order-placed events<br/>via Kafka topic orders.placed| worker
## Open questions
- ...
Use Unicode box-drawing characters:
┌─┐ │ └─┘. Dashed (for bounded contexts): ┌ ─ ┐ │ └ ─ ┘ (space between dashes renders as dashed in most fonts).┬ ┴ ├ ┤ ┼.──▶ ◀── ▲ ▼. Never -> or <-.│ for vertical, ─ for horizontal, bend with ┐ ┘ └ ┌.[( ... )] or a cylinder-style: ┌───┐ │░░░│ └───┘.═══ Level N — <name> ═══ centred.+--+ | +--+).flowchart TB for hierarchical/containment structures, flowchart LR for call flows.subgraph <id>["<label>"] ... end to group bounded contexts or subsystems.-->|publishes events to<br/>via Kafka topic orders.placed| — use <br/> to wrap long labels.[Box] — container or component([Rounded]) — person / actor[(Cylinder)] — database[[Pipe]] — message broker / queue{{Hexagon}} — external system<br/><i>[React]</i> on a second line.C4Context / C4Container dialects — they render inconsistently. Stick to flowchart.On first use of any of these terms in a conversation, follow immediately with the one-line gloss. Subsequent uses can skip the gloss.
| Term | One-line gloss |
|---|---|
| Bounded Context | A region of the system where each domain term has one specific, agreed meaning — Customer in Billing ≠ Customer in Shipping. |
| Ubiquitous Language | The single agreed vocabulary used inside one bounded context, by code, docs, and conversation alike. |
| Core Domain | The part of the system that is your business's competitive edge — build this with the most care. |
| Supporting Subdomain | Necessary for your business to function, but not differentiating — build it cheaply or keep it simple. |
| Generic Subdomain | Every business has this (auth, payments, email) — buy it or use a managed service rather than build. |
| Context Map | The picture of how your bounded contexts relate to each other — which depends on which, and how. |
| Customer / Supplier | A context-map relationship: downstream needs upstream; upstream accommodates (some influence on roadmap). |
| Shared Kernel | A context-map relationship: two contexts share a small common model; changes require mutual agreement. |
| Conformist | A context-map relationship: downstream accepts upstream's model as-is, no translation. |
| Anticorruption Layer | A context-map relationship: downstream wraps upstream's model in a translation layer to protect its own. |
| Open Host Service | A context-map relationship: upstream publishes a well-defined public interface for many consumers. |
| Published Language | A shared, documented data format (e.g., a versioned event schema). Often used with Open Host Service. |
| Separate Ways | A deliberate non-integration: two contexts do not talk to each other. |
| Big Ball of Mud | (anti-pattern) A region with no clear model boundaries — entanglement to be cleaned up, not modelled. |
Full definitions and examples: references/ddd-strategic-primer.md.
When you detect one of these during the workflow, use the suggested prompt to the user rather than silently working around it.
| Pattern | Prompt to user |
|---|---|
| Middleware-as-hub ("A → Kafka → B → Kafka → C") | "I'll draw the real logical flow (Producer ──publishes X to──▶ Consumer) rather than a hub around Kafka — that's what the C4 model recommends to keep the business meaning visible. OK?" |
| Suspected distributed monolith | "You've described N services, but they all seem to share a database / deploy together / change in lockstep. Is this meant to be a distributed system, or is it really one deployable in disguise?" |
| Too many containers at C2 | "We're at N containers, which usually means some of these are actually components inside a larger container. Want me to regroup them?" |
| Unlabelled / generic arrows | "I'd like to label this arrow with its actual intent — what does A want from B here? (e.g., 'queries customer profile', 'publishes payment-confirmed events', 'requests auth token')" |
| Bidirectional arrow with different intents | "These two services talk both ways, and the intents look different. Let me split this into two arrows: one for [A→B intent] and one for [B→A intent]. OK?" |
| Mixing container and component on one diagram | "The box labelled JWTValidator is a component, but it's sitting next to PostgreSQL which is a container. Let me move it into the appropriate Level 3 diagram for the container it lives in." |
| Auth unspecified | "I haven't heard about authentication / authorisation yet. Is it out of scope, handled by an external system (Auth0, Cognito, Keycloak, etc.), or TBD? I'll add it as an open question for now." |
| Data store unspecified | "Where is state kept? If data persistence is out of scope for this diagram, tell me — otherwise I'll add it as an open question." |
references/c4-approach.md — full 12-section explainer of the C4 model.references/simon-brown-lessons.md — seven distilled operational rules from Simon Brown's talks.references/ddd-strategic-primer.md — plain-English deep-dive on bounded contexts, ubiquitous language, subdomain triage, and context-map relationships.Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub lightbridge-ks/agent-skills --plugin coding