Every engineering team organises their codebase into folders, packages, and services. These are the declared modules, the ones in your architecture docs and on your team's Confluence page. But codebases also have emergent modules: clusters of files that, regardless of their declared organisation, behave as a single unit because they import each other densely and are loosely coupled to everything else.
These emergent clusters are what graph theory calls communities. Finding them is one of the most structurally revealing things you can do with a codebase.
Why declared modules drift from actual structure
Codebases grow organically. A file gets added to utils/ because it's small. It gets imported by five things. Someone adds a helper that only that utility needs. Now utils/ has a hidden sub-community: two files that belong together and could be extracted, but are obscured by the top-level folder name.
This drift is not a failure of engineering discipline, it is an inevitable consequence of code evolving faster than architecture gets updated. Community detection finds the drift automatically, at commit time, without requiring anyone to update a diagram.
What the Leiden algorithm finds in code
The Leiden algorithm (an improvement on Louvain) finds communities by maximising modularity: the fraction of edges inside communities versus the fraction you'd expect from a random graph. Applied to an import graph, it finds groups of files that import each other frequently and import files outside the group rarely.
The result is not a folder structure, it is a structural reality. Files in the same Leiden community belong together architecturally, even if they live in different folders. Files in different communities are loosely coupled, even if they're neighbours in the file tree.
What this reveals in practice
Hidden god objects: files that bridge multiple communities are architectural pivot points. They have high betweenness centrality, everything routes through them. These are the files that, if they break, break everything.
Extract candidates: tight sub-communities within a larger community are often extractable packages. The algorithm finds the seam for you.
Team boundary mismatches: when a community spans multiple team ownerships, you've found a coordination bottleneck. Every change in that community requires cross-team review. Decomposing along community boundaries reduces coordination overhead.
Dead weight: files that don't belong to any community (or form singleton communities) are often candidates for deletion or consolidation.
Spiderbrain's community layer
Spiderbrain builds the Leiden community partition at brain-construction time. Every node in the graph has a community ID. Community membership drives several downstream features:
- Blast radius scope: changes within a community are lower risk than changes that cross community boundaries
- Context selection: when building AI context for a question, community membership is used to select structurally related files
- Governance tracking: community boundaries are stable across commits; drifting community membership signals structural churn
The community layer is deterministic, same codebase state, same partition. This makes it usable in CI pipelines and for longitudinal tracking.
Starting with community detection
You do not need a perfect architecture to benefit from community detection. Run it on your codebase today and you will find:
- Your biggest community (the monolith kernel nobody has extracted yet)
- Your tightest community (the one that would be the cleanest package)
- Your most pivotal file (the one bridging the most communities)
Those three findings are a refactoring roadmap.
