Memoria persistente local-first para agentes AI — SQLite + FTS5 + HRR + embeddings opcionales
Project description
memento
Memoria persistente local-first para agentes AI. SQLite + FTS5 + HRR vectors + embeddings opcionales. Sin servicios externos, sin GPU, sin API keys.
Tabla de Contenidos
- ¿Por qué memento?
- Instalación
- Primeros pasos
- Arquitectura
- Características
- Embedding Providers
- MCP Server
- Web Viewer
- Benchmarks
- API
- Contribuir
- Licencia
¿Por qué memento?
Los agentes AI necesitan memoria persistente para ser útiles. Pero las opciones existentes implicaban elegir entre:
- Dependencia de APIs externas (Pinecone, OpenAI embeddings) — tu agente deja de funcionar sin internet.
- Infraestructura pesada (Chroma, Qdrant, AgentMemory con iii-engine) — 2GB+ de descarga, runtimes externos, config compleja.
- Archivos JSON artesanales — crecen como plaga, sin búsqueda, sin estructura.
memento es el punto medio: SQLite embedded, sin servidores, sin dependencias obligatorias, sin llamadas externas. Tu información nunca sale de tu máquina.
pip install memento-etch
python -c "from memento import EtchStore; s = EtchStore('memory.db'); print('anda')"
Eso es todo lo que necesitás para arrancar.
Instalación
# Mínimo: FTS5 + Jaccard (solo stdlib de Python)
pip install memento-etch
# Recomendado: FTS5 + HRR vectors (necesita numpy)
pip install "memento-etch[hrr]"
pip install "memento-etch[embeddings]"
pip install "memento-etch[mcp]"
pip install "memento-etch[all]"
Requisitos: Python 3.10-3.12 | Sin GPU | Sin CUDA | Sin runtime externo.
Primeros pasos
from memento import EtchStore, EtchRetriever
# Crear o abrir la base de datos
store = EtchStore("memory.db")
# Guardar hechos
store.add_fact("Python es un lenguaje interpretado", category="tech")
store.add_fact("SQLite soporta FTS5 para búsqueda de texto completo", category="tech")
store.add_fact("FastAPI está construido sobre Starlette", category="tech")
# Guardar con campos estructurados (v1.0)
store.add_fact(
content="Usar httpx para llamadas HTTP asincrónicas en Python",
what="Decisión técnica",
why="httpx tiene mejor soporte de async/await que requests",
where="src/http_client.py",
learned="httpx funciona con anyio y trio, no solo asyncio",
)
# Buscar
retriever = EtchRetriever(store)
results = retriever.search("búsqueda de texto completo")
for r in results:
print(f"[{r['_score']:.2f}] {r['content']}")
# Búsqueda inteligente con fallback automático (v1.0)
results = retriever.search(
"¿cómo hago requests HTTP en Python?",
mode="auto", # FTS5 → HRR multi-query → embeddings (si están configurados)
limit=5,
)
# Detección automática de proyecto (v1.0)
# Si estás en un repo git, el proyecto se detecta solo del remote origin
store = EtchStore("project.db", project="auto")
Arquitectura
┌─────────────────────────────────────────────────────┐
│ Tu Agente AI │
├─────────────────────────────────────────────────────┤
│ MCP Server (stdio) │ Python API │
├─────────────────────────────────────────────────────┤
│ EtchRetriever │
│ ┌─────────┬──────────┬───────────┬──────────────┐ │
│ │ FTS5 │ HRR │ Jaccard │ Embeddings │ │
│ │ (exact) │(vectors) │ (n-gram) │ (semántico) │ │
│ └────┴────┴────┴─────┴────┴──────┴──────┴───────┘ │
│ │ │ │
│ Reciprocal Rank Fusion (RRF) │
│ │ │
│ EtchStore — SQLite + FTS5 + triggers automáticos │
└─────────────────────────────────────────────────────┘
Tres capas de búsqueda, sin dependencias externas por defecto:
| Capa | Qué hace | Costo | Dependencia |
|---|---|---|---|
| FTS5 | Búsqueda exacta por palabras clave | ~0.05ms | stdlib |
| HRR | Similaridad semántica holográfica | ~0.8ms | numpy (opt-in) |
| Jaccard | Re-ranking por n-gramas | incluido en HRR | numpy (opt-in) |
| Embeddings | Búsqueda semántica densa | ~185ms | fastembed (opt-in) |
Por defecto usa solo FTS5 + Jaccard. Con pip install memento-etch[hrr] ganás HRR.
Con pip install memento-etch[embeddings] ganás embeddings densos.
Cada nivel es opcional, aditivo, y retrocompatible.
Características
Core (v0.x)
| Feature | Descripción |
|---|---|
| FTS5 | Búsqueda de texto completo con triggers auto-sincronizados |
| HRR vectors | Representaciones holográficas sin modelos, sin GPU |
| Jaccard re-rank | Overlap de n-gramas para ordenar resultados |
| Soft delete | Los hechos no se borran, se ocultan |
| Consolidación activa | LLM decide ante hechos duplicados o contradictorios |
| Entity tracking | N:M entre entidades con tipos y alias |
| Fact relations | compatible, conflicts_with, supersedes |
| Session timeline | Contexto cronológico por sesión |
| Web viewer | SPA en puerto :9120 |
| Trust scoring | Puntuación de confianza que se refuerza con retrievals |
| Topic upsert | Hechos que evolucionan: mismo topic_key, se actualizan |
v1.0
| Feature | Descripción |
|---|---|
| MCP Server | 9 tools vía stdio (facts, search, timeline, similar, inbox review) |
| Structured facts | Campos what/why/where/learned para memorias disciplinadas |
| Project detection | Detecta el proyecto desde git remote automáticamente |
| Embedding providers | Pluggable: NoopProvider, FastembedProvider, OllamaProvider |
| Search expanded | FTS5 con expansión progresiva (full query → OR → single terms) |
| HRR multi-query | Búsqueda paralela con variaciones semánticas de la query |
| Dynamic RRF | k adaptativo según cantidad de resultados |
| Fallback chain | Modo "auto" que cascada FTS5 → HRR → embeddings |
| SHA-256 dedup | Deduplicación exacta con ventana de 60s |
| Conflict surfacing | Detecta hechos similares al insertar y muestra conflictos |
| Circuit breaker | Protege contra fallos en cadena de LLM externos (3 fallos, 60s cooldown) |
| Auto-eviction | Elimina facts stale (trust < 0.1 o 30 días sin retrieve) |
| Session summaries | Genera resúmenes estructurados de sesiones |
| Progressive disclosure | Search devuelve resumen (200 chars), get_fact_full() da el contenido completo |
Embedding Providers
Tres modos de búsqueda semántica, plug and play:
# 1. Sin embeddings (FTS5 + HRR, cero overhead)
store = EtchStore("memory.db") # NoopProvider por defecto
# 2. Con fastembed (local, ONNX, sin API key)
# pip install memento-etch[embeddings]
from memento.embedding import FastembedProvider
store = EtchStore("memory.db", embedding_provider=FastembedProvider())
# 3. Con Ollama (si ya tenés Ollama corriendo)
from memento.embedding import OllamaProvider
store = EtchStore("memory.db", embedding_provider=OllamaProvider(
base_url="http://localhost:11434",
model="nomic-embed-text",
))
Cada provider se puede usar en cualquier combinación con el MCP server.
MCP Server
Para integrar memento con cualquier agente que soporte MCP (Claude Code, Codex, Gemini CLI, etc.):
pip install "memento-etch[mcp]"
# Con variable de entorno
set MEMENTO_DB_PATH=./memory.db
python -m memento.mcp
Herramientas MCP expuestas:
add_factsearch_factsget_factdelete_factget_timelinesearch_similarlist_inboxpromote_factreject_fact
Configuración vía MEMENTO_DB_PATH. Si no está definida, el servidor usa :memory: como default; para uso persistente, seteá una ruta explícita como ./memory.db o ~/.memento/etch.db.
Hive Memory (v1.1)
Provenance-aware facts with governed scopes and an inbox review lifecycle. Every fact can carry source identity (source_harness, source_agent, source_kind) and a scope that controls discoverability.
Scopes
| Scope | Default search | Use case |
|---|---|---|
canonical |
✅ Included | Trusted project memory |
inbox |
❌ Excluded | Untrusted / subagent writes awaiting review |
personal |
❌ Excluded | Private user facts |
ephemeral |
❌ Excluded | Transient data |
Provenance example:
store.add_fact(
"FastMCP retries on timeout",
source_harness="opencode",
source_agent="worker-1",
source_kind="manual",
scope="canonical",
)
Inbox workflow
# List pending inbox facts
inbox = store.list_inbox(project="my-project", limit=20)
# Promote to canonical (becomes searchable)
store.promote_fact(inbox[0]["fact_id"])
# Reject (soft-deleted, hidden from default search)
store.reject_fact(inbox[3]["fact_id"], reason="low quality")
No new dependencies. Works with existing add_fact callers — provenance args are optional, scope defaults to canonical. See docs/api/store.md for the full API.
Benchmark
Benchmark integrado para medir recall@k con dataset sintético y juez Gemini:
# Requiere GEMINI_API_KEY
export GEMINI_API_KEY="..."
# Benchmark memento (FTS5 + HRR)
python -m memento.benchmark --verbose
# Benchmark contra baseline JSON (para comparar)
python -m memento.benchmark --provider json-baseline --verbose
# Personalizar dataset
python -m memento.benchmark --n-docs 500 --seed 42 --output results.json
Para benchmarkear OTRO sistema de memoria contra el mismo benchmark,
implementá MemoryProvider:
from memento.benchmark import MemoryProvider, BenchmarkRunner
class MyMemory(MemoryProvider):
name = "mi-sistema"
def ingest(self, documents): ...
def retrieve(self, query, k=10, user_id=None): ...
runner = BenchmarkRunner(MyMemory())
results = runner.run(verbose=True)
print(f"Accuracy: {results['accuracy']:.1%}")
Resultado de referencia (100 docs, 18 queries):
| Provider | Accuracy | Avg retrieve |
|---|---|---|
| memento (FTS5 + HRR) | 94.4% (17/18) | 5.2ms |
| JSON baseline (word overlap) | ~40% | ~0.1ms |
Web Viewer
Visualizá toda la memoria de tu agente en un SPA local, sin servidores, sin config.
python -m memento.viewer --db ./memory.db
# http://127.0.0.1:9120
Qué ves:
| Feature | Para qué sirve |
|---|---|
| Buscador | Buscá facts por contenido, proyecto, o categoría |
| Timeline | Cronología por sesión — qué pasó y cuándo |
| Relaciones | Facts conectados: compatible, conflicts_with, supersedes |
| Metadata | trust_score, retrieval_count, categoría, proyecto |
| Soft delete | Facts archivados no se pierden, se ocultan |
Combinado con la DB versionable:
# Compartí la misma memoria con tu equipo
git add memory.db
git commit -m "seed data: 500 facts de referencia"
git push
# Otro dev hace pull y abre el viewer
git pull
python -m memento.viewer --db memory.db
# → ve exactamente los mismos facts, relaciones, timeline
Útil para debuggear el estado de un agente, revisar qué facts acumuló, o compartir datasets de prueba con el equipo.
Benchmarks
Benchmark sintético (100 documentos, 18 queries)
| Modo | Recall | Latencia | Dependencias |
|---|---|---|---|
| FTS5 + HRR (search_expanded + re-score) | 94.4% (17/18) | 5.2ms | numpy |
| Solo FTS5 raw | ~5% | ~0.05ms | stdlib |
| Con embeddings (BGE-small) | ~72% | ~185ms | fastembed + 65MB |
Benchmark reproducible:
set GEMINI_API_KEY=...
pip install "memento-etch[hrr]"
python scripts/run_amb_benchmark.py --n-docs 100 --verbose
Benchmarks en producción (VPS con facts reales de agente)
| Métrica | FTS5 solo | FTS5 + HRR | Embeddings densos |
|---|---|---|---|
| Coverage @100 facts | 39.2% | 69.7% | 72% |
| Latencia por query | ~0.05ms | ~0.8ms | ~185ms |
| Dependencias extra | ninguna | numpy | fastembed + ONNX |
HRR es 200-400x más rápido que embeddings densos con ~97% de su cobertura.
API
Documentación detallada en docs/api/:
- EtchStore — Core SQLite: CRUD, FTS5, HRR, sesiones, relaciones, consolidación.
- EtchRetriever — Búsqueda híbrida: FTS5 + HRR + Jaccard + embeddings con RRF.
- QueryClassifier — Clasificador rule-based para rutear estrategias de búsqueda.
Proyectos relacionados
| Proyecto | Diferenciador |
|---|---|
| memento | Local-first, KISS, SQLite, sin runtime externo, HRR vectors |
| CodeGraph | Code intelligence (tree-sitter + grafo de símbolos), NO es memoria de agente |
| AgentMemory | Memoria full-featured con iii-engine dedicado, más features, más complejidad |
| Engram | Memoria para agentes Go/MCP, sin embeddings, curada por el agente |
Contribuir
git clone https://github.com/Basiliskode/Memento-Memory
cd Memento-Memory
pip install -e ".[dev]"
python -m pytest tests/ -v
Todos los PRs son bienvenidos. Usamos conventional commits y TDD estricto.
Licencia
MIT. Construí algo útil.
memento nació dentro de un agente AI real que necesitaba acordarse de las cosas sin depender de servicios externos. Hoy corre en producción y está probado con miles de facts.
Si estás construyendo un agente que necesite memoria, probalo. Son 30 segundos.
pip install "memento-etch[hrr]" python -c "from memento import EtchStore; s = EtchStore('test.db'); print('anda')"
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file memento_etch-1.1.1.tar.gz.
File metadata
- Download URL: memento_etch-1.1.1.tar.gz
- Upload date:
- Size: 218.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
894be2c294cedf7c3d8d2454d8bc41aa39bf838dde8f1f2dcaff91f2dbc1f076
|
|
| MD5 |
1c6ad12355106cf0e31ea3a1aec5d51b
|
|
| BLAKE2b-256 |
a1043e5506efb0158ea661cb4947096e48559325d1ccf07f466ffde3bcca96b4
|
File details
Details for the file memento_etch-1.1.1-py3-none-any.whl.
File metadata
- Download URL: memento_etch-1.1.1-py3-none-any.whl
- Upload date:
- Size: 145.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac360ed63d92c9b951bb2a4e0f9fbecc94207620a1a4fda993cfc644ccf0b997
|
|
| MD5 |
3dec25d346aafd1a0c9cea7d6e77b449
|
|
| BLAKE2b-256 |
457452b155d092e61329c91e05c7bdedd002bf4c12c0f71d681d7498f589c177
|