How to Add Custom Language Support via languages.toml in Code-Review-Graph

Add a .code-review-graph/languages.toml file to your repository root to register new Tree-sitter grammars without forking the repository, as the loader in custom_languages.py automatically validates and merges custom language definitions into the parser's language map.

The tirth8205/code-review-graph repository provides a flexible extension mechanism for adding support for programming languages not included in the default distribution. By creating a languages.toml configuration file in your project's .code-review-graph/ directory, you can register custom Tree-sitter grammars, define file extensions, and specify node types for semantic analysis. This approach allows teams to analyze proprietary or niche languages while maintaining compatibility with the existing parsing infrastructure.

Configuration File Location and Discovery

The system searches for a file named languages.toml within a .code-review-graph/ directory at your repository root. According to the loader implementation in [custom_languages.py (lines 47-49)](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py#L47-L49), the parser constructs the path by joining the repository root with the hardcoded .code-review-graph/languages.toml relative path. If this file exists, the parser immediately triggers the custom language loading sequence during CodeParser initialization.

Understanding the languages.toml Schema

Each custom language must be defined as a table in the format [languages.<name>] where the name follows strict validation rules. The configuration supports the following fields: extensions (array of file extensions), grammar (Tree-sitter grammar name), function_node_types, class_node_types, import_node_types, call_node_types (arrays of AST node types), and an optional comment field for documentation.

Validation Rules and Constraints

The validation logic in [custom_languages.py (lines 53-68)](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py#L53-L68) enforces several strict constraints to ensure build stability. Language names must match the regular expression ^[a-z][a-z0-9_-]{0,31}$, meaning they must start with a lowercase letter and contain only alphanumeric characters, underscores, or hyphens up to 32 characters total. File extensions must conform to ^\.[a-z0-9_+-]{1,15}$, requiring a leading dot followed by 1-15 allowed characters.

The system rejects any configuration exceeding 20 custom languages total. Additionally, custom entries cannot collide with built-in language names or extensions, and duplicate extensions within your custom definitions are resolved using a "first one wins" policy where subsequent duplicates are silently ignored.

Architecture and Loading Mechanism

When you instantiate CodeParser with a repository path, the __init__ method calls load_custom_languages() to parse and validate the TOML configuration. As shown in [parser.py (lines 2101-2104)](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py#L2101-L2104), this integration happens automatically during parser initialization, merging validated CustomLanguage objects into the parser's internal language map. The actual merging logic that treats custom languages identically to built-in ones is implemented in [custom_languages.py (lines 13081-13085)](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py#L13081-L13085), where custom node type lists drive generic analyses like function extraction and import detection.

To ensure performance across multiple parsing operations, the implementation in [custom_languages.py (lines 92-98)](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py#L92-L98) caches the parsed result using the file's path, modification time, and size as a cache key. This prevents redundant TOML parsing and validation when the configuration hasn't changed.

Complete Configuration Examples

Create a minimal configuration for Erlang support by defining the required AST node types and file extensions:


# .code-review-graph/languages.toml

[languages.erlang]
extensions = [".erl", ".hrl"]
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"

Add a second custom language by creating another table, ensuring the name is unique and lowercase:

[languages.mylang]
extensions = [".myl"]
grammar = "mylang_grammar"
function_node_types = ["fn"]
class_node_types = ["class"]
import_node_types = ["import"]
call_node_types = ["call"]
comment = "My experimental language"

Initialize the parser in Python to trigger custom language loading:

from pathlib import Path
from code_review_graph.parser import CodeParser

repo_root = Path.cwd()
parser = CodeParser(repo_root)  # Automatically loads languages.toml if present

Debugging and Verification

Run the build command with the verbose flag to verify that your custom languages loaded successfully:

code-review-graph -v build .

Look for diagnostic messages indicating the number of loaded custom languages, such as "Loaded 2 custom languages from .code-review-graph/languages.toml". The loader silently ignores malformed entries to prevent build failures, so verbose output is essential for troubleshooting validation errors or extension collisions.

Summary

  • Place your configuration at .code-review-graph/languages.toml in the repository root.
  • Define languages using [languages.<name>] tables with validated extensions and Tree-sitter grammar names.
  • Respect the constraints: maximum 20 languages, lowercase names with specific character limits, and no conflicts with built-in definitions.
  • The parser automatically loads and caches custom definitions during CodeParser initialization via load_custom_languages().
  • Custom languages integrate fully with the analysis pipeline, supporting function extraction, import detection, and other semantic features.

Frequently Asked Questions

Can I override built-in language definitions with custom entries?

No, the validation logic explicitly prevents custom languages from colliding with built-in language names or file extensions. If your custom entry conflicts with a built-in definition, the loader ignores the custom entry and continues processing the remaining configuration. This safety mechanism ensures core language functionality remains intact.

What happens if my TOML file contains syntax errors?

The loader implements graceful degradation for malformed configurations. Instead of crashing the build process, it skips the invalid file and logs a warning when running in verbose mode. You can identify specific validation failures by checking the diagnostic output with the -v flag, which reports issues like invalid regex patterns or exceeding the 20-language limit.

How does the caching mechanism affect CI/CD pipelines?

The caching system uses file modification time and size to determine if the TOML needs reparsing, which significantly speeds up incremental builds. In CI/CD environments where the repository is cloned fresh each time, the cache naturally starts empty, but subsequent parsing operations within the same job benefit from cached results if you analyze multiple snapshots or branches.

Where can I find the complete schema reference for languages.toml?

Comprehensive documentation including all supported fields, validation regex patterns, and advanced configuration examples is available in [docs/CUSTOM_LANGUAGES.md](https://github.com/tirth8205/code-review-graph/blob/main/docs/CUSTOM_LANGUAGES.md). This file explains the relationship between node type definitions and Tree-sitter grammar queries, helping you correctly map AST nodes to the semantic categories required by the analysis engine.

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 →