doc: release notes for 0.4.0 (#217)

* doc: release notes for 0.4.0

* doc: release notes for 0.4.0

* doc: release notes for 0.4.0

* doc: release notes for 0.4.0
This commit is contained in:
Nicolò Boschi 2026-01-28 16:54:05 +01:00 committed by GitHub
parent 1bf90358c3
commit 20f2b92069
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 8189 additions and 235 deletions

3
.gitignore vendored
View file

@ -50,4 +50,5 @@ hindsight-clients/rust/target
.claude
whats-next.md
TASK.md
CHANGELOG.md
# Changelog is now tracked in hindsight-docs/src/pages/changelog.md
# CHANGELOG.md

View file

@ -25,7 +25,7 @@ GITHUB_REPO = "vectorize-io/hindsight"
GITHUB_RELEASES_URL = f"https://github.com/{GITHUB_REPO}/releases"
GITHUB_COMMIT_URL = f"https://github.com/{GITHUB_REPO}/commit"
REPO_PATH = Path(__file__).parent.parent.parent
CHANGELOG_PATH = REPO_PATH / "hindsight-docs" / "docs" / "changelog" / "index.md"
CHANGELOG_PATH = REPO_PATH / "hindsight-docs" / "src" / "pages" / "changelog.md"
class ChangelogEntry(BaseModel):
@ -238,7 +238,7 @@ def read_existing_changelog() -> tuple[str, str]:
"""Read existing changelog and split into header and content."""
if not CHANGELOG_PATH.exists():
header = """---
sidebar_position: 1
hide_table_of_contents: true
---
# Changelog

View file

@ -3,7 +3,7 @@ slug: learning-capabilities
title: "Agent memory that learns: observations and mental models"
authors: [hindsight]
image: /img/reflect-operation.webp
hide_table_of_contents: false
hide_table_of_contents: true
---
Today we're releasing Hindsight 0.4.0, which introduces two powerful learning capabilities for AI agents: **Observations** for automatic knowledge consolidation, and **Mental Models** for user-curated summaries.

View file

@ -220,8 +220,7 @@ const config: Config = {
className: 'navbar-item-blog',
},
{
type: 'doc',
docId: 'changelog/index',
to: '/changelog',
position: 'left',
label: 'Changelog',
className: 'navbar-item-changelog',

View file

@ -246,13 +246,6 @@ const sidebars: SidebarsConfig = {
],
},
],
changelogSidebar: [
{
type: 'doc',
id: 'changelog/index',
label: 'Changelog',
},
],
};
export default sidebars;

View file

@ -511,6 +511,17 @@ div[class*="codeBlockContent"] .prism-code {
max-width: 100%;
}
/* Force blog posts to be wider - aggressive override */
body[class*="blog"] .container,
body[class*="blog"] main .container {
max-width: 100% !important;
}
body[class*="blog"] article {
max-width: 1200px !important;
margin: 0 auto !important;
}
/* Page title with gradient */
article h1,
.markdown h1,
@ -1249,25 +1260,17 @@ ul[class*="suggestion"] {
/* ===== Blog Styling ===== */
/* Hide TOC sidebar on blog post pages */
.blog-post-page .col--3,
.blog-post-page [class*="tableOfContents"],
.blog-post-page aside[class*="toc"] {
display: none !important;
}
/* Make blog post content full width when TOC is hidden */
.blog-post-page .col--9 {
--ifm-col-width: 100%;
max-width: 100%;
flex-basis: 100%;
}
/* Hide author avatar/icon on blog posts */
[class*="blogPostAuthor"] img,
[class*="authorImage"],
.avatar__photo {
display: none !important;
/* Blog author text visible in light mode */
[class*="blogPostAuthor"],
[class*="blogPostAuthor"] *,
.avatar__name,
.avatar__name a,
.avatar__subtitle,
[class*="authorName"],
[class*="blogPostData"] a,
[class*="blogPostInfo"] a {
color: #1e293b !important;
-webkit-text-fill-color: #1e293b !important;
}
/* Blog author text visible in dark mode */

View file

@ -1,5 +1,5 @@
---
sidebar_position: 1
hide_table_of_contents: true
---
# Changelog
@ -8,7 +8,28 @@ This changelog highlights user-facing changes only. Internal maintenance, CI/CD,
For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
## [0.3.0](https://github.com/vectorize-io/hindsight/releases/tag/v0.3.0)
## [0.4.0](https://github.com/vectorize-io/hindsight/releases/tag/v0.4.0)
**Observations**, **Mental Models**, new **Agentic Reflect** and Directives, read the [announcement](/blog/learning-capabilities).
**Features**
- Added support for providing a custom prompt for memory extraction. ([`3172e99`](https://github.com/vectorize-io/hindsight/commit/3172e99))
- Expanded the LiteLLM integration with async retain/reflect support, cleaner API, and support for tags/mission (including passing API keys correctly). ([`1d4879a`](https://github.com/vectorize-io/hindsight/commit/1d4879a))
- Added a new worker service to run background tasks at scale. ([`4c79240`](https://github.com/vectorize-io/hindsight/commit/4c79240))
- MCP retain now supports timestamps. ([`b378f68`](https://github.com/vectorize-io/hindsight/commit/b378f68))
- Added support for installing skills via `npx add-skill`. ([`ec22317`](https://github.com/vectorize-io/hindsight/commit/ec22317))
**Improvements**
- CLI retain-files now accepts more file types. ([`1eeced3`](https://github.com/vectorize-io/hindsight/commit/1eeced3))
**Bug Fixes**
- Fixed a macOS crash in the embed daemon caused by an XPC connection issue. ([`e5fc6ee`](https://github.com/vectorize-io/hindsight/commit/e5fc6ee))
- Fixed occasional extraction in the wrong language. ([`87d4a36`](https://github.com/vectorize-io/hindsight/commit/87d4a36))
- Fixed PyTorch model initialization issues that could cause startup failures (meta tensor/init problems). ([`ddaa5f5`](https://github.com/vectorize-io/hindsight/commit/ddaa5f5))
**Features**

View file

@ -1,192 +0,0 @@
---
sidebar_position: 1
---
# Changelog
This changelog highlights user-facing changes only. Internal maintenance, CI/CD, and infrastructure updates are omitted.
For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
## [0.3.0](https://github.com/vectorize-io/hindsight/releases/tag/v0.3.0)
**Features**
- Add memory tags so you can label and filter memories during recall/reflect. ([`20c8f8b`](https://github.com/vectorize-io/hindsight/commit/20c8f8b))
- Allow choosing different AI providers/models per operation. ([`e6709d5`](https://github.com/vectorize-io/hindsight/commit/e6709d5))
- Add Cohere support for embeddings and reranking. ([`4de0730`](https://github.com/vectorize-io/hindsight/commit/4de0730))
- Add configurable embedding dimensions and OpenAI embeddings support. ([`70de23e`](https://github.com/vectorize-io/hindsight/commit/70de23e))
- Support custom base URLs for OpenAI-style embeddings and Cohere endpoints. ([`fa53917`](https://github.com/vectorize-io/hindsight/commit/fa53917))
- Add LiteLLM gateway support for routing LLM/embedding requests. ([`d47c8a2`](https://github.com/vectorize-io/hindsight/commit/d47c8a2))
- Add multilingual content support to improve handling and retrieval across languages. ([`c65c6a9`](https://github.com/vectorize-io/hindsight/commit/c65c6a9))
- Add delete memory bank capability. ([`4b82d2d`](https://github.com/vectorize-io/hindsight/commit/4b82d2d))
- Add backup/restore tooling for memory banks. ([`67b273d`](https://github.com/vectorize-io/hindsight/commit/67b273d))
**Improvements**
- Add retention modes to control how memories are extracted and stored. ([`fb31a35`](https://github.com/vectorize-io/hindsight/commit/fb31a35))
- Add offline (optional) database migrations to support restricted/air-gapped deployments. ([`233bd2e`](https://github.com/vectorize-io/hindsight/commit/233bd2e))
- Add database connection configuration options for more flexible deployments. ([`33fac2c`](https://github.com/vectorize-io/hindsight/commit/33fac2c))
- Load .env automatically on startup to simplify configuration. ([`c06d9b4`](https://github.com/vectorize-io/hindsight/commit/c06d9b4))
- Expose an operation ID from retain requests so async/background processing can be tracked. ([`1dacd0e`](https://github.com/vectorize-io/hindsight/commit/1dacd0e))
- Add per-request LLM token usage metrics for monitoring and cost tracking. ([`29a542d`](https://github.com/vectorize-io/hindsight/commit/29a542d))
- Add LLM call latency metrics for performance monitoring. ([`5e1f13e`](https://github.com/vectorize-io/hindsight/commit/5e1f13e))
- Include tenant in metrics labels for better multi-tenant observability. ([`1ffc2a4`](https://github.com/vectorize-io/hindsight/commit/1ffc2a4))
- Add async processing option to MCP retain tool for background retention workflows. ([`37fc7fb`](https://github.com/vectorize-io/hindsight/commit/37fc7fb))
**Bug Fixes**
- Fix extension loading in multi-worker deployments so all workers load extensions correctly. ([`f5f3fca`](https://github.com/vectorize-io/hindsight/commit/f5f3fca))
- Improve recall performance by batching recall queries. ([`5991308`](https://github.com/vectorize-io/hindsight/commit/5991308))
- Improve retrieval quality and stability for large memory banks (graph/MPFP retrieval fixes). ([`6232e69`](https://github.com/vectorize-io/hindsight/commit/6232e69))
- Fix entities list being limited to 100 entities. ([`26bf571`](https://github.com/vectorize-io/hindsight/commit/26bf571))
- Fix UI only showing the first 1000 memories. ([`67c1a42`](https://github.com/vectorize-io/hindsight/commit/67c1a42))
- Fix duplicated causal relationships and improve token usage during processing. ([`49e233c`](https://github.com/vectorize-io/hindsight/commit/49e233c))
- Improve causal link detection accuracy. ([`2a00df0`](https://github.com/vectorize-io/hindsight/commit/2a00df0))
- Make retain max completion tokens configurable to prevent truncation issues. ([`7715a51`](https://github.com/vectorize-io/hindsight/commit/7715a51))
- Fix Python SDK not sending the Authorization header, preventing authenticated requests. ([`39e3f7c`](https://github.com/vectorize-io/hindsight/commit/39e3f7c))
- Fix stats endpoint missing tenant authentication in multi-tenant setups. ([`d6ff191`](https://github.com/vectorize-io/hindsight/commit/d6ff191))
- Fix embedding dimension handling for tenant schemas in multi-tenant databases. ([`6fe9314`](https://github.com/vectorize-io/hindsight/commit/6fe9314))
- Fix Groq free-tier compatibility so requests work correctly. ([`d899d18`](https://github.com/vectorize-io/hindsight/commit/d899d18))
- Fix security vulnerability (qs / CVE-2025-15284). ([`b3becb6`](https://github.com/vectorize-io/hindsight/commit/b3becb6))
- Restore MCP tools for listing and creating memory banks. ([`9fd5679`](https://github.com/vectorize-io/hindsight/commit/9fd5679))
## [0.2.0](https://github.com/vectorize-io/hindsight/releases/tag/v0.2.0)
**Features**
- Add additional model provider support, including Anthropic Claude and LM Studio. ([`787ed60`](https://github.com/vectorize-io/hindsight/commit/787ed60))
- Add multi-bank access and new MCP tools for interacting with multiple memory banks via MCP. ([`6b5f593`](https://github.com/vectorize-io/hindsight/commit/6b5f593))
- Allow supplying custom entities when retaining memories via the retain endpoint. ([`dd59bc8`](https://github.com/vectorize-io/hindsight/commit/dd59bc8))
- Enhance the /reflect endpoint with max_tokens control and optional structured output responses. ([`d49e820`](https://github.com/vectorize-io/hindsight/commit/d49e820))
**Improvements**
- Improve local LLM support for reasoning-capable models and streamline Docker startup for local deployments. ([`eea0f27`](https://github.com/vectorize-io/hindsight/commit/eea0f27))
- Support operation validator extensions and return proper HTTP errors when validation fails. ([`ce45d30`](https://github.com/vectorize-io/hindsight/commit/ce45d30))
- Add configurable observation thresholds to control when observations are created/updated. ([`54e2df0`](https://github.com/vectorize-io/hindsight/commit/54e2df0))
- Improve graph visualization to the control plane for exploring memory relationships. ([`1a62069`](https://github.com/vectorize-io/hindsight/commit/1a62069))
**Bug Fixes**
- Fix MCP server lifecycle handling so MCP lifespan is correctly tied to the FastAPI app lifespan. ([`6b78f7d`](https://github.com/vectorize-io/hindsight/commit/6b78f7d))
## [0.1.15](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.15)
**Features**
- Add the ability to delete documents from the web UI. ([`f7ff32d`](https://github.com/vectorize-io/hindsight/commit/f7ff32d))
**Improvements**
- Improve the API health check endpoint and update the generated client APIs/types accordingly. ([`e06a612`](https://github.com/vectorize-io/hindsight/commit/e06a612))
## [0.1.14](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.14)
**Bug Fixes**
- Fixes the embedded “get-skill” installer so installing skills works correctly. ([`0b352d1`](https://github.com/vectorize-io/hindsight/commit/0b352d1))
## [0.1.13](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.13)
**Improvements**
- Improve reliability by surfacing task handler failures so retries can occur when processing fails. ([`904ea4d`](https://github.com/vectorize-io/hindsight/commit/904ea4d))
- Revamp the hindsight-embed component architecture, including a new daemon/client model and CLI updates for embedding workflows. ([`e6511e7`](https://github.com/vectorize-io/hindsight/commit/e6511e7))
**Bug Fixes**
- Fix memory retention so timestamps are correctly taken into account. ([`234d426`](https://github.com/vectorize-io/hindsight/commit/234d426))
## [0.1.12](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.12)
**Features**
- Added an extensions system for plugging in new operations/skills (including built-in tenant support). ([`2a0c490`](https://github.com/vectorize-io/hindsight/commit/2a0c490))
- Introduced the hindsight-embed tool and a native agentic skill for embedding/agent workflows. ([`da44a5e`](https://github.com/vectorize-io/hindsight/commit/da44a5e))
**Improvements**
- Improved reliability when parsing LLM JSON by retrying on parse errors and adding clearer diagnostics. ([`a831a7b`](https://github.com/vectorize-io/hindsight/commit/a831a7b))
**Bug Fixes**
- Fixed structured-output support for Ollama-based LLM providers. ([`32bca12`](https://github.com/vectorize-io/hindsight/commit/32bca12))
- Adjusted LLM validation to cap max completion tokens at 100 to prevent validation failures. ([`b94b5cf`](https://github.com/vectorize-io/hindsight/commit/b94b5cf))
## [0.1.11](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.11)
**Bug Fixes**
- Fixed the standalone Docker image and control plane standalone build process so standalone deployments build correctly. ([`2948cb6`](https://github.com/vectorize-io/hindsight/commit/2948cb6))
## [0.1.10](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.10)
*This release contains internal maintenance and infrastructure changes only.*
## [0.1.9](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.9)
**Features**
- Simplified local MCP installation and added a standalone UI option for easier setup. ([`1c6acc3`](https://github.com/vectorize-io/hindsight/commit/1c6acc3))
**Bug Fixes**
- Fixed the standalone Docker image so it builds and starts reliably. ([`b52eb90`](https://github.com/vectorize-io/hindsight/commit/b52eb90))
- Improved Docker runtime reliability by adding required system utilities (procps). ([`ae80876`](https://github.com/vectorize-io/hindsight/commit/ae80876))
## [0.1.8](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.8)
**Bug Fixes**
- Fix bank list responses when a bank has no name. ([`04f01ab`](https://github.com/vectorize-io/hindsight/commit/04f01ab))
- Fix failures when retaining memories asynchronously. ([`63f5138`](https://github.com/vectorize-io/hindsight/commit/63f5138))
- Fix a race condition in the bank selector when switching banks. ([`e468a4e`](https://github.com/vectorize-io/hindsight/commit/e468a4e))
## [0.1.7](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.7)
*This release contains internal maintenance and infrastructure changes only.*
## [0.1.6](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.6)
**Features**
- Added support for the Gemini 3 Pro and GPT-5.2 models. ([`bb1f9cb`](https://github.com/vectorize-io/hindsight/commit/bb1f9cb))
- Added a local MCP server option for running/connecting to Hindsight via MCP without a separate remote service. ([`7dd6853`](https://github.com/vectorize-io/hindsight/commit/7dd6853))
**Improvements**
- Updated the Postgres/pg0 dependency to a newer 0.11.x series for improved compatibility and stability. ([`47be07f`](https://github.com/vectorize-io/hindsight/commit/47be07f))
## [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))

View file

@ -114,7 +114,6 @@ These traits only affect the `reflect` operation, not `recall`.
- [**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

View file

@ -0,0 +1,315 @@
---
sidebar_position: 1
---
# OpenAI Agent + Hindsight Memory Integration
:::info Complete Application
This is a complete, runnable application demonstrating Hindsight integration.
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/openai-fitness-coach)
:::
A fitness coach example demonstrating how to use **OpenAI Agents** with **Hindsight as a memory backend**.
## What This Demonstrates
This example showcases:
- **OpenAI Assistants** handling conversation logic
- **Hindsight** providing sophisticated memory storage & retrieval
- **Function calling** to bridge them together
- **Streaming responses** for real-time interaction (enabled by default)
- **Bidirectional memory** - both user data AND coach observations stored
- **System-level post-processing** - automatic knowledge consolidation
- **Temporal-semantic memory** queries via function tools
- **Enhanced preference learning** - coach learns and respects user likes/dislikes
- **Real-world integration pattern** for adding memory to AI agents
## Architecture
```
User: "I ran 5K today, don't like tempo runs"
|
OpenAI Assistant
|
Function Call: store_memory(workout + preference)
|
Hindsight API (stores as world/agent)
|
OpenAI Assistant: "What should I focus on?"
|
Function Call: retrieve_memories("workouts and preferences")
|
Hindsight API (returns workouts + preferences)
|
OpenAI Assistant (analyzes, gives advice)
|
Function Call: store_memory(advice as experience)
|
Hindsight API (stores coach's advice, consolidates into observations)
|
Personalized Answer
```
## Key Difference from Standard Demo
| Component | Standard Demo | OpenAI Integration |
|-----------|---------------|-------------------|
| **Conversation** | Hindsight `/reflect` endpoint | OpenAI Assistant API |
| **Memory** | Hindsight (built-in) | Hindsight (via function calling) |
| **LLM** | Configured in Hindsight | OpenAI GPT-4 |
| **Knowledge Consolidation** | Automatic after retain | Automatic after retain |
| **Best For** | Hindsight-native apps | Integrating memory into existing OpenAI agents |
## Quick Start
### Prerequisites
1. **OpenAI API Key**
```bash
export OPENAI_API_KEY=your_openai_api_key
```
2. **Hindsight API running**
```bash
# Follow Hindsight setup instructions to start the API
# Default: http://localhost:8888
```
3. **Install dependencies**
```bash
pip install openai requests
```
### Run the Conversational Demo
```bash
cd openai-fitness-coach
export OPENAI_API_KEY=your_key_here
python demo_conversational.py
```
The demo showcases:
1. **Natural language workout logging** - Tell the coach what you did conversationally
2. **Preference learning** - Express likes/dislikes and watch the coach adapt
3. **Goal tracking** - Set goals, track progress, achieve milestones
4. **Bidirectional memory** - Both your activities AND coach's advice are stored
5. **Streaming responses** - See responses appear in real-time
6. **7 interactive phases** - From goal setting to achievement recognition
The demo uses a separate agent (`fitness-coach-demo`) to avoid mixing with real data.
## Usage
### Chat with Your Coach
**Interactive mode:**
```bash
python openai_coach.py
```
**Single question:**
```bash
python openai_coach.py "What did I do for training this week?"
```
## How It Works
### 1. Memory Tools (`memory_tools.py`)
Defines function tools that the OpenAI Agent can call:
```python
retrieve_memories(query, fact_types, top_k)
search_workouts(after_date, before_date, workout_type)
get_nutrition_summary(after_date, before_date)
get_user_goals()
get_coach_insights(about) # Retrieves observations
```
Each function makes API calls to Hindsight to fetch relevant memories.
### 2. OpenAI Agent (`openai_coach.py`)
Creates an OpenAI Assistant with:
- Fitness coaching instructions
- Access to memory function tools
- Conversation management
When you ask a question:
1. User message is sent to OpenAI Assistant
2. Assistant decides which memory functions to call
3. Functions fetch data from Hindsight
4. Assistant generates response using retrieved context
### 3. Function Calling Flow
```python
# User asks: "What did I run this week?"
# OpenAI Assistant decides to call:
search_workouts(
after_date="2024-11-18",
workout_type="running"
)
# Function retrieves from Hindsight:
{
"results": [
{"text": "User completed 45-minute cardio workout: running..."},
{"text": "User completed 60-minute cardio workout: running..."}
]
}
# OpenAI Assistant generates response:
"This week you've done two runs: a 45-minute run on Monday
and a longer 60-minute run on Wednesday. Great consistency!"
```
## Example Questions
Try asking:
```bash
python openai_coach.py "What does my training look like this week?"
python openai_coach.py "Based on my workouts, should I rest today?"
python openai_coach.py "How is my nutrition supporting my goals?"
python openai_coach.py "What's my progress toward my goal?"
python openai_coach.py "Compare my training this month to last month"
```
The agent will automatically:
1. Identify what memories it needs
2. Call the appropriate function tools
3. Retrieve data from Hindsight
4. Generate a personalized response
## Memory Types Retrieved
The OpenAI Agent can retrieve different memory types from Hindsight:
- **World Facts** (`fact_type: "world"`): Workouts, meals, activities
- **Experience Facts** (`fact_type: "experience"`): Goals, intentions, coach advice
- **Observations** (`fact_type: "observation"`): Consolidated knowledge about user patterns
## Customization
### Add New Function Tools
Edit `memory_tools.py` to add new capabilities:
```python
def get_weekly_summary(week_offset: int = 0):
"""Get a summary of a specific week."""
# Implementation
pass
# Add to MEMORY_TOOLS list
MEMORY_TOOLS.append({
"type": "function",
"function": {
"name": "get_weekly_summary",
"description": "Get training summary for a specific week",
# ... parameters
}
})
# Add to FUNCTION_MAP
FUNCTION_MAP["get_weekly_summary"] = get_weekly_summary
```
### Modify Assistant Instructions
Edit `openai_coach.py` to change the coach's personality or behavior:
```python
assistant = client.beta.assistants.create(
name="Your Custom Coach",
instructions="Your custom instructions here...",
model="gpt-4o-mini",
tools=MEMORY_TOOLS
)
```
## Use Cases
This pattern works for any application that needs memory:
1. **Customer Support Agents** - Remember past conversations and issues
2. **Personal Assistants** - Remember preferences, schedules, past decisions
3. **Educational Tutors** - Track learning progress over time
4. **Health Coaches** - Monitor habits, progress, goals (like this example)
5. **Sales Assistants** - Remember customer interactions and preferences
## Integration Pattern
**To add Hindsight memory to your own OpenAI Agent:**
1. Define function tools that call Hindsight API
2. Register them with your OpenAI Assistant
3. Implement function handlers to execute Hindsight queries
4. Let OpenAI Assistant decide when to retrieve memories
The key benefit: **Separation of concerns**
- OpenAI = Conversation logic
- Hindsight = Memory storage, retrieval, temporal queries, entity linking
## When to Use This vs. Standard Hindsight
**Use OpenAI + Hindsight (this example) when:**
- You want OpenAI's conversation capabilities
- You're already using OpenAI Agents
- You want explicit control over when to retrieve memories
- You want to combine Hindsight with other OpenAI features
**Use Hindsight directly when:**
- You want a complete memory-first solution
- You want automatic memory retrieval and observation consolidation
- You want to use different LLM providers (not just OpenAI)
- You want the `/reflect` endpoint's integrated approach
## Learning Points
After running this demo, you'll understand:
1. How to add sophisticated memory to any OpenAI Agent
2. How function calling bridges LLMs and memory systems
3. How temporal-semantic queries work via function tools
4. Real-world pattern for LLM + memory integration
## Core Files
- `demo_conversational.py` - Conversational demo showcasing preference learning and goal tracking
- `openai_coach.py` - OpenAI Assistant wrapper with streaming and memory integration
- `memory_tools.py` - Function calling tools that bridge to Hindsight API
- `.openai_assistant_id` - Saved assistant ID (auto-generated, gitignored)
## Common Issues
**"OPENAI_API_KEY not set"**
```bash
export OPENAI_API_KEY=your_api_key_here
```
**"Agent not found"**
- Make sure the Hindsight fitness-coach agent exists
**"Connection refused"**
- Make sure Hindsight API is running on localhost:8888
## Next Steps
1. Run the demo to see it in action
2. Try chatting with the coach: `python openai_coach.py`
3. Log your own workouts and meals
4. Experiment with different questions
5. Add custom function tools for your use case
---
**Built with:**
- OpenAI Assistants API
- Hindsight (temporal-semantic memory)
- Function calling for integration

View file

@ -0,0 +1,27 @@
---
sidebar_position: 1
---
import RecipeCarousel from '@site/src/components/RecipeCarousel';
# Cookbook
Practical patterns, recipes, and complete applications for building with Hindsight.
<RecipeCarousel
title="Recipes"
items={[
{ title: "Hindsight Quickstart", href: "/cookbook/recipes/quickstart" },
{ title: "Per-User Memory", href: "/cookbook/recipes/per-user-memory" },
{ title: "Support Agent with Shared Knowledge", href: "/cookbook/recipes/support-agent-shared-knowledge" },
{ title: "Memory with LiteLLM", href: "/cookbook/recipes/litellm-memory-demo" },
{ title: "Routing Tool Learning", href: "/cookbook/recipes/tool-learning-demo" }
]}
/>
<RecipeCarousel
title="Applications"
items={[
{ title: "OpenAI Agent + Hindsight Memory Integration", href: "/cookbook/applications/openai-fitness-coach" }
]}
/>

View file

@ -0,0 +1,187 @@
---
sidebar_position: 4
---
# Memory with LiteLLM
:::tip Run this notebook
This recipe is available as an interactive Jupyter notebook.
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/04-litellm-memory-demo.ipynb)
:::
This notebook demonstrates how to add persistent memory to any LLM app using the `hindsight-litellm` package. Memory storage and injection happen automatically via LiteLLM callbacks - no manual memory management needed!
**Key features demonstrated:**
1. `configure()` + `enable()` - Set up automatic memory integration
2. Automatic storage - Conversations are stored after each LLM call
3. Automatic injection - Relevant memories are injected into prompts
The `hindsight-litellm` package hooks into LiteLLM's callback system to:
- Store each conversation after successful LLM responses
- Inject relevant memories into the system prompt before LLM calls
## Prerequisites
Make sure you have Hindsight running:
```bash
export OPENAI_API_KEY=your-key
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
-e HINDSIGHT_API_LLM_MODEL=o3-mini \
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
ghcr.io/vectorize-io/hindsight:latest
```
- API: http://localhost:8888
- UI: http://localhost:9999
## Installation
```python
!pip install hindsight-litellm litellm nest_asyncio python-dotenv -U -q
```
## Setup
```python
import os
import uuid
import time
import logging
import nest_asyncio
from dotenv import load_dotenv
# Apply nest_asyncio for Jupyter compatibility
nest_asyncio.apply()
# Load environment variables
load_dotenv()
# Configure logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("LiteLLM").setLevel(logging.WARNING)
logging.getLogger("LiteLLM Router").setLevel(logging.WARNING)
logging.getLogger("LiteLLM Proxy").setLevel(logging.WARNING)
# Import hindsight_litellm
import hindsight_litellm
# Configuration
HINDSIGHT_API_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
# Check for API key
if not os.getenv("OPENAI_API_KEY"):
print("Warning: OPENAI_API_KEY not set")
```
## Configure and Enable Automatic Memory
This is all you need! After this, all LiteLLM calls will automatically:
- Have relevant memories injected into the prompt
- Store conversations to Hindsight after the response
```python
# Generate a unique bank_id for this demo session
bank_id = f"demo-{uuid.uuid4().hex[:8]}"
print(f"Using bank_id: {bank_id}")
# Configure and enable hindsight
hindsight_litellm.configure(
hindsight_api_url=HINDSIGHT_API_URL,
bank_id=bank_id,
store_conversations=True, # Automatically store conversations
inject_memories=True, # Automatically inject relevant memories
verbose=True, # Enable logging to debug memory operations
)
hindsight_litellm.enable()
print("Hindsight memory integration enabled!")
```
## Conversation 1: User Introduces Themselves
In this first conversation, the user shares some information about themselves. This will be automatically stored to Hindsight memory.
```python
user_message_1 = "Hi! I'm Alex and I work at Google as a software engineer. I love Python and machine learning."
print(f"User: {user_message_1}\n")
# Use hindsight_litellm.completion() directly
response_1 = hindsight_litellm.completion(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": user_message_1}
],
)
assistant_response_1 = response_1.choices[0].message.content
print(f"Assistant: {assistant_response_1}")
print("\n(Conversation automatically stored to Hindsight)")
```
## Wait for Memory Processing
Hindsight needs a few seconds to process and extract facts from the conversation.
```python
print("Waiting 12 seconds for memory processing...")
time.sleep(12)
print("Done!")
```
## Conversation 2: Test Memory-Augmented Response
Now we start a fresh conversation and ask what the assistant remembers. The memories from the previous conversation will be automatically injected into the prompt!
```python
user_message_2 = "What do you know about me? What programming language should I use for my next project?"
print(f"User: {user_message_2}\n")
# Memories are automatically injected before this call!
response_2 = hindsight_litellm.completion(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": user_message_2}
],
)
print(f"Assistant: {response_2.choices[0].message.content}")
```
## Summary
The assistant should have remembered that Alex:
- Works at Google as a software engineer
- Loves Python and machine learning
And it should have recommended Python based on that knowledge!
```python
print(f"Memories stored in bank: {bank_id}")
print(f"View in UI: http://localhost:9999/banks/{bank_id}")
```
## Cleanup
```python
hindsight_litellm.cleanup()
# Optional: delete the bank
import requests
response = requests.delete(f"{HINDSIGHT_API_URL}/v1/default/banks/{bank_id}")
print(f"Deleted bank: {response.json()}")
```

View file

@ -0,0 +1,247 @@
---
sidebar_position: 2
---
# Per-User Memory
:::tip Run this notebook
This recipe is available as an interactive Jupyter notebook.
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/02-per-user-memory.ipynb)
:::
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.
```python
!pip install hindsight-client nest_asyncio openai python-dotenv -U
```
## 1. Create a Bank When User Signs Up
```python
# Jupyter notebooks already run an asyncio event loop. The hindsight client
# uses loop.run_until_complete() internally, but Python doesn't allow nested
# event loops by default. nest_asyncio patches this to allow nesting.
import nest_asyncio
nest_asyncio.apply()
import os
from dotenv import load_dotenv
from openai import OpenAI as OpenAIClient
# Load environment variables from .env file
# Copy .env.example to .env and fill in your values
load_dotenv()
# Configuration (override with env vars if set)
HINDSIGHT_API_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
HINDSIGHT_UI_URL = os.getenv("HINDSIGHT_UI_URL", "http://localhost:9999")
from hindsight_client import Hindsight
client = Hindsight(base_url=HINDSIGHT_API_URL)
llm = OpenAIClient() # Uses OPENAI_API_KEY from .env
def on_user_signup(user_id: str):
client.create_bank(
bank_id=f"user-{user_id}",
name=f"Memory for {user_id}"
)
print(f"View bank: {HINDSIGHT_UI_URL}/banks/user-{user_id}?view=documents")
```
## 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
import uuid
import json
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})
def save(self, client: Hindsight):
"""Save the entire conversation. Replaces previous version if session_id exists."""
# Convert messages to string format for retain
content = "\n".join([f"{m['role']}: {m['content']}" for m in self.messages])
client.retain(
bank_id=f"user-{self.user_id}",
content=content,
document_id=self.session_id # Same ID = upsert (replace old version)
)
```
## 3. Recall Context Before Responding
```python
def get_context(user_id: str, query: str):
result = client.recall(
bank_id=f"user-{user_id}",
query=query
)
return result.results
```
## 4. Complete Agent Loop
```python
def format_results(results):
"""Format recall results for the prompt."""
if not results:
return "No relevant memories found."
return "\n".join([f"- {r.text}" for r in results])
def format_messages(messages):
"""Format conversation messages for the prompt."""
return "\n".join([f"{m['role']}: {m['content']}" for m in messages])
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 = client.recall(
bank_id=f"user-{session.user_id}",
query=user_message
)
# 3. Build system prompt with memory
system_prompt = f"""You are a helpful assistant with memory of past conversations.
## What you remember about this user
{format_results(context.results)}
Respond helpfully and reference relevant memories when appropriate."""
# 4. Generate response using OpenAI
response = llm.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
*[{"role": m["role"], "content": m["content"]} for m in session.messages]
]
)
assistant_response = response.choices[0].message.content
# 5. Add assistant response to session
session.add_message("assistant", assistant_response)
# 6. Save the updated conversation (upserts based on session_id)
session.save(client)
print(f"User: {user_message}")
print(f"Assistant: {assistant_response}\n")
return assistant_response
```
## 5. Starting a New Conversation
```python
# Create the user's bank
on_user_signup("alice")
# Each new conversation gets a new session with a unique ID
session = ConversationSession(user_id="alice")
# Multiple exchanges in the same conversation
handle_message(session, "Hi! I'm working on a Python project")
handle_message(session, "Can you help me with async/await?")
# View the stored conversation in the UI.
# Each message updates the same document (via document_id), so you'll see
# the full conversation history in a single document rather than separate entries.
print(f"\nView documents: {HINDSIGHT_UI_URL}/banks/user-alice?view=documents")
```
## 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 the Support Agent with Shared Knowledge notebook
## Cleanup
Delete the banks created during this notebook:
```python
import requests
# Delete the user-alice bank
response = requests.delete(f"{HINDSIGHT_API_URL}/v1/default/banks/user-alice")
print(f"Deleted user-alice: {response.json()}")
```

View file

@ -0,0 +1,161 @@
---
sidebar_position: 1
---
# Hindsight Quickstart
:::tip Run this notebook
This recipe is available as an interactive Jupyter notebook.
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/01-quickstart.ipynb)
:::
This notebook covers the basics of using Hindsight:
- **Retain**: Store information in memory
- **Recall**: Retrieve memories matching a query
- **Reflect**: Generate insights from memories
## Prerequisites
Make sure you have Hindsight running. The easiest way is via Docker:
```bash
export OPENAI_API_KEY=your-key
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
-e HINDSIGHT_API_LLM_MODEL=o3-mini \
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
ghcr.io/vectorize-io/hindsight:latest
```
- API: http://localhost:8888
- UI: http://localhost:9999
## Installation
Install the Hindsight Python client:
```python
!pip install hindsight-client nest_asyncio python-dotenv -U
```
## Connect to Hindsight
```python
# Jupyter notebooks already run an asyncio event loop. The hindsight client
# uses loop.run_until_complete() internally, but Python doesn't allow nested
# event loops by default. nest_asyncio patches this to allow nesting.
import nest_asyncio
nest_asyncio.apply()
import os
from dotenv import load_dotenv
# Load environment variables from .env file
# Copy .env.example to .env and fill in your values
load_dotenv()
# Configuration (override with env vars if set)
HINDSIGHT_API_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
HINDSIGHT_UI_URL = os.getenv("HINDSIGHT_UI_URL", "http://localhost:9999")
from hindsight_client import Hindsight
client = Hindsight(base_url=HINDSIGHT_API_URL)
```
## Retain: Store Information
The `retain` operation is used to push new memories into Hindsight. It tells Hindsight to _retain_ the information you pass in.
Behind the scenes, the retain operation uses an LLM to extract key facts, temporal data, entities, and relationships.
```python
# Simple retain
client.retain(
bank_id="my-bank",
content="Alice works at Google as a software engineer"
)
# View the stored document in the UI:
print(f"View documents: {HINDSIGHT_UI_URL}/banks/my-bank?view=documents")
```
```python
# Retain with context and timestamp
client.retain(
bank_id="my-bank",
content="Alice got promoted to senior engineer",
context="career update",
timestamp="2025-06-15T10:00:00Z"
)
```
## Recall: Retrieve Memories
The `recall` operation retrieves memories matching a query. It performs 4 retrieval strategies in parallel:
- **Semantic**: Vector similarity
- **Keyword**: BM25 exact matching
- **Graph**: Entity/temporal/causal links
- **Temporal**: Time range filtering
```python
# Simple recall
results = client.recall(bank_id="my-bank", query="What does Alice do?")
print("Memories:")
for r in results.results:
print(f" - {r.text}")
```
```python
# Temporal recall
results = client.recall(bank_id="my-bank", query="What happened in June?")
print("Memories:")
for r in results.results:
print(f" - {r.text}")
```
## Reflect: Generate Insights
The `reflect` operation performs reasoning over existing memories using the bank's disposition. It retrieves relevant facts and observations to generate contextual responses.
Example use cases:
- An AI Project Manager reflecting on what risks need to be mitigated
- A Sales Agent reflecting on why certain outreach messages have gotten responses
- A Support Agent reflecting on opportunities where customers have unanswered questions
```python
response = client.reflect(bank_id="my-bank", query="What should I know about Alice?")
print(response)
```
## Memory Types
Hindsight organizes knowledge into facts and consolidated observations:
- **World**: Facts about the world ("The stove gets hot")
- **Experience**: Agent's own experiences ("I touched the stove and it really hurt")
- **Observation**: Consolidated knowledge synthesized from facts ("Always be careful around hot surfaces")
## Cleanup
Delete the bank created during this notebook:
```python
import requests
response = requests.delete(f"{HINDSIGHT_API_URL}/v1/default/banks/my-bank")
print(f"Deleted my-bank: {response.json()}")
```

View file

@ -0,0 +1,315 @@
---
sidebar_position: 3
---
# Support Agent with Shared Knowledge
:::tip Run this notebook
This recipe is available as an interactive Jupyter notebook.
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/03-support-agent-shared-knowledge.ipynb)
:::
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
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 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
```python
!pip install hindsight-client nest_asyncio openai python-dotenv -U
```
## 1. Set Up Memory Banks
Create three types of banks:
```python
# Jupyter notebooks already run an asyncio event loop. The hindsight client
# uses loop.run_until_complete() internally, but Python doesn't allow nested
# event loops by default. nest_asyncio patches this to allow nesting.
import nest_asyncio
nest_asyncio.apply()
import os
from dotenv import load_dotenv
from openai import OpenAI as OpenAIClient
# Load environment variables from .env file
# Copy .env.example to .env and fill in your values
load_dotenv()
# Configuration (override with env vars if set)
HINDSIGHT_API_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
HINDSIGHT_UI_URL = os.getenv("HINDSIGHT_UI_URL", "http://localhost:9999")
from hindsight_client import Hindsight
client = Hindsight(base_url=HINDSIGHT_API_URL)
llm = OpenAIClient() # Uses OPENAI_API_KEY from .env
# 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 - retain each doc separately
client.retain(
bank_id="product-docs",
content="# Pricing Tiers\n\nBasic: $10/mo, Pro: $25/mo, Enterprise: Contact us"
)
client.retain(
bank_id="product-docs",
content="# Getting Started\n\nTo set up your account, visit the dashboard and click 'New Project'"
)
# View the stored documents in the UI:
print(f"View documents: {HINDSIGHT_UI_URL}/banks/product-docs?view=documents")
```
## 3. Store User Conversations
After each support interaction, retain it in the user's bank:
```python
def save_conversation(user_id: str, messages: list):
# Convert messages to string format
content = "\n".join([f"{m['role']}: {m['content']}" for m in messages])
client.retain(
bank_id=f"user-{user_id}",
content=content
)
```
## 4. Query Multiple Banks at Support Time
When handling a user query, retrieve context from both banks:
```python
def get_support_context(user_id: str, query: str):
# Get user's personal context
user_context = client.recall(
bank_id=f"user-{user_id}",
query=query
)
# Get relevant product documentation
docs_context = 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 format_results(results):
"""Format recall results for the prompt."""
if not results:
return "No relevant information found."
return "\n".join([f"- {r.text}" for r in results])
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=insight
)
```
## Complete Example
```python
def format_results(results):
if not results:
return "No relevant information found."
return "\n".join([f"- {r.text}" for r in results])
def handle_support_request(user_id: str, query: str):
# 1. Recall from user's memory
user_recall = client.recall(
bank_id=f"user-{user_id}",
query=query
)
# 2. Recall from shared docs
docs_recall = client.recall(
bank_id="product-docs",
query=query
)
# 3. Recall from learnings (optional)
learnings_recall = client.recall(
bank_id="support-learnings",
query=query
)
# 4. Build system prompt with context
system_prompt = f"""You are a helpful support agent. Use the context below to answer the user's question.
## User's History
{format_results(user_recall.results)}
## Product Documentation
{format_results(docs_recall.results)}
## Known Solutions
{format_results(learnings_recall.results)}
Provide helpful, accurate responses based on the documentation. Reference the user's history when relevant."""
# 5. Generate response using OpenAI
response = llm.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": query}
]
)
assistant_response = response.choices[0].message.content
# 6. Save the conversation to user's memory
conversation = f"user: {query}\nassistant: {assistant_response}"
client.retain(
bank_id=f"user-{user_id}",
content=conversation
)
return assistant_response
# Test the function
create_user_bank("bob")
print("User: How do I get started?")
result = handle_support_request("bob", "How do I get started?")
print(f"Assistant: {result}")
print(f"\nView user memory: {HINDSIGHT_UI_URL}/banks/user-bob?view=documents")
```
## 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
## Cleanup
Delete the banks created during this notebook:
```python
import requests
# Delete all banks created in this notebook
for bank_id in ["product-docs", "support-learnings", "user-bob"]:
response = requests.delete(f"{HINDSIGHT_API_URL}/v1/default/banks/{bank_id}")
print(f"Deleted {bank_id}: {response.json()}")
```

View file

@ -0,0 +1,372 @@
---
sidebar_position: 5
---
# Routing Tool Learning
:::tip Run this notebook
This recipe is available as an interactive Jupyter notebook.
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/05-tool-learning-demo.ipynb)
:::
This notebook demonstrates how Hindsight helps an LLM learn which tool to use when tool names are ambiguous. Without memory, the LLM might randomly select between similarly-named tools. With Hindsight, it learns from past interactions and consistently makes the correct choice.
## The Scenario
We have a task routing system with two tools:
- `route_to_channel_alpha` - Routes to processing channel Alpha
- `route_to_channel_omega` - Routes to processing channel Omega
The tool names and descriptions are **intentionally vague**. In reality:
- Channel Alpha handles **FINANCIAL/PAYMENT** tasks (refunds, billing, etc.)
- Channel Omega handles **TECHNICAL/SUPPORT** tasks (bugs, features, etc.)
**Without Hindsight:** The LLM guesses randomly based on vague descriptions
**With Hindsight:** The LLM learns from feedback which channel handles what
## Prerequisites
Make sure you have Hindsight running:
```bash
export OPENAI_API_KEY=your-key
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
-e HINDSIGHT_API_LLM_MODEL=o3-mini \
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
ghcr.io/vectorize-io/hindsight:latest
```
## Installation
```python
!pip install hindsight-litellm hindsight-client litellm nest_asyncio python-dotenv -U -q
```
## Setup
```python
import os
import json
import uuid
import time
import logging
import nest_asyncio
from typing import Optional
from dotenv import load_dotenv
nest_asyncio.apply()
load_dotenv()
logging.basicConfig(level=logging.INFO)
logging.getLogger("LiteLLM").setLevel(logging.WARNING)
logging.getLogger("LiteLLM Router").setLevel(logging.WARNING)
logging.getLogger("httpx").setLevel(logging.WARNING)
import litellm
import hindsight_litellm
from hindsight_client import Hindsight
HINDSIGHT_API_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888")
if not os.getenv("OPENAI_API_KEY"):
print("Warning: OPENAI_API_KEY not set")
```
## Define Tools
These tool definitions are **intentionally ambiguous** - the descriptions don't reveal which channel handles what type of request.
```python
TOOLS = [
{
"type": "function",
"function": {
"name": "route_to_channel_alpha",
"description": "Routes the customer request to processing channel Alpha. Use this channel for appropriate request types.",
"parameters": {
"type": "object",
"properties": {
"request_summary": {
"type": "string",
"description": "A brief summary of the customer's request"
},
"priority": {
"type": "string",
"enum": ["low", "medium", "high"],
"description": "Priority level of the request"
}
},
"required": ["request_summary"]
}
}
},
{
"type": "function",
"function": {
"name": "route_to_channel_omega",
"description": "Routes the customer request to processing channel Omega. Use this channel for appropriate request types.",
"parameters": {
"type": "object",
"properties": {
"request_summary": {
"type": "string",
"description": "A brief summary of the customer's request"
},
"priority": {
"type": "string",
"enum": ["low", "medium", "high"],
"description": "Priority level of the request"
}
},
"required": ["request_summary"]
}
}
}
]
```
## Test Scenarios
A mix of financial and technical requests to test routing accuracy.
```python
TEST_SCENARIOS = [
{
"type": "financial",
"request": "I was charged twice for my subscription last month. I need a refund for the duplicate charge.",
"correct_tool": "route_to_channel_alpha"
},
{
"type": "technical",
"request": "The app keeps crashing when I try to upload a file larger than 10MB. This bug is blocking my work.",
"correct_tool": "route_to_channel_omega"
},
{
"type": "financial",
"request": "My invoice shows an incorrect amount. The billing department needs to fix this.",
"correct_tool": "route_to_channel_alpha"
},
{
"type": "technical",
"request": "I'd like to request a new feature: the ability to export reports as PDF.",
"correct_tool": "route_to_channel_omega"
},
{
"type": "financial",
"request": "I need to update my payment method and understand why my last payment failed.",
"correct_tool": "route_to_channel_alpha"
},
]
```
## Helper Functions
```python
SYSTEM_PROMPT = """You are a customer service routing agent. Your job is to route customer requests to the appropriate processing channel.
You have access to two routing channels:
- route_to_channel_alpha: Routes to channel Alpha
- route_to_channel_omega: Routes to channel Omega
Analyze the customer's request and route it to the most appropriate channel. You must call one of the routing functions to process the request.
Important: Base your routing decision on what you know about each channel's purpose. If you have learned from previous interactions which channel handles specific types of requests, use that knowledge."""
def make_routing_request(user_request: str, use_hindsight: bool, bank_id: Optional[str] = None):
"""Make a routing request and return the tool called."""
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Customer Request: {user_request}"}
]
if use_hindsight and bank_id:
response = hindsight_litellm.completion(
model="gpt-4o-mini",
messages=messages,
tools=TOOLS,
tool_choice="required",
temperature=0.0,
)
else:
response = litellm.completion(
model="gpt-4o-mini",
messages=messages,
tools=TOOLS,
tool_choice="required",
temperature=0.7,
)
if response.choices[0].message.tool_calls:
tool_call = response.choices[0].message.tool_calls[0]
return tool_call.function.name
return None
def store_feedback(bank_id: str, request: str, correct_tool: str, request_type: str):
"""Store feedback about which tool was correct for a request type."""
client = Hindsight(base_url=HINDSIGHT_API_URL, timeout=60.0)
feedback_content = f"""ROUTING FEEDBACK:
Request type: {request_type}
Customer request: "{request}"
Correct routing: {correct_tool}
LEARNED RULE: {request_type.upper()} requests (like refunds, billing, payments, charges, invoices) should ALWAYS be routed to {correct_tool}.
This is important institutional knowledge for routing decisions."""
client.retain(
bank_id=bank_id,
content=feedback_content,
context=f"routing:feedback:{request_type}",
metadata={"request_type": request_type, "correct_tool": correct_tool}
)
```
## Phase 1: Without Hindsight (No Memory)
The LLM has no prior knowledge about which channel handles what. With ambiguous tool descriptions, it may route incorrectly.
```python
print("=" * 60)
print("PHASE 1: WITHOUT HINDSIGHT (No Memory)")
print("=" * 60)
phase1_results = []
for i, scenario in enumerate(TEST_SCENARIOS[:3], 1):
print(f"\n--- Test {i}: {scenario['type'].upper()} Request ---")
print(f"Request: \"{scenario['request'][:60]}...\"")
tool_name = make_routing_request(scenario['request'], use_hindsight=False)
is_correct = tool_name == scenario['correct_tool']
phase1_results.append(is_correct)
print(f"LLM chose: {tool_name}")
print(f"Correct tool: {scenario['correct_tool']}")
print(f"Result: {'✓ CORRECT' if is_correct else '✗ INCORRECT'}")
phase1_accuracy = sum(phase1_results) / len(phase1_results) * 100
print(f"\n>>> Phase 1 Accuracy: {phase1_accuracy:.0f}% ({sum(phase1_results)}/{len(phase1_results)})")
```
## Phase 2: Teaching Phase
Now we provide feedback about correct routing to build memory. This simulates a human supervisor correcting the AI's routing decisions.
```python
bank_id = f"tool-learning-{uuid.uuid4().hex[:8]}"
print(f"Using bank_id: {bank_id}")
# Configure and enable Hindsight
hindsight_litellm.configure(
hindsight_api_url=HINDSIGHT_API_URL,
bank_id=bank_id,
store_conversations=True,
inject_memories=True,
max_memories=10,
recall_budget="high",
verbose=False,
)
hindsight_litellm.enable()
print("\nStoring routing feedback...")
feedback_examples = [
("I need a refund for an incorrect charge on my account.", "route_to_channel_alpha", "financial"),
("There's a bug in the system causing data loss.", "route_to_channel_omega", "technical"),
("My billing statement has errors that need correction.", "route_to_channel_alpha", "financial"),
("I want to request a new feature for the dashboard.", "route_to_channel_omega", "technical"),
]
for request, correct_tool, req_type in feedback_examples:
print(f" Storing: {req_type.upper()} → {correct_tool}")
store_feedback(bank_id, request, correct_tool, req_type)
print("\nWaiting 15 seconds for Hindsight to process memories...")
time.sleep(15)
print("Done!")
```
## Phase 3: With Hindsight (Memory-Augmented)
The LLM now has access to learned routing knowledge via Hindsight. It should route requests correctly based on past feedback.
```python
print("=" * 60)
print("PHASE 3: WITH HINDSIGHT (Memory-Augmented)")
print("=" * 60)
phase3_results = []
for i, scenario in enumerate(TEST_SCENARIOS, 1):
print(f"\n--- Test {i}: {scenario['type'].upper()} Request ---")
print(f"Request: \"{scenario['request'][:60]}...\"")
tool_name = make_routing_request(
scenario['request'],
use_hindsight=True,
bank_id=bank_id
)
is_correct = tool_name == scenario['correct_tool']
phase3_results.append(is_correct)
print(f"LLM chose: {tool_name}")
print(f"Correct tool: {scenario['correct_tool']}")
print(f"Result: {'✓ CORRECT' if is_correct else '✗ INCORRECT'}")
phase3_accuracy = sum(phase3_results) / len(phase3_results) * 100
print(f"\n>>> Phase 3 Accuracy: {phase3_accuracy:.0f}% ({sum(phase3_results)}/{len(phase3_results)})")
```
## Summary
```python
print("=" * 60)
print("SUMMARY")
print("=" * 60)
print(f"\nPhase 1 (No Memory): {phase1_accuracy:.0f}% accuracy")
print(f"Phase 3 (With Hindsight): {phase3_accuracy:.0f}% accuracy")
improvement = phase3_accuracy - phase1_accuracy
if improvement > 0:
print(f"\n🎉 Improvement: +{improvement:.0f}% accuracy with Hindsight!")
elif improvement == 0:
print(f"\nNote: Results may vary. Run again to see learning effect.")
else:
print(f"\nNote: Phase 1 got lucky! Run again to see typical behavior.")
print(f"\nMemories stored in bank: {bank_id}")
print(f"View in UI: http://localhost:9999/banks/{bank_id}")
print("\n" + "=" * 60)
print("KEY INSIGHT")
print("=" * 60)
print("Hindsight allows the LLM to learn from experience which tool")
print("to use, even when tool names/descriptions are ambiguous.")
```
## Cleanup
```python
hindsight_litellm.cleanup()
# Optional: delete the bank
import requests
response = requests.delete(f"{HINDSIGHT_API_URL}/v1/default/banks/{bank_id}")
print(f"Deleted bank: {response.json()}")
```

View file

@ -0,0 +1,192 @@
# Admin CLI
The `hindsight-admin` CLI provides administrative commands for managing your Hindsight deployment, including database migrations, backup, and restore operations.
## Installation
The admin CLI is included with the `hindsight-api` package:
```bash
pip install hindsight-api
# or
uv add hindsight-api
```
## Commands
### run-db-migration
Run database migrations to the latest version. This is useful when you want to run migrations separately from API startup (e.g., in CI/CD pipelines or before deploying a new version).
```bash
hindsight-admin run-db-migration [OPTIONS]
```
**Options:**
| Option | Description | Default |
|--------|-------------|---------|
| `--schema`, `-s` | Database schema to run migrations on | `public` |
**Examples:**
```bash
# Run migrations on the default public schema
hindsight-admin run-db-migration
# Run migrations on a specific tenant schema
hindsight-admin run-db-migration --schema tenant_acme
```
:::tip Disabling Auto-Migrations
To disable automatic migrations on API startup, set `HINDSIGHT_API_RUN_MIGRATIONS_ON_STARTUP=false`. This is useful when you want to run migrations as a separate step in your deployment pipeline.
:::
---
### backup
Create a backup of all Hindsight data to a zip file.
```bash
hindsight-admin backup OUTPUT [OPTIONS]
```
**Arguments:**
| Argument | Description |
|----------|-------------|
| `OUTPUT` | Output file path (will add `.zip` extension if not present) |
**Options:**
| Option | Description | Default |
|--------|-------------|---------|
| `--schema`, `-s` | Database schema to backup | `public` |
**Examples:**
```bash
# Backup to a file
hindsight-admin backup /backups/hindsight-2024-01-15.zip
# Backup a specific tenant schema
hindsight-admin backup /backups/tenant-acme.zip --schema tenant_acme
```
The backup includes:
- Memory banks and their configuration
- Documents and chunks
- Entities and their relationships
- Memory units (facts, experiences, observations)
- Entity cooccurrences and memory links
:::note Consistency
Backups are created within a database transaction with `REPEATABLE READ` isolation, ensuring a consistent snapshot across all tables.
:::
---
### restore
Restore data from a backup file. **Warning: This deletes all existing data in the target schema.**
```bash
hindsight-admin restore INPUT [OPTIONS]
```
**Arguments:**
| Argument | Description |
|----------|-------------|
| `INPUT` | Input backup file (.zip) |
**Options:**
| Option | Description | Default |
|--------|-------------|---------|
| `--schema`, `-s` | Database schema to restore to | `public` |
| `--yes`, `-y` | Skip confirmation prompt | `false` |
**Examples:**
```bash
# Restore with confirmation prompt
hindsight-admin restore /backups/hindsight-2024-01-15.zip
# Restore without confirmation (for scripts)
hindsight-admin restore /backups/hindsight-2024-01-15.zip --yes
# Restore to a specific tenant schema
hindsight-admin restore /backups/tenant-acme.zip --schema tenant_acme --yes
```
:::warning Data Loss
Restore will **delete all existing data** in the target schema before importing the backup. Always verify you have a recent backup before performing a restore.
:::
---
### decommission-worker
Release all tasks owned by a worker, resetting them from "processing" back to "pending" status so they can be picked up by other workers.
```bash
hindsight-admin decommission-worker WORKER_ID [OPTIONS]
```
**Arguments:**
| Argument | Description |
|----------|-------------|
| `WORKER_ID` | ID of the worker to decommission |
**Options:**
| Option | Description | Default |
|--------|-------------|---------|
| `--schema`, `-s` | Database schema | `public` |
**Examples:**
```bash
# Before scaling down - release tasks from workers being removed
hindsight-admin decommission-worker hindsight-worker-4
hindsight-admin decommission-worker hindsight-worker-3
# Release tasks from a crashed worker
hindsight-admin decommission-worker worker-2
# For a specific tenant schema
hindsight-admin decommission-worker worker-1 --schema tenant_acme
```
**When to Use:**
- **Scaling down**: Before removing worker replicas in Kubernetes
- **Graceful removal**: When taking a worker offline for maintenance
- **Crash recovery**: If a worker crashed while processing tasks
- **Stuck worker**: When a worker is unresponsive
:::tip Finding Worker IDs
Worker IDs default to the hostname. In Kubernetes StatefulSets, this is the pod name (e.g., `hindsight-worker-0`). You can also set a custom ID with `HINDSIGHT_API_WORKER_ID` or `--worker-id`.
:::
---
## Environment Variables
The admin CLI uses the same environment variables as the API service. The most important one is:
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_DATABASE_URL` | PostgreSQL connection string | `pg0` (embedded) |
**Example:**
```bash
# Use a specific database
export HINDSIGHT_API_DATABASE_URL=postgresql://user:pass@localhost:5432/hindsight
hindsight-admin backup /backups/mybackup.zip
```

