name: codebase-research
description: Navigate, search, and map codebases efficiently to answer structural and locational questions. Use this skill whenever the user asks where something is in a codebase, how the code is organized, where a pattern or symbol is used or defined, what depends on a module, or whether something is still in use. Trigger for any of these signals: "where is this logic?", "find all usages of X", "where is Y defined?", "how is the codebase structured?", "what imports Z?", "is this used anywhere?", "which files handle X?", "give me an overview of the codebase", or any architectural question about an existing project. Always prefer this skill over ad-hoc file reading — it produces ranked, synthesized answers rather than raw tool output.
Codebase Research
Structured methodology for navigating and understanding codebases of any language or size.
Core Principle
SEARCH BEFORE READING. NEVER OPEN FILES WITHOUT KNOWING THEY MATTER.
Opening files speculatively wastes context and produces noisy answers. Always locate candidates first with search tools, then read only the files confirmed to be relevant.
Tooling Preference (in order):
rg (ripgrep) — fastest, natively respects .gitignore
git grep / git ls-files — respects .gitignore, available in any git repo
grep -rn + explicit --exclude-dir — fallback only when neither above is available
Never write out long --exclude-dir lists when rg or git grep can replace them.
Triage Gate
Before starting, classify the effort required:
- Simple lookup (one symbol, one file, answer obvious from a single search): Run the search, return the annotated result directly.
- Structural question (architecture overview, dependency chain, cross-cutting pattern, module responsibility): Use the full phased approach below.
When in doubt, default to the full approach — it takes minutes and prevents incomplete or misleading answers.
Language-Specific Patterns
Identify the project's language/ecosystem and load the relevant reference:
If the language is not listed (Go, Rust, Java, C#, etc.), do not stop — infer the standard constructs for that language (e.g., interface vs trait, struct vs class, package vs namespace, #include vs import) and adapt the generic Phase 2 patterns accordingly.
Phase 1: Orient
Always start here — even for simple lookups, a 30-second orientation prevents searching in the wrong place.
git ls-files | awk -F/ '{print $1}' | sort | uniq -c | sort -rn | head -20
git ls-files | grep -iE '^main\.|^app\.|^index\.|^cli\.|Makefile|package\.json|pyproject\.toml|Cargo\.toml|go\.mod|pom\.xml|build\.gradle'
Use this map to anchor all subsequent findings before searching.
Phase 2: Classify and Search
Identify the query type below, then apply the matching strategy.
All commands prefer git grep / git ls-files. Substitute rg PATTERN or grep -rn PATTERN if not in a git repo.
2A — File Name Discovery
"Where are the controllers?" / "Find the user service" / "Which files handle auth?"
Finding files by name is often faster than searching contents — always try this first for structural questions.
git ls-files | grep -i 'PATTERN'
git ls-files | grep -iE 'service|controller|route|handler|middleware|repo|repository'
git ls-files | grep -iE 'test|spec'
git ls-files | grep -iE '\.config\.'
2B — Usage Search
"Where do we use X?" / "Show all usages of Y" / "Which files call Z?"
git grep -l 'PATTERN' | wc -l
git grep -n 'PATTERN'
git grep -n 'PATTERN' | grep -vE '/test|/spec|/mock|_test\.|\.spec\.|\.test\.'
Result ranking — present findings in this order:
- Core business/domain logic
- Configuration and wiring
- Tests (label them as such — useful for understanding intended behavior)
2C — Definition Search
"Where is X defined?" / "Where is class Y?" / "Where is function Z?"
git grep -n -E '(class|def|function|const|type|interface|struct|trait|fn)\s+SYMBOL\b'
git grep -n -E 'export.*(class|function|const|type)\s+SYMBOL\b'
git grep -n -E '^pub (fn|struct|trait|impl)\s+SYMBOL\b'
git grep -n -E '^(public|private|protected).*(class|void)\s+SYMBOL\b'
If multiple definitions appear (e.g., abstract base + concrete implementation), surface all of them — this split is architecturally meaningful.
2D — Dependency Trace
"What imports X?" / "What depends on Y?" / "What does Z import?"
git grep -n -E '(import|from|require|use|#include).*MODULE_OR_SYMBOL'
head -50 path/to/file | grep -E '^import|^from|^require|^use |^#include|^using '
Aliasing — critical step: Scan results for renamed imports:
- Python:
from module import Foo as Bar → track Bar
- JS/TS:
import { Foo as Bar } or import * as Bar → track Bar
- Go:
import alias "package/path" → track alias
If an alias is found, immediately run a secondary Usage Search (2B) for the alias name. Missing aliases is the most common cause of incomplete dependency traces.
2E — Module Overview
"What does this module do?" / "Explain the X/ folder"
git ls-files -- 'module_path/*'
cat module_path/__init__.py 2>/dev/null
cat module_path/index.ts 2>/dev/null
cat module_path/index.js 2>/dev/null
cat module_path/mod.rs 2>/dev/null
cat module_path/lib.go 2>/dev/null
git grep -n -E '^(class|def|function|export|pub fn|func|type|interface|struct)\s+' -- 'module_path/*'
git ls-files -- 'module_path/*' | xargs wc -l 2>/dev/null | sort -rn | head -5
Summarize as: Purpose → Public API → Key classes/functions → How it connects outward.
2F — Architecture Map
"How is the codebase structured?" / "Give me an overview" / "What are the main components?"
git ls-files | grep -E '__init__\.py$|/index\.ts$|/index\.js$|/mod\.rs$'
git grep -l -E 'if __name__.*__main__|ReactDOM\.render|createRoot|app\.listen|fn main\(\)|func main\(\)'
git grep -n -E 'class.*\b(ABC|Protocol)\b|^interface |^abstract class |^trait |^type.*interface\b'
git ls-files | grep -iE 'dependencies|container|config|settings|providers|module|wiring'
Present findings as a conceptual layer diagram:
- Entry layer — CLI, HTTP handlers, event listeners, main executables
- Domain / service layer — business logic, use cases, application services
- Infrastructure layer — DB, external APIs, storage, queues, caches
- Shared / cross-cutting — config, utils, base classes, types, constants
2G — Dead Code Check
"Is X still used?" / "Can I delete Y?"
git grep -n -E '(def|class|function|const|type)\s+SYMBOL\b'
git grep -n '\bSYMBOL\b' | grep -vE '(def|class|function|const)\s+SYMBOL'
git grep -n 'SYMBOL' $(git ls-files | grep -E '__init__\.py$|index\.(ts|js)$')
git grep -n '\bSYMBOL\b' | grep -E '/test|/spec|_test\.|\.spec\.|\.test\.'
Return a clear verdict: Used / Unused / Uncertain — with explicit reasoning for each.
Phase 3: Synthesize and Present
Never output raw search results. Always annotate and synthesize.
Output Format
## Finding: [one-line direct answer to the question]
### Locations
- `path/to/file:42` — [what is happening here and why it matters]
- `path/to/other:87` — [what is happening here]
### Context
[1–3 sentences on what this tells us about the design or architecture]
### Notes ← only include if genuinely useful
[Caveats, aliases spotted, related symbols, patterns worth knowing]
Rules:
- Lead with the answer, not the search process
- File paths must be relative and include line numbers (
path/to/file:42)
- Every location gets an annotation — no bare paths or line numbers
- If more than ~8 results, group them: "5 usages in
api/routes/, 2 in services/, 1 in tests"
- If nothing found, say so immediately and suggest likely alternatives (typo? aliased import? different module?)
Process Violations — Red Flags
Stop and correct if you catch yourself doing any of the following:
- Opening files speculatively to search their contents instead of using
grep/rg first
- Writing long
--exclude-dir lists when rg or git grep would handle it automatically
- Pasting raw search output without annotation
- Reading every file in a directory instead of checking the public API entry first
- Running the same search twice with slightly different wording instead of narrowing with better flags
- Reporting 20+ locations without grouping or prioritizing
- Tracing a dependency without checking for aliased imports
Pre-Answer Checklist
Before presenting findings, verify: