Deterministic, AST-verified architecture ground truth for Python. LLMs guess your architecture. py-code-visualizer proves it — every edge is traceable to a
file:line.
⚡ Try it live in your browser →
· drop a .py file, see the graph, nothing uploaded
py-code-visualizer reads your Python source with static analysis (no code is ever imported or executed) and produces a call graph you can trust: self-healing README diagrams, PR architecture-change reports, CI gates that block circular dependencies, and a fully offline interactive map. Because the output is deterministic, it lives in your pipelines and never drifts.
pip install py-code-visualizer && py-code-visualizer visualize .Who is this for? Any Python developer, whatever your stack: Django (real request flow, not just the model schema) · FastAPI (every route's blast radius, async + decorators) · ML pipelines (map the pipeline, find dead experiments). See the honest comparison and measured facts.
An LLM asked to diagram your repo produces the architecture it expects a repo like yours to have — plausible, confident, and subtly wrong. It invents links between modules that never call each other, silently drops what didn't fit the context window, and gives a different answer every run, so you can never diff it or put it in CI.
PyVisualizer is the opposite by construction:
| LLM diagram | PyVisualizer | |
|---|---|---|
| Correctness | Inferred, often hallucinated | Parsed from the AST |
| Provenance | None | Every edge → file:line |
| Determinism | Different every run | Byte-identical |
| Ambiguity | Hidden behind confidence | Flagged, with candidates kept |
| CI-able | No | Yes — gates, diffs, drift checks |
| Code leaves the machine | Usually | Never |
When a call genuinely can't be resolved to one target, we don't pick one and
pretend — we tag the edge ambiguous and keep the full candidate list. That
honesty is the whole product.
pip install py-code-visualizer# Interactive, fully self-contained HTML map (opens offline, zero network)
py-code-visualizer visualize ./your_project -o architecture.html
# Keep a live diagram inside your README forever
py-code-visualizer readme ./your_project
# Fail CI on new circular dependencies
py-code-visualizer check ./your_project --fail-on-cycles
# What breaks if I touch this function?
py-code-visualizer impact your_pkg.core.save ./your_projectFull guide: AI_CONTEXT.md
Instead of pasting your whole codebase into Claude / ChatGPT / Cursor, give it the verified 4,000-token slice that actually matters. Three commands cover every workflow:
# Option A — describe the task in plain English (no function name needed)
py-code-visualizer context . --task "add retry logic to the HTTP client" --budget-tokens 4000
# Option B — you know the function
py-code-visualizer context . --focus send_request --budget-tokens 4000
# Option C — wire it in permanently (agents read it automatically)
py-code-visualizer export --for-ai .Copy the output of A or B → paste it before your question in the AI chat. The AI now has the right context instead of 140,000 guessed tokens.
| Approach | Tokens | Claude Opus 5 cost | Signal per 1k tokens |
|---|---|---|---|
| Full source | 139,697 | $2.10 | 1× |
| Keyword grep | 24,652 | $0.37 | 6× |
pyvisualizer --task |
~4,000 | $0.06 | 35× |
Measured on httpx (real open-source project, 1,076 functions). See measured facts.
You will never schedule a "docs sprint." So don't. Add one line to CI and your README always carries a current architecture diagram — investor- and due-diligence-ready for free — while every PR gets a comment showing exactly what changed structurally.
# .github/workflows/architecture.yml
- uses: haider1998/PyVisualizer@v2
with: { mode: readme }A new contractor onboards from the interactive map instead of a three-day Slack Q&A. Pivots stop being archaeology.
- Code never leaves the machine. Pure AST, no execution, no API calls — the anti-LLM tool for security review. Generated HTML is a single file with zero network requests (air-gap safe).
- Architecture-as-code gates. Declare layers and forbidden dependencies; the build fails on violations — at the call-graph level, stricter than import linters.
- Audit trail. Deterministic diagrams committed by CI make git history your dated, attributable architecture change-log (SOC 2 / review boards).
- Monorepo scale. Hierarchical rollup (module → class → function), never silent sampling.
# pyproject.toml
[tool.pyvisualizer.rules]
layers = ["api", "domain", "infra"]
forbid = ["domain -> api", "domain -> infra"]| Command | What it does |
|---|---|
review <path> --base <ref> |
PR review report: changed functions, blast radius, risk flags, focused subgraph — clickable file:line on every reference |
context <path> --focus <fn> |
Verified context pack for AI agents: task-scoped, budget-bounded, zero guessed edges |
context <path> --task "<prose>" |
Same pack, seeded from a natural-language task description (named symbols first, lexical matches as labeled hints; --strategy graph|text|hybrid) |
visualize |
Render html · mermaid · json · c4 · svg/png |
readme |
Inject/update a Mermaid diagram in any Markdown file (idempotent) + jump-to-source index |
json |
Emit the canonical, diffable graph JSON |
diff base.json head.json |
PR-ready architecture-change report (+ new-cycle gate) |
check |
Enforce layering rules & cycles — CI gate (--dead-code too) |
impact <fn> |
Blast-radius: transitive callers/callees + risk line (--format markdown) |
health |
Architecture health score (A–F) with an SVG badge |
export |
ARCHITECTURE.json + ARCHITECTURE.md + AGENTS.md wiring (--check freshness gate) |
init |
Opt-in setup — generate only the automation you choose (review/readme/context/gates) |
Two jobs, one engine. review makes code review on a large repo a focused
few-minute pass; context gives an AI agent a verified, 97%-smaller slice of the
architecture instead of the whole repo. See VISION.md and the
use-case walkthroughs.
If you use Claude Code or Cursor, the MCP server lets the agent query the verified graph when it needs it — no manual copy-paste required:
pip install 'py-code-visualizer[mcp]' # Python 3.10+
pyvisualizer-mcp /path/to/projectAdd to .mcp.json and three tools become available: search_code, context_pack,
and impact. The server rebuilds only when files change.
Full usage guide (all flags, troubleshooting, output walkthrough): AI_CONTEXT.md
Three end-to-end walkthroughs, each backed by a runnable fixture in
examples/scenarios/ — every command and every line of
output is reproducible, nothing is staged:
- 🗺️ The orphan monolith —
onboard onto an undocumented codebase with
visualize+health+check --dead-code. - 🛡️ The audit deadline — enforce layering rules at the call-graph level and produce dated SOC 2 evidence.
- 🧨 The fearless refactor —
impactblast radius, then adiffgate that fails a PR on a new cycle.
See the full use-case index + a recipe for every command.
Measured (reproduce with python benchmarks/bench.py → docs/benchmarks.json):
a 98,669-line project maps to a full call graph in ~4.9 s (26,658 functions),
100% of edges carry file:line, output is byte-identical across runs, and the
generated HTML makes 0 network requests. (macOS arm64, Python 3.14; speed is
hardware-dependent — provenance, determinism, and zero-network are structural.)
A single self-contained HTML file (no CDN, works offline):
- Layered abstraction — toggle module → class → function views
- Click any node — signature,
file:line, callers & callees (all clickable) - ⌘K command palette, live search, module filter
- Deep links — the URL encodes the selected node; paste it in Slack and your teammate lands on the exact function
- Tour mode — auto-generated walkthrough from detected entry points
- Overlays — cycles (red), ambiguity (dashed), and
--churngit-heatmap - Minimap, pan/zoom/drag, light/dark, SVG export
py-code-visualizer export --for-ai ./your_projectPoint Cursor / Claude at the verified ARCHITECTURE.json instead of asking a
model to re-derive structure from raw source. Point your agent at the graph,
not the repo.
- Nested classes, methods, and closures are collected with correct qualified
names (
pkg.Outer.Inner.method,mod.func.<locals>.inner). - Chained calls (
get_client().fetch()), comprehensions, and lambdas are captured. super()/inherited calls resolved through the computed MRO (taggedinherited).- Parameter and variable type annotations drive method resolution.
- Calls to stdlib/third-party code produce no edge — we never invent one.
- Ambiguous calls are tagged and kept as candidates;
--strictdrops them.
See docs/integrations.md for GitHub Actions, GitLab
CI, and pre-commit setup.
[tool.pyvisualizer]
exclude = ["tests", "migrations"]
max_nodes = 120
target = "README.md"
detail = "module" # module | class | function- ⏳ Time-travel — scrub your architecture's evolution across releases
- 🔁 Watch mode — live-reloading map while you refactor
- ✅
MCP server— shipped:pyvisualizer-mcp(search_code,context_pack,impact)
The diagram below is generated by PyVisualizer itself and kept in sync by CI.
120 functions · 214 calls · health F (46/100) — detail: module
flowchart LR
g0["bench"]
g1["genproject"]
g2["main"]
g3["models"]
g4["services"]
g5["urls"]
g6["repos"]
g7["services"]
g8["evaluate"]
g9["features"]
g10["ingest"]
g11["pipeline"]
g12["train"]
g13["cli"]
g14["pipeline"]
g15["transforms"]
g16["core"]
g17["service"]
g18["billing"]
g19["api"]
g20["changes"]
g21["cli"]
g22["config"]
g23["context"]
g24["analyzer"]
g25["graph"]
g26["diff"]
g27["export"]
g28["gates"]
g29["impact"]
g30["inject"]
g31["mcp_server"]
g32["metrics"]
g33["overlays"]
g34["retrieval"]
g35["review"]
g36["c4"]
g37["json_graph"]
g38["setup_init"]
g39["file_discovery"]
g40["d3"]
g41["html"]
g42["mermaid"]
g0 --> g1
g0 --> g19
g0 --> g37
g0 --> g41
g1 --> g6
g4 --> g3
g7 -.-> g4
g7 --> g6
g11 --> g8
g11 --> g9
g11 --> g10
g11 --> g12
g13 --> g14
g14 -.-> g7
g14 --> g15
g15 -.-> g4
g17 --> g16
g19 --> g25
g19 --> g31
g19 --> g39
g20 --> g31
g20 --> g33
g21 --> g14
g21 --> g19
g21 --> g22
g21 --> g23
g21 --> g26
g21 --> g27
g21 --> g28
g21 --> g29
g21 --> g30
g21 --> g31
g21 --> g32
g21 --> g33
g21 --> g35
g21 --> g36
g21 --> g37
g21 --> g40
g21 --> g42
g22 --> g31
g23 --> g4
g23 --> g20
g23 --> g28
g23 --> g29
g23 --> g31
g23 --> g32
g23 --> g33
g23 --> g34
g24 --> g31
g25 --> g4
g25 --> g31
g26 --> g4
g26 --> g31
g26 --> g32
g27 --> g28
g27 --> g30
g27 --> g31
g27 --> g32
g27 --> g37
g28 --> g31
g29 --> g20
g31 --> g19
g31 --> g23
g31 --> g29
g31 --> g34
g32 --> g31
g32 --> g34
g33 --> g31
g34 --> g4
g34 --> g31
g35 --> g20
g35 --> g28
g35 --> g31
g35 --> g32
g35 --> g42
g36 --> g42
g37 --> g31
g38 --> g19
g38 --> g30
g38 --> g31
g38 --> g32
g38 --> g42
g39 --> g4
g39 --> g6
g40 --> g41
g41 --> g37
g42 --> g31
🔒 Deterministic, AST-verified — no code executed. Generated by py-code-visualizer.
📍 Jump to source (120 functions)
benchmarks.bench._bench_targetbenchmarks.bench._determinism_proofbenchmarks.bench._html_network_proofbenchmarks.bench.runbenchmarks.genproject._gen_modulebenchmarks.genproject.generateexamples.sample_project.main.mainexamples.scenarios.django_shop.models.Cart.for_userexamples.scenarios.django_shop.services.CartService.addexamples.scenarios.django_shop.services.OrderService.checkoutexamples.scenarios.django_shop.services.OrderService.getexamples.scenarios.django_shop.urls.dispatchexamples.scenarios.fastapi_svc.repos.OrderRepo.insertexamples.scenarios.fastapi_svc.services.OrderFlow.fetchexamples.scenarios.fastapi_svc.services.OrderFlow.placeexamples.scenarios.ml_pipeline.evaluate.evaluate_modelexamples.scenarios.ml_pipeline.features.build_featuresexamples.scenarios.ml_pipeline.ingest.load_datasetexamples.scenarios.ml_pipeline.pipeline.runexamples.scenarios.ml_pipeline.train.train_modelexamples.scenarios.orphan_monolith.app.cli.runexamples.scenarios.orphan_monolith.app.pipeline.ReportPipeline.buildexamples.scenarios.orphan_monolith.app.pipeline.ReportPipeline.renderexamples.scenarios.orphan_monolith.app.transforms.summarizeexamples.scenarios.refactor.after.core.persistexamples.scenarios.refactor.after.service.cancel_orderexamples.scenarios.refactor.after.service.place_orderexamples.scenarios.soc2_audit.domain.billing.BillingService.chargepyvisualizer.api.build_graphpyvisualizer.changes.Linker.refpyvisualizer.changes.changed_lines_from_gitpyvisualizer.changes.map_lines_to_functionspyvisualizer.changes.repo_web_urlpyvisualizer.changes.resolve_base_refpyvisualizer.cli._buildpyvisualizer.cli._render_graphvizpyvisualizer.cli.cmd_checkpyvisualizer.cli.cmd_contextpyvisualizer.cli.cmd_diffpyvisualizer.cli.cmd_exportpyvisualizer.cli.cmd_healthpyvisualizer.cli.cmd_impactpyvisualizer.cli.cmd_readmepyvisualizer.cli.cmd_reviewpyvisualizer.cli.cmd_visualizepyvisualizer.cli.mainpyvisualizer.config.load_configpyvisualizer.context._est_tokenspyvisualizer.context._node_linepyvisualizer.context._resolve_focuspyvisualizer.context._select_nodespyvisualizer.context._select_textpyvisualizer.context._upgrade_bodiespyvisualizer.context.build_context_packpyvisualizer.core.analyzer.DefinitionCollector._visit_functionpyvisualizer.core.analyzer.DefinitionCollector.visit_ClassDefpyvisualizer.core.analyzer.ModuleAnalyzer._decorator_namespyvisualizer.core.analyzer.ModuleAnalyzer._extract_attribute_chainpyvisualizer.core.analyzer.ModuleAnalyzer._process_annotationpyvisualizer.core.analyzer.ModuleAnalyzer._process_decoratorpyvisualizer.core.graph.FunctionCallVisitor._extract_attribute_chainpyvisualizer.core.graph.FunctionCallVisitor._extract_call_targetpyvisualizer.core.graph.FunctionCallVisitor._find_method_in_hierarchypyvisualizer.core.graph.FunctionCallVisitor._resolve_callpyvisualizer.core.graph.FunctionCallVisitor._seed_param_typespyvisualizer.core.graph.FunctionCallVisitor._visit_function_commonpyvisualizer.core.graph.build_call_graphpyvisualizer.diff.diff_graphspyvisualizer.diff.render_change_mermaidpyvisualizer.diff.render_markdownpyvisualizer.export._agents_md_planpyvisualizer.export._json_contentpyvisualizer.export.build_ai_markdownpyvisualizer.export.export_for_aipyvisualizer.export.export_would_changepyvisualizer.gates.check_layer_rulespyvisualizer.gates.find_cyclespyvisualizer.impact.analyze_impactpyvisualizer.impact.render_markdownpyvisualizer.impact.resolve_targetpyvisualizer.inject.injectpyvisualizer.inject.inject_blockpyvisualizer.inject.update_filepyvisualizer.mcp_server.ProjectSession.getpyvisualizer.mcp_server.tool_context_packpyvisualizer.mcp_server.tool_impactpyvisualizer.metrics._is_entry_pointpyvisualizer.metrics.compute_healthpyvisualizer.metrics.find_dead_codepyvisualizer.overlays._gitpyvisualizer.overlays._toplevelpyvisualizer.overlays.apply_churnpyvisualizer.overlays.git_churnpyvisualizer.retrieval.BM25Index.rankpyvisualizer.retrieval.BM25Index.searchpyvisualizer.retrieval.build_bm25pyvisualizer.retrieval.derive_seedspyvisualizer.retrieval.function_sourcepyvisualizer.retrieval.rank_seedspyvisualizer.retrieval.tokenizepyvisualizer.review._risk_linespyvisualizer.review.analyze_reviewpyvisualizer.review.render_markdownpyvisualizer.review.render_textpyvisualizer.serializers.c4.generate_c4_dslpyvisualizer.serializers.json_graph.graph_to_dictpyvisualizer.serializers.json_graph.graph_to_jsonpyvisualizer.setup_init._action_readmepyvisualizer.setup_init._record_featurespyvisualizer.setup_init.run_initpyvisualizer.utils.file_discovery.analyze_projectpyvisualizer.utils.file_discovery.find_project_python_filespyvisualizer.utils.file_discovery.get_module_namepyvisualizer.visualizers.d3.generate_d3_visualizationpyvisualizer.visualizers.html.generate_html_visualizationpyvisualizer.visualizers.mermaid._categorize_methodspyvisualizer.visualizers.mermaid._rolluppyvisualizer.visualizers.mermaid.create_interactive_htmlpyvisualizer.visualizers.mermaid.generate_github_mermaidpyvisualizer.visualizers.mermaid.generate_styled_mermaid
See CONTRIBUTING.md. PyVisualizer is MIT-licensed.