View file

@ -0,0 +1,151 @@
---
sidebar_position: 8
---
# Documents
Track and manage document sources in your memory bank. Documents provide traceability — knowing where memories came from.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import documentsPy from '!!raw-loader!@site/examples/api/documents.py';
import documentsMjs from '!!raw-loader!@site/examples/api/documents.mjs';
:::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:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={documentsPy} section="document-retain" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={documentsMjs} section="document-retain" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Retain content with document ID
hindsight memory retain my-bank "Meeting notes content..." --doc-id notes-2024-03-15
# Batch retain from files
hindsight memory retain-files my-bank docs/
```
</TabItem>
</Tabs>
## Update Documents
Re-retaining with the same document_id **replaces** the old content:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={documentsPy} section="document-update" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={documentsMjs} section="document-update" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Original
hindsight memory retain my-bank "Project deadline: March 31" --doc-id project-plan
# Update
hindsight memory retain my-bank "Project deadline: April 15 (extended)" --doc-id project-plan
```
</TabItem>
</Tabs>
## 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.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={documentsPy} section="document-get" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={documentsMjs} section="document-get" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight document get my-bank meeting-2024-03-15
```
</TabItem>
</Tabs>
## Delete Document
Remove a document and all its associated memories:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={documentsPy} section="document-delete" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={documentsMjs} section="document-delete" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
hindsight document delete my-bank meeting-2024-03-15
```
</TabItem>
</Tabs>
:::warning
Deleting a document permanently removes all memories extracted from it. This action cannot be undone.
:::
## 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
- [**Operations**](./operations) — Monitor background tasks
- [**Memory Banks**](./memory-banks) — Configure bank settings

