How Memoria works
Chat stays fast because memory work happens in background workers. This page follows one fact from your message to long-term storage and back.
1. Ingest
After each chat turn, a Celery worker calls Qwen-Plus function calling (extract_memories) to pull out user-centric facts. Each fact gets a type: core, episodic, semantic, procedural, goal or preference.
2. Embed
Each memory is vectorized with text-embedding-v3 (1024 dimensions).
3. Store
The memory is saved in the PostgreSQL memories table with pgvector, next to its importance, decay rate and metadata.
4. Retrieve
retrieve_context embeds your message and ranks candidate memories by cosine similarity × importance × recency. It packs the best ones into the prompt under a token budget, core memories first. Personal Intelligence and MemoryLess change which memories are eligible.
5. Decay
Every day at 03:00 UTC, non-core memories lose importance exponentially. Memories that fall below 0.1 are archived (soft-deleted). Core memories have a decay rate of 0 and never decay.
6. Consolidate
Every week, memories from the past seven days are clustered by embedding similarity (0.75 or higher). Clusters of three or more are summarized by Qwen-Max into one semantic memory. Originals are linked through parent_id and marked is_consolidated.
7. Reflect
Reflection runs in the background on every 10th user message. Qwen produces a reflection and traits, stored as a memory and added to the system prompt.
8. Resolve conflicts
During ingestion, memories with similarity above 0.7 are checked by Qwen for contradictions. A contradicted memory is superseded, and the newer fact is kept.
Retrieval score
Each candidate memory is ordered by cosine_similarity × importance × recency. Recency is exp(-decay_rate × age_in_days), so each memory ages at its own rate. The default decay rate depends on the memory type:
| Type | Default decay rate |
|---|---|
core | 0 |
semantic | 0.01 |
episodic | 0.02 |
procedural | 0.005 |
goal | 0.01 |
preference | 0.01 |
Memory tiers
| Tier | Where | Behaviour |
|---|---|---|
| Session Memory | Redis | Last 10 messages of the active chat, always in context. |
| Personal Memory | memories table | User facts with extraction, decay, consolidation and conflict resolution. |
| Personal Intelligence | users.global_memory_enabled | On: all Personal Memories. Off: current session plus manual core memories. |
| MemoryLess | Redis only | No Personal Memory read or write, no archive. Personal Intelligence is ignored. |
| Context Archive | chat_messages | Full transcripts. Searched on demand, not used in routine retrieval. |
Scheduled jobs
Celery Beat triggers decay daily at 03:00 UTC and consolidation weekly on Saturday at 04:00 UTC. The schedule in backend/celery_app/__init__.py is crontab(day_of_week=6, hour=4, minute=0), which is Saturday in Celery. The README text says Sunday; this site follows the code.
Architecture diagram
Layers: browser, FastAPI backend, Celery workers, Redis and PostgreSQL storage, and Qwen Cloud models. External agents reach memory through the MCP endpoint.

Full text version: docs/ARCHITECTURE.md.