| name | cli-search-tools |
| description | Optimally use rg (ripgrep), fd, jq, and yq for code exploration, file discovery, and structured data querying in any repository. Use when asked to search code, find files, grep for patterns, explore a codebase structure, parse JSON or YAML configs, inspect package.json or pyproject.toml, extract API response data, find all usages of a function or variable, or filter results across file types. Works with any language, framework, or project structure. |
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