Configuration

ChunkHound is configured through a JSON file, environment variables, and CLI flags.

Configuration File

Create .chunkhound.json in your project root. Here is a full example showing all sections:

Global Defaults (cross-project configuration)

To avoid copying the same settings into every project, place a global config in one of these locations (checked in order):

  • ~/.config/chunkhound/chunkhound.json
  • ~/.config/chunkhound/.chunkhound.json
  • ~/.chunkhound/chunkhound.json
  • ~/.chunkhound/.chunkhound.json
  • ~/chunkhound.json
  • ~/.chunkhound.json

You can also point to an arbitrary file with the CHUNKHOUND_GLOBAL_CONFIG_FILE environment variable.

Example global config (~/.config/chunkhound/chunkhound.json):

{
  "embedding": {
    "provider": "voyageai",
    "model": "voyage-3.5"
  },
  "llm": {
    "provider": "anthropic"
  },
  "indexing": {
    "exclude": ["**/node_modules/**", "**/.git/**", "**/dist/**"]
  }
}

Then in a specific project you only need a minimal .chunkhound.json for project-specific overrides (or nothing at all if the globals are sufficient):

{
  "embedding": {
    "api_key": "sk-..."   // only the key differs per machine
  }
}

Global values are deep-merged; project files win for any keys they specify.

Merging behavior:

  • Nested objects (embedding, llm, research, database, etc.): deep merge. You only need to specify the keys you want to change in a higher-priority file (local, explicit config, or CLI). Siblings from global (or lower layers) are preserved. This lets a project override just an api_key, switch llm.model, or change research.algorithm without losing other global settings.

  • Lists (indexing.exclude, indexing.include): the list supplied by the higher-priority source completely replaces any list from a lower layer (including global). ChunkHound’s built-in safe defaults are still layered on top of your list in the effective excludes (see get_effective_config_excludes()), and .gitignore interaction is controlled by exclude_mode.

Example — project overrides only the secret while inheriting provider + model from global (or switches providers entirely):

{
  "embedding": {
    "api_key": "sk-..."
  }
}

or to use a completely different provider for this project:

{
  "embedding": {
    "provider": "openai",
    "model": "text-embedding-3-large",
    "api_key": "sk-..."
  }
}

Example — project uses its own exclude list (replaces global’s list at the raw config level):

{
  "indexing": {
    "exclude": ["**/my-vendor/**", "**/generated/**"]
  }
}
{
  "database": {
    "provider": "duckdb",
    "path": ".chunkhound/db"
  },
  "embedding": {
    "provider": "voyageai",
    "model": "voyage-3.5",
    "batch_size": 100
  },
  "indexing": {
    "exclude": ["**/node_modules/**", "**/dist/**"],
    "exclude_mode": "combined",
    "per_file_timeout_seconds": 3.0,
    "batch_size": 50,
    "db_batch_size": 100,
    "detect_embedded_sql": true
  },
  "llm": {
    "provider": "anthropic",
    "utility_model": "claude-haiku-4-5-20251001",
    "synthesis_model": "claude-sonnet-4-5-20250929"
  }
}

Configuration Precedence

Settings are resolved in this order (highest priority first):

  1. CLI arguments — flags passed directly on the command line
  2. Config file — loaded via --config or CHUNKHOUND_CONFIG_FILE
  3. Local .chunkhound.json — auto-detected in the target directory
  4. Global defaultsCHUNKHOUND_GLOBAL_CONFIG_FILE or auto-discovered in ~/.config/chunkhound/ (or ~/.chunkhound/)
  5. Environment variablesCHUNKHOUND_* prefixed variables
  6. Defaults — built-in fallback values

Global defaults let you maintain shared settings (e.g. embedding provider + API key, common exclude patterns, LLM roles) in a single file so you do not need to copy .chunkhound.json into every project. Any project-local .chunkhound.json (or explicit config/CLI) overrides values from the global layer. Nested objects (embedding, llm, research, database, …) are deep-merged: specify only the keys you want to change and siblings from global survive. Lists such as indexing.exclude / include from a higher layer fully replace lower ones (built-in defaults are still applied on top; see Global Defaults above for details and examples).

Embedding Providers

ProviderConfig ValueEnv VarDefault ModelNotes
VoyageAIvoyageaiCHUNKHOUND_EMBEDDING__API_KEYvoyage-3.5Recommended for code search
OpenAIopenaiCHUNKHOUND_EMBEDDING__API_KEYtext-embedding-3-smallWidely available

Embedding Options

OptionTypeDefaultDescription
base_urlstringnullCustom embedding endpoint. Required for self-hosted OpenAI-compatible embeddings.
ssl_verifybooleantrueVerify TLS certificates for requests sent to base_url. Ignored when base_url is unset.
rerank_modelstringnullReranking model name (enables multi-hop reranking)
rerank_urlstringnullSeparate rerank endpoint URL (optional when reranking is served from base_url)
rerank_ssl_verifybooleannullVerify TLS certificates for rerank requests. Inherits ssl_verify when unset.
rerank_formatstring"auto"Reranking API format: cohere, tei, or auto
rerank_batch_sizenumbernullMax documents per rerank request
timeoutnumber30Request timeout in seconds
max_retriesnumber3Max retry attempts on failure
api_versionstringnullAzure OpenAI API version (YYYY-MM-DD)
azure_endpointstringnullAzure OpenAI endpoint (mutually exclusive with base_url)
azure_deploymentstringnullAzure OpenAI deployment name

Database Backends

BackendStatusRecommended
duckdbStableYes — use this
lancedbExperimentalNo — for evaluation only

DuckDB (default)

Stable — recommended for all use cases.

Fast analytical queries and efficient storage.

{
  "database": {
    "provider": "duckdb",
    "path": ".chunkhound/db"
  }
}

LanceDB

Experimental — not recommended for production use. The LanceDB integration is actively developed but may have rough edges around index rebuilding, migration, and edge-case query correctness. Use DuckDB unless you are evaluating LanceDB specifically.

{
  "database": {
    "provider": "lancedb",
    "path": ".chunkhound/db"
  }
}

Database Options

OptionTypeDefaultDescription
max_disk_usage_mbnumbernullMax DB size in MB before indexing stops (CLI flag uses GB)
fragmentation_threshold_pctnumber30Background/auto-compaction trigger: file-size overhead above the provider’s estimated live DB size (%). 30 = compact when the DB is ~30% larger than live data. 0 = always, null = never. This does not disable the fixed chunkhound index compaction boundaries. CLI: --fragmentation-threshold-pct.
execute_timeout_secondsnumbernullTimeout for synchronous serial DB executor waits (execute_sync / _execute_in_db_thread_sync) in seconds. null = built-in defaults (30s normal ops, 660s compaction). When set, replaces both defaults for every sync operation including compaction, HNSW rebuild, and queries. Does not apply to async dispatch (execute_async), which remains unbounded. CLI: --db-execute-timeout. Env: CHUNKHOUND_DATABASE__EXECUTE_TIMEOUT_SECONDS (or legacy CHUNKHOUND_DB_EXECUTE_TIMEOUT).
lancedb_index_typestringnullLanceDB vector index type: auto, ivf_hnsw_sq, or ivf_rq
lancedb_optimize_fragment_thresholdnumber100Fragment count to trigger LanceDB compaction

DuckDB also compacts during chunkhound index at two fixed batch boundaries: once after chunking and before embedding generation, then again at the end of the indexing pass. Those boundary calls are unconditional, including --no-embeddings and noop re-index runs. If a batch compaction fails with status: "error", the index run is aborted. Providers that report compaction as unsupported/skipped keep indexing normally. Sampled/background auto-compaction (triggered by fragmentation threshold during normal operations) does NOT fail the original operation — failures are logged and skipped.

DuckDB compaction rebuilds a fresh canonical ChunkHound database file and swaps it into place atomically. This is intentionally not a generic DuckDB passthrough: only ChunkHound-owned canonical tables (schema_version, files, chunks, embeddings_*) are preserved. Any unknown or non-canonical tables are dropped during compaction by design.

Indexing Options

OptionTypeDefaultDescription
excludestring[]built-in listGlob patterns to exclude from indexing
includestring[]all supported file typesGlob patterns limiting which files are indexed; files not matching any pattern are skipped
exclude_modestringnullcombined, config_only, or gitignore_only. When an explicit exclude list is provided, defaults to "combined"; otherwise defaults to "gitignore_only"
force_reindexbooleanfalseForce re-indexing of all files
max_concurrentnumber5Max concurrent parser workers
cleanupbooleantrueRemove orphaned DB records after indexing
max_file_size_mbnumber10Skip files larger than this (MB)
config_file_size_threshold_kbnumber20Skip structured config files (JSON/YAML/TOML) larger than this (KB); 0 to disable
per_file_timeout_secondsnumber3.0Max parse time per file (0 to disable)
batch_sizenumber50Files per parsing batch
db_batch_sizenumber100Chunks per database write batch
detect_embedded_sqlbooleantrueIndex SQL in string literals
per_file_timeout_min_size_kbnumber128Only apply per-file timeout to files at least this large (KB)

By default, ChunkHound excludes common noise directories (node_modules, dist, __pycache__, .git, lock files, build artifacts). Set exclude_mode: "config_only" and exclude: [] to start with a clean slate.

Exclude Modes

  • combined (default when custom exclude patterns are provided) — merges .gitignore rules with your indexing.exclude patterns
  • config_only — only uses patterns from indexing.exclude, ignores .gitignore
  • gitignore_only (default when no custom exclude patterns are provided) — only uses .gitignore rules, ignores config excludes

LLM Configuration

The LLM provider is used for deep code research (chunkhound research and the code_research MCP tool).

ProviderConfig ValueEnv VarUtility DefaultSynthesis DefaultNotes
Claude Code CLIclaude-code-cliclaude-haiku-4-5-20251001claude-haiku-4-5-20251001Uses local Claude Code installation
Codex CLIcodex-clicodexcodexUses local Codex CLI installation
OpenCode CLIopencode-cliopencode/grok-codeopencode/grok-codeUses local OpenCode CLI installation
AnthropicanthropicCHUNKHOUND_LLM_API_KEYclaude-haiku-4-5-20251001claude-sonnet-4-5-20250929Direct API access
OpenAIopenaiCHUNKHOUND_LLM_API_KEYgpt-5-nanogpt-5Direct API access
GeminigeminiCHUNKHOUND_LLM_API_KEYMust be set explicitly via CHUNKHOUND_LLM_MODEL or llm.model (configurator defaults to gemini-3.5-flash)Must be set explicitly via CHUNKHOUND_LLM_MODEL or llm.model (configurator defaults to gemini-3.5-flash)Google Gemini API. Migration: CHUNKHOUND_GEMINI_MODEL was removed in v4.x — rename to CHUNKHOUND_LLM_MODEL.
GrokgrokCHUNKHOUND_LLM_API_KEYMust be set explicitly (configurator defaults to grok-4.3)Must be set explicitly (configurator defaults to grok-4.3)xAI API. Registry providers require explicit model.
DeepSeekdeepseekCHUNKHOUND_LLM_API_KEYMust be set explicitly (configurator defaults to deepseek-v4-flash)Must be set explicitly (configurator defaults to deepseek-v4-flash)DeepSeek API. Registry providers require explicit model.
OpenRouteropenrouterCHUNKHOUND_LLM_API_KEYMust be set explicitlyMust be set explicitlyOpenRouter API. Registry providers require explicit model.

"model" is a convenience shorthand that sets both utility_model and synthesis_model to the same value. To use different models per role, set utility_model and synthesis_model explicitly.

When an OpenAI-compatible LLM provider points at a custom base_url, ChunkHound treats it as a generic custom backend. In that mode you must set an explicit model name; ChunkHound does not guess a local default. This applies to provider: "openai", to registry providers (DeepSeek, Grok, and OpenRouter) when routed through a non-canonical endpoint, and to per-role overrides that resolve to those providers.

LLM Options

OptionTypeDefaultDescription
utility_providerstringnullOverride provider for utility operations
synthesis_providerstringnullOverride provider for synthesis operations
timeoutnumber120LLM request timeout in seconds
max_retriesnumber3Max retry attempts
output_limits_enabledbooleanfalseRestore the exact legacy numeric output limits for research synthesis instead of provider-managed limits.
output_limit_fallbacknumber64000Positive output-token fallback used when a synthesis provider cannot authoritatively omit a limit or declare one.
codex_reasoning_effortstringnullDefault reasoning effort for Codex/OpenAI: minimal, low, medium, high, xhigh
codex_reasoning_effort_utilitystringnullReasoning effort override for utility stage
codex_reasoning_effort_synthesisstringnullReasoning effort override for synthesis stage

Research Synthesis Output Limits

Provider-managed output limits are the default (llm.output_limits_enabled: false). This policy applies only to the final research synthesis path: single-pass synthesis and the map and reduce calls of map-reduce synthesis. Non-research LLM operations continue to use their existing explicit numeric caps unchanged.

For each provider-managed synthesis request, ChunkHound uses this precedence without guessing limits from model names:

  1. If the selected synthesis provider authoritatively supports omitting the output cap, omit it and let the provider manage the limit.
  2. Otherwise, use an authoritative declared positive maximum only when it includes a durable provider/API source.
  3. Otherwise, send the scalar llm.output_limit_fallback (default 64000).

UNKNOWN omission capability is handled conservatively: ChunkHound does not assume omission is safe, so it uses a valid sourced declaration or the scalar fallback. This is intentionally not a per-model lookup table.

Built-in DeepSeek, Grok, and OpenRouter configurations at their canonical endpoints authoritatively support omission. Provider-managed DeepSeek and OpenRouter requests omit max_tokens, and provider-managed Grok Chat Completions requests omit max_completion_tokens. Setting a custom base_url on any of these built-ins downgrades omission capability to UNKNOWN; generic OpenAI-compatible endpoints are also UNKNOWN and therefore use a sourced declaration or the configured fallback. An omitted client cap lets the provider apply its own policy—it does not mean output is unlimited.

At research startup, the progress display reports the resolved synthesis request-limit policy using one of these forms (runtime cap values are comma-formatted):

  • Max depth: 1; synthesis request limits: provider-managed (cap omitted)
  • Max depth: 1; synthesis request limits: provider-managed (provider-declared cap: 64,000 tokens)
  • Max depth: 1; synthesis request limits: provider-managed (fallback cap: 64,000 tokens)
  • Max depth: 1; synthesis request limits: legacy numeric (30,000-token single/reduce cap; computed per-map caps)

To roll back exactly to the legacy behavior, set llm.output_limits_enabled: true:

{
  "llm": {
    "output_limits_enabled": true
  }
}

Legacy mode preserves a 30000-token numeric request for single-pass and reduce synthesis. Each map request uses max(5000, int(30000 * cluster_tokens / total_input_tokens)); when total input tokens are zero, every map uses 30000. Provider-managed mode changes only the request’s transport allowance. Prompt guidance remains separate: 15000 for single-pass and reduce synthesis, and min(legacy_map_allowance, 7500) for each map.

Operational caveats:

  • Provider-managed output does not guarantee that the provider will not truncate a response.
  • Native provider truncation signals still raise RuntimeError; synthesis does not retry the truncated stage or return a partial or degraded result.
  • When one concurrent map fails, local sibling cancellation is best-effort. It is not a guarantee that an already-dispatched remote request stopped or that the provider will not bill it.

Anthropic-specific Options

These apply when the active provider (or a role provider) is anthropic. Each option also has a matching CHUNKHOUND_LLM_ANTHROPIC_<OPTION> environment variable (single underscore, uppercased).

OptionTypeDefaultDescription
anthropic_thinking_enabledbooleanfalseEnable extended thinking.
anthropic_thinking_modestringnullauto (default when unset), off, manual, or adaptive. auto selects adaptive on Opus 4.6+/Sonnet 4.6 and manual on older models.
anthropic_thinking_budget_tokensnumber10000Manual-mode thinking budget (min 1024). Ignored in adaptive mode (Opus 4.6+).
anthropic_thinking_displaystringnullAdaptive-mode thinking text: summarized or omitted. Opus 4.7/4.8 omit by default.
anthropic_interleaved_thinkingbooleanfalseManual-mode interleaved thinking between tool calls. Auto-enabled in adaptive mode.
anthropic_effortstringnullToken-usage effort: low, medium, high, xhigh, max. xhigh is Opus 4.7/4.8 only; max is Opus 4.6+. Unsupported levels are dropped with a warning.
anthropic_task_budget_tokensnumbernullAdvisory agentic-loop token budget (beta). Opus 4.7/4.8 only; minimum 20000.
anthropic_prompt_cachingbooleanfalseSend cache_control so the Messages API can cache prompt prefixes.
anthropic_cache_ttlstringnullPrompt-cache TTL such as 1h. null uses the API default of 5 minutes.
anthropic_context_management_enabledbooleanfalseAutomatic clearing of tool results and thinking blocks (beta).
anthropic_clear_thinking_keep_turnsnumbernullThinking turns to keep when context management clears them. null keeps all.
anthropic_clear_tool_uses_trigger_tokensnumbernullInput-token threshold that triggers tool-result clearing.
anthropic_clear_tool_uses_keepnumbernullNumber of recent tool-use pairs to keep after clearing.

Gemini-specific Options

These apply when the active provider (or a role provider) is gemini. Matching environment variables use the CHUNKHOUND_LLM_GEMINI_* prefix, and the CLI exposes --llm-gemini-thinking-level / --llm-gemini-thinking-budget.

OptionTypeDefaultDescription
gemini_thinking_levelstringnullAdaptive thinking depth for Gemini 3+ models. Allowed values: low, medium, high. Forwarded to the Google Gen AI SDK as thinking_level.
gemini_thinking_budgetnumbernullFixed thinking token budget for Gemini 2.5+ models. Forwarded to the Google Gen AI SDK as thinking_budget.

Both options can be set independently — thinking_level controls adaptive depth (Gemini 3+), while thinking_budget sets a fixed token cap (Gemini 2.5+). If both are unset, ChunkHound sends no Gemini thinking config and the model uses its own defaults.

Research Configuration

Controls the code_research MCP tool and chunkhound research command.

OptionTypeDefaultEnv VarDescription
algorithm"v1"|"v2"|"v3""v3"CHUNKHOUND_RESEARCH_ALGORITHMResearch algorithm version
query_expansion_enabledbooltrueCHUNKHOUND_RESEARCH_QUERY_EXPANSION_ENABLEDLLM-based query expansion for broader coverage
num_expanded_queriesint2CHUNKHOUND_RESEARCH_NUM_EXPANDED_QUERIESNumber of additional queries to generate (1-5)
initial_page_sizeint30CHUNKHOUND_RESEARCH_INITIAL_PAGE_SIZEResults per vector query in multi-hop search (10-100)
relevance_thresholdnumber0.5CHUNKHOUND_RESEARCH_RELEVANCE_THRESHOLDMin rerank score for chunk inclusion (0.3-0.8)
max_symbolsint5CHUNKHOUND_RESEARCH_MAX_SYMBOLSMax symbols to extract for regex search augmentation (1-20)
regex_augmentation_rationumber0.3CHUNKHOUND_RESEARCH_REGEX_AUGMENTATION_RATIORegex target as fraction of semantic count (0.1-1.0)
regex_min_resultsint20CHUNKHOUND_RESEARCH_REGEX_MIN_RESULTSMin regex results regardless of augmentation ratio (10-100)
regex_scan_page_sizeint100CHUNKHOUND_RESEARCH_REGEX_SCAN_PAGE_SIZEInternal pagination batch size for regex exclusion scanning (50-200)
multi_hop_time_limitnumber5.0CHUNKHOUND_RESEARCH_MULTI_HOP_TIME_LIMITMax seconds for evidence expansion (1.0-15.0)
multi_hop_result_limitint500CHUNKHOUND_RESEARCH_MULTI_HOP_RESULT_LIMITMax chunks accumulated during multi-hop expansion (100-2000)
multi_hop_min_candidatesint5CHUNKHOUND_RESEARCH_MULTI_HOP_MIN_CANDIDATESMin candidates above threshold to continue expansion (1-20)
multi_hop_score_degradationnumber0.15CHUNKHOUND_RESEARCH_MULTI_HOP_SCORE_DEGRADATIONMax score drop in top-5 before terminating expansion (0.05-0.5)
multi_hop_min_relevancenumber0.3CHUNKHOUND_RESEARCH_MULTI_HOP_MIN_RELEVANCEQuality floor for expansion candidates (0.1-0.8)
depth_exploration_enabledbooltrueCHUNKHOUND_RESEARCH_DEPTH_EXPLORATION_ENABLEDEnable depth exploration to find more chunks in discovered files
max_exploration_filesint5CHUNKHOUND_RESEARCH_MAX_EXPLORATION_FILESMax files to explore for additional aspects, top-K by score (1-15)
exploration_queries_per_fileint2CHUNKHOUND_RESEARCH_EXPLORATION_QUERIES_PER_FILENumber of aspect-based queries to generate per file (1-3)
depth_exploration_max_completion_tokensint10000CHUNKHOUND_RESEARCH_DEPTH_EXPLORATION_MAX_COMPLETION_TOKENSToken budget for depth exploration query generation (1-50000)
min_gapsint1CHUNKHOUND_RESEARCH_MIN_GAPSMinimum gaps to process after selection (0-5)
max_gapsint10CHUNKHOUND_RESEARCH_MAX_GAPSMaximum gaps to fill after selection (5-30)
gap_similarity_thresholdnumber0.25CHUNKHOUND_RESEARCH_GAP_SIMILARITY_THRESHOLDCosine distance threshold for clustering similar gaps (0.1-0.5)
shard_budgetint40000CHUNKHOUND_RESEARCH_SHARD_BUDGETToken budget per gap detection shard for LLM processing (20000-60000)
min_cluster_sizeint5CHUNKHOUND_RESEARCH_MIN_CLUSTER_SIZEMinimum cluster size for HDBSCAN clustering (1-20)
target_tokensint20000CHUNKHOUND_RESEARCH_TARGET_TOKENSOutput token budget for final synthesis (10000-100000)
max_compression_iterationsint5CHUNKHOUND_RESEARCH_MAX_COMPRESSION_ITERATIONSMax compression loop iterations before error (1-10)
max_boundary_expansion_linesint300CHUNKHOUND_RESEARCH_MAX_BOUNDARY_EXPANSION_LINESMax lines to expand for complete functions/classes (50-500)
max_chunks_per_file_reprint5CHUNKHOUND_RESEARCH_MAX_CHUNKS_PER_FILE_REPRTop chunks per file for representative document creation (1-10)
max_tokens_per_file_reprint2000CHUNKHOUND_RESEARCH_MAX_TOKENS_PER_FILE_REPRToken limit per file representative document (500-5000)
context_windowint150000CHUNKHOUND_RESEARCH_CONTEXT_WINDOWMax tokens for LLM context window (50000-200000)
compression_max_depthint10CHUNKHOUND_RESEARCH_COMPRESSION_MAX_DEPTHMax recursion depth for hierarchical compression (1-20)
final_synthesis_thresholdint75000CHUNKHOUND_RESEARCH_FINAL_SYNTHESIS_THRESHOLDMax tokens for final synthesis LLM call (30000-200000)
window_expansion_enabledbooltrueCHUNKHOUND_RESEARCH_WINDOW_EXPANSION_ENABLEDEnable neighboring chunk expansion for context
window_expansion_linesint50CHUNKHOUND_RESEARCH_WINDOW_EXPANSION_LINESLines to expand before/after retrieved chunks (10-200)
import_resolution_enabledbooltrueCHUNKHOUND_RESEARCH_IMPORT_RESOLUTION_ENABLEDAutomatically fetch source files for imports in retrieved chunks
import_resolution_max_filesint10CHUNKHOUND_RESEARCH_IMPORT_RESOLUTION_MAX_FILESMax import source files to fetch per synthesis (1-50)
exhaustive_modeboolfalseCHUNKHOUND_RESEARCH_EXHAUSTIVE_MODEEnable exhaustive retrieval (no result limit, 600s timeout)
exhaustive_time_limitnumber600.0CHUNKHOUND_RESEARCH_EXHAUSTIVE_TIME_LIMITSafety timeout for exhaustive mode in seconds (60-1800)
{
  "research": {
    "algorithm": "v3",
    "exhaustive_mode": false,
    "target_tokens": 20000,
    "query_expansion_enabled": true,
    "depth_exploration_max_completion_tokens": 10000,
    "relevance_threshold": 0.5
  }
}

Algorithm Versions

The algorithm setting controls how ChunkHound explores your codebase to answer a research question. All three versions produce the same output format; they differ only in how thoroughly they search.

New to ChunkHound? Start with "v3" (the default).

VersionStrategyLLM callsBest for
v1BFS — generates follow-up questions, explores one level deepMinimalQuick lookups, simple codebases
v2Wide coverage — depth-first on top files, then gap detectionMediumBalanced discovery; most production use cases
v3 (default)Runs v1 + v2 in parallel, merges resultsMost (parallel, not sequential)Complex codebases where missing context is costly

v3 is not slower than v2 — both strategies run concurrently via asyncio.gather, so the wall-clock time is roughly the same as v2 alone while covering more ground.

When to switch away from v3:

  • Use v1 when cost matters and the question is narrow and self-contained (“explain how the config loader works”)
  • Use v2 when you want a good balance without the extra LLM spend of dual-strategy merging
  • v3 is the right default for open-ended research questions (“how does authentication flow through this system?”)

Gap detection parameters (min_gaps, max_gaps, gap_similarity_threshold) only affect v2 and v3. They are silently ignored for v1.

Environment Variables

Most environment variables use the CHUNKHOUND_ prefix with __ (double underscore) as the section delimiter. The LLM section uses a single underscore (CHUNKHOUND_LLM_*).

