ast-grep

SKILL.md

ABOUTME: ast-grep universal guide for AST-aware code search and analysis

ABOUTME: Provides patterns for Go, Python, Bash, Terraform/HCL; replaces grep for structural search

ast-grep Skill

Overview

ast-grep (sg) is the preferred tool for code search. It matches code structure, not text.

When to Use ast-grep vs grep

Tool Matches False Positives Comments/Strings
grep/ripgrep Text patterns Many Included
ast-grep AST structure None Ignored

Use grep when: Searching non-code files, paths, or full-text documentation.

Use ast-grep when: Searching code for patterns, refactoring, finding anti-patterns.


Quick Reference

# Basic search
sg -p 'pattern' -l go .

# With context
sg -p 'pattern' -l python -C 3 .

# JSON output for parsing
sg -p 'pattern' -l go --json .

# Replace (dry run)
sg -p 'old_pattern' -r 'new_pattern' -l python --dry-run .

# Multiple patterns
sg scan --rule rules.yml .

Pattern Syntax

Syntax Meaning Example
$VAR Single identifier $func($arg)
$_ Any single node (wildcard) for $_ := range $_
$$$ Zero or more items func($$$)
$$ Optional element func($$, $last)

Go Patterns

Function Definitions

# Any function
sg -p 'func $NAME($$$) $$$' -l go .

# Method on type
sg -p 'func ($RECV $TYPE) $NAME($$$) $$$' -l go .

# Function returning error
sg -p 'func $NAME($$$) ($$$, error)' -l go .

# Exported functions only
sg -p 'func [A-Z]$NAME($$$) $$$' -l go .

Error Handling

# Naked error return (anti-pattern)
sg -p 'if err != nil { return err }' -l go .

# Error with context (correct)
sg -p 'if err != nil { return fmt.Errorf($$$) }' -l go .

# Ignored errors (anti-pattern)
sg -p '$_, _ := $CALL($$$)' -l go .

# errors.Is usage
sg -p 'errors.Is($ERR, $TARGET)' -l go .

# errors.As usage
sg -p 'errors.As($ERR, &$TARGET)' -l go .

Concurrency Patterns

# Goroutine spawn
sg -p 'go $FUNC($$$)' -l go .

# Goroutine with anonymous function
sg -p 'go func($$$) { $$$ }($$$)' -l go .

# Channel operations
sg -p '$CH <- $VALUE' -l go .     # Send
sg -p '$VAR := <-$CH' -l go .     # Receive

# Select statement
sg -p 'select { $$$ }' -l go .

# sync.Mutex usage
sg -p '$M.Lock()' -l go .
sg -p '$M.Unlock()' -l go .

# Context cancellation
sg -p 'ctx.Done()' -l go .

Struct and Interface

# Struct definition
sg -p 'type $NAME struct { $$$ }' -l go .

# Interface definition
sg -p 'type $NAME interface { $$$ }' -l go .

# Embedding
sg -p 'type $NAME struct { $EMBED; $$$ }' -l go .

# JSON tags
sg -p '`json:"$TAG"`' -l go .

Common Anti-Patterns

# Global mutable state
sg -p 'var $NAME = $VALUE' -l go .

# Panic in library code
sg -p 'panic($MSG)' -l go .

# Empty interface{}
sg -p 'interface{}' -l go .

# Problematic defer (arguments evaluated immediately)
sg -p 'defer require.$FUNC(t, $CALL($$$))' -l go .

# JSON tag security issue ("-,omitempty" still allows unmarshaling)
sg -p '`json:"-,$_"`' -l go .

Python Patterns

Function Definitions

# Any function
sg -p 'def $NAME($$$): $$$' -l python .

# Async function
sg -p 'async def $NAME($$$): $$$' -l python .

# Method with self
sg -p 'def $NAME(self, $$$): $$$' -l python .

# Class method
sg -p '@classmethod
def $NAME(cls, $$$): $$$' -l python .

Class Definitions

# Any class
sg -p 'class $NAME: $$$' -l python .

# Class with inheritance
sg -p 'class $NAME($PARENT): $$$' -l python .

# Dataclass
sg -p '@dataclass
class $NAME: $$$' -l python .

# Pydantic model
sg -p 'class $NAME(BaseModel): $$$' -l python .

Error Handling

# Try/except
sg -p 'try: $$$ except $EXC: $$$' -l python .

# Bare except (anti-pattern)
sg -p 'try: $$$ except: $$$' -l python .

# Catching Exception (usually bad)
sg -p 'except Exception: $$$' -l python .

# Raise with chaining
sg -p 'raise $EXC from $CAUSE' -l python .

Type Hints

# Function with return type
sg -p 'def $NAME($$$) -> $TYPE: $$$' -l python .

# Optional type
sg -p '$VAR: Optional[$TYPE]' -l python .

# Union type
sg -p '$VAR: $TYPE1 | $TYPE2' -l python .

