Search Tools Mastery: Combining rg, grepai, Serena, ast-grep, scip-search & lilmd
Last updated:
Master code search and documentation navigation by combining the right tools for maximum efficiency
Author: Florian BRUNIAUX | Contributions from Claude (Anthropic) Reading time: ~25 minutes Last updated: May 2026
Table of Contents
Section titled βTable of Contentsβ- Quick Reference Matrix
- Tool Comparison
- Decision Tree
- Combined Workflows
- Real-World Scenarios
- Performance Optimization
- Common Pitfalls
- Extended Toolkit: scip-search & lilmd
Quick Reference Matrix
Section titled βQuick Reference Matrixβ| I need toβ¦ | Use This Tool | Command Example |
|---|---|---|
| Find exact text | rg (Grep tool) | rg "authenticate" --type ts |
| Find by meaning | grepai | grepai search "user login flow" |
| Find function definition | Serena | serena find_symbol --name "login" |
| Find structural pattern | ast-grep | ast-grep "async function $F" |
| See who calls function | grepai | grepai trace callers "login" |
| Get file structure | Serena | serena get_symbols_overview |
| Refactor across files | Serena + ast-grep | Combined workflow |
| Explore unknown codebase | grepai β Serena | Discovery pattern |
| Find symbol refs without MCP (worktree-safe) | scip-search | scip-search refs AuthService.login |
| Navigate a large Markdown document | lilmd | lilmd read docs/arch.md "Authentication" |
Tool Comparison
Section titled βTool ComparisonβComplete Feature Matrix
Section titled βComplete Feature Matrixβ| Feature | rg (ripgrep) | grepai | Serena | ast-grep |
|---|---|---|---|---|
| Search Type | Regex/text | Semantic (meaning) | Symbol-aware | AST structure |
| Technology | Pattern matching | Embeddings (Ollama) | Symbol parsing | Abstract Syntax Tree |
| Speed | β‘ ~20ms | π’ ~500ms | β‘ ~100ms | π ~200ms |
| Setup | β None (built-in) | β οΈ Ollama + install | β οΈ MCP config | β οΈ npm install |
| Integration | β
Native (Grep) | β οΈ MCP server | β οΈ MCP server | β οΈ Plugin |
| Privacy | β 100% local | β 100% local | β 100% local | β 100% local |
| Context needed | None | None | Project indexation | None |
| Languages | All (text) | All | TS/JS/Py/Rust/Go | TS/JS/Py/Rust/Go/C++ |
| Call graph | β No | β Yes | β No | β No |
| Symbol tracking | β No | β No | β Yes | β No |
| Session memory | β No | β No | β Yes | β No |
| False positives | Medium | Low | Very low | Very low |
| Learning curve | Low | Medium | Low | High |
Token Cost Comparison
Section titled βToken Cost Comparisonβ| Tool | Typical Query | Tokens Consumed | Results Returned |
|---|---|---|---|
| rg | βauthenticateβ | ~500 | Exact matches only |
| grepai | βauth flowβ | ~2000 | Intent-based matches |
| Serena | find_symbol | ~1000 | Symbol + context |
| ast-grep | AST pattern | ~1500 | Structural matches |
Key insight: rg is 4x more token-efficient but 10x less intelligent than semantic tools.
Extended Tool Reference
Section titled βExtended Tool ReferenceβTwo tools that address gaps in the core stack, covered in depth in Β§ Extended Toolkit:
| Tool | Category | vs existing stack |
|---|---|---|
| scip-search | Symbol index search (SCIP) | Like Serena but stateless, no MCP, worktree-safe |
| lilmd | Markdown section navigation | No equivalent in the stack (targets docs, not code) |
Decision Tree
Section titled βDecision TreeβLevel 1: What Do You Know?
Section titled βLevel 1: What Do You Know?βDo you know the EXACT text/pattern?βββ YES β Use rg (ripgrep)β ββ Known function name: rg "createSession"β ββ Known import: rg "import.*React"β ββ Known pattern: rg "async function"βββ NO β Go to Level 2Level 2: What Are You Looking For?
Section titled βLevel 2: What Are You Looking For?βWhat's your search intent?βββ "Find by MEANING/CONCEPT"β β Use grepaiβ ββ Example: grepai search "payment validation logic"βββ "Find FUNCTION/CLASS definition"β β Use Serenaβ ββ Example: serena find_symbol --name "UserController"βββ "Find by CODE STRUCTURE"β β Use ast-grepβ ββ Example: async without error handlingβββ "Understand DEPENDENCIES" β Use grepai trace ββ Example: grepai trace callers "validatePayment"Level 2 (Worktree / No MCP)
Section titled βLevel 2 (Worktree / No MCP)βWhen running in a CI environment, a git worktree, or any context where MCP servers are unavailable:
Known symbol name, no MCP available?βββ Use scip-search (pre-built SCIP index, millisecond cold start) ββ scip-search refs "AuthService.login" --format jsonLevel 3: Optimization
Section titled βLevel 3: OptimizationβFound too many results?βββ rg β Add --type filter or narrow pathββ grepai β Add --path filter or use traceββ Serena β Filter by symbol type (function/class)ββ ast-grep β Add constraints to patternCombined Workflows
Section titled βCombined WorkflowsβWorkflow 1: Exploring Unknown Codebase
Section titled βWorkflow 1: Exploring Unknown CodebaseβGoal: Understand a new project quickly
Step-by-step:
# 1. SEMANTIC DISCOVERY (grepai)# Find files related to authenticationgrepai search "user authentication and session management"# β Output: auth.service.ts, session.middleware.ts, user.controller.ts
# 2. STRUCTURAL OVERVIEW (Serena)# Understand each file's structureserena get_symbols_overview --file auth.service.ts# β Output:# - class AuthService# - login(email, password)# - logout(sessionId)# - validateSession(token)
# 3. DEPENDENCY MAPPING (grepai trace)# See how login is usedgrepai trace callers "login"# β Output: Called by UserController, ApiGateway, AdminPanel
# 4. EXACT SEARCH (rg)# Find specific implementation detailsrg "validateSession" --type ts -A 5# β Output: Full function with 5 lines of contextResult: Complete understanding in 4 commands (vs 30+ file reads)
Workflow 2: Large-Scale Refactoring
Section titled βWorkflow 2: Large-Scale RefactoringβGoal: Rename createSession β initializeUserSession across 50+ files
Step-by-step:
# 1. IMPACT ANALYSIS (grepai trace)# Understand full scopegrepai trace callers "createSession"# β Output: 47 callers across 23 filesgrepai trace callees "createSession"# β Output: Calls validateUser, createToken, storeSession
# 2. STRUCTURAL VALIDATION (ast-grep)# Ensure consistent usage patternast-grep "createSession($$$ARGS)"# β Output: All invocations with their argument patterns
# 3. SYMBOL-AWARE REFACTORING (Serena)# Precise renamingserena find_symbol --name "createSession" --include-body true# β Get exact definition + all references
serena replace_symbol_body \ --name "createSession" \ --new-name "initializeUserSession"# β Rename across all files maintaining structure
# 4. VERIFICATION (rg)# Confirm no old references remainrg "createSession" --type ts# β Should return 0 resultsResult: Safe refactoring with full dependency awareness
Workflow 3: Security Audit
Section titled βWorkflow 3: Security AuditβGoal: Find security vulnerabilities
Step-by-step:
# 1. SEMANTIC DISCOVERY (grepai)# Find security-sensitive codegrepai search "SQL query construction"grepai search "user input validation"grepai search "password handling"
# 2. STRUCTURAL PATTERNS (ast-grep)# Find specific vulnerability patterns
# SQL injection risksast-grep 'db.query(`${$VAR}`)'
# XSS risksast-grep 'innerHTML = $VAR'
# Missing error handlingast-grep -p 'async function $F($$$) { $$$BODY }' \ --without 'try { $$$TRY } catch'
# 3. DEPENDENCY TRACING (grepai)# See where vulnerable code is calledgrepai trace callers "executeQuery"# β Identify all entry points
# 4. EXACT VERIFICATION (rg)# Confirm findingsrg "innerHTML\s*=" --type tsrg "password" --type ts | rg -v "hashed"Result: Comprehensive security audit in minutes
Real-World Benchmarks
Section titled βReal-World Benchmarksβgrepai vs grep (Janvier 2026)
Section titled βgrepai vs grep (Janvier 2026)βContexte: Benchmark sur Excalidraw (155k lignes TypeScript) Auteur: YoanDev (mainteneur de grepai - biais potentiel) MΓ©thodologie: 5 questions de dΓ©couverte de code identiques
| MΓ©trique | grep | grepai | DiffΓ©rence |
|---|---|---|---|
| Tool calls | 139 | 62 | -55% |
| Input tokens | 51k | 1.3k | -97% |
Γ retenir: Recherche sΓ©mantique rΓ©duit drastiquement les tokens en identifiant les fichiers pertinents dΓ¨s la premiΓ¨re tentative, Γ©vitant lβexploration itΓ©rative.
Limitations:
- Benchmark par le mainteneur de lβoutil
- Single-project validation (TypeScript only)
- Pas de validation indΓ©pendante Γ ce jour
Source: yoandev.co/grepai-benchmark
Note: Ce benchmark reflΓ¨te lβΓ©tat de janvier 2026. Les performances peuvent Γ©voluer avec les mises Γ jour de Claude Code et grepai.
Workflow 4: Framework Migration
Section titled βWorkflow 4: Framework MigrationβGoal: Migrate React class components β hooks
Step-by-step:
# 1. INVENTORY (ast-grep)# Find all class componentsast-grep 'class $C extends React.Component'# β Output: 34 components to migrate
# 2. DEPENDENCY ANALYSIS (grepai)# Understand component relationshipsfor component in $(ast-grep 'class $C extends' --json | jq -r '.[].name'); do grepai trace callers "$component"done# β Build migration order (leaf components first)
# 3. PATTERN DETECTION (ast-grep)# Identify lifecycle methods usedast-grep 'componentDidMount() { $$$BODY }'ast-grep 'componentWillReceiveProps($$$) { $$$BODY }'# β Map to equivalent hooks
# 4. INCREMENTAL MIGRATION (Serena + ast-grep)# Migrate one component at a timeserena find_symbol --name "UserProfile" --include-body true# β Get full component code
# Use ast-grep to transformast-grep --rewrite \ --from 'class $C extends React.Component' \ --to 'const $C = () => { }'
# 5. VERIFICATION (rg + grepai)# Ensure migration successfulrg "React.Component" --type tsx # Should decreasegrepai search "component lifecycle methods" # Find any missedResult: Systematic migration with minimal breakage
Workflow 5: Performance Optimization
Section titled βWorkflow 5: Performance OptimizationβGoal: Identify and fix performance bottlenecks
Step-by-step:
# 1. HOTSPOT DISCOVERY (grepai)# Find performance-critical codegrepai search "heavy computation or loops"grepai search "database queries in loops"
# 2. PATTERN DETECTION (ast-grep)# Find N+1 query patternsast-grep 'for ($$$) { await db.query($$$) }'
# Find missing memoizationast-grep 'useMemo' --invert-match \ --in 'const $VAR = $$$'
# 3. CALL GRAPH ANALYSIS (grepai trace)# Find hot pathsgrepai trace graph "renderUserList" --depth 3# β Visualize dependency tree
# 4. SYMBOL TRACKING (Serena)# Track function changesserena write_memory "perf_baseline" \ "renderUserList: 450ms avg"
# After optimizationserena write_memory "perf_optimized" \ "renderUserList: 45ms avg (10x improvement)"
# 5. VERIFICATION (rg)# Confirm optimizations appliedrg "useMemo|useCallback" --type tsxResult: Data-driven performance improvements
Real-World Scenarios
Section titled βReal-World ScenariosβScenario 1: βI Donβt Know What Iβm Looking Forβ
Section titled βScenario 1: βI Donβt Know What Iβm Looking ForββProblem: New project, no documentation, need to add feature
Solution: Semantic-first discovery
# Start broad with meaninggrepai search "user profile management"# β Discover relevant files
# Then narrow with structureserena get_symbols_overview --file user-profile.service.ts# β Understand available functions
# Finally, exact search for detailsrg "updateProfile" --type ts -C 3Scenario 2: βThis Function is Called from Everywhereβ
Section titled βScenario 2: βThis Function is Called from EverywhereββProblem: Need to modify a function but worried about breaking things
Solution: Dependency mapping first
# 1. See all callersgrepai trace callers "calculateTotal"# β 47 callers found
# 2. Analyze caller contextsfor file in $(grepai trace callers "calculateTotal" --json | jq -r '.[].file'); do serena get_symbols_overview --file "$file"done
# 3. Identify safe vs risky call sitesast-grep 'calculateTotal($ARGS)' --json# β Group by argument patterns
# 4. Make change with confidence# Now you know all impact pointsScenario 3: βFind All Code Doing Xβ
Section titled βScenario 3: βFind All Code Doing XββProblem: Need to apply consistent pattern across codebase
Solution: Combine semantic + structural
# Example: Find all error handling code
# 1. Semantic discoverygrepai search "error handling and exception management"
# 2. Structural patternsast-grep 'try { $$$TRY } catch ($ERR) { $$$CATCH }'ast-grep 'throw new Error($MSG)'
# 3. Verify consistencyrg "catch\s*\(" --type ts | wc -l# Compare with ast-grep count to find anomaliesScenario 4: βI Need to Understand This Moduleβ
Section titled βScenario 4: βI Need to Understand This ModuleββProblem: Complex module with unclear responsibilities
Solution: Multi-tool analysis
# 1. Get symbol overview (Serena)serena get_symbols_overview --file payment.module.ts# β See all exports, classes, functions
# 2. Understand dependencies (grepai)grepai trace callees "PaymentModule"# β What does this module use?
grepai trace callers "PaymentModule"# β Who uses this module?
# 3. Find implementation patterns (ast-grep)ast-grep 'export class $C' --file payment.module.tsast-grep 'async $METHOD($$$)' --file payment.module.ts
# 4. Read specific implementations (rg)rg "processPayment" --type ts -A 20Performance Optimization
Section titled βPerformance OptimizationβChoosing the Fastest Tool
Section titled βChoosing the Fastest ToolβGeneral Rules:
- Known exact text β Always use rg first
- Unknown exact text β Use grepai, then rg for verification
- Refactoring β Serena for symbol safety
- Large migrations β ast-grep for structural precision
Performance Benchmarks
Section titled βPerformance BenchmarksβTest: Find authentication code in 500k line codebase
| Strategy | Time | Results Quality |
|---|---|---|
| rg βauthβ only | 0.2s | 5000+ false positives |
| grepai βauthβ only | 2.5s | 50 relevant results |
| grepai β rg (combined) | 2.7s | 50 relevant, verified |
| Serena symbols only | 1.5s | 12 auth functions |
| ast-grep patterns | 3.0s | 8 auth flows |
Winner: Serena symbols (fastest + high quality) for known function names
Parallelization Strategy
Section titled βParallelization StrategyβFor large codebases (>100k lines):
# Run searches in parallel
# Terminal 1: Semantic discoverygrepai search "authentication flow" > /tmp/grepai-results.json &
# Terminal 2: Symbol indexingserena get_symbols_overview --file src/**/*.ts > /tmp/symbols.json &
# Terminal 3: Pattern detectionast-grep 'async function $F' --json > /tmp/ast-results.json &
# Wait for all, then combine resultswaitjq -s '.[0] + .[1] + .[2]' \ /tmp/grepai-results.json \ /tmp/symbols.json \ /tmp/ast-results.jsonCommon Pitfalls
Section titled βCommon PitfallsβPitfall 1: Using Semantic Search for Exact Matches
Section titled βPitfall 1: Using Semantic Search for Exact Matchesββ Wrong:
grepai search "createSession" # Slow, overkillβ Right:
rg "createSession" --type ts # Fast, preciseRule: If you know the exact text, never use semantic search.
Pitfall 2: Using rg for Conceptual Search
Section titled βPitfall 2: Using rg for Conceptual Searchββ Wrong:
rg "auth.*login.*session" --type ts # Misses variationsβ Right:
grepai search "authentication and session management"Rule: Regex doesnβt understand meaning, use semantic tools.
Pitfall 3: Ignoring Call Graph Before Refactoring
Section titled βPitfall 3: Ignoring Call Graph Before Refactoringββ Wrong:
# Directly refactor without checking callersrg "oldFunction" --type ts | sed 's/oldFunction/newFunction/g'β Right:
# Check impact firstgrepai trace callers "oldFunction"# See 47 callers across 23 files# Then plan refactoring strategyRule: Always trace dependencies before modifying shared code.
Pitfall 4: Not Combining Tools
Section titled βPitfall 4: Not Combining Toolsββ Wrong:
# Use only one tool for complex taskast-grep 'async function $F' --json | jq '.[].file' | xargs -I {} vim {}# Blindly edit without understanding contextβ Right:
# Combine for full understandingast-grep 'async function $F' --json > /tmp/async.jsonfor file in $(jq -r '.[].file' /tmp/async.json); do serena get_symbols_overview --file "$file" # Context grepai trace callers "$(jq -r '.[].name' /tmp/async.json)" # UsagedoneRule: Complex tasks need multiple perspectives.
Pitfall 5: Over-Engineering Simple Searches
Section titled βPitfall 5: Over-Engineering Simple Searchesββ Wrong:
# Setup grepai + Ollama just to find a TODO commentgrepai search "TODO comments in the code"β Right:
rg "TODO" --type tsRule: Use the simplest tool that works.
Tool Selection Cheatsheet
Section titled βTool Selection CheatsheetβQuick Decision Matrix
Section titled βQuick Decision Matrixβ| Your Situation | Use This | Not This |
|---|---|---|
βFind function loginβ | rg βloginβ | grepai search βlogin" |
| "Find login-related codeβ | grepai βlogin flowβ | rg βlogin.*" |
| "Rename function safelyβ | Serena find_symbol | rg + sed |
| βWho calls this function?β | grepai trace callers | rg + grep |
| βGet file structureβ | Serena overview | rg βclass|function" |
| "Find async without try/catchβ | ast-grep | rg βasync.*{" |
| "Migrate React classesβ | ast-grep | rg + manual |
| βFind TODOsβ | rg βTODOβ | Any other tool |
Extended Toolkit: scip-search & lilmd
Section titled βExtended Toolkit: scip-search & lilmdβTwo CLI tools that address gaps in the rg/grepai/Serena stack.
scip-search
Section titled βscip-searchβscip-search queries pre-built SCIP (Sourcegraph Code Intelligence Protocol) symbol indexes. Where grepai searches by semantic meaning and Serena requires a live MCP connection, scip-search operates against a static binary index with millisecond cold starts.
| Attribute | Details |
|---|---|
| Source | github.com/liza-mas/scip-search |
| Install | curl -fsSL https://raw.githubusercontent.com/liza-mas/scip-search/main/install.sh | bash |
| Index format | SCIP (Go, TypeScript, Python, Java, Rust, and others) |
| Output | One-line text, JSON, or location-only |
Workflow: scip-search replaces the 5-10 rg/read round-trips typical for symbol discovery.
# Step 1: generate SCIP index once per languagescip-typescript index --output index.scip
# Step 2: find a symbol definitionscip-search find AuthService
# Step 3: get all references with line numbersscip-search refs AuthService.login --format json
# Step 4: read only the returned line rangesvs Serena: Serena connects to a language server and has session memory. scip-search is stateless and works against a snapshot: no MCP, no persistent process. This makes it reliable in worktrees and ephemeral CI environments where Serenaβs LSP backend may not be available.
vs grepai: grepai finds by semantic intent (βpayment validation logicβ). scip-search finds by exact or near-exact symbol identifier. They work in sequence: grepai discovers the concept, scip-search confirms the symbol.
Worktree compatibility: indexes are per-repository files with no shared state. Running scip-typescript index inside a worktree produces a local index for that worktree.
lilmd treats Markdown files as databases. It returns a table of contents with line ranges and enables targeted section reads. An agent reading a 2,000-line guide fetches one section in a single call instead of reading the full file.
| Attribute | Details |
|---|---|
| Source | github.com/molefrog/lilmd |
| Install | npm install -g lilmd |
| Runtime | Node or Bun |
Key commands:
# TOC with line ranges (inclusive, 1-indexed)lilmd docs/architecture.md
# Read a section by name (fuzzy match by default)lilmd read docs/architecture.md "Authentication"
# Read a nested sectionlilmd read docs/architecture.md "Security > JWT"
# Exact match (prefix with =)lilmd read docs/architecture.md "=Authentication Flow"Agent-specific value: the TOC output contains line ranges for each heading. An agent parses these and requests only the relevant section rather than loading the full file. The natural pipeline is: rg (find which file) then lilmd (get TOC with ranges) then Read lines:N-M (load the specific section). This also works for CHANGELOG.md, large README files, and knowledge base documents.
Worktree compatibility: stateless, no index, runs per file. Works anywhere.
Setup Priority
Section titled βSetup PriorityβRecommended Setup Order:
- Start: rg (already built-in with Grep tool) β
- Next: Serena MCP (symbol awareness, session memory)
- Then: grepai (semantic search + call graph)
- If worktrees are part of your workflow: scip-search (stateless symbol lookup, no MCP required)
- For large documentation: lilmd (targeted Markdown section reads, no setup)
- Finally: ast-grep (structural patterns, large refactoring)
Rationale: 90% of searches work with rg + Serena. Add grepai for semantic needs. Add scip-search for worktree or CI environments where MCP is unavailable. Add ast-grep only for large-scale refactoring.
Summary: The 6-Tool Toolkit
Section titled βSummary: The 6-Tool Toolkitβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ SEARCH TOOL MASTERY ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ rg (ripgrep) β Fast, exact text matching ββ ββ Use: 90% of searches ββ ββ Speed: ~20ms ββ ββ grepai β Semantic + Call graph ββ ββ Use: Concept discovery, dependency tracing ββ ββ Speed: ~500ms (finds what rg cannot) ββ ββ Serena β Symbol-aware + Session memory ββ ββ Use: Refactoring, structure understanding ββ ββ Speed: ~100ms ββ ββ ast-grep β AST structural patterns ββ ββ Use: Large migrations, complex patterns ββ ββ Speed: ~200ms ββ ββ scip-search β Symbol index (stateless, SCIP) ββ ββ Use: CI / worktrees / no MCP environments ββ ββ Speed: ~5ms cold start ββ ββ lilmd β Markdown section navigation ββ ββ Use: Large docs, TOC + line ranges per section ββ ββ Speed: instant, no index ββ ββ βββββββββββββββββββββββββββββββββββββββββββββββββββ ββ ββ Master the combination, not individual tools. ββ Each tool has a sweet spot. Use the right one. ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββFurther Reading
Section titled βFurther Readingβ- Serena MCP Guide
- grepai Documentation
- ast-grep Patterns Skill
- Architecture: Grep vs RAG History
- scip-search GitHub
- lilmd GitHub
Last updated: May 2026 Compatible with: Claude Code 2.1.7+