Getting Started¶
This takes you from a checkout to a computed code graph: build Muundo, analyse a tree from Python, then do the same from the shell. About five minutes.
Nothing here reaches the network, runs a build system, or executes the code it reads. Muundo parses files with tree-sitter and reports what is in them.
1. Build it¶
Muundo is not on a package index yet, so you build it. The Rust crates need a stable toolchain; the Python binding needs maturin.
For the Python module:
If pyo3 says it cannot find a Python interpreter, point it at one explicitly — it otherwise resolves whatever a stale virtualenv on the path claims:
2. Analyse a tree from Python¶
import muundo
report = muundo.MuundoAnalyzer("./src", ["rust", "python"]).analyze()
print(len(report.entities), "entities")
for edge in report.call_edges[:5]:
print(edge.caller, "->", edge.callee)
The parse is the expensive part, so it runs once per MuundoAnalyzer and is
cached for that instance's lifetime. The options are fixed at construction:
build a new analyzer for a fresh analysis, which makes cache invalidation a
non-question.
Check is_complete before you trust a count. A graph that quietly drops
the files it failed on produces confident numbers about a subset, and nothing
tells the reader which subset.
Two fields say a report is partial, and checking one of them is not enough:
skipped_files— files that were never read. A parse failure, an undecodable byte, a path outside the root. Nothing about them is in the report: no entity, no call edge, no hash. Each entry carries areason_code— a stable token such asfile_too_largeorcontainment_escape— beside its sentence, so a program branches on the code and a person reads the sentence.partial_analysis— stages that stopped early on files that WERE read, because a configured limit was reached.
Neither implies the other. is_complete is both, so you do not have to
remember.
if not report.is_complete:
print("not read:", report.skipped_files)
print("stopped early:", report.partial_analysis)
3. The same from the shell¶
The command is muundo, with one subcommand per thing it computes.
That prints the version and the language names this build accepts. Then:
Every subcommand answers a single JSON object with ok and either data or an
error, so it pipes into jq without a mode flag.
4. Verify what an analysis read¶
An analysis records the hash of every file it parsed, and of the
tsconfig.json / jsconfig.json files that decided how its imports resolved —
plus, per source directory, where it looked for a nearer one and found nothing.
verify re-reads all of them AND re-runs the analysis, then tells you whether
the tree still matches:
./target/release/muundo analyze --root ./src > report.json
./target/release/muundo verify --report report.json --root ./src
verify does not only re-hash the files the report listed — it reproduces
the report. It rebuilds the analysis from the report's own configuration and
compares every source-derived field: entities, dependencies, metrics, scores,
hotspots, snippets and the file set. So it catches what a hash cannot — a metric
or snippet edited while the file's bytes were left alone, a source file added
since (never hashed because it is in no manifest), or one removed while its
claims remain. Any of those makes the verdict verified: false and names the
fields that diverged. This is what lets a finding be attributed to a specific
state of a tree rather than to "the code, at some point". Verify with the same
engine build that produced the report — reproduction needs it.
Next steps¶
- Reference — the languages, every field of a report, all six subcommands, the HTTP API and its limits
- Design decisions — the deliberate "no"s: things that look like missing features and are refusals on purpose