ast-grep
SkillDev toolsSearches and rewrites syntax with ast-grep. Use for AST-pattern codemods or authoring, testing, and configuring structural lint rules.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the ast-grep skill
What this skill tells your AI
The instructions your AI receives, as published by edmundmiller/dotfiles in skills/catalog/ast-grep/SKILL.md and read by ahel’s review.
Use ast-grep for syntax-aware search, rewriting, and tested structural coding standards. Keep formatting, type checking, path-only policy, cross-file value equality, and runtime behavior with their owning tools.
Use code-search when deciding between ast-grep and text search. After selecting ast-grep, use this skill as the source of truth for command syntax, patterns, rewrites, and repository standards.
Choose the right mode
| Need | Mode |
|---|---|
| Find one syntax shape | ast-grep run --pattern ... --lang ... |
| Preview or apply one rule file | ast-grep scan --rule rule.yml |
| Enforce repository standards | sgconfig.yml + rule and test directories |
| Search literal text, comments, or docs | grep, not ast-grep |
| Follow definitions, references, or types | language server, not ast-grep |
Reuse an existing compiler or linter rule before adding parallel policy.
Search and refactor
Start with the smallest valid AST pattern:
ast-grep run --lang typescript --pattern 'console.log($$$ARGS)' src
ast-grep run --lang python --pattern 'print($$$ARGS)' .
Use metavariables deliberately:
| Syntax | Meaning |
|---|---|
$VAR | one named AST node |
$$VAR | one named or anonymous node |
$$$ARGS | zero or more nodes |
$_ / $$$ | non-capturing single/sequence matches |
Quote patterns with single quotes so the shell does not expand $.
Inspect how a plausible query pattern is parsed when it misses:
ast-grep run --lang typescript --pattern 'console.log($$$ARGS)' --debug-query=ast src/example.ts
ast-grep run --lang typescript --pattern 'console.log($$$ARGS)' --debug-query=pattern src/example.ts
--debug-query=ast prints the query pattern's AST, not the source file's AST. Use the ast-grep Playground or language-specific tree-sitter tooling when the source tree itself must be inspected.
For a rewrite, preview before applying:
id: replace-console-log
language: TypeScript
rule:
pattern: console.log($$$ARGS)
fix: logger.info($$$ARGS)
ast-grep scan --rule replace-console-log.yml src
ast-grep scan --rule replace-console-log.yml --update-all src
Treat fix as textual substitution, not parsed output. Run the project formatter, type checker, and focused tests after applying a rewrite.
Integrate editors and automation
Start ast-grep's diagnostics-only language server from the project root so it discovers sgconfig.yml, or pass an explicit config:
ast-grep lsp
ast-grep lsp --config path/to/sgconfig.yml
Use structured output for tooling:
ast-grep run --lang typescript --pattern 'console.log($$$ARGS)' --json=stream src
ast-grep scan --json=compact .
Choose pretty for humans, stream for JSON Lines consumers, and compact for a single-line JSON array. Add --include-metadata to scan only when consumers need rule metadata.
Set up repository standards
-
Inspect repository languages, generated/vendor paths, existing linters, package manager, check runner, CI, and local agent instructions.
-
Install
ast-grepreproducibly through the repository toolchain. Prefer theast-grepexecutable over thesgalias. Pin a version when parser or snapshot stability matters. -
Confirm every required parser with a literal smoke query. Treat an unsupported-language error as a packaging problem, not a reason to replace structural policy with text search.
-
Create:
sgconfig.yml ast-grep/ ├── rules/ │ └── no-console-log.yml └── rule-tests/ └── no-console-log-test.yml -
Configure project discovery:
ruleDirs: - ast-grep/rules testConfigs: - testDir: ast-grep/rule-tests -
Verify the selected project root and config:
ast-grep scan --inspect summary
scan requires sgconfig.yml. Project discovery starts in the working directory and walks upward; use --config path/to/sgconfig.yml when invoking from elsewhere.
Author lint rules
Start from an observed violation and the smallest rule that separates it from valid code.
id: no-console-log
language: TypeScript
severity: warning
files:
- src/**/*.ts
- src/**/*.tsx
ignores:
- src/generated/**
message: Use the project logger instead of console.log.
note: Replace console.log with the logger appropriate to this module.
rule:
pattern: console.log($$$ARGS)
Require:
- a stable kebab-case
id - the exact parser
language - a concise, actionable
message - a
notewhen remediation is not obvious - narrow
filesorignoreswhere the contract is not global - the least complex rule object that expresses the invariant
Keep files and ignores relative to the sgconfig.yml directory. Never prefix their globs with ./.
Add constraints, relational rules, labels, transform, or fix only when tests prove the simpler rule insufficient. Apply constraints only to single metavariables; they filter after the main rule matches and cannot repair conflicting patterns inside not.
For detailed rule composition, read references/rule-reference.md.
Test every rule
Create a test file whose id exactly matches the rule:
id: no-console-log
valid:
- logger.info('ready')
- console.error('fatal')
invalid:
- console.log('ready')
- console.log(message, context)
Cover:
- plausible
validcode that must not report, preventing noisy matches - every prohibited
invalidform the rule claims to detect, preventing missing matches - boundaries such as nesting, alternate syntax, and structural exclusions
valid and invalid cases are source snippets and do not exercise files or ignores. Verify path globs with a temporary project scan or a focused real-tree smoke test containing included and excluded files.
Run detection tests while iterating:
ast-grep test --skip-snapshot-tests
Commit snapshots when diagnostic spans, labels, or messages are part of the contract:
ast-grep test --update-all
ast-grep test
Keep --skip-snapshot-tests in the permanent check only when detection is the complete contract and diagnostic layout is intentionally unstable. Never use interactive snapshot updates in CI.
For a rule regression, add a failing valid or invalid case first, confirm the expected noisy or missing failure, then fix the rule.
Choose severity
| Severity | Policy | Scan behavior |
|---|---|---|
error | Established invariant that blocks changes | Non-zero exit when matched |
warning | Actionable standard during adoption | Reports a warning |
info | Migration or informational finding | Reports informationally |
hint | Low-priority guidance; default | Reports a hint |
off | Temporarily disabled configuration | Does not run |
Promote a rule to error only after tests prove low false-positive risk, remediation is actionable, and the baseline is clean or narrowly scoped. Use CLI overrides for staged rollout or CI policy:
ast-grep scan --error=no-console-log
ast-grep scan --off=no-console-log
ast-grep scan --inspect entity
Control suppressions
Prefer narrow, rule-specific suppression comments with a nearby reason:
// Third-party bootstrap requires direct console output.
console.log(message); // ast-grep-ignore: no-console-log
Avoid bare ast-grep-ignore, which suppresses every diagnostic. After verifying version support and cleaning the baseline, enforce explicit IDs and stale-suppression cleanup:
ast-grep scan --error=no-suppress-all --error=unused-suppression
Integrate project checks
Run rule tests before scanning the real tree:
ast-grep test --skip-snapshot-tests
ast-grep scan
Add both commands to the existing local check runner and CI rather than creating a parallel validation path. Keep local and CI config, binary version, working directory, and severity overrides identical.
Prove the complete setup:
- Run the expected binary version from the repository toolchain.
- Load every configured parser with a literal smoke query.
- Pass all rule tests.
- Scan the repository with the intended severity behavior.
- Exercise both commands through the normal project check.
- Update the repository's agent/router documentation so AST rules route to ast-grep and non-AST policy remains with its owning tool.
Avoid failure modes
- Do not create a lint rule without at least one valid and one invalid case.
- Do not use string search disguised as an AST pattern.
- Do not assume a parser is bundled; smoke-test it.
- Do not weaken a rule merely to make a dirty baseline pass; fix, scope, or stage rollout explicitly.
- Do not add broad suppressions to silence false positives; improve the rule and tests.
- Do not duplicate ESLint, Ruff, Clippy, compiler, formatter, or runtime checks.
- Do not rely on a narrowed scan as the only CI gate if the standard is repository-wide.
Official references
Signals
- GitHub stars
- 80
- Forks
- 6
- Last commit
- Sep 2026
- Hacker News mentions
- 5
Advanced
- Catalog kind
- skill
- Gateway key
ast-grep-edmundmiller- Source
- github.com/edmundmiller/dotfiles