# How to Set the C++ Frontend for Code-Graph-RAG: Three Methods Explained

> Learn how to set the C++ frontend for code-graph-rag using CLI flags, environment variables, or Python API. Explore Tree-sitter, Hybrid, and Libclang parsing options.

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

---

**You can set the C++ frontend for code-graph-rag via the `--cpp-frontend` CLI flag, the `CPP_FRONTEND` environment variable, or programmatically using the `GraphUpdater.set_frontend()` Python API, choosing between Tree-sitter, Hybrid (default), or Libclang parsing engines.**

Code-graph-rag supports three interchangeable C++ frontends that determine how source files are parsed and indexed into the knowledge graph. Selecting the correct parser affects how qualified names, macro expansions, and `#include` imports are emitted, with each engine offering different trade-offs between speed and semantic accuracy.

## Understanding the Three C++ Frontend Options

According to the [`parsers/cpp_frontend/frontend.py`](https://github.com/vitali87/code-graph-rag/blob/main/parsers/cpp_frontend/frontend.py) implementation, code-graph-rag provides three distinct parsing strategies:

### Tree-sitter Frontend (Pure)

The **Tree-sitter** frontend uses a pure Tree-sitter parser without C++-specific analysis. In the current architecture, this parser is available but the frontend itself is **never executed** during normal operation. It exists primarily for debugging scenarios where you want to avoid libclang entirely or need a language-agnostic baseline.

### Hybrid Frontend (Default)

The **Hybrid** frontend is the recommended and default configuration. As implemented in the `HybridFrontend` class, this engine runs **after** the Tree-sitter definition pass (`AFTER_DEFINITIONS`). It layers macro-expanded `Function` nodes and `#include` imports on top of spans already produced by Tree-sitter, combining the speed of Tree-sitter with the semantic depth of libclang.

### Libclang Frontend

The **Libclang** frontend provides direct libclang parsing without Tree-sitter preprocessing. This engine runs **before** the definition pass (`BEFORE_DEFINITIONS`) and is best when you need full C++ type resolution and want to skip the Tree-sitter pass entirely. Use this when semantic accuracy outweighs indexing speed.

## How to Set the C++ Frontend in Code-Graph-RAG

The frontend selection mechanism is centralized in [`parsers/cpp_frontend/__init__.py`](https://github.com/vitali87/code-graph-rag/blob/main/parsers/cpp_frontend/__init__.py), which exposes `cpp_frontend_available()` and the dispatcher `run_cpp_frontend()`. The configuration is read from [`codebase_rag/config.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/config.py) and parsed from [`codebase_rag/workspaces/cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/workspaces/cli.py).

### Command-Line Interface (CLI)

The most direct method uses the `--cpp-frontend` flag when invoking the `cgr` command:

```bash

# Use the libclang front-end for a repository

cgr start --repo-path /path/to/project --cpp-frontend libclang

```

Valid options are `tree-sitter`, `hybrid`, or `libclang`. Omitting the flag defaults to the Hybrid frontend.

### Environment Variable Configuration

Set the `CPP_FRONTEND` environment variable to establish a fallback mode when the CLI flag is omitted:

```bash
export CPP_FRONTEND=hybrid
cgr start --repo-path /some/dir

```

The configuration loader in [`codebase_rag/config.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/config.py) checks this variable during initialization.

### Python API

For programmatic control within a Python process, instantiate `GraphUpdater` and call `set_frontend()`:

```python
from codebase_rag.graph_updater import GraphUpdater

gu = GraphUpdater()
gu.set_frontend('cpp', 'libclang')   # Options: 'tree-sitter', 'hybrid', 'libclang'

gu.update_graph(repo_path="/my/cpp/project")

```

This changes the frontend for subsequent `run_cpp_frontend()` calls within the same process.

## Critical Execution Order Considerations

The frontend choice affects pipeline execution timing. According to the test suite in [`tests/test_cpp_frontend_wiring.py`](https://github.com/vitali87/code-graph-rag/blob/main/tests/test_cpp_frontend_wiring.py), the **Hybrid** frontend expects that Tree-sitter has already produced definition spans (`AFTER_DEFINITIONS`). Conversely, the **Libclang** frontend runs `BEFORE_DEFINITIONS` and will overwrite or miss Tree-sitter-generated spans if run out of order.

Running Libclang before Tree-sitter results in incomplete graphs because the libclang pass does not produce the span definitions that downstream Hybrid processing expects. The tests in [`tests/test_cpp_frontend_qn_parity.py`](https://github.com/vitali87/code-graph-rag/blob/main/tests/test_cpp_frontend_qn_parity.py) explicitly assert correct node mapping for each mode to prevent these ordering errors.

## Summary

- **Three engines**: Choose between Tree-sitter (debugging), Hybrid (recommended default), and Libclang (semantic depth).
- **Three configuration methods**: CLI flag (`--cpp-frontend`), environment variable (`CPP_FRONTEND`), or Python API (`GraphUpdater.set_frontend()`).
- **Execution order matters**: Hybrid requires Tree-sitter definitions first (`AFTER_DEFINITIONS`), while Libclang runs standalone (`BEFORE_DEFINITIONS`).
- **Source locations**: Configuration is stored in [`codebase_rag/config.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/config.py), dispatched via [`parsers/cpp_frontend/__init__.py`](https://github.com/vitali87/code-graph-rag/blob/main/parsers/cpp_frontend/__init__.py), and implemented in [`parsers/cpp_frontend/frontend.py`](https://github.com/vitali87/code-graph-rag/blob/main/parsers/cpp_frontend/frontend.py).

## Frequently Asked Questions

### What is the default C++ frontend in code-graph-rag?

The default frontend is **Hybrid**, which combines Tree-sitter spans with libclang semantic analysis. This is configured automatically when no `--cpp-frontend` flag or `CPP_FRONTEND` environment variable is specified.

### When should I use the Libclang frontend instead of Hybrid?

Use the **Libclang** frontend when you require full C++ type resolution and want to skip the Tree-sitter pass entirely. This is useful for codebases with heavy macro usage or complex template metaprogramming where libclang's semantic analysis provides more accurate qualified names than the Hybrid approach.

### How do I verify which frontend is currently active?

Check the execution order in your logs or examine the [`codebase_rag/config.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/config.py) module at runtime. The test suite in [`tests/test_cpp_frontend_wiring.py`](https://github.com/vitali87/code-graph-rag/blob/main/tests/test_cpp_frontend_wiring.py) provides reference assertions that validate whether the dispatcher called `TreeSitterFrontend`, `HybridFrontend`, or `LibclangFrontend` from [`parsers/cpp_frontend/frontend.py`](https://github.com/vitali87/code-graph-rag/blob/main/parsers/cpp_frontend/frontend.py).

### Can I switch frontends mid-process in the Python API?

Yes. The `GraphUpdater.set_frontend('cpp', ...)` method can be called multiple times within a process to change the parser strategy before subsequent `update_graph()` calls. However, each call only affects future indexing operations and does not retroactively alter already parsed graph nodes.