Ast grep
Use for polyglot structural code search, lint, and rewrite with ast-grep (alias `sg`) across JavaScript / TypeScript / TSX, Python, Go, Rust, Java, Kotlin, C / C++, C#, Ruby, PHP, Swift, Bash, HTML, CSS, JSON, YAML, and more. Reach for it instead of grep / sed when a regex would over- or under-match because of formatting, comments, or nested structures. Covers `ast-grep run -p` one-shot patterns, `ast-grep scan` with YAML rules, `ast-grep new project` scaffolding, `ast-grep test` for rule snapshots, meta-variable syntax (`$VAR`, `$_`, `$$$`), composite rules (`all`, `any`, `not`, `inside`, `has`, `precedes`, `follows`), `constraints` regex filters, `fix` rewrites, `sgconfig.yml`, JSON output for tooling, and CI usage.From its SKILL.md
npx -y skills add Jylhis/skills --skill ast-grepAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.2 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it
ast-grep
ast-grep (CLI binary ast-grep, also aliased sg) is a polyglot
tree-sitter-backed tool for structural code search, lint, and rewrite.
Use it whenever a grep / sed regex would be brittle: it matches on
the parsed AST, so formatting, whitespace, and comments don't matter.
Default to ast-grep over regex for: API migrations, codemods,
deprecating a function, finding insecure patterns, enforcing in-house
lint rules across multiple languages.
Install
brew install ast-grep # macOS / Linux
npm i -g @ast-grep/cli # Node ecosystem
cargo install ast-grep --locked # Rust
pip install ast-grep-cli # Python ecosystem
The binary is ast-grep. sg is an alias on most distributions; on
some systems sg collides with /usr/bin/sg (setgid) — use
ast-grep in scripts.
Quick search and rewrite (ast-grep run)
run is the default subcommand; ast-grep -p ... and
ast-grep run -p ... are equivalent.
ast-grep -p 'console.log($A)' -l ts src/
ast-grep -p 'console.log($A)' -r 'logger.debug($A)' -l ts src/
ast-grep -p 'foo($$$)' -l js --json=stream | jq .
Key flags:
-p, --pattern— pattern source.-l, --lang— explicit language (js,ts,tsx,py,go,rust,java,kotlin,c,cpp,csharp,ruby,php,swift,bash,html,css,json,yaml, …). Inferred from file extension if omitted.-r, --rewrite— replacement template.-i, --interactive/-U, --update-all— confirm or apply rewrites.--stdin— read code from stdin.--json=pretty|stream|compact— machine-readable output.-A,-B,-C— context lines (likegrep).--globs— include / exclude paths.--debug-query -l <lang>— print the tree-sitter parse of the pattern; the first thing to reach for when a pattern doesn't match.
Pattern syntax
Patterns are real source code in the target language. Meta-variables introduce holes:
| Token | Matches |
|---|---|
$VAR | Exactly one named AST node; the same name must match identically. |
$_ | Exactly one anonymous node (don't capture). |
$$VAR | Exactly one unnamed AST node, captured (vs. $VAR which captures named nodes). |
$$$ | Ellipsis: any number of sibling nodes (args, statements, items). |
$$$VAR | Named ellipsis: capture the sequence for use in --rewrite. |
Examples:
# Any console method
ast-grep -p 'console.$METHOD($$$)' -l ts
# Promise.then with arrow callback
ast-grep -p '$P.then($X => $$$)' -l js
# Empty catch block
ast-grep -p 'try { $$$ } catch ($_) { }' -l ts
YAML rules and ast-grep scan
Use scan for repeatable rules with messages, fixes, and severity.
ast-grep new project # scaffolds sgconfig.yml + rules/ + rule-tests/ + utils/
ast-grep new rule no-eval -l js
ast-grep scan # uses sgconfig.yml
ast-grep scan -r rule.yml # one-off rule file
ast-grep scan --inline-rules '{id: x, language: js, rule: {pattern: eval($A)}}'
ast-grep scan --filter '^security-' --json=stream
ast-grep scan -U # apply all fixes without prompting
Rule file shape (rules/no-eval.yml):
id: no-eval
language: JavaScript
severity: error
message: Avoid eval; it executes arbitrary code.
note: Use JSON.parse or a real parser.
rule:
pattern: eval($CODE)
fix: JSON.parse($CODE)
Rule operators
-
Atomic:
pattern,kind(tree-sitter node kind),regex,nthChild,range. -
Relational:
inside,has,precedes,follows. Each takes a sub-rule plus optionalstopBy: end | neighbor | <rule>andfield: <name>(e.g.field: parameter). -
Composite:
all: [...],any: [...],not: <rule>,matches: <util-id>. -
constraints— per-meta-variable filters:rule: pattern: fetch($URL) constraints: URL: regex: '^["'']http://' # only flag plain http -
utilsinsgconfig.ymlor per-rule — named sub-rules reused viamatches: <id>. Promote any rule that appears in two places. -
rewriters— multiple fix templates selected by sub-rule, useful for one rule that produces different rewrites by case.
Project layout (sgconfig.yml)
ruleDirs:
- rules
testConfigs:
- testDir: rule-tests
utilDirs:
- utils
ast-grep walks up from CWD to find sgconfig.yml, so scan works
from any subdirectory of the project.
Testing rules (ast-grep test)
Each rule gets a sibling YAML in rule-tests/<id>-test.yml with
valid and invalid snippets. ast-grep test runs them, supports
--snapshots for golden fixes, and -U to update snapshots.
ast-grep test # run all
ast-grep test -f no-eval # filter by id regex
ast-grep test -U # accept new snapshots
Common idioms
-
Match-only, no fix: omit
fix. The rule still reports. -
Lint codebase in CI:
ast-grep scan --error # exits non-zero on any error-severity match -
Codemod with review:
ast-grep scan -i(interactive) or... -Uafter a dry run. -
Pipe into jq / ripgrep:
ast-grep --json=streamemits one JSON object per match per line. -
Hybrid lint with another tool: run
ast-grep scanalongside Ruff / ESLint / Clippy — ast-grep handles cross-language and project-specific rules they can't express.
Footguns
- A pattern that looks right but doesn't match — almost always a
tree-sitter parse mismatch. Run with
--debug-query -l <lang>to see how ast-grep parsed the pattern; adjust until the AST matches what's in the source files. -lis required when piping from stdin or when the file extension is ambiguous (.h,.tsfor TypeScript vs Typoscript, etc.).- Tree-sitter grammar drift — rules tied to a specific node
kindcan break when ast-grep upgrades a grammar. Preferpatternover rawkind:when both work; keep snapshot tests so drift is caught byast-grep test. fixstrings are templates, not code —$VARis substituted textually. Wrap in parentheses if precedence matters (fix: '($A)?.foo').- Don't reach for ast-grep for plain string search.
rgis faster and clearer for non-structural matches.
Editor / LSP integration
ast-grep lsp runs a Language Server that surfaces scan diagnostics
and quick-fixes in any LSP-aware editor. It uses the same
sgconfig.yml, so editor warnings stay in sync with CI.
ast-grep lsp # invoke from your editor's LSP config
The official VS Code extension is ast-grep.ast-grep-vscode.
Neovim users: configure ast-grep via nvim-lspconfig (server name
ast_grep).
Tool detection
for tool in ast-grep jq rg; do
command -v "$tool" >/dev/null && echo "ok: $tool" || echo "MISSING: $tool"
done
jq and rg are not required, but most workflows that consume
--json output or pre-filter files for ast-grep use them.
References
- Docs: https://ast-grep.github.io/
- Pattern reference: https://ast-grep.github.io/guide/pattern-syntax.html
- Rule reference: https://ast-grep.github.io/reference/rule.html
- CLI reference: https://ast-grep.github.io/reference/cli.html
- Rule catalog (copy-paste examples): https://ast-grep.github.io/catalog/
- Playground (paste code, iterate on patterns): https://ast-grep.github.io/playground.html
What ships with it: 27 files
22.2 KB alongside SKILL.md
evals/
- cases.yaml6.1 KB
- golden/13d0d44fba038802.json561 B
- golden/140b7c655111f295.json552 B
- golden/188668f794134f00.json767 B
- golden/1da7b1b734ca5582.json580 B
- golden/2611692e592d1961.json584 B
- golden/26264856b4a87b85.json556 B
- golden/33b0617b20cab745.json763 B
- golden/3a7b44bae3489a12.json578 B
- golden/46dc9b867d2f1356.json542 B
- golden/4cb037e965b668c2.json537 B
- golden/66ca2bd487d366f1.json586 B
- golden/6a3ef823125e6cb4.json550 B
- golden/87000054ee683d5b.json543 B
- golden/877d8dbe3b31816b.json546 B
- golden/c8c0fc20b59a9e62.json555 B
- golden/d224bb7908613b9a.json761 B
- golden/d28ff609fbb1fc2f.json540 B
- golden/d3358cb10b2c6afe.json582 B
- golden/db93bd7c38b7ec5b.json539 B
- golden/dddcb43c09581e2d.json557 B
- golden/de34708e51b72121.json587 B
- golden/ec47903f7815b3b1.json593 B
- golden/f67ab76dafa04dd0.json580 B
- golden/ff26a9047442218b.json589 B
- golden/.gitkeep239 B
- rubric.md2.0 KB