Reference for creating custom ast-grep rules. Intended for AI agents but readable by humans.
Add ast-grep rules when:
- You identify a repeated architectural violation
- ESLint can't express the rule (pattern-based matching needed)
- The pattern has caused bugs or performance issues
id: rule-name
message: |
Brief description with examples.
BAD: example
GOOD: example
severity: error # or warning
language: Tsx # or TypeScript
files: # Optional: restrict to paths
- 'src/lib/**/*.ts'
rule:
pattern: $PATTERN
note: |
Additional context for developers.| Syntax | Meaning | Example |
|---|---|---|
$VAR |
Single AST node | const $NAME = useStore() |
$$$ARGS |
Zero or more nodes | function($$$ARGS) |
$$ |
Anonymous wildcard | { $$, field: $VALUE } |
Test a pattern against the codebase:
npx ast-grep run --pattern 'const { $$$PROPS } = useUIStore($$$ARGS)' src/Test a rule file:
npx ast-grep scan -r .ast-grep/rules/zustand/no-destructure.ymlFile: .ast-grep/rules/zustand/no-destructure.yml
id: no-destructure-zustand
message: |
Don't destructure Zustand stores - use selectors instead.
BAD: const { visible } = useUIStore()
GOOD: const visible = useUIStore(state => state.visible)
severity: error
language: Tsx
rule:
any:
- pattern: const { $$$PROPS } = useUIStore($$$ARGS)
- pattern: const { $$$PROPS } = usePreferencesStore($$$ARGS)
note: |
Destructuring subscribes to the entire store, causing unnecessary re-renders.
See docs/developer/state-management.md for details.When you add a new Zustand store, update the no-destructure rule:
rule:
any:
- pattern: const { $$$PROPS } = useUIStore($$$ARGS)
- pattern: const { $$$PROPS } = useNewStore($$$ARGS) # Add new storeid: hooks-in-hooks-dir
language: TypeScript
files:
- 'src/lib/**/*.ts'
rule:
pattern: export function use$NAME($$$ARGS)id: no-store-in-lib
language: TypeScript
files:
- 'src/lib/**/*.ts'
rule:
pattern: const $VAR = $STORE(state => $$$SELECTOR)Rules not matching:
- Check
languagematches file type (Tsxfor.tsx,TypeScriptfor.ts) - Test pattern directly with
npx ast-grep run - Verify
filesglobs if using path restrictions
False positives:
- Add exceptions using
ignoresin rules - Update
sgconfig.ymlto exclude paths