# search_codebase

search_codebase is hybrid code search over repowise's indexes, routing each query to symbols, file paths or the wiki by its shape, so agents skip Grep.

A single tool that, depending on the shape of the query, searches the
indexed **symbols**, **file paths**, or the **wiki**. An identifier
routes to symbol hits, a path-shaped query to file hits, and prose to
wiki-semantic search, so the agent doesn't need to pick a strategy
up front. How the documentation is indexed for search is on
[Auto-generated wiki](https://docs.repowise.dev/intelligence/auto-wiki#search); the other tools are
on [MCP tools](https://docs.repowise.dev/mcp/overview).

## When to call

- **Locating a function/class/method by name**: symbol hits pipe
  directly into [`get_symbol`](https://docs.repowise.dev/mcp/get-symbol).
- **Resolving a path-shaped query**: file hits pipe into
  [`get_context`](https://docs.repowise.dev/mcp/get-context).
- **After `get_answer`** when confidence is medium or low: explore
  the alternatives, or discover pages by topic before drilling in.

## Parameters

| Name | Type | Default | Description |
|---|---|---|---|
| `query` | string |  | Required. Identifier, path, or natural-language query. |
| `limit` | number | `5` | Max results to return. |
| `mode` | string | `auto` | auto (default) routes by query shape. concept forces wiki-semantic search. symbol / path force the structural search. hybrid runs symbol hits first, then concept pages. An unrecognised value is reported in ignored_arguments and routed as auto. |
| `kind` | string |  | Filter results by kind: "implementation", "test", "config", "doc". |
| `symbol_kind` | string |  | Restrict symbol hits to a kind: "function", "class", "method", etc. |
| `page_type` | string |  | Concept mode only: filter by page kind: "file_page", "module_page", "symbol_spotlight". |
| `repo` | string |  | Repository alias. Pass "all" for a workspace-wide federated search. |

## Modes

- **`auto`** (default) routes by query shape:
  - an **identifier** (`GitIndexer`, `index_repo`) → searches indexed symbols;
  - a **path** (`core/ingestion/indexer.py`) → searches file pages;
  - **prose** ("how do we handle retries?") → wiki-semantic search;
  - mixed prose + identifier → **hybrid** (symbol hits first, then concept pages).
- **`concept`** forces the original wiki-semantic behavior.
- **`symbol`** / **`path`** force the structural search.

## Returns

- **Symbol hits**: `{type: "symbol", symbol_id, name, kind, file, start_line, end_line, signature, next: "get_symbol"}`. Ranked by exact-name/qualified-name match, query-token coverage, then graph centrality (PageRank / betweenness / entry-point); non-test results rank before test unless `kind="test"`.
- **File hits**: `{type: "file", page_id, file, title, next: "get_context"}`.
- **Concept hits**: ranked wiki pages with `page_id`, `title`, `page_type`, `snippet`, `target_path`, `relevance_score` (raw, absolute), `confidence_score` (normalized to the top result), and `sources` (which retriever(s) surfaced the hit: `["fts"]`, `["vector"]`, or both).

Alongside `results`, the response carries a top-level **`candidates`**
list: up to `limit` distinct openable file paths, best first, one
`{path}` entry each. `results` ranks *pages*, and a page is not always a
file: a `module_page` is named by a structural group key, an `scc_page`
by `scc-<hash>`. Ranking those is correct; opening them is not.
`candidates` resolves symbol pages to their file, collapses several
symbols of one file into a single entry, and skips every page that
names no file.

**If your next move is a Read, read `candidates`.** If you're
enumerating matches or resolving a `symbol_id`, read `results`.

Tombstoned and `exclude_patterns`-excluded results are filtered out. In
workspace mode, structural and concept searches both federate across
repos and merge.

## Example

```python
search_codebase(query="GitIndexer index_repo")           # -> symbol hits
search_codebase(query="core/ingestion/indexer.py")       # -> file hits
search_codebase(query="rate limit OR throttle OR retry") # -> wiki pages
search_codebase(query="login", mode="symbol", symbol_kind="method")
search_codebase(query="caching strategies", repo="all")
```

## Things worth knowing

- **Fused, not sequential.** Concept mode runs full-text and vector
  search in parallel (each bounded, 5s / 8s, failures swallowed) and
  fuses them with Reciprocal Rank Fusion, so a page either retriever
  surfaces contributes; a hit found by both outranks one found by only
  one. `sources` on each hit says which. A keyless index simply never
  populates the vector leg, so `sources` naturally reads `["fts"]` only.
- **Fetch-and-filter**: concept mode over-fetches 3× the requested
  limit (6× when `kind` is set, since decision/module/overview pages
  all classify as `"doc"` and would otherwise crowd out
  implementation hits), then filters by `page_type` and a minimum
  relevance threshold, keeping results rank-stable when filters are
  applied.
- **Freshness tiebreak**: a small additive nudge, sized below one RRF
  rank step, so it only reorders hits retrieval already ranked close
  together, never overriding relevance. Files with commits in the last
  30 days get the full nudge, files with any commits in the last 90
  days get half, otherwise none.
- **Workspace-wide (`repo="all"`)**: queries the repos concurrently with
  a per-repo timeout and uses Reciprocal Rank Fusion (k=60) to merge
  the results; confidence scores are renormalized within the merged set.
  A repo that fails is named in `repos_failed`, and one whose index is
  behind in `repos_stale` with its rows marked `stale: true`. `get_overview`, `get_dead_code` and `get_why` (search)
  also accept `repo="all"`; `get_context`, `get_symbol`, `get_risk` and the
  other tools do not.

> **Note**
>
> `get_answer` already runs a search internally before synthesizing.
> Reach for `search_codebase` when you want the list of candidates, not a
> synthesized answer, or when you know you're looking for a symbol or file
> by name.
