biome-gritql
1
总安装量
1
周安装量
#52892
全站排名
安装命令
npx skills add https://github.com/somtougeh/somto-dev-toolkit --skill biome-gritql
Agent 安装分布
opencode
1
cursor
1
kiro-cli
1
codex
1
claude-code
1
gemini-cli
1
Skill 文档
Biome GritQL Custom Lint Rules
Create AST-based custom lint rules using Biome’s GritQL plugin system.
Quick Start
Create a rule file (rules/no-use-effect-fetch.grit):
`useEffect($callback, $deps)` where {
$callback <: contains `fetch`,
register_diagnostic(
span = $callback,
message = "Don't fetch inside useEffect. Use TanStack Query instead.",
severity = "error"
)
}
Add to biome.json:
{
"plugins": ["./rules/no-use-effect-fetch.grit"]
}
Run: bunx biome check or any equivalent command to run linter in the codebase
GritQL Syntax
Basic Pattern Matching
`pattern_to_match` where {
register_diagnostic(
span = $matched_var,
message = "Your message here",
severity = "error" // hint | info | warn | error
)
}
make sure to read documentation
Variables
$name– captures any single node$args– captures arguments$_– wildcard (match but don’t capture)
Operators
| Operator | Meaning |
|---|---|
<: |
matches / contains |
<: contains |
deep contains |
<: r"regex" |
regex match |
not |
negation |
and |
both conditions |
or |
either condition |
Common Rule Patterns
Ban a Function Call
`console.log($args)` where {
register_diagnostic(
span = $args,
message = "Remove console.log before committing",
severity = "warn"
)
}
Ban a Hook (React)
`useMemo($args)` where {
register_diagnostic(
span = $args,
message = "useMemo unnecessary with React Compiler. Remove it.",
severity = "warn"
)
}
Ban Dynamic Imports
`await import($path)` where {
register_diagnostic(
span = $path,
message = "Use static imports at the top of the file",
severity = "error"
)
}
Require Pattern in Context
`useState($initial)` where {
not $initial <: contains `atom`,
register_diagnostic(
span = $initial,
message = "Prefer Jotai atoms over useState for shared state",
severity = "info"
)
}
CSS Rules
language css;
`$selector { $props }` where {
$props <: contains `color: $color` as $rule,
not $selector <: r"\.color-.*",
register_diagnostic(
span = $rule,
message = "Use .color-* utility classes instead of explicit colors"
)
}
Project Structure
project/
âââ biome.json
âââ rules/
âââ no-console-log.grit
âââ no-use-memo.grit
âââ no-use-callback.grit
âââ no-dynamic-import.grit
âââ no-fetch-in-effect.grit
biome.json Configuration
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"plugins": [
"./rules/no-console-log.grit",
"./rules/no-use-memo.grit",
"./rules/no-use-callback.grit"
],
"linter": {
"enabled": true
}
}
Creating Rules Workflow
- Identify the pattern to ban/enforce
- Create
.gritfile inrules/directory - Write the GritQL pattern with clear error message
- Add path to
biome.jsonplugins array - Test with
bunx biome checkor any equivalent command to run linter in the codebase
Guidelines
- Keep error messages actionable – tell the user what to do instead
- Use
severity = "error"for hard requirements,"warn"for preferences - Put all
.gritfiles in arules/directory - Name files descriptively:
no-X.gritorprefer-Y.grit - Test rules against real code before committing
Why This Matters
Instructions in CLAUDE.md degrade as context fills up. Linter rules provide immediate, persistent feedback. When Claude violates a pattern, it sees the error and self-corrects – no context drift.