VariableDescription
CHUNKHOUND_EMBEDDING__PROVIDEREmbedding provider name
CHUNKHOUND_EMBEDDING__MODELEmbedding model name
CHUNKHOUND_EMBEDDING__API_KEYAPI key for embedding provider
CHUNKHOUND_EMBEDDING__BASE_URLBase URL for OpenAI-compatible endpoints
CHUNKHOUND_EMBEDDING__SSL_VERIFYVerify TLS certificates for embedding requests sent to base_url
CHUNKHOUND_EMBEDDING__RERANK_MODELReranking model name
CHUNKHOUND_EMBEDDING__RERANK_URLSeparate rerank endpoint URL
CHUNKHOUND_EMBEDDING__RERANK_SSL_VERIFYVerify TLS certificates for rerank requests (overrides ssl_verify)
CHUNKHOUND_EMBEDDING__RERANK_FORMATReranking API format: cohere, tei, or auto
CHUNKHOUND_EMBEDDING__RERANK_BATCH_SIZEMax documents per rerank request
CHUNKHOUND_EMBEDDING__TIMEOUTRequest timeout in seconds (default: 30)
CHUNKHOUND_EMBEDDING__MAX_RETRIESMax retry attempts on failure (default: 3)
CHUNKHOUND_EMBEDDING__API_VERSIONAzure OpenAI API version (YYYY-MM-DD)
CHUNKHOUND_EMBEDDING__AZURE_ENDPOINTAzure OpenAI endpoint
CHUNKHOUND_EMBEDDING__AZURE_DEPLOYMENTAzure OpenAI deployment name
CHUNKHOUND_DATABASE__PROVIDERDatabase backend (duckdb or lancedb)
CHUNKHOUND_DATABASE__PATHDatabase storage path
CHUNKHOUND_DATABASE__MAX_DISK_USAGE_GBMax database size in GB
CHUNKHOUND_DATABASE__EXECUTE_TIMEOUT_SECONDSSync serial DB executor timeout in seconds (overrides 30s/660s defaults when set; async dispatch unbounded)
CHUNKHOUND_DATABASE__FRAGMENTATION_THRESHOLD_PCTAuto-compaction fragmentation threshold (%)
CHUNKHOUND_DATABASE__READ_ONLYOpen DB read-only (true/1/yes)
CHUNKHOUND_DATABASE__LANCEDB_INDEX_TYPELanceDB vector index type
CHUNKHOUND_DATABASE__LANCEDB_OPTIMIZE_FRAGMENT_THRESHOLDLanceDB fragment count to trigger optimize
CHUNKHOUND_LLM_PROVIDERLLM provider for research
CHUNKHOUND_LLM_MODELLLM model shorthand that sets both utility and synthesis roles
CHUNKHOUND_LLM_UTILITY_MODELLLM model for utility tasks (fast, lower cost)
CHUNKHOUND_LLM_SYNTHESIS_MODELLLM model for synthesis tasks (primary output)
CHUNKHOUND_LLM_API_KEYAPI key for LLM provider
CHUNKHOUND_LLM_BASE_URLBase URL for LLM provider (proxy / custom endpoint)
CHUNKHOUND_LLM_SSL_VERIFYVerify TLS certificates for requests sent to llm.base_url
CHUNKHOUND_LLM_UTILITY_PROVIDEROverride provider for utility operations
CHUNKHOUND_LLM_SYNTHESIS_PROVIDEROverride provider for synthesis operations
CHUNKHOUND_LLM_TIMEOUTLLM request timeout in seconds (default: 120)
CHUNKHOUND_LLM_MAX_RETRIESMax retry attempts (default: 3)
CHUNKHOUND_LLM_OUTPUT_LIMITS_ENABLEDRestore exact legacy research synthesis output limits (true/false; default: false)
CHUNKHOUND_LLM_OUTPUT_LIMIT_FALLBACKPositive provider-managed synthesis fallback in output tokens (default: 64000)
CHUNKHOUND_LLM_CODEX_REASONING_EFFORTReasoning effort for Codex models (minimal, low, medium, high, xhigh)
CHUNKHOUND_LLM_CODEX_REASONING_EFFORT_UTILITYReasoning effort override for utility stage
CHUNKHOUND_LLM_CODEX_REASONING_EFFORT_SYNTHESISReasoning effort override for synthesis stage
CHUNKHOUND_LLM_ANTHROPIC_THINKING_ENABLEDEnable extended thinking
CHUNKHOUND_LLM_ANTHROPIC_THINKING_MODEThinking mode: auto, off, manual, or adaptive
CHUNKHOUND_LLM_ANTHROPIC_THINKING_BUDGET_TOKENSManual-mode thinking budget (min 1024, default: 10000)
CHUNKHOUND_LLM_ANTHROPIC_THINKING_DISPLAYAdaptive-mode thinking text: summarized or omitted
CHUNKHOUND_LLM_ANTHROPIC_INTERLEAVED_THINKINGManual-mode interleaved thinking between tool calls
CHUNKHOUND_LLM_ANTHROPIC_EFFORTToken-usage effort: low, medium, high, xhigh, max
CHUNKHOUND_LLM_ANTHROPIC_TASK_BUDGET_TOKENSAdvisory agentic-loop token budget (beta)
CHUNKHOUND_LLM_ANTHROPIC_PROMPT_CACHINGSend cache_control for prompt caching
CHUNKHOUND_LLM_ANTHROPIC_CACHE_TTLPrompt-cache TTL (e.g. 1h)
CHUNKHOUND_LLM_ANTHROPIC_CONTEXT_MANAGEMENT_ENABLEDAutomatic clearing of tool results and thinking blocks (beta)
CHUNKHOUND_LLM_ANTHROPIC_CLEAR_THINKING_KEEP_TURNSThinking turns to keep when context management clears them
CHUNKHOUND_LLM_ANTHROPIC_CLEAR_TOOL_USES_TRIGGER_TOKENSInput-token threshold that triggers tool-result clearing
CHUNKHOUND_LLM_ANTHROPIC_CLEAR_TOOL_USES_KEEPNumber of recent tool-use pairs to keep after clearing
CHUNKHOUND_LLM_GEMINI_THINKING_LEVELGemini thinking depth (low, medium, high)
CHUNKHOUND_LLM_GEMINI_THINKING_BUDGETGemini fixed thinking token budget
CHUNKHOUND_INDEXING__EXCLUDE_MODEExclusion mode (combined, config_only, gitignore_only)
CHUNKHOUND_INDEXING__EXCLUDEGlob patterns to exclude from indexing
CHUNKHOUND_INDEXING__INCLUDEGlob patterns limiting which files are indexed
CHUNKHOUND_INDEXING__CLEANUPRemove orphaned DB records after indexing (default: true)
CHUNKHOUND_INDEXING__FORCE_REINDEXForce re-indexing of all files (default: false)
CHUNKHOUND_INDEXING__MAX_FILE_SIZE_MBSkip files larger than this (MB, default: 10)
CHUNKHOUND_INDEXING__CONFIG_FILE_SIZE_THRESHOLD_KBSkip structured config files larger than this (KB, default: 20)
CHUNKHOUND_INDEXING__PER_FILE_TIMEOUT_SECONDSPer-file parse timeout (default: 3.0)
CHUNKHOUND_INDEXING__PER_FILE_TIMEOUT_MIN_SIZE_KBOnly apply per-file timeout to files at least this large (KB, default: 128)
CHUNKHOUND_INDEXING__BATCH_SIZEFiles per parsing batch (default: 50)
CHUNKHOUND_INDEXING__DB_BATCH_SIZEChunks per database write batch (default: 100)
CHUNKHOUND_INDEXING__MAX_CONCURRENTMax concurrent parser workers (default: 5)
CHUNKHOUND_INDEXING__CHUNK_OVERLAPInternal chunk overlap (default: 50)
CHUNKHOUND_INDEXING__MIN_CHUNK_SIZEInternal min chunk size (default: 50)
CHUNKHOUND_INDEXING__INDEX_UNKNOWN_FILESIndex files with unrecognized extensions as plain text (default: false)
CHUNKHOUND_INDEXING__DETECT_EMBEDDED_SQLEnable embedded SQL detection (default: true)
CHUNKHOUND_INDEXING__DISCOVERY_BACKENDFile discovery backend: auto, python, git, git_only (default: auto)
CHUNKHOUND_INDEXING__GITIGNORE_BACKENDBackend for gitignore evaluation: python or libgit2 (default: python)
CHUNKHOUND_INDEXING__CHIGNORE_FILEChunkHound-specific ignore file name (default: .chignore)
CHUNKHOUND_INDEXING__GIT_PATHSPEC_CAPMax git pathspec entries (default: 128)
CHUNKHOUND_INDEXING__MTIME_EPSILON_SECONDSTolerance for file mtime comparison (seconds, default: 0.01)
CHUNKHOUND_INDEXING__PARALLEL_DISCOVERYEnable parallel directory traversal for large codebases (default: true)
CHUNKHOUND_INDEXING__MIN_DIRS_FOR_PARALLELMinimum top-level directories to activate parallel discovery (default: 4)
CHUNKHOUND_INDEXING__MAX_DISCOVERY_WORKERSMaximum worker processes for parallel discovery (default: 16)
CHUNKHOUND_INDEXING__WORKSPACE_GITIGNORE_OVERLAYApply CH root .gitignore as global overlay across repos (default: false)
CHUNKHOUND_INDEXING__WORKSPACE_GITIGNORE_NONREPOUse CH root .gitignore only for non-repo paths (default: true)
CHUNKHOUND_INDEXING__REALTIME_BACKENDFilesystem monitoring backend: watchman, watchdog, or polling
CHUNKHOUND_DB_EXECUTE_TIMEOUTLegacy alias for CHUNKHOUND_DATABASE__EXECUTE_TIMEOUT_SECONDS
CHUNKHOUND_YAML_ENGINEYAML parser engine (rapid or tree)
CHUNKHOUND_CONFIG_FILEPath to config file (alternative to --config)
CHUNKHOUND_WEBSEARCH_TIMEOUT_SECONDSWeb search subprocess timeout in seconds (default: 600)
CHUNKHOUND_DEBUGEnable debug logging
VOYAGE_API_KEYFallback API key for VoyageAI provider

