A typed code graph

A structural claim about code has to be computed.

Muundo parses a source tree with tree-sitter and returns what is actually there: entities, the calls between them, per-entity metrics, dependencies and reachability. No language server, no build, no network — it reads the files.

Apache‑2.0 · thirteen grammars over twelve languages · nothing leaves the machine

one entity, from a report
entitysearch.py::SearchCoordinator.build
callsdigest · hash_of · Cache.get
complexity7
fan_in3
and : every number here came from the parse tree, so it can be recomputed and checked

What it is

A model answers. A graph shows.

Ask a model whether a function is recursive and it will tell you something. Ask the graph and it points at the edge.

That difference is the whole reason this exists. A finding that is going to be attributed to a clause of a standard, and shown to somebody who audits for a living, cannot rest on a plausible sentence. It has to rest on something a second party can recompute from the same files and get the same answer.

So Muundo computes. It parses each file with tree-sitter — the same parser an editor uses for syntax highlighting, which means no build system, no dependency resolution and no running of your code — and turns the trees into a report you can read, diff and store.

Muundo is Swahili for structure.

Entities and the calls between them

Every function, method, class and module the tree declares, each with its file and line, and an edge for every call that resolves.

Metrics per entity

Cyclomatic complexity, fan-in and fan-out, nesting depth — computed from the tree rather than estimated from line counts.

Reachability

Which entities are reachable from the entry points, and which are not. Dead code is a graph question, and this answers it as one.

What was read

The hash of every file the analysis parsed. verify re-reads the tree and says whether it still matches.

Languages

Thirteen grammars over twelve languages.

Ada and C are not decoration. They are what avionics, rail and medical device code is written in, and they are usually the languages an analysis tool skips.

CC++C#AdaRustGoJavaKotlinPythonJavaScriptTypeScriptTSXYAML

Thirteen grammars, twelve languages: typescript and tsx are separate tree-sitter grammars for one language, which is why the two counts differ. A build can be compiled with fewer; muundo info prints the ones yours accepts.

Every field the report has is filled by every extractor whose language has the construct. That rule is checked by a fixture that writes one function in each language and reads what comes back — because an unfilled field and an absent construct look identical from the outside, and both are empty.

Use it

A library, a command, and an HTTP server.

It is not on a package index yet, so you build it. A stable Rust toolchain is enough for the command; the Python module needs maturin.

From the shell

cargo build --release --workspace

./target/release/muundo analyze --root ./src > report.json
./target/release/muundo verify --report report.json --root ./src

analyze, metrics, fragility, hotspots, verify and info.

From Python

report = muundo.MuundoAnalyzer(
    "./src", ["c", "cpp"]
).analyze()

for edge in report.call_edges:
    print(edge.caller, "->", edge.callee)

The parse is expensive, so it runs once per analyser and is cached for that instance's lifetime. Build a new one for a fresh analysis.

Completeness

Read these two fields before quoting a count.

A graph that quietly drops what it failed on produces confident numbers about a subset, and nothing tells the reader which subset.

A report is complete only when skipped_files and partial_analysis are both empty, and they mean different things. The first lists whole files that were never read. The second lists stages that stopped early on files that were. Either one on its own makes every number in the report a number over a subset.

if not report.is_complete:
    print("not read:", report.skipped_files)
    print("stopped early:", report.partial_analysis)

Nothing is dropped silently and nothing is rounded up. That is the claim worth checking, and it is the one the rest of the report depends on.

Limits

What it will not do.

Each of these looks like a missing feature and is a refusal on purpose. Doing better would mean either executing your code or building a full language-semantics engine, and both are somebody else's job.

It does not run your code

Everything comes from the parse tree. A call reached only through reflection, a dynamic import or a string dispatch is not an edge, because statically it is not one.

Imports resolve statically

A path a build system rewrites, an alias defined in a bundler config, a wildcard re-export — the resolver says what it can prove from the files and stops there.

Overloads stay merged

Two methods with one name are one entity. Splitting them needs type resolution, and a consumer that has types can split them itself.

It labels nothing as safe

There is no "this function sanitises" flag. Whether a function makes a value safe depends on where it is going, which the graph does not know.

The reasoning behind each one, and the ones that came and were reverted, is written down in the design decisions.

Licence

Apache-2.0. There is nothing to buy.

No licence key, no tier, no telemetry, no account. Read it, run it, fork it, ship it inside something you sell.

Questions and defects go to the issue tracker, which is where the answers are written down and stay readable. Muundo is one of several tools built here; the others are named below, and some of them are sold.

Jagora — build the whole application Litatoli — the evidence layer Sawabona — licensing and payments Kumbukumbu — auditable memory and RAG Pimatika — the egress judge NaZelo — critical software, run under controlled adversity

Manage your subscription

Change plan, update your payment card, or download your invoices. We will email you a link — your inbox is what proves the account is yours.

Talk to us

We read every message. Expect an answer within a working day.

Sales open on 9 September 2026

A date rather than "soon", because you are deciding whether to wait. Everything else — the plans, the prices, the licence you would receive — is exactly what will be on sale that day.

Nothing has been charged and no account has been created. If you would like to be told the morning it opens, use the contact link at the bottom of this page.

Start

You will be taken to our payment provider. Nothing is charged until you confirm there.

Your sign-in and your licence both go to this address. Check it — a typo here is an account you cannot open.

Search this site

Answers are passages from these pages, with a link to where each one is. Nothing is generated, so nothing is invented.