AI Architecture Diagram Generation
Architecture diagrams become outdated almost immediately after creation: developers add new services, change interactions, but Confluence diagrams never get updated. AI diagram generation from code and infrastructure files solves the "living documentation" problem — diagrams are generated automatically on every change.
Generation from Codebase
from anthropic import Anthropic
from pathlib import Path
import ast
import re
import subprocess
client = Anthropic()
class ArchitectureDiagramGenerator:
def analyze_project_structure(self, project_root: str) -> dict:
"""Analyzes Python project structure via AST"""
structure = {
"modules": [],
"imports": [],
"classes": [],
"http_clients": [],
"db_models": [],
}
for py_file in Path(project_root).rglob("*.py"):
if any(skip in str(py_file) for skip in ["migrations", "__pycache__", ".venv", "test_"]):
continue
try:
source = py_file.read_text()
tree = ast.parse(source)
rel_path = str(py_file.relative_to(project_root))
module_name = rel_path.replace("/", ".").replace(".py", "")
structure["modules"].append(module_name)
# Imports
for node in ast.walk(tree):
if isinstance(node, ast.ImportFrom) and node.module:
structure["imports"].append({
"from": module_name,
"to": node.module,
})
# Classes
if isinstance(node, ast.ClassDef):
bases = [ast.unparse(b) for b in node.bases]
structure["classes"].append({
"module": module_name,
"name": node.name,
"bases": bases,
})
# HTTP clients (requests, httpx)
if "requests.get" in source or "httpx.get" in source or "AsyncClient" in source:
urls = re.findall(r'["\']https?://[^"\']+["\']', source)
structure["http_clients"].append({
"module": module_name,
"external_calls": urls[:5],
})
except (SyntaxError, UnicodeDecodeError):
pass
return structure
def generate_mermaid_diagram(
self,
analysis: dict,
diagram_type: str = "c4",
) -> str:
"""Generates Mermaid diagram"""
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
system="""You are an architect generating Mermaid diagrams.
Create only valid Mermaid syntax.
For C4 Context/Container diagrams:
- Group by layers: Frontend, API, Services, Database, External
- Show main interactions with arrows
- Don't overload — only key components
For Flow diagrams:
- Use flowchart TD (top-down)
- Show business process clearly""",
messages=[{
"role": "user",
"content": f"""Create {diagram_type} Mermaid diagram based on project analysis.
Analysis:
{str(analysis)[:3000]}
Return only Mermaid code (starting with ```mermaid)."""
}]
)
return response.content[0].text
def generate_from_docker_compose(self, compose_file: str) -> str:
"""Generates diagram from docker-compose.yml"""
import yaml
with open(compose_file) as f:
compose = yaml.safe_load(f)
services = compose.get("services", {})
networks = compose.get("networks", {})
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
messages=[{
"role": "user",
"content": f"""Create Mermaid architecture diagram from docker-compose.
Services:
{str(services)[:2000]}
Networks:
{str(networks)}
Show:
- Each service as block with name and image
- Dependencies (depends_on) as arrows
- Ports as marks on blocks
- Shared networks as groups
Return only Mermaid code."""
}]
)
return response.content[0].text
def generate_from_terraform(self, tf_dir: str) -> str:
"""Generates AWS/GCP architecture diagram from Terraform"""
# Read all .tf files
tf_content = ""
for tf_file in Path(tf_dir).glob("*.tf"):
tf_content += tf_file.read_text() + "\n\n"
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
messages=[{
"role": "user",
"content": f"""Create Mermaid infrastructure diagram from Terraform code.
Terraform:
```hcl
{tf_content[:4000]}
Show:
- VPC/networks as containers
- EC2/ECS/Lambda as rectangles
- RDS/ElastiCache as cylinders (or databases)
- ALB/API Gateway as diamonds
- Arrows = traffic/interactions
Format: Mermaid flowchart LR.""" }] )
return response.content[0].text
### Sequence Diagram Generation
```python
def generate_sequence_diagram(endpoint_source: str, service_name: str) -> str:
"""Generates sequence diagram from endpoint handler code"""
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
messages=[{
"role": "user",
"content": f"""Create Mermaid sequence diagram for this API endpoint.
Code ({service_name}):
```python
{endpoint_source}
Show:
- Participants: Client, API, each external service/DB
- All calls in correct order
- Async calls (if any) with parallel arrows
- Conditional branches via alt/opt
Return only Mermaid code.""" }] )
return response.content[0].text
def generate_er_diagram(models_source: str) -> str: """Generates ER diagram from SQLAlchemy models"""
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
messages=[{
"role": "user",
"content": f"""Create Mermaid ER diagram from SQLAlchemy models.
{models_source}
Show all tables with:
- Fields and types
- PK/FK markers
- Relationships (one-to-one, one-to-many, many-to-many)
Use syntax: erDiagram""" }] )
return response.content[0].text
### Automatic Updates in CI/CD
```python
import subprocess
from pathlib import Path
def update_diagrams_on_push(project_root: str, docs_dir: str):
"""Updates diagrams on every push"""
generator = ArchitectureDiagramGenerator()
# Analyze project
analysis = generator.analyze_project_structure(project_root)
# Generate diagrams
diagrams = {
"architecture.md": generator.generate_mermaid_diagram(analysis, "c4"),
"database.md": generate_er_diagram(
(Path(project_root) / "models.py").read_text()
if (Path(project_root) / "models.py").exists() else ""
),
}
# docker-compose if exists
compose_file = Path(project_root) / "docker-compose.yml"
if compose_file.exists():
diagrams["infrastructure.md"] = generator.generate_from_docker_compose(str(compose_file))
# Save
docs_path = Path(docs_dir)
docs_path.mkdir(exist_ok=True)
for filename, content in diagrams.items():
(docs_path / filename).write_text(content)
# Render PNG via mmdc (mermaid-cli)
for md_file in docs_path.glob("*.md"):
png_file = md_file.with_suffix(".png")
subprocess.run(
["mmdc", "-i", str(md_file), "-o", str(png_file)],
capture_output=True
)
Practical Case: Documenting Microservices Architecture
Context: fintech startup, 12 microservices, last architecture diagram drawn 2 years ago. Onboarding new developers: "look at code, no other sources".
Implementation:
- Analysis of all docker-compose.yml and terraform files
- Generation of 4 diagrams: C4 Context, Container, Infrastructure, ER
- GitHub Actions integration: auto-update on push to main
Results:
- New developer onboarding time (understanding architecture): 2 weeks → 3 days
- Diagrams 100% up-to-date (generated on every PR)
- Detected 3 non-obvious circular dependencies between services
Diagram types generated:
| Diagram | Source | Update |
|---|---|---|
| C4 Context | Entire project | On main services change |
| ER Database | models.py / Prisma schema | On model changes |
| Infrastructure | Terraform / docker-compose | On IaC change |
| Sequence | Specific endpoint | On request |
| Dependency Graph | package.json / requirements.txt | On PR |
Timeline
- Generation of one diagram type (docker-compose or models): 1–2 days
- Full set from codebase: 3–5 days
- CI/CD integration with auto-update: 1 week
- Confluence/Notion publication: +2–3 days







