How to Add a Custom Language to code-review-graph Using languages.toml

You can add a custom language to code-review-graph by creating a languages.toml configuration file inside the .code-review-graph/ directory at your repository root, defining the grammar from the bundled tree-sitter language pack, and mapping AST node types to graph entities.

The code-review-graph tool provides extensibility for unsupported languages through a declarative TOML interface. By placing a languages.toml file in the hidden .code-review-graph/ folder at your project root, you instruct the parser to load grammars from the bundled tree-sitter-language-pack and extract functions, classes, imports, and calls using the generic AST walker. This integration allows custom languages to participate fully in dependency analysis, impact-radius queries, and MCP tool interactions.

Configuration File Location and Structure

The custom language loader expects the configuration file at a specific path relative to your repository root.

Create the file at:

<repo_root>/.code-review-graph/languages.toml

Each language is defined as a TOML table under the [languages.<name>] namespace. The schema requires you to specify file extensions, the tree-sitter grammar name, and the node-type mappings that tell the walker which AST nodes correspond to functions, classes, imports, and calls.

Required Configuration Schema

In code_review_graph/custom_languages.py (lines 48-78), the loader validates each language definition against a strict schema. You must provide the following keys inside each language table:

  • extensions – Array of file extensions (e.g., [".erl"]) that identify source files for this language.
  • grammar – String name of the tree-sitter grammar available in tree_sitter_language_pack (e.g., "erlang").
  • function_node_types – Array of AST node types representing function definitions.
  • class_node_types – Array of AST node types representing class or type definitions.
  • import_node_types – Array of AST node types representing import statements.
  • call_node_types – Array of AST node types representing function calls.
  • comment (optional) – Description for logging purposes.
  • name_field (optional) – Specifies non-standard field names within AST nodes that contain the definition's identifier.

How the Custom Language Loader Works

When you run a build, parser.py constructs a CustomLanguages instance that initiates a six-stage pipeline defined in custom_languages.py (line 116) and validated at line 77.

1. File Discovery The loader checks for .code-review-graph/languages.toml and parses it using the TOML library.

2. Schema Validation Each [languages.<name>] table is converted to a CustomLanguage object. The validator ensures extensions are unique, grammars are non-empty, and node-type lists are arrays.

3. Conflict Handling Built-in languages always take precedence over custom definitions. Duplicate extensions are ignored, and the system enforces a maximum of 20 custom languages per repository.

4. Grammar Loading The loader attempts to obtain a parser via tslp.get_parser(grammar). If the specified grammar is not available in the bundled language pack, the entry is skipped with a warning.

5. Node-Type Mapping The supplied node-type lists configure the generic walker to generate Function, Class, IMPORTS_FROM, and CALLS edges from the AST.

6. Name Extraction If your grammar stores identifiers in non-standard fields (not the default name child), use name_field entries to direct the walker to the correct location.

Step-by-Step Implementation

Follow these steps to register a custom language using the TOML configuration method.

1. Create the Configuration Directory and File

First, create the hidden directory and TOML file:

mkdir -p .code-review-graph
touch .code-review-graph/languages.toml

2. Define the Language Configuration

Edit languages.toml to declare your language. The following example registers Erlang using the bundled erlang grammar:


# .code-review-graph/languages.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"

Replace the values with the appropriate grammar and node-type names for your target language. The complete schema reference is documented in docs/CUSTOM_LANGUAGES.md (lines 37-56).

3. Build the Graph

Run the build command to compile the graph with your custom language:

uv run code-review-graph build

During initialization, you will see log output confirming the registration:

INFO  Loading custom language 'erlang' from .code-review-graph/languages.toml

4. Verify Integration

Confirm that the custom language is indexed correctly using the Python API:

from code_review_graph.parser import GraphBuilder

builder = GraphBuilder(repo_root=".")
builder.build()
count = builder.graph.nodes.filter(lambda n: n.language == "erlang").count()
print(f"Found {count} Erlang entities")

Alternatively, query the graph using MCP tools:

uv run code-review-graph query "language:erlang and type:Function"

Successful output confirms that Function, Class, and other entities are extracted and integrated into the graph.

Summary

  • Create a languages.toml file inside the .code-review-graph/ directory at your repository root.
  • Define the grammar string and node-type mappings (function_node_types, class_node_types, etc.) for the tree-sitter parser.
  • Validate that the grammar exists in the bundled tree_sitter_language_pack or the loader will skip the entry with a warning.
  • Build using uv run code-review-graph build to register the custom language and generate graph nodes.
  • Respect limits: Maximum 20 custom languages per repository, and built-in languages override custom definitions with duplicate extensions.

Frequently Asked Questions

Where must I place the languages.toml file?

The file must reside at .code-review-graph/languages.toml relative to your repository root. The loader specifically checks this path during parser initialization in code_review_graph/parser.py. Placing it elsewhere will prevent the CustomLanguages class from discovering your configuration.

What grammars are available for custom languages?

You must use grammars available in the bundled tree-sitter-language-pack. The loader calls tslp.get_parser(grammar) to instantiate the parser. If you specify a grammar not included in the pack (such as a custom tree-sitter grammar not bundled with the tool), the entry is skipped with a warning. Check the tree-sitter-language-pack documentation for the full list of supported language identifiers.

How do I handle languages that store identifiers in non-standard AST fields?

Use the optional name_field configuration key within your language table. This tells the generic AST walker which field contains the definition's name when it differs from the standard name child node. This is implemented in the name extraction logic of the walker to ensure Function and Class nodes receive correct labels.

Why is my custom language not appearing in the graph after building?

First, check the build logs for validation warnings—common issues include unknown grammars (not in tree_sitter_language_pack), duplicate file extensions that conflict with built-in languages, or exceeding the 20-custom-language limit. Second, verify that your extensions array includes the leading dot (e.g., [".erl"] not ["erl"]). Finally, ensure the TOML syntax is valid; malformed files are silently skipped by the loader in custom_languages.py.

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 →