Dependency graph
How repowise builds the two-tier dependency graph (file nodes and symbol nodes) with import resolution, call resolution, heritage extraction, and community detection.
The dependency graph is the foundation everything else sits on. Risk analysis, dead-code detection, blast radius, even the wiki itself: all of it walks the graph repowise builds at index time.
Two tiers, one graph
Tree-sitter parses every file in the repo into:
- File nodes: one per source file, with imports / imported-by edges.
- Symbol nodes: one per function, class, method, with caller / callee edges.
Both tiers live in a single NetworkX graph. You can traverse from file to file, file to symbol, or symbol to symbol in a single query.
Three-tier call resolution
Naive call resolution is "the function name matched a definition somewhere, so link them." That approach is wrong about 30% of the time on real codebases (overloads, name collisions, dynamic dispatch). Repowise uses three tiers with confidence scoring:
- Exact: the import or namespace path uniquely identifies the
target. Confidence
1.0. - Heuristic: name match plus contextual signals (file proximity,
import direction, framework conventions). Confidence
0.7to0.95. - Fallback: name-only match, surfaced for review with low
confidence (
< 0.7).
The MCP get_context tool filters callers/callees to confidence
≥ 0.7 by default: high-precision over recall.
What the resolvers handle
- Import aliases (
import foo as bar) - Barrel re-exports (
export * from "./x") - Namespace imports (
import * as Foo) - Path-mapped imports (TypeScript
tsconfig.jsonpaths, C#.csproj, Gogo.modreplace directives, RustCargo.tomlworkspace members) - Heritage: extends, implements, trait impls, derive macros, mixins, Swift extension conformance
- Framework-aware edges (Django routes, FastAPI dependency injection,
Spring
@Componentgraphs, Express routers, Rails Zeitwerk)
Per-language detail: Language support.
On top of the graph
The graph alone isn't intelligence; it's data. Repowise computes:
- PageRank: global importance ranking.
get_context(include=["metrics"])surfaces this per file. - Betweenness centrality: files on many critical paths.
- In/out degree: direct dependents and dependencies.
- Strongly connected components: circular import groups.
- Leiden community detection: logical modules even when your directory structure doesn't reflect them. Each community gets a cohesion score and a label drawn from its most-common path segment.
- Execution flow tracing: from each natural entry point, follow the call graph and rank what's reached.
All of these are exposed through get_overview,
get_context, and get_risk.
Refreshing
repowise update rebuilds only the slice of the graph affected by
changed files (incremental). A typical commit affects 3 to 10 nodes and
takes under 30 seconds.
generate_refactoring_code
Turns one structured refactoring plan from get_health(include=["refactoring"]) into generated code and a unified diff, grounded on the plan plus the real source it references.
Git history & co-changes
Hotspots, ownership, bus factor, and co-change pairs, the signals repowise mines from your last 500 commits that no AST analysis can produce.