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 — 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.7–0.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–10 nodes and
takes under 30 seconds.
get_dead_code
Tiered refactor plan for unused code — high/medium/low confidence findings with per-directory rollups, ownership hotspots, and safe-to-delete impact estimates. Pure graph + SQL, no LLM calls.
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.