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

> Learn to parse and index any code repository with Code-Graph-RAG. This guide details how to transform source code into queryable knowledge graphs using AST extraction, graph construction, and Memgraph indexing.

- Repository: [Vitali Avagyan/code-graph-rag](https://github.com/vitali87/code-graph-rag)
- Tags: how-to-guide
- Published: 2026-08-11

---

**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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/.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`](https://github.com/vitali87/code-graph-rag/blob/main/graph_updater.py)).

After ingestion, the graph can be exported as JSON for offline analysis. The `GraphLoader` class in [`codebase_rag/graph_loader.py`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/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:

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

```

This command triggers the `start` entry point (lines 50-58 of [`cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/cli.py)), which validates the repository path and invokes `GraphUpdater.run(force=True)`.

### Incremental Updates

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

```bash
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:

```bash
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`](https://github.com/vitali87/code-graph-rag/blob/main/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:

```python
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`](https://github.com/vitali87/code-graph-rag/blob/main/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:

```python
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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/parser_loader.py) and [`ast_grep_tier.py`](https://github.com/vitali87/code-graph-rag/blob/main/ast_grep_tier.py).
- **Incremental indexing** skips unchanged files using hash caches stored in [`.hash_cache.json`](https://github.com/vitali87/code-graph-rag/blob/main/.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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/.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`](https://github.com/vitali87/code-graph-rag/blob/main/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.