How to Parse and Index a Code Repository with Code-Graph-RAG: A Complete Guide

Code-Graph-RAG transforms multi-language source trees into queryable knowledge graphs through a three-stage pipeline of AST extraction, graph construction, and incremental indexing backed by Memgraph.

The vitali87/code-graph-rag toolkit enables you to parse and index a code repository with Code-Graph-RAG by orchestrating Tree-sitter parsers, multi-pass graph construction, and persistent storage layers. This system processes everything from Python and Rust to C# and PHP, creating a unified knowledge graph that supports both natural language queries and programmatic exploration.

The Three-Stage Parsing Pipeline

Stage 1: Repository Scanning and AST Extraction

In codebase_rag/graph_updater.py, the run method (lines 14-30) drives the initial parsing phase. The system walks every supported file in your repository and generates abstract syntax trees using Tree-sitter parsers or the fallback ast-grep tier for languages without native Tree-sitter specifications.

The parsing front-ends include language-specific implementations such as libclang for C/C++ and Roslyn for C#. For languages like Ruby that lack Tree-sitter support, the system falls back to codebase_rag/parsers/ast_grep_tier.py, which provides pattern-based structural parsing.

Stage 2: Graph Construction and Multi-Pass Ingestion

The GraphUpdater builds the knowledge graph through three distinct passes, as implemented in lines 49-82 of graph_updater.py:

  • Pass 1 identifies module-level structure across the codebase.
  • Pass 2 parses individual files and emits definitions with structural edges.
  • Pass 3 resolves function calls and higher-level relationships such as inheritance and data-flow.

Nodes (functions, classes, modules) and relationships (calls, imports) are streamed to Memgraph via the IngestorProtocol. The MemgraphIngestor wrapper in codebase_rag/services/graph_service.py handles batch insertion with configurable batch sizes.

Stage 3: Incremental Indexing and Persistence

For incremental builds, the system compares file hashes stored in .hash_cache.json against current file states, skipping unchanged files to avoid redundant processing. When performing an incremental update, the function registry is re-hydrated from the existing Memgraph graph rather than rebuilt from scratch (lines 34-44 of graph_updater.py).

After ingestion, the graph can be exported as JSON for offline analysis. The GraphLoader class in codebase_rag/graph_loader.py (lines 15-33) reads these exports and builds in-memory indexes including nodes by label and property look-ups.

Command-Line Interface for Repository Indexing

The CLI entry point in codebase_rag/cli.py provides direct access to the parsing pipeline.

Full Repository Build

To parse an entire repository from scratch, deleting any existing graph data:

cgr start --repo-path /path/to/my/project --update-graph --clean

This command triggers the start entry point (lines 50-58 of cli.py), which validates the repository path and invokes GraphUpdater.run(force=True).

Incremental Updates

To update only changed files, omit the --clean flag:

cgr start --repo-path /path/to/my/project --update-graph

The system checks file hashes and only re-parses modified files, reusing cached ASTs for unchanged components.

Exporting to JSON

To export the constructed graph for offline use:

cgr start --repo-path /path/to/my/project --update-graph -o graph.json

The -o/--output flag invokes export_graph_to_file (lines 22-31 of cli.py), writing the complete graph structure to the specified JSON file.

Programmatic Access with the Python SDK

Loading and Exploring Exported Graphs

After exporting, use the Python SDK to analyze the graph without a running database:

from codebase_rag.graph_loader import load_graph

graph = load_graph("graph.json")
summary = graph.summary()
print(f"Nodes: {summary.total_nodes}, Relationships: {summary.total_relationships}")

# List the first five functions

for fn in graph.find_nodes_by_label("Function")[:5]:
    print(f"{fn.properties['name']} ({fn.node_id})")

The load_graph function creates a GraphLoader instance (lines 48-61 of graph_loader.py) that builds searchable indexes from the JSON export, enabling efficient node retrieval via find_nodes_by_label and relationship traversal via get_relationships_for_node.

Querying Live Memgraph Instances

For natural language queries against a live database:

from codebase_rag.sdk.cypher_generator import CypherGenerator
from codebase_rag.services.graph_service import MemgraphIngestor
from codebase_rag.config import settings

ingestor = MemgraphIngestor(
    host=settings.MEMGRAPH_HOST,
    port=settings.MEMGRAPH_PORT,
    batch_size=5000,
    username=settings.MEMGRAPH_USERNAME,
    password=settings.MEMGRAPH_PASSWORD,
)

cypher = CypherGenerator().generate(
    "Show all classes that contain 'User' in their name"
)
results = ingestor.fetch_all(cypher, {})
for row in results:
    print(row["name"])

The CypherGenerator translates natural language prompts into Cypher queries, executed by the MemgraphIngestor against the indexed graph.

Summary

  • Code-Graph-RAG uses a three-stage pipeline in graph_updater.py to parse and index a code repository with Code-Graph-RAG: AST extraction, multi-pass graph construction, and persistence.
  • Tree-sitter and ast-grep handle language parsing across Python, TypeScript, Rust, Go, Java, C/C++, C#, PHP, Lua, Dart, and Ruby via parser_loader.py and ast_grep_tier.py.
  • Incremental indexing skips unchanged files using hash caches stored in .hash_cache.json and re-hydrates the function registry from Memgraph during updates.
  • CLI commands (cgr start with --update-graph and optional --clean) trigger full or incremental builds, with JSON export support via -o.
  • Python SDK provides GraphLoader for offline JSON analysis and CypherGenerator for natural language querying of live Memgraph instances.

Frequently Asked Questions

What programming languages does Code-Graph-RAG support?

Code-Graph-RAG supports Python, TypeScript, Rust, Go, Java, C/C++, C#, PHP, Lua, and Dart through Tree-sitter parsers loaded via parser_loader.py. For languages without Tree-sitter specifications, such as Ruby, the system falls back to the ast-grep tier implemented in codebase_rag/parsers/ast_grep_tier.py, which uses pattern-based structural parsing to extract code relationships.

How does incremental indexing avoid re-parsing unchanged files?

The system stores file hashes in .hash_cache.json and compares them against current file states before each run. When you omit the --clean flag from CLI commands, GraphUpdater.run checks these hashes and skips files that haven't changed, while re-hydrating the function registry from the existing Memgraph graph to maintain reference integrity without redundant AST generation.

Can I use Code-Graph-RAG without running Memgraph?

Yes. While the live querying features require a Memgraph instance, you can export the graph to JSON using the -o flag and analyze it offline. The GraphLoader class in codebase_rag/graph_loader.py reads these JSON exports and builds in-memory indexes, providing methods like find_nodes_by_label and get_relationships_for_node without database connectivity.

What is the difference between the three parsing passes?

Pass 1 identifies module-level structures across the entire codebase to establish the graph skeleton. Pass 2 parses individual source files to emit concrete definitions (functions, classes) and structural edges. Pass 3 resolves dynamic relationships such as function calls, inheritance chains, and data-flow dependencies that require cross-file analysis, completing the knowledge graph construction before ingestion into Memgraph.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →