Skip to content

Code Indexing

The indexer turns your workspace into a searchable database. Both Ask + Agent modes then retrieve relevant code as context automatically, and you can call search_vector_db explicitly.

Related: Semantic search covers the query side.

CodeBuddy: Index Workspace for Semantic Search

Scans → chunks → embeds → persists. Progress notification shows file + chunk counts and whether embeddings succeeded.

graph TB A[Workspace files] --> B[File discovery<br/>vscode.workspace.findFiles + .codebuddyignore + size limits] B --> C[Change detection<br/>SHA-256 vs file_metadata → skip unchanged] C --> D[Chunking worker<br/>1000-char + 200 overlap → discard < 50 chars] D --> E[Embedding<br/>Batched, rate-limited, retried<br/>Text-only fallback if API down] E --> F[SQLite<br/>chunks + FTS4 virtual table via triggers<br/>file_metadata for hash tracking] F --> G[Disk flush<br/>5s debounce → .codebuddy/vector_store.db]

Supported extensions: .ts, .tsx, .js, .jsx, .py, .java, .go, .rs, .cpp, .c, .h, .cs, .rb, .php.

Exclusions, layered:

LayerExcludes
Basenode_modules, .git, dist, out, build, coverage, .codebuddy
.codebuddyignoreCustom patterns (.gitignore syntax — **, negation !, trailing / for dirs)
Sync excludes*.min.js, *.bundle.js, *.d.ts, .DS_Store, .vscode-test
File sizeVaries by performance mode

Run CodeBuddy: Init .codebuddyignore for a starter ignore file. Live-reloads when edited.

.codebuddyignore syntax:

tests/fixtures/** # ignore
src/generated/
*.csv
!tests/fixtures/sample.ts # negation — re-include
tmp/ # trailing / = dir only
/scripts/legacy/ # leading / = anchored to root
# comment lines start with #

File size limits by performance mode:

ModeMax size
balanced (default)1 MB
performance2 MB
memory512 KB

Runs in a worker thread — never blocks the UI.

ParameterValue
Chunk size1000 chars
Overlap200 chars
Min chunk50 chars (smaller discarded)

Each chunk records id = filePath::charOffset, text, line range, chunk type (text_chunk / function / class / method / block), and language.

Tree-sitter AST chunking ships for 8 grammars — TypeScript, JavaScript, Python, Java, Go, Rust, PHP, C/C++. Split at function/method boundaries, group class bodies, keep imports together, attach docstrings/JSDoc to their function. Languages without a grammar fall back to text-based splitting (char offset + overlap).

Providers:

ProviderModelNotes
Gemini (default)text-embedding-004When codebuddy.vectorDb.embeddingModel = "gemini"
OpenAItext-embedding-3-smallOpenAI-compatible endpoint
LocalConfigurableUses local server’s /embeddings (e.g., nomic-embed-text)
DeepSeek / GroqOpenAI-compatibleSame SDK, different base URL

Anthropic doesn’t support embeddings — auto-falls back to Gemini.

Batching + rate limits:

ParamDefault
Batch size5 chunks
Rate limit1500 req/min (40 ms min interval)
Retries3, exponential backoff (delay × attempt)
Base delay1000 ms

Between batches, setImmediate() yields to the event loop — editor stays responsive.

Smart phases — the embedding pipeline uses different configs per context:

PhaseBatchMax filesDelayTimeoutRetries
Immediate (save)520100 ms30 s3
On-demand (query)315200 ms20 s2
Background (idle)101001000 ms60 s1
Bulk (full index)20Unlimited500 ms120 s2

Pre-flight check — before bulk indexing, a test embedding verifies the API is reachable. Failure → indexing continues in text-only mode: chunks stored without vectors, keyword search still works, semantic search doesn’t. Re-run after fixing to generate embeddings.

Content-hash-driven. Cheap on unchanged files.

  1. onDidSaveTextDocument fires.
  2. SHA-256 hash compared to file_metadata row.
  3. Unchanged → skip (no work).
  4. Changed → remove old chunks for this file → re-chunk → re-embed → persist.

Triggers:

TriggerScopeBehavior
File saveSingle fileImmediate incremental
Index WorkspaceWhole repoBulk; skips unchanged
Background processingChanged filesDebounced (default 1000 ms)

Auto-filtered: git commit messages, log files, paths containing node_modules, .git, .codebuddy.

Location: <workspace>/.codebuddy/vector_store.db. Falls back to editor global storage if workspace is unwritable.

Backing: sql.js (WASM). See WASM.

Schema:

CREATE TABLE chunks (
id TEXT PRIMARY KEY,
text TEXT NOT NULL,
vector BLOB, -- Float32Array (NULL in text-only mode)
file_path TEXT NOT NULL,
start_line INTEGER NOT NULL,
end_line INTEGER NOT NULL,
chunk_type TEXT NOT NULL DEFAULT 'text_chunk',
language TEXT NOT NULL DEFAULT '',
indexed_at TEXT NOT NULL
);
CREATE TABLE file_metadata (
file_path TEXT PRIMARY KEY,
file_hash TEXT NOT NULL, -- SHA-256
chunk_count INTEGER NOT NULL DEFAULT 0,
indexed_at TEXT NOT NULL
);

FTS4 virtual table synced via SQL triggers on the chunks table (INSERT / DELETE / UPDATE). On startup, if FTS row count falls behind chunks (post-crash), a back-fill runs — anti-join INSERT for < 100 rows, rebuild for larger gaps.

Persistence: dirty-flag + 5-second debounce save. Changes accumulate in memory, flush to disk periodically. Deactivation triggers immediate final flush.

  1. SqliteVectorStore singleton — loads/creates the DB.
  2. HybridSearchService — inits FTS4 virtual table.
  3. AstIndexingService — spawns worker, wires embedding service.
  4. ContextRetriever — wires search pipeline.
  5. onDidSaveTextDocument — enables incremental indexing.
  6. codebuddy.indexWorkspace command registered.

Full list in Settings Reference under Vector database + Hybrid search. Key ones:

SettingDefaultEffect
codebuddy.vectorDb.enabledtrueMaster toggle
codebuddy.vectorDb.performanceMode"balanced"Size limits + resource caps
codebuddy.vectorDb.enableBackgroundProcessingtrueIndex changes in the background
codebuddy.vectorDb.debounceDelay1000ms wait before re-indexing a changed file
codebuddy.vectorDb.batchSize10Files per embedding batch
codebuddy.indexCodebasefalseAuto-index on startup