Memory library for building stateful agents
Go to file
Phil 4797489281
telemetry: zero-initialize bounded-label metrics so an absent series means a broken scrape (#927)
* telemetry: materialize dropped-event counter children at 0

A labeled Prometheus counter exports no series until its first labels()
call, so telemetry_events_dropped stayed invisible until an event was
actually dropped — impossible to alert on or graph, and "no drops" was
indistinguishable from "metric missing / scrape broken".

Pre-create the (namespace, reason) children at 0 on emitter start, for
each reason the emitter can emit, so the metric is always present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* telemetry: generalize counter zero-init to all bounded-label counters

Extends #927 (which zero-inited telemetry_events_dropped) to every counter
whose label domain is bounded and known at startup, so metrics are present in
Prometheus before their first event — a missing series then signals a broken
scrape rather than "nothing happened yet".

- add initialize_bounded_metrics(instance_type) on PrometheusMetrics; call it
  per-process from main.py (api) and deriver/__main__.py (deriver).
- extract a shared _touch() helper; refactor initialize_telemetry_dropped_metrics
  onto it (that one stays per-emitter in start() — it's prefix-dependent).
- explicit ALL_EVENT_TYPES / HIGH_VOLUME_EVENT_TYPES registry in telemetry.events,
  drift-guarded by tests that walk BaseEvent subclasses.
- only VALID (task_type, token_type, component) tuples for deriver_tokens (the
  cartesian product would fabricate impossible always-0 series); only high-volume
  event types for sampled_out; high-cardinality labels (endpoint, workspace_name)
  left open.
- gauges: zero-init embed_now_tasks_in_flight + telemetry_buffer_size; add a new
  message_embeddings_pending backlog gauge, set each reconciliation cycle and
  zero-inited at deriver startup (Rajat's pending/in-flight ask).
- backfills the tests #927 shipped without.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* review: task-aware deriver combos + fail-soft gauge zero-init

I1: _DERIVER_TOKEN_COMBOS was factored task-independently, materializing the
impossible (ingestion, input, previous_summary) series — previous_summary is
summary-only. Make combos task-aware (_DERIVER_TOKEN_COMBOS_BY_TASK) so no
always-0 impossible series is fabricated, matching the PR's own goal. Tests
tightened to assert the ingestion/previous_summary series is absent.

I2: the three gauge .set(0) zero-inits were bare while the counter inits go
through the fail-soft _touch. Add _set_gauge_zero() so a gauge init can't
propagate an exception into process startup either.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(telemetry): isolate zero-init namespaces, add deriver-to-api guard

Global-REGISTRY assertions used a fixed "test" namespace, which several
other suites also pin, so another test's materialized children could
satisfy a presence assertion or break an absence one. Each test now runs
under a unique namespace resolved from settings at read time.

Adds the inverse per-process isolation test: deriver-only init must not
materialize API-only series (dialectic tokens, embed_now).

Co-Authored-By: Claude <noreply@anthropic.com>

* review: per-replica backlog gauge, drop duplicated constants and .meta refs

Addresses Vineeth's review on #927.

Blocking:
- message_embeddings_pending is a DB-global count, so drive it from
  ReconcilerScheduler._scheduler_loop (runs on every replica, every
  interval) instead of run_vector_reconciliation_cycle (runs off the
  queue behind work-unit dedup, so one replica per cycle). Combined with
  the zero-init, the old placement made every replica that never won the
  work unit export a confident permanent 0. Help string now names the
  owner so dashboards don't reach for sum().
- guard initialize_telemetry_dropped_metrics on METRICS.ENABLED,
  matching its sibling initializer.
- drop the duplicate REASONING_LEVELS; import the one in src/config.

Non-blocking:
- walk BaseSpecialist recursively via a shared utils.types.walk_subclasses
  (replaces the direct-children-only __subclasses__() and the test's
  private copy of the same helper).
- derive the specialist assertion from the subclasses instead of
  hardcoding two names — the hardcoded pair kept passing after
  CardRefreshSpecialist landed, leaving it uncovered.
- inline the zero-init rationale and the multi-instance bucket taxonomy;
  removes both pointers to a .meta design doc that is not in the repo.

Tests: new tests/reconciler/test_pending_backlog_gauge.py pins both
halves of the relocation (verified it fails when reverted).

* review: fix inert test guard, stale comments, and the REASONING_LEVELS drift claim

Second review pass on the branch. Findings, most severe first:

- tests/reconciler/test_pending_backlog_gauge.py: the _try_enqueue_task stub
  was patched onto the class but declared without `self`, so calling it
  raised TypeError — which _scheduler_loop swallows. The guard was inert and
  the test passed for the wrong reason. Fixed the arity.

- metrics.py still commented that the backlog gauge is "set live each
  reconciliation cycle". That is the exact claim the previous commit
  overturned; it now contradicted the help string, the bucket-3 docstring
  and sync_vectors.py.

- metrics.py claimed REASONING_LEVELS is "derived from the config Literal so
  it never drifts", but config.py hand-listed it, so the earlier dedup had
  quietly traded away the guarantee the original get_args() call provided.
  Made it true instead: config.REASONING_LEVELS = list(get_args(...)), which
  keeps the dedup and restores the invariant.

- dropped _set_gauge_zero: all three gauges it zeroed already have identical
  fail-soft setters, so it was a second way to do one thing. Using the
  setters also makes _handle_metric_error name the actual gauge.

- record_pending_embeddings_backlog's docstring oversold the covering index
  as making the COUNT "negligible". The index makes cost proportional to the
  pending backlog, not to the table — which is worst precisely when the
  backlog matters. Stated honestly.

- _scheduler_loop's docstring said it only enqueues; it also refreshes the
  gauge, at a cadence set by the shortest task interval.

- comment reconciliation: stripped #927 / "the generalization" temporal
  anchoring, a CardRefreshSpecialist change-narration clause, and
  reviewer-directed phrasing from the test file; disambiguated the
  src/utils/summarizer.py path.

- CLAUDE.md had no Prometheus section at all, so the new "add a BaseEvent
  subclass -> update ALL_EVENT_TYPES" obligation and the never-sum() rule
  for non-additive gauges were undiscoverable from the architecture doc.

Verified: ruff + basedpyright clean (0 errors), tests/telemetry + reconciler
+ dialectic + llm 497 passed, full suite 1768 passed with only the 4
pre-existing test_document failures (OpenAI key required, reproduced on
clean origin/main). Re-confirmed the relocation guard fails when reverted.

* fix: silence the two basedpyright warnings inherited from main

CI runs `uv run basedpyright` bare, and basedpyright exits non-zero on any
warning — so these two have been failing the staticanalysis job on every
branch cut from current main, not just this one:

- src/vector_store/__init__.py:209 implicit string concatenation (#496)
- tests/test_cache_redaction.py:5 private import (#869)

Both predate this branch and are unrelated to the telemetry work; fixed
here only because they block this PR from going green. Verified: clean
origin/main also reports "0 errors, 2 warnings" and exits 1.

basedpyright now 0 errors, 0 warnings, exit 0.

* docs(telemetry): make the bucket-3 aggregation rule precise

The multi-instance taxonomy said a service-scoped non-additive metric has
"no aggregation correct once they disagree", then immediately mandated that
every instance refresh on its own timer. Those undercut each other: staggered
timers ALWAYS disagree slightly, so as written the rule reads as "ensure they
don't", which is unachievable, and it leaves the reader unsure whether max()
and avg() survived the fix.

The actual rule is bounded disagreement plus a scale-preserving aggregator.
Instances are N witnesses to one fact, not N parts of one whole, so sum() can
never be correct (it scales with replica count) while max()/avg()/quantiles
are correct precisely because the per-instance timer bounds the spread.

Wording only; no behavior change. The gauge help string already said
"max() or avg(), never sum()" — this makes the normative docstring agree
with it. Surfaced walking Vineeth's comment 3668208059 for comprehension.

* refactor(bench): import REASONING_LEVELS from config instead of re-listing

Third copy of the constant, missed when ee781c0/694e07f deduped the other
two. This one re-declared the ReasoningLevel Literal as well as the list,
so the type alias could diverge from config's with nothing to catch it —
and the list was hand-written, the variant that typechecks clean while
missing a member.

No import barrier justified it: this module already imports from src, as do
seven of its siblings in tests/bench. Concrete effect of the drift was that
a newly added sixth reasoning level would be rejected by the bench CLI's
argparse choices=.

src.config.REASONING_LEVELS is now the single definition repo-wide.

* test(telemetry): pin the METRICS.ENABLED guard on the per-emitter initializer

initialize_telemetry_dropped_metrics gained a METRICS.ENABLED guard in
ee781c0, addressing Vineeth's asymmetry comment, but nothing asserted it —
it had only the enabled half of the pair its sibling has. Deleting the guard
left the suite green, so the fix closed the asymmetry in the guards and
reproduced it one level up in the tests.

Mirrors test_init_noop_when_metrics_disabled. Verified live rather than
assumed: deleting the two guard lines turns this test red.

Uses a unique namespace, without which the absence assertion would be
satisfied by the enabled test's children rather than by the guard.

* docs(telemetry): fold zero-init why-prose behind # region ai markers

Comment/docstring-only pass over the changed files, per the groudon
comment-marker standard: the terse human-facing "what" stays visible, and
load-bearing "why" (the zero-init / absent-series-means-broken-scrape
rationale, gotchas, receipts) folds into # region ai / # ai: blocks.

Behavior-preserving: AST-identical modulo docstrings/comments vs the
pre-pass merge; ruff, ruff format --check, and basedpyright all clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-20 10:24:49 -04:00
.agents docs: adding honcho-memory skill (#784) 2026-08-10 15:06:07 -04:00
.claude docs: adding honcho-memory skill (#784) 2026-08-10 15:06:07 -04:00
.github chore: add pr template and pre-pre skill (#1031) 2026-08-19 16:18:47 -04:00
.vscode Typing (#137) 2025-06-24 18:29:13 -04:00
assets Docs Refresh (#200) 2025-08-29 16:27:07 -04:00
database Standardize DB Constraint Conventions (#272) 2025-11-20 11:50:54 -05:00
docker fix: add observability to docker compose + get docker compose into a usable state (#429) 2026-03-18 13:16:22 -04:00
docs fix(llm): forward provider_params.timeout to the OpenAI-compatible embedding client (#1024) 2026-08-18 10:51:53 -04:00
examples fix: (crewai) update crew ai package and examples for latest protocol (#631) 2026-05-18 17:37:36 -04:00
honcho-cli feat(cli): add `honcho session view` transcript command (#1006) 2026-08-11 10:12:16 -04:00
mcp fix(mcp): OAuth session fixes, write scope, SDK bump (#1004) 2026-08-14 11:02:59 -04:00
migrations feat: make session_name nullable for documents and update related SDKs (#347) 2026-01-26 13:33:11 -05:00
scripts fix: increase throughput of unit tests by changing behavior db teardown (#949) 2026-07-29 11:19:41 -04:00
sdks Scopes SDK Changes (#1030) 2026-08-19 10:48:29 -04:00
skills chore: add pr template and pre-pre skill (#1031) 2026-08-19 16:18:47 -04:00
src telemetry: zero-initialize bounded-label metrics so an absent series means a broken scrape (#927) 2026-08-20 10:24:49 -04:00
tests telemetry: zero-initialize bounded-label metrics so an absent series means a broken scrape (#927) 2026-08-20 10:24:49 -04:00
.dockerignore Dialectic Endpoint Improvements (#67) 2024-09-14 17:06:11 -04:00
.env.template fix: make embedding batch size configurable (#983) 2026-08-05 15:43:32 -04:00
.gitattributes fix: force LF line endings for shell scripts (#1017) 2026-08-19 11:57:20 -04:00
.gitignore feat(dialectic): optional structured outputs with limited schema for Dialectic calls (#896) 2026-07-20 18:46:49 -04:00
.markdownlint.json Add Pre-commit Hooks (#165) 2025-07-22 15:17:53 -04:00
.pre-commit-config.yaml fix(sdk): add peer field to session creation methods (#705) 2026-05-21 12:31:53 -04:00
.python-version Switch from UUIDv4 to NanoID (#71) 2024-10-17 14:07:51 -04:00
CHANGELOG.md August Changelog Docs Sync (#1009) 2026-08-12 17:35:51 -04:00
CLAUDE.md telemetry: zero-initialize bounded-label metrics so an absent series means a broken scrape (#927) 2026-08-20 10:24:49 -04:00
CONTRIBUTING.md Kass/readme refresh (#681) 2026-05-14 13:15:37 -04:00
Dockerfile fix: reduce Honcho runtime image size (#1014) 2026-08-12 19:55:41 -04:00
LICENSE Initial commit 2023-09-10 17:29:55 -04:00
README.md docs: adding honcho-memory skill (#784) 2026-08-10 15:06:07 -04:00
alembic.ini Database Concurrency Optimizations (#80) 2024-12-13 11:56:39 -05:00
config.toml.example fix(llm): forward provider_params.timeout to the OpenAI-compatible embedding client (#1024) 2026-08-18 10:51:53 -04:00
docker-compose.yml.example fix: reduce Honcho runtime image size (#1014) 2026-08-12 19:55:41 -04:00
fly.toml switch OTEL metrics to prometheus (#344) 2026-01-25 17:26:42 -05:00
pyproject.toml fix: reduce Honcho runtime image size (#1014) 2026-08-12 19:55:41 -04:00
uv.lock fix: reduce Honcho runtime image size (#1014) 2026-08-12 19:55:41 -04:00

README.md


Static Badge PyPI version NPM version Discord

Honcho is memory infrastructure for building stateful agents that understand changing people, agents, groups, projects, and ideas over time.

Store messages and events, let Honcho reason in the background, then query peer representations, session context, search results, or natural-language insights from any model or framework. Use it managed at api.honcho.dev or self-host the FastAPI server yourself.

Using Honcho as your memory system will earn your agents higher retention, more trust, and help you build data moats to out-compete incumbents.

Honcho has defined the Pareto Frontier of Agent Memory. Watch the video, check out our evals page, and read the blog post for more detail.

Contents

The Honcho project is split between several repositories, with this one hosting the core service logic — implemented as a FastAPI server. Client SDKs for Python and TypeScript live in the sdks/ directory.

Start Here

I want to... Path Get started
Give my coding agent persistent memory Claude Code, OpenCode, OpenClaw, Hermes, or any MCP client Integrations
Add memory to my product Python or TypeScript SDK Quickstart
Self-host Honcho Docker / local development Self-hosting

Why Honcho

Capability What it means
Reasoning-first memory Extracts conclusions from conversations and events, not just matching chunks.
Peer-centric model Tracks users, agents, groups, projects, and ideas as entities that change over time.
Multi-peer perspective Models what one peer knows about another when configured.
Managed or self-hosted Use api.honcho.dev or run the FastAPI server yourself.
Agent-tool integrations MCP, Claude Code, OpenCode, OpenClaw, Hermes, Cursor-compatible clients.

The Honcho Loop

  1. Store conversations, events, documents, or tool traces as messages on a session.
  2. Reason — Honcho processes the queue in the background and updates peer representations.
  3. Query — ask Honcho for context, search results, peer representations, or a natural-language answer.
  4. Inject — drop the result into any LLM call or agent framework.

Concretely: workspaces hold peers, peers participate in sessions, messages live on sessions, and Honcho builds a per-peer representation that you query through the Chat Endpoint or directly.

Quickstart

Get an API key at app.honcho.dev — when you sign up you'll be prompted to join an organization, which gets its own dedicated Honcho instance and $100 free credits. Or self-host and run against http://localhost:8000.

Python

pip install honcho-ai
# or: uv add honcho-ai
# or: poetry add honcho-ai
import os
from honcho import Honcho

# Managed service uses api.honcho.dev by default. For self-hosted, pass
# base_url="http://localhost:8000" or set HONCHO_URL.
honcho = Honcho(
    workspace_id="my-app-testing",
    api_key=os.environ["HONCHO_API_KEY"],
)

# 1. Store: peers and messages on a session
alice = honcho.peer("alice")
tutor = honcho.peer("tutor")
session = honcho.session("session-1")
session.add_messages([
    alice.message("Hey there — can you help me with my math homework?"),
    tutor.message("Absolutely. Send me your first problem!"),
])

# 2. Reason: happens asynchronously in the background.

# 3. Query: ask Honcho what it knows, or pull prompt-ready context.
answer = alice.chat("What learning styles does the user respond to best?")
context = session.context(summary=True, tokens=10_000)

# 4. Inject: hand the context to your model of choice.
from openai import OpenAI
client = OpenAI()
completion = client.chat.completions.create(
    model=os.environ.get("OPENAI_MODEL", "gpt-4o-mini"),
    messages=context.to_openai(assistant=tutor),
)

TypeScript

npm install @honcho-ai/sdk
# or: bun add @honcho-ai/sdk
import { Honcho } from "@honcho-ai/sdk";
import OpenAI from "openai";

const honcho = new Honcho({
  workspaceId: "my-app-testing",
  apiKey: process.env.HONCHO_API_KEY,
});

const alice = await honcho.peer("alice");
const tutor = await honcho.peer("tutor");
const session = await honcho.session("session-1");
await session.addMessages([
  alice.message("Hey there — can you help me with my math homework?"),
  tutor.message("Absolutely. Send me your first problem!"),
]);

const answer = await alice.chat(
  "What learning styles does the user respond to best?",
);
const context = await session.context({ summary: true, tokens: 10_000 });

const openai = new OpenAI();
const completion = await openai.chat.completions.create({
  model: process.env.OPENAI_MODEL ?? "gpt-4o-mini",
  messages: context.toOpenAI({ assistant: tutor }),
});

Note: background reasoning is asynchronous. Newly-added messages may take a moment to be reflected in chat/representation responses; for low-latency reads, use the representation endpoint.

What Honcho Gives You

Need API
Save interaction history session.add_messages(...)
Ask what Honcho knows about a peer peer.chat(...)
Get prompt-ready context session.context(...).to_openai(...) / .to_anthropic(...)
Hybrid search (BM25 + vector) peer.search(...), session.search(...), honcho.search(...)
Low-latency static representations peer.representation(...), session.representation(...)
Import documents session.upload_file(...)
Inspect background processing honcho.queue_status(...)

See the full SDK Reference and API Reference.

Integrations

Claude Code

Two ways, depending on how deep you want to go:

Plugin (richer integration — recommended for Claude Code users):

/plugin marketplace add plastic-labs/claude-honcho
/plugin install honcho@honcho

Raw MCP (works in any MCP client — Cursor, Cline, Windsurf, etc.):

claude mcp add honcho \
  --transport http \
  --url "https://mcp.honcho.dev" \
  --header "Authorization: Bearer hch-your-key-here" \
  --header "X-Honcho-User-Name: YourName"

Details: Claude Code guide · MCP guide.

OpenCode

opencode plugin "@honcho-ai/opencode-honcho" --global

Details: OpenCode guide.

OpenClaw

openclaw plugins install @honcho-ai/openclaw-honcho
openclaw honcho setup
openclaw gateway --force

openclaw honcho setup prompts for your API key, writes the config, and optionally migrates legacy MEMORY.md / USER.md / IDENTITY.md files into Honcho (non-destructive — originals are never deleted). Details: OpenClaw guide.

Hermes

hermes memory setup   # select "honcho", point at api.honcho.dev or your local server

Details: Hermes guide.

Add Honcho to your own codebase (agent skill)

For wiring the Honcho SDK into an existing application, install the integration skill — it explores your codebase, asks about integration preferences, generates the SDK setup, and verifies it works:

npx skills add plastic-labs/honcho

Then invoke /honcho-integration in Claude Code (or /honcho-dev:integrate via the plugin marketplace). The same command also installs the memory skills — honcho-memory (concepts: the recall/record loop, session and peer strategy, plus how to connect and drive an MCP-connected Honcho) and honcho-cli (inspecting and debugging a deployment). Details: agentic development guide.

Other MCP clients

The same claude mcp add form (or its client-specific equivalent) works in any MCP-compatible client. See MCP guide.

Core Concepts

Honcho organises everything around peers — humans and AI agents alike are first-class entities. The peer model enables:

  • Multi-participant sessions with mixed human and AI agents
  • Configurable observation settings (which peers observe which others)
  • Flexible identity management for all participants
  • Support for complex multi-agent interactions

Peers exchange messages within sessions; Honcho reasons over those messages to build a representation of each peer that you can query.

  • Workspace (formerly App): top-level container; isolates data between use cases.
  • Peer (formerly User): any participant — human user or AI agent.
  • Session: a conversation context; many-to-many with peers.
  • Message: an atomic data unit (peer-to-peer communication or ingested document chunk).

What you query out of Honcho:

  • Conclusions — what Honcho has extracted about a peer (deductive and inductive). Exposed via the conclusions API.
  • Representations — static, low-latency snapshots of what Honcho knows about a peer (optionally session-scoped).
  • Peer Cards — compact identity summaries.
  • Session context / summaries — prompt-ready bundles for long-running conversations.
Internal storage (Collections & Documents)

Internally, Honcho stores peer-related observations in collections of vector-embedded documents. Collections are keyed by (observer, observed) peer pairs — the same mechanism powers self-representation (observer == observed) and cross-peer modelling (peer X's understanding of peer Y). These primitives are not exposed directly; the Conclusions API is the public surface.

Benchmarks & Evals

Honcho's evals span LongMemEval, LoCoMo, and other long-conversation benchmarks. See the evals page, the research blog post, and the Pareto-frontier announcement video for methodology and reproducible results.

Self-hosting

Honcho is open source under AGPL-3.0. You can run the full server locally with Docker, then point the SDKs at http://localhost:8000.

Quick start (Docker)

git clone https://github.com/plastic-labs/honcho.git
cd honcho
cp docker-compose.yml.example docker-compose.yml
cp .env.template .env       # fill in LLM_GEMINI_API_KEY / LLM_ANTHROPIC_API_KEY / LLM_OPENAI_API_KEY
docker compose up

Then point the SDKs at it:

honcho = Honcho(workspace_id="my-app-testing", base_url="http://localhost:8000")
# or: export HONCHO_URL=http://localhost:8000
Local development without Docker

Below is a guide on setting up a local environment for running the Honcho Server without Docker.

Prerequisites and Dependencies

Honcho is developed using python and uv.

The minimum python version is 3.10 The minimum uv version is 0.5.0

Setup

Once the dependencies are installed on the system run the following steps to get the local project setup.

  1. Clone the repository
git clone https://github.com/plastic-labs/honcho.git
  1. Enter the repository and install the python dependencies

We recommend using a virtual environment to isolate the dependencies for Honcho from other projects on the same system. uv will create a virtual environment when you sync your dependencies in the project.

cd honcho
uv sync

This will create a virtual environment and install the dependencies for Honcho. The default virtual environment will be located at honcho/.venv. Activate the virtual environment via:

source honcho/.venv/bin/activate
  1. Set up a database

Honcho utilizes Postgres for its database with pgvector. An easy way to get started with a postgres database is to create a project with Supabase

Alternatively, a docker-compose template is available with a sample database configuration. To use Docker:

cp docker-compose.yml.example docker-compose.yml
docker compose up -d database
  1. Edit the environment variables

Honcho uses a .env file for managing runtime environment variables. A .env.template file is included for convenience. Several of the configurations are not required and are only necessary for additional logging, monitoring, and security.

Below are the required configurations:

DB_CONNECTION_URI= # Connection uri for a postgres database (with postgresql+psycopg prefix)

# 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)

Note that the DB_CONNECTION_URI must have the prefix postgresql+psycopg to function properly. This is a requirement brought by sqlalchemy

The template has the additional functionality disabled by default. To ensure that they are disabled you can verify the following environment variables are set to false:

AUTH_USE_AUTH=false
SENTRY_ENABLED=false

If you set AUTH_USE_AUTH to true you will need to generate a JWT secret. You can do this with the following command:

python scripts/generate_jwt_secret.py

This will generate a JWT secret and print it to the console. You can then set the AUTH_JWT_SECRET environment variable. This is required for AUTH_USE_AUTH:

AUTH_JWT_SECRET=<generated_secret>

Once auth is enabled, use scripts/generate_jwt.py to mint tokens for local development and scripting:

# Admin token (full access, no expiry)
uv run python scripts/generate_jwt.py --admin

# Admin token expiring in 24 hours
uv run python scripts/generate_jwt.py --admin --expires 24h

# Workspace-scoped token
uv run python scripts/generate_jwt.py --workspace my-workspace --expires 30d

# Capture a token for use in curl/scripts
TOKEN=$(uv run python scripts/generate_jwt.py --admin --print-only)
curl -H "Authorization: Bearer $TOKEN" http://localhost:8000/v3/workspaces

Duration units: s (seconds), m (minutes), h (hours), d (days), w (weeks), y (years).

  1. Run database migrations

With the database set up and environment variables configured, run the migrations to create the necessary tables:

uv run alembic upgrade head

This will create all tables for Honcho including workspaces, peers, sessions, messages, and the queue system.

  1. Launch Honcho

With everything set up, you can now launch a local instance of Honcho. In addition to the database, two components need to be running:

Start the API server:

uv run fastapi dev src/main.py

This is a development server that will reload whenever code is changed.

Start a background worker (deriver):

In a separate terminal, run:

uv run python -m src.deriver

The deriver generates representations, summaries, peer cards, and manages dreaming tasks. You can increase the number of derivers to improve runtime efficiency.

Contributors: see CONTRIBUTING.md for pre-commit setup. Deploying to Fly.io: see Self-hosting docs → Deploying on Fly.io.

Configuration

Honcho uses a flexible configuration system that supports both TOML files and environment variables. Configuration values are loaded in priority order: environment variables > .env file > config.toml > defaults.

Full configuration reference

Using config.toml

Copy the example configuration file to get started:

cp config.toml.example config.toml

Then modify the values as needed. The TOML file is organized into sections:

  • [app] - Application-level settings (log level, session limits, embedding settings, namespace)
  • [db] - Database connection and pool settings
  • [auth] - Authentication configuration
  • [cache] - Redis cache configuration
  • [llm] - LLM provider API keys and general settings
  • [deriver] - Background worker settings and representation configuration
  • [peer_card] - Peer card generation settings
  • [dialectic] - Chat Endpoint configuration with per-level reasoning settings
  • [summary] - Session summarization settings
  • [dream] - Dream processing configuration (including specialist models and surprisal settings)
  • [webhook] - Webhook configuration
  • [metrics] - Prometheus pull-based metrics
  • [telemetry] - CloudEvents telemetry for analytics
  • [vector_store] - Vector store configuration (pgvector, turbopuffer, or lancedb)
  • [sentry] - Error tracking and monitoring settings

Using Environment Variables

All configuration values can be overridden using environment variables. The environment variable names follow this pattern:

  • {SECTION}_{KEY} for top-level section settings
  • Use __ inside {KEY} for nested settings
  • Just {KEY} for app-level settings

Examples:

  • DB_CONNECTION_URI - Database connection string
  • AUTH_JWT_SECRET - JWT secret key
  • DERIVER_MODEL_CONFIG__TRANSPORT - Transport for the background deriver
  • SUMMARY_MODEL_CONFIG__MODEL - Summary model override
  • DIALECTIC_LEVELS__low__MODEL_CONFIG__MODEL - Model for low reasoning level
  • LOG_LEVEL - Application log level
  • METRICS_ENABLED - Enable Prometheus metrics
  • TELEMETRY_ENABLED - Enable CloudEvents telemetry

Example

If you have this in config.toml:

[db]
CONNECTION_URI = "postgresql+psycopg://localhost/honcho_dev"
POOL_SIZE = 10

You can override just the connection URI in production:

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.

Architecture

Honcho splits into two services: Storage (workspaces, peers, sessions, messages, internal collections) and Insights (reasoning, conclusions, representations, summaries, the chat endpoint). Storage is synchronous via the API; Insights is asynchronous via a background queue consumed by the deriver worker process.

Key features:

  • Rich Reasoning System — multiple implementation methods that extract conclusions from interactions and build comprehensive representations of peers
  • Chat Endpoint — reasoning-informed responses that integrate conclusions with current context
  • Background Processing — asynchronous processing pipeline for expensive operations like representation updates and session summarization
  • Multi-Provider Support — configurable LLM providers for different use cases
Storage primitives in detail

Honcho contains several different primitives used for storing application and peer data. This data is used for managing conversations, modeling peer identity, building RAG applications, and more.

The philosophy behind Honcho is to provide a platform that is peer-centric and easily scalable from a single user to a million.

Below is a mapping of the different primitives and their relationships.

Workspaces
├── Peers ←──────────────────┐
│   ├── Sessions             │
│   └── (internal collections, keyed by observer/observed peer pair)
│                            │
│                            │
└── Sessions ←───────────────┤ (many-to-many)
    ├── Peers ───────────────┘
    └── Messages (session-level)

Relationship Details:

  • A Workspace contains multiple Peers.
  • Peers and Sessions have a many-to-many relationship (peers can participate in multiple sessions, sessions can have multiple peers).
  • Messages belong to a session and are labelled by their source peer.
  • Internal collections of vector-embedded documents are keyed by (observer, observed) peer pairs. They are not directly exposed via the API; the observations stored in them are exposed as Conclusions.

Users familiar with APIs such as the OpenAI Assistants API will be familiar with much of the mapping here.

Workspaces

This is the top level construct of Honcho. Developers can register different Workspaces for different assistants, agents, AI enabled features, etc. It is a way to isolate data between use cases and provide multi-tenant capabilities.

Peers

Within a Workspace everything revolves around a Peer. The Peer object represents any participant in the system — whether human users or AI agents. This unified model enables complex multi-participant interactions.

Sessions

The Session object represents a set of interactions between Peers within a Workspace. Other applications may refer to this as a thread or conversation. Sessions can involve multiple peers with configurable observation settings.

Messages

The Message represents an atomic data unit that exists at the session level: communication between peers within a session context. All messages are labelled by their source peer and can be processed asynchronously to update their representations. This flexible design allows for both conversational interactions and broader data ingestion for personality modelling.

Reasoning pipeline

The reasoning functionality of Honcho is built on top of the Storage service. As Messages and Sessions are created for Peers, Honcho will asynchronously reason about peer psychology to derive facts about them and store them in reserved internal collections.

A high level summary of the pipeline is as follows:

  1. Messages are created via the API.
  2. Derivation tasks are enqueued for background processing, including:
    • representation: update representations of Peers.
    • summary: create summaries of Sessions.
  3. Session-based queue processing ensures proper ordering.
  4. Results are stored internally and surfaced via the Conclusions API, Representations, Peer Cards, and the Chat Endpoint.
Retrieving data and insights

Honcho exposes several different ways to retrieve data from the system to best serve the needs of any given application.

Get Context

In long-running conversations with an LLM, the context window can fill up quickly. To address this, Honcho provides a context endpoint that returns a combination of messages, conclusions, summaries from a session up to a provided token limit.

Use this to keep sessions going indefinitely. If you'd like to see this in action, try out Honcho Chat.

There are several search endpoints that let developers query messages at the Workspace, Session, or Peer level using a hybrid search strategy.

Requests can include advanced filters to further refine the results.

Chat API

The flagship interface for using these insights is the Chat Endpoint (POST /peers/{peer_id}/chat). It takes natural-language requests to get data about a peer and returns reasoning-grounded responses. Examples:

  • Asking Honcho for a generic or specific insight about the peer.
  • Asking Honcho to hydrate a prompt with data about the peer's behaviour.
  • Asking Honcho for a second opinion on how to respond.
  • Getting personalised responses that incorporate long-term facts and context.

Representations

For low-latency use cases, Honcho provides access to a representation endpoint that returns a static document with insights about a peer in the context of a particular session. Use this to quickly add context to a prompt without having to wait for an LLM response.

SDKs

SDKs are versioned independently of the server. Current SDK versions track each other; the server badge above reflects the deployed server version.

See the SDK Reference for full API surface, the API Reference for the raw HTTP API, and per-SDK example folders for runnable demos.

Learn More

Contributing

We welcome contributions to Honcho! Please read our Contributing Guide for details on our development process, coding conventions, and how to submit pull requests.

License

Honcho is licensed under the AGPL-3.0 License. Learn more at the License file.