Files
Nicolò Boschi 6f441b0aeb revert: drop free-threaded CPython 3.14 support (#4037, #4067) (#4234)
Load testing did not justify the maintenance cost of the -py3.14t target, so
this removes it and the multi-loop server built on top of it.

Removed outright:

- `hindsight_api/_free_threading.py` and `HINDSIGHT_API_FREE_THREADING` — the
  guard that turned CPython's GIL-re-enable RuntimeWarning into an error.
- `docker/standalone/Dockerfile.freethreaded`, `docker/freethreaded-smoke.sh`,
  the `test-api (free-threaded 3.14)` CI job, and the `-py3.14t` release image
  (including its `latest=false` carve-out in the image metadata step).
- `multi_loop.py`, `HINDSIGHT_API_EVENT_LOOPS` / `--event-loops`, and
  `_serve_multi_loop`. Several event loops in one process is only a throughput
  win without the GIL; on a stock build the loops take turns, which `main.py`
  already warned about.

Multi-loop hooks reverted with it: `run_background_tasks` on MemoryEngine and
both `create_app`s, `LLMTraceRecorder.bind_loop` and its per-loop filter, and —
from the #4123 follow-up — `ExtensionContext.is_primary` plus the thread-local
context in `Extension`. With one loop per process the flag is permanently True
and only one context is ever set, so both were dead weight on a public
extension interface.

`HINDSIGHT_API_MIGRATION_ISOLATION` loses its `auto` mode and now defaults to
`false`. `auto` isolated only on a free-threaded interpreter, so this changes
nothing for any existing deployment; `true`/`false` still force it either way.

Kept, because they are real races that threads hit under the GIL too and only
their rationale was free-threading-specific: the dateparser lock and the
`regex>=2026.9.3` floor, one TEI HTTP client per thread, the shared bounded
embeddings request pool, `bank_stats_cache`'s per-loop coalescing, and
`_cross_loop.py` (still used by llm_wrapper, cross_encoder and llamacpp_llm).
Their comments now stand on plain thread/loop-safety grounds.

Ordinary Python 3.14 is untouched: the `build-api-python-versions` matrix still
covers 3.11-3.14 and the litellm >=1.93.0 cp314 floor stays.

Verified: lint.sh, ty, and the deterministic suite (8645 passed). OpenAPI and
the generated clients show no drift, and the two .env.example copies stay
byte-identical.
2026-09-09 10:30:09 +02:00

19 KiB
Raw Permalink Blame History

Installation

Hindsight can be deployed in several ways depending on your infrastructure and requirements.

:::tip Don't want to manage infrastructure? Hindsight Cloud is a fully managed service that handles all infrastructure, scaling, and maintenance — sign up here. :::

Supported Platforms

Hindsight runs on Linux, macOS, and Windows:

Platform Docker Bare Metal (pip) Embedded DB (pg0) Notes
Linux (x86_64, ARM64) Fully supported, recommended for production
macOS (Apple Silicon / arm64) Fully supported
macOS (Intel / x86_64) ⚠️ slim only Use hindsight-all-slim / hindsight-api-slim. The full bundle's local ML models (PyTorch, MLX) publish no Intel-Mac wheels, so pip install hindsight-all silently backtracks to a months-old release. Pair the slim bundle with a hosted embeddings/reranker provider or the in-process ONNX backend (hindsight-api-slim[local-onnx]).
Windows (x86_64) Fully supported — see Windows setup for external PostgreSQL option

All platforms support the embedded database (pg0) for development. On Windows, you can also use an external PostgreSQL installation — see the Windows section for a step-by-step guide.


Prerequisites

PostgreSQL

Hindsight requires PostgreSQL 14+ with a vector extension for similarity search. The supported extensions are:

  • pgvector (default)
  • pgvectorscale
  • vchord
  • scann (AlloyDB)

Configure which one to use with HINDSIGHT_API_VECTOR_EXTENSION. See Configuration for details.

By default, Hindsight uses pg0 — an embedded PostgreSQL that runs locally on your machine. This is convenient for development but not recommended for production.

For production, use an external PostgreSQL with one of the supported vector extensions:

  • Supabase — Managed PostgreSQL with pgvector built-in
  • Neon — Serverless PostgreSQL with pgvector
  • Azure Database for PostgreSQL — With pgvector and pgvectorscale support
  • Google AlloyDB / AlloyDB Omni — With pgvector and ScaNN support
  • AWS RDS / Cloud SQL — With pgvector extension enabled
  • Self-hosted — PostgreSQL 14+ with your preferred vector extension

LLM Provider

You need an LLM API key for fact extraction, entity resolution, and answer generation. See Models for supported providers, model recommendations, and configuration.

Hardware

Hindsight is designed to run on commodity hardware. The footprint depends mainly on whether the full image (which bundles local embedding and reranker models) or the slim image (which delegates those to external providers) is used.

Component Minimum RAM Recommended RAM Notes
API — Full image 1.5 GB 2 GB Loads local BGE embedder (~130 MB) and MiniLM cross-encoder (~90 MB) into memory, plus PyTorch/ONNX runtime arenas. Idle RSS settles around 0.81.0 GB; expect 1.21.5 GB under load.
API — Slim image 512 MB 1 GB No local models. Steady-state RSS is dominated by Python runtime and DB connections. Requires external embedding and reranker providers (e.g. TEI, OpenAI, Cohere).
Control Plane (UI) 128 MB 256 MB Next.js process, lightweight.
Worker (if separated) Same as API image variant Same as API image variant Workers load the same models as the API server.
PostgreSQL 512 MB 1 GB+ Scales with the number of memories and indexes.

:::tip Reducing the footprint The bulk of the full image's memory comes from the bundled embedding and reranker models and their PyTorch/ONNX runtimes. To shrink the deployment to a few hundred MB of RAM, switch to the slim image and configure external embedding and reranker providers. :::

CPU vs GPU: 2 vCPUs on CPU-only is fine for development and basic workloads. For production traffic, the local reranker (cross-encoder) is the main bottleneck and typically benefits from a GPU to keep recall latency reasonable; alternatively, offload reranking to an external reranker provider (e.g. TEI, Cohere) on dedicated GPU hardware.


Docker

Best for: Quick start, development, small deployments

Run everything in one container with embedded PostgreSQL:

export OPENAI_API_KEY=sk-xxx

docker run -it --pull always --name hindsight --restart unless-stopped --shm-size=1g -p 8888:8888 -p 9999:9999 \
  -e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
  -v hindsight-data:/home/hindsight/.pg0 \
  ghcr.io/vectorize-io/hindsight:latest

:::note Persisting data: named volume vs. host bind mount The container runs as a non-root user (UID 1000). The hindsight-data named volume above is recommended — Docker creates it owned by the container user, so it works with no extra setup.

If you instead bind-mount a host directory (-v $HOME/.hindsight-docker:/home/hindsight/.pg0), that directory must be owned by UID 1000, or the embedded database fails to start with Permission denied:

sudo chown -R 1000:1000 $HOME/.hindsight-docker

Do not run the image under a different UID with --user to work around this. The image only defines the hindsight user (UID 1000), so any other UID has no /etc/passwd entry, and startup crashes in a library that looks the running user up by ID:

KeyError: 'getpwuid(): uid not found: 1042'

Running as UID 1000 (the default) with the directory chowned to match is the supported way to use a host bind mount. If you cannot chown the directory — for example on a NAS share mounted with a fixed uid= — use a named volume instead. :::

All published images are signed with Cosign — verification is optional.

:::tip Set a stable HINDSIGHT_API_WORKER_ID in production The worker uses the container hostname as its identity, which Docker sets to the container ID by default. That value changes on every restart, so any task that was being processed when the container went down stays parked under the old ID with no way for the new container to recognize it as its own.

Set HINDSIGHT_API_WORKER_ID to a stable value (e.g., -e HINDSIGHT_API_WORKER_ID=hindsight-prod) so the worker keeps the same identity across restarts. This is recommended even for single-container deployments. For diagnosis and recovery commands, see Admin CLI - Recovering stuck operations. :::

Docker Image Variants

Variant Size (AMD64) Size (ARM64) When to use
Full (latest) ~9 GB ~3.7 GB Default. Embeddings and reranking run in the image; the LLM is always external, including for local inference.
Slim (slim) ~500 MB ~500 MB Use when you already rely on external services for embeddings and reranking (OpenAI, Cohere, TEI). Significantly smaller image, faster deploys. Requires external providers.

The slim image corresponds to the hindsight-api-slim pip package. See Configuration for external provider options.

Neither image bundles llama.cpp, so the built-in llamacpp provider is not available in Docker. To run inference locally, start llama.cpp (or Ollama, LM Studio, vLLM) alongside Hindsight and point HINDSIGHT_API_LLM_BASE_URL at it — see docker/docker-compose/local-llm/ for a working compose file.

NVIDIA GPU Acceleration (CUDA)

To run in-process local embedding and reranker models on an NVIDIA GPU, build a custom CUDA-enabled image using the recipe in docker/docker-compose/cuda/:

docker compose -f docker/docker-compose/cuda/docker-compose.yaml up --build

The recipe upgrades in-process PyTorch to CUDA 12.6 and configures GPU passthrough via the NVIDIA Container Toolkit. Build it on the machine that will run it — an emulated cross-architecture image cannot reach the GPU.

The CUDA runtime is additive: the base image's CPU PyTorch wheel stays in the lower layers, so the result is roughly 11 GB on disk against the ~9 GB Full image. This is why no CUDA image is published — the cost is only worth paying when you actually have a GPU to use.

See docker/docker-compose/cuda/README.md for prerequisites, manual build steps, and verification.

Bundling Custom Models in a Custom Image

:::tip Production deployments with non-default local models If you use a non-default local embedder or reranker, bake the models into a custom image at build time rather than enabling the Helm modelCache PVC. See docker/docker-compose/custom-models/ for a runnable example. :::

Available Tags

# Standalone (API + Control Plane)
ghcr.io/vectorize-io/hindsight:latest        # Full, latest release
ghcr.io/vectorize-io/hindsight:latest-slim          # Slim, latest release
ghcr.io/vectorize-io/hindsight:0.4.9         # Full, specific version
ghcr.io/vectorize-io/hindsight:0.4.9-slim    # Slim, specific version

# API only
ghcr.io/vectorize-io/hindsight-api:latest
ghcr.io/vectorize-io/hindsight-api:latest-slim

# Control Plane only
ghcr.io/vectorize-io/hindsight-control-plane:latest

Verifying image signatures

Images are signed with Cosign keyless OIDC. To verify any tag:

cosign verify ghcr.io/vectorize-io/hindsight:<tag> \
  --certificate-identity-regexp '^https://github\.com/vectorize-io/hindsight/\.github/workflows/(sign-images|release)\.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Helm / Kubernetes

Best for: Production deployments, auto-scaling, cloud environments

# Install with built-in PostgreSQL
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
  --set api.llm.provider=groq \
  --set api.llm.apiKey=gsk_xxxxxxxxxxxx \
  --set postgresql.enabled=true

# Or use external PostgreSQL
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
  --set api.llm.provider=groq \
  --set api.llm.apiKey=gsk_xxxxxxxxxxxx \
  --set postgresql.enabled=false \
  --set api.database.url=postgresql://user:pass@postgres.example.com:5432/hindsight

# Install a specific version
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight --version 0.1.3

# Upgrade to latest
helm upgrade hindsight oci://ghcr.io/vectorize-io/charts/hindsight

Requirements:

  • Kubernetes cluster (GKE, EKS, AKS, or self-hosted)
  • Helm 3.8+

Distributed Workers

For high-throughput deployments, enable dedicated worker pods to scale task processing independently:

helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
  --set worker.enabled=true \
  --set worker.replicaCount=3

The chart deploys workers as a StatefulSet, so each pod gets a stable name (e.g. hindsight-worker-0) that the worker uses as its HINDSIGHT_API_WORKER_ID. Tasks claimed by a pod are recognized as its own across restarts. If you swap the chart for a plain Deployment, set HINDSIGHT_API_WORKER_ID explicitly per replica — otherwise hostnames are randomized and previously-claimed tasks become orphaned. See Admin CLI - Recovering stuck operations for diagnosis.

See Services - Worker Service for configuration details and architecture.

See the Helm chart values.yaml for all chart options.


Bare Metal (pip)

Best for: Running Hindsight as a standalone service on a host machine.

Install

pip install hindsight-api        # Full — works out of the box
pip install hindsight-api-slim   # Slim — requires external services for embeddings, reranking, and the database

When using hindsight-api-slim, you must configure external providers for all model operations. See Configuration for details.

Run with Embedded Database

For development and testing, Hindsight can run with an embedded PostgreSQL (pg0):

export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx

hindsight-api

This creates a database in ~/.hindsight/data/ and starts the API on http://localhost:8888.

Run with External PostgreSQL

For production, connect to your own PostgreSQL instance:

export HINDSIGHT_API_DATABASE_URL=postgresql://user:pass@localhost:5432/hindsight
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx

hindsight-api

Note: The database must exist and have pgvector enabled (CREATE EXTENSION vector;).

CLI Options

hindsight-api --port 9000          # Custom port (default: 8888)
hindsight-api --host 127.0.0.1     # Bind to localhost only
hindsight-api --workers 4          # Multiple worker processes
hindsight-api --log-level debug    # Verbose logging

Control Plane

The Control Plane (Web UI) can be run standalone using npx:

npx @vectorize-io/hindsight-control-plane --api-url http://localhost:8888

This connects to your running API server and provides a visual interface for managing memory banks, exploring entities, and testing queries.

Options

Option Environment Variable Default Description
-p, --port PORT 9999 Port to listen on
-H, --hostname HOSTNAME 0.0.0.0 Hostname to bind to
-a, --api-url HINDSIGHT_CP_DATAPLANE_API_URL http://localhost:8888 Hindsight API URL
HINDSIGHT_CP_ACCESS_KEY (none) Access key to protect the Control Plane UI. When set, users must enter this key to log in.

Examples

# Run on custom port
npx @vectorize-io/hindsight-control-plane --port 9999 --api-url http://localhost:8888

# Using environment variables
export HINDSIGHT_CP_DATAPLANE_API_URL=http://api.example.com
npx @vectorize-io/hindsight-control-plane

# Production deployment
PORT=80 HINDSIGHT_CP_DATAPLANE_API_URL=https://api.hindsight.io npx @vectorize-io/hindsight-control-plane

Windows

Best for: Running Hindsight natively on Windows without Docker

Hindsight works on Windows with the embedded database (pg0) out of the box — just install and run:

pip install hindsight-api

set HINDSIGHT_API_LLM_PROVIDER=openai
set HINDSIGHT_API_LLM_API_KEY=sk-xxx
set HINDSIGHT_API_LLM_MODEL=gpt-4o-mini

hindsight-api

Using External PostgreSQL (optional)

If you prefer to use your own PostgreSQL instance instead of the embedded database:

# Install PostgreSQL
winget install PostgreSQL.PostgreSQL.17

# Build pgvector (requires Visual Studio Build Tools)
git clone https://github.com/pgvector/pgvector.git
cd pgvector

# Open "x64 Native Tools Command Prompt for VS" and run:
set PGROOT=C:\Program Files\PostgreSQL\17
nmake /F Makefile.win
nmake /F Makefile.win install

# Create the database and enable the vector extension
psql -U postgres -c "CREATE DATABASE hindsight;"
psql -U postgres -d hindsight -c "CREATE EXTENSION vector;"

Then run Hindsight pointing to your database:

pip install hindsight-api

set HINDSIGHT_API_DATABASE_URL=postgresql://postgres@localhost:5432/hindsight
set HINDSIGHT_API_LLM_PROVIDER=openai
set HINDSIGHT_API_LLM_API_KEY=sk-xxx
set HINDSIGHT_API_LLM_MODEL=gpt-4o-mini

hindsight-api

:::tip You can also use the slim package (pip install hindsight-api-slim) if you configure external providers for embeddings and reranking. See Configuration for details. :::

Windows + China Network Notes

If you are running on Windows behind China network restrictions:

  1. DeepSeek works well for HINDSIGHT_API_LLM_PROVIDER, but DeepSeek does not provide an embeddings endpoint.
  2. Use local embeddings (recommended for privacy and reliability in restricted networks).
  3. Set HF_ENDPOINT=https://hf-mirror.com before starting Hindsight so Hugging Face model downloads use a China-accessible mirror.
set HF_ENDPOINT=https://hf-mirror.com

set HINDSIGHT_API_LLM_PROVIDER=deepseek
set HINDSIGHT_API_LLM_API_KEY=sk-your-deepseek-key
set HINDSIGHT_API_LLM_MODEL=deepseek-v4-flash
set HINDSIGHT_API_LLM_BASE_URL=https://api.deepseek.com

set HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
set HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5

set HINDSIGHT_API_RERANKER_PROVIDER=flashrank

hindsight-api

The HF_ENDPOINT variable is used by Hugging Face tooling (huggingface_hub), not by Hindsight itself.


Embedded in a Python Application

Best for: Using Hindsight programmatically from Python without running a separate server process.

pip install hindsight-all        # Full — works out of the box (Linux, Windows, Apple Silicon Macs)
pip install hindsight-all-slim   # Slim — requires external services for embeddings, reranking, and the database

On Intel (x86_64) Macs, install hindsight-all-slim — see Supported Platforms.

hindsight-all supports two modes of embedding:

In-process (HindsightServer): the server runs in a background thread inside your application. Best when you want the tightest integration and are already managing your own process lifecycle.

from hindsight import HindsightServer, HindsightClient

with HindsightServer(llm_provider="openai", llm_api_key="sk-xxx") as server:
    client = HindsightClient(base_url=server.url)
    client.retain(bank_id="alice", content="Alice prefers concise answers.")
    results = client.recall(bank_id="alice", query="How should I respond to Alice?")

Managed subprocess (HindsightEmbedded): the server runs as a background daemon process, shared across multiple Python processes or sessions. The daemon starts on first use and runs until it is stopped.

from hindsight import HindsightEmbedded

client = HindsightEmbedded(llm_provider="openai", llm_api_key="sk-xxx")
client.retain(bank_id="alice", content="Alice prefers concise answers.")
results = client.recall(bank_id="alice", query="How should I respond to Alice?")

See the Python SDK for the full API reference.


Next Steps