# How to Configure Custom Language Parsers via `languages.toml` in code-review-graph

> Learn to configure custom language parsers using languages.toml in code-review-graph. Add tree-sitter grammars for unsupported languages and unlock comprehensive code graph analysis.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-07-29

---

**Place a [`languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/languages.toml) file inside the `.code-review-graph/` directory at your repository root to register tree-sitter grammars for unsupported languages, enabling full code graph analysis without modifying the core tool.**

The `code-review-graph` repository analyzer ships with built-in support for popular languages, but you can extend it to parse any grammar available in the tree-sitter ecosystem. By creating a configuration-driven parser definition, you teach the tool to recognize custom file extensions and extract semantic nodes (functions, classes, imports) using generic tree-sitter walkers, making impact radius and community detection features available for languages like Erlang, BibTeX, or LaTeX.

## Where to Place the Configuration File

The loader expects the configuration at a specific relative path from your repository root:

```

.code-review-graph/languages.toml

```

As defined in [`code_review_graph/custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py) at lines 47-48, the constant `CONFIG_RELATIVE_PATH = Path(".code-review-graph") / "languages.toml"` determines the lookup location. If this file exists, the tool automatically detects it during the build process when you run:

```bash
uv run code-review-graph build

```

## TOML Schema for Custom Languages

Each custom language is defined in a `[languages.<name>]` table. The schema requires specific fields that map tree-sitter node types to the tool's internal representation.

### Required Fields

- **grammar**: The tree-sitter grammar name (validated against `tslp.get_language`)
- **extensions**: Array of file extensions (e.g., `[".erl", ".hrl"]`)
- **function_node_types**: Array of AST node types representing callable units
- **class_node_types**: Array of AST node types representing type definitions or modules
- **import_node_types**: Array of AST node types representing dependency declarations
- **call_node_types**: Array of AST node types representing invocation sites

### Optional Fields

- **name_field**: String or list of strings (max 8 candidates) specifying which child field contains the identifier name
- **comment**: Descriptive string for documentation purposes

After validation in `_validate_entry` (lines 211-254 of [`custom_languages.py`](https://github.com/tirth8205/code-review-graph/blob/main/custom_languages.py)), the loader instantiates a frozen **CustomLanguage** dataclass (lines 75-86) to store these values immutably.

## Validation Rules and Safety Constraints

The loader implements a safety-first approach that prevents malformed configurations from crashing the build.

- **Pattern Enforcement**: Language names must match `_NAME_RE` and extensions must match `_EXTENSION_RE`
- **Grammar Existence**: The specified grammar must be resolvable via the tree-sitter language pack
- **Extension Conflicts**: Custom entries cannot override built-in extensions or language identifiers—built-ins always win
- **Hard Caps**: Maximum of 20 custom languages per repository and 8 candidate fields in `name_field` per language
- **Graceful Degradation**: Invalid entries are skipped with logged warnings; the build continues with valid entries only

The implementation caches the file's **mtime** and **size** (lines 97-102) to avoid re-parsing on every build, clearing only on explicit `clear_cache()` calls.

## Integration with the Parser Pipeline

Once validated, custom languages integrate seamlessly with the existing analysis infrastructure:

1. **TOML Parsing**: The file is read using `tomllib` (or `tomli` on Python < 3.11) via `tomllib.loads` at lines 155-170
2. **Registration**: `load_custom_languages()` returns a mapping of extensions to `CustomLanguage` objects
3. **Language Detection**: `CodeParser.detect_language` (in [`parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/parser.py)) consults this mapping when encountering registered extensions
4. **Node Extraction**: The generic tree-sitter walker uses your specified `node_types` lists to identify definitions, while `name_field` determines how to extract identifiers from AST nodes

According to [`parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/parser.py) at lines 1132-1138, the parser receives the custom language mapping and treats these entries identically to built-ins for downstream features like search, wiki generation, and impact analysis.

## Complete Configuration Examples

### Minimal Erlang Configuration

```toml
[languages.erlang]
extensions = [".erl"]
grammar = "erlang"
function_node_types = ["function_clause"]
class_node_types = ["record_decl"]
import_node_types = ["import_attribute"]
call_node_types = ["call"]
comment = "Erlang via the bundled tree-sitter-erlang grammar"

```

### BibTeX with Non-Standard Name Locations

For languages where identifiers appear in child fields rather than node text, use `name_field` to specify extraction candidates:

```toml
[languages.bibtex]
extensions = [".bib"]
grammar = "bibtex"
class_node_types = ["entry"]
name_field = ["key"]

```

An entry like `@article{smith2020,…}` now generates a **Class** node named `smith2020`.

### LaTeX with Multiple Name Field Candidates

```toml
[languages.latex]
extensions = [".tex"]
grammar = "latex"
class_node_types = ["section", "chapter", "subsection"]
function_node_types = ["new_command_definition"]
name_field = ["name", "text", "declaration"]

```

### Validating Your Configuration

Run this Python snippet to verify your [`languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/languages.toml) loads correctly before building:

```python
from pathlib import Path
from code_review_graph.custom_languages import load_custom_languages
from code_review_graph.parser import EXTENSION_TO_LANGUAGE, CodeParser

repo = Path("/path/to/your/repo")
langs = load_custom_languages(
    repo,
    builtin_extensions=EXTENSION_TO_LANGUAGE,
    builtin_languages=CodeParser()._builtin_language_names(),
)
print("Loaded custom languages:", list(langs))

```

## Summary

- Create [`.code-review-graph/languages.toml`](https://github.com/tirth8205/code-review-graph/blob/main/.code-review-graph/languages.toml) at your repository root to register custom tree-sitter grammars
- Define each language with required node type mappings and optional `name_field` extraction rules
- The loader enforces strict validation (max 20 languages, no built-in overrides) with graceful error handling
- Custom languages integrate into `CodeParser` and work with all analysis features immediately after configuration
- Cache invalidation occurs automatically when the configuration file changes size or modification time

## Frequently Asked Questions

### What happens if my tree-sitter grammar is not installed?

The validator calls `tslp.get_language` during `_validate_entry`. If the grammar is unavailable, the entry is skipped with a warning and the build continues without that language. Install the missing grammar via `pip install tree-sitter-<language>` or the tree-sitter language pack.

### Can I override built-in language definitions like Python or JavaScript?

No. The validation logic explicitly prevents custom entries from claiming extensions or language names already reserved by built-ins. This ensures core language parsers remain stable and prevents ambiguous extension mappings.

### How do I debug why my custom language isn't loading?

Check the build logs for warnings emitted during TOML parsing (lines 155-170) or validation (lines 211-254). Common issues include: regex mismatches in language names (must satisfy `_NAME_RE`), extension collisions, or missing required node type arrays. Use the Python validation snippet in the examples section to test programmatically.

### Where does the actual AST parsing occur for custom languages?

The `CodeParser` class in [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py) handles the tree-sitter parsing. At lines 1132-1138, it passes your custom language configuration to the generic walker, which uses your defined `node_types` to extract graph nodes. No additional code changes are required—the pipeline treats custom and built-in languages identically once registered.