Svarupa
स्वरूप — "its own true form."
Svarupa reads a codebase and produces a verified map of it: a queryable knowledge graph plus six types of architecture diagram (architecture, module dependencies, data flow, request flow, deploy topology, ERD), delivered as one interactive HTML artifact. A type the evidence cannot produce is named as absent, never fabricated.
The defining constraint: every node and every edge in every diagram carries
file:line evidence, or it does not render. Not a heuristic guess, not a
model's plausible story. A claim you can click through to the source line that
proves it.
The name states the thesis. Svarupa is a thing's actual form, not its intended one. Architecture documents describe what someone meant to build. Svarupa renders what exists.
Status: alpha (v0.1.0). The evidence contract is stable; flags and output formats may still change between minor versions.
Quickstart
uv tool install svarupa # or: pipx install svarupa / pip install svarupa
svarupa . # scans the repo, writes .svarupa/
open .svarupa/index.html
That is the whole setup — no configuration file, no daemon, no account. The first run of a typical repository takes seconds.
python -m svarupa is the same command; --out ./map writes the artifact
somewhere other than <repo>/.svarupa/. The artifact holds:
index.html: every diagram type as a tab. Click a box for its passport (kind, connections, reach, cited source lines); double-click a drillable box, or click its chevron, to open it in place down to component and code level.graph.json: the knowledge graph.svarupa query <dir> get_node <label>,get_neighbors,shortest_path,affected,god_nodes,graph_stats,query_graph;svarupa mcp <dir>serves the same over MCP.REPORT.md: the resolution scorecard and every finding, with its code.- Declared environments (production, staging, qa, development) are extracted
with
file:lineevidence and surface in the CLI summary, a REPORT.md section,graph.jsonnodes, and a cited strip on the deploy topology. --lockwrites the committed architecture lockfile;--diffprints the architecture delta against a base lockfile.svarupa setup ci_github(orci_gitlab) installs the per-pull-request workflow.
Declared environments — production, staging, qa, development — are extracted
with file:line evidence and shown as a cited strip above the topology.
Why
Every tool in this space sits on one side of a divide and cannot cross it.
| Tool | Analyzes code | Draws formal diagrams |
|---|---|---|
| Graphify | Deeply, 25+ languages | No — force-directed node-link graphs only |
| Understand-Anything | Yes, AST + LLM | No — force layouts only |
| Archify | No — reads nothing | Yes, five types, excellent quality |
| Cocoon-AI | No — prompt-to-diagram | Yes, architecture only |
Nobody closes the loop code → AST → derived formal diagram. The analyzers
produce blobs; the drawers produce unverifiable pictures.
The larger thesis: continuous architecture governance
Graphify and Understand-Anything are onboarding tools. You run one when you join a project, look at the graph, and never open it again.
Because Svarupa's output is deterministic and evidence-backed, it runs in CI on every pull request: diff the architecture, comment the impact, fail the build on policy violations. Cross-language architecture linting is a category nobody occupies.
Architecture impact of #482
+ 2 components billing.refunds, billing.webhooks
+ 1 datastore redis (compose.yml:31)
! NEW DEPENDENCY billing -> auth.internal
via billing/refunds.py:44
+ 4 endpoints POST /refunds, GET /refunds/{id}, ...
Design principles
Fail-closed on evidence. An element without a source location is not emitted. When Python's dynamic dispatch means a call target cannot be pinned, no edge is written and the gap is counted in the report, rather than papered over with a plausible one.
Three-bin honesty. The resolution scorecard reports resolved, known-external, and unresolved-unknown. Counting every failure as "external" would launder resolver bugs into a number that looks like honesty.
Deterministic by contract. Same commit, same bytes, on any machine.
Canonical ordering, ==-pinned grammars, NFC-normalized paths, no timestamps,
no locale-dependent formatting. Verified in CI across Linux and macOS on Python
3.10 through 3.13 with PYTHONHASHSEED varied.
Identity comes from structure, not from clustering. Lockfile modules are directories, packages, and workspace members. Community detection is chaotically sensitive to input perturbation — measured: one added import flips 25-38% of community assignments — so it is used for visual grouping only and never reaches anything committed.
Measured, not assumed. Function-level sequence diagrams were cut after
measurement showed call resolution at ~20% on service code with median chain
depth 0-1. Replaying this repository's own real history (15 commits of actual
development: license swaps, viewer work, layout fixes) produced a median of
0 lockfile lines per commit — the diff moves only when the architecture
moves, not when code churns. See docs/reviews/ for the numbers and the
reasoning.
Development
uv sync
uv run pytest
uv run ruff check svarupa
uv run pyright svarupa
Design and review history:
docs/superpowers/specs/— the design, with a decision log carrying the reasoning behind each choicedocs/reviews/— adversarial reviews, raw and triaged. Every finding is marked Accepted, Rejected, or Deferred with a recorded why, because a rejected finding needs its reasoning kept just as much as an accepted one
License
MIT. See LICENSE.
Release files for svarupa 0.2.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 | |
|---|---|---|---|
| svarupa-0.2.0.tar.gz | 979.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| svarupa-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.3 MB
Release files / svarupa-0.2.0.tar.gz
| Download URL | svarupa-0.2.0.tar.gz |
|---|---|
| Size | 979.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3f70785d05906da1fea375d585512bb1e461a30c2c934023b0f2f543945fe5f7
|
|
BLAKE2b-256 checksum How to use checksums |
43ba0f69ccf2e72acc267cc2c53888c60f798ee2eed6cb01547f71e29f87ce45
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / svarupa-0.2.0-py3-none-any.whl
| Download URL | svarupa-0.2.0-py3-none-any.whl |
|---|---|
| Size | 287.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e66a4c95003a8484b3c8dd943bfe7e35294c46a00ed1e5b43a860bc10cc4a5d5
|
|
BLAKE2b-256 checksum How to use checksums |
0c337bb42a41f0aab51aa00978b9e80cae3b2b7c34013ef4190a99c952731623
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|