| name | cli-search-tools |
| description | Use when asked to search, grep, find files, locate symbol usages, inspect repository structure, or parse JSON/YAML/TOML using rg, fd, jq, and yq across any language or framework. |
CLI Search Tools
Four focused tools that cover nearly all read-only codebase exploration and structured data tasks. Prefer these over native shell search commands — they are faster, smarter, and composable.
| Tool | Purpose | Best for |
|---|
rg | Fast regex content search | Finding where identifiers, strings, or patterns appear |
fd | Fast file/directory finder | Discovering files by name, extension, or location |
jq | JSON stream processor | Parsing, filtering, and transforming JSON data |
yq | YAML/JSON/XML/TOML processor | Reading and querying structured config files |
When to Use This Skill
- Searching for function, class, or variable usages across a codebase
- Finding files by name, extension, or directory pattern
- Parsing
package.json, pyproject.toml, *.yaml, or any structured config
- Extracting data from API JSON responses or log files
- Exploring an unfamiliar codebase efficiently before making changes
- Combining search and structured parsing in a pipeline
Prerequisites
Check availability before use:
command -v rg && echo "rg installed"
command -v fd || command -v fdfind && echo "fd installed"
command -v jq && echo "jq installed"
command -v yq && echo "yq installed"
# Windows PowerShell (fallback)
Get-Command rg -ErrorAction SilentlyContinue
Get-Command fd -ErrorAction SilentlyContinue
Get-Command jq -ErrorAction SilentlyContinue
Get-Command yq -ErrorAction SilentlyContinue
fd binary name by platform: On Ubuntu/Debian (including WSL), the apt package fd-find
installs the binary as fdfind. Shell profiles alias it to fd, but agents running
non-interactive bash/zsh sessions do not inherit those aliases. Use fdfind explicitly
on Linux/WSL, or resolve at runtime (see fd section below).
Install if missing:
winget install BurntSushi.ripgrep.MSVC sharkdp.fd jqlang.jq MikeFarah.yq
brew install ripgrep fd jq yq
sudo apt install ripgrep fd-find jq
pip install yq
Tool Selection Guide
Search file CONTENTS for text or pattern? → rg
FIND files by name, extension, location? → fd
Query or transform JSON data? → jq
Query or transform YAML / TOML / XML? → yq
Find files, then search their contents? → fd | rg (or rg with globs)
Search and parse JSON in rg output? → rg --json | jq
rg — Content Search
Essentials
rg "pattern"
rg -i "pattern"
rg -F "exact.string"
rg -w "word"
rg -l "pattern"
rg -c "pattern"
rg -C 3 "pattern"
rg -n "pattern"
Filter by File Type
rg "pattern" --type py
rg "pattern" --type js
rg "pattern" --type ts
rg "pattern" --type json
rg "pattern" --type yaml
rg --type-list
rg "pattern" -g "*.test.ts"
rg "pattern" -g "!*.test.ts"
Scope and Exclusion
rg "pattern" src/
rg "pattern" -g "!node_modules/**"
rg "pattern" --hidden
rg "pattern" --max-depth 3
rg "pattern" -L
Structured Output (for Piping)
rg "pattern" --json | jq 'select(.type=="match") | .data.path.text'
rg -l0 "pattern" | xargs -0 wc -l
rg "pattern" --no-filename src/module.py
Code Exploration Patterns
rg "^def " --type py
rg "^(export )?function " --type js
rg "^(export )?(async )?function\b" --type ts
rg "^class " --type py
rg "^(export )?(abstract )?class " --type ts
rg "\bmyFunction\b"
rg "TODO|FIXME|HACK|XXX"
rg "from mymodule import|import mymodule" --type py
rg "except .+:" --type py
rg "catch\s*\(" --type ts
fd — File Discovery
Cross-Platform Binary Name
| Platform | Binary | Install |
|---|
| Windows (Git Bash/PowerShell) | fd | winget install sharkdp.fd |
| macOS (Homebrew) | fd | brew install fd |
| Linux / WSL (Ubuntu/Debian) | fdfind | sudo apt install fd-find |
Agent rule: Do not assume fd resolves on Linux/WSL. Resolve the binary at runtime:
FD=$(command -v fd 2>/dev/null || command -v fdfind) && $FD "pattern" dir/
Or inline per command:
$(command -v fd 2>/dev/null || echo fdfind) -e py src/
Essentials
fd "config"
fd -e py
fd -e yaml -e yml
fd "\.test\.(ts|js)$"
fd -t d "src"
fd -t f "readme"
Scoping and Exclusion
fd "pattern" src/
fd "pattern" --exclude node_modules --exclude .git
fd -H "pattern"
fd "pattern" --max-depth 2
fd "pattern" --absolute-path
Output and Piping
fd -e py --exec rg "TODO" {}
fd -0 "pattern" | xargs -0 wc -l
fd -e json --max-depth 1
Common Discovery Tasks
fd "test_" -e py
fd "\.spec\.(ts|js)$"
fd "\.test\.(ts|js)$"
fd -e yaml -e yml -e toml -e json --max-depth 2
fd -e md
fd --changed-within 7d
fd --size +1mb
jq — JSON Query
Essentials
jq '.'
jq '.field'
jq '.parent.child'
jq '.[0]'
jq '.items[]'
jq -r '.version'
jq -c '.items[]'
Filtering and Conditions
jq '.items[] | select(.status == "active")'
jq '.items[] | select(.id != null)'
jq '.items[] | select(.count > 10)'
jq '.items[] | select(.name | contains("api"))'
Common Repo Tasks
jq '.version' package.json
jq '.dependencies | keys' package.json
jq '.scripts' package.json
rg "pattern" --json | jq -r 'select(.type=="match") | .data.path.text' | sort -u
rg "pattern" --json \
| jq -r 'select(.type=="match") | .data.path.text' \
| sort | uniq -c | sort -rn
jq 'keys' file.json
Transformation
jq '[.items[] | {id: .id, label: .name}]'
jq '[.items[] | .tags[]] | unique'
jq '[.items[] | .status] | group_by(.) | map({status: .[0], count: length})'
jq '.version = "2.0.0"' file.json
jq 'del(.private)' package.json
yq — YAML / TOML / XML Query
Essentials
yq '.'
yq '.field' file.yaml
yq '.parent.child' config.yaml
yq '.tool.ruff.line-length' pyproject.toml
yq '.version' package.json
Common Config Exploration
yq '.jobs | keys' .github/workflows/ci.yml
yq '.jobs.build.steps[].name' .github/workflows/ci.yml
yq '.on' .github/workflows/release.yml
yq '.services | keys' docker-compose.yml
yq '.services.app.environment' docker-compose.yml
yq '.project.version' pyproject.toml
yq '.project.dependencies' pyproject.toml
yq '.tool.ruff.line-length' pyproject.toml
yq '.metadata.name' deployment.yaml
yq '.spec.containers[].image' deployment.yaml
yq 'select(.kind == "Deployment") | .metadata.name' manifests.yaml
Format Conversion
yq -o=json file.yaml | jq '.field'
yq -o=yaml file.json
yq -o=json pyproject.toml | jq '.tool.ruff'
Combined Power Patterns
fd -e py --exec rg -l "old_function" {} | sort
fd -e yml -e yaml .github/ --exec rg -l "uses: actions/checkout" {}
fd -e json --max-depth 1 --exec sh -c 'echo "=== {} ==="; jq "keys" {}'
rg -n "TODO|FIXME" -C 1 --type py
rg "^from (.+) import|^import (.+)" --type py -o --no-filename | sort -u
rg "def test_" --json --type py \
| jq -r 'select(.type=="match") | "\(.data.path.text):\(.data.line_number)"'
fd "pyproject.toml" --exec yq '.project.dependencies' {}
Output Format Tips for AI Agent Use
- Prefer
rg --json | jq over parsing plain rg output — handles filenames with colons or spaces
- Use
jq -r for raw strings when embedding results in further shell commands
- Use
fd -0 | xargs -0 for filenames that may contain spaces
- Use
yq -o=json | jq when you need YAML data fed into a jq pipeline
- Use
rg -l (filenames only) when building a file list to pass to other tools
- On Windows PowerShell, pipe works the same; prefer single quotes inside double-quoted
-e expressions
- PowerShell stderr: Use
2>$null instead of 2>/dev/null. Never use 2>&1 when
piping --json output to a JSON consumer — it merges stderr and corrupts JSON.
Tool Selection Matrix
| Need | Best tool | Fallback |
|---|
| Find function or class definition | rg "^def|^class" dir/ | grep_search |
| Find all usages of a symbol | rg symbol dir/ | grep_search |
| Full semantic code search | semantic_search | rg with globs |
| Find a file by partial name | fd partial_name (Win/macOS), fdfind partial_name (Linux/WSL) | file_search |
| Find files by extension | fd -e ext dir/ (Win/macOS), fdfind -e ext dir/ (Linux/WSL) | file_search **/ext |
| Inspect JSON output | jq pipe | manual read_file |
| Inspect YAML/TOML configs | yq | manual read_file |
| Semantic / conceptual questions | semantic_search | N/A |
Integration with Agent Workflow
When rg and fd are available, prefer them in the parallel context-gathering phase.
On Linux/WSL use fdfind directly (agents do not inherit shell aliases):
Phase 1 (parallel read-only): rg / fd (or fdfind on Linux/WSL) / jq for fast discovery
Phase 2 (sequential): read_file for specific line ranges
Phase 3 (sequential): edits + validation
Example workflow for finding and fixing a function:
rg "def my_function" src/ --type py
rg "my_function" src/ --type py
fd "test_" tests/ -e py --exec rg "my_function" {}
Command Safety Guardrails (PowerShell Only)
These rules apply only when the shell is PowerShell. Git Bash, macOS, and WSL do not have these constraints.
Multi-key sorting
# FORBIDDEN — parser error
Sort-Object Percent -Descending, Lines -Descending
# CORRECT — explicit per-key direction (preferred)
Sort-Object -Property @{Expression='Percent'; Descending=$true}, @{Expression='Lines'; Descending=$true}
# CORRECT — same direction for all keys
Sort-Object -Property Percent, Lines -Descending
Markdown lint target discipline
- Run Markdown linters only on Markdown targets (
*.md).
- Do not pass JSON, Python, or other non-Markdown files to markdownlint tools.
- Prefer a project-provided Markdown lint script (e.g.
npm run lint:md) to keep globs and ignores consistent.
References