Code Dependency Mapping and Architecture Maps

Every codebase has a shape nobody wrote down. Someone on the team knows that billing reaches into the user module through two helpers, and that one of those helpers is called from a webhook handler nobody has opened in a year. When that person is on holiday, everyone else greps. Dependency mapping is the work of making that shape explicit: which code calls which, how far a change travels, and where the seams actually sit.

What dependency mapping across a codebase means

The phrase covers two different jobs that get mixed up constantly. The first is package dependency mapping: your lockfile, the third-party libraries you pull in, the vulnerability report. Plenty of tools do that, and all of them stop at the package boundary. The second is dependency mapping inside code you wrote: this function calls that one, this class implements that interface, this HTTP route ends up in this handler, this service imports a type that lives in a different repository.

The second job is the one that decides whether a change is safe to make. It is also the one that goes stale fastest, because it changes with every merge. A diagram drawn in a workshop last quarter describes a system that no longer exists. A map worth having gets rebuilt from the code on every index, so what you read is what compiles.

Why folder structure and grep undersell it

A folder tree tells you where files were filed. Directory layout follows team habits, historical refactors, and whoever set up the repo, and it says nothing about which module calls which at runtime. Two files sitting in the same directory can share no code path at all, while a single import can bind two directories at opposite ends of the tree.

Grep gets closer, because it reads the code, then fails in both directions at once. It matches strings, so a search for formatCurrency returns comments, docs, a changelog entry, and a local variable that happens to share the name. And it misses real calls: when the call site goes through an interface method named format and the concrete implementation is formatCurrency, no string search will ever connect them. You get noise to read and calls you cannot see, from the same query. In a second repository, the search does not run at all.

What the graph stores

Symvanta parses each repository into nodes and edges. A node is a symbol: a function, class, interface, struct, enum, HTTP endpoint, or test case. An edge is a relationship the parser saw, such as calls, imports, contains, references, plus type-hierarchy edges that keep each language's own vocabulary (extends in TypeScript, implements in Java, conforms_to in Swift, impl_trait in Rust, embeds_interface in Go, uses_trait in PHP, include in Ruby). Eleven languages parse today: TypeScript, JavaScript, Python, Java, Kotlin, C#, Go, Rust, Swift, PHP, and Ruby.

Edges carry a confidence tier, and the tier ships with the answer. High means a compiler-grade index resolved the symbol. Medium is a framework or heuristic match. Low is a string heuristic. Correlational means the two symbols keep changing together in git history, which is a lead worth checking and nothing stronger. A map that hides its own uncertainty invites you to trust the weakest line on it.

Once the edges exist, the questions get cheap. The callers of a symbol are the edges pointing at it. Its dependencies are the edges leaving it. Blast radius is a recursive walk up the caller edges, capped so the answer comes back inside one tool call, which turns "what breaks if I change this" into a list of symbols and files. That walk crosses repository boundaries when a project holds more than one repo, which is exactly where a hand-drawn map gives up. We wrote the long version of that argument in what breaks when you change a function and blast radius analysis.

From symbols to an architecture map

Symbol-level edges answer local questions well and drown you at repository scale. A million-edge graph printed as a graph is a hairball. So the same edges get clustered: Louvain community detection groups symbols into modules by how densely they call each other, and PageRank picks out the hub symbol inside each module. What comes back is a map at the altitude people actually reason about, a few dozen functional modules with call-weighted arrows between them, derived from call behavior and frequently disagreeing with the directory layout.

You can read the output before indexing anything. The architecture library runs this over public repositories and publishes the result: prisma/prisma resolves into 66 modules at modularity Q=0.84, with a module map diagram, the load-bearing symbols to read first, and the commit each snapshot came from. Same pipeline, same clustering, on repositories you can go check by hand.

The map is built for an agent to query

Codebase architecture visualization usually means a picture for a human. A picture is useful once a quarter. The reader that needs this map every few minutes is the coding agent in your editor, and it cannot read a PNG.

Symvanta gives your AI coding agent your codebase's real call graph over MCP, so it stops guessing and knows what breaks before it edits. Every part of the map is a tool call: resolve a symbol to its file and signature, list its callers or dependencies, ask what implements an interface, trace the path between two symbols, look up an HTTP route by method and path, pull the module map, or ask a behavior question and get an answer with citations. Claude Code, Cursor, Windsurf, Codex, Zed, and any other MCP client call the same tools.

That changes the ordering of a session. The agent asks for the blast radius before it writes the edit, so a rename that reaches fourteen call sites across three repositories shows up as a list at planning time instead of a red build twenty minutes later. Reads follow tracked feature branches, and uncommitted working-tree edits can be overlaid on the graph, so the map matches the code in front of you.

Where a dependency map earns its keep

Onboarding, where a new engineer gets the module map and the hub symbols in each module instead of a two-week tour. Refactors, where the argument about scope gets settled by a caller list. Incidents, where the question is which callers reach the failing function. Reviews of agent-written diffs, where the reviewer needs to know what the agent did not look at. Each one is the same query at a different altitude.

Point Symvanta at a repository and the first index gives you the symbol graph, the callers, the blast radius, and the module map, over MCP and in the dashboard. Book a walkthrough and we will run it against your codebase, on a call, with your own repositories.

See Symvanta on your own codebase →