How Louvain Community Detection Discovers Functional Modules in Codebase-Memory-MCP
Codebase-Memory-MCP employs a multi-level Leiden algorithm—a refined variant of Louvain community detection—to partition a software project's call graph into cohesive functional modules by optimizing modularity.
Codebase-Memory-MCP analyzes software architecture by modeling codebases as directed graphs where functions, methods, and classes represent nodes and call relationships form edges. By applying Louvain community detection through the Leiden algorithm implementation, the system automatically discovers functional modules that reflect natural architectural boundaries in your source code.
Modeling Code as a Call Graph
The foundation of module discovery begins with graph construction. In src/store/store.c, the arch_clusters routine selects all nodes labeled as Function, Method, or Class by querying the internal database (lines 5290–5293).
The system then extracts computational relationships by querying the edges table for rows where type='CALLS' and both endpoints belong to the selected node set (lines 5439–5450). This produces a CSR-style edge list encoded as cbm_louvain_edge_t structures, representing the directed call relationships between code elements.
The Leiden Algorithm Pipeline
Once the call graph is constructed, Codebase-Memory-MCP executes the Leiden algorithm through the cbm_leiden wrapper (declared in src/store/store.h lines 638–640 and implemented in src/store/store.c lines 5152–5155). This modern variant of Louvain community detection proceeds through three repeating phases until convergence:
Local Moving Phase
Each node evaluates neighboring communities and moves to the one yielding the highest modularity gain. This optimization targets the resolution-adjusted modularity metric to ensure statistically significant groupings.
Refinement Phase
The algorithm guarantees that every resulting community remains internally connected. This step is crucial for producing coherent functional modules where every member can reach every other member through internal call paths.
Aggregation Phase
Each identified community contracts into a super-node, creating a coarser graph. The process then repeats on this reduced graph, enabling multi-level community detection that adapts to both fine-grained and coarse architectural patterns.
This implementation follows the reference algorithm by Traag, Waltman, and van Eck (2019) as specified in src/store/store.c.
Post-Processing and Module Extraction
After community detection converges, arch_clusters computes per-community statistics to rank and label the discovered modules. For each community, the system calculates:
- Cohesion score: The ratio of internal edges to total edges (internal + boundary), computed at lines 5422–5424 in
src/store/store.c - Member count: Total nodes belonging to the community
- Representative label: Derived from the most frequent package name among members
- Key nodes: Top-degree nodes that serve as entry points
The system returns the top 12 communities (configurable) containing at least two members as the final functional modules (lines 5408–5429).
Practical Implementation
C API Integration
Developers can invoke the module discovery pipeline directly using the cbm_store_get_architecture function:
cbm_store_t *store = cbm_store_open("my_project.db");
cbm_architecture_info_t arch;
/* Discover functional modules for the whole project */
int rc = cbm_store_get_architecture(
store, /* store handle */
"my_project", /* project name */
NULL, /* path = NULL → whole project */
NULL, 0, /* aspects = NULL → all aspects */
&arch); /* output */
if (rc == CBM_STORE_OK) {
for (int i = 0; i < arch.cluster_count; ++i) {
const cbm_cluster_info_t *c = &arch.clusters[i];
printf("Module %d: %d members, cohesion %.2f, label %s\n",
c->id, c->members, c->cohesion, c->label);
}
}
cbm_store_close(store);
Command-Line Interface
For CLI usage, the PyPI package provides a convenience wrapper:
$ codebase-mcp-get-architecture \
--project my_project \
--store my_project.db \
--aspects all
This command ultimately calls cbm_store_get_architecture, executing the same Louvain/Leiden pipeline described above.
Key Source Files
The implementation spans several critical files in the repository:
src/store/store.h: Declares the public API forcbm_louvain,cbm_leiden, and related data types includingcbm_cluster_info_tsrc/store/store.c: Contains the full Leiden algorithm implementation, thecbm_louvainwrapper, and thearch_clustersorchestratorsrc/mcp/mcp.c: High-level command-line dispatcher that routes to the architecture extraction functionstests/test_store_arch.c: Unit tests validating the community detection flow and module output
Summary
- Graph Representation: Codebase-Memory-MCP models software as a call graph where functions, methods, and classes are nodes connected by
CALLSrelationships. - Algorithm: The system uses the Leiden algorithm, a modern refinement of Louvain community detection, to optimize modularity through local moving, refinement, and aggregation phases.
- Implementation: Core functions reside in
src/store/store.c, witharch_clustersorchestrating the pipeline andcbm_leidenexecuting the detection. - Output: Results include cohesion scores, member counts, and package-derived labels, returning the top 12 valid communities as functional modules.
- Resolution Control: The API exposes a resolution parameter to bias granularity, allowing detection of either fine-grained or coarse architectural modules.
Frequently Asked Questions
What is the difference between the Louvain and Leiden algorithms in this implementation?
The Leiden algorithm guarantees that all communities are internally connected and typically converges faster than the classic Louvain method. In Codebase-Memory-MCP, cbm_leiden implements the Traag et al. (2019) variant, which adds a refinement phase between local moving and aggregation to ensure well-connected modules, producing more coherent functional groupings than standard Louvain optimization.
How does the system determine the quality of a discovered module?
The system calculates a cohesion score defined as internal edges divided by the sum of internal and boundary edges. This metric, computed in src/store/store.c at lines 5422–5424, quantifies how tightly knit a module is; higher values indicate stronger internal coupling and clearer separation from other modules.
Can I adjust the granularity of the detected modules?
Yes. The cbm_leiden API exposes a resolution parameter that allows you to bias the granularity of community detection. Higher resolution values produce smaller, more numerous modules, while lower values yield larger, more encompassing functional groups, enabling analysis at different architectural zoom levels.
Why are only Function, Method, and Class nodes included in the analysis?
The arch_clusters routine specifically filters for these node types to focus on executable code units that exhibit meaningful call relationships. This filtering occurs in src/store/store.c (lines 5290–5293) and ensures that the Louvain community detection operates on the functional structure of the codebase rather than non-executable elements like comments or documentation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →