---
title: Under the Hood
description: Technical deep dive into ChunkHound's architecture, algorithms, and design decisions
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import { Card, CardGrid, Aside } from '@astrojs/starlight/components';
import SemanticSearchFlow from '../../components/SemanticSearchFlow.tsx';
import MultiHopSearchFlow from '../../components/MultiHopSearchFlow.tsx';

## Architecture Overview

ChunkHound uses a local-first architecture with embedded databases and universal code parsing. The system is built around the [cAST (Chunking via Abstract Syntax Trees)](https://arxiv.org/pdf/2506.15655) algorithm for intelligent code segmentation:

<CardGrid>
  <Card title="Database Layer" icon="setting">
    **[DuckDB](https://duckdb.org/)** (primary) - OLAP columnar database with HNSW vector indexing
    **[LanceDB](https://lancedb.github.io/lancedb/)** (experimental) - Purpose-built vector database with [Apache Arrow](https://arrow.apache.org/) format
  </Card>

  <Card title="Parsing Engine" icon="open-book">
    **[Tree-sitter](https://tree-sitter.github.io/tree-sitter/)** - Universal AST parser supporting 20+ languages
    **Language-agnostic** - Same semantic concepts across all languages
  </Card>

  <Card title="Flexible Providers" icon="puzzle">
    **Pluggable backends** - [OpenAI](https://platform.openai.com/docs/guides/embeddings), [VoyageAI](https://docs.voyageai.com/), [Ollama](https://ollama.ai/)
    **Cloud & Local** - Run with APIs or fully offline with local models
  </Card>

  <Card title="Advanced Algorithms" icon="rocket">
    **[cAST](https://arxiv.org/pdf/2506.15655)** - Semantic code chunking preserving AST structure
    **Multi-Hop Search** - Context-aware search with reranking
  </Card>
</CardGrid>

ChunkHound's local-first architecture provides key advantages: **Privacy** - Your code never leaves your machine. **Speed** - No network latency or API rate limits. **Reliability** - Works offline and in air-gapped environments. **Cost** - No per-token charges for indexing large codebases.

## The cAST Algorithm

When AI assistants search your codebase, they need code split into "chunks" - searchable pieces small enough to understand but large enough to be meaningful. The challenge: how do you split code without breaking its logic?

**Research Foundation**: ChunkHound implements the [cAST (Chunking via Abstract Syntax Trees)](https://arxiv.org/pdf/2506.15655) algorithm developed by researchers at Carnegie Mellon University and Augment Code. This approach demonstrates significant improvements in code retrieval and generation tasks.

### Three Approaches Compared

**1. Naive Fixed-Size Chunking**

Split every 1000 characters regardless of code structure:

```python
def authenticate_user(username, password):
    if not username or not password:
        return False

    hashed = hash_password(password)
    user = database.get_u
# CHUNK BOUNDARY CUTS HERE ❌
ser(username)
    return user and user.password_hash == hashed
```

**Problem**: Functions get cut in half, breaking meaning.

**2. Naive AST Chunking**

Split only at function/class boundaries:

```python
# Chunk 1: Tiny function (50 characters)
def get_name(self):
    return self.name

# Chunk 2: Massive function (5000 characters)
def process_entire_request(self, request):
    # ... 200 lines of complex logic ...
```

**Problem**: Creates chunks that are too big or too small.

**3. Smart cAST Algorithm (ChunkHound's Solution)**

Respects code boundaries AND enforces size limits:

```python
# Right-sized chunks that preserve meaning
def authenticate_user(username, password):    # ✅ Complete function
    if not username or not password:          #    fits in one chunk
        return False
    hashed = hash_password(password)
    user = database.get_user(username)
    return user and user.password_hash == hashed

def hash_password(password):                  # ✅ Small adjacent functions
def validate_email(email):                   #    merged together
def sanitize_input(data):
    # All fit together in one chunk
```

### How cAST Works

The algorithm is surprisingly simple:

1. **Parse** code into a syntax tree (AST) using [Tree-sitter](https://tree-sitter.github.io/tree-sitter/)
2. **Walk** the tree top-down (classes → functions → statements)
3. **For each piece**:
   - If it fits in size limit (1200 chars) → make it a chunk
   - If too big → split at smart boundaries (`;`, `}`, line breaks)
   - If too small → merge with neighboring pieces
4. **Result**: Every chunk is meaningful code that fits in context window

**Performance**: The [research paper](https://arxiv.org/pdf/2506.15655) shows cAST provides 4.3 point gain in Recall@5 on RepoEval retrieval and 2.67 point gain in Pass@1 on SWE-bench generation tasks.

<Aside type="tip">
**Think of code like paragraphs in an essay**. You wouldn't split a paragraph mid-sentence - cAST doesn't split code mid-statement. It keeps related logic together while respecting size limits.
</Aside>

### Why This Matters for AI

- **Better Search**: Find complete functions, not fragments
- **Better Context**: AI sees full logic flow, not half-statements
- **Better Results**: AI gives accurate suggestions based on complete code understanding
- **Research-Backed**: [Peer-reviewed algorithm](https://arxiv.org/pdf/2506.15655) with proven performance gains

Traditional chunking gives AI puzzle pieces. cAST gives it complete pictures.

**Learn More**: Read the full [cAST research paper](https://arxiv.org/pdf/2506.15655) for implementation details and benchmarks.

## Semantic Search Architecture

ChunkHound provides two search modes depending on your embedding provider's capabilities. The system uses vector embeddings from providers like [OpenAI](https://platform.openai.com/docs/guides/embeddings), [VoyageAI](https://docs.voyageai.com/docs/embeddings), or [local models via Ollama](https://ollama.ai/).

### Regular Semantic Search

The standard approach used by most embedding providers:

<SemanticSearchFlow client:load />

**How it works**:
1. Convert query to embedding vector
2. Search the vector index for nearest neighbors
3. Return top-k most similar code chunks

### Multi-Hop Semantic Search

Traditional semantic search finds code that directly matches your query, but real codebases are interconnected webs of relationships. When you search for "authentication," you don't just want the login function—you want the password hashing, token validation, session management, and security logging that work together to make authentication complete.

Multi-hop search addresses this by following semantic relationships. It starts with direct matches, then identifies similar code to expand the result set. Through iterative expansion rounds, it discovers related functionality across architectural boundaries.

<MultiHopSearchFlow client:load />

The process resembles following references in technical documentation. Starting with "authentication," you might discover "cryptographic hash," then "salt generation," then "timing attack prevention." Each step reveals related concepts that share semantic similarity with your original query.

The algorithm maintains focus throughout exploration by continuously reranking all discovered code against the original query. This prevents semantic drift, ensuring that expansion doesn't compromise relevance.

Consider how ChunkHound discovers these semantic chains in its own codebase: a search for "HNSW optimization" finds the initial embedding repository code, expands to discover the DuckDB provider optimizations, then the search service coordination, and finally the indexing orchestration—a complete end-to-end picture of how vector indexing works across architectural layers.

### How Multi-Hop Search Works

Multi-hop search begins by retrieving more initial candidates than standard semantic search. Instead of returning just the requested number of results, it retrieves three times that amount (up to 100 total) of the top-ranked matches. This provides the reranking algorithm with more high-quality candidates to evaluate. These expanded initial results undergo immediate reranking against the original query, establishing a relevance baseline for subsequent expansion rounds.

The expansion phase takes the highest-scoring chunks as seeds to discover semantic neighbors—code that shares similar patterns, concepts, or functionality. This creates the "hops": from query to initial matches, then from those matches to their related code, forming chains of semantic relationships across the codebase.

After each expansion round, the algorithm maintains focus by reranking all discovered code against the original query. This continuous relevance assessment prevents semantic drift, ensuring that multi-hop exploration doesn't compromise result quality.

The process continues iteratively until convergence detection triggers termination. Multi-hop search monitors its progress through rate-of-change analysis, ending exploration when score improvements diminish below the threshold, when computational limits are reached, or when insufficient expansion candidates remain.

### Convergence Detection

Multi-hop search implements several termination criteria to balance comprehensive discovery with computational efficiency. Left unchecked, semantic expansion could theoretically connect any piece of code to any other piece through enough intermediate hops—most codebases are more interconnected than they appear. The algorithm uses gradient-based convergence detection to recognize when exploration should cease.

The system monitors three key signals for termination. First, it employs **rate-of-change monitoring** similar to early stopping in machine learning: when reranking scores degrade by more than 0.15 between iterations, indicating diminishing relevance returns. This derivative-based stopping criterion is common in optimization algorithms, effectively measuring the "convergence velocity" of score improvements. Second, it respects computational boundaries—both execution time (5 seconds maximum) and result volume (500 candidates maximum). Third, it detects resource exhaustion when fewer than 5 high-scoring candidates remain for productive expansion.

This convergence detection creates a practical balance. The algorithm explores broadly enough to discover cross-domain relationships while terminating before semantic drift compromises result quality.

<Aside type="tip" title="When Multi-Hop Activates">
Multi-hop search automatically activates when you use providers with reranking support:
- **[VoyageAI](https://docs.voyageai.com/docs/reranking)**: Built-in `rerank-lite-1` model
- **Custom servers**: With reranking endpoints following [OpenAI format](https://platform.openai.com/docs/api-reference)
- **[OpenAI](https://platform.openai.com/docs/guides/embeddings)**: Falls back to regular search (no reranking)

See [Configuration](/chunkhound/configuration/) for provider setup details.
</Aside>

## Real-Time Monitoring & Smart Diffs

ChunkHound's MCP servers include automatic file watching and update mechanisms that keep your index current without manual intervention. When files change, ChunkHound uses intelligent diffing to minimize reprocessing:

**Direct String Comparison**: Each chunk's content is compared as a string. If the content hasn't changed, the existing embedding is preserved.

**Set Operations**: The algorithm categorizes chunks into:
- **Unchanged** - Content identical, keep existing embeddings
- **Added** - New chunks that need embedding generation
- **Deleted** - Removed chunks to clean up from database
- **Modified** - Changed chunks that need re-embedding

**Efficiency Benefits**: Only chunks with actual content changes get re-processed. A file with 100 chunks where only 2 functions changed will preserve 98 existing embeddings and generate only 2 new ones.

This approach enables efficient branch switching - when you `git checkout`, only files that actually differ between branches get re-indexed.

## Learn More

### Research & Documentation
- **[cAST Paper](https://arxiv.org/pdf/2506.15655)** - Original research on structure-aware code chunking
- **[MCP Specification](https://spec.modelcontextprotocol.io/)** - Protocol for AI assistant integration
- **[Tree-sitter Documentation](https://tree-sitter.github.io/tree-sitter/)** - Universal code parsing

### Database Technologies
- **[DuckDB Documentation](https://duckdb.org/docs/)** - High-performance analytical database
- **[LanceDB Documentation](https://lancedb.github.io/lancedb/)** - Vector database for AI applications
- **[Apache Arrow](https://arrow.apache.org/)** - Columnar data format and interoperability

### Embedding Providers
- **[OpenAI Embeddings Guide](https://platform.openai.com/docs/guides/embeddings)** - Industry-standard embedding API
- **[VoyageAI Documentation](https://docs.voyageai.com/)** - Code-optimized embeddings and reranking
- **[Ollama](https://ollama.ai/)** - Local model deployment and management