View file

@ -0,0 +1,141 @@
---
sidebar_position: 2
---
# Main Methods
Hindsight provides three core operations: **retain**, **recall**, and **reflect**.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import mainMethodsPy from '!!raw-loader!@site/examples/api/main-methods.py';
import mainMethodsMjs from '!!raw-loader!@site/examples/api/main-methods.mjs';
:::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.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mainMethodsPy} section="main-retain" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={mainMethodsMjs} section="main-retain" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```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
```
</TabItem>
</Tabs>
**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.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mainMethodsPy} section="main-recall" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={mainMethodsMjs} section="main-recall" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```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
```
</TabItem>
</Tabs>
**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 using memories and observations.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mainMethodsPy} section="main-reflect" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={mainMethodsMjs} section="main-reflect" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Basic reflect
hindsight reflect my-bank "Should we adopt TypeScript for our backend?"
# Verbose output (shows sources and observations)
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
```
</TabItem>
</Tabs>
**What happens:** Memories and observations are recalled, bank disposition is applied, and the LLM reasons through the evidence to generate a response.
**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 + observations | Reasoned response |
| **Uses LLM** | Yes (extraction) | No | Yes (generation) |
| **Uses observations** | No | Yes | 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
- [**Memory Banks**](./memory-banks) — Managing memory bank disposition

View file

@ -0,0 +1,161 @@
---
sidebar_position: 6
---
# Memory Banks
Memory banks are isolated containers that store all memory-related data for a specific context or use case.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import memoryBanksPy from '!!raw-loader!@site/examples/api/memory-banks.py';
import memoryBanksMjs from '!!raw-loader!@site/examples/api/memory-banks.mjs';
import directivesPy from '!!raw-loader!@site/examples/api/directives.py';
import directivesMjs from '!!raw-loader!@site/examples/api/directives.mjs';
## 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
- **Directives** — Hard rules the agent must follow during reflect operations
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
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={memoryBanksPy} section="create-bank" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={memoryBanksMjs} section="create-bank" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Set mission
hindsight bank mission my-bank "I am a research assistant specializing in ML"
# Set disposition
hindsight bank disposition my-bank \
--skepticism 4 \
--literalism 3 \
--empathy 3
```
</TabItem>
</Tabs>
## Mission and Disposition
Mission and disposition are optional settings that influence how the bank reasons during [reflect](./reflect) operations.
:::info
Mission and disposition only affect the `reflect` operation. They do not impact `retain`, `recall`, or other memory operations.
:::
### Mission
The mission is a first-person narrative providing context for reasoning:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={memoryBanksPy} section="bank-mission" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={memoryBanksMjs} section="bank-mission" language="javascript" />
</TabItem>
</Tabs>
### Disposition Traits
Disposition traits influence how reasoning is performed 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 |
## Directives
Directives are hard rules that the agent must follow during [reflect](./reflect) operations. Unlike disposition traits which influence *how* the agent reasons, directives are explicit instructions that are *always* enforced.
:::info
Directives only affect the `reflect` operation. They are injected into prompts and the agent is required to comply with them in all responses.
:::
### When to Use Directives
Use directives for rules that must never be violated:
- **Language/style constraints**: "Always respond in formal English"
- **Privacy rules**: "Never share personal data with third parties"
- **Domain constraints**: "Prefer conservative investment recommendations"
- **Behavioral guardrails**: "Always cite sources when making claims"
### Creating Directives
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={directivesPy} section="create-directive" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={directivesMjs} section="create-directive" language="javascript" />
</TabItem>
</Tabs>
### Listing Directives
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={directivesPy} section="list-directives" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={directivesMjs} section="list-directives" language="javascript" />
</TabItem>
</Tabs>
### Updating Directives
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={directivesPy} section="update-directive" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={directivesMjs} section="update-directive" language="javascript" />
</TabItem>
</Tabs>
### Deleting Directives
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={directivesPy} section="delete-directive" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={directivesMjs} section="delete-directive" language="javascript" />
</TabItem>
</Tabs>
### Directives vs Disposition
| Aspect | Directives | Disposition |
|--------|------------|-------------|
| **Nature** | Hard rules, must be followed | Soft influence on reasoning style |
| **Enforcement** | Strict — responses are rejected if violated | Flexible — shapes interpretation |
| **Use case** | Compliance, guardrails, constraints | Personality, character, tone |
| **Example** | "Never recommend specific stocks" | High skepticism: questions claims |

View file

