Searching codebases
Skill oaustegard/claude-skills/plugins/code-intelligence/skills/searching-codebases
Binding-resolved Python symbol queries — find all true callers (--refs), go-to-definition (--def), or inferred signature (--hover) of a .py symbol via pyright, excluding same-named false positives that text grep cannot. Use when a task needs ALL callers/users of a Python symbol or its real definition and text matching would over-match. For everything else — literal tokens, regex patterns, concept/natural-language search, any repo size — plain ripgrep is faster and equally accurate: measured 2026-07-04 on real issue-localization tasks, the semantic and indexed-regex tiers tied or lost against naive rg at 4-60x the wall-clock cost. Those tiers remain available below but are NOT recommended as a default.From its SKILL.md
npx -y skills add oaustegard/claude-skills --skill searching-codebasesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
7.6 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it
Searching Codebases
Find code in any codebase by pattern or concept. One entry point, two search strategies, automatic routing.
Prerequisites
uv tool install ripgrep
tree-sitting installs automatically when needed — for --expand context
expansion and for the binding-resolved --refs/--def/--hover tier, which
uses it to resolve symbol positions. Only the bare tree-sitter package is
fetched; the language grammars ship bundled.
Primary Command
SKILL_DIR=/mnt/skills/user/searching-codebases
python3 $SKILL_DIR/scripts/search.py SOURCE "query1" ["query2" ...] [OPTIONS]
SOURCE is any of:
- Local directory path
- GitHub URL (downloads tarball automatically)
uploads(uses/mnt/user-data/uploads/)project(uses/mnt/project/)- Path to a
.zipor.tar.gzarchive
Search Modes
Regex mode (patterns, identifiers, literal text):
python3 $SKILL_DIR/scripts/search.py ./repo "def handle_error"
python3 $SKILL_DIR/scripts/search.py ./repo "class.*Exception" --regex
python3 $SKILL_DIR/scripts/search.py ./repo "TODO|FIXME|HACK"
Semantic mode (concepts, natural language):
python3 $SKILL_DIR/scripts/search.py ./repo "retry logic with backoff" --semantic
python3 $SKILL_DIR/scripts/search.py ./repo "authentication flow"
python3 $SKILL_DIR/scripts/search.py ./repo "error handling strategy"
Auto-detection: short queries and code-like tokens → regex. Multi-word
natural language → semantic. Override with --regex or --semantic.
Binding-resolved mode (Python only — pyright via the python-lsp skill):
python3 $SKILL_DIR/scripts/search.py ./repo --refs SYMBOL # find all real uses
python3 $SKILL_DIR/scripts/search.py ./repo --def SYMBOL # go-to-definition
python3 $SKILL_DIR/scripts/search.py ./repo --hover SYMBOL # inferred type/signature
Regex mode matches text, so a cross-reference for a function false-positives
on shadowed and same-named-but-unrelated symbols. --refs is binding-resolved:
pyright excludes the unrelated same-named symbol and follows imports. Use it when
you need a true "find all callers/users" for a .py symbol, not a text grep.
The tier is engaged lazily — pyright's index cost is paid only when you ask
for --refs/--def/--hover, never on ordinary searches. It is Python-only;
for non-.py sources, or when pyright/node is unavailable, it prints a one-line
degradation note and falls back to the regex text path. Each takes a single bare
symbol name and is mutually exclusive with the other two and with text queries.
Options
--regex/--semantic: Force search mode--refs SYMBOL/--def SYMBOL/--hover SYMBOL: Binding-resolved Python queries via pyright (see Binding-resolved mode above)--expand: Return full function bodies via tree-sitting AST context--benchmark: Compare indexed regex vs brute-force ripgrep--branch NAME: Git branch for GitHub URLs (default: main)--skip DIRS: Comma-separated directories to skip--json: Machine-readable output-v: Show index stats and query routing decisions
How It Works
Regex search builds a sparse n-gram inverted index over all files. Queries are decomposed into literal fragments, looked up in the index to identify candidate files (typically 90-99% reduction), then verified with ripgrep. Frequency-weighted n-grams make rare character sequences more selective.
Semantic search builds a TF-IDF index over code chunks (functions, classes, structural entries). Queries are ranked by cosine similarity.
Context expansion (--expand) uses tree-sitting's AST cache to
identify function/class boundaries, returning complete structural units
rather than line fragments. On first use, tree-sitting scans the repo
(~700ms for 250 files); subsequent expansions are sub-millisecond.
Small codebases (< 20 files) skip indexing entirely — direct ripgrep is faster when there's nothing to narrow.
Mixed Queries
Multiple queries can use different modes in a single invocation. Each query is auto-routed independently, and indexes are built once per mode:
python3 $SKILL_DIR/scripts/search.py ./repo \
"class.*Error" \
"error recovery strategy" \
"def retry"
Dependencies
- tree-sitting: Provides AST context expansion for
--expandand the symbol→position resolution that seeds the binding-resolved tier (--refs/--def/--hover). Auto-installs the baretree-sitterpackage when either is used (grammars are bundled). Regex and semantic search work without it. - ripgrep: Required for regex verification. Install via
uv tool install ripgrep. - scikit-learn: Required for semantic mode. Installs automatically.
- python-lsp: Provides the binding-resolved tier (
--refs/--def/--hover). Self-bootstraps pyright on first use and requires systemnode(v18+). Not required — without it those flags degrade to the regex text path.
When to Use — narrow, by design
The ONE recommended use: binding-resolved Python symbol queries.
- "find all callers of
X" / "where isXreally defined" for a.pysymbol, when same-named-but-unrelated symbols would pollute a text grep. Empirical basis:rg geton psf/requests returned 232 hits, 224 of them false;--refs getexcluded all 224 (2026-06-15).
When NOT to Use — which is most of the time
Everything else. Measured head-to-head on real issue-localization tasks (7 scikit-learn issues with merged fix-PRs, gold = PR diff files, 2026-07-04, replicating the file-discovery metric of arXiv:2602.11988):
- Literal tokens / identifiers: naive
rg -ltied or beat the indexed tier on recall@10 in every instance, at 0.4s vs 25s. - Concept / natural-language search: the TF-IDF semantic tier never beat identifier grep — not even on identifier-poor issues, which are themselves rare (~0.3% of merged-PR traffic in the sample).
- First encounter / "what is this repo": use exploring-codebases.
- Repos under ~20 files: read them.
The self-test before invoking: would plain rg return the same answer?
If yes, use rg. The indexed-regex and semantic tiers are retained for
completeness and for corpora where they may yet earn their cost (very
large repos, non-code document collections), but they carry the burden
of proof.
Files
scripts/search.py— Entry point, query routing, output formattingscripts/resolve.py— Input source resolution (GitHub, uploads, archives)scripts/context.py— tree-sitting-based AST context expansionscripts/ngram_index.py— Sparse n-gram inverted index, regex decompositionscripts/sparse_ngrams.py— Core n-gram algorithms, frequency weightsscripts/code_rag.py— TF-IDF semantic search over code chunksscripts/lsp_refs.py— Binding-resolved Python tier: symbol→position resolution (tree-sitting), pyright queries (python-lsp), soft fallback
What ships with it: 14 files
100.4 KB alongside SKILL.md, 12 of them executable
scripts/
- code_rag.pyruns20.4 KB
- context.pyruns6.3 KB
- lsp_refs.pyruns18.4 KB
- ngram_index.pyruns20.7 KB
- resolve.pyruns4.5 KB
- search.pyruns12.8 KB
- sparse_ngrams.pyruns6.1 KB
tests/
- fixture/pkg/__init__.pyruns0 B
- fixture/pkg/models.pyruns188 B
- fixture/pkg/other.pyruns62 B
- fixture/pkg/service.pyruns125 B
- test_lsp_refs.pyruns5.5 KB
- CHANGELOG.md3.4 KB
- README.md1.9 KB