Code-Graph-RAG Graph Schema: Complete Protocol Buffers Reference for Property Graph Modeling
The graph schema for Code-Graph-RAG is defined in a Protocol Buffers file at codec/schema.proto, which specifies nodes (Project, Package, Class, Function, etc.) and directed relationships (CONTAINS_FILE, DEFINES, CALLS, INHERITS, etc.) that together model an entire codebase as a serializable property graph.
Code-Graph-RAG is an open-source tool by vitali87 that transforms source code repositories into queryable knowledge graphs for retrieval-augmented generation (RAG) pipelines. Understanding its graph schema is essential for anyone building custom queries, extending the indexer, or integrating the output with graph databases like Memgraph.
Schema Location and Structure
The canonical schema definition lives at codec/schema.proto. The repository includes auto-generated Python bindings in [codec/schema_pb2.py](https://github.com/vitali87/code-graph-rag/blob/main/codec/schema_pb2.py) that provide programmatic access to all message types.
At the root of every indexed codebase sits a GraphCodeIndex message containing two repeated fields:
nodes— a collection of strongly-typed entities wrapped in genericNodecontainersrelationships— directed edges connecting nodes by their primary keys
This flat structure enables efficient serialization while preserving rich semantic relationships.
Node Types and Their Primary Keys
Each node type uses a qualified name or path as its stable identifier, ensuring deterministic graph construction across indexing runs.
| Node Type | Primary Key Field | Key Characteristics |
|---|---|---|
| Project | name |
Single root node per codebase |
| Package | qualified_name |
Logical grouping (Maven/Gradle/npm equivalent) |
| Folder | path |
Physical directory on disk |
| File | path |
Individual source file with extension metadata |
| Module | qualified_name |
Language-specific module with Rust/Python-specific fields like rust_cfg_test_mods and flow_covered |
| Class | qualified_name |
OO definition with docstring, line numbers, decorators, is_exported |
| Function | qualified_name |
Stand-alone function with ast_fingerprint, return_type, param_types |
| Method | qualified_name |
Same fields as Function with method semantics |
| ExternalPackage | name |
Third-party dependency boundary |
| ExternalModule | qualified_name |
Module from external dependency |
| Pattern / CodeSmell / SecurityIssue | qualified_name |
Quality signals from AST-grep with snippet evidence |
| Resource | qualified_name |
I/O resources: files, network, environment variables |
| Section | qualified_name |
Markdown documentation headings |
| Interface / Enum / Type / Union | qualified_name |
Language-specific type constructs |
The Node message itself uses a oneof payload to enforce type safety while allowing polymorphic storage:
// From codec/schema.proto
message Node {
oneof payload {
Project project = 1;
Package package = 2;
// ... all other node types
Function function = 10;
Method method = 11;
}
}
Relationship Types and Semantics
Relationships are defined in the Relationship.RelationshipType enum. The design follows append-only versioning: each enum value is frozen to guarantee wire-format compatibility when new edge types are added.
Hierarchical Containment
CONTAINS_PACKAGE— Project → PackageCONTAINS_FOLDER— Package/Folder → FolderCONTAINS_FILE— Folder → FileCONTAINS_MODULE— File → Module
Definition Edges
DEFINES— Module → Class/Function/Interface/Enum/TypeDEFINES_METHOD— Class → Method
Code Dependencies
IMPORTS— Module/File → external symbolCALLS— Function/Method → callable targetINHERITS— Class → parent ClassOVERRIDES— Method → overridden Method
Cross-Package Relationships
DEPENDS_ON_EXTERNAL— Package → ExternalPackageIMPLEMENTS_MODULE— Module → external interface/traitEXPORTS— Module → public API surface
Quality and Security Signals
HAS_SMELL— any node → CodeSmellHAS_VULNERABILITY— any node → SecurityIssueHAS_PATTERN— any node → Pattern (AST-grep match)
Reference Resolution
REFERENCES— generic usage edgeRESOLVES_TO— symbol → its definition (for import resolution)
Every Relationship stores source_id, target_id, source_label, target_label, and an extensible properties Struct for edge attributes.
Building and Serializing Graphs
The following example demonstrates constructing a minimal graph programmatically using the Python bindings from codec/schema_pb2.py:
from codec import schema_pb2 as schema
from google.protobuf.struct_pb2 import Struct
# Create nodes
project = schema.Node(project=schema.Project(name="my_service"))
source_file = schema.Node(
file=schema.File(
path="src/app.py",
name="app.py",
extension=".py"
)
)
# Establish containment relationship
contains_rel = schema.Relationship(
type=schema.Relationship.CONTAINS_FILE,
source_id="my_service", # Project.name
target_id="src/app.py", # File.path
source_label="Project",
target_label="File",
properties=Struct()
)
# Assemble and serialize
index = schema.GraphCodeIndex(
nodes=[project, source_file],
relationships=[contains_rel]
)
# Write to disk for later ingestion
with open("codebase_index.pb", "wb") as f:
f.write(index.SerializeToString())
Loading and Querying Existing Indexes
For analysis or database ingestion, load a serialized index as follows:
from codec import schema_pb2 as schema
# Parse from disk
with open("codebase_index.pb", "rb") as f:
index = schema.GraphCodeIndex()
index.ParseFromString(f.read())
# Extract all exported functions with their line ranges
exported_functions = [
(node.function.qualified_name,
node.function.start_line,
node.function.end_line)
for node in index.nodes
if node.HasField("function") and node.function.is_exported
]
print(f"Found {len(exported_functions)} exported functions")
Key Implementation Files
| File | Role in Schema Pipeline |
|---|---|
codec/schema.proto |
Ground-truth protobuf definition |
[codec/schema_pb2.py](https://github.com/vitali87/code-graph-rag/blob/main/codec/schema_pb2.py) |
Generated Python API |
[codebase_rag/graph_loader.py](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_loader.py) |
Deserializes GraphCodeIndex to in-memory objects |
[codebase_rag/graph_updater.py](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_updater.py) |
Incremental updates using schema semantics |
[codebase_rag/services/graph_service.py](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/services/graph_service.py) |
Orchestrates indexing and persistence |
[codebase_rag/cypher_queries.py](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/cypher_queries.py) |
Cypher templates matching schema labels |
Summary
- The Code-Graph-RAG graph schema is a Protocol Buffers property graph defined in
codec/schema.proto. - Nodes represent 15+ code entities from Project to SecurityIssue, each with a stable primary key.
- Relationships are typed directed edges from an append-only enum, covering containment, definition, dependency, and quality signals.
- The GraphCodeIndex message provides a flat, serializable container for entire codebases.
- Generated Python bindings enable programmatic graph construction, mutation, and analysis.
Frequently Asked Questions
What file format does Code-Graph-RAG use for graph storage?
Code-Graph-RAG uses Protocol Buffers as its native serialization format. The GraphCodeIndex message can be written to .pb files, sent over gRPC, or loaded directly into Python for processing. This binary format is compact and schema-evolution safe.
How are node types distinguished in the schema?
Node types use a discriminated union pattern: the Node message contains a oneof payload field that holds exactly one strongly-typed message (e.g., Project, Function, Class). The Python API provides HasField() to test which type is populated without manual type inspection.
Can I add custom properties to relationships?
Yes. Every Relationship includes a properties field of type google.protobuf.Struct, which accepts arbitrary JSON-like key-value pairs. This allows the schema to remain stable while supporting extensible edge attributes for specific use cases.
What guarantees does the relationship enum provide?
The RelationshipType enum is append-only: existing numeric values never change, ensuring that indexes serialized with older schema versions remain readable. New edge types receive the next available integer, maintaining backward and forward compatibility.
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 →