name: architecture-knowledge-graph description: Guide for reading a codebase and building a high-quality, persistent architecture knowledge graph via the Excalidraw Architect MCP kg_* tools. Use when creating or updating the knowledge graph (.claude/architecture.md), mapping services and their dependencies, or analyzing one or more repos to capture how services communicate.
Architecture Knowledge Graph Guide
This skill teaches you how to turn a codebase into a clean, durable knowledge
graph using the kg_* MCP tools. The graph (default .claude/architecture.md)
is the single source of truth; diagrams are rendered views of it.
Graph quality depends almost entirely on how well you read the code. The MCP preserves, validates, and renders whatever you put in — it does not analyze the codebase. That analysis is your job.
Core Principle
Model services/components and how they communicate, not classes, functions,
or every import. A "service" is a deployable unit / bounded context — one
repo, one container, one logical responsibility.
Workflow (do the passes in order — don't interleave)
kg_initonce (orkg_importto bootstrap from an existing.excalidraw).- Discovery pass — identify every service first. Add each with
kg_add_service, settingcomponent_type,domain, andownerwhile the info is in front of you (Dockerfiles,CODEOWNERS, READMEs, manifests). - Linking pass — only after all services exist, add edges with
kg_link. Linking before a target exists fails; that's why discovery comes first. kg_lint— catch dangling references, cycles, and single points of failure. Fix them before rendering.kg_render(whole graph) orkg_render_view/kg_render_around/kg_render_domainfor focused diagrams.
How to find the edges (where services talk)
Look for these signals and translate each into a labelled kg_link:
| Signal in code | Link | Label / style |
|---|---|---|
| HTTP client, base URL, OpenAPI/Swagger spec | sync call | "REST /orders", style: solid |
| gRPC stub / proto service | sync call | "gRPC GetOrder", style: solid |
| Kafka/SQS/RabbitMQ producer | async event | "Kafka order.created", style: dashed |
| Kafka/SQS/RabbitMQ consumer | async event (incoming) | label with the same topic |
| DB connection string / ORM config | datastore | "reads/writes", style: solid |
Service-discovery / env var (PAYMENTS_URL) |
dependency | name the protocol |
Cross-repo detection (multiple repos)
To connect services across repos, match a producer in repo A to a consumer in repo B using the shared join key:
- Async: topic / queue name (A publishes
order.created, B subscribesorder.created→kg_link order-svc -> fulfilment-svc "Kafka order.created" style=dashed). - Sync: the called service's route/host (A calls
https://payments/charge→ link A → payments).
Do a producer/consumer inventory across all repos before linking, so you don't miss an edge whose two ends live in different codebases.
Conventions (keep the graph consistent across sessions)
- Stable kebab-case ids, reused everywhere:
order-service— neverOrderServiceone session andordersthe next. Id drift silently corrupts a cumulative graph. - Every edge is labelled with the mechanism. No bare arrows between services.
- Style encodes transport:
solid= sync (REST/gRPC/DB),dashed= async (events/queues). Consistency makes diagrams instantly readable. - Set
domainto group services (team / bounded context / tier) so you can render one domain at a time.
Granularity
The full graph may be large, but any single rendered view should stay readable
(~6–15 services). If a domain has 20 services, render it per sub-domain with
kg_render_domain / kg_render_view rather than one giant picture. Resist
decomposing a service into its internal classes — that's a different diagram.
Known limitation: parallel edges
A dependency is keyed on (from_id, to_id), so a second kg_link between the
same pair replaces the first. If A talks to B two ways (REST and Kafka),
combine them into one label — "REST /orders · Kafka order.created" — or link
the primary transport. Don't issue two kg_link calls expecting two arrows.
Verify
Unlike diagrams, the graph is deterministically checkable. After building, run
whats_connected_to <service> and kg_lint to sanity-check the topology
matches your understanding of the system before sharing rendered views.