vizzle
UML visualization for git: parse a codebase (or a git diff) and render UML
diagrams — as Mermaid text or as an interactive d3-powered HTML page — with
changes highlighted so a reader immediately sees what a change did to the
shape of the code. Two diagram types so far: class (the shape of the
code) and component (the shape of the application). Each type has a spec
in docs/diagram-types/ — what an element is, how it is detected, what its
diff means, and the modelling decisions behind it (e.g. why aggregation and
composition diamonds are a convention rather than an inference:
docs/diagram-types/class.md §5.4).
- Rust core (
crates/vizzle-core): tree-sitter parsing (Python + TypeScript), a language-neutral class graph + import graph, a component detector (manifest-driven), graph diff engines, and Mermaid renderers. Parses ~200 classes in well under a second. - PyO3 bindings (
crates/vizzle-py): built with maturin into the private extension modulevizzle_cli._core. - Click CLI (
packages/vizzle-cli): thevizzlecommand. Python owns the git orchestration; Rust owns everything hot.
Three source layers ship as one wheel — pip install vizzle gets the CLI
and the compiled core together, so their versions cannot drift apart.
Install
Nothing to install — run it straight from PyPI, with nothing added to the repo you are looking at:
uvx vizzle component ~/code/some-repo
Or keep it around: uv tool install vizzle (or pipx install vizzle). Needs
Python ≥ 3.10 and git on PATH; on Linux, glibc ≥ 2.28. Why it is distributed
this way is in docs/distribution.md.
For coding agents
vizzle ships a Claude Code plugin, so an agent knows to reach for a diagram instead of reading the repo file by file — a component diagram of a 358-file codebase costs about 1.5k tokens:
claude plugin marketplace add stiproot/vizzle
claude plugin install vizzle@vizzle-marketplace
From a clone
For development — requires uv and a Rust toolchain:
uv sync # builds the Rust extension via maturin and installs the CLI
Working from a clone, read uv run vizzle … wherever the examples below say
uvx vizzle …, so you exercise your build rather than the published one.
Usage
Full class diagram of a codebase:
uvx vizzle class ~/code/repo/h -o h-classes.mmd
Grouped into namespace blocks — --group-by component for one block per
package, --group-by module for one per file:
uvx vizzle class ~/code/repo/h --group-by component --no-members
Component diagram — one box per build-level module (workspace package, app,
service; any directory with a package.json/pyproject.toml/Cargo.toml/
go.mod), one dashed arrow per dependency derived from imports
(spec: docs/diagram-types/component.md):
uvx vizzle component ~/code/repo/h -o h-components.mmd --weights
uvx vizzle component ~/code/repo/h -o h-components.html # interactive
In the HTML view each app/package gets a labelled box you can drag as a
unit, and every component carries a + toggle that explodes it into a full
UML class diagram — boxes with stereotypes, fields and methods, data types on
every member, and the association, dependency and inheritance edges between
them (or use Show classes to open them all at once). Each explosion is laid
out once at load and then only shown or hidden, so toggling stays instant.
--no-classes omits that detail for a leaner file.
What changed, as a diagram (added = green ✚, removed = red ✖, modified = yellow ✱; unchanged classes in touched files render as context):
# working tree vs HEAD
uvx vizzle diff ~/code/repo/h
# between two revisions
uvx vizzle diff ~/code/repo/h --base HEAD~20 --head HEAD -o changes.mmd
# did the change rewire the application? (parses both full revisions;
# added/removed dependency edges render loudest)
uvx vizzle diff ~/code/repo/h --type component
# for a script: the verdict as JSON (changed, counts, rendered size), so it
# never has to read the diagram text
uvx vizzle diff ~/code/repo/h --type component -o changes.mmd --stats verdict.json
# make a point: light the classes an explanation is about and dim the rest,
# or keep only a class and its neighbours
uvx vizzle class src --no-members --highlight LaunchRunRequest,TaskAgent
uvx vizzle class src --around TaskAgent --depth 1
# one manifest but many subsystems: split the package into its subpackages,
# focus the diff on the changed ones and their neighbours, and zoom into the
# classes that changed inside them
uvx vizzle diff . --type component --split src/mypkg --focus -o shape.mmd --zoom inside.mmd
Interactive HTML (d3)
Write to a .html file (or pass --format html) and vizzle emits a fully
self-contained page — d3 v7 is inlined, no network needed — that renders the
class graph as SVG with zoom (scroll), pan (drag the background),
draggable class boxes, a fit-to-view button, and a live filter box. Diff
pages color whole classes and individual member rows (removed members are
struck through). In a component diff, opening a changed component shows only
the classes and members that changed, banded in their change colour, with the
rest folded behind a count and a link to show them:
uvx vizzle class ~/code/repo/h -o h-classes.html
uvx vizzle diff ~/code/repo/h --base HEAD~20 --head HEAD -o changes.html
open changes.html
Layout is a d3 force simulation (link + charge + rectangle collision) with a weak per-module gravity, ticked synchronously before first paint so the page opens settled. The component view adds a two-level relaxation pass — components separate within their group, then groups separate as blocks — so group boxes never overlap, including after a component is expanded.
Both views are built from one shared core (assets/viz-core.{css,js}, inlined
into every page): the palette, geometry, viewport, filter, and header. A
template only describes what its own nodes look like.
Comprehension first. Nothing here needs a git diff: vizzle class and
vizzle component are for reading unfamiliar code. The diff is a lens laid
over the same diagram — under it, unchanged elements fade to neutral context
and only what changed keeps saturated color, so the change reads instantly
without losing its surroundings.
On a pull request
.github/workflows/pr-diagram.yml posts a component diff as a PR comment, so
reviewers see what a change did to the shape of the application without
installing anything. GitHub renders ```mermaid blocks natively, so there is
no image hosting involved. Copy the file into any repo with Python or
TypeScript in it — the only requirement is uvx on the runner.
It edits one comment rather than appending, says so in a single line when
nothing structural moved, and skips fork PRs (which get a read-only token)
rather than failing them. It deliberately does not use pull_request_target;
the reasoning is in docs/distribution.md §2.3.
Live server with hot reload
vizzle serve hosts the diagram and watches the source tree; every save
re-parses and pushes a reload to connected browsers (stdlib http.server +
server-sent events + watchfiles — no web framework). Your zoom/pan position
survives reloads.
uvx vizzle serve ~/code/repo/h # live class diagram
uvx vizzle serve ~/code/repo/h --diff --open # watch your working-tree
# changes vs HEAD reshape
# the UML as you edit
uvx vizzle serve ~/code/repo/h --type component --diff # live rewiring view
Defaults to http://127.0.0.1:8499/; see --port, --host, --base. The
server answers only requests addressed to this machine; --host 0.0.0.0
publishes the repository's structure to the network, and says so.
Useful flags (class and diff): --no-members, --modules (add a «module»
box per module holding its public module-level functions), --group-by module|component (mermaid namespace blocks per module or per component),
--externals (edges to types outside the parsed set), --direction LR
(mermaid), -I/-E include/exclude globs and -l language (every command; on
diff they apply to both revisions, so a filtered file never reads as added
or removed), --title, -f/--format mermaid|html. serve takes the same
selection flags plus --no-members, --modules, --externals and --title.
Render the .mmd output with mermaid-cli:
npx -y @mermaid-js/mermaid-cli -i changes.mmd -o changes.svg
Or let vizzle drive it, which is usually what you want:
uvx vizzle render changes.mmd out/ # one source
uvx vizzle render docs/diagrams out/ -f svg # a directory, README excluded
vizzle render finds mmdc on PATH or runs it through bunx/npx, points
puppeteer at a browser you already have rather than letting it download a
redundant one, and raises Mermaid's default 50,000-character maxTextSize —
past which a whole-repo diagram renders a small error graphic instead of
failing loudly. The HTML output has no such limit.
Committed diagrams that stay true
A Markdown file can carry a gen:c4-code manifest naming the classes its
diagram covers, or a source path to cover in full. vizzle doc regenerates
the fence from the code, and --check fails when the committed diagram has
drifted, which is the shape a lint step wants:
uvx vizzle doc docs/architecture.md # regenerate one document
uvx vizzle doc --dir docs --check # verify every managed doc, write nothing
The manifest format and what --check guarantees are in
docs/curated-diagrams.md.
How the diff works
vizzle diff asks git for the changed files (git diff --name-status -M -z),
pulls the base-revision contents via git show, and hands both revisions to
the Rust core. The core parses each side into a class graph, diffs the graphs
(classes keyed by qualified name, members fingerprinted by signature), and
renders a single diagram where every class and member carries its change
status.
Mermaid 11 quirk, learned the hard way: in
classDiagram,classDefstatements only take effect when they appear after thecssClassattachments. The renderer emits them last.
Development
uv sync # also installs dev tools (ruff, pre-commit)
uv run pre-commit install # one-time: enable the git hook
cargo test -p vizzle-core # core unit tests
uv run pytest packages/vizzle-cli/tests # CLI end-to-end tests
uv sync --reinstall-package vizzle # rebuild after Rust changes
Formatting and linting run on every commit via pre-commit: ruff format +
ruff check --fix (Python), cargo fmt + cargo clippy -D warnings (Rust),
plus whitespace/YAML/TOML hygiene checks. Run everything manually with
uv run pre-commit run --all-files. Vendored (assets/d3.*) and generated
(examples/) files are excluded.
JS dependencies (bun)
The d3 bundle inlined into HTML output is a real dependency managed with
bun in web/, then vendored into the Python package so
wheels stay self-contained:
cd web
bun install # or: bun update d3
bun run sync-assets # copies node_modules/d3/dist/d3.min.js into assets/
The vendored copy is committed; re-run sync-assets after bumping d3.
Example outputs generated from the h codebase live in examples/.
Metadata
Release files for vizzle 0.11.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| vizzle-0.11.0.tar.gz | 206.9 kB | With provenance | Details for vizzle-0.11.0.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| vizzle-0.11.0-cp310-abi3-manylinux_2_28_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ x86-64 | Details for vizzle-0.11.0-cp310-abi3-manylinux_2_28_x86_64.whl |
| vizzle-0.11.0-cp310-abi3-manylinux_2_28_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ ARM64 | Details for vizzle-0.11.0-cp310-abi3-manylinux_2_28_aarch64.whl |
| vizzle-0.11.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details for vizzle-0.11.0-cp310-abi3-macosx_11_0_arm64.whl |
| vizzle-0.11.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details for vizzle-0.11.0-cp310-abi3-macosx_10_12_x86_64.whl |
Total release size: 7.1 MB
Release files / vizzle-0.11.0.tar.gz
| Download URL | vizzle-0.11.0.tar.gz |
|---|---|
| Size | 206.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a36f375ae3a6bcced06653072101847a949f4219454ac6fada201ecd2ca5de49
|
|
BLAKE2b-256 checksum How to use checksums |
01a22fd331c3413aff3c137a94a418c2d277b6d4b1e13610907617c0e00c6ec2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / vizzle-0.11.0-cp310-abi3-manylinux_2_28_x86_64.whl
| Download URL | vizzle-0.11.0-cp310-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
f29343f9fcf95c2e3d4310e321093436009fe868d00d0da190d2751d179ae6c3
|
|
BLAKE2b-256 checksum How to use checksums |
662b74abbb6cdce79a4acb9704660791aeb7ab745a1b857d890aa1b2c279102d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / vizzle-0.11.0-cp310-abi3-manylinux_2_28_aarch64.whl
| Download URL | vizzle-0.11.0-cp310-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.7 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
6f92ea12768453a04556a56c9c9c385b3209c82cda93e98ada0554e46f3101a3
|
|
BLAKE2b-256 checksum How to use checksums |
c48e65cd88428b698bf9cf42c4af0216f81e8c1ad9dcba5ebd78892ead650385
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / vizzle-0.11.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | vizzle-0.11.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c3d013c98ba1e9db32c52a1343782474ee3f02a618d5489670c845baf22c4fd8
|
|
BLAKE2b-256 checksum How to use checksums |
b772a9252667e88da525f4b0cafcf962ebbaeee4d63d122b6268f8ae5b814929
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / vizzle-0.11.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | vizzle-0.11.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.7 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
7d084a6c2a783b56f06fd69746f984afe3396e7d5309286436150de6877e2fc4
|
|
BLAKE2b-256 checksum How to use checksums |
814770af0986585edf2c185c9ff347216c8c469a076abd0ba1762350f2fc1da1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logSecurity for vizzle 0.11.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 5 files in this release have been uploaded with provenance metadata.
Attestation for vizzle-0.11.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.