Advanced routing

The homepage configurator emits the 30-second onboarding shape. Real enterprise deployments often need to hit Azure, a self-hosted endpoint, or an LLM proxy. Below is what ChunkHound actually wires through, and what it doesn’t.

TLS verification for custom endpoints

ssl_verify is explicit now. ChunkHound does not disable certificate verification automatically.

  • embedding.ssl_verify only affects requests sent to an explicit embedding.base_url.
  • embedding.rerank_ssl_verify only affects rerank requests and overrides inherited ssl_verify when set.
  • llm.ssl_verify only affects requests sent to an explicit llm.base_url.
  • If base_url is unset, ssl_verify is ignored for security.
  • If rerank_url is unset, rerank_ssl_verify is ignored.
  • Prefer a proper CA trust chain when possible. Use false only for local endpoints or trusted internal networks with self-signed/private certificates.

Azure OpenAI (embeddings)

ChunkHound’s OpenAI embedding provider speaks Azure OpenAI natively. Supply the four Azure fields and omit base_url — the two are mutually exclusive.

{
  "embedding": {
    "provider": "openai",
    "model": "text-embedding-3-small",
    "api_key": "<YOUR_AZURE_KEY>",
    "azure_endpoint": "https://<resource>.openai.azure.com",
    "api_version": "2024-02-01",
    "azure_deployment": "<your-deployment-name>"
  }
}

LLM-side Azure OpenAI is not supported yet — the llm section has no Azure fields. Use a proxy (see below) if you need to route LLM traffic through Azure.

VoyageAI on Azure ML / AI Foundry

VoyageAI models are available on the Azure Marketplace and in Microsoft Foundry. ChunkHound can target an Azure-hosted Voyage deployment via base_url:

{
  "embedding": {
    "provider": "voyageai",
    "model": "voyage-3.5",
    "api_key": "<YOUR_AZURE_VOYAGE_KEY>",
    "base_url": "https://<your-resource>.services.ai.azure.com/models",
    "ssl_verify": true,
    "rerank_url": "https://<your-rerank-endpoint>/rerank",
    "rerank_ssl_verify": true,
    "rerank_format": "tei"
  }
}

Caveats:

  • Native Voyage API required. The Azure deployment must expose /v1/embeddings with the native Voyage shape (true for Voyage marketplace listings; verify your specific deployment).
  • Bundled reranker unavailable. VoyageAI’s rerank-* models are not accessible through a custom base_url — the embedding endpoint doesn’t expose /rerank. Run a separate reranker and point rerank_url at it. vLLM with Qwen/Qwen3-Reranker-0.6B is a drop-in option:
    vllm serve Qwen/Qwen3-Reranker-0.6B --task score --port 8000
  • TLS disablement is primarily for the HTTP reranker path. The separate rerank_url path respects ssl_verify / rerank_ssl_verify. For the VoyageAI SDK path, prefer trusted CA configuration such as REQUESTS_CA_BUNDLE.
  • Concurrency throttled to 1 by default when base_url is set, to respect Azure serverless rate limits. Override via max_concurrent_batches if your SKU permits.
  • api_key still required. The validator doesn’t enforce it when base_url is present, but Azure-hosted endpoints still need their own key — supply it.

LLM via proxy (Anthropic, OpenAI, Grok, DeepSeek, OpenRouter)

The Anthropic, OpenAI, Grok, DeepSeek, and OpenRouter LLM providers all forward base_url to their SDK. Point them at a gateway like LiteLLM to centralize auth, logging, and rate limiting:

{
  "llm": {
    "provider": "anthropic",
    "model": "claude-sonnet-4-5-20250929",
    "api_key": "<YOUR_GATEWAY_KEY>",
    "base_url": "https://your-gateway.example.com",
    "ssl_verify": true
  }
}

The gateway must preserve each provider’s native request/response shape — ChunkHound uses the vendor SDKs, not a generic HTTP client.

Local OpenAI-compatible servers (Ollama, vLLM)

Local inference servers that speak the OpenAI API work via provider: "openai" with base_url pointing at the local endpoint. No api_key is needed for servers that don’t enforce auth, but you must set an explicit model.

Ollama

Ollama provides embeddings, reranking, and LLM inference in a single process. Pull the models you need, then point ChunkHound at the Ollama endpoint:

# Embedding + reranker models
ollama pull qwen3-embedding && ollama pull qwen3-reranker

# LLM — pick one
ollama pull qwen3-coder:30b
ollama pull gemma4:27b

Embedding and reranker config (.chunkhound.json):

{
  "embedding": {
    "provider": "openai",
    "model": "qwen3-embedding",
    "base_url": "http://localhost:11434/v1",
    "ssl_verify": false,
    "rerank_model": "qwen3-reranker",
    "rerank_format": "cohere"
  }
}

No rerank_url is needed — it is auto-derived from base_url.

LLM config:

Migration note: Do not set llm.provider to "ollama". ChunkHound treats Ollama as an OpenAI-compatible endpoint, so use provider: "openai" with the Ollama base_url and an explicit model.

{
  "llm": {
    "provider": "openai",
    "model": "qwen3-coder:30b",
    "base_url": "http://localhost:11434/v1",
    "ssl_verify": false
  }
}

Use whichever model you pulled in llm.model. For example, set "model": "gemma4:27b" if you want the Gemma 4 path instead of Qwen. ChunkHound does not infer a local default model from base_url.

If your embeddings stay on the official provider but reranking goes to a local HTTPS service with a self-signed certificate, override the reranker only:

{
  "embedding": {
    "provider": "openai",
    "model": "text-embedding-3-small",
    "api_key": "<YOUR_OPENAI_KEY>",
    "rerank_model": "Qwen/Qwen3-Reranker-0.6B",
    "rerank_url": "https://localhost:8001/rerank",
    "rerank_ssl_verify": false,
    "rerank_format": "tei"
  }
}

vLLM

