Most users only need the setup from the Self-Hosting Guide. This page is the full reference for customizing providers, tuning features, and hardening your deployment.
- Environment variables (always take precedence)
.envfileconfig.tomlfile- Built-in defaults
.env for secrets and overrides, config.toml for base settings. Or use environment variables exclusively — whatever fits your deployment. Copy the examples to get started:
Environment Variable Naming
All config values map to environment variables:{SECTION}_{KEY}for top-level section settings (e.g.,DB_CONNECTION_URI→[db].CONNECTION_URI){KEY}for app-level settings (e.g.,LOG_LEVEL→[app].LOG_LEVEL)- Use
__inside{KEY}for nested settings (e.g.,DIALECTIC_LEVELS__minimal__MODEL_CONFIG__TRANSPORT,DERIVER_MODEL_CONFIG__OVERRIDES__BASE_URL)
LLM Configuration
The Self-Hosting Guide covers the basic setup: either the built-in OpenAI defaults or one OpenAI-compatible endpoint/model for all features. This section covers recommended model tiers, using multiple providers, and per-feature tuning.All Honcho agents (deriver, dialectic, dream) require tool calling. Your models must support the OpenAI tool calling format.
Choosing Models
Model choice matters more for tool-use reliability than raw intelligence:
You can mix providers freely — for example, use Gemini for the deriver and Claude for dreaming.
Provider Types
For OpenAI-compatible proxies (OpenRouter, vLLM, Ollama, etc.), use
transport = "openai" and set MODEL_CONFIG__OVERRIDES__BASE_URL on each feature to point at your endpoint.
Some OpenAI-compatible providers don’t support OpenAI Structured Outputs (
json_schema). Set DERIVER_MODEL_CONFIG__STRUCTURED_OUTPUT_MODE=json_object to request loose JSON mode and inject the schema into the prompt instead.This setting only applies to the deriver on the openai transport — it is the only feature that uses structured output. The dialectic, summarizer, and dreamer don’t request structured output, so the setting has no effect there, and the anthropic/gemini transports reject it.Tiered Model Setup
Once you’re past initial setup, you can assign different models per feature for better cost/quality tradeoffs. This example uses OpenRouter with light/medium/heavy tiers:Direct Vendor Keys
Instead of an OpenAI-compatible proxy, you can use vendor APIs directly. Each transport picks up its ownLLM_{TRANSPORT}_API_KEY.
If you keep the built-in defaults, only LLM_OPENAI_API_KEY is required:
Self-Hosted (vLLM / Ollama)
Usetransport = "openai" and set MODEL_CONFIG__OVERRIDES__BASE_URL on each feature:
MODEL_CONFIG__TRANSPORT, MODEL_CONFIG__MODEL, and MODEL_CONFIG__OVERRIDES__BASE_URL for each feature the same way.
The same overrides are available in config.toml:
Thinking Budget
Built-in defaults do not setMODEL_CONFIG__THINKING_BUDGET_TOKENS or MODEL_CONFIG__THINKING_EFFORT. Add one only when your chosen model supports it.
Use MODEL_CONFIG__THINKING_EFFORT for OpenAI reasoning models:
MODEL_CONFIG__THINKING_BUDGET_TOKENS for Anthropic and Gemini models. Set it to 0 or omit it for providers that don’t support extended thinking:
Provider-Specific Parameters
Each model config supports anoverrides.provider_params dict for passing arbitrary parameters to the underlying provider SDK. Use this for vendor-specific features that aren’t part of the standard config:
timeout gotchas:
- The value is validated at config load: it must coerce to a positive,
finite number of seconds (numbers or numeric strings like
"3600"), or the process refuses to start with an error naming the offending config path. This applies to both the primary model config and itsfallback.overrides. - The unit is always seconds, regardless of transport. OpenAI and
Anthropic receive it as the SDK’s
timeoutkwarg; Gemini has no such kwarg, so Honcho converts it to milliseconds onhttp_options.timeout. - When unset, nothing is forwarded and each SDK’s default applies — adding this key is opt-in and changes no existing behavior.
- A too-tight timeout doesn’t fail once: the aborted request goes through the normal retry/fallback chain before the caller sees an error, so the observed latency is several multiples of the timeout.
Transport passthrough keys
Three keys insideprovider_params are recognized as request-level escape hatches and forwarded to the underlying transport. Where a transport actually validates and merges one of these keys, its value must be a mapping — a non-mapping value raises a configuration error (see the per-transport behavior below; a key a transport ignores is not validated):
extra_body— merged into the request bodyextra_headers— extra HTTP headersextra_query— extra URL query parameters
- OpenAI and Anthropic forward all three as identically-named SDK kwargs (
extra_body,extra_headers,extra_query). - Gemini has no SDK kwargs for these. It merges
extra_bodyinto theGenerateContentConfigdict and foldsextra_headersintohttp_options.headers;extra_queryis unsupported and silently ignored.
extra_body, your value replaces Honcho’s. You are responsible for choosing a coherent combination — e.g. unset thinking_budget_tokens when supplying an extra_body.thinking for Anthropic-via-proxy, since Honcho will not translate between the two shapes.
Because Gemini merges extra_body directly into GenerateContentConfig (rather than a nested request body), an extra_body written for OpenAI/Anthropic generally will not transfer to Gemini unchanged — and a key collision there can overwrite a field Honcho manages (thinking_config, response_schema, tools, …).
Changing Transport
When changing a feature’stransport, always specify model explicitly. Partial overrides that change transport without model will keep the previous model name, which may not be valid for the new provider.
General LLM Settings
Embedding Configuration
Embeddings use their own nested model config, separate from the main text-generation LLM settings.EMBEDDING_MODEL_CONFIG__MAX_BATCH_SIZE defaults to 2048 for OpenAI. For
Gemini the client applies a conservative default of 100 — Gemini does not
document a per-request limit. Set it when an OpenAI-compatible embedding
provider accepts fewer inputs per request, such as DashScope
text-embedding-v4 with a limit of 10.
Forwarding dimensions= to OpenAI-compatible providers is controlled by EMBEDDING_MODEL_CONFIG__DIMENSIONS_MODE:
auto(default): forwardsdimensions=when the operator has explicitly setEMBEDDING_VECTOR_DIMENSIONS— provenance, not value — and the configured model is not on the known-rejecting list (currentlytext-embedding-ada-002). ExplicitEMBEDDING_VECTOR_DIMENSIONS=1536does trigger the forward; this is howtext-embedding-3-largetruncation to 1536 is expressed. Deployments that leave the setting unset get their existing behavior (dimensions=is not forwarded).always: always forward, regardless of whetherEMBEDDING_VECTOR_DIMENSIONSwas set. Use for OpenAI-compatible self-hosted providers that require it. Do not pickalwaysjust for same-as-default truncation —autohandles that case correctly as long as you setEMBEDDING_VECTOR_DIMENSIONS=1536explicitly in your environment.alwaysis the right answer when your config layer might strip explicit “default-valued” envs, or when you want defense-in-depth.never: never forward. Explicit opt-out for providers that reject the parameter (e.g.text-embedding-ada-002if it slips past the known-rejecting allowlist).
Bootstrapping non-default dimensions
EMBEDDING_VECTOR_DIMENSIONS is treated as immutable for the life of a deployment. The pgvector schema is dim-pinned by Alembic at 1536 by default; if you want a different dim, you must ALTER the empty columns once at bootstrap time.
Install order for a non-default dim:
text-embedding-3-small need no action — step 3 detects matching dims and skips.
The script refuses to ALTER tables that already contain non-null embeddings. To switch dim or model on a populated deployment, stand up a new deployment at the new configuration and migrate data out of band; there is no in-place re-embedding affordance. See Changing Embeddings for the destroy + rebuild recipe and the same-dim model-swap caveat.
External vector stores (Turbopuffer, LanceDB) do not need bootstrap setup. Namespaces are per-workspace and lazy-created on first write at whatever dim the embedding client returns. Use --report to inventory the existing namespaces against the configured dim:
src/startup/embedding_validator.py enforces the dim invariant at boot for both the API (src/main.py lifespan) and the deriver (src/deriver/__main__.py). A mismatch crashes the process with an actionable error before any HTTP route is served or any queue task is processed.
VECTOR_STORE_DIMENSIONS is deprecated. EMBEDDING_VECTOR_DIMENSIONS is the single source of truth; setting VECTOR_STORE_DIMENSIONS explicitly emits a startup warning and is otherwise ignored. The field will be removed in a future release; drop it from your .env to silence the warning.
The VECTOR_STORE_MIGRATED flag still exists and still controls dual-write / cutover semantics for legacy tenants moving between storage backends (pgvector ↔ turbopuffer ↔ lancedb). It is unrelated to dimension configuration after this release.
Feature-Specific Model Configuration
Each feature can use a different provider and model. Below are all the tuning knobs. Dialectic API: The Dialectic API provides theory-of-mind informed responses. It uses a tiered reasoning system with five levels:Core Configuration
Application Settings
Database
Authentication
python scripts/generate_jwt_secret.py
Cache (Redis)
Redis caching is optional. Honcho works without it but benefits from caching in high-traffic scenarios.Webhooks
Vector Store
Monitoring
Prometheus Metrics
Honcho exposes/metrics endpoints for scraping:
- API process: Port 8000
- Deriver process: Port 9090
CloudEvents Telemetry
Sentry
Reference config.toml
A complete config.toml with all defaults. Copy and modify what you need:Database Migrations
Troubleshooting
-
Database connection errors — Ensure
DB_CONNECTION_URIusespostgresql+psycopg://prefix. Verify database is running and pgvector extension is installed. -
Authentication issues — Generate and set
AUTH_JWT_SECRETwhenAUTH_USE_AUTH=true. Usepython scripts/generate_jwt_secret.py. - LLM provider errors — Verify API keys are set. Check model names match your provider’s format. Ensure models support tool calling.
-
Deriver not processing — Check logs. Increase
DERIVER_WORKERSfor throughput. Verify database and LLM connectivity. -
Dialectic level issues — Unset level fields inherit from the built-in defaults. For Anthropic,
THINKING_BUDGET_TOKENSmust be >= 1024 when enabled. For providers without budgeted thinking, omit it or set it to0.MAX_OUTPUT_TOKENSmust exceedTHINKING_BUDGET_TOKENS. -
Vector store issues — For Turbopuffer, set the API key. Check that
EMBEDDING_VECTOR_DIMENSIONSmatches your embedding model — the startup validator will refuse to boot on a mismatch.