biome-gritql-plugins

star 0

Writing custom Biome lint rules as GritQL plugins. Use when creating, editing, or debugging .grit files for Biome's plugin system. Covers GritQL pattern syntax, AST node matching, metavariables, the register_diagnostic API, and testing patterns.

aliou By aliou schedule Updated 2/8/2026

name: biome-gritql-plugins description: Writing custom Biome lint rules as GritQL plugins. Use when creating, editing, or debugging .grit files for Biome's plugin system. Covers GritQL pattern syntax, AST node matching, metavariables, the register_diagnostic API, and testing patterns.

Biome GritQL Plugins

GritQL is a structural pattern matching language that operates on Biome's AST. Each plugin is a .grit file that matches code patterns and emits diagnostics.

File structure

Every .grit file requires two headers:

engine biome(1.0)
language js(jsx)

Supported language values: js, js(jsx), js(typescript), js(typescript,jsx), css.

After headers, write one pattern with conditions and a register_diagnostic() call.

Plugin API

One function is available:

register_diagnostic(
    span = $node,        -- required: AST node to underline
    message = "...",     -- required: diagnostic message
    severity = "error"   -- optional: error (default), warn, info, hint
)

Pattern syntax

Code snippets

Backtick-wrapped code matches structurally (ignores formatting, quote style, whitespace):

`console.log($msg)`

Metavariables

  • $name captures an AST node
  • $_ is a wildcard (match but don't capture)
  • Same variable used twice in a snippet must match the same code: `$fn && $fn()` matches foo && foo() but not foo && bar()

Operators

Operator Meaning Example
<: matches $method <: "log"
contains search descendants $value <: contains JsTemplateExpression()
or { ... } match any $m <: or { "log", "warn" }
not negate not $name <: r".*Icon"
as $var alias a match contains "color: $c" as $rule
where { ... } add conditions `$x` where { $x <: `foo` }

Regex

Use r"pattern" to match captured text against a regex:

$name <: r".*Icon"

Named AST nodes

Use Biome's PascalCase AST types for precise matching:

jsx_attribute(name = "className", $value) where {
    $value <: contains JsTemplateExpression(),
    register_diagnostic(span = $value, message = "Use cn() instead")
}

Common node types:

  • JsxAttribute, JsxElement, JsxSelfClosingElement, JsxOpeningElement
  • JsTemplateExpression, JsCallExpression, JsIfStatement
  • JsxExpressionChild (for {expr} in JSX)

Both snake_case (jsx_attribute) and PascalCase (JsxAttribute) work. Discover node names via the Biome Playground syntax tree view.

Examples

Disallow template literals in className

engine biome(1.0)
language js(jsx)

jsx_attribute(name = "className", $value) where {
    $value <: contains JsTemplateExpression(),
    register_diagnostic(
        span = $value,
        message = "Use cn() instead of template literal in className",
        severity = "error"
    )
}

Disallow Object.assign

engine biome(1.0)
language js

`$fn($args)` where {
    $fn <: `Object.assign`,
    register_diagnostic(
        span = $fn,
        message = "Prefer object spread instead of Object.assign()"
    )
}

CSS: disallow explicit color declarations

engine biome(1.0)
language css

`$selector { $props }` where {
    $props <: contains `color: $color` as $rule,
    not $selector <: r"\.color-.*",
    register_diagnostic(
        span = $rule,
        message = "Don't set explicit colors. Use .color-* classes instead."
    )
}

Configuration

Add plugins in biome.json:

{
  "plugins": [
    "plugins/my-rule.grit"
  ]
}

Paths are resolved relative to the biome.json file. For plugins installed via npm:

{
  "plugins": [
    "./node_modules/@scope/my-plugins/plugins/rule.grit"
  ]
}

Testing

Create a test file with both violations and valid code, then run:

biome lint /tmp/test-file.tsx

Plugin diagnostics appear with the plugin category in output.

Limitations

  • Only JavaScript and CSS target languages are supported
  • No plugin options or configuration per-rule
  • No automatic npm package resolution (must use relative paths)
  • GritQL support in Biome is still experimental; some GritQL features are missing

After creating a plugin

After creating a new plugin, update the plugin table in the following files so they stay in sync:

  • README.md (consumer-facing)
  • AGENTS.md (agent context)

Add a row to the plugin table in each file with the plugin filename (without extension) and a short description.

References

Install via CLI
npx skills add https://github.com/aliou/biome-plugins --skill biome-gritql-plugins
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator