How to Add Support for a Custom Language in CRG: TOML Configuration Guide

You can add support for a custom language in code-review-graph by creating a .code-review-graph/languages.toml file that maps file extensions to Tree-sitter grammars and node types, without modifying the core codebase or forking the repository.

The code-review-graph (CRG) analyzer relies on Tree-sitter grammars from the tree-sitter-language-pack to parse source files. When you need to parse a language that isn't included as a built-in, you can extend support declaratively using a TOML configuration file that defines node type mappings for functions, classes, imports, and call expressions.

Creating the Configuration File

CRG looks for custom language definitions in a specific location within your repository. The loader checks for .code-review-graph/languages.toml as defined by the CONFIG_RELATIVE_PATH constant in [code_review_graph/custom_languages.py](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/custom_languages.py#L47-L49).

File Location

Create the configuration file at the repository root:

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

The load_custom_languages() function reads this file, caches the result, and validates each entry during the build process.

Schema and Required Fields

Each language entry uses the [languages.<name>] table format. The language name must match the regex ^[a-z][a-z0-9_-]{0,31}$ (enforced by _NAME_RE in the validator).

Required keys include:

  • extensions: Array of file extensions including the leading dot (must match ^\.[a-z0-9_+-]{1,15}$ per _EXTENSION_RE)
  • grammar: Exact name of the grammar as it appears in tree-sitter-language-pack
  • Node type arrays (at least one must be non-empty):
    • function_node_types: Tree-sitter node types representing function definitions
    • class_node_types: Tree-sitter node types representing class definitions
    • import_node_types: Tree-sitter node types representing import statements
    • call_node_types: Tree-sitter node types representing call expressions

Optional fields include name_field (array of field names to locate definition names when default heuristics fail) and comment (human-readable note).

Here is a minimal example for Erlang as documented in [CUSTOM_LANGUAGES.md](https://github.com/tirth8205/code-review-graph/blob/main/docs/CUSTOM_LANGUAGES.md#L12-L22):

[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"

And a minimal example for a fictitious language "foo":

[languages.foo]
extensions = [".foo"]
grammar = "foo"
function_node_types = ["def_func"]
class_node_types = ["def_class"]
import_node_types = ["import_stmt"]
call_node_types = ["call_expr"]
name_field = ["identifier", "name"]
comment = "Support for the Foo language via tree-sitter-language-pack"

Validation Rules and Constraints

When load_custom_languages() executes (lines 10-28 in custom_languages.py), it performs strict validation on every entry:

  • Naming restrictions: Custom languages cannot shadow built-in language names or claim extensions already handled by built-in parsers (see lines 24-30).
  • Grammar availability: The specified grammar must be loadable via tslp.get_language(grammar) (lines 33-35); otherwise, the entry is skipped with a warning.
  • Quantity limit: Maximum of 20 custom languages per repository (MAX_CUSTOM_LANGUAGES).
  • Pattern compliance: Language names and extensions must match their respective regex patterns.

If any validation fails, the loader emits a warning via logger.warning() in _validate_entry and skips the invalid entry, continuing with the remaining configurations.

Building the Graph with Custom Languages

After saving your configuration, you must trigger a fresh build to load the new grammar. The build process recreates the CodeParser instance, which invokes the generic walker in [parser.py](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py#L10622-L10630) to process the custom language using the same extraction logic as built-in languages.

Run the build command:

uv run code-review-graph build

Files matching your declared extensions will now parse using the specified Tree-sitter grammar. The extracted entities appear in the graph with language = "your_language" attributes, and edges like CALLS and IMPORTS_FROM generate automatically based on your call_node_types and import_node_types mappings.

Verifying Grammar Availability

Before configuring a language, verify that the grammar exists in the tree-sitter-language-pack:

uv run python - <<'EOF'
import tree_sitter_language_pack as tslp
print(tslp.get_language("erlang"))  # Replace with your grammar name

EOF

A LookupError indicates the grammar is not bundled and cannot be used until added to the language pack.

Summary

  • Create .code-review-graph/languages.toml in your repository root to add custom language support in CRG without code changes or forks.
  • Define language entries with required fields: extensions, grammar, and at least one node type array (function_node_types, class_node_types, import_node_types, or call_node_types).
  • Validation enforces unique names/extensions, available grammars via tslp.get_language(), and a maximum of 20 custom languages.
  • Run uv run code-review-graph build to apply changes and parse files using the new configuration.
  • Custom languages integrate fully with existing graph features including impact radius analysis and community detection via the generic walker.

Frequently Asked Questions

What file extensions are valid for custom languages?

Extensions must start with a dot and contain only lowercase letters, numbers, underscores, plus signs, or hyphens, matching the pattern ^\.[a-z0-9_+-]{1,15}$ enforced by _EXTENSION_RE. For example, .erl and .foo are valid, but extensions longer than 15 characters or containing uppercase letters will fail validation.

Can I override a built-in language parser with a custom configuration?

No. The validator in code_review_graph/custom_languages.py explicitly prevents custom languages from shadowing built-in language names or claiming extensions already handled by built-in parsers (lines 24-30). If you attempt this, the loader will skip your entry and emit a warning via logger.warning().

What happens if I specify a grammar that isn't in the tree-sitter-language-pack?

The validation step calls tslp.get_language(grammar) to verify availability (lines 33-35). If the grammar is not found, the validator logs a warning and skips that language entry. The build continues, but files with matching extensions will not be parsed as that language.

Do I need to restart the CRG server after adding a custom language?

No server restart is required, but you must run a fresh build using uv run code-review-graph build. The build process reinitializes the CodeParser and reloads the languages.toml configuration through load_custom_languages(), caching the validated results for the current analysis session.

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 →