Use ast-grep for AST-based code pattern matching.
Use ast-grep for AST-based code pattern matching.
Skill({ skill: 'code-structural-search', args: 'pattern-here --lang ts' });
ast-grep supports 20+ languages via tree-sitter:
| Language | Flag | File Extensions |
|---|---|---|
| JavaScript | --lang js |
.js, .jsx |
| TypeScript | --lang ts |
.ts, .tsx |
| Python | --lang py |
.py, .pyi |
| Go | --lang go |
.go |
| Rust | --lang rs |
.rs |
| Java | --lang java |
.java |
| C | --lang c |
.c, .h |
| C++ | --lang cpp |
.cpp, .cc, .hpp, .hh |
| C# | --lang cs |
.cs |
| Kotlin | --lang kt |
.kt, .kts |
| Swift | --lang swift |
.swift |
| PHP | --lang php |
.php |
| Ruby | --lang rb |
.rb |
| Lua | --lang lua |
.lua |
| Elixir | --lang ex |
.ex, .exs |
| HTML | --lang html |
.html, .htm |
| CSS | --lang css |
.css |
| JSON | --lang json |
.json |
| Bash | --lang bash |
.sh, .bash |
| Thrift | --lang thrift |
.thrift |
Find all functions:
function $NAME($ARGS) { $$ }
Find functions with exactly 2 arguments:
function $NAME($A, $B) { $$ }
Find async functions:
async function $NAME($ARGS) { $$ }
Find class methods:
class $NAME {
$METHOD($ARGS) { $$ }
}
Find arrow functions:
const $NAME = ($ARGS) => { $$ }
Find console.log statements:
console.log($$$)
Find try-catch blocks:
try { $$ } catch ($ERR) { $$ }
Find all functions:
def $NAME($ARGS): $$$
Find class definitions:
class $NAME: $$$
Find async functions:
async def $NAME($ARGS): $$$
Find imports:
import $MODULE
Find from imports:
from $MODULE import $$$
Find all functions:
func $NAME($ARGS) $RETURN { $$ }
Find struct definitions:
type $NAME struct { $$$ }
Find interface definitions:
type $NAME interface { $$$ }
Find all functions:
fn $NAME($ARGS) -> $RETURN { $$ }
Find impl blocks:
impl $NAME { $$$ }
Find pub functions:
pub fn $NAME($ARGS) -> $RETURN { $$ }
Find all methods:
public $RETURN $NAME($ARGS) { $$ }
Find class definitions:
public class $NAME { $$$ }
Find interface definitions:
public interface $NAME { $$$ }
| Symbol | Meaning | Example |
|---|---|---|
$NAME |
Single node/identifier | function $NAME() {} |
$$$ |
Zero or more statements/nodes | class $NAME { $$$ } |
$$ |
Zero or more statements (block) | if ($COND) { $$ } |
$_ |
Anonymous wildcard (discard) | console.log($_) |
vs Ripgrep (grep):
vs Semantic Search (Phase 1):
Broad search with ripgrep:
Skill({ skill: 'ripgrep', args: 'authenticate --type ts' })
Structural refinement with ast-grep:
Skill({ skill: 'code-structural-search', args: 'function authenticate($$$) { $$ } --lang ts' })
Semantic understanding with Phase 1:
Skill({ skill: 'code-semantic-search', args: 'authentication logic' })
Find unvalidated inputs:
router.post($PATH, ($REQ, $RES) => { $$ })
Find SQL queries (potential injection):
db.query(`SELECT * FROM ${$VAR}`)
Find eval usage:
eval($$$)
Find deeply nested functions:
function $NAME($ARGS) {
if ($COND) {
if ($COND2) {
if ($COND3) { $$ }
}
}
}
Find long parameter lists (>5 params):
function $NAME($A, $B, $C, $D, $E, $F, $$$) { $$ }
Find unused variables:
const $NAME = $VALUE;
Find old API usage:
oldAPI.deprecatedMethod($$$)
Find callback patterns (convert to async/await):
$FUNC($ARGS, ($ERR, $DATA) => { $$ })
Find React class components (convert to hooks):
class $NAME extends React.Component { $$$ }
--lang flag — without a language flag, ast-grep applies heuristics that produce false positives; specify --lang ts, --lang py, etc. for accurate AST parsing.$$$ for variable argument lists, not * or . — ast-grep uses metavariable syntax ($NAME, $$$, $$); regex or glob syntax in patterns produces silent failures.| Anti-Pattern | Why It Fails | Correct Approach |
|---|---|---|
No --lang flag |
Wrong parser applied; produces false positives and misses | Always specify --lang ts, --lang py, etc. |
| Running project-wide without ripgrep pre-filter | Slow on large codebases; many irrelevant results | Use ripgrep to identify candidate files first |
| Regex for structural matching | Breaks on multi-line, whitespace variations, nesting | Use ast-grep AST patterns ($NAME, $$$, etc.) |
| Untested pattern on full codebase | Incorrect patterns silently return nothing | Test on one known match first |
Using * or . for wildcards |
Not valid ast-grep syntax; ignored or errors | Use $NAME for single node, $$$ for sequences |
Before starting:
Read .claude/context/memory/learnings.md
After completing:
.claude/context/memory/learnings.md.claude/context/memory/issues.md.claude/context/memory/decisions.mdASSUME INTERRUPTION: If it's not in memory, it didn't happen.