pi-lens-ast-grep
Skill0 starsChanged 15 days agoISCView on GitHub
Use when searching or replacing code patterns - use ast-grep instead of text search for semantic accuracy
1 other project uses a version of this.
Adopted by
Most recently taken up by
- apmantza/pi-lensword for word, first seen Oct 8, 2026
Other versions1 project uses a version of this.
Word for word · 1
- apmantza/pi-lens★ 521100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository18 other files it gives its agents.
- AGENTS.mdAGENTS.md
- apex-performance-auditorSkill
- checkSkill
- context7-mcpSkill
- design-craftSkill
- framework-engine-stacksSkill
- guardrailsSkill
- hypermedia-engine-stacksSkill
- learning-curatorSkill
- okf-docsSkill
- pi-lens-lsp-navigationSkill
- pi-lens-write-ast-grep-ruleSkill
- pi-lens-write-tree-sitter-ruleSkill
- rust-systemsSkill
- scalabilitySkill
- select-modelSkill
- skill-authoring-visionSkill
- systems-auditorSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 1 is distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Use ast_grep_search and ast_grep_replace for semantic code search/replace.
- Very specific: line 52
Use $$$ when you don't need the captured value.
- Distinctive: line 68
Use these instead of writing raw YAML:
- Very specific: line 108
When a pattern returns zero matches and you don't know the correct node kind or field name, use ast_grep_search with dump=true to inspect a …
- Very specific: line 126
Use kind: directly when you want to match a node type without a pattern:
- Very specific: line 167
Use ast_grep_search dump=true on a sample snippet to verify the correct node kind
- Very specific: line 173
Use these as starting points, then scope paths tightly.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AST-Grep Code Search
Use ast_grep_search and ast_grep_replace for semantic code search/replace. ast-grep understands code structure, not just text.
These tools (plus ast_grep_outline, lsp_navigation) are registered but inactive by default on hosts that support pi's dynamic tooling. If a call to one of them isn't recognized, activate it first: pi_lens_activate_tools tools=["ast_grep_search", "ast_grep_replace"].
On hosts that aggregate pi-lens behind a single lens tool, the ast_grep_* tools and pi_lens_activate_tools may not be registered at all. There, fall back to the ast-grep CLI (alias sg) — patterns, metavariables, and YAML rules are identical:
# search (≈ ast_grep_search)
ast-grep run -p 'fetchMetrics($$$ARGS)' -l ts src/
# rewrite (≈ ast_grep_replace; -U applies all)
ast-grep run -p 'var $X' -r 'let $X' -l js src/ -U
# full YAML rule (≈ the rule: parameter)
ast-grep scan --rule my-rule.yml src/Structural-intent parameters map to YAML constraints: insideKind → inside: { kind: ..., stopBy: end }, hasKind/hasDescendantKind → has: { kind: ... }, follows → follows: { pattern: ... }, precedes → precedes: { pattern: ... }.
When to Use
- Function calls, imports, class methods (structured code)
- Safe replacements across files
- Use LSP first for: definitions/references/types — then scope ast-grep to files discovered by LSP
- Use grep for: partial string patterns, comments, URLs, or after one simplified ast-grep retry still returns zero matches
Golden Rules
- Be specific —
fetchMetrics($ARGS)notfetchMetrics - Scope it — always specify
pathsto relevant files - Retry once on zero matches — simplify the pattern, same
paths, then fall back to grep - Dry-run first —
apply: falsebeforeapply: true - Valid code only —
function $NAME($$$) { $$$ }notfunction $NAME( - Avoid
selectorunless expert — narrows to AST node kind; does not extract metavariables - Metavariables don't work inside strings —
from "$PATH"matches literal"$PATH", not a wildcard
Metavariables
| Syntax | Matches | Named? |
$X | single node | yes — captures the node |
$$$ | zero or more nodes | no — unnamed wildcard |
$$$ARGS | zero or more nodes | yes — captures the list |
Use $$$ when you don't need the captured value; $$$NAME when you do.
Quick Reference
Patterns
| Pattern | Matches |
fetchMetrics($ARGS) | call with any single arg |
fetchMetrics($$$ARGS) | call with any number of args |
function $NAME($$$) { $$$ } | function declaration |
import { $NAMES } from $PATH | named import (no quotes on path) |
const $X = $Y | variable declaration |
Structural-intent parameters (preferred for cross-context queries)
Use these instead of writing raw YAML:
| Parameter | Tool | What it does |
insideKind | both | Only match inside an ancestor of this node kind (searches ALL ancestors, stopBy: end) |
hasKind | both | Only match nodes whose immediate child has this kind (stopBy: neighbor — NOT recursive) |
hasDescendantKind | both | Only match nodes containing this kind anywhere in their descendants (stopBy: end) — use this instead of hasKind when the target isn't a direct child |
follows | both | Only match nodes preceded by a sibling matching this pattern |
precedes | both | Only match nodes followed by a sibling matching this pattern |
hasKind and hasDescendantKind are mutually exclusive on both tools — combining them errors.
⚠ insideKind searches ALL ancestors (stopBy: end) with no boundary of its own — on a deeply nested file it can escalate past the enclosing function you meant and match against an unrelated outer scope; scope with paths or a raw YAML rule: with its own stopBy boundary if that matters.
# console.log only inside functions
ast_grep_search pattern="console.log($MSG)" lang="typescript" insideKind="function_declaration"
# replace var with let, scoped to functions only
ast_grep_replace pattern="var $X" rewrite="let $X" lang="javascript" insideKind="function_declaration"These synthesize a YAML rule automatically. Use rule: for the full DSL when you need all/any/not, nthChild, regex, or other advanced constraints.
Raw YAML rule (rule: parameter)
Pass a complete ast-grep YAML rule to unlock the full DSL:
ast_grep_search rule="id: my-rule
language: TypeScript
rule:
pattern: console.log($MSG)
inside:
kind: function_declaration
stopBy: end" lang="typescript"Debugging unknown node kinds — ast_grep_search dump mode
When a pattern returns zero matches and you don't know the correct node kind or field name, use ast_grep_search with dump=true to inspect a SMALL representative snippet:
ast_grep_search dump=true pattern="function foo() { return 1; }" lang="typescript"Returns the full indented AST with node kinds and positions. Then use the correct kind in your pattern or insideKind.
Composite (has/inside) in raw YAML
# console.log inside a class method
pattern: console.log($$$)
inside:
kind: method_definition
stopBy: endUse kind: directly when you want to match a node type without a pattern:
# any arrow function
kind: arrow_functionCommon Gotchas
❌ $VAR inside quotes — matches literal "$VAR", not a metavar
from "$PATH" → use grep for wildcard path matching
from "./utils" → ✅ exact string literal works fine
❌ Trailing comma in objects
{ type: $T, } → use { type: $T }
❌ Shorthand property mismatch
{ runnerId: $RID } → won't match { runnerId }
use { runnerId } or { runnerId, $$$REST }
❌ Unnamed $$$ when you need the value
foo($$$) → captures nothing; use foo($$$ARGS) to inspect matches
❌ Multiple top-level statements — triggers "Multiple AST nodes are detected"
Two shapes, two fixes:
1. Sequence inside a block — wrap in braces:
foo(); bar(); → { foo(); bar(); }
2. Cross-context (module-level + block-level together, e.g. an import AND a call) —
wrapping in {} makes the pattern invalid (imports can't live inside a block).
Use two searches: find files containing the import, then scope the call search
to those paths. Or use a YAML `inside:`/`has:` rule (see Composite section above).No matches?
For nodeKind, do not also pass pattern or rule; those forms are mutually exclusive. For rule, provide YAML containing both id and language fields. Use strictness: relaxed when unnamed punctuation is the only mismatch.
- Try
strictness: relaxed— ignores unnamed punctuation (trailing commas, semicolons) thatsmartmode requires - Use
ast_grep_search dump=trueon a sample snippet to verify the correct node kind - Simplify the pattern and retry once
- Fall back to
greporlsp_navigation
Agent task recipes
Use these as starting points, then scope paths tightly.
| Task | Pattern / params |
| Find object-literal function dependency by name | pattern: { resetLSPService: $FN, $$$REST } |
| Find empty catches | pattern: try { $$$BODY } catch ($ERR) { } |
| Find fire-and-forget async calls | pattern: void $CALL |
For lifecycle bugs, search first, then use the returned details.matchLocations[].readSlice handle for bounded context.
Metavar captures appear automatically below each match line:
src/foo.ts:1:1: const x = foo(a, b)
$VAR=x $$$ARGS=a,bNamed captures ($X, $$$NAME) are shown; unnamed wildcards ($$$) are not.
Pagination — use skip: N when results are truncated (next-page hint appears in output).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

