Container-Based Layered Diagram Skill (C4 Container Implementation · D2)
This skill is for drawing
container-based layered diagrams (diagrams with the structure of "large containers nesting small containers, multi-level vertical nesting").
D2 is the implementation method (
d2lang.com).
This SKILL.md is a
router — read it for main workflow, iron rules, and triage; refer to documents under
as needed (see
§4 References Routing Table).
1. What to Draw: C4 Container Diagram (Align Objectives First)
1.1 Definition: What is a Container-Based Layered Diagram (Including C4 Container)
This skill draws "container-based layered diagrams" — diagrams with large containers nesting small containers, multi-level vertical nesting, and sub-containers distributed with equal width in each layer. The most typical form is the C4 model Container Diagram (the 2nd layer diagram in c4model.com standard), but its scope is broader:
- C4 model Container Diagram: Shows what containers a software system consists of (Official C4 definition: "A container represents an application or data store... The container diagram shows the high-level technology choices and how the containers communicate with one another.").
- Technical architecture diagrams / product architecture diagrams / business capability layered diagrams / microservice architecture diagrams: Any diagram that fits the form of "multi-level vertical nesting of large containers + sub-container distribution" is applicable to this skill.
Out of scope (see complete list in frontmatter description): Flowcharts, sequence diagrams, ER diagrams, UML class diagrams, C4 Component/Code layers.
Key concepts:
- Container = An independently divisible unit in the diagram (application, service, data storage, business module, etc.), not Docker container.
- Container-based layered diagram = Zoom in on a system/product/business to show "what containers it consists of + how containers communicate with each other".
For the 9 characteristic requirements, feature-to-syntax mapping, dynamic padding calculation, and layered specifications (color/spacing/shape/rounded corner/color scheme), see references/c4-container-spec.md.
1.2 Align with Iron Rules (Highest Priority)
The following iron rules are the final effect standards — any syntax or template must comply. Self-check against them after generation; if not met =不合格, must adjust.
Iron Rule 1 (Boundary): The four edges (top, bottom, left, right) of any sub-container must not exceed the boundary of its parent container. Check one by one after rendering: the leftmost/rightmost/topmost/bottommost of the sub-container ≤ the corresponding boundary of the parent container.
Iron Rule 2 (Symmetry): The distance from sub-containers to the left and right borders of the parent container must be equal (horizontally centered) — this is a hard requirement that all containers must meet. Vertical direction: Only require even distribution (relying on sub-container height formula, see references/layout-and-grid.md) in the scenario of single-column containers (vertical bar/label column, grid-columns:1); no vertical centering requirement for multi-row/multi-column containers (ordinary layer containers) (D2/ELK grid forces equal column height, sub-containers are aligned to the top, vertical centering is physically impossible). "Sticking to the top" is allowed, but "sticking to the left but not the right" is not.
Iron Rule 3 (Uniformity): Sub-containers in the same layer/same container must have equal width and height, consistent spacing, and be evenly distributed visually.
Iron Rule 4 (Complete Text): All labels must be displayed completely, without truncation or overflow beyond the sub-container boundary.
Iron Rule 5 (Alignment): The left boundaries of each layer of containers must be aligned, and their widths must be consistent; vertical bars/label columns must be visually coordinated with the main body.
1.3 Core Methodology (DSL Guarantees from the Source)
D2 is a declarative DSL — every requirement can be guaranteed by syntax from the source, no need to "draw first then check for errors". When generating code, ensure that the syntax naturally meets the requirements, and rendering is only for verification.
Calculate according to rules before writing code, let DSL syntax carry constraints: Symmetry/uniformity rely on the dimension formulas in references/layout-and-grid.md to calculate width/height first; boundaries rely on precise formulas (wrong calculation = inevitable overflow); rounded corners rely on attaching classes as specified in references/c4-container-spec.md §4.8; text relies on reference formulas + trade-off, see references/d2-syntax-cheatsheet.md; vertical uniformity only applies to single-column vertical bars (Iron Rule 2 in §1.2).
Position of self-check: Self-check (references/troubleshooting.md) is verification (confirming that the syntax is written correctly), not a repair method (modifying after finding errors). If problems are found during self-check, it means the above rules were not followed — go back to modify the writing method instead of applying temporary patches.
Generation Process (Follow this order every time you draw a diagram):
- Align structure (Steps 1-3 in §2 Workflow)
- Calculate the width/height of all sub-containers using the formulas in references/layout-and-grid.md (every container, every partition, every sub-module)
- Attach rounded corner classes to each node as specified in c4-container-spec.md §4.8
- Write code → render → self-check verification (should pass at one time)
2. Workflow (Triage → 5 Steps for New Diagrams / Modifications Follow §2.3)
2.1 Triage (First Thing When Entering the Skill: New vs Modify vs Read-Only)
Automatic judgment is default, asking users is only a fallback (only ask when it's really unclear). Core signal: Diagrams are carried by d2 code blocks in Markdown — users reference/point to a certain d2 code block = modify the diagram.
Automatic Judgment (Do Not Interrupt Users):
- User input points to an existing d2 block — provides location + diagram name ("the capability layered diagram in "), pastes the code block, or says "modify/adjust/update that diagram" → Modify Mode (§2.3 Workbench extract → modify → render → sync)
- User uses new diagram terms (draw/create/add a new diagram) and does not reference existing blocks → New Mode (complete all 5 steps in §2.2; if there is another diagram at the target location → insert a new block, do not touch the old diagram)
- User says redraw/override/regenerate a certain diagram → Modify Mode (replace the code block)
- User says "check/look at" → Read-Only Mode (acceptance via troubleshooting.md, no code modification)
Fallback (Only Ask Users When Information Is Insufficient):
- Unable to locate: User does not provide document path/cannot find any d2 block, and cannot clarify intent → ask "Where is the target document/diagram?"
- Multiple blocks do not match: The document has multiple d2 blocks, and the diagram name mentioned by the user does not match the first-line comment of any block → list the diagram names of each block for the user to choose ("The document contains: ① System Architecture Diagram ② Deployment Architecture Diagram... Which one to modify?")
- No location at all: Only says "draw a diagram" without any document clues → ask "Where to draw it?"
Information Collection (Locate by Diagram Name, Not Serial Number): Read the target document, extract the first-line comment (diagram name) of all ```d2 blocks, and perform semantic matching with the diagram name mentioned by the user (match if either Chinese or English matches). ⚠️ If the target diagram has no name (no first-line comment): First ask the user "Do you want to give it a name?" — can suggest a name based on the content of the diagram (e.g., "Application Architecture Diagram"), and add the name first before modifying after user confirmation, gradually converging to all diagrams in the document having identifiable names. Prohibit writing d2 code before completing triage (clear choice among the three).
Rendering Method: d2 code blocks are automatically rendered by the project Markdown rendering engine (embedded ```d2 is rendered). AI does not manually render SVG to files — all diagram outputs are in Markdown code blocks. Only temporarily render SVG with scripts for verification during self-check (see references/troubleshooting.md).
2.2 New Mode (5 Steps)
CRITICAL — BLOCKING (Blocking Requirement #1, Step 2): Before drawing an architecture diagram, must first align with the user on number of layers / modules in each layer / label style (top-centered vs left vertical arrangement). Prohibit writing d2 code before alignment.
CRITICAL — BLOCKING (Blocking Requirement #2, Step 3): Before writing the d2 code block, MUST first show the general structure of the diagram (number of layers + modules in each layer + connections between layers) to the user via an ASCII architecture diagram in the conversation. Prohibit writing d2 code before user confirmation. (See references/templates.md for ASCII diagram elements)
- Locate the target Markdown document: Confirm the insertion position (new) or target code block (modify). Prohibit writing d2 code before confirming the target document
- Align architecture diagram parameters (Mandatory, Blocking #1): Confirm with the user: ① Number of layers (usually 3~6 layers); ② Module names in each layer (users will list each product/service/capability name — must use real business labels, prohibit placeholders such as e1/e2/c1/c2, placeholders only appear in skill template examples); ③ Label style (top-centered = mainstream / left vertical arrangement = architect-style); ④ Color preference (default to the five layer systems of blue/purple/green/orange/gray, or user-specified); ⑤ Whether inter-layer arrows are needed (default to implicit dependency via stacking; when arrows are needed, only connect between layer containers, parent to parent, see references/connection-routing.md)
- ASCII Architecture Confirmation (Mandatory, Blocking #2): Directly output an ASCII architecture diagram (number of layers + modules in each layer + connections between layers + label position) in a code block in the conversation, and wait for the user's explicit confirmation. If the user proposes modifications, update the ASCII diagram and confirm again. (See references/templates.md)
- Write/modify the code block in the target document: Write the diagram name comment in the first line () — this is the identifier of the diagram, and subsequent location/modification relies on semantic matching (§2.1), prohibit omission. Format is not limited: Chinese is preferred (e.g.,
# System Architecture Diagram
), subject to user preference, both Chinese and English are acceptable (e.g., ) — the key is to have an identifiable name. Start the second line with vars: { d2-config: { layout-engine: elk } }
(default elk), and you can continue to write meta-information comments such as perspective/purpose. After writing, rendering is automatically completed by the Markdown engine, AI does not perform any output/rendering actions
- Self-check: Use one command from §2.3 Workbench (automatically verify viewBox/overflow/equal width/rounded corners) — for new diagrams:
extract docs.md --name Diagram Name
to extract the newly written block for verification (no sync needed); for modifications to existing diagrams: . Use the manual process in troubleshooting.md only when the workbench is unavailable.
Completion Criteria: The
code block in the target Markdown document has been written/updated; the
script passes the verification; the rendering result is consistent with the ASCII architecture confirmed in Step 3.
2.3 Modify Mode (Adjust Existing Diagrams, ≠ Redraw)
Objective: Modify diagrams quickly from the second time (3~5 minutes each time), not rewrite the entire diagram. Core principle:
Authoritative source = Markdown code block, always modify the original document content when changing code (keep
literals); temporary .d2 files are read-only for verification,
prohibit "modifying temporary files then copying back" to cause duplicate maintenance. If the target block has no diagram name (no first-line comment): First ask the user to add a name (can suggest), add it before modifying — make all diagrams identifiable (§2.1).
Recommended Workflow (Workbench Script, One-Command Closed Loop):
bash
# 1. Extract: Semantic matching by diagram name (first-line comment) or diagram serial number → workspace .d2/.svg/.png + verification
# (without parameters, it will list the diagram names of all d2 blocks in the document)
python3 scripts/d2-workbench.py extract docs.md --name "System Architecture Diagram"
python3 scripts/d2-workbench.py extract docs.md 1 --out . # or by serial number
# 2. Iterate modification: Edit workspace .d2 (modify label/add container/adjust width) → render + verify
python3 scripts/d2-workbench.py render docs-fig1.d2
# 3. Write back: Sync workspace .d2 back to md (replace original code block; see troubleshooting.md §7.4 for fallback semantics)
python3 scripts/d2-workbench.py sync docs.md docs-fig1.d2 --name "System Architecture Diagram"
python3 scripts/d2-workbench.py sync docs.md docs-fig1.d2 1 # or by serial number
# Explicit fallback when needed: sync docs.md docs-fig1.d2 --fallback=img ; cleanup: clean-fallback docs.md
Partial Modification Rules (Only Modify the Relevant Part):
- ⚠️ Modify Mode Exempts Blocking #1/#2 in §2.2: Alignment parameters (Blocking #1) and ASCII confirmation (Blocking #2) only need to be re-executed when the structure changes (adding layers/changing column count/moving modules); directly modify for pure label/width/color/arrow adjustments, and verify the closed loop with workbench commands after modification
- ⚠️ Modification = Replace the target code block in place, prohibit adding a second d2 block (high-frequency mistake: insert new content next to the original when modifying, resulting in two diagrams in the document). After modification, must confirm that the number of d2 blocks at the target location remains unchanged — naturally guaranteed by workbench sync (only replaces the Nth block + block count consistency assertion, aborts with error if blocks are added/deleted); count the number of after manual Markdown editing
- Only recalculate the width of the modified layer (formula in references/layout-and-grid.md): Keep the original values for unchanged layers/containers, do not recalculate the entire diagram for "consistency" — only modify the label when changing the label, only modify the color when changing the color
- Check for edges with the same semantics before adding containers/layers (avoid duplicate edges), remember to set for new containers (c4-container-spec.md §4.8)
- Literal Iron Rule: Write (two characters: backslash + n) for line breaks in labels, prohibit actual line breaks; prohibit /unquoted heredoc/Python string concatenation when writing .d2 with scripts (see references/d2-syntax-cheatsheet.md) — workbench scripts naturally avoid this (direct file IO writing)
3. ASCII Architecture Confirmation (Mandatory Before Drawing)
Purpose: Align the general structure of the diagram (number of layers + modules in each layer + connections between layers + label position) with the user before writing the d2 code block, avoiding rework due to inconsistencies after writing.
Practice: After understanding the user's requirements, directly output an ASCII architecture diagram (number of layers + module names in each layer + label position + connections between layers) in a
code block in the conversation, briefly describe key decisions (diagram type / engine / color / label style), and ask "The architecture is as above, shall I start writing the d2 code after confirmation? Or need adjustments?"
See references/templates.md for the ASCII architecture diagram element list + complete examples, and confirmation protocol. Prohibit writing d2 code or calling rendering commands before the user's explicit confirmation (blocking requirement).
4. References Routing Table (What You Need to Do → Which File to Read)
| What You Need to Do | Read This |
|---|
| 9 characteristics / feature-to-syntax mapping / Padding / layered specifications (color·spacing·shape·rounded corner·color scheme) | references/c4-container-spec.md |
| Dimension formulas / width·height calculation / grid·layout·equal width / no width setting for vertical bars | references/layout-and-grid.md |
| Inter-layer arrows / bidirectional arrows (parent to parent·complete path) | references/connection-routing.md |
| D2 syntax pitfalls / engine selection / multi-board·TALA prohibition / viewBox overflow / line breaks / long labels | references/d2-syntax-cheatsheet.md |
| Pre/post-generation self-check process, SVG coordinate verification, acceptance execution, fallback, CLI quick reference | references/troubleshooting.md |
| ASCII elements / tested templates (3-layer standard·vertical arrangement·vertical bar·intra-layer partition·minimal skeleton) | references/templates.md |
| Basic connection syntax (edge type/label/chain/arrow style) | references/connections.md |
| Grid layout examples / container forms / ELK engine / post-rendering review checklist | references/grid-diagrams.md · containers.md · elk.md · diagram-review.md |
is a
project-specific post-rendering organization review checklist; other
connections/containers/elk/grid-diagrams
are localized D2 official documents.
5. Iron Rule Quick Reference (Non-Negotiable Red Lines, Must Follow When Drawing/Modifying Diagrams)
Each of the following is a red line, must adjust to comply if violated. See corresponding references for detailed rules.
- Explicit width calculation for each layer: For each layer of nesting (A→B→C→D), explicitly calculate the width of sub-containers (references/layout-and-grid.md); the only exception: single-column vertical bars do not require setting width, let ELK automatically wrap and center them. Calculating only the outermost layer will cause "left-aligned offset".
- Parent-to-parent arrows: Inter-layer arrows only connect between parent layer containers (
Overall Architecture.Layer A -> Overall Architecture.Layer B
), do not connect sub-containers within layers; must write the complete path, otherwise d2 silently creates duplicate top-level nodes (references/connection-routing.md).
- Multi-board diagrams prohibited: multi-board syntax cannot be output by the Markdown rendering engine, split into multiple independent code blocks (references/d2-syntax-cheatsheet.md).
- TALA engine prohibited: TALA is closed-source and paid (free version has watermarks), use uniformly (d2-syntax-cheatsheet.md).
- viewBox integer overflow: Combination of multiple classes + deep nesting + vertical bars will trigger ELK int64 overflow (viewBox=-9e18 blank diagram). Must use single class + outer 1×1 grid + no width setting for vertical bars (d2-syntax-cheatsheet.md §6.16).
- Line Break Iron Rule: Write literal (two characters: backslash + n) for line breaks in labels, prohibit actual line breaks; long labels (>8 characters) must be split with into lines with ≤8 characters each (d2-syntax-cheatsheet.md §6.17).
- Global rounded rectangles: Every graphic (outer layer/layer/partition/innermost sub-module/vertical bar) must have rounded corners (c4-container-spec.md §4.8).
6. Self-Check (One-Command Closed Loop)
Use one command from the workbench script (automatically verify viewBox/overflow/equal width/rounded corners), see references/troubleshooting.md for detailed process.
bash
# Extract d2 block from md → workspace .d2/.svg/.png + automatic verification (preferred for modification)
python3 scripts/d2-workbench.py extract docs.md --name "System Architecture Diagram"
# Iterate modification
python3 scripts/d2-workbench.py render docs-fig1.d2
# Write back to md (replace original code block, automatically perform round-trip verification and prevent multiple diagrams)
python3 scripts/d2-workbench.py sync docs.md docs-fig1.d2 --name "System Architecture Diagram"
When the workbench is unavailable, use the manual process in troubleshooting.md §7.2 (
→ render →
).
Authoritative acceptance script:
python3 scripts/verify-svg.py out.svg
(judges overflow/equal width/rounded corners, outputs PASS/FAIL + values).
7. CLI Quick Reference (For Self-Check, SVG Only)
bash
d2 in.d2 out.svg # Render to SVG (default)
d2 in.d2 out.svg --layout=elk # Specify layout (default elk is already written in vars)
d2 validate in.d2 # Syntax verification (no file output)
d2 fmt --check in.d2 # Format check
d2 --theme=0 in.d2 out.svg # Theme: 0 Neutral Default / 200 Dark Mauve
8. Short Example (Minimal 3-Layer Skeleton)
Complete templates (3-layer standard/vertical arrangement/vertical bar/intra-layer partition) are available in references/templates.md.
d2
# Minimal Architecture Diagram
vars: { d2-config: { layout-engine: elk } }
Overall Architecture: {
grid-rows: 1
grid-columns: 1
grid-gap: 24
Entry Layer: {
width: 1000; grid-columns: 3; grid-gap: 12; class: module
h1: { width: 317; height: 60; class: module }
h2: { width: 317; height: 60; class: module }
h3: { width: 317; height: 60; class: module }
}
Business Layer: {
width: 1000; grid-columns: 2; grid-gap: 12; class: module
b1: { width: 482; height: 60; class: module }
b2: { width: 482; height: 60; class: module }
}
Support Layer: {
width: 1000; grid-columns: 2; grid-gap: 12; class: module
s1: { width: 482; height: 60; class: module }
s2: { width: 482; height: 60; class: module }
}
}