Self-hosting docs overhaul: single-provider default, restructured config guide (#510)

* fix: Inconsistencies in Docs, health endpoint, troubleshooting guide

* fix: (docs) maintain consistency on postgres db name

* chore: (docs) update v2 contributing docs with updates db paths

* docs: overhaul self-hosting docs for provider-agnostic setup

- .env.template: lead with provider options (custom, vllm, google,
  anthropic, openai, groq) instead of baking in vendor-specific keys.
  All provider/model settings commented out so server fails fast until
  configured. Separate endpoint config from per-feature provider+model
  from tuning knobs.
- docker-compose.yml.example: fix healthcheck -d honcho -> -d postgres
  to match POSTGRES_DB=postgres.
- config.toml.example: reorder and document LLM key section with
  OpenRouter and vLLM examples.
- self-hosting.mdx: replace multi-vendor key table with provider options
  table. Add examples for OpenRouter, vLLM/Ollama, and direct vendor
  keys. Remove duplicated key lists from Docker/manual setup sections.
- configuration.mdx: replace scattered provider docs with provider types
  table. Fix Docker Compose snippet to match actual compose file. Note
  code defaults as fallback, not recommended path.
- troubleshooting.mdx: add alternative provider issues section (custom
  provider config, model name format, Docker localhost, structured
  output failures).

* docs: add Docker build troubleshooting for permission errors

- Document BuildKit requirement (RUN --mount syntax)
- AppArmor/SELinux blocking Docker builds on Linux
- Volume mount UID mismatch between host and container app user
- Note in self-hosting docs that Docker path builds from source

* docs: reframe self-hosting as contributor/dev path, point to cloud service

* Revert "docs: reframe self-hosting as contributor/dev path, point to cloud service"

This reverts commit 3e766eb1a9.

* docs: add production compose, model guidance, thinking budget docs

- Add docker-compose.prod.yml for VM/server deployment: no source
  mounts, restart policies, 127.0.0.1-bound ports, cache enabled
- Add model tier guidance and community quick-start link to self-hosting
- Document THINKING_BUDGET_TOKENS gotcha for non-Anthropic providers
- Add reverse proxy examples (Caddy + nginx) to production section
- Add backup/restore commands to production considerations

* docs: simplify self-hosting to single provider, restructure config guide

Self-hosting page now defaults to one OpenAI-compatible endpoint
with one model for all features. Moved model tiers, alternative
providers, and per-feature tuning into the configuration guide.
Eliminated duplicate config priority sections, dev/prod split,
and redundant TOML examples.

* docs: merge compose files, restore provider/model to feature sections in .env.template

Single docker-compose.yml.example with dev sections commented out.
Moved PROVIDER and MODEL back alongside each feature in .env.template
so settings stay colocated with their module. Updated self-hosting
docs to reference single compose file.

* fix: broken anchor links, redundant migration step, minor inconsistencies

Fix 4 broken internal links (#llm-provider-setup, #llm-api-keys,
#which-api-keys-do-i-need, #alternative-providers) to point to
correct headings. Remove redundant Docker migration step (entrypoint
already runs alembic). Fix cache URL missing ?suppress=true in
reference config. Fix uv install command to use official method.

* docs: env template ready to use, simplify self-hosting flow

.env.template now has provider/model lines uncommented with
placeholder values — user just sets endpoint, key, and model name.
Thinking budgets default to 0 for non-Anthropic providers.

Self-hosting page: removed 30-line env var wall, LLM setup now
points to the template. Merged duplicate verify sections.
Removed api_key from SDK examples (auth off by default).

* docs: reorder next steps, configuration guide first

* fix: default embedding provider to openrouter for single-endpoint setup

Without this, embeddings default to openai which requires a separate
LLM_OPENAI_API_KEY. Setting to openrouter routes embeddings through
the same OpenAI-compatible endpoint as everything else.

* fix: review issues — hermes page, thinking budget, production wording

Hermes integration page: replaced inline Docker/manual setup with
link to self-hosting guide, added elkimek community link. Removed
old env var names (OPENAI_API_KEY without LLM_ prefix).

Troubleshooting: removed "or 1" from thinking budget guidance.
Self-hosting: softened "production-ready" to "production-oriented"
since auth is disabled by default.

* docs: model examples in template, expanded LLM setup, better verify flow

.env.template: added "e.g. google/gemini-2.5-flash" hints next to
model placeholders so users know the expected format.

Self-hosting: expanded LLM Setup to show the 3 things users need to
set (endpoint, key, model name) with find-replace tip. Added build
time note, deriver log check, and real smoke test (create workspace)
to verify section. Health check now notes it doesn't verify DB/LLM.

* fix: smoke test uses v3 API path, not v1

* docs: clarify deriver metrics port vs Prometheus host port

* fix: remove deprecated memoryMode from hermes config example

* docs: update hermes page to match current memory provider config

Updated config to match hermes-agent docs: removed apiKey (not needed
for self-hosted), added hermes memory setup CLI command, added config
fields table (recallMode, writeFrequency, sessionStrategy, etc.).

Better verification tests: store-and-recall across sessions, direct
tool calling test. Links to upstream hermes docs for full field list.

* fix: invalid THINKING_BUDGET_TOKENS=0 and missing docker/ in image

Comment out THINKING_BUDGET_TOKENS=0 in .env.template — deriver,
summary, and dream validators require gt=0. Dialectic levels also
commented out since non-thinking models don't need the override.

Add COPY for docker/ directory in Dockerfile so entrypoint.sh is
available when docker-compose.yml.example references it.

* chore: Additional troubleshooting step

---------

Co-authored-by: Vineeth Voruganti <13438633+VVoruganti@users.noreply.github.com>
This commit is contained in:
Eri Barrett 2026-04-07 22:49:57 -04:00 committed by GitHub
parent 95c72d76d3
commit ff116b0601
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 919 additions and 930 deletions

View File

@ -57,160 +57,135 @@ AUTH_USE_AUTH=false
# AUTH_JWT_SECRET=your-secret-key-here
# =============================================================================
# LLM API Keys (REQUIRED for full functionality)
# LLM Provider (REQUIRED)
# =============================================================================
# OpenAI API key for embeddings
LLM_OPENAI_API_KEY=your-openai-api-key-here
# Anthropic API key for dialectic and deriver functionality
LLM_ANTHROPIC_API_KEY=your-anthropic-api-key-here
# Google API key for summarization (if using Gemini)
# LLM_GEMINI_API_KEY=your-google-api-key-here
# Groq API key for query generation (if using Groq)
# LLM_GROQ_API_KEY=your-groq-api-key-here
# Base URL for OpenAI Compatible Requests if you want to use a different provider
# LLM_OPENAI_COMPATIBLE_BASE_URL=
# LLM_OPENAI_COMPATIBLE_API_KEY=
# Separate vLLM endpoint (for local models)
# LLM_VLLM_API_KEY=
# LLM_VLLM_BASE_URL=
# =============================================================================
# LLM Configuration
# =============================================================================
# Global LLM settings
# Honcho uses LLMs for memory extraction, summarization, dialectic chat, and
# dream consolidation. The server will fail to start without a provider configured.
#
# Quick start: uncomment the two lines below, set your endpoint and API key,
# then uncomment the provider/model lines in each feature section below.
# Any OpenAI-compatible endpoint works (OpenRouter, Together, Fireworks, etc.).
# Models must support tool calling (function calling).
#
LLM_OPENAI_COMPATIBLE_BASE_URL=https://openrouter.ai/api/v1
LLM_OPENAI_COMPATIBLE_API_KEY=your-api-key-here
#
# Provider options for each feature: custom, vllm, google, anthropic, openai, groq
# "custom" routes through the OpenAI-compatible endpoint above.
# Model name format depends on your provider (e.g., OpenRouter: vendor/model-name).
#
# ---- Alternative: vLLM self-hosted ------------------------------------------
# LLM_VLLM_BASE_URL=http://localhost:8000/v1
# LLM_VLLM_API_KEY=not-needed
#
# ---- Alternative: direct vendor keys (no endpoint needed) -------------------
# LLM_GEMINI_API_KEY=
# LLM_ANTHROPIC_API_KEY=
# LLM_OPENAI_API_KEY=
# LLM_GROQ_API_KEY=
#
# ---- General LLM settings ---------------------------------------------------
# Embedding provider — defaults to openai (requires LLM_OPENAI_API_KEY).
# Set to openrouter to route embeddings through your custom endpoint instead.
LLM_EMBEDDING_PROVIDER=openrouter
# LLM_DEFAULT_MAX_TOKENS=2500
# LLM_EMBEDDING_PROVIDER=openai
# LLM_MAX_TOOL_OUTPUT_CHARS=10000 # Max chars for tool output (~2500 tokens)
# LLM_MAX_MESSAGE_CONTENT_CHARS=2000 # Max chars per message in tool results
# LLM_MAX_TOOL_OUTPUT_CHARS=10000
# LLM_MAX_MESSAGE_CONTENT_CHARS=2000
# =============================================================================
# Deriver (Background Worker) Settings
# Deriver (Background Worker)
# =============================================================================
# DERIVER_ENABLED=true
DERIVER_PROVIDER=custom
DERIVER_MODEL=your-model-here # e.g. google/gemini-2.5-flash
# DERIVER_THINKING_BUDGET_TOKENS=1024 # gt=0 required; omit for non-thinking models
# DERIVER_WORKERS=1
# DERIVER_POLLING_SLEEP_INTERVAL_SECONDS=1.0
# DERIVER_STALE_SESSION_TIMEOUT_MINUTES=5
# DERIVER_QUEUE_ERROR_RETENTION_SECONDS=2592000 # 30 days
# DERIVER_PROVIDER=google
# DERIVER_MODEL=gemini-2.5-flash-lite
# DERIVER_QUEUE_ERROR_RETENTION_SECONDS=2592000
# DERIVER_TEMPERATURE=
# DERIVER_DEDUPLICATE=true
# DERIVER_MAX_OUTPUT_TOKENS=4096
# DERIVER_THINKING_BUDGET_TOKENS=1024
# DERIVER_LOG_OBSERVATIONS=false
# DERIVER_MAX_INPUT_TOKENS=23000
# DERIVER_WORKING_REPRESENTATION_MAX_OBSERVATIONS=100
# DERIVER_REPRESENTATION_BATCH_MAX_TOKENS=1024
# DERIVER_FLUSH_ENABLED=false # Bypass batch token threshold, process work immediately
# DERIVER_BACKUP_PROVIDER=
# DERIVER_BACKUP_MODEL=
# DERIVER_FLUSH_ENABLED=false
# =============================================================================
# Peer Card Configuration
# Peer Card
# =============================================================================
# PEER_CARD_ENABLED=true
# =============================================================================
# Dialectic Settings
# Dialectic
# =============================================================================
# Global dialectic settings
# DIALECTIC_MAX_OUTPUT_TOKENS=8192
# DIALECTIC_MAX_INPUT_TOKENS=100000
# DIALECTIC_HISTORY_TOKEN_LIMIT=8192
# DIALECTIC_SESSION_HISTORY_MAX_TOKENS=4096
# Per-level settings (reasoning_level parameter in API)
# Each level can have its own provider, model, thinking budget, tool iterations, and max output tokens
# MAX_OUTPUT_TOKENS is optional per level; if not set, uses global DIALECTIC_MAX_OUTPUT_TOKENS
# Minimal level
# DIALECTIC_LEVELS__minimal__PROVIDER=google
# DIALECTIC_LEVELS__minimal__MODEL=gemini-2.5-flash-lite
#
# Per-level provider, model, and tuning:
DIALECTIC_LEVELS__minimal__PROVIDER=custom
DIALECTIC_LEVELS__minimal__MODEL=your-model-here # e.g. google/gemini-2.5-flash
# DIALECTIC_LEVELS__minimal__THINKING_BUDGET_TOKENS=0
# DIALECTIC_LEVELS__minimal__MAX_TOOL_ITERATIONS=1
# DIALECTIC_LEVELS__minimal__MAX_OUTPUT_TOKENS=250 # Reduced output for cost savings
# Low level
# DIALECTIC_LEVELS__low__PROVIDER=google
# DIALECTIC_LEVELS__low__MODEL=gemini-2.5-flash-lite
# DIALECTIC_LEVELS__minimal__MAX_OUTPUT_TOKENS=250
DIALECTIC_LEVELS__low__PROVIDER=custom
DIALECTIC_LEVELS__low__MODEL=your-model-here
# DIALECTIC_LEVELS__low__THINKING_BUDGET_TOKENS=0
# DIALECTIC_LEVELS__low__MAX_TOOL_ITERATIONS=5
# DIALECTIC_LEVELS__low__MAX_OUTPUT_TOKENS=8192 # Optional: override global default
# Medium level
# DIALECTIC_LEVELS__medium__PROVIDER=anthropic
# DIALECTIC_LEVELS__medium__MODEL=claude-haiku-4-5
# DIALECTIC_LEVELS__medium__THINKING_BUDGET_TOKENS=1024
DIALECTIC_LEVELS__medium__PROVIDER=custom
DIALECTIC_LEVELS__medium__MODEL=your-model-here
# DIALECTIC_LEVELS__medium__THINKING_BUDGET_TOKENS=0
# DIALECTIC_LEVELS__medium__MAX_TOOL_ITERATIONS=2
# DIALECTIC_LEVELS__medium__MAX_OUTPUT_TOKENS=8192 # Optional: override global default
# DIALECTIC_LEVELS__medium__TOOL_CHOICE=
# High level
# DIALECTIC_LEVELS__high__PROVIDER=anthropic
# DIALECTIC_LEVELS__high__MODEL=claude-haiku-4-5
# DIALECTIC_LEVELS__high__THINKING_BUDGET_TOKENS=1024
DIALECTIC_LEVELS__high__PROVIDER=custom
DIALECTIC_LEVELS__high__MODEL=your-model-here
# DIALECTIC_LEVELS__high__THINKING_BUDGET_TOKENS=0
# DIALECTIC_LEVELS__high__MAX_TOOL_ITERATIONS=4
# DIALECTIC_LEVELS__high__MAX_OUTPUT_TOKENS=8192 # Optional: override global default
# Max level
# DIALECTIC_LEVELS__max__PROVIDER=anthropic
# DIALECTIC_LEVELS__max__MODEL=claude-haiku-4-5
# DIALECTIC_LEVELS__max__THINKING_BUDGET_TOKENS=2048
DIALECTIC_LEVELS__max__PROVIDER=custom
DIALECTIC_LEVELS__max__MODEL=your-model-here
# DIALECTIC_LEVELS__max__THINKING_BUDGET_TOKENS=0
# DIALECTIC_LEVELS__max__MAX_TOOL_ITERATIONS=10
# DIALECTIC_LEVELS__max__MAX_OUTPUT_TOKENS=8192 # Optional: override global default
# Optional backup per level (must set both or neither):
# DIALECTIC_LEVELS__max__BACKUP_PROVIDER=google
# DIALECTIC_LEVELS__max__BACKUP_MODEL=gemini-2.5-pro
# =============================================================================
# Summary Settings
# Summary
# =============================================================================
# SUMMARY_ENABLED=true
SUMMARY_PROVIDER=custom
SUMMARY_MODEL=your-model-here # e.g. google/gemini-2.5-flash
# SUMMARY_THINKING_BUDGET_TOKENS=512 # gt=0 required; omit for non-thinking models
# SUMMARY_MESSAGES_PER_SHORT_SUMMARY=20
# SUMMARY_MESSAGES_PER_LONG_SUMMARY=60
# SUMMARY_PROVIDER=google
# SUMMARY_MODEL=gemini-2.5-flash
# SUMMARY_MAX_TOKENS_SHORT=1000
# SUMMARY_MAX_TOKENS_LONG=4000
# SUMMARY_THINKING_BUDGET_TOKENS=512
# SUMMARY_BACKUP_PROVIDER=
# SUMMARY_BACKUP_MODEL=
# =============================================================================
# Dream Settings
# Dream
# =============================================================================
# DREAM_ENABLED=true
DREAM_PROVIDER=custom
DREAM_MODEL=your-model-here # e.g. google/gemini-2.5-flash
DREAM_DEDUCTION_MODEL=your-model-here
DREAM_INDUCTION_MODEL=your-model-here
# DREAM_THINKING_BUDGET_TOKENS=8192 # gt=0 required; omit for non-thinking models
# DREAM_DOCUMENT_THRESHOLD=50
# DREAM_IDLE_TIMEOUT_MINUTES=60
# DREAM_MIN_HOURS_BETWEEN_DREAMS=8
# DREAM_ENABLED_TYPES=["omni"]
# DREAM_PROVIDER=anthropic
# DREAM_MODEL=claude-sonnet-4-20250514
# DREAM_MAX_OUTPUT_TOKENS=16384
# DREAM_THINKING_BUDGET_TOKENS=8192
# DREAM_MAX_TOOL_ITERATIONS=20
# DREAM_HISTORY_TOKEN_LIMIT=16384
# DREAM_BACKUP_PROVIDER=
# DREAM_BACKUP_MODEL=
# Specialist models (use same provider as main model)
# DREAM_DEDUCTION_MODEL=claude-haiku-4-5
# DREAM_INDUCTION_MODEL=claude-haiku-4-5
# Dream Surprisal Settings (Tree-based observation sampling for targeted reasoning)
#
# Surprisal sampling (advanced):
# DREAM_SURPRISAL__ENABLED=false
# DREAM_SURPRISAL__TREE_TYPE=kdtree # Options: kdtree, balltree, rptree, covertree, lsh, graph, prototype
# DREAM_SURPRISAL__TREE_K=5 # Number of neighbors for kNN-based trees
# DREAM_SURPRISAL__SAMPLING_STRATEGY=recent # Options: recent, random, all
# DREAM_SURPRISAL__SAMPLE_SIZE=200 # Number of observations to sample for tree building
# DREAM_SURPRISAL__TOP_PERCENT_SURPRISAL=0.10 # Top percentage of observations (0.10 = top 10%)
# DREAM_SURPRISAL__MIN_HIGH_SURPRISAL_FOR_REPLACE=10 # Hybrid mode: min observations to replace standard questions
# DREAM_SURPRISAL__INCLUDE_LEVELS=["explicit","deductive"] # Observation levels to include
# DREAM_SURPRISAL__TREE_TYPE=kdtree
# DREAM_SURPRISAL__TREE_K=5
# DREAM_SURPRISAL__SAMPLING_STRATEGY=recent
# DREAM_SURPRISAL__SAMPLE_SIZE=200
# DREAM_SURPRISAL__TOP_PERCENT_SURPRISAL=0.10
# DREAM_SURPRISAL__MIN_HIGH_SURPRISAL_FOR_REPLACE=10
# DREAM_SURPRISAL__INCLUDE_LEVELS=["explicit","deductive"]
# =============================================================================
# Webhook Settings

View File

@ -106,7 +106,7 @@ git commit -m "docs(readme): update installation instructions"
### Python Code Style
- Follow [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guidelines
- Use [Black](https://black.readthedocs.io/) for code formatting (we may add this to CI in the future)
- Use [ruff](https://docs.astral.sh/ruff/) for linting and code formatting
- Use type hints where possible
- Write docstrings for functions and classes using Google style docstrings

View File

@ -41,6 +41,7 @@ RUN addgroup --system app && adduser --system --group app && mkdir -p /tmp/uv-ca
COPY --chown=app:app src/ /app/src/
COPY --chown=app:app migrations/ /app/migrations/
COPY --chown=app:app scripts/ /app/scripts/
COPY --chown=app:app docker/ /app/docker/
COPY --chown=app:app alembic.ini /app/alembic.ini
# Copy config files - this will copy config.toml if it exists, and config.toml.example
COPY --chown=app:app config.toml* /app/
@ -51,6 +52,6 @@ USER app
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/openapi.json')" || exit 1
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
CMD ["fastapi", "run", "--host", "0.0.0.0", "src/main.py"]

View File

@ -162,8 +162,8 @@ Server.
Honcho is developed using [python](https://www.python.org/) and [uv](https://docs.astral.sh/uv/).
The minimum python version is `3.9`
The minimum uv version is `0.4.9`
The minimum python version is `3.10`
The minimum uv version is `0.5.0`
### Setup
@ -221,11 +221,11 @@ Below are the required configurations:
```env
DB_CONNECTION_URI= # Connection uri for a postgres database (with postgresql+psycopg prefix)
# LLM Provider API Keys (at least one required depending on your configuration)
LLM_ANTHROPIC_API_KEY= # API Key for Anthropic (used for dialectic by default)
LLM_OPENAI_API_KEY= # API Key for OpenAI (optional, for embeddings if EMBED_MESSAGES=true)
LLM_GEMINI_API_KEY= # API Key for Google Gemini (used for summary/deriver by default)
LLM_GROQ_API_KEY= # API Key for Groq (used for query generation by default)
# LLM Provider API Keys
LLM_GEMINI_API_KEY= # API Key for Google Gemini (used for deriver, summary, and dialectic minimal/low by default)
LLM_ANTHROPIC_API_KEY= # API Key for Anthropic (used for dialectic medium/high/max and dream by default)
LLM_OPENAI_API_KEY= # API Key for OpenAI (used for embeddings when EMBED_MESSAGES=true)
LLM_GROQ_API_KEY= # API Key for Groq (optional)
```
> Note that the `DB_CONNECTION_URI` must have the prefix `postgresql+psycopg` to
@ -455,14 +455,14 @@ If you have this in `config.toml`:
```toml
[db]
CONNECTION_URI = "postgresql://localhost/honcho_dev"
CONNECTION_URI = "postgresql+psycopg://localhost/honcho_dev"
POOL_SIZE = 10
```
You can override just the connection URI in production:
```bash
export DB_CONNECTION_URI="postgresql://prod-server/honcho_prod"
export DB_CONNECTION_URI="postgresql+psycopg://prod-server/honcho_prod"
```
The application will use the production connection URI while keeping the pool size from config.toml.

View File

@ -55,17 +55,21 @@ EMBEDDING_PROVIDER = "openai"
MAX_TOOL_OUTPUT_CHARS = 10000 # Max chars for tool output (~2500 tokens)
MAX_MESSAGE_CONTENT_CHARS = 2000 # Max chars per message in tool results
# API Keys for LLM providers
# ANTHROPIC_API_KEY = "your-api-key"
# OPENAI_API_KEY = "your-api-key"
# OPENAI_COMPATIBLE_API_KEY = "your-api-key"
# GEMINI_API_KEY = "your-api-key"
# GROQ_API_KEY = "your-api-key"
# OPENAI_COMPATIBLE_BASE_URL = "your-base-url"
# API Keys for LLM providers (set the ones you need)
# GEMINI_API_KEY = "your-api-key" # Default: deriver, summary, dialectic minimal/low
# ANTHROPIC_API_KEY = "your-api-key" # Default: dialectic medium/high/max, dream
# OPENAI_API_KEY = "your-api-key" # Default: embeddings
# GROQ_API_KEY = "your-api-key" # Not used by default
# Separate vLLM endpoint (for local models)
# VLLM_API_KEY = "your-api-key"
# VLLM_BASE_URL = "your-base-url"
# OpenAI-compatible endpoint (OpenRouter, Together, Fireworks, LiteLLM, etc.)
# Set provider to "custom" in feature config to route calls through this endpoint.
# OPENAI_COMPATIBLE_BASE_URL = "https://openrouter.ai/api/v1"
# OPENAI_COMPATIBLE_API_KEY = "your-api-key"
# vLLM endpoint (for self-hosted models)
# Set provider to "vllm" in feature config to route calls through this endpoint.
# VLLM_BASE_URL = "http://localhost:8000/v1"
# VLLM_API_KEY = "not-needed"
# Deriver settings
[deriver]

View File

@ -1,6 +1,15 @@
# Honcho Docker Compose
#
# Usage:
# cp docker-compose.yml.example docker-compose.yml
# cp .env.template .env # edit with your provider config
# docker compose up -d --build
#
# By default, ports are bound to 127.0.0.1 (localhost only).
# For development, uncomment the source mounts and monitoring services below.
services:
api:
image: honcho:latest
build:
context: .
dockerfile: Dockerfile
@ -11,16 +20,20 @@ services:
redis:
condition: service_healthy
ports:
- 8000:8000
volumes:
- .:/app
- venv:/app/.venv
- "127.0.0.1:8000:8000"
# -- Development: mount source for live reload --
# volumes:
# - .:/app
# - venv:/app/.venv
environment:
- DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@database:5432/postgres
- CACHE_URL=redis://redis:6379/0?suppress=true
- CACHE_ENABLED=true
env_file:
- path: .env
required: false
restart: unless-stopped
deriver:
build:
context: .
@ -31,27 +44,29 @@ services:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- .:/app
- venv:/app/.venv
# -- Development: mount source for live reload --
# volumes:
# - .:/app
# - venv:/app/.venv
environment:
- DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@database:5432/postgres
- CACHE_URL=redis://redis:6379/0?suppress=true
- METRICS_ENABLED=true
- CACHE_ENABLED=true
env_file:
- path: .env
required: false
restart: unless-stopped
database:
image: pgvector/pgvector:pg15
restart: always
restart: unless-stopped
ports:
- 5432:5432
command: ["postgres", "-c", "max_connections=800"]
- "127.0.0.1:5432:5432"
command: ["postgres", "-c", "max_connections=200"]
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_HOST_AUTH_METHOD=trust
- PGDATA=/var/lib/postgresql/data/pgdata
volumes:
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
@ -61,44 +76,49 @@ services:
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:8.2
restart: always
restart: unless-stopped
ports:
- 6379:6379
- "127.0.0.1:6379:6379"
volumes:
- ./redis-data:/data
- redis-data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli ping"]
interval: 5s
timeout: 5s
retries: 5
prometheus:
image: prom/prometheus:v3.2.1
ports:
- 9090:9090
volumes:
- ./docker/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
depends_on:
api:
condition: service_started
grafana:
image: grafana/grafana:11.4.0
ports:
- 3000:3000
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
volumes:
- ./grafana-data:/var/lib/grafana
- ./docker/grafana-datasource.yml:/etc/grafana/provisioning/datasources/datasource.yml:ro
depends_on:
prometheus:
condition: service_started
# -- Development: monitoring stack (uncomment to enable) --
# prometheus:
# image: prom/prometheus:v3.2.1
# ports:
# - "127.0.0.1:9090:9090"
# volumes:
# - ./docker/prometheus.yml:/etc/prometheus/prometheus.yml:ro
# - prometheus-data:/prometheus
# depends_on:
# api:
# condition: service_started
# grafana:
# image: grafana/grafana:11.4.0
# ports:
# - "127.0.0.1:3000:3000"
# environment:
# - GF_SECURITY_ADMIN_USER=admin
# - GF_SECURITY_ADMIN_PASSWORD=admin
# - GF_AUTH_ANONYMOUS_ENABLED=true
# - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
# volumes:
# - ./docker/grafana-datasource.yml:/etc/grafana/provisioning/datasources/datasource.yml:ro
# depends_on:
# prometheus:
# condition: service_started
volumes:
pgdata:
venv:
prometheus-data:
redis-data:
# -- Development: uncomment if using source mounts --
# venv:
# prometheus-data:

View File

@ -143,7 +143,8 @@
"group": "Self-Hosting",
"pages": [
"v3/contributing/self-hosting",
"v3/contributing/configuration"
"v3/contributing/configuration",
"v3/contributing/troubleshooting"
]
},
{

View File

@ -96,14 +96,14 @@ If you have this in `config.toml`:
```toml
[db]
CONNECTION_URI = "postgresql://localhost/honcho_dev"
CONNECTION_URI = "postgresql+psycopg://localhost/honcho_dev"
POOL_SIZE = 10
```
You can override just the connection URI in production:
```bash
export DB_CONNECTION_URI="postgresql://prod-server/honcho_prod"
export DB_CONNECTION_URI="postgresql+psycopg://prod-server/honcho_prod"
```
The application will use the production connection URI while keeping the pool size from config.toml.
@ -149,7 +149,7 @@ LOCAL_METRICS_FILE=metrics.jsonl
DB_CONNECTION_URI=postgresql+psycopg://username:password@host:port/database
# Example for local development
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@localhost:5432/honcho
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@localhost:5432/postgres
# Example for production
DB_CONNECTION_URI=postgresql+psycopg://honcho_user:secure_password@db.example.com:5432/honcho_prod

View File

@ -135,24 +135,21 @@ Download from [postgresql.org](https://www.postgresql.org/download/windows/)
```bash
docker run --name honcho-db \
-e POSTGRES_DB=honcho \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
-d pgvector/pgvector:pg15
```
### 3. Create Database and Enable Extensions
### 3. Enable Extensions
Connect to PostgreSQL and set up the database:
Connect to PostgreSQL and enable pgvector:
```bash
# Connect to PostgreSQL
psql -U postgres
# Create database and enable extensions
CREATE DATABASE honcho;
\c honcho
# Enable extensions on the default database
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
\q
@ -170,7 +167,7 @@ Edit `.env` with your configuration:
```bash
# Database connection
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@localhost:5432/honcho
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@localhost:5432/postgres
# Optional API keys (required for LLM features)
OPENAI_API_KEY=your-openai-api-key

File diff suppressed because it is too large Load Diff

View File

@ -20,9 +20,9 @@ By the end of this guide, you'll have:
Before you begin, ensure you have the following installed:
### Required Software
- **uv** - Python package manager: `pip install uv` (manages Python installations automatically)
- **uv** - Python package manager: `curl -LsSf https://astral.sh/uv/install.sh | sh` or `brew install uv`
- **Git** - [Download from git-scm.com](https://git-scm.com/downloads)
- **Docker** (optional) - [Download from docker.com](https://www.docker.com/products/docker-desktop/)
- **Docker** (required for Docker setup, not needed for manual setup) - [Download from docker.com](https://www.docker.com/products/docker-desktop/)
### Database Options
You'll need a PostgreSQL database with the pgvector extension. Choose one:
@ -32,9 +32,48 @@ You'll need a PostgreSQL database with the pgvector extension. Choose one:
- **Railway** - Simple cloud PostgreSQL hosting
- **Your own PostgreSQL server**
## LLM Setup
Honcho uses LLMs for memory extraction, summarization, dialectic chat, and dreaming. The server will **fail to start** without a provider configured.
You need one API key and one model. Any OpenAI-compatible endpoint works — OpenRouter, Together, Fireworks, Ollama, vLLM, or a direct vendor API. Models must support tool calling (function calling).
The `.env.template` has provider and model lines ready for each feature. After copying it to `.env`, you need to set three things:
```bash
# 1. Your endpoint and API key (already uncommented in the template)
LLM_OPENAI_COMPATIBLE_BASE_URL=https://openrouter.ai/api/v1
LLM_OPENAI_COMPATIBLE_API_KEY=sk-or-v1-...
# 2. Replace "your-model-here" everywhere with your model
# (these are spread across the Deriver, Dialectic, Summary, and Dream sections)
DERIVER_MODEL=google/gemini-2.5-flash # e.g. google/gemini-2.5-flash
SUMMARY_MODEL=google/gemini-2.5-flash
DREAM_MODEL=google/gemini-2.5-flash
DIALECTIC_LEVELS__minimal__MODEL=google/gemini-2.5-flash
# ... same for low, medium, high, max
# 3. Everything else is already configured:
# - PROVIDER=custom for all features (routes through your endpoint)
# - THINKING_BUDGET_TOKENS=0 (correct for non-Anthropic models)
# - LLM_EMBEDDING_PROVIDER=openrouter (uses same endpoint for embeddings)
```
Use find-and-replace to swap all `your-model-here` with your chosen model in one step.
<Info>
For recommended model tiers per feature, using multiple providers, or direct vendor API keys, see the [Configuration Guide](./configuration#llm-configuration).
</Info>
<Info>
**Community quick-start**: [elkimek/honcho-self-hosted](https://github.com/elkimek/honcho-self-hosted) provides a one-command installer with pre-configured model tiers, interactive provider setup, and Hermes Agent integration.
</Info>
## Docker Setup (Recommended)
The easiest way to get started is using Docker Compose, which handles both the database and Honcho server.
Docker Compose handles the database, Redis, and Honcho server. The compose file **builds the image from source** (there is no pre-built image on Docker Hub). This requires Docker with BuildKit enabled — see [Troubleshooting](./troubleshooting#docker-build-fails-with-permission-errors) if the build fails.
The compose file is production-oriented by default (ports bound to `127.0.0.1`, restart policies, caching enabled). For development, uncomment the source mounts and monitoring services inside the file.
### 1. Clone the Repository
@ -51,45 +90,37 @@ Copy the example environment file and configure it:
cp .env.template .env
```
Edit `.env` and set your API keys (if using LLM features):
```bash
# Optional API keys (required for LLM features)
OPENAI_API_KEY=your-openai-api-key
ANTHROPIC_API_KEY=your-anthropic-api-key
# Database will be created automatically by Docker
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@database:5432/postgres
# Disable auth for local development
AUTH_USE_AUTH=false
```
Edit `.env` and configure your LLM provider — see [LLM Setup](#llm-setup) above. The database connection is set in the compose file. Auth is disabled by default (`AUTH_USE_AUTH=false`).
### 3. Start the Services
```bash
# Copy the example docker-compose file
cp docker-compose.yml.example docker-compose.yml
# Start PostgreSQL and Honcho
docker compose up -d
docker compose up -d --build
```
### 4. Verify It's Working
The first build takes a few minutes (compiling from source). Subsequent starts are fast.
Check that both services are running:
This starts four services: **api** (port 8000), **deriver** (background worker), **database** (PostgreSQL with pgvector, port 5432), and **redis** (port 6379). All ports are bound to `127.0.0.1`. Redis caching is enabled by default.
For development, uncomment the source mount and monitoring sections inside `docker-compose.yml` to enable live reload, Prometheus, and Grafana.
### 4. Verify
Migrations run automatically on startup.
```bash
# Check all containers are running
docker compose ps
```
Test the Honcho API:
```bash
# Health check (confirms the process is up)
curl http://localhost:8000/health
# Check the deriver is processing (look for "polling" or "processing" in logs)
docker compose logs deriver --tail 20
```
You should see a response indicating the service is healthy.
For a full end-to-end test, see [Verify Your Setup](#verify-your-setup) below.
## Manual Setup
@ -134,26 +165,22 @@ Download from [postgresql.org](https://www.postgresql.org/download/windows/)
```bash
docker run --name honcho-db \
-e POSTGRES_DB=honcho \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
-d pgvector/pgvector:pg15
```
### 3. Create Database and Enable Extensions
### 3. Enable Extensions
Connect to PostgreSQL and set up the database:
Connect to PostgreSQL and enable pgvector:
```bash
# Connect to PostgreSQL
psql -U postgres
# Create database and enable extensions
CREATE DATABASE honcho;
\c honcho
# Enable the pgvector extension on the default database
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
\q
```
@ -165,17 +192,10 @@ Create a `.env` file with your settings:
cp .env.template .env
```
Edit `.env` with your configuration:
Edit `.env` — configure your LLM provider (see [LLM Setup](#llm-setup) above) and set the database connection:
```bash
# Database connection
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@localhost:5432/honcho
# Optional API keys (required for LLM features)
OPENAI_API_KEY=your-openai-api-key
ANTHROPIC_API_KEY=your-anthropic-api-key
# Development settings
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@localhost:5432/postgres
AUTH_USE_AUTH=false
LOG_LEVEL=DEBUG
```
@ -191,11 +211,21 @@ uv run alembic upgrade head
```bash
# Start the development server
fastapi dev src/main.py
uv run fastapi dev src/main.py
```
The server will be available at `http://localhost:8000`.
### 7. Start the Background Worker (Deriver)
In a **separate terminal**, start the deriver background worker:
```bash
uv run python -m src.deriver
```
The deriver is essential for Honcho's core functionality. It processes incoming messages to extract observations, build peer representations, generate session summaries, and run dream consolidation. Without it, messages will be stored but no memory or reasoning will occur.
## Cloud Database Setup
If you prefer to use a managed PostgreSQL service:
@ -206,7 +236,6 @@ If you prefer to use a managed PostgreSQL service:
2. **Enable pgvector extension** in the SQL editor:
```sql
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
```
3. **Get your connection string** from Settings > Database
4. **Update your `.env` file** with the connection string
@ -227,23 +256,38 @@ Once your Honcho server is running, verify everything is working:
```bash
curl http://localhost:8000/health
# {"status":"ok"}
```
### 2. API Documentation
Note: `/health` only confirms the process is running. It does not check database or LLM connectivity.
### 2. Smoke Test (database + API)
This confirms the database connection, migrations, and API are all working:
```bash
# Create a workspace
curl -s -X POST http://localhost:8000/v3/workspaces \
-H "Content-Type: application/json" \
-d '{"name": "test"}' | python3 -m json.tool
```
If you get back a workspace object with an `id`, your database is connected and migrations ran correctly.
### 3. API Documentation
Visit `http://localhost:8000/docs` to see the interactive API documentation.
### 3. Test with SDK
Create a simple test script:
### 4. Test with SDK
```python
from honcho import Honcho
# Connect to your local instance
client = Honcho(base_url="http://localhost:8000")
client = Honcho(
base_url="http://localhost:8000",
workspace_id="test"
)
# Create a test peer
peer = client.peer("test-user")
print(f"Created peer: {peer.id}")
```
@ -259,8 +303,7 @@ Now that Honcho is running locally, you can connect your applications:
from honcho import Honcho
client = Honcho(
base_url="http://localhost:8000", # Your local instance
api_key="your-api-key" # If auth is enabled
base_url="http://localhost:8000",
)
```
@ -269,56 +312,93 @@ client = Honcho(
import { Honcho } from '@honcho-ai/sdk';
const client = new Honcho({
baseUrl: 'http://localhost:8000', // Your local instance
apiKey: 'your-api-key' // If auth is enabled
baseUrl: 'http://localhost:8000',
});
```
### Next Steps
- **Configure Honcho**: Visit the [Configuration Guide](./configuration) for model tiers, provider options, and tuning
- **Explore the API**: Check out the [API Reference](../api-reference/introduction)
- **Try the SDKs**: See our [guides](../guides) for examples
- **Configure Honcho**: Visit the [Configuration Guide](./configuration) for detailed settings
- **Join the community**: [Discord](https://discord.gg/honcho)
## Troubleshooting
### Common Issues
Running into issues? See the [Troubleshooting Guide](./troubleshooting) for detailed solutions to common problems including:
**Database Connection Errors**
- Ensure PostgreSQL is running
- Verify the connection string format: `postgresql+psycopg://...`
- Check that pgvector extension is installed
- Startup failures (missing API keys, database issues)
- Runtime errors ("An unexpected error occurred" on every request)
- Deriver not processing messages
- Database connection and migration issues
- Docker and Redis problems
**API Key Issues**
- Verify your OpenAI and Anthropic API keys are valid
- Check that the keys have sufficient credits/quota
**Port Already in Use**
- Pass a different port to FastAPI or stop other services using port 8000
**Docker Issues**
- Ensure Docker is running
- Check container logs: `docker compose logs`
- Restart containers: `docker compose down && docker compose up -d`
**Migration Errors**
- Ensure the database exists and pgvector is enabled
- Check database permissions
- Run migrations manually: `uv run alembic upgrade head`
### Getting Help
- **GitHub Issues**: [Report bugs](https://github.com/plastic-labs/honcho/issues)
- **Discord**: [Join our community](https://discord.gg/honcho)
- **Documentation**: Check the [Configuration Guide](./configuration) for detailed settings
**Quick checks:**
- Verify the server is running: `curl http://localhost:8000/health`
- Check logs: `docker compose logs api` (Docker) or check terminal output (manual setup)
- Ensure migrations ran: `uv run alembic upgrade head`
## Production Considerations
When self-hosting for production, consider:
The default compose file is already production-oriented — ports bound to `127.0.0.1`, restart policies, caching enabled.
- **Security**: Enable authentication, use HTTPS, secure your database
- **Scaling**: Use connection pooling, consider load balancing
- **Monitoring**: Set up logging, error tracking, health checks
- **Backups**: Regular database backups, disaster recovery plan
- **Updates**: Keep Honcho and dependencies updated
### Security
- Set `AUTH_USE_AUTH=true` and generate a JWT secret with `python scripts/generate_jwt_secret.py`
- Use HTTPS via a reverse proxy in front of Honcho. Example with Caddy (automatic TLS):
```
honcho.example.com {
reverse_proxy localhost:8000
}
```
Or with nginx:
```nginx
server {
listen 443 ssl;
server_name honcho.example.com;
ssl_certificate /etc/letsencrypt/live/honcho.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/honcho.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
- Secure your database with strong credentials and restrict network access
- The production compose binds PostgreSQL and Redis to `127.0.0.1` only — they are not accessible from the network
### Scaling the Deriver
- Increase `DERIVER_WORKERS` (default: 1) for higher message throughput
- You can also run multiple deriver processes across machines — they coordinate via the database queue
- Monitor deriver logs for processing backlog
### Caching
- The production compose enables Redis caching by default (`CACHE_ENABLED=true`)
- For the development compose, enable manually: `CACHE_ENABLED=true`
- Configure `CACHE_URL` to point to your Redis instance (or use a managed Redis service)
### Database Migrations
- Always run `uv run alembic upgrade head` after updating Honcho before starting the server
- Check current migration status with `uv run alembic current`
### LLM Providers
- Ensure your API keys are configured (see [LLM Setup](#llm-setup))
- For alternative providers or per-feature model overrides, see the [Configuration Guide](./configuration#llm-configuration)
### Monitoring
- Enable Prometheus metrics with `METRICS_ENABLED=true`. The API exposes `/metrics` on port 8000, the deriver on port 9090 (internal to its container — not published to the host by default).
- Enable Sentry error tracking with `SENTRY_ENABLED=true`
- The development compose includes Prometheus (host port 9090) and Grafana (host port 3000) for scraping and dashboards. Uncomment those services to enable them.
### Backups
- Set up regular PostgreSQL backups:
```bash
# One-off backup
docker compose exec database pg_dump -U postgres postgres > backup-$(date +%Y%m%d).sql
# Restore
cat backup.sql | docker compose exec -T database psql -U postgres postgres
```
- Back up your `.env` or `config.toml` configuration files

View File

@ -0,0 +1,299 @@
---
title: 'Troubleshooting'
sidebarTitle: 'Troubleshooting'
description: 'Common issues and solutions when self-hosting Honcho'
icon: 'wrench'
---
This page covers common issues you may encounter when self-hosting Honcho, what causes them, and how to fix them.
## Startup Failures
### Server won't start: "Missing client for ..."
```
ValueError: Missing client for Deriver: google
```
**Cause:** The server validates at startup that all configured LLM providers have API keys. If a provider is referenced in your configuration but the corresponding API key isn't set, the server refuses to start.
**Fix:** Set the API keys for your configured providers. With default configuration, you need:
```bash
LLM_GEMINI_API_KEY=... # Used by deriver, summary, dialectic minimal/low
LLM_ANTHROPIC_API_KEY=... # Used by dialectic medium/high/max, dream
LLM_OPENAI_API_KEY=... # Used by embeddings (when EMBED_MESSAGES=true)
```
See the [LLM Setup](/v3/contributing/self-hosting#llm-setup) section for provider configuration. You can change which providers are used in your `.env` or `config.toml` (see [Configuration Guide](./configuration#llm-configuration)).
### Server won't start: "JWT_SECRET must be set"
```
ValueError: JWT_SECRET must be set if USE_AUTH is true
```
**Cause:** You enabled authentication (`AUTH_USE_AUTH=true`) but didn't provide a JWT secret.
**Fix:** Generate a secret and set it:
```bash
python scripts/generate_jwt_secret.py
# Then set the output as:
AUTH_JWT_SECRET=<generated_secret>
```
Or disable authentication for local development: `AUTH_USE_AUTH=false`
## Runtime Errors
### API returns "An unexpected error occurred" on every request
**Cause:** This is almost always a database issue. The health endpoint (`/health`) will return `{"status": "ok"}` even when the database is unreachable because it doesn't check the database connection. The actual error appears in the server logs.
**Common causes and fixes:**
1. **Database is unreachable** — Check that PostgreSQL is running and the `DB_CONNECTION_URI` is correct
2. **Migrations haven't been run** — The server starts successfully without tables, but every API call will fail. Run:
```bash
uv run alembic upgrade head
```
In Docker:
```bash
docker compose exec api uv run alembic upgrade head
```
3. **pgvector extension not installed** — The `vector` extension must be enabled in your database:
```sql
CREATE EXTENSION IF NOT EXISTS vector;
```
**How to diagnose:** Check the server logs for the actual error. Look for:
- `sqlalchemy.exc.OperationalError` — database connection issue
- `sqlalchemy.exc.ProgrammingError` with "relation does not exist" — migrations not run
- `psycopg.OperationalError` — connection refused or authentication failed
### Health check passes but API calls fail
The `/health` endpoint is a lightweight check that confirms the server process is running. It does **not** verify:
- Database connectivity
- That migrations have been run
- That LLM providers are reachable
To verify full functionality, try creating a workspace:
```bash
curl -X POST http://localhost:8000/v3/workspaces \
-H "Content-Type: application/json" \
-d '{"name": "test"}'
```
If this succeeds, your database connection and migrations are working.
### Deriver not processing messages
Messages are stored but no observations, summaries, or representations are being generated.
**Common causes:**
1. **Deriver isn't running** — In manual setup, the deriver is a separate process:
```bash
uv run python -m src.deriver
```
In Docker, it starts automatically via `docker compose up`.
2. **Deriver can't reach the database** — Check deriver logs for connection errors. The deriver uses the same `DB_CONNECTION_URI` as the API server.
3. **Missing LLM API key for deriver provider** — By default the deriver uses Google Gemini (`LLM_GEMINI_API_KEY`). Check deriver logs for API errors.
4. **Processing backlog** — With `DERIVER_WORKERS=1` (default), high message volume can cause a backlog. Increase workers:
```bash
DERIVER_WORKERS=4
```
5. **Representation Batch Max** — By default the deriver is set to buffer its operations until there are enough tokens for a given representation in a session. This is set via the `REPRESENTATION_BATCH_MAX_TOKENS` environment variable. If you aren't seeing tasks continue it may be that the batch size is set too high or enough data hasn't flowed into to the session yet. See [token batching](/v3/documentation/core-concepts/reasoning#token-batching) for more details
## Alternative Provider Issues
### OpenRouter / custom provider not working
If you set `PROVIDER=custom` but calls fail:
1. **Verify the endpoint and key are set:**
```bash
LLM_OPENAI_COMPATIBLE_BASE_URL=https://openrouter.ai/api/v1
LLM_OPENAI_COMPATIBLE_API_KEY=sk-or-v1-...
```
2. **Check model names match the provider's format.** OpenRouter uses `vendor/model` format (e.g., `anthropic/claude-haiku-4-5`), not the raw model ID.
3. **Ensure your model supports tool calling.** The deriver, dialectic, and dream agents require tool use. Check the provider's model page for tool calling support.
4. **Check server logs for the actual error.** API errors from the upstream provider will appear in Honcho's logs with the HTTP status code and message body.
### vLLM / Ollama not responding
1. **Verify the model server is running** and accessible from the Honcho process (or container):
```bash
curl http://localhost:8000/v1/models # vLLM
curl http://localhost:11434/v1/models # Ollama
```
2. **In Docker**, `localhost` inside a container doesn't reach the host. Use `host.docker.internal` (macOS/Windows) or the host's network IP:
```bash
LLM_VLLM_BASE_URL=http://host.docker.internal:8000/v1
```
3. **Structured output failures** — vLLM's structured output support is limited to certain response formats. If you see JSON parsing errors, check the deriver/dream logs for the raw response.
### Thinking budget errors with non-Anthropic providers
If you see errors like `thinking budget not supported`, `invalid parameter`, or silent failures where agents produce no output, your `THINKING_BUDGET_TOKENS` is likely set to a value > 0 with a provider that doesn't support Anthropic-style extended thinking.
**Fix:** Set `THINKING_BUDGET_TOKENS=0` for every component when using non-Anthropic providers:
```bash
DERIVER_THINKING_BUDGET_TOKENS=0
SUMMARY_THINKING_BUDGET_TOKENS=0
DREAM_THINKING_BUDGET_TOKENS=0
DIALECTIC_LEVELS__minimal__THINKING_BUDGET_TOKENS=0
DIALECTIC_LEVELS__low__THINKING_BUDGET_TOKENS=0
DIALECTIC_LEVELS__medium__THINKING_BUDGET_TOKENS=0
DIALECTIC_LEVELS__high__THINKING_BUDGET_TOKENS=0
DIALECTIC_LEVELS__max__THINKING_BUDGET_TOKENS=0
```
This applies to OpenRouter (with non-Anthropic models), vLLM, Ollama, Groq, Google, and OpenAI providers. Only Anthropic models support the thinking budget parameter.
## Database Issues
### Connection string format
The connection URI **must** use the `postgresql+psycopg` prefix:
```bash
# Correct
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@localhost:5432/postgres
# Wrong - will fail
DB_CONNECTION_URI=postgresql://postgres:postgres@localhost:5432/postgres
DB_CONNECTION_URI=postgres://postgres:postgres@localhost:5432/postgres
```
### Checking migration status
```bash
# See current migration version
uv run alembic current
# See migration history
uv run alembic history
# Upgrade to latest
uv run alembic upgrade head
```
## Cache & Redis
### Redis is optional
Redis is used for caching when `CACHE_ENABLED=true` (default: `false`). If Redis is unreachable, Honcho **gracefully falls back to in-memory caching** and logs a warning. This means:
- The server and deriver will still start and function normally
- Performance may be reduced under high load without Redis
- You do not need Redis for local development or testing
### Redis connection issues
If you see Redis connection warnings in logs but `CACHE_ENABLED=false`, they can be safely ignored. If you want caching:
```bash
# Start Redis via Docker
docker run -d -p 6379:6379 redis:latest
# Configure Honcho
CACHE_ENABLED=true
CACHE_URL=redis://localhost:6379/0
```
## Docker Issues
### Docker build fails with permission errors
The Honcho Dockerfile uses BuildKit mount syntax and creates a non-root `app` user. Common build failures:
**1. BuildKit not enabled**
The Dockerfile uses `RUN --mount=type=cache` which requires Docker BuildKit. If you see syntax errors during build:
```bash
# Ensure BuildKit is enabled
DOCKER_BUILDKIT=1 docker compose build
```
Or add to your Docker daemon config (`/etc/docker/daemon.json`):
```json
{ "features": { "buildkit": true } }
```
**2. Permission denied during build or at runtime (Linux)**
On Linux, AppArmor or SELinux can block Docker build operations and volume mounts. Symptoms include permission denied errors during `COPY`, `RUN`, or when the container tries to access mounted volumes.
```bash
# Check if AppArmor is blocking Docker
sudo aa-status | grep docker
# Temporarily test without AppArmor (for diagnosis only)
docker compose down
sudo aa-remove-unknown
docker compose up -d
```
For SELinux, add `:z` to volume mounts in `docker-compose.yml`:
```yaml
volumes:
- .:/app:z
```
**3. Volume mount UID mismatch**
The Dockerfile creates a non-root `app` user, but `docker-compose.yml.example` mounts `.:/app` which overlays the container filesystem with host-owned files. The `app` user inside the container may not have permission to read them.
If you see permission errors at runtime (not build time), you can either:
- Run without the source mount (remove `- .:/app` from volumes — the image already contains the code)
- Or fix ownership: `sudo chown -R 100:101 .` (matches the `app` user inside the container)
### Containers start but API fails
1. Check container status: `docker compose ps`
2. Check API logs: `docker compose logs api`
3. Check database logs: `docker compose logs database`
4. Ensure migrations ran: `docker compose exec api uv run alembic upgrade head`
### Port conflicts
If port 8000 is already in use:
```bash
# Check what's using the port
lsof -i :8000
# Or change the port mapping in docker-compose.yml
ports:
- "8001:8000" # Map to a different host port
```
### Rebuilding after code changes
```bash
docker compose build --no-cache
docker compose up -d
```
## Getting Help
If your issue isn't covered here:
- **Check the logs** — most issues are diagnosed from server or deriver logs
- **GitHub Issues** — [Report bugs](https://github.com/plastic-labs/honcho/issues)
- **Discord** — [Join our community](https://discord.gg/plasticlabs)
- **Configuration** — See the [Configuration Guide](./configuration) for all available settings

View File

@ -41,130 +41,82 @@ Hermes exposes four Honcho tools to the agent:
| `honcho_context` | Dialectic Q&A powered by Honcho's LLM. Synthesizes answers from conversation history. |
| `honcho_conclude` | Writes durable facts to Honcho when the user states preferences, corrections, or important context. |
## Two memory layers
When Honcho is enabled, Hermes operates with two layer memory by default (`hybrid`):
**Local session history** -- the immediate transcript for the current chat, thread, or CLI session. Use it for recent turns, short-lived task context, and follow-up questions.
**Honcho memory** -- the semantic, cross-session layer. Use it for user preferences, durable project facts, cross-session continuity, and synthesized peer context.
## Running Honcho locally with Hermes
If you want to point Hermes at a local Honcho instance instead of the hosted API:
### Docker (quickest)
Follow the [Self-Hosting Guide](/v3/contributing/self-hosting) to get Honcho running locally. Once it's up, point Hermes at your instance:
```bash
git clone https://github.com/plastic-labs/honcho.git
cd honcho
cp .env.template .env
cp docker-compose.yml.example docker-compose.yml
hermes memory setup # select "honcho", enter http://localhost:8000 as the base URL
```
Edit `.env`:
```bash
OPENAI_API_KEY=your-openai-api-key
ANTHROPIC_API_KEY=your-anthropic-api-key
DB_CONNECTION_URI=postgresql+psycopg://postgres:postgres@database:5432/honcho
AUTH_USE_AUTH=false
```
```bash
docker compose up -d
curl http://localhost:8000/health
```
### Manual
```bash
git clone https://github.com/plastic-labs/honcho.git
cd honcho
uv sync
cp .env.template .env
```
Edit `.env` with a local or cloud Postgres connection string and API keys, then:
```bash
uv run alembic upgrade head
uv run fastapi dev src/main.py
```
Then update `~/.honcho/config.json` to point at your local instance:
Or manually create/edit the config file (checked in order: `$HERMES_HOME/honcho.json` > `~/.hermes/honcho.json` > `~/.honcho/config.json`):
```json
{
"apiKey": "not-needed-with-auth-disabled",
"baseUrl": "http://localhost:8000",
"hosts": {
"hermes": {
"workspace": "hermes",
"peerName": "your-name",
"enabled": true,
"aiPeer": "hermes",
"memoryMode": "hybrid",
"enabled": true
"peerName": "your-name",
"workspace": "hermes"
}
}
}
```
The `baseUrl` field overrides the default hosted API. With `AUTH_USE_AUTH=false` on the server, the `apiKey` value is ignored but the field must still be present.
For the full list of config fields (`recallMode`, `writeFrequency`, `sessionStrategy`, `dialecticReasoningLevel`, etc.), see the [Hermes memory provider docs](https://hermes-agent.nousresearch.com/docs/user-guide/features/memory-providers#honcho).
See the full [self-hosting guide](/v3/contributing/self-hosting) for database options, cloud setup, and troubleshooting.
<Info>
**Community quick-start**: [elkimek/honcho-self-hosted](https://github.com/elkimek/honcho-self-hosted) provides a one-command installer with pre-configured model tiers and Hermes Agent integration.
</Info>
## Verifying the integration
Steps to test the integration via CLI and agentically by speaking to Hermes agent in natural language.
### 1. Check configuration
### 1. Check status
```bash
hermes honcho status
hermes memory status
```
### 2. Test cross-session recall
This should show Honcho as the active memory provider with your base URL.
In one conversation:
### 2. Store a fact and recall it across sessions
In one conversation, tell Hermes something specific:
```text
Remember that my test phrase is velvet circuit.
My favorite programming language is Rust and I always use dark mode.
```
In a fresh conversation (different thread, new CLI session):
Start a **new session** (different thread, new CLI invocation, or a different platform). Ask:
```text
What is my test phrase?
What do you know about my preferences?
```
If Hermes recalls "velvet circuit" after short-term context is gone, Honcho is working.
If Hermes mentions Rust and dark mode without being told again, cross-session memory is working. The deriver processed your messages, extracted observations, and the dialectic recalled them.
### 3. Test writeback
### 3. Test tool calling directly
Tell Hermes a preference:
Ask Hermes to use a specific Honcho tool:
```text
Remember that I prefer terse answers.
Use your honcho_search tool to find anything you know about me.
```
Wait briefly if writes are asynchronous. Open a fresh conversation:
If Hermes calls the tool and returns results, the full tool pipeline (API connection, vector search, embedding) is functional.
```text
How should you respond to me?
```
If Hermes answers with the stored preference, writeback is functioning.
## Session strategy
| Scope | When to use |
|----------------------|---------------------------------------------------------|
| Per-Session | A honcho session starts fresh each time a new Hermes session is created. Hermes remembers the user across sessions. |
| Per Directory | One honcho session per project directory. Context is scoped to each directory. Coding/project memory scoped to each repository/workspace. |
| Global (per user) | Continuity across all chats, threads, and projects. One honcho session globally for the user and Hermes agent. |
## Configuration options
| Field | Default | Description |
|---|---|---|
| `recallMode` | `hybrid` | `hybrid` (auto-inject + tools), `context` (inject only), `tools` (tools only) |
| `writeFrequency` | `async` | `async`, `turn`, `session`, or integer N |
| `sessionStrategy` | `per-directory` | `per-directory`, `per-repo`, `per-session`, `global` |
| `dialecticReasoningLevel` | `low` | `minimal`, `low`, `medium`, `high`, `max` |
| `dialecticDynamic` | `true` | Auto-bump reasoning level by query complexity |
| `messageMaxChars` | `25000` | Max chars per message (chunked if exceeded) |
## Next steps
@ -182,6 +134,6 @@ If Hermes answers with the stored preference, writeback is functioning.
</Card>
<Card title="Self-Hosting Guide" icon="server" href="/v3/contributing/self-hosting">
Full local environment setup, database options, and troubleshooting.
Full local environment setup, provider configuration, and troubleshooting.
</Card>
</CardGroup>

View File

@ -196,6 +196,12 @@ app.include_router(webhooks.router, prefix="/v3")
app.add_route("/metrics", metrics_endpoint, methods=["GET"])
@app.get("/health")
async def health_check():
"""Health check endpoint for monitoring and container orchestration."""
return {"status": "ok"}
# Global exception handlers
@app.exception_handler(HonchoException)
async def honcho_exception_handler(_request: Request, exc: HonchoException):