vLLM gives you dedicated processes per model, which is better for throughput and lets you serve HuggingFace model IDs directly. When embeddings and reranking are served from the same OpenAI-compatible endpoint, ChunkHound infers the reranker path from base_url just like it does for Ollama:

# Embedding + reranker server
vllm serve Qwen/Qwen3-Embedding-0.6B --port 8000

# LLM server
vllm serve Qwen/Qwen3-Coder-30B-A3B-Instruct --port 11434

Embedding and reranker config (.chunkhound.json):

{
  "embedding": {
    "provider": "openai",
    "model": "Qwen/Qwen3-Embedding-0.6B",
    "base_url": "http://localhost:8000/v1",
    "rerank_model": "Qwen/Qwen3-Reranker-0.6B",
    "rerank_format": "cohere"
  }
}

No rerank_url is needed when the reranker lives behind the same OpenAI-compatible endpoint. ChunkHound auto-derives /rerank from base_url.

If you split embeddings and reranking across different services, keep base_url pointed at the embedding server and set rerank_url explicitly:

{
  "embedding": {
    "provider": "openai",
    "model": "Qwen/Qwen3-Embedding-0.6B",
    "base_url": "http://localhost:8025/v1",
    "rerank_model": "Qwen/Qwen3-Reranker-0.6B",
    "rerank_url": "http://localhost:8000/rerank",
    "rerank_format": "cohere"
  }
}

LLM config:

{
  "llm": {
    "provider": "openai",
    "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
    "base_url": "http://localhost:11434/v1"
  }
}

Ollama vs vLLM: Ollama is simpler — one process, one command per model. vLLM is better for throughput and gives you full control over each serving process. Both work equally well with ChunkHound as long as llm.model is set explicitly.

The websearch tool searches the web via DuckDuckGo, fetches the top pages, indexes the fetched content in memory, and runs the same deep research pipeline used for local code search. It is available as an MCP tool and as chunkhound websearch.

Requirements

The web search tool requires all three provider capabilities to be configured:

  • Embedding provider — e.g. embedding.provider: "voyageai" or "openai"
  • LLM provider — for query expansion and answer synthesis
  • Rerankingembedding.rerank_model must be set for relevance-aware multi-hop search

If any of these are missing, the MCP websearch tool is not registered (capability gating) and the CLI command will fail.

Parameters

ParameterTypeDefaultDescription
querystringrequiredNatural-language or keyword query sent to DuckDuckGo
--limit / limitint30Max results to fetch (1–100). CLI uses --limit, MCP uses limit.

Environment Variables

VariableDescription
CHUNKHOUND_WEBSEARCH_TIMEOUT_SECONDSWall-clock timeout (seconds) for the research subprocess. Default: 600. Also returned for malformed values.

Fixed Constants

ConstantValueDescription
WEBSEARCH_LIMIT_MAX100Upper bound for the --limit / limit parameter

Browser Dependency

The fetch path uses zendriver (v0.15.3, core dependency — no extra install needed) to drive the system-installed Google Chrome for rich page rendering. Chrome >=124 is required. If Chrome is not found or too old, fetches fall back to urllib (less capable — may miss JS-rendered content and cannot fetch some PDFs).

Research Config Linkage

The web search tool delegates to the same deep research pipeline as code_research. All settings in the Research Configuration section apply: algorithm, multi_hop_time_limit, relevance_threshold, query_expansion_enabled, target_tokens, etc.

Fetch URL

The fetchurl tool fetches a single URL, extracts its content, and returns a focused Markdown answer via one LLM call (short pages) or a rerank+elbow pipeline over page chunks (long pages with a query). It is available as an MCP tool and as chunkhound fetchurl. Fetches use the same zendriver + system Chrome transport as Web Search with the same urllib fallback — see that section’s Browser Dependency note for Chrome version requirements and fallback behavior.

Requirements

The fetch URL tool requires two provider capabilities to be configured:

  • LLM provider — for the extraction/answer call
  • Reranker-capable embedding provider — VoyageAI (SDK), or a Cohere/TEI HTTP reranker. rerank_model is required for the VoyageAI SDK and Cohere paths; TEI needs rerank_format=tei + rerank_url (no rerank_model).

If either is missing, the MCP fetchurl tool is not registered (capability gating hides it from tools/list) and the CLI command exits 1 with an explicit error message.

Parameters

ParameterTypeDefaultDescription
urlstringrequiredAbsolute http:// or https:// URL. Non-http(s) schemes are rejected, as are hosts resolving to loopback / private / link-local / reserved / multicast / unspecified addresses.
query / --query / -qstring""Optional question. When set, focuses extraction and enables the rerank+elbow path on pages exceeding fetchurl.rerank_threshold_tokens.

Environment Variables

VariableDescription
CHUNKHOUND_FETCHURL_RERANK_THRESHOLD_TOKENSOverrides fetchurl.rerank_threshold_tokens.
CHUNKHOUND_FETCHURL_TRUNCATE_TOKENSOverrides fetchurl.truncate_tokens.
CHUNKHOUND_FETCHURL_MAX_RETRIESOverrides fetchurl.max_retries.

Configuration File

{
  "fetchurl": {
    "rerank_threshold_tokens": 15000,
    "truncate_tokens": 15000,
    "max_retries": 3
  }
}
KeyTypeDefaultDescription
rerank_threshold_tokensint (≥1)15000Estimated token count above which the chunk-rerank path (chunk + rerank + elbow filter) is used instead of the truncate path (token-truncate + single LLM call). Only applies when query is set — without a query, the truncate path is always used regardless of page size. Tokens are estimated at 4 chars/token.
truncate_tokensint (≥1)15000Token cap applied to the truncate-option input before the LLM call. Content is sliced to truncate_tokens × 4 characters.
max_retriesint (1–10)3Fetch attempts including the first. Uses exponential backoff with full jitter capped at 8s. Browser-transport death consumes an attempt slot and downgrades remaining attempts to urllib.

CLI vs MCP: The three knobs above are exposed as --fetchurl-* flags on the CLI (chunkhound fetchurl). The MCP fetchurl tool accepts only url and query — knob overrides must come from config or CHUNKHOUND_FETCHURL_* env vars.