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

> Configure capture selection for relationship types in Code-Graph-RAG. Control inclusion/exclusion of calls, io, types, and more with the CGR_CAPTURE variable.

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

---

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

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

```

Source: [`capture.py#L13-L15`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/capture.py#L13-L15)

## Environment-Based Configuration

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

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

```

Source: [`capture.py#L33-L37`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/capture.py#L33-L37)

Set this in your `.env` file or shell:

```bash

# .env

CGR_CAPTURE=all,-io

```

## Practical Configuration Examples

### Enable Only Specific Groups

```bash

# Structure and calls only, nothing else

CGR_CAPTURE=none,structure,calls

```

### Exclude a Single Relationship from an Enabled Group

```bash

# All default relationships except FINDINGS group, minus WRITES_TO specifically

CGR_CAPTURE=all,-findings,-writes_to

```

### Complex Mixed Selection

```bash

# 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

```python
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`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants/graph.py) | `RelationshipType` enum, `CaptureGroup` enum, `CAPTURE_GROUP_RELS` mapping |
| [`codebase_rag/capture.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/capture.py) | Token parsing (`split_spec`), resolution (`_resolve_token`, `resolve_capture`), default capture (`default_capture`) |
| [`codebase_rag/config.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/config.py) | Settings object containing `CGR_CAPTURE` environment binding |
| [`codebase_rag/graph_loader.py`](https://github.com/vitali87/code-graph-rag/blob/main/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`](https://github.com/vitali87/code-graph-rag/blob/main/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.