diff --git a/hindsight-api/hindsight_api/api/mcp.py b/hindsight-api/hindsight_api/api/mcp.py
index f5eacc80..7bdca74b 100644
--- a/hindsight-api/hindsight_api/api/mcp.py
+++ b/hindsight-api/hindsight_api/api/mcp.py
@@ -61,7 +61,7 @@ def create_mcp_server(memory: MemoryEngine) -> FastMCP:
"""
try:
bank_id = get_current_bank_id()
- await memory.put_batch_async(
+ await memory.retain_batch_async(
bank_id=bank_id,
contents=[{"content": content, "context": context}]
)
diff --git a/hindsight-api/hindsight_api/config.py b/hindsight-api/hindsight_api/config.py
index d320f9c3..1f3fda7c 100644
--- a/hindsight-api/hindsight_api/config.py
+++ b/hindsight-api/hindsight_api/config.py
@@ -30,6 +30,7 @@ ENV_PORT = "HINDSIGHT_API_PORT"
ENV_LOG_LEVEL = "HINDSIGHT_API_LOG_LEVEL"
ENV_MCP_ENABLED = "HINDSIGHT_API_MCP_ENABLED"
ENV_GRAPH_RETRIEVER = "HINDSIGHT_API_GRAPH_RETRIEVER"
+ENV_MCP_LOCAL_BANK_ID = "HINDSIGHT_API_MCP_LOCAL_BANK_ID"
# Default values
DEFAULT_DATABASE_URL = "pg0"
@@ -47,6 +48,7 @@ DEFAULT_PORT = 8888
DEFAULT_LOG_LEVEL = "info"
DEFAULT_MCP_ENABLED = True
DEFAULT_GRAPH_RETRIEVER = "bfs" # Options: "bfs", "mpfp"
+DEFAULT_MCP_LOCAL_BANK_ID = "mcp"
# Required embedding dimension for database schema
EMBEDDING_DIMENSION = 384
diff --git a/hindsight-api/hindsight_api/mcp_local.py b/hindsight-api/hindsight_api/mcp_local.py
new file mode 100644
index 00000000..64af70ac
--- /dev/null
+++ b/hindsight-api/hindsight_api/mcp_local.py
@@ -0,0 +1,192 @@
+"""
+Local MCP server for use with Claude Code (stdio transport).
+
+This runs a fully local Hindsight instance with embedded PostgreSQL (pg0).
+No external database or server required.
+
+Run with:
+ hindsight-local-mcp
+
+Or with uvx:
+ uvx hindsight-api@latest hindsight-local-mcp
+
+Configure in Claude Code's MCP settings:
+ {
+ "mcpServers": {
+ "hindsight": {
+ "command": "uvx",
+ "args": ["hindsight-api@latest", "hindsight-local-mcp"],
+ "env": {
+ "HINDSIGHT_API_LLM_API_KEY": "your-openai-key"
+ }
+ }
+ }
+ }
+
+Environment variables:
+ HINDSIGHT_API_LLM_API_KEY: Required. API key for LLM provider.
+ HINDSIGHT_API_LLM_PROVIDER: Optional. LLM provider (default: "openai").
+ HINDSIGHT_API_LLM_MODEL: Optional. LLM model (default: "gpt-4o-mini").
+ HINDSIGHT_API_MCP_LOCAL_BANK_ID: Optional. Memory bank ID (default: "mcp").
+ HINDSIGHT_API_LOG_LEVEL: Optional. Log level (default: "info").
+"""
+
+import logging
+import os
+import sys
+
+from mcp.server.fastmcp import FastMCP
+
+from hindsight_api.config import (
+ ENV_MCP_LOCAL_BANK_ID,
+ DEFAULT_MCP_LOCAL_BANK_ID,
+)
+
+# Configure logging - default to info
+_log_level_str = os.environ.get("HINDSIGHT_API_LOG_LEVEL", "info").lower()
+_log_level_map = {
+ "critical": logging.CRITICAL,
+ "error": logging.ERROR,
+ "warning": logging.WARNING,
+ "info": logging.INFO,
+ "debug": logging.DEBUG,
+}
+logging.basicConfig(
+ level=_log_level_map.get(_log_level_str, logging.WARNING),
+ format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
+ stream=sys.stderr, # MCP uses stdout for protocol, logs go to stderr
+)
+logger = logging.getLogger(__name__)
+
+
+def create_local_mcp_server(bank_id: str, memory=None) -> FastMCP:
+ """
+ Create a stdio MCP server with retain/recall tools.
+
+ Args:
+ bank_id: The memory bank ID to use for all operations.
+ memory: Optional MemoryEngine instance. If not provided, creates one with pg0.
+
+ Returns:
+ Configured FastMCP server instance.
+ """
+ # Import here to avoid slow startup if just checking --help
+ from hindsight_api import MemoryEngine
+ from hindsight_api.engine.memory_engine import Budget
+ from hindsight_api.engine.response_models import VALID_RECALL_FACT_TYPES
+
+ # Create memory engine with pg0 embedded database if not provided
+ if memory is None:
+ memory = MemoryEngine(db_url="pg0://hindsight-mcp")
+
+ mcp = FastMCP("hindsight")
+
+ @mcp.tool()
+ async def retain(content: str, context: str = "general") -> dict:
+ """
+ Store important information to long-term memory.
+
+ Use this tool PROACTIVELY whenever the user shares:
+ - Personal facts, preferences, or interests
+ - Important events or milestones
+ - User history, experiences, or background
+ - Decisions, opinions, or stated preferences
+ - Goals, plans, or future intentions
+ - Relationships or people mentioned
+ - Work context, projects, or responsibilities
+
+ Args:
+ content: The fact/memory to store (be specific and include relevant details)
+ context: Category for the memory (e.g., 'preferences', 'work', 'hobbies', 'family'). Default: 'general'
+ """
+ import asyncio
+
+ async def _retain():
+ try:
+ await memory.retain_batch_async(
+ bank_id=bank_id,
+ contents=[{"content": content, "context": context}]
+ )
+ except Exception as e:
+ logger.error(f"Error storing memory: {e}", exc_info=True)
+
+ # Fire and forget - don't block on memory storage
+ asyncio.create_task(_retain())
+ return {"status": "accepted", "message": "Memory storage initiated"}
+
+ @mcp.tool()
+ async def recall(query: str, max_tokens: int = 4096, budget: str = "low") -> dict:
+ """
+ Search memories to provide personalized, context-aware responses.
+
+ Use this tool PROACTIVELY to:
+ - Check user's preferences before making suggestions
+ - Recall user's history to provide continuity
+ - Remember user's goals and context
+ - Personalize responses based on past interactions
+
+ Args:
+ query: Natural language search query (e.g., "user's food preferences", "what projects is user working on")
+ max_tokens: Maximum tokens to return in results (default: 4096)
+ budget: Search budget level - "low", "mid", or "high" (default: "low")
+ """
+ try:
+ # Map string budget to enum
+ budget_map = {"low": Budget.LOW, "mid": Budget.MID, "high": Budget.HIGH}
+ budget_enum = budget_map.get(budget.lower(), Budget.LOW)
+
+ search_result = await memory.recall_async(
+ bank_id=bank_id,
+ query=query,
+ fact_type=list(VALID_RECALL_FACT_TYPES),
+ budget=budget_enum,
+ max_tokens=max_tokens
+ )
+
+ return search_result.model_dump()
+ except Exception as e:
+ logger.error(f"Error searching: {e}", exc_info=True)
+ return {"error": str(e), "results": []}
+
+ return mcp
+
+
+async def _initialize_and_run(bank_id: str):
+ """Initialize memory and run the MCP server."""
+ from hindsight_api import MemoryEngine
+
+ # Create and initialize memory engine with pg0 embedded database
+ print("Initializing memory engine...", file=sys.stderr)
+ memory = MemoryEngine(db_url="pg0://hindsight-mcp")
+ await memory.initialize()
+ print("Memory engine initialized.", file=sys.stderr)
+
+ # Create and run the server
+ mcp = create_local_mcp_server(bank_id, memory=memory)
+ await mcp.run_stdio_async()
+
+
+def main():
+ """Main entry point for the stdio MCP server."""
+ import asyncio
+ from hindsight_api.config import get_config, ENV_LLM_API_KEY
+
+ # Check for required environment variables
+ config = get_config()
+ if not config.llm_api_key:
+ print(f"Error: {ENV_LLM_API_KEY} environment variable is required", file=sys.stderr)
+ print("Set it in your MCP configuration or shell environment", file=sys.stderr)
+ sys.exit(1)
+
+ # Get bank ID from environment, default to "mcp"
+ bank_id = os.environ.get(ENV_MCP_LOCAL_BANK_ID, DEFAULT_MCP_LOCAL_BANK_ID)
+
+ # Print startup message to stderr (stdout is reserved for MCP protocol)
+ print(f"Hindsight MCP server starting (bank_id={bank_id})...", file=sys.stderr)
+
+ # Run the async initialization and server
+ asyncio.run(_initialize_and_run(bank_id))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/hindsight-api/hindsight_api/pg0.py b/hindsight-api/hindsight_api/pg0.py
index 1dc7ff6e..7f22853b 100644
--- a/hindsight-api/hindsight_api/pg0.py
+++ b/hindsight-api/hindsight_api/pg0.py
@@ -6,7 +6,6 @@ from pg0 import Pg0
logger = logging.getLogger(__name__)
-DEFAULT_PORT = 5555
DEFAULT_USERNAME = "hindsight"
DEFAULT_PASSWORD = "hindsight"
DEFAULT_DATABASE = "hindsight"
@@ -17,14 +16,14 @@ class EmbeddedPostgres:
def __init__(
self,
- port: int = DEFAULT_PORT,
+ port: Optional[int] = None,
username: str = DEFAULT_USERNAME,
password: str = DEFAULT_PASSWORD,
database: str = DEFAULT_DATABASE,
name: str = "hindsight",
**kwargs,
):
- self.port = port
+ self.port = port # None means pg0 will auto-assign
self.username = username
self.password = password
self.database = database
@@ -33,18 +32,22 @@ class EmbeddedPostgres:
def _get_pg0(self) -> Pg0:
if self._pg0 is None:
- self._pg0 = Pg0(
- name=self.name,
- port=self.port,
- username=self.username,
- password=self.password,
- database=self.database,
- )
+ kwargs = {
+ "name": self.name,
+ "username": self.username,
+ "password": self.password,
+ "database": self.database,
+ }
+ # Only set port if explicitly specified
+ if self.port is not None:
+ kwargs["port"] = self.port
+ self._pg0 = Pg0(**kwargs)
return self._pg0
async def start(self, max_retries: int = 3, retry_delay: float = 2.0) -> str:
"""Start the PostgreSQL server with retry logic."""
- logger.info(f"Starting embedded PostgreSQL (name: {self.name}, port: {self.port})...")
+ port_info = f"port={self.port}" if self.port else "port=auto"
+ logger.info(f"Starting embedded PostgreSQL (name={self.name}, {port_info})...")
pg0 = self._get_pg0()
last_error = None
@@ -53,9 +56,9 @@ class EmbeddedPostgres:
try:
loop = asyncio.get_event_loop()
info = await loop.run_in_executor(None, pg0.start)
- logger.info(f"PostgreSQL started on port {self.port}")
- # Construct URI manually since pg0-embedded may return None
- uri = info.uri if info and info.uri else f"postgresql://{self.username}:{self.password}@localhost:{self.port}/{self.database}"
+ # Get URI from pg0 (includes auto-assigned port)
+ uri = info.uri
+ logger.info(f"PostgreSQL started: {uri}")
return uri
except Exception as e:
last_error = str(e)
@@ -91,9 +94,7 @@ class EmbeddedPostgres:
pg0 = self._get_pg0()
loop = asyncio.get_event_loop()
info = await loop.run_in_executor(None, pg0.info)
- # Construct URI manually since pg0-embedded may return None
- uri = info.uri if info and info.uri else f"postgresql://{self.username}:{self.password}@localhost:{self.port}/{self.database}"
- return uri
+ return info.uri
async def is_running(self) -> bool:
"""Check if the PostgreSQL server is currently running."""
diff --git a/hindsight-api/pyproject.toml b/hindsight-api/pyproject.toml
index 733d2d09..b791dd10 100644
--- a/hindsight-api/pyproject.toml
+++ b/hindsight-api/pyproject.toml
@@ -50,6 +50,7 @@ test = [
[project.scripts]
hindsight-api = "hindsight_api.main:main"
+hindsight-local-mcp = "hindsight_api.mcp_local:main"
[tool.hatch.build.targets.wheel]
packages = ["hindsight_api"]
diff --git a/hindsight-api/tests/test_mcp_local.py b/hindsight-api/tests/test_mcp_local.py
new file mode 100644
index 00000000..1ccc3cba
--- /dev/null
+++ b/hindsight-api/tests/test_mcp_local.py
@@ -0,0 +1,162 @@
+"""Test local MCP server."""
+
+import asyncio
+import pytest
+from unittest.mock import AsyncMock, MagicMock
+
+
+@pytest.fixture
+def mock_memory():
+ """Create a mock MemoryEngine."""
+ memory = MagicMock()
+ memory._initialized = True
+ memory.retain_batch_async = AsyncMock()
+ memory.recall_async = AsyncMock(return_value=MagicMock(results=[]))
+ return memory
+
+
+@pytest.mark.asyncio
+async def test_local_mcp_server_retain(mock_memory):
+ """Test that retain tool fires async and returns immediately."""
+ from hindsight_api.mcp_local import create_local_mcp_server
+
+ bank_id = "test-bank"
+ mcp_server = create_local_mcp_server(bank_id, memory=mock_memory)
+
+ # Get the tools
+ tools = mcp_server._tool_manager._tools
+ assert "retain" in tools
+
+ # Call retain
+ retain_tool = tools["retain"]
+ result = await retain_tool.fn(content="test content", context="test_context")
+
+ # Returns immediately with accepted status
+ assert result["status"] == "accepted"
+
+ # Wait for background task to complete
+ await asyncio.sleep(0.1)
+
+ # Verify the memory was called correctly
+ mock_memory.retain_batch_async.assert_called_once()
+ call_kwargs = mock_memory.retain_batch_async.call_args.kwargs
+ assert call_kwargs["bank_id"] == "test-bank"
+ assert call_kwargs["contents"] == [{"content": "test content", "context": "test_context"}]
+
+
+@pytest.mark.asyncio
+async def test_local_mcp_server_recall(mock_memory):
+ """Test that recall tool calls memory.recall_async with correct params."""
+ from hindsight_api.mcp_local import create_local_mcp_server
+ from hindsight_api.engine.memory_engine import Budget
+
+ # Mock recall_async to return a proper pydantic model
+ mock_result = MagicMock()
+ mock_result.model_dump.return_value = {"results": []}
+ mock_memory.recall_async = AsyncMock(return_value=mock_result)
+
+ bank_id = "test-bank"
+ mcp_server = create_local_mcp_server(bank_id, memory=mock_memory)
+
+ # Get the tools
+ tools = mcp_server._tool_manager._tools
+ assert "recall" in tools
+
+ # Call recall with new params
+ recall_tool = tools["recall"]
+ result = await recall_tool.fn(query="test query", max_tokens=2048, budget="mid")
+
+ # Result is a dict
+ assert isinstance(result, dict)
+
+ # Verify the memory was called correctly
+ mock_memory.recall_async.assert_called_once()
+ call_kwargs = mock_memory.recall_async.call_args.kwargs
+ assert call_kwargs["bank_id"] == "test-bank"
+ assert call_kwargs["query"] == "test query"
+ assert call_kwargs["max_tokens"] == 2048
+ assert call_kwargs["budget"] == Budget.MID
+
+
+@pytest.mark.asyncio
+async def test_local_mcp_server_retain_with_default_context(mock_memory):
+ """Test that retain uses default context when not provided."""
+ from hindsight_api.mcp_local import create_local_mcp_server
+
+ bank_id = "test-bank"
+ mcp_server = create_local_mcp_server(bank_id, memory=mock_memory)
+
+ tools = mcp_server._tool_manager._tools
+ retain_tool = tools["retain"]
+
+ # Call retain without context
+ await retain_tool.fn(content="test content")
+
+ # Wait for background task
+ await asyncio.sleep(0.1)
+
+ call_kwargs = mock_memory.retain_batch_async.call_args.kwargs
+ assert call_kwargs["contents"] == [{"content": "test content", "context": "general"}]
+
+
+@pytest.mark.asyncio
+async def test_local_mcp_server_retain_error_handling(mock_memory):
+ """Test that retain errors are logged but don't affect response."""
+ from hindsight_api.mcp_local import create_local_mcp_server
+
+ mock_memory.retain_batch_async = AsyncMock(side_effect=Exception("Test error"))
+
+ mcp_server = create_local_mcp_server("test-bank", memory=mock_memory)
+
+ tools = mcp_server._tool_manager._tools
+ retain_tool = tools["retain"]
+
+ # Retain returns immediately with accepted status (fire and forget)
+ result = await retain_tool.fn(content="test content")
+ assert result["status"] == "accepted"
+
+ # Wait for background task to complete (and log error)
+ await asyncio.sleep(0.1)
+
+
+@pytest.mark.asyncio
+async def test_local_mcp_server_recall_error_handling(mock_memory):
+ """Test that recall handles errors gracefully."""
+ from hindsight_api.mcp_local import create_local_mcp_server
+
+ mock_memory.recall_async = AsyncMock(side_effect=Exception("Test error"))
+
+ mcp_server = create_local_mcp_server("test-bank", memory=mock_memory)
+
+ tools = mcp_server._tool_manager._tools
+ recall_tool = tools["recall"]
+
+ result = await recall_tool.fn(query="test query")
+
+ # Result is a dict with error
+ assert isinstance(result, dict)
+ assert "error" in result
+ assert result["results"] == []
+
+
+@pytest.mark.asyncio
+async def test_local_mcp_server_recall_with_defaults(mock_memory):
+ """Test that recall uses default max_tokens and budget."""
+ from hindsight_api.mcp_local import create_local_mcp_server
+ from hindsight_api.engine.memory_engine import Budget
+
+ mock_result = MagicMock()
+ mock_result.model_dump.return_value = {"results": []}
+ mock_memory.recall_async = AsyncMock(return_value=mock_result)
+
+ mcp_server = create_local_mcp_server("test-bank", memory=mock_memory)
+
+ tools = mcp_server._tool_manager._tools
+ recall_tool = tools["recall"]
+
+ # Call with defaults
+ await recall_tool.fn(query="test query")
+
+ call_kwargs = mock_memory.recall_async.call_args.kwargs
+ assert call_kwargs["max_tokens"] == 4096
+ assert call_kwargs["budget"] == Budget.LOW
diff --git a/hindsight-api/tests/test_mcp_routing.py b/hindsight-api/tests/test_mcp_routing.py
index a64e29d2..dd7c385f 100644
--- a/hindsight-api/tests/test_mcp_routing.py
+++ b/hindsight-api/tests/test_mcp_routing.py
@@ -8,7 +8,7 @@ from unittest.mock import AsyncMock, MagicMock
def mock_memory():
"""Create a mock MemoryEngine."""
memory = MagicMock()
- memory.put_batch_async = AsyncMock()
+ memory.retain_batch_async = AsyncMock()
memory.recall_async = AsyncMock(return_value=MagicMock(results=[]))
return memory
@@ -52,8 +52,8 @@ async def test_mcp_tools_use_context_bank_id(mock_memory):
assert "successfully" in result.lower()
# Verify the memory was called with the context bank_id
- mock_memory.put_batch_async.assert_called_once()
- call_kwargs = mock_memory.put_batch_async.call_args.kwargs
+ mock_memory.retain_batch_async.assert_called_once()
+ call_kwargs = mock_memory.retain_batch_async.call_args.kwargs
assert call_kwargs["bank_id"] == "context-bank-id"
finally:
_current_bank_id.reset(token)
diff --git a/hindsight-docs/docs/sdks/integrations/local-mcp.md b/hindsight-docs/docs/sdks/integrations/local-mcp.md
new file mode 100644
index 00000000..d0be4e94
--- /dev/null
+++ b/hindsight-docs/docs/sdks/integrations/local-mcp.md
@@ -0,0 +1,199 @@
+---
+sidebar_position: 2
+---
+
+# Local MCP Server
+
+Hindsight provides a fully local MCP server that runs entirely on your machine with an embedded PostgreSQL database. No external server or database setup required.
+
+This is ideal for:
+- **Personal use with Claude Code** — Give Claude long-term memory across conversations
+- **Development and testing** — Quick setup without infrastructure
+- **Privacy-focused setups** — All data stays on your machine
+
+## Quick Start
+
+### With uvx (recommended)
+
+```bash
+uvx hindsight-api@latest hindsight-local-mcp
+```
+
+### With pip
+
+```bash
+pip install hindsight-api
+hindsight-local-mcp
+```
+
+## Claude Code Configuration
+
+Add to your Claude Code MCP settings (`~/.claude/claude_desktop_config.json`):
+
+```json
+{
+ "mcpServers": {
+ "hindsight": {
+ "command": "uvx",
+ "args": ["hindsight-api@latest", "hindsight-local-mcp"],
+ "env": {
+ "HINDSIGHT_API_LLM_API_KEY": "your-openai-key"
+ }
+ }
+ }
+}
+```
+
+### With Custom Bank ID
+
+By default, memories are stored in a bank called `mcp`. To use a different bank:
+
+```json
+{
+ "mcpServers": {
+ "hindsight": {
+ "command": "uvx",
+ "args": ["hindsight-api@latest", "hindsight-local-mcp"],
+ "env": {
+ "HINDSIGHT_API_LLM_API_KEY": "your-openai-key",
+ "HINDSIGHT_API_MCP_LOCAL_BANK_ID": "my-personal-memory"
+ }
+ }
+ }
+}
+```
+
+## Environment Variables
+
+| Variable | Required | Default | Description |
+|----------|----------|---------|-------------|
+| `HINDSIGHT_API_LLM_API_KEY` | Yes | - | API key for the LLM provider |
+| `HINDSIGHT_API_LLM_PROVIDER` | No | `openai` | LLM provider (`openai`, `groq`, `anthropic`) |
+| `HINDSIGHT_API_LLM_MODEL` | No | `gpt-4o-mini` | Model to use for fact extraction |
+| `HINDSIGHT_API_MCP_LOCAL_BANK_ID` | No | `mcp` | Memory bank ID |
+| `HINDSIGHT_API_LOG_LEVEL` | No | `info` | Log level (`debug`, `info`, `warning`, `error`) |
+
+## Available Tools
+
+### retain
+
+Store information to long-term memory. This is a **fire-and-forget** operation — it returns immediately while processing happens in the background.
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `content` | string | Yes | The fact or memory to store |
+| `context` | string | No | Category for the memory (default: `general`) |
+
+**Example:**
+```json
+{
+ "name": "retain",
+ "arguments": {
+ "content": "User's favorite color is blue",
+ "context": "preferences"
+ }
+}
+```
+
+**Response:**
+```json
+{
+ "status": "accepted",
+ "message": "Memory storage initiated"
+}
+```
+
+### recall
+
+Search memories to provide personalized responses.
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `query` | string | Yes | Natural language search query |
+| `max_tokens` | integer | No | Maximum tokens to return (default: 4096) |
+| `budget` | string | No | Search depth: `low`, `mid`, or `high` (default: `low`) |
+
+**Example:**
+```json
+{
+ "name": "recall",
+ "arguments": {
+ "query": "What are the user's color preferences?",
+ "max_tokens": 2048,
+ "budget": "mid"
+ }
+}
+```
+
+**Response:**
+```json
+{
+ "results": [
+ {
+ "id": "...",
+ "text": "User's favorite color is blue",
+ "fact_type": "world",
+ "context": "preferences",
+ "event_date": null,
+ "score": 0.95
+ }
+ ],
+ "total_tokens": 42
+}
+```
+
+## How It Works
+
+The local MCP server:
+
+1. **Starts an embedded PostgreSQL** (pg0) on an automatically assigned port
+2. **Initializes the Hindsight memory engine** with local embeddings
+3. **Connects via stdio** to Claude Code using the MCP protocol
+
+Data is persisted in the pg0 data directory (`~/.pg0/hindsight-mcp/`), so your memories survive restarts.
+
+## Comparison: Local vs Server MCP
+
+| Feature | Local MCP | Server MCP |
+|---------|-----------|------------|
+| Setup | Zero config | Requires running server |
+| Database | Embedded (pg0) | External PostgreSQL |
+| Multi-user | Single user | Multi-tenant |
+| Scalability | Single machine | Horizontally scalable |
+| Use case | Personal/development | Production/teams |
+
+## Troubleshooting
+
+### "HINDSIGHT_API_LLM_API_KEY required"
+
+Make sure you've set the API key in your MCP configuration:
+
+```json
+{
+ "env": {
+ "HINDSIGHT_API_LLM_API_KEY": "sk-..."
+ }
+}
+```
+
+### Slow startup
+
+The first startup may take longer as it:
+- Downloads the embedding model (~100MB)
+- Initializes the PostgreSQL database
+
+Subsequent starts are faster.
+
+### Checking logs
+
+Set `HINDSIGHT_API_LOG_LEVEL=debug` for verbose output:
+
+```json
+{
+ "env": {
+ "HINDSIGHT_API_LOG_LEVEL": "debug"
+ }
+}
+```
+
+Logs are written to stderr and visible in Claude Code's MCP server output.
diff --git a/hindsight-docs/static/llms-full.txt b/hindsight-docs/static/llms-full.txt
index 9ff96c3d..e69de29b 100644
--- a/hindsight-docs/static/llms-full.txt
+++ b/hindsight-docs/static/llms-full.txt
@@ -1,5212 +0,0 @@
-# Hindsight Documentation
-
-> Agent Memory that Works Like Human Memory
-
-This file contains the complete Hindsight documentation for LLM consumption.
-Generated: 2025-12-15T13:52:15.559Z
-
----
-
-
-## File: developer/index.md
-
-# Overview
-
-## Why Hindsight?
-
-AI agents forget everything between sessions. Every conversation starts from zero—no context about who you are, what you've discussed, or what the assistant has learned. This isn't just an implementation detail; it fundamentally limits what AI Agents can do.
-
-**The problem is harder than it looks:**
-
-- **Simple vector search isn't enough** — "What did Alice do last spring?" requires temporal reasoning, not just semantic similarity
-- **Facts get disconnected** — Knowing "Alice works at Google" and "Google is in Mountain View" should let you answer "Where does Alice work?" even if you never stored that directly
-- **AI Agents needs to form opinions** — A coding assistant that remembers "the user prefers functional programming" should weigh that when making recommendations
-- **Context matters** — The same information means different things to different memory banks with different personalities
-
-Hindsight solves these problems with a memory system designed specifically for AI agents.
-
-## What Hindsight Does
-
-```mermaid
-graph TB
- subgraph app["Your Application"]
- Agent[AI Agent]
- end
-
- subgraph hindsight["Hindsight"]
- API[API Server]
-
- subgraph bank["Memory Bank"]
- Documents[Documents]
- Memories[Memories]
- Entities[Entities]
- end
- end
-
- Agent -->|retain| API
- Agent -->|recall| API
- Agent -->|reflect| API
-
- API --> Documents
- API --> Memories
- API --> Entities
-```
-
-**Your AI agent** stores information via `retain()`, searches with `recall()`, and reasons with `reflect()` — all interactions with its dedicated **memory bank**
-
-## Key Components
-
-### Three Memory Types
-
-Hindsight separates memories by type for epistemic clarity:
-
-| Type | What it stores | Example |
-|------|----------------|---------|
-| **World** | Objective facts received | "Alice works at Google" |
-| **Bank** | Bank's own actions | "I recommended Python to Bob" |
-| **Opinion** | Formed beliefs + confidence | "Python is best for ML" (0.85) |
-
-### Multi-Strategy Retrieval (TEMPR)
-
-Four search strategies run in parallel:
-
-```mermaid
-graph LR
- Q[Query] --> S[Semantic]
- Q --> K[Keyword]
- Q --> G[Graph]
- Q --> T[Temporal]
-
- S --> RRF[RRF Fusion]
- K --> RRF
- G --> RRF
- T --> RRF
-
- RRF --> CE[Cross-Encoder]
- CE --> R[Results]
-```
-
-| Strategy | Best for |
-|----------|----------|
-| **Semantic** | Conceptual similarity, paraphrasing |
-| **Keyword (BM25)** | Names, technical terms, exact matches |
-| **Graph** | Related entities, indirect connections |
-| **Temporal** | "last spring", "in June", time ranges |
-
-### Disposition Traits
-
-Memory banks have disposition traits that influence how opinions are formed during Reflect:
-
-| Trait | Scale | Low (1) | High (5) |
-|-------|-------|---------|----------|
-| **Skepticism** | 1-5 | Trusting | Skeptical |
-| **Literalism** | 1-5 | Flexible interpretation | Literal interpretation |
-| **Empathy** | 1-5 | Detached | Empathetic |
-
-These traits only affect the `reflect` operation, not `recall`.
-
-## Next Steps
-
-### Getting Started
-- [**Quick Start**](/developer/api/quickstart) — Install and get up and running in 60 seconds
-- [**RAG vs Hindsight**](/developer/rag-vs-hindsight) — See how Hindsight differs from traditional RAG with real examples
-
-### Core Concepts
-- [**Retain**](/developer/retain) — How memories are stored with multi-dimensional facts
-- [**Recall**](/developer/retrieval) — How TEMPR's 4-way search retrieves memories
-- [**Reflect**](/developer/reflect) — How disposition influences reasoning and opinion formation
-
-### API Methods
-- [**Retain**](/developer/api/retain) — Store information in memory banks
-- [**Recall**](/developer/api/recall) — Search and retrieve memories
-- [**Reflect**](/developer/api/reflect) — Reason with disposition
-- [**Memory Banks**](/developer/api/memory-banks) — Configure disposition and background
-- [**Entities**](/developer/api/entities) — Track people, places, and concepts
-- [**Documents**](/developer/api/documents) — Manage document sources
-- [**Operations**](/developer/api/operations) — Monitor async tasks
-
-### Deployment
-- [**Server Setup**](/developer/installation) — Deploy with Docker Compose, Helm, or pip
-
-
----
-
-
-## File: developer/api/quickstart.md
-
-# Quick Start
-
-Get up and running with Hindsight in 60 seconds.
-
-
-
-
-## Start the API Server
-
-
-
-
-```bash
-pip install hindsight-api
-export OPENAI_API_KEY=sk-xxx
-export HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY
-
-hindsight-api
-```
-
-API available at http://localhost:8888
-
-
-
-
-```bash
-
-export OPENAI_API_KEY=sk-xxx
-
-docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
- -e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
- -v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
- ghcr.io/vectorize-io/hindsight:latest
-```
-
-- **API**: http://localhost:8888
-- **Control Plane** (Web UI): http://localhost:9999
-
-
-
-
-:::tip LLM Provider
-Hindsight requires an LLM with structured output support. Recommended: **Groq** with `gpt-oss-20b` for fast, cost-effective inference.
-See [LLM Providers](/developer/models#llm) for more details.
-:::
-
----
-
-## Use the Client
-
-
-
-
-```bash
-pip install hindsight-client
-```
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(base_url="http://localhost:8888")
-
-# Retain: Store information
-client.retain(bank_id="my-bank", content="Alice works at Google as a software engineer")
-
-# Recall: Search memories
-client.recall(bank_id="my-bank", query="What does Alice do?")
-
-# Reflect: Generate disposition-aware response
-client.reflect(bank_id="my-bank", query="Tell me about Alice")
-```
-
-
-
-
-```bash
-npm install @vectorize-io/hindsight-client
-```
-
-```javascript
-const { HindsightClient } = require('@vectorize-io/hindsight-client');
-
-const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
-
-// Retain: Store information
-await client.retain('my-bank', 'Alice works at Google as a software engineer');
-
-// Recall: Search memories
-await client.recall('my-bank', 'What does Alice do?');
-
-// Reflect: Generate response
-await client.reflect('my-bank', 'Tell me about Alice');
-```
-
-
-
-
-```bash
-curl -fsSL https://hindsight.vectorize.io/get-cli | bash
-```
-
-```bash
-# Retain: Store information
-hindsight memory retain my-bank "Alice works at Google as a software engineer"
-
-# Recall: Search memories
-hindsight memory recall my-bank "What does Alice do?"
-
-# Reflect: Generate response
-hindsight memory reflect my-bank "Tell me about Alice"
-```
-
-
-
-
----
-
-## What's Happening
-
-| Operation | What it does |
-|-----------|--------------|
-| **Retain** | Content is processed, facts are extracted, entities are identified and linked in a knowledge graph |
-| **Recall** | Four search strategies (semantic, keyword, graph, temporal) run in parallel to find relevant memories |
-| **Reflect** | Retrieved memories are used to generate a disposition-aware response |
-
----
-
-## Next Steps
-
-- [**Retain**](./retain) — Advanced options for storing memories
-- [**Recall**](./recall) — Search and retrieval strategies
-- [**Reflect**](./reflect) — Disposition-aware reasoning
-- [**Memory Banks**](./memory-banks) — Configure disposition and background
-- [**Server Deployment**](/developer/installation) — Docker Compose, Helm, and production setup
-
-
----
-
-
-## File: developer/api/main-methods.md
-
-# Main Methods
-
-Hindsight provides three core operations: **retain**, **recall**, and **reflect**.
-
-
-
-
-:::tip Prerequisites
-Make sure you've [installed Hindsight](../installation) and completed the [Quick Start](./quickstart).
-:::
-
-## Retain: Store Information
-
-Store conversations, documents, and facts into a memory bank.
-
-
-
-
-```python
-# Store a single fact
-client.retain(
- bank_id="my-bank",
- content="Alice joined Google in March 2024 as a Senior ML Engineer"
-)
-
-# Store a conversation
-conversation = """
-User: What did you work on today?
-Assistant: I reviewed the new ML pipeline architecture.
-User: How did it look?
-Assistant: Promising, but needs better error handling.
-"""
-
-client.retain(
- bank_id="my-bank",
- content=conversation,
- context="Daily standup conversation"
-)
-
-# Batch retain multiple items
-client.retain_batch(
- bank_id="my-bank",
- contents=[
- {"content": "Bob prefers Python for data science"},
- {"content": "Alice recommends using pytest for testing"},
- {"content": "The team uses GitHub for code reviews"}
- ]
-)
-```
-
-
-
-
-```javascript
-// Store a single fact
-await client.retain({
- bankId: 'my-bank',
- content: 'Alice joined Google in March 2024 as a Senior ML Engineer'
-});
-
-// Store a conversation
-await client.retain({
- bankId: 'my-bank',
- content: `
-User: What did you work on today?
-Assistant: I reviewed the new ML pipeline architecture.
-User: How did it look?
-Assistant: Promising, but needs better error handling.
- `,
- context: 'Daily standup conversation'
-});
-
-// Batch retain
-await client.retainBatch({
- bankId: 'my-bank',
- contents: [
- { content: 'Bob prefers Python for data science' },
- { content: 'Alice recommends using pytest for testing' },
- { content: 'The team uses GitHub for code reviews' }
- ]
-});
-```
-
-
-
-
-```bash
-# Store a single fact
-hindsight retain my-bank "Alice joined Google in March 2024 as a Senior ML Engineer"
-
-# Store from a file
-hindsight retain my-bank --file conversation.txt --context "Daily standup"
-
-# Store multiple files
-hindsight retain my-bank --files docs/*.md
-```
-
-
-
-
-**What happens:** Content is processed by an LLM to extract rich facts, identify entities, and build connections in a knowledge graph.
-
-**See:** [Retain Details](./retain) for advanced options and parameters.
-
----
-
-## Recall: Search Memories
-
-Search for relevant memories using multi-strategy retrieval.
-
-
-
-
-```python
-# Basic search
-results = client.recall(
- bank_id="my-bank",
- query="What does Alice do at Google?"
-)
-
-for result in results:
- print(f"[{result['weight']:.2f}] {result['text']}")
-
-# Search with options
-results = client.recall(
- bank_id="my-bank",
- query="What happened last spring?",
- budget="high", # More thorough graph traversal
- max_tokens=8192, # Return more context
- fact_type="world" # Only world facts
-)
-
-# Include entity information
-results = client.recall(
- bank_id="my-bank",
- query="Tell me about Alice",
- include_entities=True,
- max_entity_tokens=500
-)
-
-# Check entity details
-for entity in results["entities"]:
- print(f"Entity: {entity['name']}")
- print(f"Observations: {entity['observations']}")
-```
-
-
-
-
-```javascript
-// Basic search
-const results = await client.recall({
- bankId: 'my-bank',
- query: 'What does Alice do at Google?'
-});
-
-results.forEach(r => {
- console.log(`[${r.weight.toFixed(2)}] ${r.text}`);
-});
-
-// Search with options
-const detailedResults = await client.recall({
- bankId: 'my-bank',
- query: 'What happened last spring?',
- budget: 'high',
- maxTokens: 8192,
- factType: 'world'
-});
-
-// Include entity information
-const withEntities = await client.recall({
- bankId: 'my-bank',
- query: 'Tell me about Alice',
- includeEntities: true,
- maxEntityTokens: 500
-});
-```
-
-
-
-
-```bash
-# Basic search
-hindsight recall my-bank "What does Alice do at Google?"
-
-# Search with options
-hindsight recall my-bank "What happened last spring?" \
- --budget high \
- --max-tokens 8192 \
- --fact-type world
-
-# Verbose output (shows weights and sources)
-hindsight recall my-bank "Tell me about Alice" -v
-```
-
-
-
-
-**What happens:** Four search strategies (semantic, keyword, graph, temporal) run in parallel, results are fused and reranked.
-
-**See:** [Recall Details](./recall) for tuning quality vs latency.
-
----
-
-## Reflect: Reason with Disposition
-
-Generate disposition-aware responses that form opinions based on evidence.
-
-
-
-
-```python
-# Basic reflect
-response = client.reflect(
- bank_id="my-bank",
- query="Should we adopt TypeScript for our backend?"
-)
-
-print(response["text"])
-print("\nBased on:", len(response["based_on"]["world"]), "facts")
-print("New opinions:", len(response["new_opinions"]))
-
-# Reflect with options
-response = client.reflect(
- bank_id="my-bank",
- query="What are Alice's strengths for the team lead role?",
- budget="high", # More thorough reasoning
- include_entities=True
-)
-
-# Access formed opinions
-for opinion in response["new_opinions"]:
- print(f"Opinion: {opinion['text']}")
- print(f"Confidence: {opinion['confidence']}")
-
-# See which facts influenced the response
-for fact in response["based_on"]["world"]:
- print(f"[{fact['weight']:.2f}] {fact['text']}")
-```
-
-
-
-
-```javascript
-// Basic reflect
-const response = await client.reflect({
- bankId: 'my-bank',
- query: 'Should we adopt TypeScript for our backend?'
-});
-
-console.log(response.text);
-console.log(`\nBased on: ${response.basedOn.world.length} facts`);
-console.log(`New opinions: ${response.newOpinions.length}`);
-
-// Reflect with options
-const detailed = await client.reflect({
- bankId: 'my-bank',
- query: "What are Alice's strengths for the team lead role?",
- budget: 'high',
- includeEntities: true
-});
-
-// Access formed opinions
-detailed.newOpinions.forEach(op => {
- console.log(`Opinion: ${op.text}`);
- console.log(`Confidence: ${op.confidence}`);
-});
-```
-
-
-
-
-```bash
-# Basic reflect
-hindsight reflect my-bank "Should we adopt TypeScript for our backend?"
-
-# Verbose output (shows sources and opinions)
-hindsight reflect my-bank "What are Alice's strengths for the team lead role?" -v
-
-# With higher reasoning budget
-hindsight reflect my-bank "Analyze our tech stack" --budget high
-```
-
-
-
-
-**What happens:** Memories are recalled, bank disposition is loaded, LLM reasons through evidence, new opinions are formed and stored.
-
-**See:** [Reflect Details](./reflect) for disposition configuration.
-
----
-
-## Comparison
-
-| Feature | Retain | Recall | Reflect |
-|---------|--------|--------|---------|
-| **Purpose** | Store information | Find information | Reason about information |
-| **Input** | Raw text/documents | Search query | Question/prompt |
-| **Output** | Memory IDs | Ranked facts | Reasoned response + opinions |
-| **Uses LLM** | Yes (extraction) | No | Yes (generation) |
-| **Forms opinions** | No | No | Yes |
-| **Disposition** | No | No | Yes |
-
----
-
-## Next Steps
-
-- [**Retain**](./retain) — Advanced options for storing memories
-- [**Recall**](./recall) — Tuning search quality and performance
-- [**Reflect**](./reflect) — Configuring disposition and opinions
-- [**Memory Banks**](./memory-banks) — Managing memory bank disposition
-
-
----
-
-
-## File: developer/retain.md
-
-# Retain: How Hindsight Stores Memories
-
-When you call `retain()`, Hindsight transforms conversations and documents into structured, searchable memories that preserve meaning and context.
-
-## What Retain Does
-
-```mermaid
-graph LR
- A[Your Content] --> B[Extract Facts]
- B --> C[Identify Entities]
- C --> D[Build Connections]
- D --> E[Memory Bank]
-```
-
----
-
-## Rich Fact Extraction
-
-Hindsight doesn't just store what was said — it captures **why**, **how**, and **what it means**.
-
-### What Gets Captured
-
-When you retain "Alice joined Google last spring and was thrilled about the research opportunities", Hindsight extracts:
-
-**The core facts:**
-- Alice joined Google
-- This happened last spring
-
-**The emotions and meaning:**
-- She was thrilled
-- It represented an important opportunity
-
-**The reasoning:**
-- She chose it for the research opportunities
-
-This rich extraction means you can later ask "Why did Alice join Google?" and get a meaningful answer, not just "she joined Google."
-
-### Preserving Context
-
-Traditional systems fragment information:
-- "Bob suggested Summer Vibes"
-- "Alice wanted something unique"
-- "They chose Beach Beats"
-
-Hindsight preserves the full narrative:
-- "Alice and Bob discussed naming their summer party playlist. Bob suggested 'Summer Vibes' because it's catchy, but Alice wanted something unique. They ultimately decided on 'Beach Beats' for its playful tone."
-
-This means search results include the full context, not disconnected fragments.
-
----
-
-## Two Types of Facts
-
-Hindsight distinguishes between **world** facts (about others) and **experience** (conversations and events):
-
-| Type | Description | Example |
-|-----------------|-----------------------------------|---------|
-| **world** | Facts about people, places, things | "Alice works at Google" |
-| **experience** | Conversations and events | "I recommended Python to Alice" |
-
-This separation is important for `reflect()` — the bank can reason about what it knows versus what happened in conversations.
-
-**Note:** Opinions aren't created during `retain()` — only during `reflect()` when the bank forms beliefs.
-
----
-
-## Entity Recognition
-
-Hindsight automatically identifies and tracks **entities** — the people, organizations, and concepts that matter.
-
-### What Gets Recognized
-
-- **People:** "Alice", "Dr. Smith", "Bob Chen"
-- **Organizations:** "Google", "MIT", "OpenAI"
-- **Places:** "Paris", "Central Park", "California"
-- **Products & Concepts:** "Python", "TensorFlow", "machine learning"
-
-### Entity Resolution
-
-The same entity mentioned different ways gets unified:
-- "Alice" + "Alice Chen" + "Alice C." → one person
-- "Bob" + "Robert Chen" → one person (nickname resolution)
-
-**Why it matters:** You can ask "What do I know about Alice?" and get everything, even if she was mentioned as "Alice Chen" in some conversations.
-
-### Context-Aware Disambiguation
-
-If "Alice" appears with "Google" and "Stanford" multiple times, a new "Alice" mentioning those is likely the same person. Hindsight uses co-occurrence patterns to disambiguate common names.
-
----
-
-## Building Connections
-
-Memories aren't isolated — Hindsight creates a **knowledge graph** with four types of connections:
-
-### Entity Connections
-
-All facts mentioning the same entity are linked together.
-
-**Enables:** "Tell me everything about Alice" → retrieves all Alice-related facts
-
-### Time-Based Connections
-
-Facts close in time are connected, with stronger links for closer dates.
-
-**Enables:** "What else happened around then?" → finds contextually related events
-
-### Meaning-Based Connections
-
-Semantically similar facts are linked, even if they use different words.
-
-**Enables:** "Tell me about similar topics" → finds thematically related information
-
-### Causal Connections
-
-Cause-effect relationships are explicitly tracked.
-
-**Enables:** "Why did this happen?" → trace reasoning chains
-**Example:** "Alice felt burned out" ← caused by ← "She worked 80-hour weeks"
-
----
-
-## Understanding Time
-
-Hindsight tracks **two temporal dimensions**:
-
-### When It Happened
-
-For events (meetings, trips, milestones), Hindsight records when they occurred.
-- "Alice got married in June 2024" → occurred in June 2024
-
-For general facts (preferences, characteristics), there's no specific occurrence time.
-- "Alice prefers Python" → ongoing preference
-
-### When You Learned It
-
-Hindsight also tracks when you told it each fact.
-
-**Why both?**
-
-Imagine in January 2025, someone tells you "Alice got married in June 2024":
-- **Historical queries** work: "What did Alice do in 2024?" → finds the marriage
-- **Recency ranking** works: Recent mentions get priority in search
-- **Temporal reasoning** works: "What happened before her marriage?" → finds earlier events
-
-Without this distinction, old information would either be unsearchable by date or treated as irrelevant.
-
----
-
-## Entity Observations
-
-As facts accumulate about an entity, Hindsight synthesizes **observations** — high-level summaries that capture what's known:
-
-**From multiple facts:**
-- "Alice works at Google"
-- "Alice is a software engineer"
-- "Alice specializes in ML"
-
-**Hindsight creates:**
-- "Alice is a software engineer at Google specializing in ML"
-
-**Why it helps:** You can quickly understand an entity without reading through dozens of individual facts.
-
----
-
-## What You Get
-
-After `retain()` completes:
-
-- **Structured facts** that preserve meaning, emotions, and reasoning
-- **Unified entities** that resolve different name variations
-- **Knowledge graph** with entity, temporal, semantic, and causal links
-- **Temporal grounding** for both historical and recency-based queries
-- **Background processing** that generates entity summaries
-
-All stored in your isolated **memory bank**, ready for `recall()` and `reflect()`.
-
----
-
-## Next Steps
-
-- [**Recall**](./retrieval) — How multi-strategy search retrieves relevant memories
-- [**Reflect**](./reflect) — How disposition influences reasoning and opinion formation
-- [API Reference](./api/retain) — Code examples for retaining memories
-
-
----
-
-
-## File: developer/retrieval.md
-
-# Recall: How Hindsight Retrieves Memories
-
-When you call `recall()`, Hindsight uses multiple search strategies in parallel to find the most relevant memories, regardless of how you phrase your query.
-
-```mermaid
-graph LR
- Q[Query] --> S[Semantic]
- Q --> K[Keyword]
- Q --> G[Graph]
- Q --> T[Temporal]
-
- S --> RRF[RRF Fusion]
- K --> RRF
- G --> RRF
- T --> RRF
-
- RRF --> CE[Cross-Encoder]
- CE --> R[Results]
-```
-
----
-
-## The Challenge of Memory Recall
-
-Different queries need different search approaches:
-
-- **"Alice works at Google"** → needs exact name matching
-- **"Where does Alice work?"** → needs semantic understanding
-- **"What did Alice do last spring?"** → needs temporal reasoning
-- **"Why did Alice leave?"** → needs causal relationship tracing
-
-No single search method handles all these well. Hindsight solves this with **TEMPR** — four complementary strategies that run in parallel.
-
----
-
-## Four Search Strategies
-
-### Semantic Search
-
-**What it does:** Understands the *meaning* behind words, not just the words themselves.
-
-**Best for:**
-- Conceptual matches: "Alice's job" → "Alice works as a software engineer"
-- Paraphrasing: "Bob's expertise" → "Bob specializes in machine learning"
-- Synonyms: "meeting" matches "conference", "discussion", "gathering"
-
-**Why it matters:** You can ask questions naturally without matching exact keywords.
-
----
-
-### Keyword Search
-
-**What it does:** Finds exact terms and names, even when they're spelled uniquely.
-
-**Best for:**
-- Proper nouns: "Google", "Alice Chen", "MIT"
-- Technical terms: "PostgreSQL", "HNSW", "TensorFlow"
-- Unique identifiers: URLs, product names, specific phrases
-
-**Why it matters:** Ensures you never miss results that mention specific names or terms, even if they're semantically distant from your query.
-
----
-
-### Graph Traversal
-
-**What it does:** Follows connections between entities to find indirectly related information.
-
-**Best for:**
-- Indirect relationships: "What does Alice do?" → Alice → Google → Google's products
-- Entity exploration: "Bob's colleagues" → Bob → co-workers → shared projects
-- Multi-hop reasoning: "Alice's team's achievements"
-
-**Why it matters:** Retrieves facts that aren't semantically or lexically similar but are **structurally connected** through the knowledge graph.
-
-**Example:** Even if Alice and her manager are never mentioned together, graph traversal can find the manager through shared projects or team relationships.
-
----
-
-### Temporal Search
-
-**What it does:** Understands time expressions and filters by when events occurred.
-
-**Best for:**
-- Historical queries: "What did Alice do in 2023?"
-- Time ranges: "What happened last spring?"
-- Relative time: "What did Bob work on last year?"
-- Before/after: "What happened before Alice joined Google?"
-
-**How it works:** Combines semantic understanding with time filtering to find events within specific periods.
-
-**Why it matters:** Enables precise historical queries without losing old information.
-
----
-
-## Result Fusion
-
-After the four strategies run, results are **fused together**:
-
-- Memories appearing in **multiple strategies** rank higher (consensus)
-- **Rank matters more than score** (robust across different scoring systems)
-- Final results are **re-ranked** using a neural model that considers query-memory interaction
-
-**Why fusion matters:** A fact that's both semantically similar AND mentions the right entity will rank higher than one that's only semantically similar.
-
----
-
-## Token Budget Management
-
-Hindsight is built for AI agents, not humans. Traditional search systems return "top-k" results, but agents don't think in terms of result counts—they think in tokens. An agent's context window is measured in tokens, and that's exactly how Hindsight measures results.
-
-**How it works:**
-- Top-ranked memories selected first
-- Stops when token budget is exhausted
-- You specify context budget, Hindsight fills it with the most relevant memories
-
-**Parameters you control:**
-- `max_tokens`: How much memory content to return (default: 4096 tokens)
-- `budget`: Budget level for graph traversal (low, mid, high)
-- `fact_type`: Filter by world, experience, opinion, or all
-
-### Additional Context: Chunks and Entity Observations
-
-For the most relevant memories, you can optionally retrieve additional context—each with its own token budget:
-
-| Option | Parameters | Description |
-|--------|------------|-------------|
-| **Chunks** | `include_chunks`, `max_chunk_tokens` | Raw text chunks that generated the memories |
-| **Entity Observations** | `include_entities`, `max_entity_tokens` | Related observations about entities mentioned in results |
-
-This gives your agent richer context while maintaining precise control over total token consumption.
-
----
-
-## Tuning Recall: Quality vs Latency
-
-Different use cases require different trade-offs between **recall quality** and **response speed**. Two parameters control this:
-
-### Budget: Graph Exploration Depth
-
-Controls how many nodes to explore when traversing the knowledge graph:
-
-| Budget | Nodes Explored | Best For | Trade-off |
-|--------|----------------|----------|-----------|
-| **low** | 100 nodes | Quick lookups, simple queries | Fast, may miss distant connections |
-| **mid** | 300 nodes | Most queries, balanced | Good coverage, reasonable speed |
-| **high** | 600 nodes | Complex multi-hop queries | Thorough, slower |
-
-**Example:** "What did Alice's manager's team work on?" benefits from high budget to traverse Alice → manager → team → projects.
-
-### Max Tokens: Context Window Size
-
-Controls how much memory content to return:
-
-| Max Tokens | ~Pages of Text | Best For | Trade-off |
-|------------|----------------|----------|-----------|
-| **2048** | ~2 pages | Focused answers, fast LLM | Fewer memories, faster |
-| **4096** (default) | ~4 pages | Balanced context | Good coverage, standard |
-| **8192** | ~8 pages | Comprehensive context | More memories, slower LLM |
-
-**Example:** "Summarize everything about Alice" benefits from higher max_tokens to include more facts.
-
-### Two Independent Dimensions
-
-Budget and max_tokens control different aspects of recall:
-
-| Parameter | What it controls | Latency impact | Example |
-|-----------|------------------|----------------|---------|
-| **Budget** | How deep to explore the graph | Search time | High budget finds Alice → manager → team → projects |
-| **Max Tokens** | How much context to return | LLM processing time | High tokens returns more memories to the agent |
-
-**They're independent.** Common combinations:
-
-| Budget | Max Tokens | Use Case |
-|--------|------------|----------|
-| high | low | Deep search, return only the best results |
-| low | high | Quick search, return everything found |
-| high | high | Comprehensive research queries |
-| low | low | Fast chatbot responses |
-
-### Recommended Configurations
-
-| Use Case | Budget | Max Tokens | Why |
-|----------|--------|------------|-----|
-| **Chatbot replies** | low | 2048 | Fast responses, focused context |
-| **Document Q&A** | mid | 4096 | Balanced coverage and speed |
-| **Research queries** | high | 8192 | Comprehensive, multi-hop reasoning |
-| **Real-time search** | low | 2048 | Minimize latency |
-
----
-
-## Why Multiple Strategies?
-
-Consider the query: **"What did Alice think about Python last spring?"**
-
-- **Semantic** finds facts about Alice's opinions on programming
-- **Keyword** ensures "Python" is actually mentioned
-- **Graph** connects Alice → opinions → programming languages
-- **Temporal** filters to "last spring" timeframe
-
-The **fusion** of all four gives you exactly what you're looking for, even though no single strategy would suffice.
-
----
-
-## Next Steps
-
-- [**Retain**](./retain) — How memories are stored with rich context
-- [**Reflect**](./reflect) — How disposition influences reasoning
-
-
----
-
-
-## File: developer/reflect.md
-
-# Reflect: How Hindsight Reasons with Disposition
-
-When you call `reflect()`, Hindsight doesn't just retrieve facts — it **reasons** about them through the lens of the bank's unique disposition, forming new opinions and generating contextual responses.
-
-```mermaid
-graph LR
- A[Query] --> B[Recall Memories]
- B --> C[Load Disposition]
- C --> D[Reason]
- D --> E[Form Opinions]
- E --> F[Response]
-```
-
----
-
-## Why Reflect?
-
-Most AI systems can retrieve facts, but they can't **reason** about them in a consistent way. Every response is generated fresh without a stable perspective or evolving beliefs.
-
-### The Problem
-
-Without reflect:
-- **No consistent character**: "Should we adopt remote work?" gets a different answer each time based on the LLM's randomness
-- **No opinion formation**: The system never develops beliefs based on accumulated evidence
-- **No reasoning context**: Responses don't reflect what the bank has learned or its perspective
-- **Generic responses**: Every AI sounds the same — no disposition, no point of view
-
-### The Value
-
-With reflect:
-- **Consistent character**: A bank configured as "detail-oriented, cautious" will consistently emphasize risks and thorough planning
-- **Evolving opinions**: As the bank learns more about a topic, its opinions strengthen, weaken, or change — just like a real expert
-- **Contextual reasoning**: Responses reflect the bank's accumulated knowledge and perspective: "Based on what I know about your team's remote work success..."
-- **Differentiated behavior**: Customer support bots sound diplomatic, code reviewers sound direct, creative assistants sound open-minded
-
-### When to Use Reflect
-
-| Use `recall()` when... | Use `reflect()` when... |
-|------------------------|-------------------------|
-| You need raw facts | You need reasoned interpretation |
-| You're building your own reasoning | You want disposition-consistent responses |
-| You need maximum control | You want the bank to "think" for itself |
-| Simple fact lookup | Forming recommendations or opinions |
-
-**Example:**
-- `recall("Alice")` → Returns all Alice facts
-- `reflect("Should we hire Alice?")` → Reasons about Alice's fit based on accumulated knowledge, weighs evidence, forms opinion
-
----
-
-## Disposition Traits
-
-When you create a memory bank, you can configure its disposition using three traits. These traits influence how the bank interprets information and forms opinions during `reflect()`:
-
-| Trait | Scale | Low (1) | High (5) |
-|-------|-------|---------|----------|
-| **Skepticism** | 1-5 | Trusting, accepts information at face value | Skeptical, questions and doubts claims |
-| **Literalism** | 1-5 | Flexible interpretation, reads between the lines | Literal interpretation, takes things at face value |
-| **Empathy** | 1-5 | Detached, focuses on facts | Empathetic, considers emotional context |
-
-### Background: Natural Language Identity
-
-Beyond numeric traits, you can provide a natural language **background** that describes the bank's identity:
-
-```python
-client.create_bank(
- bank_id="my-bank",
- background="I am a senior software architect with 15 years of distributed "
- "systems experience. I prefer simplicity over cutting-edge technology.",
- disposition={
- "skepticism": 4, # Questions new technologies
- "literalism": 4, # Focuses on concrete specs
- "empathy": 2 # Prioritizes technical facts
- }
-)
-```
-
-The background provides context that shapes how disposition traits are applied:
-- "I prefer simplicity" + high skepticism → questions complex solutions
-- "15 years experience" → responses reference this expertise
-- First-person perspective → creates consistent voice
-
----
-
-## Opinion Formation
-
-When `reflect()` encounters a question that warrants forming an opinion, disposition shapes the response.
-
-### Same Facts, Different Opinions
-
-Two banks with different dispositions, given identical facts about remote work:
-
-**Bank A** (low skepticism, high empathy):
-> "Remote work enables flexibility and work-life balance. The team seems happier and more productive when they can choose their environment."
-
-**Bank B** (high skepticism, low empathy):
-> "Remote work claims need verification. What are the actual productivity metrics? The anecdotal benefits may not translate to measurable outcomes."
-
-**Same facts → Different conclusions** because disposition shapes interpretation.
-
----
-
-## Opinion Evolution
-
-Opinions aren't static — they evolve as new evidence arrives. Here's a real-world example with a database library:
-
-| Event | What the bank learns | Opinion formed |
-|-------|---------------------|----------------|
-| **Day 1** | "Redis is open source under BSD license" | "Redis is excellent for caching — fast, reliable, and OSS-friendly" (confidence: 0.85) |
-| **Day 2** | "Redis has great community support and documentation" | Opinion reinforced (confidence: 0.90) |
-| **Day 30** | "Redis changed license to SSPL, restricting cloud usage" | "Redis is still technically strong, but license concerns for cloud deployments" (confidence: 0.65) |
-| **Day 45** | "Valkey forked Redis under BSD license with Linux Foundation backing" | "Consider Valkey for new projects requiring true OSS; Redis for existing deployments" (confidence: 0.80) |
-
-**Before the license change:**
-> "Should we use Redis for our caching layer?"
-> → "Yes, Redis is the industry standard — fast, battle-tested, and fully open source."
-
-**After the license change:**
-> "Should we use Redis for our caching layer?"
-> → "It depends. For cloud deployments, consider Valkey (the BSD-licensed fork). For on-premise, Redis remains excellent technically."
-
-This **continuous learning** ensures recommendations stay current with real-world changes.
-
----
-
-## Disposition Presets by Use Case
-
-Different use cases benefit from different disposition configurations:
-
-| Use Case | Recommended Traits | Why |
-|----------|-------------------|-----|
-| **Customer Support** | skepticism: 2, literalism: 2, empathy: 5 | Trusting, flexible, understanding |
-| **Code Review** | skepticism: 4, literalism: 5, empathy: 2 | Questions assumptions, precise, direct |
-| **Legal Analysis** | skepticism: 5, literalism: 5, empathy: 2 | Highly skeptical, exact interpretation |
-| **Therapist/Coach** | skepticism: 2, literalism: 2, empathy: 5 | Supportive, reads between lines |
-| **Research Assistant** | skepticism: 4, literalism: 3, empathy: 3 | Questions claims, balanced interpretation |
-
----
-
-## What You Get from Reflect
-
-When you call `reflect()`:
-
-**Returns:**
-- **Response text** — Disposition-influenced answer
-- **Based on** — Which memories were used (with relevance scores)
-
-**Example:**
-```json
-{
- "text": "Based on Alice's ML expertise and her work at Google, she'd be an excellent fit for the research team lead position...",
- "based_on": {
- "world": [
- {"text": "Alice works at Google...", "weight": 0.95},
- {"text": "Alice specializes in ML...", "weight": 0.88}
- ]
- }
-}
-```
-
-**Note:** New opinions are formed asynchronously in the background. They'll influence future `reflect()` calls but aren't returned directly.
-
----
-
-## Why Disposition Matters
-
-Without disposition, all AI assistants sound the same. With disposition:
-
-- **Customer support bots** can be diplomatic and empathetic
-- **Code review assistants** can be direct and thorough
-- **Creative assistants** can be open to unconventional ideas
-- **Risk analysts** can be appropriately cautious
-
-Disposition creates **consistent character** across conversations while allowing opinions to **evolve with evidence**.
-
----
-
-## Next Steps
-
-- [**Retain**](./retain) — How rich facts are stored
-- [**Recall**](./retrieval) — How multi-strategy search works
-- [API Reference: Reflect](./api/reflect) — Code examples and usage
-
-
----
-
-
-## File: developer/api/retain.md
-
-# Ingest Data
-
-Store documents, conversations, and raw content into Hindsight to automatically extract and create memories.
-
-When you **retain** content, Hindsight doesn't just store the raw text—it intelligently analyzes the content to extract meaningful facts, identify entities, and build a connected knowledge graph. This process transforms unstructured information into structured, queryable memories.
-
-
-
-
-:::info How Retain Works
-Learn about fact extraction, entity resolution, and graph construction in the [Retain Architecture](/developer/retain) guide.
-:::
-
-:::tip Prerequisites
-Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
-:::
-
-## Store a Single Memory
-
-
-
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(base_url="http://localhost:8888")
-
-client.retain(
- bank_id="my-bank",
- content="Alice works at Google as a software engineer"
-)
-```
-
-
-
-
-```typescript
-
-
-const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
-
-await client.retain('my-bank', 'Alice works at Google as a software engineer');
-```
-
-
-
-
-```bash
-hindsight memory put my-bank "Alice works at Google as a software engineer"
-```
-
-
-
-
-## The Importance of Context
-
-The `context` parameter is crucial for guiding how Hindsight extracts memories from your content. Think of it as providing a lens through which the system interprets the information.
-
-**Why context matters:**
-- **Steers memory extraction**: Context tells the memory bank what type of information to focus on and how to interpret ambiguous content
-- **Improves relevance**: Memories extracted with proper context are more accurately categorized and easier to retrieve
-- **Disambiguates meaning**: The same sentence can have different implications depending on context (e.g., "the project was terminated" means different things in a career vs. product context)
-
-## Store with Context and Date
-
-Always provide context and event dates for optimal memory extraction:
-
-
-
-
-```python
-client.retain(
- bank_id="my-bank",
- content="Alice got promoted to senior engineer",
- context="career update",
- timestamp="2024-03-15T10:00:00Z"
-)
-```
-
-
-
-
-```typescript
-await client.retain('my-bank', 'Alice got promoted to senior engineer', {
- context: 'career update',
- timestamp: '2024-03-15T10:00:00Z'
-});
-```
-
-
-
-
-```bash
-hindsight memory put my-bank "Alice got promoted" \
- --context "career update" \
- --event-date "2024-03-15"
-```
-
-
-
-
-The `timestamp` defaults to the current time if not specified. Providing explicit timestamps enables temporal queries like "What happened last spring?"
-
-## Batch Ingestion
-
-Store multiple items in a single request. **Batch ingestion is the recommended approach** as it significantly improves performance by reducing network overhead and allowing Hindsight to optimize the memory extraction process across related content.
-
-
-
-
-```python
-client.retain_batch(
- bank_id="my-bank",
- items=[
- {"content": "Alice works at Google", "context": "career"},
- {"content": "Bob is a data scientist at Meta", "context": "career"},
- {"content": "Alice and Bob are friends", "context": "relationship"}
- ],
- document_id="conversation_001"
-)
-```
-
-
-
-
-```typescript
-await client.retainBatch('my-bank', [
- { content: 'Alice works at Google', context: 'career' },
- { content: 'Bob is a data scientist at Meta', context: 'career' },
- { content: 'Alice and Bob are friends', context: 'relationship' }
-], { documentId: 'conversation_001' });
-```
-
-
-
-
-The `document_id` groups related memories for later management.
-
-## Store from Files
-
-
-
-
-```bash
-# Single file
-hindsight memory put-files my-bank document.txt
-
-# Multiple files
-hindsight memory put-files my-bank doc1.txt doc2.md notes.txt
-
-# With document ID
-hindsight memory put-files my-bank report.pdf --document-id "q4-report"
-```
-
-
-
-
-
-## Async Ingestion
-
-For large batches, use async ingestion to avoid blocking:
-
-
-
-
-```python
-# Start async ingestion (returns immediately)
-result = client.retain_batch(
- bank_id="my-bank",
- items=[...large batch...],
- document_id="large-doc",
- retain_async=True
-)
-
-# Check if it was processed asynchronously
-print(result.var_async) # True
-```
-
-
-
-
-```typescript
-// Start async ingestion (returns immediately)
-const result = await client.retainBatch('my-bank', largeItems, {
- documentId: 'large-doc',
- async: true
-});
-
-console.log(result.async); // true
-```
-
-
-
-
-
-
----
-
-
-## File: developer/api/recall.md
-
-# Recall Memories
-
-Retrieve memories using multi-strategy recall.
-
-
-
-
-:::info How Recall Works
-Learn about the four retrieval strategies (semantic, keyword, graph, temporal) and RRF fusion in the [Recall Architecture](/developer/retrieval) guide.
-:::
-
-:::tip Prerequisites
-Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
-:::
-
-## Basic Recall
-
-
-
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(base_url="http://localhost:8888")
-
-response = client.recall(bank_id="my-bank", query="What does Alice do?")
-for r in response.results:
- print(f"{r.text} (score: {r.weight:.2f})")
-```
-
-
-
-
-```typescript
-
-
-const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
-
-const response = await client.recall('my-bank', 'What does Alice do?');
-for (const r of response.results) {
- console.log(`${r.text} (score: ${r.weight})`);
-}
-```
-
-
-
-
-```bash
-hindsight recall my-bank "What does Alice do?"
-```
-
-
-
-
-## Recall Parameters
-
-| Parameter | Type | Default | Description |
-|-----------|------|---------|-------------|
-| `query` | string | required | Natural language query |
-| `types` | list | all | Filter: `world`, `experience`, `opinion` |
-| `budget` | string | "mid" | Budget level: "low", "mid", "high" |
-| `max_tokens` | int | 4096 | Token budget for results |
-| `trace` | bool | false | Enable trace output for debugging |
-| `include_entities` | bool | false | Include entity observations |
-| `max_entity_tokens` | int | 500 | Token budget for entity observations |
-
-
-
-
-```python
-response = client.recall(
- bank_id="my-bank",
- query="What does Alice do?",
- types=["world", "experience"],
- budget="high",
- max_tokens=8000,
- trace=True,
- include_entities=True,
- max_entity_tokens=500
-)
-
-# Access results
-for r in response.results:
- print(f"{r.text} (score: {r.weight:.2f})")
-
-# Access entity observations (if include_entities=True)
-if response.entities:
- for entity in response.entities:
- print(f"Entity: {entity.name}")
-```
-
-
-
-
-```typescript
-const response = await client.recall('my-bank', 'What does Alice do?', {
- types: ['world', 'experience'],
- budget: 'high',
- maxTokens: 8000,
- trace: true
-});
-
-// Access results
-for (const r of response.results) {
- console.log(`${r.text} (score: ${r.weight})`);
-}
-```
-
-
-
-
-## Filter by Fact Type
-
-Recall specific memory types:
-
-
-
-
-```python
-# Only world facts (objective information)
-world_facts = client.recall(
- bank_id="my-bank",
- query="Where does Alice work?",
- types=["world"]
-)
-
-# Only experience (conversations and events)
-experience = client.recall(
- bank_id="my-bank",
- query="What have I recommended?",
- types=["experience"]
-)
-
-# Only opinions (formed beliefs)
-opinions = client.recall(
- bank_id="my-bank",
- query="What do I think about Python?",
- types=["opinion"]
-)
-
-# World facts and experience (exclude opinions)
-facts = client.recall(
- bank_id="my-bank",
- query="What happened?",
- types=["world", "experience"]
-)
-```
-
-
-
-
-```bash
-hindsight recall my-bank "Python" --fact-type opinion
-hindsight recall my-bank "Alice" --fact-type world,experience
-```
-
-
-
-
-:::warning About Opinions
-Opinions are beliefs formed during [reflect](/developer/api/reflect) operations. Unlike world facts and experience, opinions are subjective interpretations and may not represent objective truth. Depending on your use case:
-- **Exclude opinions** (`types=["world", "experience"]`) when you need factual, verifiable information
-- **Include opinions** when you want the agent's perspective or formed beliefs
-- **Use opinions alone** (`types=["opinion"]`) only when specifically asking about the agent's views
-:::
-
-## Token Budget Management
-
-Hindsight is built for AI agents, not humans. Traditional retrieval systems return "top-k" results, but agents don't think in terms of result counts—they think in tokens. An agent's context window is measured in tokens, and that's exactly how Hindsight measures results.
-
-The `max_tokens` parameter lets you control how much of your agent's context budget to spend on memories:
-
-```python
-# Fill up to 4K tokens of context with relevant memories
-results = client.recall(bank_id="my-bank", query="What do I know about Alice?", max_tokens=4096)
-
-# Smaller budget for quick lookups
-results = client.recall(bank_id="my-bank", query="Alice's email", max_tokens=500)
-```
-
-This design means you never have to guess whether 10 results or 50 results will fit your context. Just specify the token budget and Hindsight returns as many relevant memories as will fit.
-
-## Include Related Context
-
-Beyond the core memory results, you can optionally retrieve additional context—each with its own token budget:
-
-| Option | Parameter | Description |
-|--------|-----------|-------------|
-| **Chunks** | `include_chunks`, `max_chunk_tokens` | Raw text chunks that generated the memories |
-| **Entity Observations** | `include_entities`, `max_entity_tokens` | Related observations about entities mentioned in results |
-
-```python
-response = client.recall(
- bank_id="my-bank",
- query="What does Alice do?",
- max_tokens=4096, # Budget for memories
- include_entities=True,
- max_entity_tokens=1000 # Budget for entity observations
-)
-
-# Access the additional context
-entities = response.entities or []
-```
-
-This gives your agent richer context while maintaining precise control over total token consumption.
-
-## Budget Levels
-
-The `budget` parameter controls graph traversal depth:
-
-- **"low"**: Fast, shallow retrieval — good for simple lookups
-- **"mid"**: Balanced — default for most queries
-- **"high"**: Deep exploration — finds indirect connections
-
-
-
-
-```python
-# Quick lookup
-results = client.recall(bank_id="my-bank", query="Alice's email", budget="low")
-
-# Deep exploration
-results = client.recall(bank_id="my-bank", query="How are Alice and Bob connected?", budget="high")
-```
-
-
-
-
-```typescript
-// Quick lookup
-const results = await client.recall('my-bank', "Alice's email", { budget: 'low' });
-
-// Deep exploration
-const deep = await client.recall('my-bank', 'How are Alice and Bob connected?', { budget: 'high' });
-```
-
-
-
-
-
----
-
-
-## File: developer/api/reflect.md
-
-# Reflect
-
-Generate disposition-aware responses using retrieved memories.
-
-When you call **reflect**, Hindsight performs a multi-step reasoning process:
-1. **Recalls** relevant memories from the bank based on your query
-2. **Applies** the bank's disposition traits to shape the reasoning style
-3. **Generates** a contextual answer grounded in the retrieved facts
-4. **Forms opinions** in the background based on the reasoning (available in subsequent calls)
-
-The response includes the generated answer along with the facts that were used, providing full transparency into how the answer was derived.
-
-
-
-
-:::info How Reflect Works
-Learn about disposition-driven reasoning and opinion formation in the [Reflect Architecture](/developer/reflect) guide.
-:::
-
-:::tip Prerequisites
-Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
-:::
-
-## Basic Usage
-
-
-
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(base_url="http://localhost:8888")
-
-client.reflect(bank_id="my-bank", query="What should I know about Alice?")
-```
-
-
-
-
-```typescript
-
-
-const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
-
-await client.reflect('my-bank', 'What should I know about Alice?');
-```
-
-
-
-
-```bash
-hindsight memory think my-bank "What should I know about Alice?"
-```
-
-
-
-
-## Parameters
-
-| Parameter | Type | Default | Description |
-|-----------|------|---------|-------------|
-| `query` | string | required | Question or prompt |
-| `budget` | string | "low" | Budget level: "low", "mid", "high" |
-| `context` | string | None | Additional context for the query |
-
-
-
-
-```python
-response = client.reflect(
- bank_id="my-bank",
- query="What do you think about remote work?",
- budget="mid",
- context="We're considering a hybrid work policy"
-)
-```
-
-
-
-
-```typescript
-const response = await client.reflect('my-bank', 'What do you think about remote work?', {
- budget: 'mid',
- context: "We're considering a hybrid work policy"
-});
-```
-
-
-
-
-## The Role of Context
-
-The `context` parameter steers how the reflection is performed without impacting the memory recall. It provides situational information that helps shape the reasoning and response.
-
-**How context is used:**
-- **Shapes reasoning**: Helps understand the situation when formulating an answer
-- **Disambiguates intent**: Clarifies what aspect of the query matters most
-- **Does not affect recall**: The same memories are retrieved regardless of context
-
-
-
-
-```python
-# Context is passed to the LLM to help it understand the situation
-response = client.reflect(
- bank_id="my-bank",
- query="What do you think about the proposal?",
- context="We're in a budget review meeting discussing Q4 spending"
-)
-```
-
-
-
-
-```typescript
-// Context helps the LLM understand the current situation
-const response = await client.reflect('my-bank', 'What do you think about the proposal?', {
- context: "We're in a budget review meeting discussing Q4 spending"
-});
-```
-
-
-
-
-## Opinion Formation
-
-When reflect reasons about a question, it may form new **opinions** based on the evidence in the memory bank. These opinions are created in the background and become available in subsequent `reflect` and `recall` calls.
-
-**Why opinions matter:**
-- **Consistent thinking**: Opinions ensure the memory bank maintains a coherent perspective over time
-- **Evolving viewpoints**: As more information is retained, opinions can be refined or updated
-- **Grounded reasoning**: Opinions are always derived from factual evidence in the memory bank
-
-Opinions are stored as a special memory type and are automatically retrieved when relevant to future queries. This creates a natural evolution of the bank's perspective, similar to how humans form and refine their views based on accumulated experience.
-
-## Disposition Influence
-
-The bank's disposition affects reflect responses:
-
-| Trait | Low (1) | High (5) |
-|-------|---------|----------|
-| **Skepticism** | Trusting, accepts claims | Questions and doubts claims |
-| **Literalism** | Flexible interpretation | Exact, literal interpretation |
-| **Empathy** | Detached, fact-focused | Considers emotional context |
-
-
-
-
-```python
-# Create a bank with specific disposition
-client.create_bank(
- bank_id="cautious-advisor",
- background="I am a risk-aware financial advisor",
- disposition={
- "skepticism": 5, # Very skeptical of claims
- "literalism": 4, # Focuses on exact requirements
- "empathy": 2 # Prioritizes facts over feelings
- }
-)
-
-# Reflect responses will reflect this disposition
-response = client.reflect(
- bank_id="cautious-advisor",
- query="Should I invest in crypto?"
-)
-# Response will likely emphasize risks and caution
-```
-
-
-
-
-```typescript
-// Create a bank with specific disposition
-await client.createBank('cautious-advisor', {
- background: 'I am a risk-aware financial advisor',
- disposition: {
- skepticism: 5,
- literalism: 4,
- empathy: 2
- }
-});
-
-// Reflect responses will reflect this disposition
-const response = await client.reflect('cautious-advisor', 'Should I invest in crypto?');
-```
-
-
-
-
-## Using Sources
-
-The `based_on` field shows which memories informed the response:
-
-
-
-
-```python
-response = client.reflect(bank_id="my-bank", query="Tell me about Alice")
-
-print("Response:", response.text)
-print("\nBased on:")
-for fact in response.based_on or []:
- print(f" - [{fact.type}] {fact.text}")
-```
-
-
-
-
-```typescript
-const response = await client.reflect('my-bank', 'Tell me about Alice');
-
-console.log('Response:', response.text);
-console.log('\nBased on:');
-for (const fact of response.based_on || []) {
- console.log(` - [${fact.type}] ${fact.text}`);
-}
-```
-
-
-
-
-This enables:
-- **Transparency** — users see why the bank said something
-- **Verification** — check if the response is grounded in facts
-- **Debugging** — understand retrieval quality
-
-
----
-
-
-## File: developer/api/memory-banks.md
-
-# Memory Banks
-
-Memory banks are isolated containers that store all memory-related data for a specific context or use case.
-
-
-
-
-## What is a Memory Bank?
-
-A memory bank is a complete, isolated storage unit containing:
-
-- **Memories** — Facts and information retained from conversations
-- **Documents** — Files and content indexed for retrieval
-- **Entities** — People, places, concepts extracted from memories
-- **Relationships** — Connections between entities in the knowledge graph
-
-Banks are completely isolated from each other — memories stored in one bank are not visible to another.
-
-You don't need to pre-create a bank. Hindsight will automatically create it with default settings when you first use it.
-
-:::tip Prerequisites
-Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
-:::
-
-## Creating a Memory Bank
-
-
-
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(base_url="http://localhost:8888")
-
-client.create_bank(
- bank_id="my-bank",
- name="Research Assistant",
- background="I am a research assistant specializing in machine learning",
- disposition={
- "skepticism": 4,
- "literalism": 3,
- "empathy": 3
- }
-)
-```
-
-
-
-
-```typescript
-
-
-const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
-
-await client.createBank('my-bank', {
- name: 'Research Assistant',
- background: 'I am a research assistant specializing in machine learning',
- disposition: {
- skepticism: 4,
- literalism: 3,
- empathy: 3
- }
-});
-```
-
-
-
-
-```bash
-# Set background
-hindsight bank background my-bank "I am a research assistant specializing in ML"
-
-# Set disposition
-hindsight bank disposition my-bank \
- --skepticism 4 \
- --literalism 3 \
- --empathy 3
-```
-
-
-
-
-## Background and Disposition
-
-Background and disposition are optional settings that influence how the bank forms opinions during [reflect](./reflect) operations.
-
-:::info
-Background and disposition only affect the `reflect` operation (opinion formation). They do not impact `retain`, `recall`, or other memory operations.
-:::
-
-### Background
-
-The background is a first-person narrative providing context for opinion formation:
-
-
-
-
-```python
-client.create_bank(
- bank_id="financial-advisor",
- background="""I am a conservative financial advisor with 20 years of experience.
- I prioritize capital preservation over aggressive growth.
- I have seen multiple market crashes and believe in diversification."""
-)
-```
-
-
-
-
-```typescript
-await client.createBank('financial-advisor', {
- background: `I am a conservative financial advisor with 20 years of experience.
- I prioritize capital preservation over aggressive growth.
- I have seen multiple market crashes and believe in diversification.`
-});
-```
-
-
-
-
-### Disposition Traits
-
-Disposition traits influence how opinions are formed during reflection. Each trait is scored 1 to 5:
-
-| Trait | Low (1) | High (5) |
-|-------|---------|----------|
-| **Skepticism** | Trusting, accepts information at face value | Skeptical, questions and doubts claims |
-| **Literalism** | Flexible interpretation, reads between the lines | Literal interpretation, takes things exactly as stated |
-| **Empathy** | Detached, focuses on facts and logic | Empathetic, considers emotional context |
-
-
----
-
-
-## File: developer/api/entities.md
-
-# Entities
-
-Entities are the people, organizations, places, and concepts that Hindsight automatically extracts and tracks across your memory bank.
-
-:::info Automatic Feature
-You don't need to do anything to use entities—Hindsight extracts them automatically when you call `retain`. However, understanding how entities work is important because they power key features in [recall](./recall) and [reflect](./reflect).
-:::
-
-## Why Entities Matter
-
-Entities improve recall quality in two ways:
-
-1. **Co-occurrence tracking** — When entities appear together in facts, Hindsight builds a graph of relationships. This enables graph-based recall to find indirect connections.
-
-2. **Observations** — Hindsight synthesizes high-level summaries about each entity from multiple facts. Including entity observations in recall provides richer context.
-
-## What Gets Extracted?
-
-When you retain information, the LLM extracts named entities from each fact:
-
-- **People** — Names like "Alice", "Dr. Smith", "CEO John"
-- **Organizations** — Companies, teams, institutions
-- **Places** — Cities, countries, specific locations
-- **Products/Objects** — Software, tools, significant items
-- **Concepts** — Abstract themes like "career growth", "friendship"
-
-**Example:**
-
-```
-Content: "Alice works at Google in Mountain View. She specializes in TensorFlow."
-
-Entities extracted:
-- Alice (person)
-- Google (organization)
-- Mountain View (location)
-- TensorFlow (product)
-```
-
-## Entity Resolution
-
-When the same entity is mentioned multiple times (possibly with different names), Hindsight resolves them to a single canonical entity using a scoring algorithm:
-
-### Resolution Factors
-
-1. **Name similarity (50%)** — How closely the text matches existing entity names. Handles variations like "Alice" vs "Alice Chen" or partial matches.
-
-2. **Co-occurrence (30%)** — Entities that frequently appear together are more likely to be the same. If "Alice" always appears with "Google" and "TensorFlow", a new mention of "Alice" near those entities scores higher for matching.
-
-3. **Temporal proximity (20%)** — Recent mentions are weighted more heavily. If an entity was seen in the last 7 days, new similar mentions are more likely to match.
-
-### Resolution Threshold
-
-A match requires a combined score above **0.6** (60%). Below this threshold, Hindsight creates a new entity rather than risk merging distinct entities.
-
-This means:
-- Exact name matches with recent co-occurring entities → strong match
-- Partial name matches without context → likely creates new entity
-- Same name in completely different contexts → may create separate entities
-
-## Entity Observations
-
-Observations are **derived state**—high-level summaries that Hindsight automatically synthesizes from the facts associated with an entity. They provide a condensed view of what the system knows about important entities.
-
-**Example:**
-
-Facts about Alice:
-- "Alice works at Google"
-- "Alice is a software engineer"
-- "Alice specializes in ML"
-- "Alice joined Google in 2020"
-- "Alice leads the search team"
-
-Observation created:
-- "Alice is a software engineer at Google who joined in 2020, specializes in ML, and leads the search team"
-
-### How Observations Work
-
-Observations are **not generated for every entity**. When you retain new documents:
-
-1. **Top entities selected** — Hindsight identifies the top 5 most-mentioned entities in the batch
-2. **Threshold check** — Only entities with at least 5 facts get observations
-3. **Regeneration** — Observations are regenerated using the entity's most recent 50 facts
-4. **Old observations replaced** — Previous observations are deleted and new ones created
-
-This means:
-- Frequently mentioned entities get observations; rarely mentioned ones don't
-- Observations stay up-to-date as new information is retained
-- The system prioritizes entities that matter most to your memory bank
-
-### Observations vs Opinions
-
-Observations are **objective summaries**—they synthesize facts without any bias or perspective. This is different from [opinions](./opinions), which are influenced by the memory bank's disposition.
-
-| | Observations | Opinions |
-|---|---|---|
-| **Purpose** | Summarize what's known about an entity | Express the bank's perspective on a topic |
-| **Disposition influence** | No | Yes |
-| **Scope** | Per-entity | Any topic |
-| **Generation** | Automatic (top entities) | On-demand via reflect |
-
-### Using Observations
-
-Observations are included in recall results when you set `include_entities=True`. They provide quick context about key entities without retrieving all underlying facts.
-
-## Next Steps
-
-- [**Recall**](./recall) — Use entities in memory retrieval
-- [**Reflect**](./reflect) — Get entity-aware responses
-
-
----
-
-
-## File: developer/api/documents.md
-
-# Documents
-
-Track and manage document sources in your memory bank. Documents provide traceability — knowing where memories came from.
-
-
-
-
-:::tip Prerequisites
-Make sure you've completed the [Quick Start](./quickstart) and understand [how retain works](./retain).
-:::
-
-## What Are Documents?
-
-Documents are containers for retained content. They help you:
-
-- **Track sources** — Know which PDF, conversation, or file a memory came from
-- **Update content** — Re-retain a document to update its facts
-- **Delete in bulk** — Remove all memories from a document at once
-- **Organize memories** — Group related facts by source
-
-## Chunks
-
-When you retain content, Hindsight splits it into chunks before extracting facts. These chunks are stored alongside the extracted memories, preserving the original text segments.
-
-**Why chunks matter:**
-- **Context preservation** — Chunks contain the raw text that generated facts, useful when you need the exact wording
-- **Richer recall** — Including chunks in recall provides surrounding context for matched facts
-
-:::tip Include Chunks in Recall
-Use `include_chunks=True` in your recall calls to get the original text chunks alongside fact results. See [Recall](./recall) for details.
-:::
-
-## Retain with Document ID
-
-Associate retained content with a document:
-
-
-
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(base_url="http://localhost:8888")
-
-# Retain with document ID
-client.retain(
- bank_id="my-bank",
- content="Alice presented the Q4 roadmap...",
- document_id="meeting-2024-03-15"
-)
-
-# Batch retain for a document
-client.retain_batch(
- bank_id="my-bank",
- items=[
- {"content": "Item 1: Product launch delayed to Q2"},
- {"content": "Item 2: New hiring targets announced"},
- {"content": "Item 3: Budget approved for ML team"}
- ],
- document_id="meeting-2024-03-15"
-)
-
-# From file
-with open("notes.txt") as f:
- client.retain(
- bank_id="my-bank",
- content=f.read(),
- document_id="notes-2024-03-15"
- )
-```
-
-
-
-
-```typescript
-
-
-const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
-
-// Retain with document ID
-await client.retain('my-bank', 'Alice presented the Q4 roadmap...', {
- document_id: 'meeting-2024-03-15'
-});
-
-// Batch retain
-await client.retainBatch('my-bank', [
- { content: 'Item 1: Product launch delayed to Q2' },
- { content: 'Item 2: New hiring targets announced' },
- { content: 'Item 3: Budget approved for ML team' }
-], { documentId: 'meeting-2024-03-15' });
-```
-
-
-
-
-```bash
-# Retain file with document ID
-hindsight retain my-bank --file notes.txt --document-id notes-2024-03-15
-
-# Batch retain directory
-hindsight retain my-bank --files docs/*.md --document-id project-docs
-```
-
-
-
-
-## Update Documents
-
-Re-retaining with the same document_id **replaces** the old content:
-
-
-
-
-```python
-# Original
-client.retain(
- bank_id="my-bank",
- content="Project deadline: March 31",
- document_id="project-plan"
-)
-
-# Update (deletes old facts, creates new ones)
-client.retain(
- bank_id="my-bank",
- content="Project deadline: April 15 (extended)",
- document_id="project-plan"
-)
-```
-
-
-
-
-```typescript
-// Original
-await client.retain('my-bank', 'Project deadline: March 31', {
- document_id: 'project-plan'
-});
-
-// Update
-await client.retain('my-bank', 'Project deadline: April 15 (extended)', {
- document_id: 'project-plan'
-});
-```
-
-
-
-
-```bash
-# Original
-hindsight retain my-bank "Project deadline: March 31" --document-id project-plan
-
-# Update
-hindsight retain my-bank "Project deadline: April 15 (extended)" --document-id project-plan
-```
-
-
-
-
-## Get Document
-
-Retrieve a document's original text and metadata. This is useful for expanding document context after a recall operation returns memories with document references.
-
-
-
-
-```python
-from hindsight_client_api import ApiClient, Configuration
-from hindsight_client_api.api import DefaultApi
-
-config = Configuration(host="http://localhost:8888")
-api_client = ApiClient(config)
-api = DefaultApi(api_client)
-
-# Get document to expand context from recall results
-doc = api.get_document(
- bank_id="my-bank",
- document_id="meeting-2024-03-15"
-)
-
-print(f"Document: {doc.id}")
-print(f"Original text: {doc.original_text}")
-print(f"Memory count: {doc.memory_unit_count}")
-print(f"Created: {doc.created_at}")
-```
-
-
-
-
-```typescript
-
-
-const apiClient = createClient(createConfig({ baseUrl: 'http://localhost:8888' }));
-
-// Get document to expand context from recall results
-const { data: doc } = await sdk.getDocument({
- client: apiClient,
- path: { bank_id: 'my-bank', document_id: 'meeting-2024-03-15' }
-});
-
-console.log(`Document: ${doc.id}`);
-console.log(`Original text: ${doc.original_text}`);
-console.log(`Memory count: ${doc.memory_unit_count}`);
-console.log(`Created: ${doc.created_at}`);
-```
-
-
-
-
-```bash
-hindsight documents get my-bank meeting-2024-03-15
-```
-
-
-
-
-## Document Response Format
-
-```json
-{
- "id": "meeting-2024-03-15",
- "bank_id": "my-bank",
- "original_text": "Alice presented the Q4 roadmap...",
- "content_hash": "abc123def456",
- "memory_unit_count": 12,
- "created_at": "2024-03-15T14:00:00Z",
- "updated_at": "2024-03-15T14:00:00Z"
-}
-```
-
-## Next Steps
-
-- [**Entities**](./entities) — Track people, places, and concepts
-- [**Operations**](./operations) — Monitor background tasks
-- [**Memory Banks**](./memory-banks) — Configure bank settings
-
-
----
-
-
-## File: developer/api/operations.md
-
-# Operations
-
-Background tasks that Hindsight executes asynchronously.
-
-:::tip Prerequisites
-Make sure you've completed the [Quick Start](./quickstart) and understand [how retain works](./retain).
-:::
-
-## How Operations Work
-
-Hindsight processes several types of tasks in the background to maintain memory quality and consistency. These operations run automatically—you don't need to trigger them manually.
-
-By default, all background operations are executed in-process within the API service.
-
-:::note Kafka Integration
-Support for external streaming platforms like Kafka for scale-out processing is planned but **not available out of the box** in the current release.
-:::
-
-## Operation Types
-
-| Operation | Trigger | Description |
-|-----------|---------|-------------|
-| **batch_retain** | `retain_batch` with `async=True` | Processes large content batches in the background |
-| **form_opinion** | After each `reflect` call | Extracts and stores new opinions formed during reflection |
-| **reinforce_opinion** | After `retain` | Updates opinion confidence based on new supporting evidence |
-| **access_count_update** | After `recall` | Tracks which memories are accessed for relevance scoring |
-| **regenerate_observations** | Bank profile update | Regenerates entity observations when disposition changes |
-
-## Next Steps
-
-- [**Documents**](./documents) — Track document sources
-- [**Entities**](./entities) — Monitor entity tracking
-- [**Memory Banks**](./memory-banks) — Configure bank settings
-
-
----
-
-
-## File: developer/installation.md
-
-# Installation
-
-Hindsight can be deployed in three ways depending on your infrastructure and requirements.
-
-## Prerequisites
-
-### PostgreSQL with pgvector
-
-Hindsight requires PostgreSQL with the **pgvector** extension for vector similarity search.
-
-**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 pgvector:
-- **Supabase** — Managed PostgreSQL with pgvector built-in
-- **Neon** — Serverless PostgreSQL with pgvector
-- **AWS RDS** / **Cloud SQL** / **Azure** — With pgvector extension enabled
-- **Self-hosted** — PostgreSQL 14+ with pgvector installed
-
-### LLM Provider
-
-You need an LLM API key for fact extraction, entity resolution, and answer generation:
-
-- **Groq** (recommended): Fast inference with `gpt-oss-20b`
-- **OpenAI**: GPT-4o, GPT-4o-mini
-- **Ollama**: Run models locally
-
-See [Models](./models) for detailed comparison and configuration.
-
----
-
-## Docker
-
-**Best for**: Quick start, development, small deployments
-
-### Single Container (Quickest)
-
-Run everything in one container with embedded PostgreSQL:
-
-```bash
-export OPENAI_API_KEY=sk-xxx
-
-docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
- -e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
- -v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
- ghcr.io/vectorize-io/hindsight:latest
-```
-
-- **API Server**: http://localhost:8888
-- **Control Plane** (Web UI): http://localhost:9999
-
----
-
-## Helm / Kubernetes
-
-**Best for**: Production deployments, auto-scaling, cloud environments
-
-```bash
-# 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+
-
-See the [Helm chart documentation](https://github.com/vectorize-io/hindsight/tree/main/helm) for advanced configuration.
-
----
-
-## Bare Metal (pip)
-
-**Best for**: Custom deployments, integration into existing Python applications
-
-### Install
-
-```bash
-pip install hindsight-all
-```
-
-### Run with Embedded Database
-
-For development and testing, Hindsight can run with an embedded PostgreSQL (pg0):
-
-```bash
-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:
-
-```bash
-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
-
-```bash
-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 --mcp # Enable MCP server
-hindsight-api --log-level debug # Verbose logging
-```
-
----
-
-## Next Steps
-
-- [Configuration](./configuration.md) — Environment variables and settings
-- [Models](./models.md) — ML models and providers
-- [Metrics](./metrics.md) — Monitoring and observability
-
-
----
-
-
-## File: developer/configuration.md
-
-# Configuration
-
-Complete reference for configuring Hindsight server through environment variables and configuration files.
-
-## Environment Variables
-
-Hindsight is configured entirely through environment variables, making it easy to deploy across different environments and container orchestration platforms.
-
-All environment variable names and defaults are defined in `hindsight_api.config`. You can use `MemoryEngine.from_env()` to create a MemoryEngine instance configured from environment variables:
-
-```python
-from hindsight_api import MemoryEngine
-
-# Create from environment variables
-memory = MemoryEngine.from_env()
-await memory.initialize()
-```
-
-### LLM Provider Configuration
-
-Configure the LLM provider used for fact extraction, entity resolution, and reasoning operations.
-
-#### Common LLM Settings
-
-| Variable | Description | Default | Required |
-|----------|-------------|---------|----------|
-| `HINDSIGHT_API_LLM_PROVIDER` | LLM provider: `groq`, `openai`, `gemini`, `ollama` | `groq` | Yes |
-| `HINDSIGHT_API_LLM_API_KEY` | API key for LLM provider | - | Yes (except ollama) |
-| `HINDSIGHT_API_LLM_MODEL` | Model name | Provider-specific | No |
-| `HINDSIGHT_API_LLM_BASE_URL` | Custom LLM endpoint | Provider default | No |
-
-#### Provider-Specific Examples
-
-**Groq (Recommended for Fast Inference)**
-
-```bash
-export HINDSIGHT_API_LLM_PROVIDER=groq
-export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
-export HINDSIGHT_API_LLM_MODEL=openai/gpt-oss-20b
-```
-
-**OpenAI**
-
-```bash
-export HINDSIGHT_API_LLM_PROVIDER=openai
-export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx
-export HINDSIGHT_API_LLM_MODEL=gpt-4o
-```
-
-**Gemini**
-
-```bash
-export HINDSIGHT_API_LLM_PROVIDER=gemini
-export HINDSIGHT_API_LLM_API_KEY=xxxxxxxxxxxx
-export HINDSIGHT_API_LLM_MODEL=gemini-2.0-flash
-```
-
-**Ollama (Local, No API Key)**
-
-```bash
-export HINDSIGHT_API_LLM_PROVIDER=ollama
-export HINDSIGHT_API_LLM_BASE_URL=http://localhost:11434/v1
-export HINDSIGHT_API_LLM_MODEL=llama3.1
-```
-
-**OpenAI-Compatible Endpoints**
-
-```bash
-export HINDSIGHT_API_LLM_PROVIDER=openai
-export HINDSIGHT_API_LLM_BASE_URL=https://your-endpoint.com/v1
-export HINDSIGHT_API_LLM_API_KEY=your-api-key
-export HINDSIGHT_API_LLM_MODEL=your-model-name
-```
-
-### Database Configuration
-
-Configure the PostgreSQL database connection and behavior.
-
-| Variable | Description | Default | Required |
-|----------|-------------|---------|----------|
-| `HINDSIGHT_API_DATABASE_URL` | PostgreSQL connection string | - | Yes* |
-
-**\*Note**: If `DATABASE_URL` is not provided, the server will use embedded `pg0` (embedded PostGRE).
-
-### MCP Server Configuration
-
-Configure the Model Context Protocol (MCP) server for AI assistant integrations.
-
-| Variable | Description | Default | Required |
-|----------|-------------|---------|----------|
-| `HINDSIGHT_API_MCP_ENABLED` | Enable MCP server | `true` | No |
-
-```bash
-# Enable MCP server (default)
-export HINDSIGHT_API_MCP_ENABLED=true
-
-# Disable MCP server
-export HINDSIGHT_API_MCP_ENABLED=false
-```
-
-### Embeddings Configuration
-
-Configure the embeddings provider for semantic search. By default, uses local SentenceTransformers models.
-
-| Variable | Description | Default | Required |
-|----------|-------------|---------|----------|
-| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local` or `tei` | `local` | No |
-| `HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL` | Model name for local provider | `BAAI/bge-small-en-v1.5` | No |
-| `HINDSIGHT_API_EMBEDDINGS_TEI_URL` | TEI server URL | - | Yes (if provider is `tei`) |
-
-**Local Provider (Default)**
-
-Uses SentenceTransformers to run embedding models locally. Good for development and smaller deployments.
-
-```bash
-export HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
-export HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5
-```
-
-**TEI Provider (HuggingFace Text Embeddings Inference)**
-
-Uses a remote [TEI server](https://github.com/huggingface/text-embeddings-inference) for high-performance inference. Recommended for production deployments.
-
-```bash
-export HINDSIGHT_API_EMBEDDINGS_PROVIDER=tei
-export HINDSIGHT_API_EMBEDDINGS_TEI_URL=http://localhost:8080
-```
-
-:::warning
-All embedding models must produce 384-dimensional vectors to match the database schema.
-:::
-
-### Reranker Configuration
-
-Configure the cross-encoder reranker for improving search result relevance. By default, uses local SentenceTransformers models.
-
-| Variable | Description | Default | Required |
-|----------|-------------|---------|----------|
-| `HINDSIGHT_API_RERANKER_PROVIDER` | Provider: `local` or `tei` | `local` | No |
-| `HINDSIGHT_API_RERANKER_LOCAL_MODEL` | Model name for local provider | `cross-encoder/ms-marco-MiniLM-L-6-v2` | No |
-| `HINDSIGHT_API_RERANKER_TEI_URL` | TEI server URL | - | Yes (if provider is `tei`) |
-
-**Local Provider (Default)**
-
-Uses SentenceTransformers CrossEncoder to run reranking locally.
-
-```bash
-export HINDSIGHT_API_RERANKER_PROVIDER=local
-export HINDSIGHT_API_RERANKER_LOCAL_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
-```
-
-**TEI Provider (HuggingFace Text Embeddings Inference)**
-
-Uses a remote [TEI server](https://github.com/huggingface/text-embeddings-inference) with a reranker model.
-
-```bash
-export HINDSIGHT_API_RERANKER_PROVIDER=tei
-export HINDSIGHT_API_RERANKER_TEI_URL=http://localhost:8081
-```
-
-:::tip
-When using TEI, you can run separate servers for embeddings and reranking, or use a single server if it supports both operations with your chosen model.
-:::
-
-## Configuration Files
-
-### .env File
-
-The Hindsight API will look for a `.env` file:
-
-```bash
-# .env
-
-# Database
-HINDSIGHT_API_DATABASE_URL=postgresql://hindsight:hindsight_dev@localhost:5432/hindsight
-
-# LLM
-HINDSIGHT_API_LLM_PROVIDER=groq
-HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
-
-# Embeddings (optional, defaults to local)
-# HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
-# HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5
-
-# Reranker (optional, defaults to local)
-# HINDSIGHT_API_RERANKER_PROVIDER=local
-# HINDSIGHT_API_RERANKER_LOCAL_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
-```
-
----
-
-For configuration issues not covered here, please [open an issue](https://github.com/your-repo/hindsight/issues) on GitHub.
-
-
----
-
-
-## File: developer/models.md
-
-# Models
-
-Hindsight uses several machine learning models for different tasks.
-
-## Overview
-
-| Model Type | Purpose | Default | Configurable |
-|------------|---------|---------|--------------|
-| **LLM** | Fact extraction, reasoning, generation | Provider-specific | Yes |
-| **Embedding** | Vector representations for semantic search | `BAAI/bge-small-en-v1.5` | Yes |
-| **Cross-Encoder** | Reranking search results | `cross-encoder/ms-marco-MiniLM-L-6-v2` | Yes |
-
-All local models (embedding, cross-encoder) are automatically downloaded from HuggingFace on first run.
-
----
-
-## LLM
-
-Used for fact extraction, entity resolution, opinion generation, and answer synthesis.
-
-**Supported providers:** OpenAI, Gemini, Groq, Ollama
-
-### Tested Models
-
-The following models have been tested and verified to work correctly with Hindsight:
-
-| Provider | Model |
-|----------|-------|
-| **OpenAI** | `gpt-5` |
-| **OpenAI** | `gpt-5-mini` |
-| **OpenAI** | `gpt-5-nano` |
-| **OpenAI** | `gpt-4.1-mini` |
-| **OpenAI** | `gpt-4.1-nano` |
-| **OpenAI** | `gpt-4o-mini` |
-| **Gemini** | `gemini-2.5-flash` |
-| **Gemini** | `gemini-2.5-flash-lite` |
-| **Groq** | `openai/gpt-oss-120b` |
-| **Groq** | `openai/gpt-oss-20b` |
-| **Groq** | `llama-3.3-70b-versatile` |
-
-### Using Other Models
-
-Other LLM models not listed above may work with Hindsight, but they must support **at least 65,000 output tokens** to ensure reliable fact extraction. If you need support for a specific model that doesn't meet this requirement, please [open an issue](https://github.com/hindsight-ai/hindsight/issues) to request an exception.
-
-### Configuration
-
-```bash
-# Groq (recommended)
-export HINDSIGHT_API_LLM_PROVIDER=groq
-export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
-export HINDSIGHT_API_LLM_MODEL=openai/gpt-oss-20b
-
-# OpenAI
-export HINDSIGHT_API_LLM_PROVIDER=openai
-export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx
-export HINDSIGHT_API_LLM_MODEL=gpt-4o
-
-# Gemini
-export HINDSIGHT_API_LLM_PROVIDER=gemini
-export HINDSIGHT_API_LLM_API_KEY=xxxxxxxxxxxx
-export HINDSIGHT_API_LLM_MODEL=gemini-2.0-flash
-
-# Ollama (local)
-export HINDSIGHT_API_LLM_PROVIDER=ollama
-export HINDSIGHT_API_LLM_BASE_URL=http://localhost:11434/v1
-export HINDSIGHT_API_LLM_MODEL=llama3.1
-```
-
-**Note:** The LLM is the primary bottleneck for retain operations. See [Performance](./performance) for optimization strategies.
-
----
-
-## Embedding Model
-
-Converts text into dense vector representations for semantic similarity search.
-
-**Default:** `BAAI/bge-small-en-v1.5` (384 dimensions, ~130MB)
-
-**Alternatives:**
-
-| Model | Use Case |
-|-------|----------|
-| `BAAI/bge-small-en-v1.5` | Default, fast, good quality |
-| `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` | Multilingual (50+ languages) |
-
-:::warning
-All embedding models must produce **384-dimensional vectors** to match the database schema.
-:::
-
-**Configuration:**
-
-```bash
-# Local provider (default)
-export HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
-export HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5
-
-# TEI provider (remote)
-export HINDSIGHT_API_EMBEDDINGS_PROVIDER=tei
-export HINDSIGHT_API_EMBEDDINGS_TEI_URL=http://localhost:8080
-```
-
----
-
-## Cross-Encoder (Reranker)
-
-Reranks initial search results to improve precision.
-
-**Default:** `cross-encoder/ms-marco-MiniLM-L-6-v2` (~85MB)
-
-**Alternatives:**
-
-| Model | Use Case |
-|-------|----------|
-| `cross-encoder/ms-marco-MiniLM-L-6-v2` | Default, fast |
-| `cross-encoder/ms-marco-MiniLM-L-12-v2` | Higher accuracy |
-| `cross-encoder/mmarco-mMiniLMv2-L12-H384-v1` | Multilingual |
-
-**Configuration:**
-
-```bash
-# Local provider (default)
-export HINDSIGHT_API_RERANKER_PROVIDER=local
-export HINDSIGHT_API_RERANKER_LOCAL_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
-
-# TEI provider (remote)
-export HINDSIGHT_API_RERANKER_PROVIDER=tei
-export HINDSIGHT_API_RERANKER_TEI_URL=http://localhost:8081
-```
-
-
----
-
-
-## File: developer/rag-vs-hindsight.md
-
-# RAG vs Memory
-
-Traditional RAG (Retrieval-Augmented Generation) retrieves documents similar to a query. Hindsight provides structured memory with temporal reasoning, entity understanding, and belief formation.
-
-## Capability Comparison
-
-| Capability | RAG | Hindsight |
-|------------|-----|-----------|
-| **Search strategy** | Semantic similarity only | Semantic + keyword + graph + temporal |
-| **Multi-hop reasoning** | Limited to retrieved chunks | Graph traversal across entity relationships |
-| **Temporal queries** | Keyword matching ("spring") | Date parsing and range filtering |
-| **Entity understanding** | None | Entity resolution, observations, co-occurrence |
-| **Belief formation** | Stateless | Opinions with confidence scores that evolve |
-| **Disposition** | None | 3 traits (skepticism, literalism, empathy) influence interpretation |
-
-## Architecture Comparison
-
-### RAG
-
-| Step | Operation |
-|------|-----------|
-| 1 | Embed query |
-| 2 | Vector similarity search |
-| 3 | Return top-k chunks |
-| 4 | Generate response |
-
-Single retrieval strategy. No state between queries.
-
-### Hindsight
-
-| Step | Operation |
-|------|-----------|
-| 1 | Parse query (extract temporal expressions, entities) |
-| 2 | Execute 4 parallel retrievals: semantic, BM25, graph, temporal |
-| 3 | Fuse results with RRF |
-| 4 | Rerank with cross-encoder |
-| 5 | Apply disposition traits |
-| 6 | Generate response |
-
-Multiple retrieval strategies. Persistent state across sessions.
-
-## Example Scenarios
-
-### Multi-Hop Reasoning
-
-**Stored facts:**
-- "Alice is the tech lead on Project Atlas"
-- "Project Atlas uses Kubernetes"
-- "Kubernetes cluster had an outage Tuesday"
-
-**Query:** "Was Alice affected by recent issues?"
-
-| System | Result |
-|--------|--------|
-| RAG | Retrieves facts about Alice only (no semantic similarity to "issues") |
-| Hindsight | Traverses Alice → Project Atlas → Kubernetes → outage via entity links |
-
-### Temporal Queries
-
-**Stored facts with timestamps:**
-- March: "Alice started microservices migration"
-- April: "Alice completed auth service"
-- October: "Alice focusing on performance"
-
-**Query:** "What did Alice do last spring?"
-
-| System | Result |
-|--------|--------|
-| RAG | Returns all Alice facts regardless of date |
-| Hindsight | Parses "last spring" → March-May, filters to that range |
-
-### Entity Understanding
-
-**Stored facts about a user across sessions:**
-- "Pro subscription"
-- "Mobile app crashes in settings"
-- "Switched to annual billing"
-- "Desktop app working fine"
-
-**Query:** "What do you know about my account?"
-
-| System | Result |
-|--------|--------|
-| RAG | Lists disconnected facts |
-| Hindsight | Returns synthesized entity observations: subscription status, billing, known issues |
-
-### Belief Evolution
-
-**Week 1:** User struggles with async Python, succeeds with threads
-**Week 3:** User asks about asyncio, implements async database calls
-
-| System | Behavior |
-|--------|----------|
-| RAG | No memory of progression |
-| Hindsight | Forms opinion "user prefers sync" (0.7) → updates to "user growing comfortable with async" (0.6) |
-
-## When to Use Each
-
-| Use Case | Recommended |
-|----------|-------------|
-| Document Q&A over static corpus | RAG |
-| Search with no temporal requirements | RAG |
-| AI assistants with persistent memory | Hindsight |
-| Applications requiring entity tracking | Hindsight |
-| Systems needing consistent disposition | Hindsight |
-| Temporal queries ("last month", "in 2023") | Hindsight |
-
-
----
-
-
-## File: sdks/python.md
-
-# Python Client
-
-Official Python client for the Hindsight API.
-
-
-
-
-## Installation
-
-
-
-
-The `hindsight-all` package includes embedded PostgreSQL, HTTP API server, and client:
-
-```bash
-pip install hindsight-all
-```
-
-
-
-
-If you already have a Hindsight server running:
-
-```bash
-pip install hindsight-client
-```
-
-
-
-
-## Quick Start
-
-
-
-
-```python
-
-from hindsight import HindsightServer, HindsightClient
-
-with HindsightServer(
- llm_provider="openai",
- llm_model="gpt-4.1-mini",
- llm_api_key=os.environ["OPENAI_API_KEY"]
-) as server:
- client = HindsightClient(base_url=server.url)
-
- # Retain a memory
- client.retain(bank_id="my-bank", content="Alice works at Google")
-
- # Recall memories
- results = client.recall(bank_id="my-bank", query="What does Alice do?")
- for r in results:
- print(r.text)
-
- # Reflect - generate response with disposition
- answer = client.reflect(bank_id="my-bank", query="Tell me about Alice")
- print(answer.text)
-```
-
-
-
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(base_url="http://localhost:8888")
-
-# Retain a memory
-client.retain(bank_id="my-bank", content="Alice works at Google")
-
-# Recall memories
-results = client.recall(bank_id="my-bank", query="What does Alice do?")
-for r in results:
- print(r.text)
-
-# Reflect - generate response with disposition
-answer = client.reflect(bank_id="my-bank", query="Tell me about Alice")
-print(answer.text)
-```
-
-
-
-
-## Client Initialization
-
-```python
-from hindsight_client import Hindsight
-
-client = Hindsight(
- base_url="http://localhost:8888", # Hindsight API URL
- timeout=30.0, # Request timeout in seconds
-)
-```
-
-## Core Operations
-
-### Retain (Store Memory)
-
-```python
-# Simple
-client.retain(
- bank_id="my-bank",
- content="Alice works at Google as a software engineer",
-)
-
-# With options
-from datetime import datetime
-
-client.retain(
- bank_id="my-bank",
- content="Alice got promoted",
- context="career update",
- timestamp=datetime(2024, 1, 15),
- document_id="conversation_001",
- metadata={"source": "slack"},
-)
-```
-
-### Retain Batch
-
-```python
-client.retain_batch(
- bank_id="my-bank",
- items=[
- {"content": "Alice works at Google", "context": "career"},
- {"content": "Bob is a data scientist", "context": "career"},
- ],
- document_id="conversation_001",
- retain_async=False, # Set True for background processing
-)
-```
-
-### Recall (Search)
-
-```python
-# Simple - returns list of RecallResult
-results = client.recall(
- bank_id="my-bank",
- query="What does Alice do?",
-)
-
-for r in results.results:
- print(f"{r.text} (type: {r.type})")
-
-# With options
-results = client.recall(
- bank_id="my-bank",
- query="What does Alice do?",
- types=["world", "opinion"], # Filter by fact type
- max_tokens=4096,
- budget="high", # low, mid, or high
-)
-```
-
-### Recall with Full Response
-
-```python
-# Returns RecallResponse with entities and chunks
-response = client.recall(
- bank_id="my-bank",
- query="What does Alice do?",
- types=["world", "experience"],
- budget="mid",
- max_tokens=4096,
- include_entities=True,
- max_entity_tokens=500
-)
-
-print(f"Found {len(response.results)} memories")
-for r in response.results:
- print(f" - {r.text}")
-
-# Access entities
-if response.entities:
- for entity in response.entities:
- print(f"Entity: {entity.name}")
-```
-
-### Reflect (Generate Response)
-
-```python
-answer = client.reflect(
- bank_id="my-bank",
- query="What should I know about Alice?",
- budget="low", # low, mid, or high
- context="preparing for a meeting",
-)
-
-print(answer.text) # Generated response
-```
-
-## Bank Management
-
-### Create Bank
-
-```python
-client.create_bank(
- bank_id="my-bank",
- name="Assistant",
- background="I am a helpful AI assistant",
- disposition={
- "skepticism": 3, # 1-5: trusting to skeptical
- "literalism": 3, # 1-5: flexible to literal
- "empathy": 3, # 1-5: detached to empathetic
- },
-)
-```
-
-### List Memories
-
-```python
-client.list_memories(
- bank_id="my-bank",
- type="world", # Optional: filter by type
- search_query="Alice", # Optional: text search
- limit=100,
- offset=0,
-)
-```
-
-## Async Support
-
-All methods have async versions prefixed with `a`:
-
-```python
-
-from hindsight_client import Hindsight
-
-async def main():
- client = Hindsight(base_url="http://localhost:8888")
-
- # Async retain
- await client.aretain(bank_id="my-bank", content="Hello world")
-
- # Async recall
- results = await client.arecall(bank_id="my-bank", query="Hello")
- for r in results:
- print(r.text)
-
- # Async reflect
- answer = await client.areflect(bank_id="my-bank", query="What did I say?")
- print(answer.text)
-
- client.close()
-
-asyncio.run(main())
-```
-
-## Context Manager
-
-```python
-from hindsight_client import Hindsight
-
-with Hindsight(base_url="http://localhost:8888") as client:
- client.retain(bank_id="my-bank", content="Hello")
- results = client.recall(bank_id="my-bank", query="Hello")
-# Client automatically closed
-```
-
-
----
-
-
-## File: sdks/nodejs.md
-
-# Node.js Client
-
-Official TypeScript/JavaScript client for the Hindsight API.
-
-## Installation
-
-```bash
-npm install @vectorize-io/hindsight-client
-```
-
-## Quick Start
-
-```typescript
-const { HindsightClient } = require('@vectorize-io/hindsight-client');
-
-const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
-
-// Retain a memory
-await client.retain('my-bank', 'Alice works at Google');
-
-// Recall memories
-const response = await client.recall('my-bank', 'What does Alice do?');
-for (const r of response.results) {
- console.log(r.text);
-}
-
-// Reflect - generate response with disposition
-const answer = await client.reflect('my-bank', 'Tell me about Alice');
-console.log(answer.text);
-```
-
-## Client Initialization
-
-```typescript
-
-
-const client = new HindsightClient({
- baseUrl: 'http://localhost:8888',
-});
-```
-
-## Core Operations
-
-### Retain (Store Memory)
-
-```typescript
-// Simple
-await client.retain('my-bank', 'Alice works at Google');
-
-// With options
-await client.retain('my-bank', 'Alice got promoted', {
- timestamp: new Date('2024-01-15'),
- context: 'career update',
- metadata: { source: 'slack' },
- async: false, // Set true for background processing
-});
-```
-
-### Retain Batch
-
-```typescript
-await client.retainBatch('my-bank', [
- { content: 'Alice works at Google', context: 'career' },
- { content: 'Bob is a data scientist', context: 'career' },
-], {
- async: false,
-});
-```
-
-### Recall (Search)
-
-```typescript
-// Simple - returns RecallResponse
-const response = await client.recall('my-bank', 'What does Alice do?');
-
-for (const r of response.results) {
- console.log(`${r.text} (type: ${r.type})`);
-}
-
-// With options
-const response = await client.recall('my-bank', 'What does Alice do?', {
- types: ['world', 'opinion'], // Filter by fact type
- maxTokens: 4096,
- budget: 'high', // 'low', 'mid', or 'high'
-});
-```
-
-### Reflect (Generate Response)
-
-```typescript
-const answer = await client.reflect('my-bank', 'What should I know about Alice?', {
- budget: 'low', // 'low', 'mid', or 'high'
- context: 'preparing for a meeting',
-});
-
-console.log(answer.text); // Generated response
-```
-
-## Bank Management
-
-### Create Bank
-
-```typescript
-await client.createBank('my-bank', {
- name: 'Assistant',
- background: 'I am a helpful AI assistant',
- disposition: {
- skepticism: 3, // 1-5: trusting to skeptical
- literalism: 3, // 1-5: flexible to literal
- empathy: 3, // 1-5: detached to empathetic
- },
-});
-```
-
-### List Memories
-
-```typescript
-const response = await client.listMemories('my-bank', {
- type: 'world', // Optional filter
- q: 'Alice', // Optional text search
- limit: 100,
- offset: 0,
-});
-console.log(response)
-```
-
-
----
-
-
-## File: sdks/cli.md
-
-# CLI Reference
-
-The Hindsight CLI provides command-line access to memory operations and bank management.
-
-## Installation
-
-```bash
-curl -fsSL https://hindsight.vectorize.io/get-cli | bash
-```
-
-## Configuration
-
-Configure the API URL:
-
-```bash
-# Interactive configuration
-hindsight configure
-
-# Or set directly
-hindsight configure --api-url http://localhost:8888
-
-# Or use environment variable (highest priority)
-export HINDSIGHT_API_URL=http://localhost:8888
-```
-
-## Core Commands
-
-### Retain (Store Memory)
-
-Store a single memory:
-
-```bash
-hindsight memory retain "Alice works at Google as a software engineer"
-
-# With context
-hindsight memory retain "Bob loves hiking" --context "hobby discussion"
-
-# Queue for background processing
-hindsight memory retain "Meeting notes" --async
-```
-
-### Retain Files
-
-Bulk import from files:
-
-```bash
-# Single file
-hindsight memory retain-files notes.txt
-
-# Directory (recursive by default)
-hindsight memory retain-files ./documents/
-
-# With context
-hindsight memory retain-files meeting-notes.txt --context "team meeting"
-
-# Background processing
-hindsight memory retain-files ./data/ --async
-```
-
-### Recall (Search)
-
-Search memories using semantic similarity:
-
-```bash
-hindsight memory recall "What does Alice do?"
-
-# With options
-hindsight memory recall "hiking recommendations" \
- --budget high \
- --max-tokens 8192
-
-# Filter by fact type
-hindsight memory recall "query" --fact-type world,opinion
-
-# Show trace information
-hindsight memory recall "query" --trace
-```
-
-### Reflect (Generate Response)
-
-Generate a response using memories and bank disposition:
-
-```bash
-hindsight memory reflect "What do you know about Alice?"
-
-# With additional context
-hindsight memory reflect "Should I learn Python?" --context "career advice"
-
-# Higher budget for complex questions
-hindsight memory reflect "Summarize my week" --budget high
-```
-
-## Bank Management
-
-### List Banks
-
-```bash
-hindsight bank list
-```
-
-### View Profile
-
-```bash
-hindsight bank profile
-```
-
-### View Statistics
-
-```bash
-hindsight bank stats
-```
-
-### Set Bank Name
-
-```bash
-hindsight bank name "My Assistant"
-```
-
-### Set Background
-
-```bash
-hindsight bank background "I am a helpful AI assistant interested in technology"
-
-# Skip automatic disposition inference
-hindsight bank background "Background text" --no-update-disposition
-```
-
-## Document Management
-
-```bash
-# List documents
-hindsight document list
-
-# Get document details
-hindsight document get
-
-# Delete document and its memories
-hindsight document delete
-```
-
-## Entity Management
-
-```bash
-# List entities
-hindsight entity list
-
-# Get entity details
-hindsight entity get
-
-# Regenerate entity observations
-hindsight entity regenerate
-```
-
-## Output Formats
-
-```bash
-# Pretty (default)
-hindsight memory recall "query"
-
-# JSON
-hindsight memory recall "query" -o json
-
-# YAML
-hindsight memory recall "query" -o yaml
-```
-
-## Global Options
-
-| Flag | Description |
-|------|-------------|
-| `-v, --verbose` | Show detailed output including request/response |
-| `-o, --output ` | Output format: pretty, json, yaml |
-| `--help` | Show help |
-| `--version` | Show version |
-
-## Interactive Explorer
-
-Launch the TUI explorer for visual navigation of your memory banks:
-
-```bash
-hindsight explore
-```
-
-The explorer provides an interactive terminal interface to:
-
-- **Browse memory banks** — View all banks and their statistics
-- **Search memories** — Run recall queries with real-time results
-- **Inspect entities** — Explore the knowledge graph and entity relationships
-- **View facts** — Browse world facts, experiences, and opinions
-- **Navigate documents** — See source documents and their extracted memories
-
-### Keyboard Shortcuts
-
-| Key | Action |
-|-----|--------|
-| `↑/↓` | Navigate items |
-| `Enter` | Select / Expand |
-| `Tab` | Switch panels |
-| `/` | Search |
-| `q` | Quit |
-
-
-
-## Example Workflow
-
-```bash
-# Configure API URL
-hindsight configure --api-url http://localhost:8888
-
-# Store some memories
-hindsight memory retain demo "Alice works at Google"
-hindsight memory retain demo "Bob is a data scientist"
-hindsight memory retain demo "Alice and Bob are colleagues"
-
-# Search memories
-hindsight memory recall demo "Who works with Alice?"
-
-# Generate a response
-hindsight memory reflect demo "What do you know about the team?"
-
-# Check bank profile
-hindsight bank profile demo
-```
-
-
----
-
-
-## File: cookbook/index.md
-
-# Cookbook
-
-Practical patterns and recipes for building with Hindsight.
-
-## Use Cases
-
-### [Per-User Memory](/cookbook/per-user-memory)
-
-The simplest pattern: give your agent persistent memory for each user. The agent remembers past conversations, preferences, and context across sessions.
-
-**Use when:** Building chatbots, personal assistants, or any 1:1 user-to-agent interaction.
-
-### [Support Agent with Shared Knowledge](/cookbook/support-agent-with-shared-knowledge)
-
-Build a support agent that combines per-user memory with shared product documentation. Users get personalized support while you index docs only once.
-
-**Use when:** Building multi-tenant support agents, RAG + memory applications, or any scenario needing user isolation with shared reference data.
-
-
----
-
-
-## File: cookbook/per-user-memory.md
-
-# Per-User Memory
-
-The simplest pattern: give your agent persistent memory for each user. The agent remembers past conversations, user preferences, and context across sessions.
-
-## The Problem
-
-Without memory, every conversation starts from scratch:
-
-```
-Session 1: "I prefer dark mode and use Python"
-Session 2: "What's my preferred language?" → Agent doesn't know
-```
-
-## The Solution: One Bank Per User
-
-```
-┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
-│ User A Bank │ │ User B Bank │ │ User C Bank │
-│ │ │ │ │ │
-│ - Conversations│ │ - Conversations│ │ - Conversations│
-│ - Preferences │ │ - Preferences │ │ - Preferences │
-│ - Context │ │ - Context │ │ - Context │
-└─────────────────┘ └─────────────────┘ └─────────────────┘
- │ │ │
- 100% isolated 100% isolated 100% isolated
-```
-
-Each user gets their own memory bank. Complete isolation, simple mental model.
-
-## Implementation
-
-### 1. Create a Bank When User Signs Up
-
-```python
-from hindsight import HindsightClient
-
-client = HindsightClient()
-
-def on_user_signup(user_id: str):
- client.create_bank(
- bank_id=f"user-{user_id}",
- name=f"Memory for {user_id}"
- )
-```
-
-### 2. Manage Conversation Sessions
-
-Use `document_id` to group messages belonging to the same conversation. When you retain with the same `document_id`, Hindsight replaces the previous version (upsert behavior), keeping the memory up-to-date as the conversation evolves.
-
-```python
-
-
-class ConversationSession:
- def __init__(self, user_id: str):
- self.user_id = user_id
- self.session_id = str(uuid.uuid4()) # Unique ID for this conversation
- self.messages = []
-
- def add_message(self, role: str, content: str):
- self.messages.append({"role": role, "content": content})
-
- async def save(self, client: HindsightClient):
- """Save the entire conversation. Replaces previous version if session_id exists."""
- await client.retain(
- bank_id=f"user-{self.user_id}",
- content=self.messages,
- document_id=self.session_id # Same ID = upsert (replace old version)
- )
-```
-
-### 3. Recall Context Before Responding
-
-```python
-async def get_context(user_id: str, query: str):
- result = await client.recall(
- bank_id=f"user-{user_id}",
- query=query
- )
- return result.results
-```
-
-### 4. Complete Agent Loop
-
-```python
-async def handle_message(session: ConversationSession, user_message: str):
- # 1. Add user message to session
- session.add_message("user", user_message)
-
- # 2. Recall relevant context from past conversations
- context = await client.recall(
- bank_id=f"user-{session.user_id}",
- query=user_message
- )
-
- # 3. Build prompt with memory
- prompt = f"""You are a helpful assistant with memory of past conversations.
-
-## What you remember about this user
-{format_results(context.results)}
-
-## Current conversation
-{format_messages(session.messages)}
-"""
-
- # 4. Generate response
- response = await llm.complete(prompt)
-
- # 5. Add assistant response to session
- session.add_message("assistant", response)
-
- # 6. Save the updated conversation (upserts based on session_id)
- await session.save(client)
-
- return response
-```
-
-### 5. Starting a New Conversation
-
-```python
-# Each new conversation gets a new session with a unique ID
-session = ConversationSession(user_id="alice")
-
-# Multiple exchanges in the same conversation
-await handle_message(session, "Hi! I'm working on a Python project")
-await handle_message(session, "Can you help me with async/await?")
-
-# Start a new conversation later (new session_id)
-new_session = ConversationSession(user_id="alice")
-await handle_message(new_session, "Different topic today...")
-```
-
-## How Document ID Works
-
-The `document_id` parameter is key to managing evolving conversations:
-
-| Scenario | Behavior |
-|----------|----------|
-| First retain with `document_id="session_123"` | Creates new document |
-| Retain again with same `document_id="session_123"` | **Replaces** previous version (upsert) |
-| Retain with different `document_id="session_456"` | Creates separate document |
-| Retain without `document_id` | Creates new document each time |
-
-This upsert behavior means:
-- You always retain the **full conversation** state
-- Facts are re-extracted from the complete conversation
-- No duplicate or stale facts from old versions
-- Memory stays consistent as conversations evolve
-
-## What Gets Remembered
-
-Hindsight automatically extracts and connects:
-
-- **Facts**: "User prefers Python", "User is building a CLI tool"
-- **Entities**: People, projects, technologies mentioned
-- **Relationships**: How entities relate to each other
-- **Temporal context**: When things happened
-
-You don't need to manually extract or structure this - just retain the conversations.
-
-## When to Use This Pattern
-
-**Good fit:**
-- Chatbots and assistants
-- Personal AI companions
-- Any 1:1 user-to-agent interaction
-
-**Consider adding shared knowledge if:**
-- You have product docs or FAQs to reference
-- Multiple users need access to the same information
-- See [Support Agent with Shared Knowledge](./support-agent-with-shared-knowledge)
-
-
----
-
-
-## File: cookbook/support-agent-with-shared-knowledge.md
-
-# Support Agent with Shared Knowledge
-
-This pattern shows how to build a support agent that combines **per-user memory** with **shared product knowledge** (RAG), giving users personalized support while leveraging a single source of truth for documentation.
-
-## The Problem
-
-You're building a support agent that needs to:
-- Remember each user's history, preferences, and past issues
-- Access shared product documentation
-- Keep user data completely isolated from other users
-
-A naive approach would index product docs into each user's memory bank, but this is expensive and wasteful (N copies for N users).
-
-## The Solution: Multi-Bank Architecture
-
-Create separate memory banks for different concerns:
-
-```
-┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
-│ User A Bank │ │ User B Bank │ │ Shared Docs │
-│ │ │ │ │ Bank │
-│ - Conversations│ │ - Conversations│ │ │
-│ - Preferences │ │ - Preferences │ │ - Product docs │
-│ - Past issues │ │ - Past issues │ │ - FAQs │
-│ - Solutions │ │ - Solutions │ │ - Guides │
-└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
- │ │ │
- └───────────────────────┴───────────────────────┘
- │
- Agent queries
- multiple banks
-```
-
-**Key benefits:**
-- Product docs indexed once, shared by all users
-- User memory is 100% isolated
-- Simple mental model, no complex filtering
-
-## Implementation
-
-### 1. Set Up Memory Banks
-
-Create three types of banks:
-
-```python
-from hindsight import HindsightClient
-
-client = HindsightClient()
-
-# Shared knowledge bank (created once)
-shared_bank = client.create_bank(
- bank_id="product-docs",
- name="Product Documentation"
-)
-
-# Per-user banks (created when user signs up)
-def create_user_bank(user_id: str):
- return client.create_bank(
- bank_id=f"user-{user_id}",
- name=f"Memory for {user_id}"
- )
-```
-
-### 2. Index Product Documentation
-
-Index your product docs into the shared bank (do this once, or on doc updates):
-
-```python
-# Index product documentation
-client.retain(
- bank_id="product-docs",
- content=[
- {
- "role": "document",
- "content": "# Pricing Tiers\n\nBasic: $10/mo...",
- "metadata": {"source": "pricing.md"}
- },
- {
- "role": "document",
- "content": "# Getting Started\n\nTo set up...",
- "metadata": {"source": "quickstart.md"}
- }
- ]
-)
-```
-
-### 3. Store User Conversations
-
-After each support interaction, retain it in the user's bank:
-
-```python
-def save_conversation(user_id: str, messages: list):
- client.retain(
- bank_id=f"user-{user_id}",
- content=messages # [{"role": "user", "content": "..."}, ...]
- )
-```
-
-### 4. Query Multiple Banks at Support Time
-
-When handling a user query, retrieve context from both banks:
-
-```python
-async def get_support_context(user_id: str, query: str):
- # Get user's personal context
- user_context = await client.recall(
- bank_id=f"user-{user_id}",
- query=query
- )
-
- # Get relevant product documentation
- docs_context = await client.recall(
- bank_id="product-docs",
- query=query
- )
-
- return {
- "user_history": user_context.results,
- "documentation": docs_context.results
- }
-```
-
-### 5. Build the Agent Prompt
-
-Combine both contexts in your agent's prompt:
-
-```python
-def build_prompt(query: str, context: dict) -> str:
- return f"""You are a helpful support agent.
-
-## User's History
-{format_results(context["user_history"])}
-
-## Product Documentation
-{format_results(context["documentation"])}
-
-## Current Question
-{query}
-
-Use the user's history to personalize your response and the documentation
-for accurate product information. If you find a solution, remember it for
-future reference.
-"""
-```
-
-## Promoting Learnings to Shared Knowledge
-
-When the agent discovers a solution that's not in the docs, you can optionally promote it to a "learnings" bank:
-
-```
-┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
-│ User A Bank │ │ Shared Docs │ │ Learnings │
-│ │ │ Bank │ │ Bank │
-│ - Conversations│ │ │ │ │
-│ - Preferences │ │ - Product docs │ │ - Verified │
-│ - Past issues │ │ - FAQs │ │ solutions │
-│ - Solutions │ │ - Guides │ │ - Workarounds │
-└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
- │ │ │
- └───────────────────────┴───────────────────────┘
- │
- Agent queries
- all three banks
-```
-
-```python
-# Optional: Create a curated learnings bank
-learnings_bank = client.create_bank(
- bank_id="support-learnings",
- name="Curated Support Learnings"
-)
-
-# After a successful resolution
-def promote_learning(insight: str):
- client.retain(
- bank_id="support-learnings",
- content=[{
- "role": "system",
- "content": insight,
- "metadata": {"type": "verified_solution"}
- }]
- )
-```
-
-Then query three banks: user + docs + learnings.
-
-## Complete Example
-
-```python
-from hindsight import HindsightClient
-
-client = HindsightClient()
-
-async def handle_support_request(user_id: str, query: str):
- # 1. Recall from user's memory
- user_recall = await client.recall(
- bank_id=f"user-{user_id}",
- query=query
- )
-
- # 2. Recall from shared docs
- docs_recall = await client.recall(
- bank_id="product-docs",
- query=query
- )
-
- # 3. Recall from learnings (optional)
- learnings_recall = await client.recall(
- bank_id="support-learnings",
- query=query
- )
-
- # 4. Build context for LLM
- context = f"""
-User History:
-{format_results(user_recall.results)}
-
-Product Docs:
-{format_results(docs_recall.results)}
-
-Known Solutions:
-{format_results(learnings_recall.results)}
-"""
-
- # 5. Generate response with your LLM
- response = await llm.complete(
- system="You are a support agent...",
- context=context,
- query=query
- )
-
- # 6. Save the conversation to user's memory
- await client.retain(
- bank_id=f"user-{user_id}",
- content=[
- {"role": "user", "content": query},
- {"role": "assistant", "content": response}
- ]
- )
-
- return response
-```
-
-## When to Use This Pattern
-
-**Good fit:**
-- Support agents with shared documentation
-- Multi-tenant applications with shared reference data
-- Any scenario needing user isolation + shared knowledge
-
-**Consider alternatives if:**
-- You need cross-user learning (users benefiting from other users' solutions)
-- Entity relationships must span across users and docs
-
-
-
----
-
-
-## File: changelog/index.md
-
-# Changelog
-
-For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
-
-## [0.1.5](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.5)
-
-**Features**
-
-- Added LiteLLM integration so Hindsight can capture and manage memories from LiteLLM-based LLM calls. ([`dfccbf2`](https://github.com/vectorize-io/hindsight/commit/dfccbf2))
-- Added an optional graph-based retriever (MPFP) to improve recall by leveraging relationships between memories. ([`7445cef`](https://github.com/vectorize-io/hindsight/commit/7445cef))
-
-**Improvements**
-
-- Switched the embedded Postgres layer to pg0-embedded for a smoother local/standalone experience. ([`94c2b85`](https://github.com/vectorize-io/hindsight/commit/94c2b85))
-
-**Bug Fixes**
-
-- Fixed repeated retries on 400 errors from the LLM, preventing unnecessary request loops and failures. ([`70983f5`](https://github.com/vectorize-io/hindsight/commit/70983f5))
-- Fixed recall trace visualization in the control plane so search/recall debugging displays correctly. ([`922164e`](https://github.com/vectorize-io/hindsight/commit/922164e))
-- Fixed the CLI installer to make installation more reliable. ([`158a6aa`](https://github.com/vectorize-io/hindsight/commit/158a6aa))
-- Updated Next.js to patch security vulnerabilities (CVE-2025-55184, CVE-2025-55183). ([`f018cc5`](https://github.com/vectorize-io/hindsight/commit/f018cc5))
-
-## [0.1.3](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.3)
-
-**Improvements**
-
-- Improved CLI and UI branding/polish, including new banner/logo assets and updated interface styling. ([`fa554b8`](https://github.com/vectorize-io/hindsight/commit/fa554b8))
-
-
-## [0.1.2](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.2)
-
-**Bug Fixes**
-
-- Fixed the standalone Docker image so it builds/runs correctly. ([`1056a20`](https://github.com/vectorize-io/hindsight/commit/1056a20))
-
-
----
-
-
-## File: developer/api/opinions.md
-
-# Opinions
-
-How memory banks form, store, and evolve beliefs.
-
-
-
-
-:::tip Prerequisites
-Make sure you've completed the [Quick Start](./quickstart) to install the client and start the server.
-:::
-
-## What Are Opinions?
-
-Opinions are beliefs formed by the memory bank based on evidence and disposition. Unlike world facts (objective information received) or experience (conversations and events), opinions are **judgments** with confidence scores.
-
-| Type | Example | Confidence |
-|------|---------|------------|
-| World Fact | "Python was created in 1991" | — |
-| Experience | "I recommended Python to Bob" | — |
-| Opinion | "Python is the best language for data science" | 0.85 |
-
-## How Opinions Form
-
-Opinions are created during `reflect` operations when the memory bank:
-1. Retrieves relevant facts
-2. Applies disposition traits
-3. Forms a judgment
-4. Assigns a confidence score
-
-```mermaid
-graph LR
- F[Facts] --> D[Disposition Filter]
- D --> J[Judgment]
- J --> O[Opinion + Confidence]
- O --> S[(Store)]
-```
-
-
-
-
-```python
-# Ask a question that might form an opinion
-answer = client.reflect(
- bank_id="my-bank",
- query="What do you think about functional programming?"
-)
-
-# Check if new opinions were formed
-for opinion in answer.get("new_opinions", []):
- print(f"New opinion: {opinion['text']}")
- print(f"Confidence: {opinion['confidence']}")
-```
-
-
-
-
-## Searching Opinions
-
-
-
-
-```python
-# Search only opinions
-opinions = client.recall(
- bank_id="my-bank",
- query="programming languages",
- types=["opinion"]
-)
-
-for op in opinions:
- print(f"{op['text']} (confidence: {op['confidence_score']:.2f})")
-```
-
-
-
-
-```bash
-hindsight recall my-bank "programming" --types opinion
-```
-
-
-
-
-## Opinion Evolution
-
-Opinions change as new evidence arrives:
-
-| Evidence Type | Effect |
-|---------------|--------|
-| **Reinforcing** | Confidence increases (+0.1) |
-| **Weakening** | Confidence decreases (-0.15) |
-| **Contradicting** | Opinion revised, confidence reset |
-
-**Example evolution:**
-
-```
-t=0: "Python is best for data science" (0.70)
- ↓ New evidence: Python dominates ML libraries
-t=1: "Python is best for data science" (0.85)
- ↓ New evidence: Julia is 10x faster for numerical computing
-t=2: "Python is best for data science, though Julia is faster" (0.75)
- ↓ New evidence: Most teams still use Python
-t=3: "Python is best for data science" (0.82)
-```
-
-## Disposition Influence
-
-Different dispositions form different opinions from the same facts:
-
-
-
-
-```python
-# Create two memory banks with different dispositions
-client.create_bank(
- bank_id="open-minded",
- disposition={"skepticism": 2, "literalism": 2, "empathy": 4}
-)
-
-client.create_bank(
- bank_id="conservative",
- disposition={"skepticism": 5, "literalism": 5, "empathy": 2}
-)
-
-# Store the same facts to both
-facts = [
- "Rust has better memory safety than C++",
- "C++ has a larger ecosystem and more libraries",
- "Rust compile times are longer than C++"
-]
-for fact in facts:
- client.retain(bank_id="open-minded", content=fact)
- client.retain(bank_id="conservative", content=fact)
-
-# Ask both the same question
-q = "Should we rewrite our C++ codebase in Rust?"
-
-answer1 = client.reflect(bank_id="open-minded", query=q)
-# Likely: "Yes, Rust's safety benefits outweigh migration costs"
-
-answer2 = client.reflect(bank_id="conservative", query=q)
-# Likely: "No, C++'s ecosystem and our team's expertise make it the safer choice"
-```
-
-
-
-
-## Opinions in Reflect Responses
-
-When `reflect` uses opinions, they appear in `based_on`:
-
-```python
-answer = client.reflect(bank_id="my-bank", query="What language should I learn?")
-
-print("World facts used:")
-for f in answer.based_on.get("world", []):
- print(f" {f['text']}")
-
-print("\nOpinions used:")
-for o in answer.based_on.get("opinion", []):
- print(f" {o['text']} (confidence: {o['confidence_score']})")
-```
-
-## Confidence Thresholds
-
-Opinions below a confidence threshold may be:
-- Excluded from responses
-- Marked as uncertain
-- Revised more easily
-
-```python
-# Low confidence opinions are held loosely
-# "I think Python might be good for this" (0.45)
-
-# High confidence opinions are stated firmly
-# "Python is definitely the right choice" (0.92)
-```
-
-
----
-
-
-## File: developer/development.md
-
-# Development Guide
-
-Guide to setting up a local development environment for contributing to Hindsight.
-
-## Prerequisites
-
-- Python 3.11+
-- [uv](https://docs.astral.sh/uv/) - Fast Python package manager
-- Docker and Docker Compose
-- An LLM API key (OpenAI, Groq, or Ollama)
-
-## Local Development Setup
-
-### 1. Clone the Repository
-
-```bash
-git clone https://github.com/vectorize-io/hindsight.git
-cd hindsight
-```
-
-### 2. Install Dependencies
-
-```bash
-uv sync
-```
-
-### 3. Start PostgreSQL
-
-Start only the database via Docker:
-
-```bash
-cd docker && docker-compose up -d postgres
-```
-
-### 4. Configure Environment
-
-```bash
-cp .env.example .env
-```
-
-Edit `.env` with your LLM API key:
-
-```bash
-# Database (connects to Docker postgres)
-HINDSIGHT_API_DATABASE_URL=postgresql://hindsight:hindsight_dev@localhost:5432/hindsight
-
-# LLM Provider (choose one)
-HINDSIGHT_API_LLM_PROVIDER=groq
-HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
-HINDSIGHT_API_LLM_MODEL=llama-3.1-70b-versatile
-```
-
-### 5. Start the API Server
-
-```bash
-./scripts/start-server.sh --env local
-```
-
-The server will be available at http://localhost:8888.
-
-## Running Tests
-
-```bash
-# Run all tests
-uv run pytest
-
-# Run specific test file
-uv run pytest tests/test_retrieval.py
-
-# Run with verbose output
-uv run pytest -v
-```
-
-## Code Generation
-
-### Regenerate API Clients
-
-When you modify the OpenAPI spec, regenerate the clients:
-
-```bash
-./scripts/generate-clients.sh
-```
-
-This generates:
-- Python client in `hindsight-clients/python/`
-- TypeScript client in `hindsight-clients/typescript/`
-
-### Export OpenAPI Schema
-
-```bash
-./scripts/export-openapi.sh
-```
-
-## Project Structure
-
-```
-hindsight/
-├── hindsight-api/ # Main API server
-│ ├── hindsight_api/
-│ │ ├── api/ # HTTP endpoints
-│ │ ├── engine/ # Memory engine, retrieval, reasoning
-│ │ └── web/ # Server entry point
-│ └── tests/
-├── hindsight-clients/ # Generated SDK clients
-│ ├── python/
-│ └── typescript/
-├── hindsight-control-plane/ # Admin UI (Next.js)
-├── docker/ # Docker Compose setup
-└── scripts/ # Development scripts
-```
-
-## Contributing
-
-1. Create a feature branch from `main`
-2. Make your changes
-3. Run tests: `uv run pytest`
-4. Submit a pull request
-
-## Troubleshooting
-
-### Database Connection Issues
-
-Ensure PostgreSQL is running:
-
-```bash
-docker-compose ps
-```
-
-Check database connectivity:
-
-```bash
-psql postgresql://hindsight:hindsight_dev@localhost:5432/hindsight
-```
-
-### ML Model Download
-
-On first run, Hindsight downloads embedding and reranking models. This may take a few minutes. Models are cached in `~/.cache/huggingface/`.
-
-### Port Conflicts
-
-If port 8888 is in use:
-
-```bash
-HINDSIGHT_API_PORT=8889 ./scripts/start-server.sh --env local
-```
-
-
----
-
-
-## File: developer/mcp-server.md
-
-# MCP Server
-
-Hindsight includes a built-in [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that allows AI assistants to store and retrieve memories directly.
-
-## Access
-
-The MCP server is **enabled by default** and mounted at `/mcp` on the API server. Each memory bank has its own MCP endpoint:
-
-```
-http://localhost:8888/mcp/{bank_id}/
-```
-
-For example, to connect to the memory bank `alice`:
-```
-http://localhost:8888/mcp/alice/
-```
-
-To disable the MCP server, set the environment variable:
-
-```bash
-export HINDSIGHT_API_MCP_ENABLED=false
-```
-
-## Per-Bank Endpoints
-
-Unlike traditional MCP servers where tools require explicit identifiers, Hindsight uses **per-bank endpoints**. The `bank_id` is part of the URL path, so tools don't need to specify which bank to use—it's implicit from the connection.
-
-This design:
-- **Simplifies tool usage** — no need to pass `bank_id` with every call
-- **Enforces isolation** — each MCP connection is scoped to a single bank
-- **Enables multi-tenant setups** — connect different users to different endpoints
-
----
-
-## Available Tools
-
-### retain
-
-Store information to long-term memory.
-
-| Parameter | Type | Required | Description |
-|-----------|------|----------|-------------|
-| `content` | string | Yes | The fact or memory to store |
-| `context` | string | No | Category for the memory (default: `general`) |
-
-**Example:**
-```json
-{
- "name": "retain",
- "arguments": {
- "content": "User prefers Python over JavaScript for backend development",
- "context": "programming_preferences"
- }
-}
-```
-
-**When to use:**
-- User shares personal facts, preferences, or interests
-- Important events or milestones are mentioned
-- Decisions, opinions, or goals are stated
-- Work context or project details are discussed
-
----
-
-### recall
-
-Search memories to provide personalized responses.
-
-| Parameter | Type | Required | Description |
-|-----------|------|----------|-------------|
-| `query` | string | Yes | Natural language search query |
-| `max_results` | integer | No | Maximum results to return (default: 10) |
-
-**Example:**
-```json
-{
- "name": "recall",
- "arguments": {
- "query": "What are the user's programming language preferences?"
- }
-}
-```
-
-**Response:**
-```json
-{
- "results": [
- {
- "id": "fact_abc123",
- "text": "User prefers Python over JavaScript for backend development",
- "type": "world",
- "context": "programming_preferences",
- "event_date": null
- }
- ]
-}
-```
-
-**When to use:**
-- Start of conversation to recall relevant context
-- Before making recommendations
-- When user asks about something they may have mentioned before
-- To provide continuity across conversations
-
----
-
-## Integration with AI Assistants
-
-The MCP server can be used with any MCP-compatible AI assistant.
-
-### Claude Desktop Configuration
-
-To connect Claude Desktop to a specific memory bank:
-
-```json
-{
- "mcpServers": {
- "hindsight-alice": {
- "url": "http://localhost:8888/mcp/alice/"
- }
- }
-}
-```
-
-Each user can have their own MCP server configuration pointing to their personal memory bank.
-
-
----
-
-
-## File: developer/metrics.md
-
-# Metrics
-
-Hindsight exposes Prometheus metrics at `/metrics` for monitoring.
-
-```bash
-curl http://localhost:8888/metrics
-```
-
-## Available Metrics
-
-### Operation Metrics
-
-| Metric | Type | Labels | Description |
-|--------|------|--------|-------------|
-| `hindsight.operation.duration` | Histogram | operation, bank_id, budget, max_tokens, success | Duration of operations in seconds |
-| `hindsight.operation.total` | Counter | operation, bank_id, budget, max_tokens, success | Total number of operations executed |
-
-The `operation` label values are: `retain`, `recall`, `reflect`.
-
-### Token Metrics
-
-| Metric | Type | Labels | Description |
-|--------|------|--------|-------------|
-| `hindsight.tokens.input` | Counter | operation, bank_id, budget, max_tokens | Input tokens consumed |
-| `hindsight.tokens.output` | Counter | operation, bank_id, budget, max_tokens | Output tokens generated |
-
-## Prometheus Configuration
-
-```yaml
-scrape_configs:
- - job_name: 'hindsight'
- static_configs:
- - targets: ['localhost:8888']
-```
-
-
----
-
-
-## File: developer/performance.md
-
-# Performance
-
-Hindsight is designed for high-performance semantic memory operations at scale. This page covers performance characteristics, optimization strategies, and best practices.
-
-## Overview
-
-Hindsight's performance is optimized across three key operations:
-
-- **Retain (Ingestion)**: Batch processing with async operations for large-scale memory storage
-- **Recall (Search)**: Sub-second semantic search with configurable thinking budgets
-- **Reflect (Reasoning)**: Disposition-aware answer generation with controllable compute
-
-## Design Philosophy: Optimized for Fast Reads
-
-Hindsight is **architected from the ground up to prioritize read performance over write performance**. This design decision reflects the typical usage pattern of memory systems: memories are written once but read many times.
-
-The system makes deliberate trade-offs to ensure **sub-second recall operations**:
-
-- **Pre-computed embeddings**: All memory embeddings are generated and indexed during retention
-- **Optimized vector search**: HNSW indexes enable fast approximate nearest neighbor search
-- **Fact extraction at write time**: Complex LLM-based fact extraction happens during retention, not retrieval
-- **Structured memory graphs**: Relationships and temporal information are resolved upfront
-
-This means **Recall (search) operations are blazingly fast** because all the heavy lifting has already been done.
-
-### Performance Comparison
-
-| Operation | Typical Latency | Primary Bottleneck | Optimization Strategy |
-|-----------|----------------|-------------------|----------------------|
-| **Recall** | 100-600ms | Vector search, graph traversal | ✅ Already optimized |
-| **Reflect** | 800-3000ms | LLM generation + search | Reduce search budget, use faster LLM |
-| **Retain** | 500ms-2000ms per batch | **LLM fact extraction** | Use high-throughput LLM provider |
-
-Hindsight is designed to ensure your **application's read path (recall/reflect) is always fast**, even if it means spending more time upfront during writes. This is the right trade-off for memory systems where:
-
-- Memories are retained in background processes or during low-traffic periods
-- Memories are queried frequently in user-facing, latency-sensitive contexts
-- The ratio of reads to writes is high (typically 10:1 or higher)
-
----
-
-## Retain Performance
-
-**Retain (write) operations are inherently slower** because they involve LLM-based fact extraction, entity recognition, temporal reasoning, relationship mapping, and embedding generation. **The LLM is the primary bottleneck for write latency.**
-
-### Hindsight Doesn't Need a Smart Model
-
-The fact extraction process is structured and well-defined, so smaller, faster models work extremely well. Our recommended model is `gpt-oss-20b` (available via Groq and other providers).
-
-To maximize retention throughput:
-
-1. **Use high-throughput LLM providers**: Choose providers with high requests-per-minute (RPM) limits and low latency
- - ✅ **Fast**: [Groq](https://groq.com) with `gpt-oss-20b` or other openai-oss models, self-hosted models on GPU clusters (vLLM, TGI)
- - ⚠️ **Slower**: Standard cloud LLM providers with rate limits
-
-2. **Batch your operations**: Group related content into batch requests. The only limit is the HTTP payload size — Hindsight automatically splits large batches into smaller, optimized chunks under the hood, so you don't have to worry about it.
-
-3. **Use async mode for large datasets**: Queue operations in the background
-
-4. **Parallel processing**: For very large datasets, use multiple concurrent retention requests with different `document_id` values
-
-### Throughput
-
-Typical ingestion performance:
-
-| Mode | Items/second | Use Case |
-|------|--------------|----------|
-| Synchronous | ~50-100 | Real-time updates, small batches |
-| Async (batched) | ~500-1000 | Bulk imports, background processing |
-| Parallel async | ~2000-5000 | Large-scale data migration |
-
-**Factors affecting throughput:**
-- Document size and complexity
-- LLM provider rate limits (for fact extraction)
-- Database write performance
-- Available CPU/memory resources
-
----
-
-## Recall Performance
-
-### Budget
-
-The `budget` parameter controls the search depth and quality. Choose based on query complexity — comprehensive questions that need thorough analysis benefit from higher budgets:
-
-| Budget | Latency | Memory Activation | Use Case |
-|--------|---------|-------------------|----------|
-| `low` | 100-300ms | ~10-50 facts | Quick lookups, real-time chat |
-| `mid` | 300-600ms | ~50-200 facts | Standard queries, balanced performance |
-| `high` | 500-1500ms | ~200-500 facts | Comprehensive questions, thorough analysis |
-
-### Search Optimization
-
-1. **Appropriate budgets**: Use lower budgets for simple queries, higher for comprehensive reasoning
-2. **Limit result tokens**: Set `max_tokens` to control response size (default: 4096)
-3. **Include entities/chunks**: Use `include_entities` and `include_chunks` to retrieve additional context when needed — each has its own token budget
-
-### Database Performance
-
-Hindsight uses PostgreSQL with pgvector for efficient vector search:
-
-- **Index type**: HNSW for approximate nearest neighbor search
-- **Typical query time**: 10-50ms for vector search on 100K+ facts
-- **Scalability**: Tested with millions of facts per bank
-
-## Reflect Performance
-
-### Performance Characteristics
-
-| Component | Latency | Description |
-|-----------|---------|-------------|
-| Memory search | 300-1000ms | Based on budget (low/mid/high) |
-| LLM generation | 500-2000ms | Depends on provider and response length |
-| **Total** | **800-3000ms** | Typical end-to-end latency |
-
-### Optimization Strategies
-
-1. **Budget selection**: Use lower budgets when context is sufficient
-2. **Context provision**: Provide relevant `context` to reduce search requirements
-3. **Streaming responses**: Use streaming APIs (when available) for faster time-to-first-token
-4. **Caching**: Cache frequent queries at the application level
-
-## Best Practices
-
-### Operations
-- **Use appropriate budgets**: Don't over-provision for simple queries; use higher budgets for comprehensive reasoning
-- **Batch retain operations**: Group related content together for better efficiency
-- **Cache frequent queries**: Cache at the application level for repeated queries
-- **Profile with trace**: Use the `trace` parameter to identify slow operations
-
-### Scaling
-- **Horizontal scaling**: Deploy multiple API instances behind a load balancer with shared PostgreSQL
-- **Concurrency**: 100+ simultaneous requests supported; memory search scales with CPU cores
-- **LLM rate limits**: Distribute load across multiple API keys/providers (typically 60-500 RPM per key)
-
-### Cost Optimization
-- **Use efficient models**: `gpt-oss-20b` via Groq for retain — Hindsight doesn't need frontier models
-- **Control token budgets**: Limit `max_tokens` for recall, use lower budgets when possible
-- **Optimize chunks**: Larger chunks (1000-2000 tokens) are more efficient than many small ones
-
-### Monitoring
-- **Prometheus metrics**: Available at `/metrics` — track latency percentiles, throughput, and error rates
-- **Key metrics**: `hindsight_recall_duration_seconds`, `hindsight_reflect_duration_seconds`, `hindsight_retain_items_total`
-
-
----
-
-
-## File: developer/storage.md
-
-# Storage
-
-Hindsight uses PostgreSQL as its sole storage backend.
-
-## Why PostgreSQL?
-
-PostgreSQL provides all capabilities required for a semantic memory system in a single database:
-
-| Capability | Implementation |
-|------------|----------------|
-| Vector search | pgvector extension with HNSW indexes |
-| Full-text search | Built-in tsvector with GIN indexes |
-| Relational data | Native PostgreSQL |
-| JSON documents | JSONB with indexing |
-| Graph queries | Recursive CTEs |
-
-### Reduced System Dependencies
-
-Building exclusively for PostgreSQL simplifies deployment and operations:
-
-- Single connection string to configure
-- Single backup and restore strategy
-- Single monitoring target
-- ACID transactions across all data types
-- Single upgrade path
-
-### No Storage Abstraction
-
-Hindsight does not abstract storage behind a generic interface. This is a deliberate trade-off.
-
-We believe PostgreSQL is becoming the standard database API. Its popularity, extension ecosystem, and modularity mean that PostgreSQL-compatible interfaces are appearing everywhere—from serverless offerings to distributed databases. Building for PostgreSQL today means compatibility with a growing ecosystem tomorrow.
-
-Supporting multiple databases would increase flexibility but conflict with our core goals: Hindsight is fully open source and designed to be as simple as possible to run and use. Adding database abstractions introduces complexity in code, testing, documentation, and operations—complexity that we pass on to users.
-
-By committing to PostgreSQL, we keep the system simple:
-- One set of deployment instructions
-- One set of performance characteristics to understand
-- One codebase optimized for one backend
-- No configuration decisions about which database to use
-
-## Development with pg0
-
-For local development, Hindsight uses **[pg0](https://github.com/vectorize-io/pg0)**—an embedded PostgreSQL distribution.
-
-### What is pg0?
-
-pg0 is a single binary containing:
-- PostgreSQL server
-- pgvector extension (pre-installed)
-- Automatic initialization
-
-### Behavior
-
-When no `DATABASE_URL` is configured, Hindsight:
-1. Downloads the pg0 binary for the current platform (macOS ARM, Linux x86_64/ARM64, Windows)
-2. Starts an embedded PostgreSQL instance on port 5555
-3. Initializes the schema
-4. Stores data in `~/.hindsight/pg0/`
-
-### Environments
-
-| Environment | Database | Configuration |
-|-------------|----------|---------------|
-| Development | pg0 (embedded) | Automatic |
-| Production | PostgreSQL 15+ | `DATABASE_URL` environment variable |
-
-## Requirements
-
-- PostgreSQL 15 or later
-- pgvector 0.5.0 or later
-
-Any PostgreSQL instance that satisfies these requirements should work. If you encounter issues with a specific setup, [open a GitHub issue](https://github.com/hindsight-ai/hindsight/issues).
-
-### Tested Managed Services
-
-- AWS RDS (PostgreSQL 15+)
-- Google Cloud SQL
-- Azure Database for PostgreSQL
-- Supabase
-- Neon
-
-
----
-
-
-## File: sdks/integrations/litellm.md
-
-# LiteLLM
-
-Universal LLM memory integration via [LiteLLM](https://github.com/BerriAI/litellm). Add persistent memory to any LLM application with just a few lines of code.
-
-## Features
-
-- **Universal LLM Support** - Works with 100+ LLM providers via LiteLLM (OpenAI, Anthropic, Groq, Azure, AWS Bedrock, Google Vertex AI, and more)
-- **Simple Integration** - Just configure, enable, and use `hindsight_litellm.completion()`
-- **Automatic Memory Injection** - Relevant memories are injected into prompts before LLM calls
-- **Automatic Conversation Storage** - Conversations are stored to Hindsight for future recall
-- **Two Memory Modes** - Choose between `reflect` (synthesized context) or `recall` (raw memory retrieval)
-- **Direct Memory APIs** - Query, synthesize, and store memories manually
-- **Native Client Wrappers** - Alternative wrappers for OpenAI and Anthropic SDKs
-
-## Installation
-
-```bash
-pip install hindsight-litellm
-```
-
-## Quick Start
-
-```python
-
-
-# Configure and enable memory integration
-hindsight_litellm.configure(
- hindsight_api_url="http://localhost:8888",
- bank_id="my-agent",
-)
-hindsight_litellm.enable()
-
-# Use the convenience wrapper - memory is automatically injected and stored
-response = hindsight_litellm.completion(
- model="gpt-4o-mini",
- messages=[{"role": "user", "content": "What did we discuss about AI?"}]
-)
-```
-
-## How It Works
-
-When you call `completion()`, the following happens automatically:
-
-1. **Memory Retrieval** - Hindsight is queried for relevant memories based on the conversation
-2. **Prompt Injection** - Memories are injected into the system message
-3. **LLM Call** - The enriched prompt is sent to the LLM
-4. **Conversation Storage** - The conversation is stored to Hindsight for future recall
-5. **Response Returned** - You receive the response as normal
-
-## Configuration Options
-
-```python
-hindsight_litellm.configure(
- # Required
- hindsight_api_url="http://localhost:8888", # Hindsight API server URL
- bank_id="my-agent", # Memory bank ID
-
- api_key="your-api-key", # Optional API key for authentication
-
- # Optional - Memory behavior
- store_conversations=True, # Store conversations after LLM calls
- inject_memories=True, # Inject relevant memories into prompts
- use_reflect=False, # Use reflect API (synthesized) vs recall (raw memories)
- reflect_include_facts=False, # Include source facts with reflect responses
- max_memories=None, # Maximum memories to inject (None = unlimited)
- max_memory_tokens=4096, # Maximum tokens for memory context
- recall_budget="mid", # Recall budget: "low", "mid", "high"
- fact_types=["world", "agent"], # Filter fact types to inject
-
- # Optional - Bank Configuration
- bank_name="My Agent", # Human-readable display name for the memory bank
- background="This agent...", # Instructions guiding what Hindsight should remember
-
- # Optional - Advanced
- injection_mode="system_message", # or "prepend_user"
- excluded_models=["gpt-3.5*"], # Exclude certain models
- verbose=True, # Enable verbose logging and debug info
-)
-```
-
-### Bank Configuration
-
-The `background` and `bank_name` parameters configure the memory bank itself. When provided, `configure()` will automatically create or update the bank with these settings.
-
-```python
-hindsight_litellm.configure(
- hindsight_api_url="http://localhost:8888",
- bank_id="support-router",
- bank_name="Customer Support Router",
- background="""This agent routes customer support requests to the appropriate team.
- Remember which types of issues should go to which teams (billing, technical, sales).
- Track customer preferences for communication channels and past issue resolutions.""",
-)
-```
-
-### Memory Modes: Reflect vs Recall
-
-- **Recall mode** (`use_reflect=False`, default): Retrieves raw memory facts and injects them as a numbered list. Best when you need precise, individual memories.
-- **Reflect mode** (`use_reflect=True`): Synthesizes memories into a coherent context paragraph. Best for natural, conversational memory context.
-
-```python
-# Recall mode - raw memories
-hindsight_litellm.configure(
- bank_id="my-agent",
- use_reflect=False, # Default
-)
-# Injects: "1. [WORLD] User prefers Python\n2. [OPINION] User dislikes Java..."
-
-# Reflect mode - synthesized context
-hindsight_litellm.configure(
- bank_id="my-agent",
- use_reflect=True,
-)
-# Injects: "Based on previous conversations, the user is a Python developer who..."
-```
-
-## Multi-Provider Support
-
-Works with any LiteLLM-supported provider:
-
-```python
-
-
-hindsight_litellm.configure(
- hindsight_api_url="http://localhost:8888",
- bank_id="my-agent",
-)
-hindsight_litellm.enable()
-
-# OpenAI
-hindsight_litellm.completion(model="gpt-4o", messages=[...])
-
-# Anthropic
-hindsight_litellm.completion(model="claude-3-5-sonnet-20241022", messages=[...])
-
-# Groq
-hindsight_litellm.completion(model="groq/llama-3.1-70b-versatile", messages=[...])
-
-# Azure OpenAI
-hindsight_litellm.completion(model="azure/gpt-4", messages=[...])
-
-# AWS Bedrock
-hindsight_litellm.completion(model="bedrock/anthropic.claude-3", messages=[...])
-
-# Google Vertex AI
-hindsight_litellm.completion(model="vertex_ai/gemini-pro", messages=[...])
-```
-
-## Direct Memory APIs
-
-### Recall - Query raw memories
-
-```python
-from hindsight_litellm import configure, recall
-
-configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
-
-memories = recall("what projects am I working on?", budget="mid")
-for m in memories:
- print(f"- [{m.fact_type}] {m.text}")
-```
-
-### Reflect - Get synthesized context
-
-```python
-from hindsight_litellm import configure, reflect
-
-configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
-
-result = reflect("what do you know about the user's preferences?")
-print(result.text)
-```
-
-### Retain - Store memories
-
-```python
-from hindsight_litellm import configure, retain
-
-configure(bank_id="my-agent", hindsight_api_url="http://localhost:8888")
-
-result = retain(
- content="User mentioned they're working on a machine learning project",
- context="Discussion about current projects",
-)
-```
-
-### Async APIs
-
-```python
-from hindsight_litellm import arecall, areflect, aretain
-
-# Async versions of all memory APIs
-memories = await arecall("what do you know about me?")
-context = await areflect("summarize user preferences")
-result = await aretain(content="New information to remember")
-```
-
-## Native Client Wrappers
-
-Alternative to LiteLLM callbacks for direct SDK integration.
-
-### OpenAI Wrapper
-
-```python
-from openai import OpenAI
-from hindsight_litellm import wrap_openai
-
-client = OpenAI()
-wrapped = wrap_openai(
- client,
- bank_id="my-agent",
- hindsight_api_url="http://localhost:8888",
-)
-
-response = wrapped.chat.completions.create(
- model="gpt-4",
- messages=[{"role": "user", "content": "What do you know about me?"}]
-)
-```
-
-### Anthropic Wrapper
-
-```python
-from anthropic import Anthropic
-from hindsight_litellm import wrap_anthropic
-
-client = Anthropic()
-wrapped = wrap_anthropic(
- client,
- bank_id="my-agent",
- hindsight_api_url="http://localhost:8888",
-)
-
-response = wrapped.messages.create(
- model="claude-3-5-sonnet-20241022",
- max_tokens=1024,
- messages=[{"role": "user", "content": "Hello!"}]
-)
-```
-
-## Debug Mode
-
-When `verbose=True`, you can inspect exactly what memories are being injected:
-
-```python
-from hindsight_litellm import configure, enable, completion, get_last_injection_debug
-
-configure(
- bank_id="my-agent",
- hindsight_api_url="http://localhost:8888",
- verbose=True,
-)
-enable()
-
-response = completion(
- model="gpt-4o-mini",
- messages=[{"role": "user", "content": "What's my favorite color?"}]
-)
-
-# Inspect what was injected
-debug = get_last_injection_debug()
-if debug:
- print(f"Mode: {debug.mode}") # "reflect" or "recall"
- print(f"Injected: {debug.injected}") # True/False
- print(f"Results: {debug.results_count}")
- print(f"Memory context:\n{debug.memory_context}")
-```
-
-## Context Manager
-
-```python
-from hindsight_litellm import hindsight_memory
-
-
-with hindsight_memory(bank_id="user-123"):
- response = litellm.completion(model="gpt-4", messages=[...])
-# Memory integration automatically disabled after context
-```
-
-## Disabling and Cleanup
-
-```python
-from hindsight_litellm import disable, cleanup
-
-# Temporarily disable memory integration
-disable()
-
-# Clean up all resources (call when shutting down)
-cleanup()
-```
-
-## API Reference
-
-### Main Functions
-
-| Function | Description |
-|----------|-------------|
-| `configure(...)` | Configure global Hindsight settings |
-| `enable()` | Enable memory integration with LiteLLM |
-| `disable()` | Disable memory integration |
-| `is_enabled()` | Check if memory integration is enabled |
-| `cleanup()` | Clean up all resources |
-
-### Configuration Functions
-
-| Function | Description |
-|----------|-------------|
-| `get_config()` | Get current configuration |
-| `is_configured()` | Check if Hindsight is configured |
-| `reset_config()` | Reset configuration to defaults |
-
-### Memory Functions
-
-| Function | Description |
-|----------|-------------|
-| `recall(query, ...)` | Synchronously query raw memories |
-| `arecall(query, ...)` | Asynchronously query raw memories |
-| `reflect(query, ...)` | Synchronously get synthesized memory context |
-| `areflect(query, ...)` | Asynchronously get synthesized memory context |
-| `retain(content, ...)` | Synchronously store a memory |
-| `aretain(content, ...)` | Asynchronously store a memory |
-
-### Debug Functions
-
-| Function | Description |
-|----------|-------------|
-| `get_last_injection_debug()` | Get debug info from last memory injection |
-| `clear_injection_debug()` | Clear stored debug info |
-
-### Client Wrappers
-
-| Function | Description |
-|----------|-------------|
-| `wrap_openai(client, ...)` | Wrap OpenAI client with memory |
-| `wrap_anthropic(client, ...)` | Wrap Anthropic client with memory |
-
-## Requirements
-
-- Python >= 3.10
-- litellm >= 1.40.0
-- A running Hindsight API server
-
-
----