Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vectorize-io/hindsight/llms.txt

Use this file to discover all available pages before exploring further.

Extensions let you customize Hindsight behavior by injecting Python classes that hook into the system’s lifecycle. They are loaded at startup via environment variables and receive configuration through prefixed env vars. Extensions can add authentication, custom HTTP endpoints, operation validation, and MCP tools without touching core code.
# General pattern
HINDSIGHT_API_<TYPE>_EXTENSION=mypackage.module:MyExtensionClass

# Configuration for extensions uses the same prefix
HINDSIGHT_API_<TYPE>_SOME_CONFIG=value
# Extension receives: {"some_config": "value"}
All extensions support on_startup() and on_shutdown() lifecycle hooks, and receive an ExtensionContext that provides access to run_migration(schema) and get_memory_engine().

TenantExtension

Handles authentication and multi-tenancy. Validates incoming requests and determines which PostgreSQL schema to use for database operations, enabling complete tenant isolation.

Built-in: ApiKeyTenantExtension

Validates API keys against an environment variable. All authenticated requests use the public schema.
HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.tenant:ApiKeyTenantExtension
HINDSIGHT_API_TENANT_API_KEY=your-secret-key
When enabled, requests must include the key as a Bearer token:
curl -H "Authorization: Bearer your-secret-key" \
  http://localhost:8888/v1/default/banks

Built-in: SupabaseTenantExtension

Validates Supabase JWTs and provides per-user schema isolation. Each authenticated user gets their own PostgreSQL schema ({prefix}_{user_id}). Uses JWKS for local JWT verification — no network call per request.
HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.supabase_tenant:SupabaseTenantExtension
HINDSIGHT_API_TENANT_SUPABASE_URL=https://your-project.supabase.co
# Optional: only needed for legacy HS256 projects
HINDSIGHT_API_TENANT_SUPABASE_SERVICE_KEY=your-service-role-key

Custom: JWT authentication

Implement a custom TenantExtension for JWT, OAuth, or any other auth scheme:
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))
AuthenticationError accepts an optional headers dict forwarded in both HTTP and MCP error responses:
raise AuthenticationError(
    "Authorization required",
    headers={"WWW-Authenticate": 'Bearer realm="example"'},
)
Configure via environment variables:
HINDSIGHT_API_TENANT_EXTENSION=my_extensions.auth:JwtTenantExtension
HINDSIGHT_API_TENANT_JWT_SECRET=your-signing-secret

HttpExtension

Adds custom HTTP endpoints under the /ext/ path prefix. Useful for domain-specific APIs that need access to Hindsight’s memory engine. No built-in implementation — provide your own.
HINDSIGHT_API_HTTP_EXTENSION=mypackage.ext:MyHttpExtension
HttpExtension provides two router methods:
  • get_router(memory) — returns a FastAPI router mounted at /ext/
  • get_root_router(memory) — returns a FastAPI router mounted at the application root (for well-known paths or other specific locations). Returns None by default.
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):
            pool = await memory._get_pool()
            # ... custom logic
            return {"status": "ok"}

        return router

    def get_root_router(self, memory: MemoryEngine) -> APIRouter | None:
        """Optional: mount routes at the app root (not under /ext/)."""
        router = APIRouter()

        @router.get("/.well-known/my-metadata")
        async def metadata():
            return {"version": "1.0"}

        return router
Routes from get_router are available at /ext/hello, /ext/custom/{bank_id}/action, and so on. Routes from get_root_router are available at the exact paths specified (e.g., /.well-known/my-metadata).

OperationValidatorExtension

Hooks into retain, recall, and reflect operations before and after execution. Use cases include rate limiting, permission checks, audit logging, and custom metrics. No built-in implementation — provide your own.
HINDSIGHT_API_OPERATION_VALIDATOR_EXTENSION=mypackage.validators:MyValidator
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:
        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

Deferring operations

A validate_retain hook can defer an operation for a future time by raising DeferOperation. Unlike a retry, deferral does not increment retry_count or write an error message. The worker sets next_retry_at and the task is invisible to claim queries until that time.
from datetime import datetime, timedelta, timezone
from hindsight_api.extensions import DeferOperation, OperationValidatorExtension, RetainContext, ValidationResult

class QuotaAwareValidator(OperationValidatorExtension):
    async def validate_retain(self, ctx: RetainContext) -> ValidationResult:
        if not await self._quota_available(ctx.bank_id):
            raise DeferOperation(
                exec_date=datetime.now(timezone.utc) + timedelta(minutes=5),
                reason="bank quota window exhausted",
            )
        return ValidationResult.accept()
DeferOperation is worker-only. Do not raise it from validate_recall or validate_reflect in synchronous HTTP request paths — there is no queue to defer to and it will surface as a 500 error.

MCPExtension

Registers additional MCP (Model Context Protocol) tools on the Hindsight MCP server. Enables external packages to add custom tools without modifying core code. No built-in implementation.
HINDSIGHT_API_MCP_EXTENSION=mypackage.mcp:MyMCPExtension
from mcp.server.fastmcp import FastMCP
from hindsight_api.extensions import MCPExtension
from hindsight_api.engine import MemoryEngine

class MyMCPExtension(MCPExtension):
    async def register_tools(self, mcp: FastMCP, memory: MemoryEngine) -> None:
        @mcp.tool()
        async def custom_search(query: str) -> str:
            """Custom MCP tool for specialized search."""
            pool = await memory._get_pool()
            # ... custom logic
            return f"Results for: {query}"

Deploying custom extensions

Mount your extension package as a volume and configure via environment variables:
# 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

Contributing extensions

Custom extensions that solve common use cases are welcome contributions. If you’ve built an extension for authentication providers, rate limiting, audit logging, metrics exporters, or custom endpoints, consider contributing it to the hindsight_api.extensions.builtin package. Open an issue or pull request on GitHub to discuss.

Build docs developers (and LLMs) love