Semantic search over code is not an embedding problem with a vector database bolted on. In production, retrieval quality is usually dominated by five coupled decisions: benchmark discipline, chunk boundaries, index choice, lexical+dense fusion, and update policy. Sourcegraph's public engineering posts explicitly separate retrieval from ranking under token-budget constraints, while recent code-RAG work shows that chunking alone can move retrieval recall by several points.
Code search also has a benchmark trap that is easy to miss. CodeSearchNet made natural-language-to-code retrieval practical as a public task, with about 6 million functions across six languages, 99 natural-language queries, and roughly 4,000 expert relevance annotations. But CoIR was introduced later because models were overfitting existing code leaderboards; it spans 10 curated datasets, 8 retrieval tasks, and 7 domains, and its authors show large CodeSearchNet-to-CoIR gaps for several popular models. Any architecture discussion that treats CodeSearchNet as sufficient is already behind the state of the field.
The practical conclusion is straightforward. For closed-model stacks, Voyage has the strongest code-retrieval story in the public sources I found. For open and self-hosted stacks, Nomic has the strongest code-specific evidence. OpenAI's text-embedding-ada-002 remains an important historical baseline because it unified text and code search into one model, but it is hard to recommend as a greenfield choice on retrieval quality alone. Mixedbread is compelling as an open general retriever with strong compression knobs and increasingly strong reranking support, but the public evidence is much stronger for general retrieval than for code-specialized embedding.
Benchmark hygiene before architecture
CodeSearchNet still matters because it shaped the field's default unit of retrieval: the function. A large fraction of code-search systems still assume that "retrieve code" means "retrieve a function or method body," partly because that is how the benchmark corpus was built. OpenAI's own code-search example follows the same pattern: extract Python functions, embed each function, and score natural-language queries against function embeddings. This is why function-level indexing feels natural to so many teams; it is not just an engineering convenience, it is benchmark inheritance.
But CodeSearchNet is no longer enough. CoIR's authors built a broader benchmark precisely because semantic code retrieval involves more than docstring-style function matching. CoIR covers diverse tasks and domains, and the paper explicitly calls out large CodeSearchNet-to-CoIR gaps for models such as OpenAI-Ada-002 and Voyage-Code-002 as evidence of leaderboard overfitting. The safest way to read public numbers, then, is as leaderboard scores under specific benchmark constructions, not as a universal measure of "accuracy."
A sane evaluation stack is layered. Use CodeSearchNet for continuity, because many model cards still publish it. Use CoIR to sanity-check generalization. Then add an internal benchmark with your own workload: symbol lookup, "where is X configured?", error-message search, implementation-pattern search, and cross-file questions. Public benchmarks tell you whether a model is competitive; your own workload tells you whether the architecture is usable. Companion entries: Code Retrieval Benchmarks, Benchmark Overfitting.
Model selection for code: what the public evidence actually supports
Table 1 condenses the best public evidence I could find for the requested model families. Where public code-specific evidence is missing or vendor-reported, the table says so directly instead of smoothing over the gap.
| Model family | Public retrieval evidence | Operational story | Working judgment |
|---|---|---|---|
OpenAI text-embedding-ada-002 |
Unified text/code model; CoIR avg score 45.59 and CodeSearchNet score 74.21 | 1536 dimensions, 8192 context; OpenAI later introduced stronger v3 models and recommends them for new use | Important legacy baseline; acceptable for simple unified text+code retrieval, but not a frontier code-search choice |
| Voyage-Code-002 / 3 | voyage-code-002 scores 56.26 on CoIR and 81.79 on CodeSearchNet; Voyage says code-2 beat competitors by 14.52% recall across 11 code tasks; Voyage says code-3 beats OpenAI-v3-large by 13.8% on 32 code datasets, but the HF card says 238 |
Code-2: 16K context. Code-3: 32K context, 2048/1024/512/256 dims, float/int8/uint8/binary/ubinary outputs, API + AWS SageMaker + on-prem | Strongest closed-model code-retrieval option in the public sources, with a real cost/storage story |
| Nomic Embed Code | Open-weight 7B model card reports better CodeSearchNet scores than Voyage Code 3 and OpenAI Embed 3 Large across several languages; weights, training data, and eval code released | Fully open-source; trained on CoRNStack code/docstring data; self-hostable | Strongest open code-specific story in the sources, especially for local-first or self-hosted stacks |
Mixedbread mxbai-embed-large-v1 |
Strong general retrieval evidence on MTEB (54.39 retrieval vs ada-002 at 49.25), but I did not find an equally strong public code-specific embedding benchmark; Mixedbread's rerank-v2 does publish code-search evaluation |
Open model, prompt-sensitive retrieval, Matryoshka truncation, int8/binary support, easy self-hosting | Strong open general/doc retriever; public evidence is thinner for code-specialized embedding than for Voyage or Nomic |
Ada/Voyage benchmark scores above come from the CoIR leaderboard; OpenAI and Voyage operational claims come from official OpenAI and Voyage materials; Nomic's code scores come from its model card; Mixedbread's numbers come from Mixedbread's model and reranker pages. The absence of a comparable public code-embedding benchmark for Mixedbread is itself a finding.
The cleanest public apples-to-apples comparison in this set is still CoIR. On CoIR's leaderboard, Voyage-Code-002 scores 56.26 on average versus OpenAI-Ada-002 at 45.59. On the CodeSearchNet slice of that same leaderboard, Voyage-Code-002 is at 81.79 versus Ada-002 at 74.21. That is not a marginal gap. It is large enough that "Ada because it is easy" should be understood as a convenience choice, not a merit choice.
OpenAI's case is historically important but strategically weaker today. In 2022, text-embedding-ada-002 replaced separate text-search and code-search models, improved over OpenAI's earlier embedding stack on text search, code search, and sentence similarity tasks, extended context length to 8192, and reduced embedding size to 1536 dimensions. But in 2024 OpenAI introduced text-embedding-3-small and text-embedding-3-large as stronger successors on MIRACL and MTEB, while explicitly recommending the newer models for new use. That leaves ada-002 as a baseline, not a frontier recommendation.
Voyage's case is the opposite: the public story is aggressively code-specific. The voyage-code-2 launch says the model is optimized for semantic retrieval of code and related text from natural-language and code queries, claims a 14.52% recall improvement over competitors on 11 code retrieval tasks, and expands context to 16K. The voyage-code-3 launch adds 32K context, lower-dimensional Matryoshka embeddings, and quantized outputs down to binary. The caveat is that Voyage's own public materials disagree on the size of the headline evaluation suite: the blog says 32 code retrieval datasets, while the Hugging Face card says 238. The directional claim looks credible; the exact aggregate gain should be treated as vendor-reported rather than independently settled.
Nomic's story is the cleanest open-weight code-specific story in the set. The nomic-embed-code model card states that the model outperforms Voyage Code 3 and OpenAI Embed 3 Large on CodeSearchNet, publishes per-language numbers, and explicitly releases model weights, training data, and evaluation code. The model is trained on CoRNStack, which is itself presented as high-quality contrastive data for code retrieval and reranking. The honest caveat is that the strongest public number visible for the 7B model in these sources is on CodeSearchNet, not CoIR. That is still meaningful, but it is not the same thing as a broad code-retrieval generalization claim. For teams that need a smaller open model, Nomic also publishes a 137M CodeRankEmbed model card with 77.9 on CodeSearchNet and 60.1 on CoIR.
Mixedbread is where the public evidence thins out. mxbai-embed-large-v1 is a strong open English retriever, with MTEB average 64.68 and retrieval 54.39, ahead of ada-002 on the same table. The model card also shows query prompting, truncation via Matryoshka-style dimension reduction, and native int8/binary outputs. But those are general retrieval claims, not code-specialized ones. Mixedbread's clearer code-search evidence lives on the reranking side: mxbai-rerank-v2 says it was evaluated on code-search benchmarks, and the company states that BM25 is the first-stage retriever in that setup. Mixedbread belongs in a code-search architecture discussion, but more as a general retriever with strong compression and reranking options than as a proven code-specialized embedder on public code benchmarks.
One engineering detail matters more than many model cards admit: query formatting. Mixedbread says retrieval queries should be prefixed with "Represent this sentence for searching relevant passages:". Nomic's smaller CodeRankEmbed similarly requires a code-search prefix, and Nomic Embed Code's SentenceTransformers example uses prompt_name="query". Forgetting those asymmetries is an easy way to sabotage an otherwise good model. A surprising amount of "model A vs model B" drift comes from "correct query mode vs document mode."
One encoder for code and docs, or separate encoders?
For mixed code-and-documentation search, there are two defensible patterns.
A single shared encoder is simplest when most queries are natural-language descriptions of code, API docs, READMEs, or docstrings. OpenAI's ada-002 was explicitly designed as a unified text-and-code embedding model. Voyage-Code-2 is described as working over "code and related text data" from natural-language and code queries. Nomic Embed Code is trained on docstring-code pairs, which strongly suggests that doc-to-code retrieval is part of its intended operating regime. If your documentation corpus looks like software documentation rather than essays, a single code-aware encoder is attractive.
Separate encoders make more sense when your "documentation" includes long-form design docs, tickets, ADRs, internal wiki pages, and other prose that is stylistically far from code. In that world, a code-specialized model for code plus a strong general retriever for docs is usually the better architecture. Candidate sets can then be merged and reranked in a shared second stage. This is also the cleanest way to make use of Mixedbread today: let a code-specific model own code retrieval, and let a stronger general retriever or reranker own the document side. Sourcegraph's public architecture stresses that context sources extend far beyond code, including wikis and documentation, which is exactly why mixed-corpus retrieval should be treated as an architecture question rather than a single-model identity question.
Companion entries: Multimodal Retrieval for Developer Tools, Code vs Prose Embedding Spaces.
Chunking strategies for source code
Chunking is the most underrated decision in code search. cAST's central claim is blunt: line-based heuristics often break semantic structure, split functions, or merge unrelated code, and that hurts downstream retrieval and generation. Their AST-aware method recursively splits large syntax nodes and merges sibling nodes under a size budget, improving Recall@5 by 4.3 points on RepoEval retrieval and Pass@1 by 2.67 points on SWE-bench generation. This is one of the rare places in code RAG where there is direct controlled evidence that a retrieval plumbing choice materially changes quality.
A useful way to think about chunking is to ask what unit you want the model to retrieve by default. Table 2 summarizes the three dominant choices. The first two rows are mostly production heuristics; the third has the strongest direct research support.
| Strategy | Default unit | Strength | Weakness | Best use |
|---|---|---|---|---|
| Function-level | Function / method body | High precision for API and implementation lookup; benchmark-aligned | Loses file/module/class context | Natural-language-to-code search over well-factored repos |
| File-level | Entire file | Preserves imports, paths, neighboring helpers, config context | Noisier retrieval, larger chunks, weaker precision | Small files, config/schema lookup, module-level questions |
| AST-aware | Syntax-preserving semantic blocks | Keeps syntactic integrity while staying smaller than full files | More parser complexity; requires language-aware tooling | Strong general default for code retrieval and code RAG |
Function-level chunks
Function-level indexing is the default for a reason. CodeSearchNet is function-based, and OpenAI's official code-search example extracts functions and indexes them individually. For API lookup, "what function validates JWTs?", "where do we parse YAML frontmatter?", or "find the retry wrapper," function-level chunks are high-precision and low-noise. They align with the natural answer unit for a large class of developer questions.
The cost is context loss. Functions do not carry file-level intent, module relationships, naming neighborhoods, or class structure unless you deliberately attach that metadata. The benchmark world normalizes this because it mostly retrieves self-contained functions. Production repos do not. That is why function-level search tends to feel impressively precise on "what implements X?" and frustrating on "where is this behavior defined?" or "which module owns this configuration?" even when the embedder is good.
File-level chunks
File-level chunks are best understood as a recall instrument, not a precision instrument. They help with short files, configuration modules, schema files, data pipelines whose meaning spans several helper functions, and cases where the developer's question is really about a module or responsibility rather than a single symbol. They also make path names, imports, class declarations, and neighboring helper routines visible in one hit. The price is obvious: more noise, longer chunks, higher storage costs, and more accidental similarity matches.
In practice, file-level indexing works best when paired with a second representation. A file summary, symbol inventory, or file-level overview node can preserve module context without forcing every query to compare against full files. That is synthesis rather than benchmark fact, but it matches what production systems end up doing when developers want both precision and context.
AST-aware chunks
AST-aware chunking is the best current compromise. cAST's design goals are syntactic integrity, high information density, language invariance, and plug-and-play compatibility. The implementation uses tree-sitter to parse code, greedily merge AST nodes into chunks, and recursively split nodes that exceed size limits. In controlled experiments, the gains over fixed-size chunking are not hypothetical. On RepoEval retrieval, Jina-v2-code reaches Recall@5 of 87.9 with cAST versus 84.9 with fixed-size chunking, and CodeSage-small-v2 reaches 83.9 versus 82.1. The deltas are not universal or huge on every model, but they are consistent enough to treat AST-awareness as a serious default.
The productionization story exists now as well. LlamaIndex's CodeSplitter explicitly says it parses code into an AST and chunks while preserving syntactic structure. Roo Code documents the same general pattern: Tree-sitter identifies semantic blocks like functions, classes, and methods; Markdown gets header-aware handling; unsupported file types fall back to line-based chunking; and large functions are split at logical boundaries. That mix—syntax-aware when possible, graceful fallback when not—is what mature chunking looks like.
My default recommendation for code is therefore: index AST-aware semantic blocks as the main dense retrieval unit, attach file and symbol metadata, and keep a lighter file-level representation for recall and context expansion. For documentation, use heading-aware chunks rather than fixed token windows so that section titles, API headings, and changelog entries remain intact. Companion entry: AST-aware Code Chunking.
Index architecture: HNSW, IVF, and exact search
Index choice is where many teams accidentally pay the wrong bill. The real question is not "which ANN algorithm is best?" It is "which error budget and hardware budget are you actually willing to accept?"
Exact brute-force / Flat
Exact search is underrated. Faiss's guidance is unambiguous: if you will perform only a few thousand searches, index build time is not amortized, and direct computation can be the most efficient option. Exact Flat search is also the only option that guarantees exact results, adds no indexing overhead on top of the vectors, and is a strong fit for small corpora. Weaviate similarly recommends Flat for small indexes under roughly 10,000–20,000 objects and for multi-tenant setups where each tenant has a small isolated corpus.
This matters more for code search than many teams admit. Per-repo or per-tenant indexes are often small enough that exact search is fine, especially during early rollout or on local developer machines. If your average tenant has 8,000 chunks, HNSW may be engineering theater.
HNSW
HNSW became the default because it buys high recall and low latency without the tuning burden of IVF. The original HNSW paper describes a multi-layer proximity graph that achieves logarithmic complexity scaling and strongly outperforms prior vector-only approaches. Faiss summarizes the operational rule of thumb even more bluntly: if you have lots of RAM or the dataset is small, HNSW is very fast and accurate; the speed–accuracy tradeoff is set with efSearch, and the memory cost is roughly (d * 4 + M * 2 * 4) bytes per vector.
The catch is memory. Weaviate's documentation spells out how quickly the bill rises: for HNSW, the node component alone scales with vector dimension, and their example table estimates roughly 2–12 GB for 1 million vectors and 200–1200 GB for 100 million vectors, plus edge overhead of about 200 MB at 1 million vectors and 20 GB at 100 million. That is why quantization and reduced dimensions matter so much in production. HNSW is cheap in latency, not in RAM.
There is also a library-level nuance that matters for incremental indexing. Faiss's HNSW does not support removals; Weaviate's custom HNSW advertises full CRUD support. So "we use HNSW" is not a complete answer. Update semantics depend on the implementation, not just the algorithm name.
If you want concrete latency intuition, Weaviate's public HNSW benchmarks are useful, though not code-specific. On a 1M-object 1536-dimensional "DBPedia OpenAI" dataset, the recommended configuration reports Recall@10 of 97.24%, 5,639 QPS, 2.80 ms mean latency, and 4.43 ms p99. On an 8.8M-object 768-dimensional MSMARCO dataset, the recommended config reports Recall@10 of 97.36%, 7,363 QPS, 2.15 ms mean latency, and 3.69 ms p99. Those are not universal numbers, but they are a good reminder that HNSW can stay comfortably interactive into the multi-million range if memory is available.
IVF and its variants
IVF is the right answer when memory pressure, scale, or filter-heavy queries make graph indexes less attractive. Milvus's explanation is the cleanest concise summary: nlist controls how many clusters the corpus is partitioned into at build time; nprobe controls how many clusters are searched at query time; larger nprobe increases recall and usually increases latency roughly linearly. That makes IVF tunable at runtime in a way HNSW is not.
The variants matter. IVF_FLAT stores raw vectors and can reach 95%+ recall but keeps the raw-vector memory bill. IVF_SQ8 quantizes vectors and typically preserves 90%+ recall with better efficiency. IVF_PQ is the aggressive compression option: Milvus notes that 64:1 compression is often around 70% recall, but recall can exceed 90% if you relax the compression ratio. If you are building a code-search system for enormous monorepos, or one with hard memory ceilings, IVF_PQ is not a theoretical curiosity; it is often the only way the economics close.
IVF also has a filtered-search advantage. In Milvus's comparison table, HNSW is extremely fast for unfiltered search and usually slightly higher recall, but IVF is more memory efficient, faster to build, and more stable under high filtering ratios because candidate generation happens at the cluster level rather than through a graph that can fragment. For code search systems with aggressive metadata filters—language, repo, branch, path prefix, ownership, visibility—this matters.
A short operational summary is more useful than theory alone. Table 3 is partly synthesis, but the support points—Flat for 10k–20k objects, Faiss's "few searches" guidance, dynamic Flat→HNSW, and IVF/HNSW tradeoffs—come from Weaviate, Faiss, and Milvus.
| Index type | Strength | Weakness | Best use |
|---|---|---|---|
| Exact / Flat | Perfect recall, no training, low structural overhead | Query time scales linearly with corpus size | Small shards, local-first indexes, early-stage systems, per-tenant corpora under ~10k–20k objects |
| HNSW | Excellent recall/latency for interactive search; easy default | RAM-heavy; implementation-specific update semantics | Medium to large interactive search where memory is available |
| IVF_FLAT / SQ8 / PQ | Better memory discipline, faster builds, runtime-tunable via nprobe, better filtered stability |
More tuning; can lose recall, especially with aggressive compression | Very large corpora, memory-constrained deployments, filter-heavy workloads |
| Dynamic Flat→HNSW | Good multi-tenant compromise | More platform-specific behavior | Tenants or repos with unpredictable size distributions |
One more quantitative result ties model choice directly to index cost. In CoIR's retrieval-efficiency analysis on a 156k-corpus slice, 768-dimensional models occupy about 0.3 GB and show retrieval latency around 38.1 microseconds; 1536-dimensional OpenAI-Ada-002 and Voyage-Code-002 occupy about 0.9 GB and show 56.8 microseconds; 4096-dimensional E5-Mistral occupies about 2.3 GB and shows 115.5 microseconds. Dimension is not free. If two models are close on quality, the smaller embedding often wins in production even before you touch ANN tuning.
Raw vector storage makes the point even harder. A 2048-dimensional float32 embedding is about 8 KB before index overhead; the same vector at int8 is about 2 KB, and binary is about 256 bytes. Voyage-code-3 explicitly exposes 2048/1024/512/256 dimensions and float/int8/uint8/binary/ubinary outputs, while Mixedbread exposes dimension truncation and native int8/binary encodings. Those are not cosmetic API knobs. They are cost controls. Companion entry: Vector Index Design.
Hybrid search: BM25, dense retrieval, and reranking
Dense retrieval is not sufficient for code search. Code is packed with identifiers, file paths, error messages, config keys, and syntax tokens that should match exactly. Sourcegraph's BM25F writeup makes this concrete: after adapting BM25 to code search and rewarding symbol definitions and file names, their internal evaluations showed roughly 20% improvement across key metrics versus their previous baseline. The same post argues, correctly, that matches in file names and symbol definitions are often much more meaningful than matches buried in comments or statements.
This is why hybrid retrieval is not optional. Weaviate's hybrid search combines vector search with BM25F and fuses the result sets with configurable methods and weights. Qdrant's hybrid search tutorial describes the same architecture in a more advanced form: dense embeddings for semantics, sparse/BM25 representations for keyword coverage, and late-interaction reranking with ColBERT for final precision. Sourcegraph's context engine describes the same high-level decomposition from the product side: retrieval maximizes recall, ranking maximizes precision under token-budget constraints. The field has converged here for good reason.
A code-search lexical index should not just index raw text. It should explicitly index file paths, symbol definitions, and ideally structured code fields. Sourcegraph's BM25F implementation is a good public example because it uses field-aware boosts instead of naive score addition, then applies a second ranking stage on the merged candidate set. That is a better mental model than "vector search plus some backup keyword search." The lexical side is a first-class retriever, not a fallback.
Reranking is where the last 10–20% of developer trust often comes from. Sourcegraph describes a transformer ranking model that merges candidates from multiple retrievers. Qdrant's tutorial uses late interaction via ColBERT. Mixedbread's rerank-v2 was explicitly evaluated on code-search benchmarks, and the company states that BM25 is the first-stage retriever in that setup. This is an important asymmetry in the Mixedbread story: if you want the clearest public code-search claim from Mixedbread today, it is on reranking, not on the base embedding model.
A practical default is therefore: retrieve semantically, retrieve lexically, merge candidates, then rerank. Dense retrieval should recover conceptual similarity. Lexical retrieval should recover identifiers and exact structure. The reranker should decide which candidates are actually worth showing or injecting into a prompt. Companion entries: Hybrid Retrieval for Developer Tools, BM25F for Code Search, Rerankers in Production.
Deployment patterns: local-first, cloud-hosted, and keeping the index honest
The cleanest separation in deployment is not "open source vs proprietary." It is local-first versus cloud-hosted.
Local-first systems optimize for privacy, branch fidelity, and developer trust. Warp's Codebase Context documentation says it indexes Git-tracked code locally and that code is never stored on Warp servers. Continue's @Codebase docs say embeddings are calculated locally by default with transformers.js and stored locally. Roo Code combines local parsing with either cloud or local vector storage, documenting local Docker-based Qdrant as an option. If users are deeply uncomfortable with source egress, this class of design matters more than a two-point benchmark gap.
Cloud-hosted systems optimize for operational simplicity and managed scale. OpenAI is the obvious managed-cloud example. Voyage is unusually flexible for a closed model because it advertises API access, AWS SageMaker private deployment, and on-prem deployment. Roo Code also illustrates the middle ground from the tooling side: cloud embedding providers, local providers like Ollama, cloud Qdrant, or local Qdrant are all viable permutations. The real deployment landscape is not one topology but a matrix: where inference runs, where vectors live, and whether source code ever leaves the machine.
Incremental indexing is non-negotiable. Roo Code's docs describe file watching, reprocessing only modified files, branch-aware handling, and hash-based caching to avoid unnecessary work. Warp documents periodic sync, new-conversation triggers, and separate indexing for Git worktrees so that branch context stays accurate. The important subtlety is that incremental indexing is still eventually consistent, not magically current: Warp explicitly warns that after large changes or a branch switch there can be a short delay where the agent sees stale files. That is a real production concern, not an edge case.
Ignore rules are part of retrieval quality, not just UX. Warp respects .gitignore plus several tool-specific ignore files. Continue respects .gitignore and .continueignore. Roo respects .gitignore and .rooignore, and explicitly warns that common dependency folders should be excluded because filtering depends on it. A code index that ingests vendored code, build outputs, or generated artifacts is not "more complete." It is often simply noisier and more expensive.
The local-first versus cloud-hosted decision therefore comes down to four real questions: where code may legally live, how much ops burden the team can absorb, how heavy the embedding model can be, and how much branch-local freshness developers expect. The benchmark does not answer those questions. The deployment model does. Companion entries: Local-First AI Tooling, Incremental Indexing, Repository Branch Awareness.
A reference architecture that holds up in practice
For a serious code-and-doc search system, I would deploy four retrieval representations, not one.
First, AST-aware code blocks as the primary dense-retrieval unit. Second, heading-aware documentation chunks. Third, a lexical/BM25F index over code text, file paths, symbols, and document headings. Fourth, a lighter file-level or module-level representation for recall and context expansion. The dense layer finds conceptual neighbors; the lexical layer catches exact tokens; the file-level layer repairs context loss from small chunks. The reranker decides what is actually shown or passed downstream. This architecture is directly aligned with Sourcegraph's two-stage retrieval/ranking framing, with Weaviate's dense+sparse fusion, and with Qdrant's dense+sparse+late-interaction template.
For the embedding layer itself, three archetypes are defensible.
The first is a closed, cloud-centric stack: Voyage Code for code, optionally the same model for software docs, HNSW for interactive shards, BM25F for lexical retrieval, and a reranker on the merged candidate set. This is the simplest path to strong managed code retrieval if vendor dependency is acceptable.
The second is an open, local-first stack: Nomic Embed Code for code, a local vector store like Qdrant, AST-aware chunking via tree-sitter, Flat or small HNSW per repo, and strict .gitignore-aware incremental updates. If documentation is more prose-heavy than code-adjacent, a separate general text model can own that corpus.
The third is a split-encoder stack for mixed corpora: a code-specific model for code plus a strong general retriever for docs. This is the scenario where Mixedbread makes the most sense in the requested set, especially if you value open weights, compression support, and code-aware reranking. The central point is that "one embedding model for everything" is often less elegant in practice than in blog-post diagrams.
What I would actually choose
If the question is "best closed model for code search right now from the requested set," the answer is Voyage, with the important caveat that the most impressive voyage-code-3 headline numbers are still vendor-reported and slightly inconsistent across public materials. The combination of public CoIR strength for voyage-code-002, explicit code specialization, long context, dimension control, and quantized outputs is the strongest closed-model package in the sources I found.
If the question is "best open/self-hosted story," the answer is Nomic. Not because the 7B model has the broadest public benchmark sheet—it does not in the sources above—but because the package is unusually complete: open weights, open training data, open evaluation code, and strong published CodeSearchNet numbers against strong baselines. For teams that want local-first deployment without giving up code-specific training, that matters more than elegance.
If the question is "can I just use OpenAI ada-002 because it is easy?", the honest answer is yes, but only if you treat it as a convenience baseline. It unified text and code search cleanly, and it still works. It is just no longer where the best public code retrieval evidence points, and OpenAI's own messaging around the v3 models makes that clear.
If the question is "where does Mixedbread fit?", the honest answer is that it fits better than many people realize, but differently than the hype suggests. It is a strong open retriever for documents and general corpora, it has real storage/compression knobs, and Mixedbread's rerankers have clearer public code-search support than its base embedding model. What I would not do is pretend that I found a public code-embedding benchmark story for Mixedbread that is as strong as Voyage's or Nomic's. I did not.
Failure modes worth naming explicitly
The first failure mode is evaluating on CodeSearchNet alone and shipping the result into a monorepo. CoIR exists because that mistake is common.
The second is using fixed token windows for code because that is what worked for prose. The cAST results are strong enough that syntax-aware chunking should now be the default assumption, not the fancy option.
The third is dropping lexical retrieval because the embedding model "understands code semantics." It does not understand exact identifiers, paths, stack traces, or config keys as reliably as BM25F does. Sourcegraph's public numbers are strong enough that this is no longer speculative.
The fourth is treating indexing freshness as an ops detail. A stale branch-local index is a silent quality failure, and Warp's own docs acknowledge this directly.
The through-line is simple: pick a model with real evidence on code retrieval, preserve syntax in chunking, pay the right index bill, keep lexical retrieval in the loop, and make freshness a first-class requirement. Teams that do those five things usually get better search before they ever touch fine-tuning or agent tricks.
Related entries
Code Retrieval Benchmarks AST-aware Code Chunking Hybrid Retrieval for Developer Tools BM25F for Code Search Vector Index Design Rerankers in Production Tree-sitter for AI Systems Local-First AI Tooling Incremental Indexing Repository Branch Awareness Metadata Filtering in Vector Search
If you want, I can also turn this into a tighter house style with a front-matter summary, infobox, and "Key takeaways / Decision matrix / Further reading" blocks for direct wiki ingestion.