DOT Graph Tool¶
Code is structure — modules depend on modules, functions call functions, data flows through pipelines. But staring at code doesn't always reveal the shape of that structure. The DOT Graph tool lets you express structure as diagrams in Graphviz DOT format and then do things with it: validate that your graph syntax is correct, render it to an image, analyze its properties without rendering, scan a codebase into a structural inventory, and assemble module-level graphs into system-level overviews.
This isn't just a rendering tool. The analysis operations let you ask structural questions — are there cycles in this dependency graph? What's the critical path? What changed between two versions of an architecture? — and get precise, computed answers instead of eyeballing a picture.
Core Capabilities¶
The DOT Graph tool has five operations, each serving a different stage of working with graphs.
Validate — Check Before You Render¶
Validation runs your DOT content through up to three layers of checking:
| Layer | What It Checks | Catches |
|---|---|---|
| syntax | DOT grammar is well-formed | Missing semicolons, unclosed braces, bad attribute syntax |
| structural | Graph makes logical sense | Duplicate edges, orphaned nodes, empty subgraphs |
| render | Graphviz can actually produce output | Layout engine errors, unsupported attributes |
By default, all three layers run. You can also request specific layers if you only care about one:
Validate this architecture diagram
[Tool: dot_graph] validate
dot_content: "digraph arch { frontend -> api; api -> database; api -> cache; }"
Syntax: OK
Structural: OK
Render: OK — valid DOT, ready to render
When something is wrong, the tool tells you exactly where:
Check this graph for errors
[Tool: dot_graph] validate
dot_content: "digraph broken { a -> b; b -> c; c -> }"
Syntax: ERROR — expected node identifier at position 42, found "}"
Validate early and validate often. Catching a syntax error before rendering saves a round trip.
Render — From Text to Image¶
Rendering takes DOT content and produces a visual output file. The tool supports multiple formats and layout engines:
Formats: SVG, PNG, PDF, PS, EPS, JSON
Layout engines:
| Engine | Best For |
|---|---|
dot |
Directed graphs, hierarchies, flowcharts (default) |
neato |
Undirected graphs, network topologies |
fdp |
Large undirected graphs with clustering |
sfdp |
Very large graphs (thousands of nodes) |
twopi |
Radial layouts from a central node |
circo |
Circular layouts, ring structures |
Render the service architecture as a PNG
[Tool: dot_graph] render
dot_content: "digraph services {
rankdir=LR;
gateway -> auth; gateway -> api; api -> db;
api -> cache; auth -> db;
}"
format: "png"
engine: "dot"
output_path: "/tmp/services.png"
Rendered to /tmp/services.png (12KB)
You can also let the tool auto-generate a temp file path if you don't care where it lands:
Quick render of this graph to SVG
[Tool: dot_graph] render
dot_content: "digraph { a -> b -> c -> d }"
format: "svg"
Rendered to /tmp/dot_graph_a3f2.svg (4KB)
Analyze — Structure Without Pixels¶
This is where the DOT Graph tool goes beyond visualization. The analyze operations compute structural properties of your graph using networkx — no rendering needed, no images produced. Just answers.
stats — basic graph metrics:
[Tool: dot_graph] analyze
analysis: "stats"
dot_content: "digraph { a -> b; b -> c; c -> d; a -> d; }"
Nodes: 4
Edges: 4
Density: 0.33
Is DAG: yes
Connected components: 1
cycles — detect circular dependencies:
Are there any cycles in the module dependency graph?
[Tool: dot_graph] analyze
analysis: "cycles"
dot_content: "digraph deps {
auth -> users; users -> permissions;
permissions -> auth; api -> auth;
}"
Cycles found: 1
auth → users → permissions → auth
That cycle means auth, users, and permissions are mutually dependent — a common design smell that's hard to spot by reading imports.
reachability — what can be reached from a given node:
[Tool: dot_graph] analyze
analysis: "reachability"
source_node: "gateway"
Reachable from gateway: auth, api, db, cache (4 nodes)
paths — all simple paths between two nodes:
[Tool: dot_graph] analyze
analysis: "paths"
source_node: "gateway"
target_node: "db"
Paths (2 found):
gateway → api → db
gateway → auth → db
critical_path — the longest path in a DAG, showing the bottleneck chain:
[Tool: dot_graph] analyze
analysis: "critical_path"
Critical path: gateway → api → processor → validator → db (length: 4)
diff — structural differences between two versions of a graph:
[Tool: dot_graph] analyze
analysis: "diff"
dot_content: "digraph v1 { a -> b; b -> c; }"
dot_content_b: "digraph v2 { a -> b; b -> c; c -> d; b -> d; }"
Added nodes: d
Added edges: c → d, b → d
Removed nodes: (none)
Removed edges: (none)
subgraph_extract — pull a named cluster out as a standalone graph:
[Tool: dot_graph] analyze
analysis: "subgraph_extract"
cluster_name: "cluster_auth"
Extracted cluster_auth as standalone DOT (3 nodes, 4 edges)
Prescan — Inventory Your Codebase¶
Before you can diagram a system, you need to know what's in it. Prescan walks a repository and produces a structural inventory — languages detected, modules found, files per module:
Scan this repo to see what we're working with
[Tool: dot_graph] prescan
repo_path: "/home/user/project"
Languages: Python (87%), JavaScript (10%), YAML (3%)
Modules: 12
src/auth/ — 8 files, 1200 lines
src/api/ — 14 files, 2800 lines
src/models/ — 6 files, 900 lines
...
Prescan output feeds directly into assembly — once you know the modules, you can diagram each one and merge them together.
Assemble — Build the Big Picture¶
Assembly takes per-module DOT files and merges them into subsystem and overview graphs. This is hierarchical: module-level diagrams combine into subsystem diagrams, which combine into a full system overview.
Assemble the architecture diagrams from per-module DOTs
[Tool: dot_graph] assemble
manifest: { ... module DOT mappings ... }
output_dir: "/tmp/architecture"
Assembled:
/tmp/architecture/subsystem_backend.dot
/tmp/architecture/subsystem_frontend.dot
/tmp/architecture/overview.dot
Rendered PNGs alongside each DOT file.
By default, assembly also renders each assembled graph to PNG. Set render_png: false if you only want the DOT files.
Assembly supports incremental updates — pass invalidated_modules to re-assemble only the subsystems affected by changes, rather than rebuilding everything.
Tips¶
Validate before rendering. A validation call is cheap and catches syntax errors instantly. A failed render gives you less helpful error messages and wastes more time.
Use analysis for questions, render for communication. If you want to know whether cycles exist, use analyze. If you want to show the architecture to your team, use render. They serve different purposes.
Pick the right layout engine. Hierarchical code flows want dot. Network topologies want neato. If your graph looks tangled with the default engine, try a different one before restructuring the DOT.
Diff before and after refactors. Diagram the dependency structure before a refactor, then again after. The diff analysis shows exactly what changed structurally, which is much clearer than diffing code.
Leverage incremental assembly. For large projects, don't reassemble everything when one module changes. Use invalidated_modules to rebuild just the affected subsystems.
Next Steps¶
- Learn about the Bash Tool for running Graphviz commands directly when you need lower-level control
- See Filesystem Tools for reading and writing DOT files
- Explore Delegate Tool for delegating complex architecture analysis to sub-agents