Skip to main content
V3Code builds a searchable index of your codebase on your own hardware. It’s what lets the agent find relevant code by meaning, not just exact text, and it’s a big reason the agent seems to understand a project the moment you start typing.

Reading comes first

A quick philosophy note, because it shapes everything below: V3Code leans on the agent reading real code, Claude-Code style, and uses the index for fast recall when it’s needed — not as a replacement for reading. We’ve found models are more accurate when they read more and reach for the index to jump straight to the right place. They hit harder and miss less. The index makes that fast; it doesn’t do the thinking.

Local by default

The index lives on your machine in a local IndexedDB store (database v3code-index), with embeddings kept as compact int8-quantized vectors (~4× smaller than float32, scored directly with a per-vector scale). Your code is never uploaded to build or query it. See Privacy.

Embeddings: a fast code model by default

The embedding model is chosen by v3code.semanticIndex.embedModel (default auto):
ModelDimEngineNotes
potion-code-16M (default)256Model2Vec static (no forward pass)Tuned for code; hundreds of times faster than a transformer on CPU — this is why local indexing is fast.
Qwen3-Embedding-0.6B (quality)1024llama.cpp (GPU)Higher quality; only auto-selected if already downloaded, so auto never triggers a surprise download.
all-MiniLM-L6-v2384ONNX transformerGeneral-purpose fallback (~30 MB).
jina-embeddings-v2-base-code768ONNX transformerCode transformer fallback.
During a model upgrade (e.g. backfilling to Qwen3), queries are embedded in both the old and new spaces and fused, so search stays live mid-migration.

Why a small model is enough: structural enrichment

A lightweight embedder would normally cost recall. V3Code buys it back with structure. Chunks are cut structurally with tree-sitter (parent/child code blocks, not blind line windows), and the code graph is upgraded with real LSP-derived edges (v3code.semanticIndex.lspGraphEdges, on by default, tightly budgeted). That structural signal — surrounding symbol, file, and relationships — sharpens recall and ranking, so the small, fast model punches above its size.

How ranking works

Retrieval is a hybrid, RRF-fused search, not a single vector lookup:
  • Lexical channel — IDF token overlap (weight 0.4).
  • Dense vector channel — int8 cosine over the embeddings (weight 0.6).
  • Previous-model channel — dual-space scoring during a model swap (0.5).
  • Recency — a multiplicative boost (up to ~1.25× for the most-recently-touched code).
  • Graph neighbors — one-hop expansion over the code graph after ranking.
Channels are merged with Reciprocal Rank Fusion at k = 30 (deliberately steeper than the classic 60), with adaptive widening when too few strong results come back. Child chunks collapse into their parent (top-3, decayed). An optional local Qwen3-Reranker-0.6B cross-encoder can reorder the top candidates. semantic_search returns up to topK results (default 30).

Staying current

  • Builds on startup (autoRebuildOnStartup, on by default) and follows edits.
  • Incremental via a content-hash (Merkle-style) manifest — only changed files are re-chunked and re-embedded — plus a content-addressed store so switching branches back to a known state is instant.
  • Security denylist — secrets-shaped files (.env*, .ssh/, .aws/, …) are never indexed, regardless of your include settings.
V3Code doesn’t lean on a single index. It runs a layered retrieval system, and all of it answers through one semantic_search call — you never think about which engine served a result. The fusion is adaptive: it leans on lexical signal when vectors are sparse and on vectors when they’re strong.

The local semantic index

The engine described above — meaning-based recall, in your editor, on your hardware. It starts instantly on the fast potion-code-16M model and quietly upgrades to Qwen3 quality in the background once the first pass finishes, so search is useful immediately and gets sharper as it warms up.

The native symbol sidecar

Vectors are great at “what does this mean” and bad at “where is this exactly.” So V3Code ships a second engine — a purpose-built Rust sidecar for precision:
  • Trigram-indexed (Tantivy) for instant substring and identifier search, with a recall → regex-confirm pass so matches are exact, not fuzzy.
  • Symbol-aware — tree-sitter parses every file into a symbol index of definitions and references across many languages.
  • Cross-file resolved — stack-graphs follow real go-to-definition and find-references edges, not text look-alikes, so “what uses this?” is answered by the actual call graph.
  • Hot-swappable — it runs as its own process (the ripgrep model): it can start, be killed, or restart mid-flight without ever breaking search. If it’s not there, the system degrades gracefully.
The payoff is symbol lookups and change-impact traces in single-digit milliseconds, riding alongside the semantic index’s meaning-based recall. It’s also what powers graph-anchored memory.

The cloud index (opt-in, paid)

An optional hosted index — never required. It exists so people on low-end hardware, or who want indexing to run against their own BYOK models, can offload the work. It’s a per-workspace service with its own lexical, vector, and symbol-graph search. Local-hardware users never need it; and if your local index ever hits trouble, V3Code falls back to the cloud index free so search keeps working. In short: local for your own hardware, cloud for low-end machines or BYOK-model indexing — your choice.
The indexing stack is actively evolving (deeper sidecar fusion and a cloud-model path are in progress). This page describes current default behavior.