How to Configure Capture Selection for Relationship Types in Code-Graph-RAG

Set the CGR_CAPTURE environment variable in your .env file or export it directly to enable, disable, or mix relationship type groups (like calls, io, types) using + prefixes, - prefixes, all, or none tokens.

Configuring capture selection for relationship types in Code-Graph-RAG lets you control which edges appear in your Neo4j-style code graph. This is essential for keeping graph sizes manageable and focusing analysis on relevant relationships. The system organizes relationship types into named capture groups and provides a flexible token-based API for runtime selection.

Understanding Capture Groups

Relationship types in Code-Graph-RAG are grouped logically in codebase_rag/constants/graph.py. The CAPTURE_GROUP_RELS dictionary (lines 79-86) defines these mappings:

Capture Group Relationship Types
structure CONTAINS_PACKAGE, DEFINES, CONTAINS_MODULE, CONTAINS_CLASS, CONTAINS_FUNCTION
calls CALLS, REFERENCES, INSTANTIATES
types INHERITS, IMPLEMENTS, MIXIN, OVERRIDES
imports IMPORTS, EXPORTS, RE_EXPORTS
io READS_FROM, WRITES_TO, FLOWS_TO, EXPOSES, RESOLVES_TO
findings HAS_SMELL, HAS_VULNERABILITY, HAS_BUG, HAS_PERFORMANCE_ISSUE

Source: graph.py#L79-L86

By default, only four groups are enabled: structure, calls, types, and imports. The io and findings groups are excluded unless explicitly requested.

How Capture Selection Works

The selection engine lives in codebase_rag/capture.py. Understanding its mechanics helps you construct precise capture specifications.

Token Resolution

The _resolve_token function (lines 70-78) handles individual tokens:

  1. First, it checks if the token matches a capture group name (e.g., io) and returns all relationships in that group
  2. If no group matches, it checks for a single relationship type (e.g., writes_to)

Source: capture.py#L70-L78

Processing Rules in resolve_capture

The main resolve_capture function (lines 88-115) processes tokens left-to-right with these semantics:

  • none — clears all relationships (empty set)
  • all — enables every relationship type (_ALL_RELS)
  • +prefix or no prefix — adds relationships
  • -prefix — removes relationships
  • Unknown tokens — generates a warning, continues processing

Source: capture.py#L88-L115

The split_spec function (lines 18-30) parses raw strings by splitting on commas, semicolons, or spaces.

Source: capture.py#L18-L30

Soft Dependencies

Some relationships require companions to be meaningful. The _SOFT_DEPENDENCIES dict (lines 13-15) warns if OVERRIDES is enabled without INHERITS:

_SOFT_DEPENDENCIES = {cs.RelationshipType.OVERRIDES: cs.RelationshipType.INHERITS}

Source: capture.py#L13-L15

Environment-Based Configuration

The default_capture() function (lines 33-37) reads CGR_CAPTURE from your environment:

def default_capture() -> CaptureSelection:
    from .config import settings
    return resolve_capture(split_spec(settings.CGR_CAPTURE))

Source: capture.py#L33-L37

Set this in your .env file or shell:


# .env

CGR_CAPTURE=all,-io

Practical Configuration Examples

Enable Only Specific Groups


# Structure and calls only, nothing else

CGR_CAPTURE=none,structure,calls

Exclude a Single Relationship from an Enabled Group


# All default relationships except FINDINGS group, minus WRITES_TO specifically

CGR_CAPTURE=all,-findings,-writes_to

Complex Mixed Selection


# Start empty, add IO group, remove it entirely, then add back just FLOWS_TO

CGR_CAPTURE=none,io,-io,flows_to

This sequence demonstrates left-to-right evaluation: the final set contains only FLOWS_TO.

Programmatic API Usage

from codebase_rag.capture import resolve_capture, split_spec, default_capture
from codebase_rag.graph_loader import load_graph

# Method 1: Direct token construction

tokens = split_spec("calls,reads_from,writes_to")
selection = resolve_capture(tokens)
print(selection.enabled_rels)

# {RelationshipType.CALLS, RelationshipType.REFERENCES, 

#  RelationshipType.INSTANTIATES, RelationshipType.READS_FROM, 

#  RelationshipType.WRITES_TO}

# Method 2: Use environment-driven default

graph = load_graph(
    project_path="my_project",
    capture=default_capture()  # Reads CGR_CAPTURE env var

)

Integration with Graph Loading

When codebase_rag/graph_loader.py builds your graph, it applies the CaptureSelection to filter edges before persistence. Only relationships in CaptureSelection.enabled_rels are written to Neo4j, along with their associated node labels. This keeps query performance high and storage costs low for large codebases.

Key Source Files

File Purpose
codebase_rag/constants/graph.py RelationshipType enum, CaptureGroup enum, CAPTURE_GROUP_RELS mapping
codebase_rag/capture.py Token parsing (split_spec), resolution (_resolve_token, resolve_capture), default capture (default_capture)
codebase_rag/config.py Settings object containing CGR_CAPTURE environment binding
codebase_rag/graph_loader.py Consumes CaptureSelection to filter edges during graph construction

Summary

  • Capture groups organize relationship types into logical sets defined in constants/graph.py
  • Token syntax uses all, none, group names, and individual types with +/- prefixes
  • Left-to-right evaluation allows complex additive and subtractive specifications
  • Environment variable CGR_CAPTURE drives default capture selection via default_capture()
  • Soft dependencies warn when companion relationships are missing

Frequently Asked Questions

What is the default capture configuration in Code-Graph-RAG?

The default enables structure, calls, types, and imports groups. This is defined by DEFAULT_CAPTURE_GROUPS in the constants module. The io and findings groups are excluded by default to minimize graph size and focus on structural and call relationships.

Can I enable individual relationships without using capture groups?

Yes. Tokens that don't match group names are checked against individual RelationshipType values. For example, CGR_CAPTURE=none,calls,-instantiates,writes_to enables CALLS and REFERENCES from the calls group, excludes INSTANTIATES, and adds the single WRITES_TO relationship from the IO group.

What happens if I specify conflicting tokens like io,-io,io?

The left-to-right evaluation applies each operation sequentially. io enables all IO relationships, -io removes them all, and the final io re-enables them. The effective result is the IO group being enabled. This sequential semantics lets you build complex selections through explicit overrides.

How do I verify which relationships are actually enabled?

Inspect the enabled_rels attribute of the CaptureSelection object. When using the programmatic API, print selection.enabled_rels after calling resolve_capture(). The set contains the RelationshipType enum values that will be included in your graph.

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 →