# How to Query Code Using Natural Language with Code-Graph-RAG

> Query code using natural language with Code-Graph-RAG. Ask questions in plain English and get precise answers from a live knowledge graph in Memgraph. Explore the vitali87/code-graph-rag repository.

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

---

**Code-Graph-RAG enables developers to ask questions about any codebase using plain English and receive precise, deterministic answers derived from a live knowledge graph stored in Memgraph.**

Code-Graph-RAG bridges the gap between human language and code analysis by combining Tree-sitter parsing with graph database technology. The open-source tool constructs a language-agnostic representation of your source code in Memgraph, then exposes both natural language interfaces and deterministic query APIs to explore relationships between symbols. Whether you need to find callers of a function or trace implementation hierarchies, the system translates your intent into optimized Cypher queries against the graph.

## Architecture of the Natural Language Query System

The foundation for querying code using natural language rests on a three-tier architecture that transforms raw source into a traversable graph. First, the Tree-sitter-powered parser in [`codebase_rag/graph_loader.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_loader.py) extracts every function, class, module, and their relationships from your repository. These entities populate a Memgraph database following a strict schema defined in [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py), creating nodes for symbols and edges for relationships like `CALLS`, `IMPLEMENTS`, and `IMPORTS`.

When you submit a natural language question, the RAG (Retrieval-Augmented Generation) layer either routes complex intent to an LLM for Cypher generation or executes pre-written deterministic queries for reproducible operations. The deterministic path guarantees identical results for questions like "find definition" or "list callers" by using optimized Cypher statements stored in [`codebase_rag/cypher_queries.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/cypher_queries.py).

## Core Query Functions in graph_query.py

The deterministic query engine lives in [`codebase_rag/graph_query.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_query.py), implementing direct interactions with the Memgraph backend. These functions provide the building blocks for both CLI usage and programmatic integration.

The **`resolve`** function (lines 41-90) maps a symbol name or `path:line` reference to its definition(s), handling ambiguous matches across the codebase. When you need complete source context, the **`definition`** function (lines 19-62) retrieves the file location, source snippet, docstring, and existence flag for any qualified name.

For relationship traversal, **`callers`** and **`callee`** (lines 21-41) walk `CALLS` edges to enumerate direct call sites, supporting depth parameters for transitive analysis. Additional utilities like **`implementors`**, **`overrides`**, **`importers`**, and **`tests_reaching`** (lines 43-85) expose inheritance hierarchies and test coverage paths through specialized Cypher patterns.

## Querying via the Command Line Interface

The `cgr graph` command group in [`codebase_rag/graph_cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_cli.py) exposes deterministic queries as JSON-encoded CLI tools. Each subcommand wires Click options directly to the corresponding function in [`graph_query.py`](https://github.com/vitali87/code-graph-rag/blob/main/graph_query.py): lines 63-77 handle `resolve`, lines 75-84 manage `definition`, and lines 97-108 process `callers`.

Resolve a symbol to its definitions:

```bash
cgr graph resolve "my_module:42"

```

Retrieve full source and documentation:

```bash
cgr graph definition my_pkg.utils.Helper

```

Find immediate callers with optional depth traversal:

```bash
cgr graph callers my_pkg.service.process_data --depth 3

```

Discover interface implementations:

```bash
cgr graph implementors my_pkg.interfaces.IWorker

```

Identify test files that reach specific symbols:

```bash
cgr graph tests-reaching my_pkg.core.CoreEngine

```

## Programmatic Python Integration

Embed queries directly into development tools by importing from `codebase_rag.graph_query`. This bypasses CLI overhead and allows custom result processing within Python scripts.

```python
from codebase_rag.graph_query import definition, callers

# fetch_all represents a Memgraph QueryFn obtained from connect_memgraph

def analyze_symbol(fetch_all, project, qualified_name, repo_root):
    # Get definition details including source and docstring

    def_info = definition(fetch_all, project, qualified_name, repo_root)
    
    # Find all callers up to depth 2

    call_sites = callers(fetch_all, project, qualified_name, depth=2)
    return def_info, call_sites

```

## Natural Language to Cypher Translation

While deterministic queries handle structured lookups, the natural language interface routes complex questions through an LLM that generates Cypher queries against the graph schema. This hybrid approach ensures that simple navigation commands remain reproducible while open-ended questions like "How does the authentication flow work?" leverage semantic understanding to compose multi-hop graph traversals.

The LLM receives context about the graph schema—node labels like `Function` and `Class`, relationship types such as `CALLS` and `IMPLEMENTS`—and produces parameterized Cypher that executes against Memgraph. Results return as structured JSON that the system renders as human-readable answers, maintaining traceability back to specific source locations in [`graph_loader.py`](https://github.com/vitali87/code-graph-rag/blob/main/graph_loader.py).

## Summary

- **Code-Graph-RAG** combines Tree-sitter parsing with Memgraph to create a queryable knowledge graph of your codebase.
- **Deterministic queries** in [`graph_query.py`](https://github.com/vitali87/code-graph-rag/blob/main/graph_query.py) provide reproducible results for navigation tasks without LLM variance.
- **CLI tools** via `cgr graph` expose resolution, definition lookup, caller analysis, and relationship traversal as JSON commands.
- **Python API** allows direct integration of graph queries into custom development tools and scripts.
- **Natural language interface** translates English questions into Cypher for complex exploratory analysis while maintaining precision for simple lookups.

## Frequently Asked Questions

### What database does Code-Graph-RAG use to store the code graph?

Code-Graph-RAG uses **Memgraph** as its backend graph database. The system stores parsed symbols as nodes and their relationships (calls, implementations, imports) as typed edges, enabling efficient traversal queries through Cypher according to the schema defined in [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py).

### How does the system handle ambiguous symbol names?

The `resolve` function in [`codebase_rag/graph_query.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_query.py) handles ambiguity by accepting either a qualified name or a `path:line` coordinate. When multiple definitions exist, it returns all candidates with their respective file locations and existence flags, allowing downstream tools to disambiguate based on context.

### Can I use Code-Graph-RAG without an LLM for deterministic results?

Yes. The deterministic query layer in [`graph_query.py`](https://github.com/vitali87/code-graph-rag/blob/main/graph_query.py) executes pre-written Cypher statements directly against Memgraph for operations like finding definitions, callers, or implementations. These functions bypass the LLM entirely, ensuring consistent, reproducible results ideal for CI/CD pipelines and automated analysis.

### What languages does the parser support?

The parser utilizes **Tree-sitter**, which supports multiple programming languages including Python, JavaScript, TypeScript, Java, C, and C++. The graph schema in [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py) remains language-agnostic, representing concepts like functions, classes, and modules uniformly regardless of source language.