# Hybrid Code-Retrieval Pipeline

> Symbol-aware retrieval over large codebases, combining lexical, semantic and structural signals behind an intent-routed planner.

**Category:** Retrieval / RAG  
**Period:** 2026  
**Stack:** Python, Tree-sitter, SQLite FTS5, sqlite-vec, Azure OpenAI, Cohere Rerank

| Metric | Value | Independently verifiable |
|---|---|---|
| Tree-sitter extractors | 19 | yes |
| Retrieval intents | 8 | yes |
| Embedding dimensions | 3072 | yes |

---
## The problem

An LLM coding agent is only as good as the context it retrieves. Ask "what breaks if
I change this function?" and a naive semantic search returns things that *read*
similar rather than things that are actually coupled. Ask for a symbol by name and a
vector search buries the exact match under paraphrases.

Different questions need different retrieval strategies, and one pipeline tuned for
the average question serves none of them well.

## What I built

Retrieval over three signals — lexical BM25, semantic vectors, and structural
call-graph edges — fused with reciprocal rank fusion, then reranked. Chunking is
symbol-boundary rather than fixed-window, so a chunk is always a complete function
or class with its context header attached.

The part worth explaining is the routing.

### An intent table rather than a branching executor

Eight query intents each map to a row in a single declarative table: which retrieval
legs to run and in what order, how far to expand the call graph, whether to skip
reranking, how many symbols to budget, and how to pack the final context. Adding an
intent is a row, not a code change.

The sharpest pair is directional. "What does this depend on?" walks the import graph
*forward* two hops. "What breaks if I change this?" walks it *backward* one hop with a
much larger symbol budget and breadth-first packing, so every affected file gets a
representative rather than one file consuming the whole budget. Encoding graph
direction as retrieval policy is the idea I would carry to any future system.

### Fusion that does not quietly favour one signal

Reciprocal rank fusion combines the legs by rank, not score, and on collision keeps
the first-seen result rather than the highest-scoring one. That is deliberate:
cosine similarity lands in a narrow high band while BM25 scores spread low, so
score-based replacement would let the vector leg silently win every tie regardless of
which signal was actually more relevant.

### Alias-aware seeding

Import aliases exist only in import statements, never in symbol bodies, so a text
search structurally cannot find them. A dedicated retrieval leg resolves them
directly. That is not a clever trick — it came from watching real queries fail and
asking why.

## Honest limitations

Cross-file call resolution matches on bare symbol name, so common names resolve
imprecisely and those edges feed graph expansion. The system has no evaluation
harness committed alongside it, which means its retrieval quality is asserted rather
than reproducible — the single biggest gap, and the reason my own public work now
treats a committed benchmark as non-negotiable.