@ -0,0 +1,262 @@
---
sidebar_position: 4
---
# Mental Models
User-curated summaries that provide high-quality, pre-computed answers for common queries.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import mentalModelsPy from '!!raw-loader!@site/examples/api/mental-models.py';
## What Are Mental Models?
Mental models are **saved reflect responses** that you curate for your memory bank. When you create a mental model, Hindsight runs a reflect operation with your source query and stores the result. During future reflect calls, these pre-computed summaries are checked first — providing faster, more consistent answers.
```mermaid
graph LR
A[Create Mental Model] --> B[Run Reflect]
B --> C[Store Result]
C --> D[Future Queries]
D --> E{Match Found?}
E -->|Yes| F[Return Mental Model]
E -->|No| G[Run Full Reflect]
```
### Why Use Mental Models?
| Benefit | Description |
|---------|-------------|
| **Consistency** | Same answer every time for common questions |
| **Speed** | Pre-computed responses are returned instantly |
| **Quality** | Manually curated summaries you've reviewed |
| **Control** | Define exactly how key topics should be answered |
### Hierarchical Retrieval
During reflect, the agent checks sources in priority order:
1. **Mental Models** — User-curated summaries (highest priority)
2. **Observations** — Consolidated knowledge
3. **Raw Facts** — Ground truth memories
Mental models are checked first because they represent your explicitly curated knowledge.
---
## Create a Mental Model
Creating a mental model runs a reflect operation in the background and saves the result:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="create-mental-model" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Create a mental model (async operation)
curl -X POST "http://localhost:8888/v1/default/banks/my-bank/mental-models" \
-H "Content-Type: application/json" \
-d '{
"name": "Team Communication Preferences",
"source_query": "How does the team prefer to communicate?",
"tags": ["team"]
}'
# Response: {"operation_id": "op-123"}
# Use the operations endpoint to check completion
```
</TabItem>
</Tabs>
### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Human-readable name for the mental model |
| `source_query` | string | Yes | The query to run to generate content |
| `tags` | list | No | Tags for filtering during retrieval |
| `max_tokens` | int | No | Maximum tokens for the mental model content |
| `trigger` | object | No | Trigger settings (see [Automatic Refresh](#automatic-refresh)) |
---
## Automatic Refresh
Mental models can be configured to **automatically refresh** when observations are updated. This keeps them in sync with the latest knowledge without manual intervention.
### Trigger Settings
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `refresh_after_consolidation` | bool | false | Automatically refresh after observations consolidation |
When `refresh_after_consolidation` is enabled, the mental model will be re-generated every time the bank's observations are consolidated — ensuring it always reflects the latest synthesized knowledge.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="create-mental-model-with-trigger" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
# Create a mental model with automatic refresh enabled
curl -X POST "http://localhost:8888/v1/default/banks/my-bank/mental-models" \
-H "Content-Type: application/json" \
-d '{
"name": "Project Status",
"source_query": "What is the current project status?",
"trigger": {"refresh_after_consolidation": true}
}'
```
</TabItem>
</Tabs>
### When to Use Automatic Refresh
| Use Case | Automatic Refresh | Why |
|----------|-------------------|-----|
| **Real-time dashboards** | ✅ Enabled | Status should always be current |
| **Policy summaries** | ❌ Disabled | Policies change infrequently, manual refresh preferred |
| **User preferences** | ✅ Enabled | Preferences evolve with new interactions |
| **FAQ answers** | ❌ Disabled | Answers are curated, should be reviewed before updating |
:::tip
Enable automatic refresh for mental models that need to stay current. Disable it for curated content where you want to review changes before they go live.
:::
---
## List Mental Models
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="list-mental-models" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
curl "http://localhost:8888/v1/default/banks/my-bank/mental-models"
```
</TabItem>
</Tabs>
---
## Get a Mental Model
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="get-mental-model" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
curl "http://localhost:8888/v1/default/banks/my-bank/mental-models/{mental_model_id}"
```
</TabItem>
</Tabs>
### Response Fields
| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique mental model ID |
| `bank_id` | string | Memory bank ID |
| `name` | string | Human-readable name |
| `source_query` | string | The query used to generate content |
| `content` | string | The generated mental model text |
| `tags` | list | Tags for filtering |
| `last_refreshed_at` | string | When the mental model was last updated |
| `created_at` | string | When the mental model was created |
| `reflect_response` | object | Full reflect response including `based_on` facts |
---
## Refresh a Mental Model
Re-run the source query to update the mental model with current knowledge:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="refresh-mental-model" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
curl -X POST "http://localhost:8888/v1/default/banks/my-bank/mental-models/{mental_model_id}/refresh"
```
</TabItem>
</Tabs>
Refreshing is useful when:
- New memories have been retained that affect the topic
- Observations have been updated
- You want to ensure the mental model reflects current knowledge
---
## Update a Mental Model
Update the mental model's name:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="update-mental-model" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
curl -X PATCH "http://localhost:8888/v1/default/banks/my-bank/mental-models/{mental_model_id}" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Team Communication Preferences"}'
```
</TabItem>
</Tabs>
---
## Delete a Mental Model
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={mentalModelsPy} section="delete-mental-model" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
curl -X DELETE "http://localhost:8888/v1/default/banks/my-bank/mental-models/{mental_model_id}"
```
</TabItem>
</Tabs>
---
## Use Cases
| Use Case | Example |
|----------|---------|
| **FAQ Answers** | Pre-compute answers to common customer questions |
| **Onboarding Summaries** | "What should new team members know?" |
| **Status Reports** | "What's the current project status?" refreshed weekly |
| **Policy Summaries** | "What are our security policies?" |
---
## Next Steps
- [**Reflect**](./reflect) — How the agentic loop uses mental models
- [**Observations**](/developer/observations) — How knowledge is consolidated
- [**Operations**](./operations) — Track async mental model creation

View file

@ -0,0 +1,94 @@
---
sidebar_position: 9
---
# 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 |
| **consolidate** | After `retain` | Consolidates new facts into observations |
## Async Retain Example
When retaining large batches of memories, use `async=true` to process in the background. The response includes an `operation_id` that you can use to poll for completion.
### 1. Submit async retain request
```bash
curl -X POST "http://localhost:8000/v1/default/banks/my-bank/memories" \
-H "Content-Type: application/json" \
-d '{
"items": [
{"content": "Alice joined Google in 2023"},
{"content": "Bob prefers Python over JavaScript"}
],
"async": true
}'
```
Response:
```json
{
"success": true,
"bank_id": "my-bank",
"items_count": 2,
"async": true,
"operation_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
### 2. Poll for operation status
```bash
curl "http://localhost:8000/v1/default/banks/my-bank/operations"
```
Response:
```json
{
"bank_id": "my-bank",
"operations": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"task_type": "retain",
"items_count": 2,
"document_id": null,
"created_at": "2024-01-15T10:30:00Z",
"status": "completed",
"error_message": null
}
]
}
```
### Operation Status Values
| Status | Description |
|--------|-------------|
| `pending` | Operation is queued and waiting to be processed |
| `completed` | Operation finished successfully |
| `failed` | Operation failed (check `error_message` for details) |
## Next Steps
- [**Documents**](./documents) — Track document sources
- [**Memory Banks**](./memory-banks) — Configure bank settings

View file

@ -0,0 +1,109 @@
---
sidebar_position: 0
---
# Quick Start
Get up and running with Hindsight in 60 seconds.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import quickstartPy from '!!raw-loader!@site/examples/api/quickstart.py';
import quickstartMjs from '!!raw-loader!@site/examples/api/quickstart.mjs';
import quickstartSh from '!!raw-loader!@site/examples/api/quickstart.sh';
## Start the API Server
<Tabs>
<TabItem value="pip" label="pip (API only)">
```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](http://localhost:8888/docs)
</TabItem>
<TabItem value="docker" label="Docker (Full Experience)">
```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
</TabItem>
</Tabs>
:::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
<Tabs>
<TabItem value="python" label="Python">
```bash
pip install hindsight-client
```
<CodeSnippet code={quickstartPy} section="quickstart-full" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
```bash
npm install @vectorize-io/hindsight-client
```
<CodeSnippet code={quickstartMjs} section="quickstart-full" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
```bash
curl -fsSL https://hindsight.vectorize.io/get-cli | bash
```
<CodeSnippet code={quickstartSh} section="quickstart-full" language="bash" />
</TabItem>
</Tabs>
---
## 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 mission
- [**Server Deployment**](/developer/installation) — Docker Compose, Helm, and production setup

View file

@ -0,0 +1,159 @@
---
sidebar_position: 2
---
# Recall Memories
Retrieve memories using multi-strategy recall.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import recallPy from '!!raw-loader!@site/examples/api/recall.py';
import recallMjs from '!!raw-loader!@site/examples/api/recall.mjs';
import recallSh from '!!raw-loader!@site/examples/api/recall.sh';
:::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
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-basic" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={recallMjs} section="recall-basic" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={recallSh} section="recall-basic" language="bash" />
</TabItem>
</Tabs>
## Recall Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `query` | string | required | Natural language query |
| `types` | list | all | Filter: `world`, `experience`, `observation` |
| `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_chunks` | bool | false | Include raw text chunks that generated the memories |
| `max_chunk_tokens` | int | 500 | Token budget for chunks |
| `tags` | list | None | Filter memories by tags (see [Tag Filtering](#filter-by-tags)) |
| `tags_match` | string | "any" | How to match tags: `any`, `all`, `any_strict`, `all_strict` |
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-with-options" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={recallMjs} section="recall-with-options" language="javascript" />
</TabItem>
</Tabs>
## Filter by Fact Type
Recall specific memory types:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-world-only" language="python" />
<CodeSnippet code={recallPy} section="recall-experience-only" language="python" />
<CodeSnippet code={recallPy} section="recall-observations-only" language="python" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={recallSh} section="recall-fact-type" language="bash" />
</TabItem>
</Tabs>
:::tip About Observations
Observations are consolidated knowledge synthesized from multiple facts. They capture patterns, preferences, and learnings that the memory bank has built up over time. Observations are automatically created in the background after retain operations.
:::
## 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:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-token-budget" language="python" />
</TabItem>
</Tabs>
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.
## 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
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-budget-levels" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={recallMjs} section="recall-budget-levels" language="javascript" />
</TabItem>
</Tabs>
## Filter by Tags
Tags enable **visibility scoping**—filter memories based on tags assigned during [retain](./retain#tagging-memories). This is essential for multi-user agents where each user should only see their own memories.
### Basic Tag Filtering
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-with-tags" language="python" />
</TabItem>
</Tabs>
### Tag Match Modes
The `tags_match` parameter controls how tags are matched:
| Mode | Behavior | Untagged Memories |
|------|----------|-------------------|
| `any` | OR: memory has ANY of the specified tags | **Included** |
| `all` | AND: memory has ALL of the specified tags | **Included** |
| `any_strict` | OR: memory has ANY of the specified tags | **Excluded** |
| `all_strict` | AND: memory has ALL of the specified tags | **Excluded** |
**Strict modes** are useful when you want to ensure only tagged memories are returned:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-tags-strict" language="python" />
</TabItem>
</Tabs>
**AND matching** requires all specified tags to be present:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={recallPy} section="recall-tags-all" language="python" />
</TabItem>
</Tabs>
### Use Cases
| Scenario | Tags | Mode | Result |
|----------|------|------|--------|
| User A's memories only | `["user:alice"]` | `any_strict` | Only memories tagged `user:alice` |
| Support + feedback | `["support", "feedback"]` | `any` | Memories with either tag + untagged |
| Multi-user room | `["user:alice", "room:general"]` | `all_strict` | Only memories with both tags |
| Global + user-specific | `["user:alice"]` | `any` | Alice's memories + shared (untagged) |

View file

@ -0,0 +1,168 @@
---
sidebar_position: 3
---
# Reflect
Generate disposition-aware responses using an agentic reasoning loop.
When you call **reflect**, Hindsight runs an **agentic loop** that:
1. **Autonomously searches** for relevant information using multiple tools
2. **Applies** the bank's disposition traits to shape the reasoning style
3. **Generates** a grounded answer with citations to the sources used
The agent has access to hierarchical retrieval tools (mental models → observations → raw facts) and decides what information it needs to answer your query.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import reflectPy from '!!raw-loader!@site/examples/api/reflect.py';
import reflectMjs from '!!raw-loader!@site/examples/api/reflect.mjs';
import reflectSh from '!!raw-loader!@site/examples/api/reflect.sh';
:::info How Reflect Works
Learn about disposition-driven reasoning 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
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={reflectPy} section="reflect-basic" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={reflectMjs} section="reflect-basic" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={reflectSh} section="reflect-basic" language="bash" />
</TabItem>
</Tabs>
## Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `query` | string | required | Question or prompt |
| `budget` | string | "low" | Budget level: `low`, `mid`, `high` (see below) |
| `max_tokens` | int | 4096 | Maximum tokens for the final response |
| `response_schema` | object | None | JSON Schema for [structured output](#structured-output) |
| `tags` | list | None | Filter memories by tags during reflection |
| `tags_match` | string | "any" | How to match tags: `any`, `all`, `any_strict`, `all_strict` |
| `trace` | bool | false | Include detailed agent trace in response |
### Budget
The `budget` parameter controls the research depth — how thoroughly the agent explores before answering:
| Budget | Research Depth | Use Case |
|--------|----------------|----------|
| `low` | Shallow | Quick answers, simple lookups. Prioritizes speed over completeness. |
| `mid` | Moderate | Balanced exploration. Checks multiple sources when warranted. |
| `high` | Deep | Comprehensive analysis. Explores all knowledge levels, uses multiple query variations. |
Use `high` for complex questions that require synthesizing information from multiple sources or verifying facts across different retrieval levels.
### Max Tokens
The `max_tokens` parameter limits the length of the final generated response. This does not affect how much the agent can retrieve during the agentic loop — only the final answer length.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={reflectPy} section="reflect-with-params" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={reflectMjs} section="reflect-with-params" language="javascript" />
</TabItem>
</Tabs>
## 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 |
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={reflectPy} section="reflect-disposition" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={reflectMjs} section="reflect-disposition" language="javascript" />
</TabItem>
</Tabs>
## Citations
The response includes a `based_on` field that shows which sources were used:
- `based_on.memories` — Memory facts (world, experience) that were retrieved and cited
- `based_on.mental_models` — User-curated mental models that were used
- `based_on.directives` — Directives that were enforced
**Important:** Only IDs that were actually retrieved during the agent loop can be cited. The agent validates citations to prevent hallucinated references.
This enables:
- **Transparency** — users see exactly which sources informed the answer
- **Verification** — check if the response is grounded in actual memories
- **Debugging** — use `trace=True` for detailed tool call logs
## Structured Output
For applications that need to process responses programmatically, you can request structured output by providing a JSON Schema via `response_schema`. When provided, the response includes a `structured_output` field with the LLM response parsed according to the schema. The `text` field will be empty since only a single LLM call is made for efficiency.
The easiest way to define a schema is using **Pydantic models**:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={reflectPy} section="reflect-structured-output" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={reflectMjs} section="reflect-structured-output" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={reflectSh} section="reflect-structured-output" language="bash" />
</TabItem>
</Tabs>
| Use Case | Why Structured Output Helps |
|----------|----------------------------|
| **Decision pipelines** | Parse recommendations into workflow systems |
| **Dashboards** | Extract confidence scores, risk factors for visualization |
| **Multi-agent systems** | Pass structured data between agents |
| **Auditing** | Log structured decisions with clear reasoning |
**Tips:**
- Use Pydantic's `model_json_schema()` for type-safe schema generation
- Use `model_validate()` to parse the response back into your Pydantic model
- Keep schemas focused — extract only what you need
- Use `Optional` fields for data that may not always be available
## Filter by Tags
Like [recall](./recall#filter-by-tags), reflect supports tag filtering to scope which memories are considered during reasoning. This is essential for multi-user scenarios where reflection should only consider memories relevant to a specific user.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={reflectPy} section="reflect-with-tags" language="python" />
</TabItem>
</Tabs>
The `tags_match` parameter works the same as in recall:
| Mode | Behavior |
|------|----------|
| `any` | OR matching, includes untagged memories |
| `all` | AND matching, includes untagged memories |
| `any_strict` | OR matching, excludes untagged memories |
| `all_strict` | AND matching, excludes untagged memories |
See [Retain API](./retain#tagging-memories) for how to tag memories and [Recall API](./recall#filter-by-tags) for more details on tag matching modes.

View file

@ -0,0 +1,178 @@
---
sidebar_position: 2
---
# 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.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
{/* Import raw source files */}
import retainPy from '!!raw-loader!@site/examples/api/retain.py';
import retainMjs from '!!raw-loader!@site/examples/api/retain.mjs';
import retainSh from '!!raw-loader!@site/examples/api/retain.sh';
:::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
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-basic" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-basic" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={retainSh} section="retain-basic" language="bash" />
</TabItem>
</Tabs>
## 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:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-with-context" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-with-context" language="javascript" />
</TabItem>
<TabItem value="cli" label="CLI">
<CodeSnippet code={retainSh} section="retain-with-context" language="bash" />
</TabItem>
</Tabs>
The `timestamp` defaults to the current time if not specified. Providing explicit timestamps enables temporal queries like "What happened last spring?"
### Response Fields
The retain response includes:
| Field | Type | Description |
|-------|------|-------------|
| `success` | bool | Whether the operation succeeded |
| `bank_id` | string | The memory bank ID |
| `items_count` | int | Number of items processed |
| `async` | bool | Whether processed asynchronously |
| `usage` | TokenUsage | Token usage metrics for LLM calls (synchronous only) |
The `usage` field contains token metrics for cost tracking:
- `input_tokens`: Tokens consumed by prompts
- `output_tokens`: Tokens generated by the LLM
- `total_tokens`: Sum of input and output tokens
Note: `usage` is only present for synchronous operations. Async operations (`async: true`) do not return usage metrics.
## 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.
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-batch" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-batch" language="javascript" />
</TabItem>
</Tabs>
The `document_id` groups related memories for later management.
## Store from Files
<Tabs>
<TabItem value="cli" label="CLI">
```bash
# Single file
hindsight memory retain-files my-bank document.txt
# Directory (recursive by default)
hindsight memory retain-files my-bank ./documents/
```
</TabItem>
</Tabs>
## Async Ingestion
For large batches, use async ingestion to avoid blocking:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-async" language="python" />
</TabItem>
<TabItem value="node" label="Node.js">
<CodeSnippet code={retainMjs} section="retain-async" language="javascript" />
</TabItem>
</Tabs>
## Tagging Memories
Tags enable **visibility scoping**—useful when one memory bank serves multiple users but each should only see relevant memories. For example, an agent that chats with multiple users can tag memories by user ID and filter during recall.
### Tag Individual Items
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-with-tags" language="python" />
</TabItem>
</Tabs>
### Apply Tags to All Items in a Batch
Use `document_tags` to apply the same tags to all items in a request:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-with-document-tags" language="python" />
</TabItem>
</Tabs>
When both `document_tags` and item-level `tags` are provided, they are merged together.
### Tag Naming Conventions
Use consistent naming patterns for tags:
| Pattern | Example | Use Case |
|---------|---------|----------|
| `user:<id>` | `user:alice` | Multi-user agent filtering |
| `session:<id>` | `session:123` | Session-based scoping |
| `room:<id>` | `room:general` | Chat room isolation |
| `topic:<name>` | `topic:feedback` | Topic categorization |
### Listing Tags
Use the list tags API to discover existing tags, useful for UI autocomplete or wildcard expansion:
<Tabs>
<TabItem value="python" label="Python">
<CodeSnippet code={retainPy} section="retain-list-tags" language="python" />
</TabItem>
</Tabs>
See [Recall API](./recall#filter-by-tags) for filtering memories by tags during retrieval.

View file

@ -0,0 +1,455 @@
# Configuration
Complete reference for configuring Hindsight services through environment variables.
Hindsight has two services, each with its own configuration prefix:
| Service | Prefix | Description |
|---------|--------|-------------|
| **API Service** | `HINDSIGHT_API_*` | Core memory engine |
| **Control Plane** | `HINDSIGHT_CP_*` | Web UI |
---
## API Service
The API service handles all memory operations (retain, recall, reflect).
### Database
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_DATABASE_URL` | PostgreSQL connection string | `pg0` (embedded) |
| `HINDSIGHT_API_RUN_MIGRATIONS_ON_STARTUP` | Run database migrations on API startup | `true` |
If not provided, the server uses embedded `pg0` — convenient for development but not recommended for production.
### Database Connection Pool
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_DB_POOL_MIN_SIZE` | Minimum connections in the pool | `5` |
| `HINDSIGHT_API_DB_POOL_MAX_SIZE` | Maximum connections in the pool | `100` |
| `HINDSIGHT_API_DB_COMMAND_TIMEOUT` | PostgreSQL command timeout in seconds | `60` |
| `HINDSIGHT_API_DB_ACQUIRE_TIMEOUT` | Connection acquisition timeout in seconds | `30` |
For high-concurrency workloads, increase `DB_POOL_MAX_SIZE`. Each concurrent recall/think operation can use 2-4 connections.
To run migrations manually (e.g., before starting the API), use the admin CLI:
```bash
hindsight-admin run-db-migration
# Or for a specific schema:
hindsight-admin run-db-migration --schema tenant_acme
```
### LLM Provider
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_LLM_PROVIDER` | Provider: `openai`, `anthropic`, `gemini`, `groq`, `ollama`, `lmstudio` | `openai` |
| `HINDSIGHT_API_LLM_API_KEY` | API key for LLM provider | - |
| `HINDSIGHT_API_LLM_MODEL` | Model name | `gpt-5-mini` |
| `HINDSIGHT_API_LLM_BASE_URL` | Custom LLM endpoint | Provider default |
| `HINDSIGHT_API_LLM_MAX_CONCURRENT` | Max concurrent LLM requests | `32` |
| `HINDSIGHT_API_LLM_TIMEOUT` | LLM request timeout in seconds | `120` |
| `HINDSIGHT_API_LLM_GROQ_SERVICE_TIER` | Groq service tier: `on_demand`, `flex`, `auto` | `auto` |
**Provider Examples**
```bash
# Groq (recommended for fast inference)
export HINDSIGHT_API_LLM_PROVIDER=groq
export HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=openai/gpt-oss-20b
# For free tier users: override to on_demand if you get service_tier errors
# export HINDSIGHT_API_LLM_GROQ_SERVICE_TIER=on_demand
# 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
# Anthropic
export HINDSIGHT_API_LLM_PROVIDER=anthropic
export HINDSIGHT_API_LLM_API_KEY=sk-ant-xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=claude-sonnet-4-20250514
# Ollama (local, no API key)
export HINDSIGHT_API_LLM_PROVIDER=ollama
export HINDSIGHT_API_LLM_BASE_URL=http://localhost:11434/v1
export HINDSIGHT_API_LLM_MODEL=llama3
# LM Studio (local, no API key)
export HINDSIGHT_API_LLM_PROVIDER=lmstudio
export HINDSIGHT_API_LLM_BASE_URL=http://localhost:1234/v1
export HINDSIGHT_API_LLM_MODEL=your-local-model
# OpenAI-compatible endpoint
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
```
### Per-Operation LLM Configuration
Different memory operations have different requirements. **Retain** (fact extraction) benefits from models with strong structured output capabilities, while **Reflect** (reasoning/response generation) can use lighter, faster models. Configure separate LLM models for each operation to optimize for cost and performance.
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_RETAIN_LLM_PROVIDER` | LLM provider for retain operations | Falls back to `HINDSIGHT_API_LLM_PROVIDER` |
| `HINDSIGHT_API_RETAIN_LLM_API_KEY` | API key for retain LLM | Falls back to `HINDSIGHT_API_LLM_API_KEY` |
| `HINDSIGHT_API_RETAIN_LLM_MODEL` | Model for retain operations | Falls back to `HINDSIGHT_API_LLM_MODEL` |
| `HINDSIGHT_API_RETAIN_LLM_BASE_URL` | Base URL for retain LLM | Falls back to `HINDSIGHT_API_LLM_BASE_URL` |
| `HINDSIGHT_API_REFLECT_LLM_PROVIDER` | LLM provider for reflect operations | Falls back to `HINDSIGHT_API_LLM_PROVIDER` |
| `HINDSIGHT_API_REFLECT_LLM_API_KEY` | API key for reflect LLM | Falls back to `HINDSIGHT_API_LLM_API_KEY` |
| `HINDSIGHT_API_REFLECT_LLM_MODEL` | Model for reflect operations | Falls back to `HINDSIGHT_API_LLM_MODEL` |
| `HINDSIGHT_API_REFLECT_LLM_BASE_URL` | Base URL for reflect LLM | Falls back to `HINDSIGHT_API_LLM_BASE_URL` |
| `HINDSIGHT_API_CONSOLIDATION_LLM_PROVIDER` | LLM provider for observation consolidation | Falls back to `HINDSIGHT_API_LLM_PROVIDER` |
| `HINDSIGHT_API_CONSOLIDATION_LLM_API_KEY` | API key for consolidation LLM | Falls back to `HINDSIGHT_API_LLM_API_KEY` |
| `HINDSIGHT_API_CONSOLIDATION_LLM_MODEL` | Model for consolidation operations | Falls back to `HINDSIGHT_API_LLM_MODEL` |
| `HINDSIGHT_API_CONSOLIDATION_LLM_BASE_URL` | Base URL for consolidation LLM | Falls back to `HINDSIGHT_API_LLM_BASE_URL` |
:::tip When to Use Per-Operation Config
- **Retain**: Use models with strong structured output (e.g., GPT-4o, Claude) for accurate fact extraction
- **Reflect**: Use faster/cheaper models (e.g., GPT-4o-mini, Groq) for reasoning and response generation
- **Recall**: Does not use LLM (pure retrieval), so no configuration needed
:::
**Example: Separate Models for Retain and Reflect**
```bash
# Default LLM (used as fallback)
export HINDSIGHT_API_LLM_PROVIDER=openai
export HINDSIGHT_API_LLM_API_KEY=sk-xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=gpt-4o
# Use GPT-4o for retain (strong structured output)
export HINDSIGHT_API_RETAIN_LLM_MODEL=gpt-4o
# Use faster/cheaper model for reflect
export HINDSIGHT_API_REFLECT_LLM_PROVIDER=groq
export HINDSIGHT_API_REFLECT_LLM_API_KEY=gsk_xxxxxxxxxxxx
export HINDSIGHT_API_REFLECT_LLM_MODEL=llama-3.3-70b-versatile
```
### Embeddings
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_EMBEDDINGS_PROVIDER` | Provider: `local`, `tei`, `openai`, `cohere`, or `litellm` | `local` |
| `HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL` | Model for local provider | `BAAI/bge-small-en-v1.5` |
| `HINDSIGHT_API_EMBEDDINGS_TEI_URL` | TEI server URL | - |
| `HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY` | OpenAI API key (falls back to `HINDSIGHT_API_LLM_API_KEY`) | - |
| `HINDSIGHT_API_EMBEDDINGS_OPENAI_MODEL` | OpenAI embedding model | `text-embedding-3-small` |
| `HINDSIGHT_API_EMBEDDINGS_OPENAI_BASE_URL` | Custom base URL for OpenAI-compatible API (e.g., Azure OpenAI) | - |
| `HINDSIGHT_API_COHERE_API_KEY` | Cohere API key (shared for embeddings and reranker) | - |
| `HINDSIGHT_API_EMBEDDINGS_COHERE_MODEL` | Cohere embedding model | `embed-english-v3.0` |
| `HINDSIGHT_API_EMBEDDINGS_COHERE_BASE_URL` | Custom base URL for Cohere-compatible API (e.g., Azure-hosted) | - |
| `HINDSIGHT_API_LITELLM_API_BASE` | LiteLLM proxy base URL (shared for embeddings and reranker) | `http://localhost:4000` |
| `HINDSIGHT_API_LITELLM_API_KEY` | LiteLLM proxy API key (optional, depends on proxy config) | - |
| `HINDSIGHT_API_EMBEDDINGS_LITELLM_MODEL` | LiteLLM embedding model (use provider prefix, e.g., `cohere/embed-english-v3.0`) | `text-embedding-3-small` |
```bash
# Local (default) - uses SentenceTransformers
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
export HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5
# OpenAI - cloud-based embeddings
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=openai
export HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY=sk-xxxxxxxxxxxx # or reuses HINDSIGHT_API_LLM_API_KEY
export HINDSIGHT_API_EMBEDDINGS_OPENAI_MODEL=text-embedding-3-small # 1536 dimensions
# Azure OpenAI - embeddings via Azure endpoint
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=openai
export HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY=your-azure-api-key
export HINDSIGHT_API_EMBEDDINGS_OPENAI_MODEL=text-embedding-3-small
export HINDSIGHT_API_EMBEDDINGS_OPENAI_BASE_URL=https://your-resource.openai.azure.com/openai/deployments/your-deployment
# TEI - HuggingFace Text Embeddings Inference (recommended for production)
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=tei
export HINDSIGHT_API_EMBEDDINGS_TEI_URL=http://localhost:8080
# Cohere - cloud-based embeddings
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=cohere
export HINDSIGHT_API_COHERE_API_KEY=your-api-key
export HINDSIGHT_API_EMBEDDINGS_COHERE_MODEL=embed-english-v3.0 # 1024 dimensions
# Azure-hosted Cohere - embeddings via custom endpoint
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=cohere
export HINDSIGHT_API_COHERE_API_KEY=your-azure-api-key
export HINDSIGHT_API_EMBEDDINGS_COHERE_MODEL=embed-english-v3.0
export HINDSIGHT_API_EMBEDDINGS_COHERE_BASE_URL=https://your-azure-cohere-endpoint.com
# LiteLLM proxy - unified gateway for multiple providers
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=litellm
export HINDSIGHT_API_LITELLM_API_BASE=http://localhost:4000
export HINDSIGHT_API_LITELLM_API_KEY=your-litellm-key # optional
export HINDSIGHT_API_EMBEDDINGS_LITELLM_MODEL=text-embedding-3-small # or cohere/embed-english-v3.0
```
#### Embedding Dimensions
Hindsight automatically detects the embedding dimension from the model at startup and adjusts the database schema accordingly. The default model (`BAAI/bge-small-en-v1.5`) produces 384-dimensional vectors, while OpenAI models produce 1536 or 3072 dimensions.
:::warning Dimension Changes
Once memories are stored, you cannot change the embedding dimension without losing data. If you need to switch to a model with different dimensions:
1. **Empty database**: The schema is adjusted automatically on startup
2. **Existing data**: Either delete all memories first, or use a model with matching dimensions
Supported OpenAI embedding dimensions:
- `text-embedding-3-small`: 1536 dimensions
- `text-embedding-3-large`: 3072 dimensions
- `text-embedding-ada-002`: 1536 dimensions (legacy)
:::
### Reranker
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_RERANKER_PROVIDER` | Provider: `local`, `tei`, `cohere`, `flashrank`, `litellm`, or `rrf` | `local` |
| `HINDSIGHT_API_RERANKER_LOCAL_MODEL` | Model for local provider | `cross-encoder/ms-marco-MiniLM-L-6-v2` |
| `HINDSIGHT_API_RERANKER_LOCAL_MAX_CONCURRENT` | Max concurrent local reranking (prevents CPU thrashing under load) | `4` |
| `HINDSIGHT_API_RERANKER_TEI_URL` | TEI server URL | - |
| `HINDSIGHT_API_RERANKER_TEI_BATCH_SIZE` | Batch size for TEI reranking | `128` |
| `HINDSIGHT_API_RERANKER_TEI_MAX_CONCURRENT` | Max concurrent TEI reranking requests | `8` |
| `HINDSIGHT_API_RERANKER_COHERE_MODEL` | Cohere rerank model | `rerank-english-v3.0` |
| `HINDSIGHT_API_RERANKER_COHERE_BASE_URL` | Custom base URL for Cohere-compatible API (e.g., Azure-hosted) | - |
| `HINDSIGHT_API_RERANKER_LITELLM_MODEL` | LiteLLM rerank model (use provider prefix, e.g., `cohere/rerank-english-v3.0`) | `cohere/rerank-english-v3.0` |
| `HINDSIGHT_API_RERANKER_FLASHRANK_MODEL` | FlashRank model for fast CPU-based reranking | `ms-marco-MiniLM-L-12-v2` |
| `HINDSIGHT_API_RERANKER_FLASHRANK_CACHE_DIR` | Cache directory for FlashRank models | System default |
```bash
# Local (default) - uses SentenceTransformers CrossEncoder
export HINDSIGHT_API_RERANKER_PROVIDER=local
export HINDSIGHT_API_RERANKER_LOCAL_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
# TEI - for high-performance inference
export HINDSIGHT_API_RERANKER_PROVIDER=tei
export HINDSIGHT_API_RERANKER_TEI_URL=http://localhost:8081
# Cohere - cloud-based reranking
export HINDSIGHT_API_RERANKER_PROVIDER=cohere
export HINDSIGHT_API_COHERE_API_KEY=your-api-key # shared with embeddings
export HINDSIGHT_API_RERANKER_COHERE_MODEL=rerank-english-v3.0
# Azure-hosted Cohere - reranking via custom endpoint
export HINDSIGHT_API_RERANKER_PROVIDER=cohere
export HINDSIGHT_API_COHERE_API_KEY=your-azure-api-key
export HINDSIGHT_API_RERANKER_COHERE_MODEL=rerank-english-v3.0
export HINDSIGHT_API_RERANKER_COHERE_BASE_URL=https://your-azure-cohere-endpoint.com
# LiteLLM proxy - unified gateway for multiple reranking providers
export HINDSIGHT_API_RERANKER_PROVIDER=litellm
export HINDSIGHT_API_LITELLM_API_BASE=http://localhost:4000
export HINDSIGHT_API_LITELLM_API_KEY=your-litellm-key # optional
export HINDSIGHT_API_RERANKER_LITELLM_MODEL=cohere/rerank-english-v3.0 # or voyage/rerank-2, together_ai/...
```
LiteLLM supports multiple reranking providers via the `/rerank` endpoint:
- Cohere (`cohere/rerank-english-v3.0`, `cohere/rerank-multilingual-v3.0`)
- Together AI (`together_ai/...`)
- Voyage AI (`voyage/rerank-2`)
- Jina AI (`jina_ai/...`)
- AWS Bedrock (`bedrock/...`)
### Authentication
By default, Hindsight runs without authentication. For production deployments, enable API key authentication using the built-in tenant extension:
```bash
# Enable the built-in API key authentication
export HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.tenant:ApiKeyTenantExtension
export HINDSIGHT_API_TENANT_API_KEY=your-secret-api-key
```
When enabled, all requests must include the API key in the `Authorization` header:
```bash
curl -H "Authorization: Bearer your-secret-api-key" \
http://localhost:8888/v1/default/banks
```
Requests without a valid API key receive a `401 Unauthorized` response.
:::tip Custom Authentication
For advanced authentication (JWT, OAuth, multi-tenant schemas), implement a custom `TenantExtension`. See the [Extensions documentation](./extensions.md) for details.
:::
### Server
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_HOST` | Bind address | `0.0.0.0` |
| `HINDSIGHT_API_PORT` | Server port | `8888` |
| `HINDSIGHT_API_WORKERS` | Number of uvicorn worker processes | `1` |
| `HINDSIGHT_API_LOG_LEVEL` | Log level: `debug`, `info`, `warning`, `error` | `info` |
| `HINDSIGHT_API_LOG_FORMAT` | Log format: `text` or `json` (structured logging for cloud platforms) | `text` |
| `HINDSIGHT_API_MCP_ENABLED` | Enable MCP server at `/mcp/{bank_id}/` | `true` |
### Retrieval
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_GRAPH_RETRIEVER` | Graph retrieval algorithm: `link_expansion`, `mpfp`, or `bfs` | `link_expansion` |
| `HINDSIGHT_API_RECALL_MAX_CONCURRENT` | Max concurrent recall operations per worker (backpressure) | `32` |
| `HINDSIGHT_API_RECALL_CONNECTION_BUDGET` | Max concurrent DB connections per recall operation | `4` |
| `HINDSIGHT_API_RERANKER_MAX_CANDIDATES` | Max candidates to rerank per recall (RRF pre-filters the rest) | `300` |
| `HINDSIGHT_API_MPFP_TOP_K_NEIGHBORS` | Fan-out limit per node in MPFP graph traversal | `20` |
| `HINDSIGHT_API_MENTAL_MODEL_REFRESH_CONCURRENCY` | Max concurrent mental model refreshes | `8` |
#### Graph Retrieval Algorithms
- **`link_expansion`** (default): Fast, simple graph expansion from semantic seeds via entity co-occurrence and causal links. Target latency under 100ms. Recommended for most use cases.
- **`mpfp`**: Multi-Path Fact Propagation - iterative graph traversal with activation spreading. More thorough but slower.
- **`bfs`**: Breadth-first search from seed facts. Simple but less effective for large graphs.
### Retain
Controls the retain (memory ingestion) pipeline.
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_RETAIN_MAX_COMPLETION_TOKENS` | Max completion tokens for fact extraction LLM calls | `64000` |
| `HINDSIGHT_API_RETAIN_CHUNK_SIZE` | Max characters per chunk for fact extraction. Larger chunks extract fewer LLM calls but may lose context. | `3000` |
| `HINDSIGHT_API_RETAIN_EXTRACTION_MODE` | Fact extraction mode: `concise`, `verbose`, or `custom` | `concise` |
| `HINDSIGHT_API_RETAIN_CUSTOM_INSTRUCTIONS` | Custom extraction guidelines (only used when mode is `custom`) | - |
| `HINDSIGHT_API_RETAIN_EXTRACT_CAUSAL_LINKS` | Extract causal relationships between facts | `true` |
#### Extraction Modes
The extraction mode controls how aggressively facts are extracted from content:
- **`concise`** (default): Selective extraction that focuses on significant, long-term valuable facts. Filters out greetings, filler, and trivial information. Produces fewer but higher-quality facts with better performance.
- **`verbose`**: Detailed extraction that captures every piece of information with maximum verbosity. Produces more facts with extensive detail but slower performance and higher token usage.
- **`custom`**: Inject your own extraction guidelines while keeping the structural parts of the prompt (output format, coreference resolution, temporal handling, etc.) intact. Useful for A/B testing different extraction strategies or domain-specific customization.
**Example: Custom Extraction Mode**
```bash
# Set mode to custom
export HINDSIGHT_API_RETAIN_EXTRACTION_MODE=custom
# Define custom guidelines (multi-line is fine)
export HINDSIGHT_API_RETAIN_CUSTOM_INSTRUCTIONS="ONLY extract facts that are:
✅ Technical decisions and their rationale
✅ Architecture patterns and design choices
✅ Performance metrics and benchmarks
✅ Code reviews and feedback
DO NOT extract:
❌ Generic greetings or pleasantries
❌ Process chatter (\"let me check\", \"one moment\")
❌ Repeated information already captured
CONSOLIDATE related technical discussions into ONE fact when possible.
Ask yourself: 'Would this technical context be useful in 6 months?' If no, skip it."
```
### Observations (Experimental)
Observations are consolidated knowledge synthesized from facts.
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_ENABLE_OBSERVATIONS` | Enable observation consolidation | `true` |
| `HINDSIGHT_API_CONSOLIDATION_BATCH_SIZE` | Memories to load per batch (internal optimization) | `50` |
| `HINDSIGHT_API_RETAIN_OBSERVATIONS_ASYNC` | Run observation generation asynchronously (after retain completes) | `false` |
### Reflect
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_REFLECT_MAX_ITERATIONS` | Max tool call iterations before forcing a response | `10` |
### Local MCP Server
Configuration for the local MCP server (`hindsight-local-mcp` command).
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_MCP_LOCAL_BANK_ID` | Memory bank ID for local MCP | `mcp` |
| `HINDSIGHT_API_MCP_INSTRUCTIONS` | Additional instructions appended to retain/recall tool descriptions | - |
```bash
# Example: instruct MCP to also store assistant actions
export HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take, including tool calls and decisions made."
```
### Distributed Workers
Configuration for background task processing. By default, the API processes tasks internally. For high-throughput deployments, run dedicated workers. See [Services - Worker Service](./services#worker-service) for details.
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_WORKER_ENABLED` | Enable internal worker in API process | `true` |
| `HINDSIGHT_API_WORKER_ID` | Unique worker identifier | hostname |
| `HINDSIGHT_API_WORKER_POLL_INTERVAL_MS` | Database polling interval in milliseconds | `500` |
| `HINDSIGHT_API_WORKER_BATCH_SIZE` | Tasks to claim per poll cycle | `10` |
| `HINDSIGHT_API_WORKER_MAX_RETRIES` | Max retries before marking task failed | `3` |
| `HINDSIGHT_API_WORKER_HTTP_PORT` | HTTP port for worker metrics/health (worker CLI only) | `8889` |
### Performance Optimization
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_API_SKIP_LLM_VERIFICATION` | Skip LLM connection check on startup | `false` |
| `HINDSIGHT_API_LAZY_RERANKER` | Lazy-load reranker model (faster startup) | `false` |
### Programmatic Configuration
You can also configure the API programmatically using `MemoryEngine.from_env()`:
```python
from hindsight_api import MemoryEngine
memory = MemoryEngine.from_env()
await memory.initialize()
```
---
## Control Plane
The Control Plane is the web UI for managing memory banks.
| Variable | Description | Default |
|----------|-------------|---------|
| `HINDSIGHT_CP_DATAPLANE_API_URL` | URL of the API service | `http://localhost:8888` |
```bash
# Point Control Plane to a remote API service
export HINDSIGHT_CP_DATAPLANE_API_URL=http://api.example.com:8888
```
---
## Example .env File
```bash
# API Service
HINDSIGHT_API_DATABASE_URL=postgresql://hindsight:hindsight_dev@localhost:5432/hindsight
HINDSIGHT_API_LLM_PROVIDER=groq
HINDSIGHT_API_LLM_API_KEY=gsk_xxxxxxxxxxxx
# Authentication (optional, recommended for production)
# HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.tenant:ApiKeyTenantExtension
# HINDSIGHT_API_TENANT_API_KEY=your-secret-api-key
# Control Plane
HINDSIGHT_CP_DATAPLANE_API_URL=http://localhost:8888
```
---
For configuration issues not covered here, please [open an issue](https://github.com/vectorize-io/hindsight/issues) on GitHub.

View file

@ -0,0 +1,149 @@
---
sidebar_position: 7
---
# 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
```

View file

@ -0,0 +1,226 @@
# Extensions
Extensions allow you to customize and extend Hindsight behavior without modifying core code. They enable multi-tenancy, custom authentication, additional HTTP endpoints, and operation hooks.
---
## Available Extensions
### TenantExtension
Handles multi-tenancy and API key authentication. Validates incoming requests and determines which PostgreSQL schema to use for database operations, enabling tenant isolation at the database level.
**Built-in: ApiKeyTenantExtension**
A simple implementation that validates API keys against an environment variable and uses the `public` schema for all authenticated requests.
```bash
HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.tenant:ApiKeyTenantExtension
HINDSIGHT_API_TENANT_API_KEY=your-secret-key
```
For multi-tenant setups with separate schemas per tenant (e.g., JWT-based auth with per-tenant schemas), implement a custom `TenantExtension`.
---
### HttpExtension
Adds custom HTTP endpoints under the `/ext/` path prefix. Useful for adding domain-specific APIs that integrate with Hindsight's memory engine.
**No built-in implementation** - implement your own to add custom endpoints.
```bash
HINDSIGHT_API_HTTP_EXTENSION=mypackage.ext:MyHttpExtension
```
---
### OperationValidatorExtension
Hooks into retain/recall/reflect operations for validation and monitoring. Use cases include:
- Rate limiting and quota enforcement
- Permission checks and content filtering
- Audit logging and usage tracking
- Custom metrics collection
**No built-in implementation** - implement your own based on your requirements.
```bash
HINDSIGHT_API_OPERATION_VALIDATOR_EXTENSION=mypackage.validators:MyValidator
```
---
## Writing Custom Extensions
### Extension Basics
Extensions are Python classes loaded via environment variables:
```bash
HINDSIGHT_API_<TYPE>_EXTENSION=mypackage.module:MyExtensionClass
```
Configuration is passed via prefixed environment variables:
```bash
HINDSIGHT_API_<TYPE>_SOME_CONFIG=value
# Extension receives: {"some_config": "value"}
```
All extensions support lifecycle hooks:
- `on_startup()` - Called when the application starts
- `on_shutdown()` - Called when the application shuts down
Extensions have access to an `ExtensionContext` that provides:
- `run_migration(schema)` - Run database migrations for a schema
- `get_memory_engine()` - Get the MemoryEngine interface
### Example: Custom TenantExtension with JWT
```python
import jwt
from hindsight_api.extensions import TenantExtension, TenantContext, AuthenticationError
class JwtTenantExtension(TenantExtension):
def __init__(self, config: dict[str, str]):
super().__init__(config)
self.jwt_secret = config.get("jwt_secret")
if not self.jwt_secret:
raise ValueError("HINDSIGHT_API_TENANT_JWT_SECRET is required")
async def authenticate(self, context: RequestContext) -> TenantContext:
token = context.api_key
if not token:
raise AuthenticationError("Bearer token required")
try:
payload = jwt.decode(token, self.jwt_secret, algorithms=["HS256"])
tenant_id = payload.get("tenant_id")
if not tenant_id:
raise AuthenticationError("Missing tenant_id in token")
return TenantContext(schema_name=f"tenant_{tenant_id}")
except jwt.InvalidTokenError as e:
raise AuthenticationError(str(e))
```
### Example: Custom HttpExtension
```python
from fastapi import APIRouter
from hindsight_api.extensions import HttpExtension
class MyHttpExtension(HttpExtension):
def get_router(self, memory: MemoryEngine) -> APIRouter:
router = APIRouter()
@router.get("/hello")
async def hello():
return {"message": "Hello from extension!"}
@router.post("/custom/{bank_id}/action")
async def custom_action(bank_id: str):
# Access memory engine for database operations
pool = await memory._get_pool()
# ... custom logic
return {"status": "ok"}
return router
```
Routes are available at `/ext/hello`, `/ext/custom/{bank_id}/action`, etc.
### Example: Custom OperationValidatorExtension
```python
from hindsight_api.extensions import (
OperationValidatorExtension,
ValidationResult,
RetainContext,
RecallContext,
ReflectContext,
RetainResult,
)
class MyValidator(OperationValidatorExtension):
# Pre-operation validation (required)
async def validate_retain(self, ctx: RetainContext) -> ValidationResult:
# Implement your validation logic
return ValidationResult.accept()
# Or reject: return ValidationResult.reject("Reason")
async def validate_recall(self, ctx: RecallContext) -> ValidationResult:
return ValidationResult.accept()
async def validate_reflect(self, ctx: ReflectContext) -> ValidationResult:
return ValidationResult.accept()
# Post-operation hooks (optional)
async def on_retain_complete(self, result: RetainResult) -> None:
# Log usage, update metrics, send notifications, etc.
pass
```
---
## Deploying Custom Extensions
### With Docker
Mount your extension package as a volume and set the environment variable:
```yaml
# docker-compose.yml
services:
hindsight-api:
image: vectorize/hindsight-api:latest
volumes:
- ./my_extensions:/app/my_extensions
environment:
- HINDSIGHT_API_TENANT_EXTENSION=my_extensions.auth:JwtTenantExtension
- HINDSIGHT_API_TENANT_JWT_SECRET=${JWT_SECRET}
- PYTHONPATH=/app
```
Or build a custom image with your extensions:
```dockerfile
FROM vectorize/hindsight-api:latest
COPY my_extensions /app/my_extensions
ENV PYTHONPATH=/app
```
### Bare Metal
Install your extension package in the same Python environment as Hindsight:
```bash
# Install Hindsight
pip install hindsight-api
# Install your extension package
pip install ./my-extensions
# or
pip install my-extensions-package
# Configure
export HINDSIGHT_API_TENANT_EXTENSION=my_extensions.auth:JwtTenantExtension
export HINDSIGHT_API_TENANT_JWT_SECRET=your-secret
# Run
hindsight-api
```
---
## Contributing Extensions
Custom extensions that solve common use cases are welcome contributions to the Hindsight project. If you've built an extension for:
- Authentication providers (OAuth, SAML, API gateways)
- Rate limiting or quota management
- Audit logging integrations
- Metrics exporters (Datadog, New Relic, etc.)
- Custom HTTP endpoints for specific platforms
Consider contributing it to the `hindsight_api.extensions.builtin` package. Open an issue or pull request on [GitHub](https://github.com/vectorize-io/hindsight) to discuss your extension.

View file

@ -0,0 +1,138 @@
---
sidebar_position: 1
slug: /
---
# 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 need to consolidate knowledge** — A coding assistant that remembers "the user prefers functional programming" should consolidate this into an observation and weigh it 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 LR
subgraph app["<b>Your Application</b>"]
Agent[AI Agent]
end
subgraph hindsight["<b>Hindsight</b>"]
API[API Server]
subgraph bank["<b>Memory Bank</b>"]
direction TB
MentalModels[Mental Models]
Observations[Observations]
MemEnt[Memories & Entities]
Chunks[Chunks]
Documents[Documents]
MentalModels --> Observations --> MemEnt --> Chunks --> Documents
end
end
Agent -->|retain| API
Agent -->|recall| API
Agent -->|reflect| API
API --> bank
```
**Your AI agent** stores information via `retain()`, searches with `recall()`, and reasons with `reflect()` — all interactions with its dedicated **memory bank**
## Key Components
### Memory Types
Hindsight organizes knowledge into a hierarchy of facts and consolidated knowledge:
| Type | What it stores | Example |
|------|----------------|---------|
| **Mental Model** | User-curated summaries for common queries | "Team communication best practices" |
| **Observation** | Automatically consolidated knowledge from facts | "User was a React enthusiast but has now switched to Vue" (captures history) |
| **World Fact** | Objective facts received | "Alice works at Google" |
| **Experience Fact** | Bank's own actions and interactions | "I recommended Python to Bob" |
During reflect, the agent checks sources in priority order: **Mental Models → Observations → Raw Facts**.
### 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 |
### Observation Consolidation
After memories are retained, Hindsight automatically consolidates related facts into **observations** — synthesized knowledge representations that capture patterns and learnings:
- **Automatic synthesis**: New facts are analyzed and consolidated into existing or new observations
- **Evidence tracking**: Each observation tracks which facts support it
- **Continuous refinement**: Observations evolve as new evidence arrives
### Mission, Directives & Disposition
Memory banks can be configured to shape how the agent reasons during `reflect`:
| Configuration | Purpose | Example |
|---------------|---------|---------|
| **Mission** | Natural language identity for the bank | "I am a research assistant specializing in ML. I prefer simplicity over cutting-edge." |
| **Directives** | Hard rules the agent must follow | "Never recommend specific stocks", "Always cite sources" |
| **Disposition** | Soft traits that influence reasoning style | Skepticism, literalism, empathy (1-5 scale) |
The **mission** tells Hindsight what knowledge to prioritize and provides context for reasoning. **Directives** are guardrails and compliance rules that must never be violated. **Disposition traits** subtly influence interpretation style.
These settings 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 mission, directives, and disposition shape reasoning
### API Methods
- [**Retain**](/developer/api/retain) — Store information in memory banks
- [**Recall**](/developer/api/recall) — Search and retrieve memories
- [**Reflect**](/developer/api/reflect) — Agentic reasoning with memory
- [**Mental Models**](/developer/api/mental-models) — User-curated summaries for common queries
- [**Memory Banks**](/developer/api/memory-banks) — Configure mission, directives, and disposition
- [**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

View file

@ -0,0 +1,184 @@
# Installation
Hindsight can be deployed in several ways depending on your infrastructure and requirements.
:::tip Don't want to manage infrastructure?
**[Hindsight Cloud](https://vectorize.io/hindsight/cloud)** is a fully managed service that handles all infrastructure, scaling, and maintenance. We're onboarding design partners now — [request early access](https://vectorize.io/hindsight/cloud).
:::
## 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
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+
### Distributed Workers
For high-throughput deployments, enable dedicated worker pods to scale task processing independently:
```bash
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
--set worker.enabled=true \
--set worker.replicaCount=3
```
See [Services - Worker Service](./services#worker-service) for configuration details and architecture.
See the [Helm chart values.yaml](https://github.com/vectorize-io/hindsight/tree/main/helm/hindsight/values.yaml) for all chart options.
---
## 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 --log-level debug # Verbose logging
```
### Control Plane
The Control Plane (Web UI) can be run standalone using npx:
```bash
npx @vectorize-io/hindsight-control-plane --api-url http://localhost:8888
```
This connects to your running API server and provides a visual interface for managing memory banks, exploring entities, and testing queries.
#### Options
| Option | Environment Variable | Default | Description |
|--------|---------------------|---------|-------------|
| `-p, --port` | `PORT` | 9999 | Port to listen on |
| `-H, --hostname` | `HOSTNAME` | 0.0.0.0 | Hostname to bind to |
| `-a, --api-url` | `HINDSIGHT_CP_DATAPLANE_API_URL` | http://localhost:8888 | Hindsight API URL |
#### Examples
```bash
# Run on custom port
npx @vectorize-io/hindsight-control-plane --port 9999 --api-url http://localhost:8888
# Using environment variables
export HINDSIGHT_CP_DATAPLANE_API_URL=http://api.example.com
npx @vectorize-io/hindsight-control-plane
# Production deployment
PORT=80 HINDSIGHT_CP_DATAPLANE_API_URL=https://api.hindsight.io npx @vectorize-io/hindsight-control-plane
```
---
## Next Steps
- [Configuration](./configuration.md) — Environment variables and settings
- [Models](./models.md) — ML models and providers
- [Monitoring](./monitoring.md) — Metrics and observability

View file

@ -0,0 +1,129 @@
---
sidebar_position: 5
---
# 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.

View file

@ -0,0 +1,237 @@
# 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, mental model consolidation, and answer synthesis.
**Supported providers:** OpenAI, Anthropic, Gemini, Groq, Ollama, LM Studio, and **any OpenAI-compatible API**
:::tip OpenAI-Compatible Providers
Hindsight works with any provider that exposes an OpenAI-compatible API (e.g., Azure OpenAI). Simply set `HINDSIGHT_API_LLM_PROVIDER=openai` and configure `HINDSIGHT_API_LLM_BASE_URL` to point to your provider's endpoint.
See [Configuration](./configuration#llm-provider) for setup examples.
:::
### Tested Models
The following models have been tested and verified to work correctly with Hindsight:
| Provider | Model |
|----------|-------|
| **OpenAI** | `gpt-5.2` |
| **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` |
| **Anthropic** | `claude-sonnet-4-20250514` |
| **Anthropic** | `claude-3-5-sonnet-20241022` |
| **Gemini** | `gemini-3-pro-preview` |
| **Gemini** | `gemini-2.5-flash` |
| **Gemini** | `gemini-2.5-flash-lite` |
| **Groq** | `openai/gpt-oss-120b` |
| **Groq** | `openai/gpt-oss-20b` |
### 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
# Anthropic
export HINDSIGHT_API_LLM_PROVIDER=anthropic
export HINDSIGHT_API_LLM_API_KEY=sk-ant-xxxxxxxxxxxx
export HINDSIGHT_API_LLM_MODEL=claude-sonnet-4-20250514
# Ollama (local)
export HINDSIGHT_API_LLM_PROVIDER=ollama
export HINDSIGHT_API_LLM_BASE_URL=http://localhost:11434/v1
export HINDSIGHT_API_LLM_MODEL=llama3
# LM Studio (local)
export HINDSIGHT_API_LLM_PROVIDER=lmstudio
export HINDSIGHT_API_LLM_BASE_URL=http://localhost:1234/v1
export HINDSIGHT_API_LLM_MODEL=your-local-model
```
**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)
### Supported Providers
| Provider | Description | Best For |
|----------|-------------|----------|
| `local` | SentenceTransformers (default) | Development, low latency |
| `openai` | OpenAI embeddings API | Production, high quality |
| `cohere` | Cohere embeddings API | Production, multilingual |
| `tei` | HuggingFace Text Embeddings Inference | Production, self-hosted |
| `litellm` | LiteLLM proxy (unified gateway) | Multi-provider setups |
### Local Models
| Model | Dimensions | Use Case |
|-------|------------|----------|
| `BAAI/bge-small-en-v1.5` | 384 | Default, fast, good quality |
| `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` | 384 | Multilingual (50+ languages) |
### OpenAI Models
| Model | Dimensions | Use Case |
|-------|------------|----------|
| `text-embedding-3-small` | 1536 | Default OpenAI, cost-effective |
| `text-embedding-3-large` | 3072 | Higher quality, more expensive |
| `text-embedding-ada-002` | 1536 | Legacy model |
### Cohere Models
| Model | Dimensions | Use Case |
|-------|------------|----------|
| `embed-english-v3.0` | 1024 | English text |
| `embed-multilingual-v3.0` | 1024 | 100+ languages |
:::warning Embedding Dimensions
Hindsight automatically detects the embedding dimension at startup and adjusts the database schema. Once memories are stored, you cannot change dimensions without losing data.
:::
**Configuration Examples:**
```bash
# Local provider (default)
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=local
export HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-small-en-v1.5
# OpenAI
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=openai
export HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY=sk-xxxxxxxxxxxx
export HINDSIGHT_API_EMBEDDINGS_OPENAI_MODEL=text-embedding-3-small
# Cohere
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=cohere
export HINDSIGHT_API_COHERE_API_KEY=your-api-key
export HINDSIGHT_API_EMBEDDINGS_COHERE_MODEL=embed-english-v3.0
# TEI (self-hosted)
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=tei
export HINDSIGHT_API_EMBEDDINGS_TEI_URL=http://localhost:8080
# LiteLLM proxy
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=litellm
export HINDSIGHT_API_LITELLM_API_BASE=http://localhost:4000
export HINDSIGHT_API_EMBEDDINGS_LITELLM_MODEL=text-embedding-3-small
```
See [Configuration](./configuration#embeddings) for all options including Azure OpenAI and custom endpoints.
---
## Cross-Encoder (Reranker)
Reranks initial search results to improve precision.
**Default:** `cross-encoder/ms-marco-MiniLM-L-6-v2` (~85MB)
### Supported Providers
| Provider | Description | Best For |
|----------|-------------|----------|
| `local` | SentenceTransformers CrossEncoder (default) | Development, low latency |
| `cohere` | Cohere rerank API | Production, high quality |
| `tei` | HuggingFace Text Embeddings Inference | Production, self-hosted |
| `flashrank` | FlashRank (lightweight, fast) | Resource-constrained environments |
| `litellm` | LiteLLM proxy (unified gateway) | Multi-provider setups |
| `rrf` | RRF-only (no neural reranking) | Testing, minimal resources |
### Local Models
| 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 |
### Cohere Models
| Model | Use Case |
|-------|----------|
| `rerank-english-v3.0` | English text |
| `rerank-multilingual-v3.0` | 100+ languages |
### LiteLLM Supported Providers
LiteLLM supports multiple reranking providers via the `/rerank` endpoint:
| Provider | Model Example |
|----------|---------------|
| Cohere | `cohere/rerank-english-v3.0` |
| Together AI | `together_ai/...` |
| Voyage AI | `voyage/rerank-2` |
| Jina AI | `jina_ai/...` |
| AWS Bedrock | `bedrock/...` |
**Configuration Examples:**
```bash
# Local provider (default)
export HINDSIGHT_API_RERANKER_PROVIDER=local
export HINDSIGHT_API_RERANKER_LOCAL_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
# Cohere
export HINDSIGHT_API_RERANKER_PROVIDER=cohere
export HINDSIGHT_API_COHERE_API_KEY=your-api-key
export HINDSIGHT_API_RERANKER_COHERE_MODEL=rerank-english-v3.0
# TEI (self-hosted)
export HINDSIGHT_API_RERANKER_PROVIDER=tei
export HINDSIGHT_API_RERANKER_TEI_URL=http://localhost:8081
# FlashRank (lightweight)
export HINDSIGHT_API_RERANKER_PROVIDER=flashrank
# LiteLLM proxy
export HINDSIGHT_API_RERANKER_PROVIDER=litellm
export HINDSIGHT_API_LITELLM_API_BASE=http://localhost:4000
export HINDSIGHT_API_RERANKER_LITELLM_MODEL=cohere/rerank-english-v3.0
# RRF-only (no neural reranking)
export HINDSIGHT_API_RERANKER_PROVIDER=rrf
```
See [Configuration](./configuration#reranker) for all options including Azure-hosted endpoints and batch settings.

View file

@ -0,0 +1,199 @@
# Monitoring
Hindsight provides comprehensive monitoring through Prometheus metrics and pre-built Grafana dashboards.
## Local Development
For local metrics visualization, a convenience script downloads and runs Prometheus and Grafana:
```bash
./scripts/dev/start-monitoring.sh
```
This will start:
- **Grafana**: http://localhost:8890 (anonymous access enabled)
- **Prometheus**: http://localhost:8889
- **API Metrics**: http://localhost:8888/metrics
:::note Production Deployment
The local monitoring script is for development only. In production, you need to install and configure Prometheus and Grafana separately, then point Prometheus to scrape your Hindsight API's `/metrics` endpoint.
:::
## Grafana Dashboards
Pre-built dashboards are available in [`monitoring/grafana/dashboards/`](https://github.com/anthropics/hindsight/tree/main/monitoring/grafana/dashboards). Import these JSON files into your Grafana instance:
| Dashboard | Description |
|-----------|-------------|
| **Hindsight Operations** | Operation rates, latency percentiles, per-bank metrics |
| **Hindsight LLM Metrics** | LLM calls, token usage, latency by scope/provider |
| **Hindsight API Service** | HTTP requests, error rates, DB pool, process metrics |
The dashboards are automatically provisioned when using the monitoring stack script.
## Metrics Endpoint
Hindsight exposes Prometheus metrics at `/metrics`:
```bash
curl http://localhost:8888/metrics
```
## Available Metrics
### Operation Metrics
| Metric | Type | Labels | Description |
|--------|------|--------|-------------|
| `hindsight.operation.duration` | Histogram | operation, bank_id, source, budget, max_tokens, success | Duration of operations in seconds |
| `hindsight.operation.total` | Counter | operation, bank_id, source, budget, max_tokens, success | Total number of operations executed |
**Labels:**
- `operation`: Operation type (`retain`, `recall`, `reflect`)
- `bank_id`: Memory bank identifier
- `source`: Where the operation was triggered from (`api`, `reflect`, `internal`)
- `budget`: Budget level if specified (`low`, `mid`, `high`)
- `max_tokens`: Max tokens if specified
- `success`: Whether the operation succeeded (`true`, `false`)
The `source` label allows distinguishing between:
- `api`: Direct API calls from clients
- `reflect`: Internal recall calls made during reflect operations
- `internal`: Other internal operations
### LLM Metrics
| Metric | Type | Labels | Description |
|--------|------|--------|-------------|
| `hindsight.llm.duration` | Histogram | provider, model, scope, success | Duration of LLM API calls in seconds |
| `hindsight.llm.calls.total` | Counter | provider, model, scope, success | Total number of LLM API calls |
| `hindsight.llm.tokens.input` | Counter | provider, model, scope, success, token_bucket | Input tokens for LLM calls |
| `hindsight.llm.tokens.output` | Counter | provider, model, scope, success, token_bucket | Output tokens from LLM calls |
**Labels:**
- `provider`: LLM provider (`openai`, `anthropic`, `gemini`, `groq`, `ollama`, `lmstudio`)
- `model`: Model name (e.g., `gpt-4`, `claude-3-sonnet`)
- `scope`: What the LLM call is for (`memory`, `reflect`, `consolidation`, `answer`)
- `success`: Whether the call succeeded (`true`, `false`)
- `token_bucket`: Token count bucket for cardinality control (`0-100`, `100-500`, `500-1k`, `1k-5k`, `5k-10k`, `10k-50k`, `50k+`)
### HTTP Request Metrics
| Metric | Type | Labels | Description |
|--------|------|--------|-------------|
| `hindsight.http.duration` | Histogram | method, endpoint, status_code, status_class | Duration of HTTP requests in seconds |
| `hindsight.http.requests.total` | Counter | method, endpoint, status_code, status_class | Total number of HTTP requests |
| `hindsight.http.requests.in_progress` | UpDownCounter | method, endpoint | Number of HTTP requests currently being processed |
**Labels:**
- `method`: HTTP method (`GET`, `POST`, `PUT`, `DELETE`)
- `endpoint`: Request path (normalized to reduce cardinality - UUIDs replaced with `{id}`)
- `status_code`: HTTP status code (`200`, `400`, `500`, etc.)
- `status_class`: Status code class (`2xx`, `4xx`, `5xx`)
### Database Pool Metrics
| Metric | Type | Labels | Description |
|--------|------|--------|-------------|
| `hindsight.db.pool.size` | Gauge | - | Current number of connections in the pool |
| `hindsight.db.pool.idle` | Gauge | - | Number of idle connections in the pool |
| `hindsight.db.pool.min` | Gauge | - | Minimum pool size |
| `hindsight.db.pool.max` | Gauge | - | Maximum pool size |
### Process Metrics
| Metric | Type | Labels | Description |
|--------|------|--------|-------------|
| `hindsight.process.cpu.seconds` | Gauge | type | Process CPU time in seconds |
| `hindsight.process.memory.bytes` | Gauge | type | Process memory usage in bytes |
| `hindsight.process.open_fds` | Gauge | - | Number of open file descriptors |
| `hindsight.process.threads` | Gauge | - | Number of active threads |
**Labels:**
- `type` (CPU): `user` or `system`
- `type` (Memory): `rss_max` (maximum resident set size)
### Histogram Buckets
Custom bucket boundaries are configured for better percentile accuracy:
**Operation Duration Buckets (seconds):**
```
0.1, 0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 5.0, 7.5, 10.0, 15.0, 20.0, 30.0, 60.0, 120.0
```
**LLM Duration Buckets (seconds):**
```
0.1, 0.25, 0.5, 1.0, 2.0, 3.0, 5.0, 10.0, 15.0, 30.0, 60.0, 120.0
```
**HTTP Duration Buckets (seconds):**
```
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0
```
## Prometheus Configuration
```yaml
scrape_configs:
- job_name: 'hindsight'
static_configs:
- targets: ['localhost:8888']
```
## Example Queries
### Average operation latency by type
```promql
rate(hindsight_operation_duration_sum[5m]) / rate(hindsight_operation_duration_count[5m])
```
### LLM calls per minute by provider
```promql
rate(hindsight_llm_calls_total[1m]) * 60
```
### P95 LLM latency
```promql
histogram_quantile(0.95, rate(hindsight_llm_duration_bucket[5m]))
```
### Total tokens consumed by model
```promql
sum by (model) (hindsight_llm_tokens_input_total + hindsight_llm_tokens_output_total)
```
### Internal vs API recall operations
```promql
sum by (source) (rate(hindsight_operation_total{operation="recall"}[5m]))
```
### HTTP requests per second by endpoint
```promql
sum by (endpoint) (rate(hindsight_http_requests_total[1m]))
```
### HTTP error rate (5xx)
```promql
sum(rate(hindsight_http_requests_total{status_class="5xx"}[5m])) / sum(rate(hindsight_http_requests_total[5m]))
```
### P95 HTTP latency
```promql
histogram_quantile(0.95, sum by (le) (rate(hindsight_http_duration_seconds_bucket[5m])))
```
### Database pool utilization
```promql
hindsight_db_pool_size / hindsight_db_pool_max
```
### Active database connections
```promql
hindsight_db_pool_size - hindsight_db_pool_idle
```
### CPU usage rate
```promql
rate(hindsight_process_cpu_seconds{type="user"}[1m])
```

View file

@ -0,0 +1,217 @@
---
sidebar_position: 5
---
# Multilingual Support
Hindsight automatically detects the language of your input and responds in the same language. This means facts, entities, and reflect responses are preserved in their original language without translation to English.
## How It Works
```mermaid
graph LR
A[Chinese Input] --> B[Language Detection]
B --> C[Extract Facts in Chinese]
C --> D[Chinese Entities]
D --> E[Chinese Response]
```
When you retain content or reflect on a query, Hindsight:
1. **Detects the input language** automatically from the content
2. **Extracts facts in the original language** - preserving nuance and meaning
3. **Stores entities in their native script** - 张伟 stays 张伟, not "Zhang Wei"
4. **Responds in the same language** - queries in Chinese get Chinese answers
---
## Retain with Non-English Content
When you retain content in any language, Hindsight extracts and stores facts in that same language.
### Example: Chinese Content
```python
from hindsight import Hindsight
hindsight = Hindsight()
# Retain Chinese content
hindsight.retain(
bank_id="user-123",
content="""
张伟是一位资深软件工程师,在腾讯工作了五年。
他专门研究分布式系统,并领导了公司微服务架构的开发。
""",
context="团队概述"
)
# Query in Chinese - get Chinese results
results = hindsight.recall(
bank_id="user-123",
query="告诉我关于张伟的信息"
)
# Facts are returned in Chinese:
# - 张伟是一位资深软件工程师,在腾讯工作了五年
# - 张伟专门研究分布式系统,并领导了公司微服务架构的开发
```
### Example: Japanese Content
```python
hindsight.retain(
bank_id="user-123",
content="""
田中さんはソフトウェアエンジニアで、東京のスタートアップで働いています。
彼女はPythonとTypeScriptが得意で、毎日コードレビューをしています。
""",
context="チームプロフィール"
)
# Query in Japanese
results = hindsight.recall(
bank_id="user-123",
query="田中さんについて教えてください"
)
```
---
## Reflect with Non-English Queries
The `reflect` operation also respects the input language, generating thoughtful responses in the same language as the query.
### Example: Chinese Reflection
```python
# Store facts about team members (in Chinese)
hindsight.retain(
bank_id="team-eval",
content="张伟是一位优秀的软件工程师,完成了五个重大项目。他总是按时交付,代码整洁有良好的文档。",
context="绩效评估"
)
hindsight.retain(
bank_id="team-eval",
content="李明最近加入团队。他错过了第一个截止日期代码有很多bug。",
context="绩效评估"
)
# Reflect in Chinese
result = hindsight.reflect(
bank_id="team-eval",
query="谁是更可靠的工程师?"
)
# Response is in Chinese:
# "我认为张伟更可靠。张伟完成了五个重大项目,按时交付,代码质量高..."
```
---
## Mixed Language Content
Hindsight handles mixed-language content gracefully, preserving both languages where appropriate.
### Example: Chinese Text with English Company Names
```python
hindsight.retain(
bank_id="user-123",
content="""
王芳在Google北京办公室工作她是一名高级产品经理。
之前她在Microsoft和Amazon工作过。
她负责管理YouTube在中国市场的推广策略。
""",
context="员工资料"
)
# Facts preserve both languages:
# - 王芳在Google北京办公室工作担任高级产品经理
# - 王芳曾在Microsoft和Amazon工作过
# - 王芳负责管理YouTube在中国市场的推广策略
```
---
## Supported Languages
**Hindsight's multilingual support depends entirely on your LLM's language capabilities.** Hindsight instructs the LLM to detect the input language and respond in that same language. If your LLM supports a language, Hindsight will work with it.
Most modern LLMs (GPT-4, Claude, Gemini, Llama 3, etc.) support dozens of languages including:
- **East Asian**: Chinese (Simplified/Traditional), Japanese, Korean
- **European**: Spanish, French, German, Italian, Portuguese, Dutch, Polish, Russian
- **Middle Eastern**: Arabic, Hebrew, Turkish
- **South Asian**: Hindi, Bengali, Tamil
- **Southeast Asian**: Thai, Vietnamese, Indonesian
**To verify support for your target language**, test your LLM directly with content in that language. If the LLM can understand and generate text in the language, Hindsight will preserve it correctly.
---
## Configuring for Multilingual Use
For optimal multilingual performance, you should configure all three components of the pipeline:
### 1. LLM (Required)
Your LLM must support the target languages. Most modern LLMs do, but verify with your specific model.
### 2. Embedding Model (Recommended)
The default embedding model (`BAAI/bge-small-en-v1.5`) is **English-only**. For multilingual content, use a multilingual embedding model:
```bash
# In your .env file
HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL=BAAI/bge-m3
```
**Recommended multilingual embedding models:**
| Model | Languages | Notes |
|-------|-----------|-------|
| `BAAI/bge-m3` | 100+ | Best overall multilingual performance |
| `intfloat/multilingual-e5-large` | 100+ | Good alternative |
| `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` | 50+ | Lighter weight |
### 3. Reranker Model (Recommended)
The default reranker (`cross-encoder/ms-marco-MiniLM-L-6-v2`) is **English-only**. For multilingual content, use a multilingual reranker:
```bash
# In your .env file
HINDSIGHT_API_RERANKER_LOCAL_MODEL=BAAI/bge-reranker-v2-m3
```
**Recommended multilingual reranker models:**
| Model | Languages | Notes |
|-------|-----------|-------|
| `BAAI/bge-reranker-v2-m3` | 100+ | Best multilingual reranking |
| `cross-encoder/mmarco-mMiniLMv2-L12-H384-v1` | 14 | Lighter alternative |
---
## Best Practices
### 1. Use Multilingual Models for Non-English Content
If you primarily work with non-English content, configure multilingual embedding and reranker models. English-only models will still store your content correctly, but semantic search quality will be degraded.
### 2. Keep Content in One Language Per Retain Call
While mixed content works, keeping each `retain` call in a single language produces more consistent results.
### 3. Query in the Same Language as Your Content
For best results, query using the same language as your stored content. Cross-language queries (e.g., English query for Chinese content) may work but results can vary depending on your embedding model.
---
## Technical Details
Multilingual support is implemented through LLM prompt instructions rather than external language detection libraries. This approach:
- **Requires no additional dependencies**
- **Works with any LLM** that supports multiple languages
- **Handles edge cases** like mixed-language content naturally
- **Preserves semantic meaning** better than rule-based translation
The LLM is instructed to:
1. Detect the input language
2. Extract all facts, entities, and descriptions in that same language
3. Never translate to English unless the input is in English

View file

@ -0,0 +1,168 @@
---
sidebar_position: 5
---
import CodeSnippet from '@site/src/components/CodeSnippet';
import recallPy from '!!raw-loader!@site/examples/api/recall.py';
import memoryBanksPy from '!!raw-loader!@site/examples/api/memory-banks.py';
# Observations: Knowledge Consolidation
After memories are retained, Hindsight automatically consolidates related facts into **observations** — synthesized knowledge representations that capture patterns and learnings.
```mermaid
graph LR
A[New Facts] --> B[Consolidation Engine]
B --> C{Existing Observation?}
C -->|Yes| D[Refine Observation]
C -->|No| E[Create Observation]
D --> F[Observations]
E --> F
```
---
## What Are Observations?
Observations are **consolidated knowledge** synthesized from multiple facts. Unlike raw facts which are individual pieces of information, observations represent patterns, preferences, and learnings that emerge from accumulated evidence.
| Raw Facts | Observation |
|-----------|--------------|
| "Alice prefers Python" | "Alice is a Python-focused developer who values readability and simplicity" |
| "Alice dislikes verbose code" | |
| "Alice recommends type hints" | |
Observations provide:
- **Synthesis**: Patterns that emerge from multiple facts
- **Context**: Richer understanding than individual facts
- **Efficiency**: Condensed knowledge for faster retrieval
---
## How Consolidation Works
### Automatic Background Processing
After `retain()` completes, the consolidation engine runs automatically:
1. **New facts analyzed** — Each new fact is compared against existing observations
2. **Pattern detection** — Related facts are grouped and synthesized
3. **Observation creation/update** — New observations are created or existing ones refined
4. **Evidence tracking** — Each observation maintains references to supporting facts
### Evidence-Based Evolution
Observations evolve as new evidence arrives:
| Event | What the bank learns | Observation state |
|-------|---------------------|----------------|
| **Day 1** | "Redis is open source under BSD license" | "Redis is excellent for caching — fast, reliable, and OSS-friendly" (2 supporting facts) |
| **Day 2** | "Redis has great community support" | Observation reinforced (3 supporting facts) |
| **Day 30** | "Redis changed license to SSPL" | Observation refined: "Redis is technically strong, but has license concerns for cloud" |
| **Day 45** | "Valkey forked Redis under BSD" | New observation: "Consider Valkey for new projects requiring true OSS" |
### Handling Contradictory Evidence
What happens when a new fact contradicts an existing observation?
The consolidation engine doesn't blindly overwrite — it **reconciles** the contradiction by capturing the evolution:
**Example: User preference changes**
| Time | Fact | Observation |
|------|------|--------------|
| Week 1 | "User says they love React" | "User prefers React for frontend development" |
| Week 2 | "User praises React's component model" | "User is enthusiastic about React, particularly its component model" |
| Week 3 | "User says they've switched to Vue and won't use React anymore" | "User was previously a React enthusiast who appreciated its component model, but has now switched to Vue and no longer uses React" |
Notice how the final observation captures the **full journey** — not just "User prefers Vue" but the complete evolution of their preference. This nuanced understanding means:
- Your agent won't recommend React tutorials to someone who explicitly moved away from it
- Your agent understands *why* this matters (they were enthusiastic before, so this is a deliberate choice)
- Your agent can reference this history when relevant ("I know you used to work with React...")
The system:
1. **Detects the conflict** — New fact contradicts existing observation
2. **Preserves history** — Incorporates the previous understanding into the new observation
3. **Creates nuanced observation** — Synthesizes a richer understanding that captures the change
4. **Updates freshness** — Marks the observation as recently updated
**Example: Correcting misinformation**
| Time | Fact | Observation |
|------|------|--------------|
| Day 1 | "Alice works at Google" | "Alice is a Google employee" |
| Day 10 | "Alice actually works at Meta, not Google" | "Alice works at Meta (previously thought to work at Google)" |
When a fact explicitly corrects previous information, the observation is updated to reflect the correction while noting the previous understanding. The raw facts are always preserved, so you can trace back to see what was originally stated and when it was corrected.
---
## Observations in Retrieval
Observations are automatically included in both `recall()` and `reflect()` operations:
### In Recall
Observations are returned alongside raw facts, filtered by the `types` parameter:
<CodeSnippet code={recallPy} section="recall-with-observations" language="python" />
### In Reflect
The reflect agent uses **hierarchical retrieval**:
1. **[Mental Models](/developer/api/mental-models)** — User-curated summaries (highest priority)
2. **Observations** — Consolidated knowledge with freshness awareness
3. **Raw Facts** — Ground truth for verification
The agent automatically queries observations and uses them to inform its reasoning.
---
## Freshness Awareness
Observations track when they were last updated. During reflect, the agent considers freshness:
- **Fresh observations**: Used directly for reasoning
- **Stale observations**: Agent verifies against current facts before relying on them
This ensures responses stay accurate even as the underlying data changes.
---
## Mission-Oriented Consolidation
The bank's **mission** directly influences what knowledge gets consolidated into observations. When you set a mission on your memory bank, the consolidation engine focuses on extracting knowledge that serves that mission.
**Example:**
<CodeSnippet code={memoryBanksPy} section="bank-support-agent" language="python" />
With this mission, the consolidation engine will:
- **Prioritize** customer preferences, issue patterns, and communication styles
- **Skip** ephemeral details that don't serve support goals
- **Synthesize** observations focused on helping customers
Without a mission, the engine performs general-purpose consolidation. With a mission, it becomes focused and efficient — extracting only knowledge that matters for your use case.
| Mission | Observations Focus |
|---------|-------------------|
| *Customer support agent* | Customer preferences, issue patterns, resolution history |
| *Code review assistant* | Coding patterns, team conventions, common mistakes |
| *Research assistant* | Topic expertise, source reliability, methodology preferences |
---
## Configuration
Observation consolidation runs automatically. You can monitor consolidation via the [Operations API](./api/operations).
---
## Next Steps
- [**Retain**](./retain) — How facts are stored and trigger consolidation
- [**Recall**](./retrieval) — How observations are retrieved
- [**Reflect**](./reflect) — How the agentic loop uses observations
- [**Mental Models**](./api/mental-models) — User-curated summaries for common queries

View file

@ -0,0 +1,133 @@
# 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 | Re-ranker (on CPU) | Use GPU for re-ranking, or reduce budget |
| **Reflect** | 800-3000ms | LLM generation | 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)
- **Slow**: 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
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 | Use Case |
|--------|----------|
| `low` | Quick lookups, real-time chat |
| `mid` | Standard queries, balanced performance |
| `high` | Comprehensive questions, thorough analysis |
### 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 chunks**: Use `include_chunks` to retrieve the raw text that generated memories when you need additional context
### 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 | 100-600ms | Based on budget (low/mid/high) |
| LLM generation | 500-2000ms | Depends on provider and response length |
| **Total** | **600-2600ms** | 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 recall requirements and steer towards more focused answers
## 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`

View file

@ -0,0 +1,110 @@
---
sidebar_position: 2
---
# 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, co-occurrence tracking |
| **Knowledge consolidation** | Stateless | Mental models that synthesize and 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 connected facts via entity graph: subscription status, billing, known issues |
### Knowledge 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 | Consolidates mental model "user prefers sync" → refines to "user growing comfortable with async" |
## 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 |

View file

@ -0,0 +1,240 @@
---
sidebar_position: 4
---
import CodeSnippet from '@site/src/components/CodeSnippet';
import memoryBanksPy from '!!raw-loader!@site/examples/api/memory-banks.py';
# Reflect: Agentic Reasoning with Disposition
When you call `reflect()`, Hindsight runs an **agentic loop** that autonomously gathers evidence and reasons through the lens of the bank's disposition to generate contextual responses.
```mermaid
graph TB
subgraph agent["Reflect Agent Loop"]
A[Query] --> B{Need more info?}
B -->|Yes| C[Call Tools]
C --> D[search_mental_models]
C --> E[search_observations]
C --> F[recall]
C --> G[expand]
D --> B
E --> B
F --> B
G --> B
B -->|No| H[Generate Response]
end
H --> I[Response + Citations]
```
---
## How It Works
Unlike simple retrieval, reflect is an **agentic system** that:
1. **Autonomously gathers evidence** — The agent decides what information it needs and calls appropriate tools
2. **Uses hierarchical retrieval** — Checks mental models first, then observations, then raw facts
3. **Applies disposition** — Shapes reasoning based on the bank's personality traits
4. **Enforces directives** — Hard rules that must be followed in all responses
5. **Cites sources** — Returns which memories and observations were used
### The Agentic Loop
The reflect agent runs in a loop with access to these tools:
| Tool | Purpose | Priority |
|------|---------|----------|
| `search_mental_models` | User-curated summaries | Highest (check first) |
| `search_observations` | Consolidated knowledge | High |
| `recall` | Raw facts (ground truth) | Fallback |
| `expand` | Get more context for a memory | As needed |
| `done` | Complete with final answer | When ready |
The agent:
- **Must gather evidence** before answering (guardrail prevents empty responses)
- **Runs up to 10 iterations** to find relevant information
- **Validates citations** — only IDs that were actually retrieved can be cited
### Hierarchical Retrieval Strategy
The agent uses a smart retrieval hierarchy:
1. **[Mental Models](/developer/api/mental-models)** — User-curated summaries you've pre-computed for common queries
2. **[Observations](/developer/observations)** — Consolidated knowledge with freshness awareness
3. **Raw Facts** — Ground truth for verification when observations are stale
**Mental models** are saved reflect responses that you create for frequently asked questions. They're checked first because they represent explicitly curated knowledge. See the [Mental Models API](/developer/api/mental-models) for how to create and manage them.
If an observation is marked as **stale**, the agent automatically verifies it against current facts.
---
## Why Reflect?
Most AI systems can retrieve facts, but they can't **reason** about them in a consistent way.
### The Problem
Without reflect:
- **No consistent character**: Same question gets different answers each time
- **No knowledge synthesis**: System never connects related facts
- **No reasoning context**: Responses don't reflect accumulated knowledge
- **Generic responses**: Every AI sounds the same
### The Value
With reflect:
- **Consistent character**: A "detail-oriented, cautious" bank emphasizes risks and thorough planning
- **Evolving knowledge**: Observations strengthen and adapt as evidence accumulates
- **Contextual reasoning**: "Based on what I know about your team's remote work success..."
- **Differentiated behavior**: Support bots sound diplomatic, code reviewers sound direct
### 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 |
**Example:**
- `recall("Alice")` → Returns all Alice facts and relevant mental models
- `reflect("Should we hire Alice?")` → Agent gathers evidence about Alice, reasons about fit, returns answer with citations
---
## 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 reasons 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 |
### Mission: Natural Language Identity
Beyond numeric traits, you can provide a natural language **mission** that describes the bank's identity:
<CodeSnippet code={memoryBanksPy} section="bank-with-disposition" language="python" />
The mission tells Hindsight what knowledge to prioritize and shapes how disposition traits are applied:
- "keep track of system designs" → focuses consolidation on architectural decisions
- "prefer simplicity over cutting-edge" + high skepticism → questions complex solutions
- Explicit guidance → consistent memory focus across conversations
---
## Disposition Shapes Reasoning
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.
---
## 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 |
---
## Directives: Hard Rules
While disposition traits *influence* reasoning style, **directives** are hard rules that the agent *must* follow. Directives are injected into the prompt and enforced in every response.
### When to Use Directives
Use directives for constraints that must never be violated:
- **Compliance rules**: "Never recommend specific stocks or financial products"
- **Privacy constraints**: "Never share personal data with third parties"
- **Style requirements**: "Always respond in formal English"
- **Domain guardrails**: "Always cite sources when making factual claims"
### Directives vs Disposition
| Aspect | Disposition | Directives |
|--------|-------------|------------|
| **Nature** | Soft influence | Hard rules |
| **Effect** | Shapes interpretation and tone | Must be followed exactly |
| **Violation** | Acceptable (it's a tendency) | Not acceptable |
| **Example** | High skepticism → questions claims | "Never make medical diagnoses" |
:::tip
Use disposition for personality and character. Use directives for compliance and guardrails.
:::
See [Memory Banks: Directives](/developer/api/memory-banks#directives) for how to create and manage directives.
---
## What You Get from Reflect
When you call `reflect()`:
**Returns:**
- **Response text** — Disposition-influenced answer from the agent
- **based_on** — Evidence used: memories, mental models, and directives that grounded the response
- **trace** — Tool calls, LLM calls, and observations accessed (when `include.tool_calls=True`)
- **structured_output** — Parsed response if `response_schema` was provided
- **usage** — Token usage metrics
**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": {
"memories": [
{"id": "mem-123", "text": "Alice has 5 years of ML experience", "type": "world"},
{"id": "mem-456", "text": "Alice worked at Google on search ranking", "type": "experience"}
],
"mental_models": [],
"directives": [
{"id": "dir-001", "name": "Formal Language", "rules": ["Always respond in formal English"]}
]
},
"usage": {"input_tokens": 1500, "output_tokens": 500, "total_tokens": 2000}
}
```
The agent automatically gathers evidence, validates citations, and generates a grounded response.
---
## 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 observations **evolve with evidence**.
---
## Next Steps
- [**Observations**](./observations) — How knowledge is consolidated
- [**Retain**](./retain) — How rich facts are stored
- [**Recall**](./retrieval) — How multi-strategy search works
- [**Reflect API**](./api/reflect) — Code examples and parameters

View file

@ -0,0 +1,199 @@
---
sidebar_position: 2
---
# 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" |
**Note:** Observations are consolidated automatically in the background after `retain()` operations complete. This consolidation process synthesizes patterns from new facts into the bank's knowledge base.
---
## 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.
---
## Tagging Memories
Tags enable visibility scoping—useful when one memory bank serves multiple users but each should only see relevant memories.
- **Item tags**: Tag individual memories with specific scopes
- **Document tags**: Apply tags to all items in a batch
- **Tag filtering**: Filter during recall/reflect by tags
See [Retain API](./api/retain) for code examples and [Recall API](./api/recall) for filtering options.
---
## 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
- **Optional tags** for filtering during recall
All stored in your isolated **memory bank**, ready for `recall()` and `reflect()`.
---
## Observation Consolidation
After `retain()` completes, Hindsight automatically triggers **observation consolidation** in the background. This process:
1. Analyzes new facts against existing observations
2. Creates new observations when patterns emerge
3. Refines existing observations with new evidence
4. Tracks which facts support each observation
This happens asynchronously — your `retain()` call returns immediately while consolidation runs in the background.
See [Observations](./observations) for details on how consolidation works.
---
## Next Steps
- [**Observations**](./observations) — How knowledge is consolidated after retain
- [**Recall**](./retrieval) — How multi-strategy search retrieves relevant memories
- [**Reflect**](./reflect) — How the agentic loop uses observations
- [**Retain API**](./api/retain) — Code examples and parameters

View file

@ -0,0 +1,226 @@
---
sidebar_position: 3
---
# 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.
---
## Why Multiple Strategies?
Consider the query: **"What did Alice say about Python last spring?"**
- **Semantic** finds facts about Alice's views on programming
- **Keyword** ensures "Python" is actually mentioned
- **Graph** connects Alice → programming languages → related entities
- **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.
---
## 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`: Search depth level (low, mid, high)
- `types`: Filter by world, experience, observation, or all
- `tags`: Filter memories by visibility tags
- `tags_match`: How to match tags (see [Recall API](./api/recall) for all options)
### Expanding Context: Chunks
Memories are distilled facts—concise but sometimes missing nuance. When your agent needs deeper context, you can optionally retrieve the source material:
**Chunks** return the raw text that generated each memory—useful when the distilled fact loses important nuance:
```
Memory: "Alice prefers Python over JavaScript"
Chunk: "Alice mentioned she prefers Python over JavaScript, mainly because
of its data science ecosystem, though she admits JS is better for
frontend work and she's been learning TypeScript lately."
```
Use `include_chunks=True` with `max_chunk_tokens` to control the token budget for chunks. This is useful when generating responses that need verbatim quotes or when context matters (e.g., "What exactly did Alice say about the project?").
---
## Tuning Recall: Quality vs Latency
Different use cases require different trade-offs between **recall quality** and **response speed**. Two parameters control this:
### Budget: Search Depth
Controls how thoroughly Hindsight explores the memory bank—affecting graph traversal depth, candidate pool size, and cross-encoder re-ranking:
| Budget | Best For | Trade-off |
|--------|----------|-----------|
| **low** | Quick lookups, simple queries | Fast, may miss indirect connections |
| **mid** | Most queries, balanced | Good coverage, reasonable speed |
| **high** | Complex queries requiring deep exploration | Thorough, slower |
**Example:** "What did Alice's manager's team work on?" benefits from high budget to traverse multiple hops (Alice → manager → team → projects) and evaluate more candidates.
### 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 thoroughly to explore memories | 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 |
---
## Graph Retrieval Algorithms
Hindsight supports multiple graph traversal algorithms. The default (`link_expansion`) is optimized for fast retrieval with target latency under 100ms.
See [Configuration → Retrieval](./configuration#retrieval) for available algorithms and how to configure them.
---
## Next Steps
- [**Retain**](./retain) — How memories are stored with rich context
- [**Reflect**](./reflect) — How disposition influences reasoning
- [**Recall API**](./api/recall) — Code examples, parameters, and tag filtering

View file

@ -0,0 +1,66 @@
# Services
Hindsight consists of three services that can run together or separately depending on your deployment needs.
## API Service
The core memory engine. Handles all memory operations:
- **Retain**: Ingests content, extracts facts, builds knowledge graph
- **Recall**: Semantic search across memories
- **Reflect**: Disposition-aware answer generation
```bash
hindsight-api # Default port: 8888
```
The API service is stateless and can be horizontally scaled behind a load balancer. All state is stored in PostgreSQL.
By default, the API also processes background tasks (mental model consolidation) internally. For high-throughput deployments, you can disable this and run dedicated workers instead.
## Worker Service
Dedicated task processor for background operations. Uses the **same package and Docker image** as the API service, just with a different entry point.
```bash
hindsight-worker # Default metrics port: 8889
```
Workers use PostgreSQL as a task broker, polling for pending tasks. Multiple workers can run simultaneously without conflicts.
| Deployment | Internal Worker | Dedicated Workers |
|------------|-----------------|-------------------|
| **Development** | ✅ Simple, all-in-one | ❌ Overkill |
| **Small production** | ✅ Less infrastructure | ❌ Overkill |
| **High throughput** | ❌ API bottleneck | ✅ Scale independently |
| **Long-running tasks** | ❌ Blocks API resources | ✅ Isolated processing |
To use dedicated workers, disable the internal worker in the API and start worker processes:
```bash
# Disable internal worker in API
HINDSIGHT_API_WORKER_ENABLED=false hindsight-api
# Start dedicated workers (run multiple instances)
hindsight-worker --worker-id worker-1
hindsight-worker --worker-id worker-2
```
Each worker exposes `/health` and `/metrics` endpoints for monitoring.
Before scaling down or removing workers, release their tasks with `hindsight-admin decommission-worker <worker-id>`.
See [Configuration - Distributed Workers](./configuration#distributed-workers) for all worker settings and [Installation - Helm](./installation#distributed-workers) for Kubernetes deployment.
## Control Plane
Web UI for managing and exploring your memory banks:
- Browse agents and memory banks
- Explore entities and relationships
- View ingestion history and operations
- Test recall queries interactively
The Control Plane connects to the API service and provides a visual interface for development and debugging.
For bare metal deployments, you can run the Control Plane standalone using npx. See [Installation - Bare Metal](./installation#control-plane) for details.

View file

@ -0,0 +1,79 @@
# 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. Starts an embedded PostgreSQL instance on port 5555
2. Initializes the schema
3. 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

View file

@ -0,0 +1,244 @@
---
sidebar_position: 3
---
# CLI Reference
The Hindsight CLI provides command-line access to memory operations and bank management. All commands follow the [OpenAPI specification](/api-reference), so you can use `--help` on any command to see all available options.
## 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
# With API key for authentication
hindsight configure --api-url http://localhost:8888 --api-key your-api-key
# Or use environment variables (highest priority)
export HINDSIGHT_API_URL=http://localhost:8888
export HINDSIGHT_API_KEY=your-api-key
```
## Core Commands
### Retain (Store Memory)
Store a single memory:
```bash
hindsight memory retain <bank_id> "Alice works at Google as a software engineer"
# With context
hindsight memory retain <bank_id> "Bob loves hiking" --context "hobby discussion"
# Queue for background processing
hindsight memory retain <bank_id> "Meeting notes" --async
```
### Retain Files
Bulk import from files:
```bash
# Single file
hindsight memory retain-files <bank_id> notes.txt
# Directory (recursive by default)
hindsight memory retain-files <bank_id> ./documents/
# With context
hindsight memory retain-files <bank_id> meeting-notes.txt --context "team meeting"
# Background processing
hindsight memory retain-files <bank_id> ./data/ --async
```
### Recall (Search)
Search memories using semantic similarity:
```bash
hindsight memory recall <bank_id> "What does Alice do?"
# With options
hindsight memory recall <bank_id> "hiking recommendations" \
--budget high \
--max-tokens 8192
# Filter by fact type
hindsight memory recall <bank_id> "query" --fact-type world,observation
# Show trace information
hindsight memory recall <bank_id> "query" --trace
```
### Reflect (Generate Response)
Generate a response using memories and bank disposition:
```bash
hindsight memory reflect <bank_id> "What do you know about Alice?"
# With additional context
hindsight memory reflect <bank_id> "Should I learn Python?" --context "career advice"
# Higher budget for complex questions
hindsight memory reflect <bank_id> "Summarize my week" --budget high
```
## Bank Management
### List Banks
```bash
hindsight bank list
```
### View Disposition
```bash
hindsight bank disposition <bank_id>
```
### View Statistics
```bash
hindsight bank stats <bank_id>
```
### Set Bank Name
```bash
hindsight bank name <bank_id> "My Assistant"
```
### Set Mission
```bash
hindsight bank mission <bank_id> "I am a helpful AI assistant interested in technology"
```
## Document Management
```bash
# List documents
hindsight document list <bank_id>
# Get document details
hindsight document get <bank_id> <document_id>
# Delete document and its memories
hindsight document delete <bank_id> <document_id>
```
## Entity Management
```bash
# List entities
hindsight entity list <bank_id>
# Get entity details
hindsight entity get <bank_id> <entity_id>
```
## Output Formats
```bash
# Pretty (default)
hindsight memory recall <bank_id> "query"
# JSON
hindsight memory recall <bank_id> "query" -o json
# YAML
hindsight memory recall <bank_id> "query" -o yaml
```
## Global Options
| Flag | Description |
|------|-------------|
| `-v, --verbose` | Show detailed output including request/response |
| `-o, --output <format>` | Output format: pretty, json, yaml |
| `--help` | Show help |
| `--version` | Show version |
## Control Plane UI
Launch the web-based Control Plane UI directly from the CLI:
```bash
hindsight ui
```
This runs the Control Plane locally on port 9999 using the API URL from your configuration. The UI provides:
- **Memory bank management** — Browse and manage all your banks
- **Entity explorer** — Visualize the knowledge graph
- **Query testing** — Interactive recall and reflect testing
- **Operation history** — View ingestion and processing logs
:::tip
The UI command requires Node.js to be installed. It automatically downloads and runs the `@vectorize-io/hindsight-control-plane` package via npx.
:::
## 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 observations
- **Navigate documents** — See source documents and their extracted memories
### Keyboard Shortcuts
| Key | Action |
|-----|--------|
| `↑/↓` | Navigate items |
| `Enter` | Select / Expand |
| `Tab` | Switch panels |
| `/` | Search |
| `q` | Quit |
<!-- Screenshot placeholder: explore command TUI -->
## 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 disposition
hindsight bank disposition demo
```

View file

@ -0,0 +1,345 @@
---
sidebar_position: 1
---
# 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
import hindsight_litellm
# 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
mission="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 `mission` 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",
mission="""You're a customer support router - keep track of which types of issues
should go to which teams (billing, technical, sales), 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. [MENTAL MODEL] User prefers simple code..."
# 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
import hindsight_litellm
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
import litellm
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

View file

@ -0,0 +1,193 @@
---
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 Desktop** — Give Claude long-term memory across conversations
- **Development and testing** — Quick setup without infrastructure
- **Privacy-focused setups** — All data stays on your machine
## Quick Install
```bash
curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- \
--app claude-desktop \
--set HINDSIGHT_API_LLM_API_KEY=sk-...
```
This script will:
1. Install [uv](https://docs.astral.sh/uv/) if not already installed
2. Configure Claude Desktop to use the Hindsight MCP server
3. Set the provided environment variables in the MCP configuration
:::info Other MCP Applications
The quick install script currently supports Claude Desktop only. For other MCP-compatible applications (Cursor, Cline, etc.), follow the [Manual Configuration](#manual-configuration) steps below.
:::
## Manual Configuration
Add the following to your MCP client's configuration. For Claude Desktop:
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
For other MCP clients, refer to their documentation for the configuration file location.
```json
{
"mcpServers": {
"hindsight": {
"command": "uvx",
"args": ["--from", "hindsight-api", "hindsight-local-mcp"],
"env": {
"HINDSIGHT_API_LLM_API_KEY": "sk-..."
}
}
}
}
```
### 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": ["--from", "hindsight-api", "hindsight-local-mcp"],
"env": {
"HINDSIGHT_API_LLM_API_KEY": "sk-...",
"HINDSIGHT_API_MCP_LOCAL_BANK_ID": "my-personal-memory"
}
}
}
}
```
## Environment Variables
All standard [Hindsight configuration variables](/developer/configuration) are supported.
### Local MCP Specific
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `HINDSIGHT_API_MCP_LOCAL_BANK_ID` | No | `mcp` | Memory bank ID to use |
| `HINDSIGHT_API_MCP_INSTRUCTIONS` | No | - | Additional instructions appended to both `retain` and `recall` tools |
### Customizing Tool Behavior
You can customize what gets stored by adding instructions to the tools. Re-run the install script with the additional `--set` flag:
```bash
curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- \
--app claude-desktop \
--set HINDSIGHT_API_LLM_API_KEY=sk-... \
--set HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take, code you write, and files you modify."
```
These instructions are appended to the default tool descriptions, guiding Claude on when and how to use the memory tools.
## 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"
}
}
```
## 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.
## 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.

View file

@ -0,0 +1,323 @@
---
sidebar_position: 3
---
# Skills
Hindsight provides an Agent Skill that gives AI coding assistants persistent memory across sessions. Skills are reusable prompt templates that agents can load when needed to gain specialized capabilities.
## Supported Platforms
| Platform | Skills Directory |
|----------|-----------------|
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `~/.claude/skills/` |
| [OpenCode](https://github.com/opencode-ai/opencode) | `~/.opencode/skills/` |
| [Codex CLI](https://github.com/openai/codex) | `~/.codex/skills/` |
## Deployment Modes
The skill supports two deployment modes:
| Mode | Best For | Data Location |
|------|----------|---------------|
| **Local** | Individual developers | Your machine (`~/.pg0/`) |
| **Cloud** | Teams sharing knowledge | Hindsight Cloud |
## Quick Install
### Option 1: Interactive Installer (Recommended)
```bash
curl -fsSL https://hindsight.vectorize.io/get-skill | bash
```
The installer will:
1. Prompt you to select your AI coding assistant
2. Select deployment mode (local or cloud)
3. Configure the appropriate settings
4. Install the skill to the appropriate directory
### Install for a Specific Platform
```bash
# Claude Code (interactive mode selection)
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude
# OpenCode
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app opencode
# Codex CLI
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app codex
```
### Install with Cloud Mode
```bash
# Direct cloud setup (skips interactive prompts for mode)
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude --mode cloud
```
### Option 2: Using add-skill
If you use [add-skill](https://add-skill.org/) to manage your agent skills:
```bash
# For local mode (individual developers)
npx add-skill vectorize-io/hindsight --skill hindsight-local
# For Hindsight Cloud (teams)
npx add-skill vectorize-io/hindsight --skill hindsight-cloud
# For self-hosted Hindsight servers
npx add-skill vectorize-io/hindsight --skill hindsight-self-hosted
```
On first use, the AI will guide you through the remaining setup:
- **Local**: Run `uvx hindsight-embed configure` to set up your LLM provider
- **Cloud**: Provide your API key and bank ID
- **Self-hosted**: Provide your server URL, API key, and bank ID
## What the Skill Provides
Once installed, your AI assistant gains the ability to:
- **Retain** - Store user preferences, learnings, and procedure outcomes
- **Recall** - Search for relevant context before starting tasks
- **Reflect** - Synthesize memories into contextual answers
The skill uses the `hindsight-embed` CLI which runs a lightweight local daemon with an embedded database.
## How Skills Work
Skills are **model-invoked**, meaning the AI assistant automatically decides when to use them based on the context of your conversation. You don't need to explicitly trigger the skill.
The assistant will:
- **Store** when you share preferences, when tasks succeed/fail, or when learnings emerge
- **Recall** before starting non-trivial tasks to get relevant context
### What Gets Stored
The skill is optimized to store:
| Category | Examples |
|----------|----------|
| **User Preferences** | Coding style, tool preferences, language choices |
| **Procedure Outcomes** | Commands that worked, configurations that resolved issues |
| **Learnings** | Bug solutions, workarounds, architecture decisions |
## Architecture
### Local Mode
```
AI Coding Assistant
Hindsight Skill (SKILL.md)
hindsight-embed CLI
Local Daemon (auto-started)
Embedded PostgreSQL (~/.pg0/hindsight-embed/)
```
All data stays on your machine. The daemon auto-starts when needed and shuts down after inactivity.
### Cloud Mode
```
AI Coding Assistant
Hindsight Skill (SKILL.md)
hindsight-cli
Hindsight Cloud API (https://api.hindsight.vectorize.io)
Shared Memory Bank (team-accessible)
```
Data is stored in Hindsight Cloud and shared across your team. All team members with the same bank ID can access shared memories.
---
## Local Mode Setup
The skill uses configuration stored in `~/.hindsight/config.env`. Reconfigure anytime:
```bash
uvx hindsight-embed configure
```
---
## Cloud Mode Setup
Cloud mode connects to [Hindsight Cloud](https://vectorize.io/hindsight/cloud), allowing teams to share memories about a codebase. When one team member learns something, everyone benefits.
### Prerequisites
1. A Hindsight Cloud account ([request access](https://vectorize.io/hindsight/cloud))
2. An API key from your team admin
3. A bank ID for your project (e.g., `team-acme-frontend`)
### Installation
Run the installer with cloud mode:
```bash
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
```
You'll be prompted for:
| Setting | Description | Example |
|---------|-------------|---------|
| **Cloud API URL** | Hindsight Cloud endpoint | `https://api.hindsight.vectorize.io` |
| **API Key** | Your authentication key | `hs_xxx...` |
| **Bank ID** | Shared memory bank for your team | `team-acme-frontend` |
### Configuration Files
Cloud mode creates two files:
**`~/.hindsight/config`** — API connection settings (TOML format):
```toml
api_url = "https://api.hindsight.vectorize.io"
api_key = "hs_xxx..."
```
**`~/.claude/skills/hindsight/SKILL.md`** — Skill definition with your bank ID baked in.
### Team Setup
To set up cloud mode for your team:
1. **Team admin** creates a bank in Hindsight Cloud (e.g., `team-acme-frontend`)
2. **Team admin** generates API keys for each team member
3. **Each developer** runs the installer with their API key and the shared bank ID
4. All team members now share the same memory bank
### What to Store in Team Banks
Cloud mode uses a **shared team bank**. Be thoughtful about what goes in:
| Type | Examples | How to Store |
|------|----------|--------------|
| **Project conventions** | Linting rules, testing requirements, Node version | `"Project uses ESLint with Airbnb config"` |
| **Team knowledge** | Architecture decisions, common pitfalls, domain logic | `"Auth module requires Redis 7+"` |
| **Individual preferences** | Personal coding style, communication preferences | `"Alice prefers verbose commit messages"` |
**Key distinction**: Project conventions apply to everyone. Individual preferences should include the person's name so the AI knows when to apply them.
### Example Workflow
```
Day 1: Alice discovers a requirement
─────────────────────────────────────
Alice's AI assistant stores:
"The auth module requires Redis 7+ due to HEXPIRE command usage"
"Alice prefers explicit error handling over silent failures"
Day 2: Bob starts working on auth
─────────────────────────────────
Bob's AI assistant recalls:
"The auth module requires Redis 7+ due to HEXPIRE command usage"
Bob avoids the same issue Alice hit!
(Alice's personal preference is stored but won't be applied to Bob)
```
### Testing Cloud Connection
After installation, verify the connection:
```bash
# Store a test memory
hindsight memory retain team-acme-frontend "Alice works at Google as a software engineer"
# Recall it
hindsight memory recall team-acme-frontend "Alice"
```
### Switching Between Banks
If you work on multiple projects, you can have different skills installed for each AI assistant, or manually switch banks:
```bash
# Environment variable override (temporary)
HINDSIGHT_API_URL=https://api.hindsight.vectorize.io \
HINDSIGHT_API_KEY=hs_xxx \
hindsight memory recall different-bank "query"
```
For permanent multi-bank setups, reinstall the skill with a different bank ID.
## Troubleshooting
### Skill not activating
The skill activates based on its description matching your request. Try being explicit:
- "Remember that..." triggers storage
- "What do you know about..." triggers recall
### Local Mode Issues
**Daemon not starting:**
```bash
uvx hindsight-embed daemon status
uvx hindsight-embed daemon logs
```
**Reconfigure LLM provider:**
```bash
uvx hindsight-embed configure
```
### Cloud Mode Issues
**Authentication errors:**
```bash
# Verify your config
cat ~/.hindsight/config
# Test connection manually
hindsight bank list
```
**Wrong bank ID:**
Check your SKILL.md file to see which bank ID is configured:
```bash
cat ~/.claude/skills/hindsight/SKILL.md | grep "memory retain"
```
To change the bank ID, reinstall the skill:
```bash
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --mode cloud
```
**Network/firewall issues:**
```bash
# Test connectivity to cloud API
curl -I https://api.hindsight.vectorize.io/health
```
## Requirements
### Local Mode
- Python 3.10+ (for `uvx`)
- An LLM API key (OpenAI, Anthropic, Groq, etc.)
### Cloud Mode
- Python 3.10+ (for `uvx`)
- Hindsight Cloud API key
- Network access to `https://api.hindsight.vectorize.io`

View file

@ -0,0 +1,129 @@
---
sidebar_position: 2
---
# 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
import { HindsightClient } from '@vectorize-io/hindsight-client';
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', 'observation'], // 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',
mission: "You're a helpful AI assistant - keep track of user preferences and conversation history.",
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)
```

View file

@ -0,0 +1,259 @@
---
sidebar_position: 1
---
# Python Client
Official Python client for the Hindsight API.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Installation
<Tabs>
<TabItem value="all-in-one" label="All-in-One (Recommended)">
The `hindsight-all` package includes embedded PostgreSQL, HTTP API server, and client:
```bash
pip install hindsight-all
```
</TabItem>
<TabItem value="client-only" label="Client Only">
If you already have a Hindsight server running:
```bash
pip install hindsight-client
```
</TabItem>
</Tabs>
## Quick Start
<Tabs>
<TabItem value="all-in-one" label="All-in-One">
```python
import os
from hindsight import HindsightServer, HindsightClient
with HindsightServer(
llm_provider="openai",
llm_model="gpt-4o-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)
```
</TabItem>
<TabItem value="client-only" label="Client Only">
```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)
```
</TabItem>
</Tabs>
## 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", "observation"], # Filter by fact type
max_tokens=4096,
budget="high", # low, mid, or high
)
```
### Recall with Chunks
```python
# Returns RecallResponse with source chunks
response = client.recall(
bank_id="my-bank",
query="What does Alice do?",
types=["world", "experience"],
budget="mid",
max_tokens=4096,
include_chunks=True,
max_chunk_tokens=500
)
print(f"Found {len(response.results)} memories")
for r in response.results:
print(f" - {r.text}")
if r.chunks:
print(f" Source: {r.chunks[0].text[:100]}...")
```
### 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",
mission="You're a helpful AI assistant - keep track of user preferences and conversation history.",
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
import asyncio
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
```

View file

@ -238,12 +238,5 @@
}
]
}
],
"changelogSidebar": [
{
"type": "doc",
"id": "changelog/index",
"label": "Changelog"
}
]
}

View file

@ -0,0 +1,247 @@
{
"developerSidebar": [
{
"type": "category",
"label": "Architecture",
"collapsible": false,
"items": [
{
"type": "doc",
"id": "developer/index",
"label": "Overview"
},
{
"type": "doc",
"id": "developer/retain",
"label": "Retain"
},
{
"type": "doc",
"id": "developer/retrieval",
"label": "Recall"
},
{
"type": "doc",
"id": "developer/reflect",
"label": "Reflect"
},
{
"type": "doc",
"id": "developer/observations",
"label": "Observations"
},
{
"type": "doc",
"id": "developer/multilingual",
"label": "Multilingual"
},
{
"type": "doc",
"id": "developer/performance",
"label": "Performance"
},
{
"type": "doc",
"id": "developer/storage",
"label": "Storage"
},
{
"type": "doc",
"id": "developer/rag-vs-hindsight",
"label": "RAG vs Memory"
}
]
},
{
"type": "category",
"label": "API",
"collapsible": false,
"items": [
{
"type": "doc",
"id": "developer/api/quickstart",
"label": "Quick Start"
},
{
"type": "doc",
"id": "developer/api/retain",
"label": "Retain"
},
{
"type": "doc",
"id": "developer/api/recall",
"label": "Recall"
},
{
"type": "doc",
"id": "developer/api/reflect",
"label": "Reflect"
},
{
"type": "doc",
"id": "developer/api/mental-models",
"label": "Mental Models"
},
{
"type": "doc",
"id": "developer/api/memory-banks",
"label": "Memory Banks"
},
{
"type": "doc",
"id": "developer/api/documents",
"label": "Documents"
},
{
"type": "doc",
"id": "developer/api/operations",
"label": "Operations"
}
]
},
{
"type": "category",
"label": "Hosting",
"collapsible": false,
"items": [
{
"type": "doc",
"id": "developer/installation",
"label": "Installation"
},
{
"type": "doc",
"id": "developer/services",
"label": "Services"
},
{
"type": "doc",
"id": "developer/configuration",
"label": "Configuration"
},
{
"type": "doc",
"id": "developer/admin-cli",
"label": "Admin CLI"
},
{
"type": "doc",
"id": "developer/extensions",
"label": "Extensions"
},
{
"type": "doc",
"id": "developer/models",
"label": "Models"
},
{
"type": "doc",
"id": "developer/monitoring",
"label": "Monitoring"
},
{
"type": "doc",
"id": "developer/mcp-server",
"label": "MCP Server"
}
]
}
],
"sdksSidebar": [
{
"type": "category",
"label": "Clients",
"collapsible": false,
"items": [
{
"type": "doc",
"id": "sdks/python",
"label": "Python"
},
{
"type": "doc",
"id": "sdks/nodejs",
"label": "Node.js"
},
{
"type": "doc",
"id": "sdks/cli",
"label": "CLI"
}
]
},
{
"type": "category",
"label": "Integrations",
"collapsible": false,
"items": [
{
"type": "doc",
"id": "sdks/integrations/local-mcp",
"label": "Local MCP Server"
},
{
"type": "doc",
"id": "sdks/integrations/litellm",
"label": "LiteLLM"
},
{
"type": "doc",
"id": "sdks/integrations/skills",
"label": "Skills"
}
]
}
],
"cookbookSidebar": [
{
"type": "doc",
"id": "cookbook/index",
"label": "Overview"
},
{
"type": "category",
"label": "Recipes",
"collapsible": false,
"items": [
{
"type": "doc",
"id": "cookbook/recipes/quickstart",
"label": "Hindsight Quickstart"
},
{
"type": "doc",
"id": "cookbook/recipes/per-user-memory",
"label": "Per-User Memory"
},
{
"type": "doc",
"id": "cookbook/recipes/support-agent-shared-knowledge",
"label": "Support Agent with Shared Knowledge"
},
{
"type": "doc",
"id": "cookbook/recipes/litellm-memory-demo",
"label": "Memory with LiteLLM"
},
{
"type": "doc",
"id": "cookbook/recipes/tool-learning-demo",
"label": "Routing Tool Learning"
}
]
},
{
"type": "category",
"label": "Applications",
"collapsible": false,
"items": [
{
"type": "doc",
"id": "cookbook/applications/openai-fitness-coach",
"label": "OpenAI Agent + Hindsight Memory Integration"
}
]
}
]
}

View file

@ -1 +1,4 @@
[]
[
"0.4",
"0.3"
]