Adaptive memory system for conversational AI.
RecallOS gives AI assistants persistent, structured memory. It ingests conversations, extracts episodic memories, atomic facts, and foresight predictions, then retrieves them with purpose-aware search that adapts over time. Memories decay naturally, consolidate when redundant, and strengthen when useful — mimicking how human memory actually works.
Most AI memory systems are glorified vector databases — they store embeddings and do similarity search. RecallOS is fundamentally different:
It understands conversation structure. A 3-tier boundary detector (heuristics, embedding similarity, LLM) identifies where one topic ends and another begins — at 93% less cost than calling an LLM on every message.
It extracts multiple memory types. Each conversation segment produces episodes (narrative summaries), atomic facts (structured knowledge with subject-predicate-object triples), and foresight predictions (anticipated future impacts). Not just raw text chunks.
It organizes memories into clusters. Related episodes are grouped by topic using weighted multi-feature affinity scoring (semantic similarity, temporal proximity, participant overlap, entity overlap). Clusters enable neighborhood recall — finding related memories you didn't explicitly search for.
It builds user profiles automatically. Preferences, routines, commitments, active projects, and communication style are extracted incrementally and merged with contradiction detection.
It learns from usage. Retrieved memories that get cited in AI responses are reinforced. Memories that are consistently ignored decay faster. Fusion weights adapt based on what actually helps.
It consolidates over time. Duplicate facts are merged. Superseded information is archived. Expired predictions are resolved. Repetitive episodes are generalized ("weekly standup meetings in January" replaces 4 individual standup records).
Memories have lifecycles. Each memory has a temporal relevance score that decays based on its type (preferences decay over years, event details decay in days). Dormant memories are pruned from vector indexes to keep search fast, but can be reactivated if referenced again.
# Start PostgreSQL and Redis
docker compose up -d
# Install dependencies
uv sync
# Configure environment
cp .env.example .env
# Edit .env with your LLM API keys
# Run database migrations
uv run alembic upgrade head
# Start the server
uv run recallThe server starts at http://localhost:1995. Interactive API docs at http://localhost:1995/docs.
# Ingest a message
curl -X POST http://localhost:1995/v2/messages \
-H "Content-Type: application/json" \
-d '{
"message_id": "msg-001",
"sender_id": "alice",
"sender_name": "Alice",
"content": "I prefer morning meetings and tea over coffee",
"group_id": "project-alpha"
}'
# Search memories
curl -X POST http://localhost:1995/v2/search \
-H "Content-Type: application/json" \
-d '{
"query": "What does Alice prefer?",
"top_k": 10,
"assemble_context": true
}'
# Batch ingest a conversation
curl -X POST http://localhost:1995/v2/messages/batch \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"message_id": "m1", "sender_id": "alice", "content": "Lets discuss the API migration"},
{"message_id": "m2", "sender_id": "bob", "content": "Sure, I finished the auth endpoints"},
{"message_id": "m3", "sender_id": "alice", "content": "Great, the deadline is April 15th"}
]
}'| Method | Path | Description |
|---|---|---|
POST |
/v2/messages |
Ingest a message into the memory pipeline |
POST |
/v2/messages/batch |
Batch ingest multiple messages |
POST |
/v2/search |
Search memories with purpose-aware retrieval |
GET |
/v2/memories |
List memories with filtering and pagination |
GET |
/v2/memories/{id} |
Get a single memory with full detail |
DELETE |
/v2/memories |
Soft-delete memories by ID |
POST |
/v2/memories/{id}/pin |
Pin a memory to prevent decay |
POST |
/v2/feedback |
Submit feedback (thumbs up/down, flag, pin) |
GET |
/v2/profiles/{user_id} |
View user profile (preferences, routines, projects) |
GET |
/v2/conversations/{group_id} |
Conversation metadata and participants |
PATCH |
/v2/conversations/{group_id} |
Update conversation metadata |
GET |
/v2/groups/{group_id}/clusters |
Browse topic clusters |
GET |
/v2/status/{group_id} |
Pipeline processing status |
GET |
/v2/stats |
System-wide statistics |
DELETE |
/v2/users/{id}/data |
Delete all user data (GDPR Art. 17) |
GET |
/v2/users/{id}/data/export |
Export all user data (GDPR Art. 20) |
GET |
/health |
Service health check |
Message arrives
-> Boundary Detection (3-tier: heuristics -> embedding -> LLM)
-> If boundary: seal conversation segment, enqueue extraction job
-> If no boundary: accumulate in conversation window
Extraction Worker (async, background):
-> Episode extraction (group + per-participant perspectives)
-> Atomic fact extraction (with SPO triples and categorization)
-> Foresight extraction (gated — only when commitment/decision language detected)
-> Cluster assignment (weighted multi-feature affinity scoring)
-> Profile update (gated — only when profile-relevant signals detected)
-> Persist to PostgreSQL + emit outbox events for index sync
Search query arrives
-> Query understanding (rule-based fast path, LLM for ambiguous queries)
-> Parallel candidate generation across memory types
-> Score fusion (per-purpose weights + type priors + freshness + group)
-> Reranking (gate decides if worth the cost)
-> Optional: agentic multi-round retrieval (evidence gap analysis + action planning)
-> Context assembly (deduplication, token budgeting, narrative formatting)
Temporal Relevance Worker (periodic):
-> Compute decay per memory (type-specific half-lives)
-> Manage lifecycle transitions (active -> cooling -> dormant -> archived)
-> Prune dormant memories from vector indexes
Consolidation Worker (periodic):
-> Deduplicate semantically identical facts
-> Detect superseded facts (newer contradicts older)
-> Resolve expired foresight predictions
-> Generalize repetitive episodes into summaries
Feedback Loop (post-response):
-> Detect which memories were cited in AI responses
-> Update per-memory retrieval usefulness scores
-> Adapt fusion weights via online learning
RecallOS supports three operating modes that control cost vs. quality tradeoffs:
| Feature | Cheap | Balanced | Premium |
|---|---|---|---|
| Boundary detection | Heuristics + LLM | Heuristics + Embedding + LLM | Full 3-tier |
| Foresight extraction | Off | On | On |
| Persona profiles | Off | Off | On |
| Feedback learning | Off | Capture only | Capture + online learning |
| Consolidation | Embedding-only dedup | Monthly episode generalization | Weekly + LLM verification |
| Temporal worker | Every 24h | Every 6h | Every 3h |
Set via OPERATING_MODE=cheap|balanced|premium in .env, or programmatically:
from recall.config import RecallAppConfig
from recall.domain.enums import OperatingMode
config = RecallAppConfig.from_operating_mode(OperatingMode.PREMIUM)| Layer | Technology |
|---|---|
| Language | Python 3.12 |
| Web framework | FastAPI + uvicorn |
| Database | PostgreSQL 16 + pgvector |
| Cache / Queue | Redis 7 (Streams for async job queue) |
| LLM integration | Direct aiohttp (no LangChain) |
| Configuration | pydantic-settings with env var + .env support |
| Migrations | Alembic |
| Observability | structlog + Prometheus + OpenTelemetry |
| Testing | pytest + testcontainers |
| Linting | ruff |
# Run all tests (251 total)
uv run pytest
# Unit tests only (fast, no Docker needed)
uv run pytest tests/unit/
# Integration tests (requires Docker for PostgreSQL)
uv run pytest tests/integration/ --timeout=120
# Lint and format
uv run ruff check src/ tests/
uv run ruff format src/ tests/src/recall/
├── api/ # 17 REST endpoints
├── llm/ # LLM client with pooled connections and tier routing
├── prompts/ # YAML prompt templates with token budgeting
├── boundary/ # 3-tier conversation boundary detection
├── pipeline/ # Async memorize pipeline with Redis Streams
├── extraction/ # Episode, fact, foresight extractors with partial failure handling
├── clustering/ # Multi-feature affinity clustering with EMA centroids
├── profiles/ # Two-layer profile system with delta-based updates
├── vectorize/ # Purpose-aware embedding with 3-layer cache
├── rerank/ # Score fusion with gate and cascade
├── retrieval/ # Multi-form search with query understanding
├── agentic/ # Multi-round retrieval reasoning
├── assembly/ # Context assembly with token budgeting
├── feedback/ # Citation detection and online learning
├── temporal/ # Decay, reinforcement, lifecycle management
├── consolidation/ # Fact dedup, supersession, episode generalization
├── persistence/ # PostgreSQL repositories and search backends
├── core/ # DI container, lifecycle, middleware, observability
└── migrations/ # Alembic schema (17 tables, 30+ indexes)
Apache 2.0