Common Anti-Patterns

# Mutable default argument
sg -p 'def $NAME($ARG=[]): $$$' -l python .
sg -p 'def $NAME($ARG={}): $$$' -l python .

# eval usage (security risk)
sg -p 'eval($$$)' -l python .

# exec usage (security risk)
sg -p 'exec($$$)' -l python .

# Using assert for validation (stripped in -O)
sg -p 'assert $COND, $MSG' -l python .

# print debugging
sg -p 'print($$$)' -l python .

Bash Patterns

# Function definition
sg -p '$NAME() { $$$ }' -l bash .

# If statement with [[ ]]
sg -p 'if [[ $COND ]]; then $$$; fi' -l bash .

# Old-style [ ] test (anti-pattern)
sg -p 'if [ $COND ]; then $$$; fi' -l bash .

# For loop
sg -p 'for $VAR in $$$; do $$$; done' -l bash .

# Command substitution (correct)
sg -p '$($CMD)' -l bash .

# Backticks (anti-pattern)
sg -p '`$CMD`' -l bash .

Terraform/HCL Patterns

# Resource blocks
sg -p 'resource "$TYPE" "$NAME" { $$$ }' -l hcl .

# Data blocks
sg -p 'data "$TYPE" "$NAME" { $$$ }' -l hcl .

# Variable definitions
sg -p 'variable "$NAME" { $$$ }' -l hcl .

# Output definitions
sg -p 'output "$NAME" { $$$ }' -l hcl .

# Module calls
sg -p 'module "$NAME" { $$$ }' -l hcl .

# Provider configuration
sg -p 'provider "$NAME" { $$$ }' -l hcl .

# Locals block
sg -p 'locals { $$$ }' -l hcl .

Terraform Anti-Patterns

# Hardcoded secrets
sg -p 'password = "$VALUE"' -l hcl .
sg -p 'secret = "$VALUE"' -l hcl .

# Missing description on variable
sg -p 'variable "$NAME" {
  type = $TYPE
}' -l hcl .

# Using count (prefer for_each)
sg -p 'count = $VALUE' -l hcl .

YAML Rule Files

For complex searches, use rule files:

# rules.yml
id: naked-error-return
language: go
rule:
  kind: if_statement
  pattern: |
    if err != nil {
      return err
    }
message: "Error returned without context; wrap with fmt.Errorf"
severity: warning
---
id: ignored-error
language: go
rule:
  pattern: '$_, _ := $CALL($$$)'
message: "Error ignored; handle or explicitly document reason"
severity: error

Run with:

sg scan --rule rules.yml .

Workflow: Finding Technical Debt

# Find TODOs, FIXMEs in code
sg -p '// TODO$$$' -l go .
sg -p '# TODO$$$' -l python .
sg -p '# TODO$$$' -l bash .

# Find FIXMEs
sg -p '// FIXME$$$' -l go .
sg -p '# FIXME$$$' -l python .

Workflow: Security Audit

# SQL injection risks
sg -p 'db.Query($SQL + $VAR)' -l go .
sg -p 'cursor.execute($SQL % $VAR)' -l python .
sg -p 'cursor.execute(f"$SQL")' -l python .

# Command injection
sg -p 'exec.Command($CMD + $VAR)' -l go .
sg -p 'os.system($CMD)' -l python .
sg -p 'subprocess.call($CMD, shell=True)' -l python .

# Hardcoded credentials
sg -p 'password := "$VAL"' -l go .
sg -p 'password = "$VAL"' -l python .
sg -p 'api_key = "$VAL"' -l python .

Workflow: Performance Analysis

# N+1 query patterns (Go)
sg -p 'for $_ := range $ITEMS {
    $DB.$METHOD($$$)
}' -l go .

# Goroutine leaks (missing done channel)
sg -p 'go func() {
    for {
        $$$
    }
}()' -l go .

# Python: list append in loop (prefer list comprehension)
sg -p 'for $VAR in $ITER:
    $LIST.append($$$)' -l python .

Integration with Claude Code

When using Claude Code, prefer ast-grep for structural searches:

# Instead of:
grep -r "func.*error" --include="*.go" .

# Use:
sg -p 'func $NAME($$$) ($$$, error)' -l go .

Benefits:

  • No false positives from comments or strings
  • Matches actual code structure
  • Works across renamed variables
  • Provides semantic understanding

Checklist

Before completing a code search task:

  • Used ast-grep for structural code patterns
  • Used grep/ripgrep only for non-code or full-text searches
  • Applied correct language flag (-l go, -l python, etc.)
  • Used metavariables ($VAR, $$$, $_) appropriately
  • Considered creating a rule file for complex multi-pattern searches

Resources

Weekly Installs
4
GitHub Stars
9
First Seen
Feb 16, 2026
Installed on
cline4
github-copilot4
codex4
kimi-cli4
gemini-cli4
cursor4