Saltar al contenido
Menú

Producto

Soluciones

Integraciones

Desarrolladores

Idioma

Producto

Un solo binario, archivos markdown y un índice derivado

Los hooks capturan la actividad del agente. Markdown en git guarda las páginas; SQLite guarda su índice de búsqueda y registros exclusivos de la base, como sesiones, traspasos y cuentas. Haz copia de ambos. Sigue abajo el recorrido desde la captura hasta el próximo informe.

Un solo binario, un directorio de datos.

SQLite va incluido, libgit2 va vendorizado y el embedder es Rust puro. No hay sidecar, ni servidor de base de datos, ni cola que mantener. Todo lo que sabe está en una carpeta.

<data_dir>/

wiki/Páginas markdown con frontmatter YAML, en un repositorio git. La fuente de verdad.
db/memory.sqliteÍndice de búsqueda y registros exclusivos de la base: sesiones, observaciones, traspasos, cuentas y auditoría. Modo WAL.
raw/Segmentos JSONL inmutables y saneados de las sesiones gestionadas con ai-memory run.
models/El modelo local de embeddings, all-MiniLM-L6-v2, de unos 87 MB y con SHA-256 fijado.
logs/Logs con rotación diaria.
config.tomlSe lee una vez al arrancar. Cada valor se puede sobrescribir con una variable AI_MEMORY_*.

El servidor escucha en 127.0.0.1:49374 por defecto. Hacer una copia de seguridad es ejecutar ai-memory backup, o un git push de la wiki más un rsync de la carpeta.

De un hook al siguiente resumen.

Siete de estos ocho pasos corren sin modelo y sin clave de API. El paso con LLM está apagado hasta que configuras un proveedor.

Hook

Sanear

Escritor único

Observaciones

Observaciones

Página de sesión

LLM opcional

Wiki en git

Resumen

Wiki en git

Hook

Solo la etapa en línea discontinua necesita un LLM. La flecha de retorno es el resumen que se inyecta en el siguiente SessionStart.
  1. HookCero LLM

    La CLI del agente dispara un hook de ciclo de vida. Es fire and forget con un presupuesto de 200 ms: los hooks nativos guardan el evento en una cola local y un helper independiente lo entrega. El servidor responde 202, o 429 si está saturado.

  2. SaneadoCero LLM

    El router de /hook elimina los secretos y limita los tamaños. Es el único camino del texto no confiable hacia el store.

  3. Escritor únicoCero LLM

    El evento saneado entra en una sola cola, que vacía un solo hilo, dueño de la única conexión de escritura.

  4. ObservacionesCero LLM

    Los eventos caen en SQLite como un rastro de auditoría operativo. Es una proyección acotada de la sesión, nunca una transcripción completa.

  5. Fin de sesiónCero LLM

    Unas reglas, sin modelo, convierten las observaciones en sessions/<id>.md y abren una fila Handoff para el siguiente agente, en una sola transacción.

  6. ConsolidaciónLLM opcional

    Con un proveedor configurado, un LLM reescribe el resumen o lo reparte en concepts/, decisions/, gotchas/ y procedures/. Corre desde una cola con reintentos, fuera de la latencia de los hooks.

  7. Commit e índiceCero LLM

    Cada escritura de página es atómica (tmp, rename, fsync), se commitea en git y se indexa en la misma transacción de SQLite que su fila.

  8. Consulta y resumenCero LLM

    memory_query busca en el índice. En el siguiente SessionStart, el hook trae el traspaso abierto y un resumen estructurado para ese directorio.

Dos capas, una fuente de verdad.

Si los archivos y el índice no coinciden, ganan los archivos.

Escritor

Markdown en git

Fuente de verdad

Índice SQLite

Derivado

Markdown en git

File watcher

Reindexar

Índice SQLite

  • Los archivos son la verdad

    Las páginas son markdown con frontmatter YAML bajo wiki///. Ábrelas en Obsidian, pásales grep, súbelas a un remoto.

  • El índice de páginas es derivado

    Reindex reconstruye páginas, enlaces y búsqueda de texto desde Markdown. No recupera sesiones, observaciones, traspasos, usuarios, claves ni auditoría que solo existen en la base.

  • Las escrituras son del servidor

    Las escrituras normales pasan por la capa de la wiki, que actualiza juntos el archivo, el historial de git y el índice.

  • Un watcher recoge el resto

    Un file watcher detecta las ediciones hechas desde vim u Obsidian. Un diff completo cada 30 segundos recoge los eventos que se le escaparon.

Recuperación: cinco flujos, un ranking.

Consulta

FTS5

Entidades

Grafo

Observaciones

Vectores

RRF k=60

Autoridad

Resultados

El carril de vectores va en línea discontinua porque la búsqueda funciona sin él.
  • Texto completo

    SQLite FTS5 sobre los títulos y los cuerpos de las páginas, con las stopwords filtradas en las consultas sin operadores.

  • Coincidencia de entidades

    Un índice léxico de nombres sacados de las entidades y los tags del frontmatter, ponderado por frecuencia inversa de página.

  • Vecinos en el grafo

    Un salto sobre la tabla de enlaces: wikilinks, enlaces markdown, aristas tipadas y enlaces entre proyectos. SQL plano, sin base de datos de grafos.

  • Observaciones

    Texto completo sobre las observaciones en bruto del proyecto. Cada sesión que coincide vota una sola vez, a través de su mejor observación, por su propia página de sesión, así que el detalle que nunca llegó a la página también la encuentra. Activado por defecto desde la 3.0.

  • Vectores, opcionales

    Similitud coseno sobre embeddings del modelo local que corre dentro del proceso. Activados por defecto desde la 2.0, nunca obligatorios, y por fuerza bruta a propósito.

Después de la fusión

  • Reciprocal Rank Fusion con k=60 fusiona los flujos por posición, así que ningún flujo necesita calibrar sus puntuaciones.
  • Después, un multiplicador de autoridad acotado inclina los empates ajustados hacia reglas, decisiones, procedimientos y gotchas que se mantienen al día. Las páginas episódicas e históricas siguen apareciendo en las búsquedas, y nada se excluye del todo.
  • Rerank opcional con LLM: una llamada por consulta sobre hasta 30 títulos y fragmentos. Ante cualquier fallo se conserva el orden local. Todavía no hay un reranker local.
  • Si las páginas compiladas no dan ningún resultado, una búsqueda acotada sobre las observaciones en bruto devuelve raw_hits.
  • Los filtros se aplican antes del ranking: kind, tag, tier y un prefijo de ruta acotan todas las vías, así una página poco frecuente no queda desplazada por una común.
  • Dos señales opcionales parten de cero: una baja la autoridad de una página con feedback de obsoleta o errónea sin resolver; la otra favorece una página que la misma sesión leyó o marcó como útil para una consulta parecida. Una reescritura borra ambas.
  • Pasa explain=true para ver las posiciones por flujo, las contribuciones de RRF y el multiplicador de cada resultado.

Japonés, coreano y chino

  • Las secuencias de Han, Kana y Hangul sin separadores de palabras necesitan coincidencias por caracteres. Un segundo índice de secuencias de uno y dos caracteres se escribe en la misma transacción que la página.
  • Es un índice de SQLite, no un modelo. Buscar en japonés o coreano sigue sin costar ninguna llamada de API ni embeddings.
  • El texto latino sigue la vía de siempre, sin cambios. Un almacén que viene de una versión anterior rellena el índice nuevo antes de aceptar tráfico.

Tiempo: as_of

  • Pasa una fecha ISO para preguntar qué decía la wiki sobre algo en ese momento.
  • Solo registra el tiempo de ingesta: cuándo ai-memory aprendió un dato y cuándo lo reemplazó, nunca cuándo fue cierto en el mundo.
  • No reproduce el ranking que habría devuelto una búsqueda en esa fecha.
Validez temporal en la documentación

Aristas tipadas

  • El campo relations: del frontmatter acepta un conjunto cerrado: causes, fixes, contradicts. Una errata no puede crear un tipo nuevo.
  • contradicts alimenta el lint sin LLM y se reporta hasta que alguien lo reconcilia.
  • En la búsqueda solo sirven para explain: entran en el grafo como enlaces normales y no mueven el ranking, porque el benchmark no dio base para asignarles un peso. memory_read_page puede recorrerlas para listar páginas relacionadas.
Aristas tipadas en la documentación

Un solo receptor, un solo escritor.

Dos reglas sostienen casi toda la corrección: un traspaso se puede reclamar una sola vez, y solo un hilo escribe en SQLite.

Los traspasos son un protocolo

  • Un traspaso es un registro tipado: agente de origen y de destino, proyecto, cwd, resumen, preguntas abiertas, archivos tocados, siguientes pasos.
  • Aceptar es un compare and set atómico. Un segundo agente que pregunte no recibe nada.
  • El cwd coincide por límites de ruta: /repo cubre /repo/api y nunca /repo-other.
  • Un traspaso manual gana al automático. Aceptarlo expira los candidatos automáticos más antiguos en la misma transacción.
  • En un servidor compartido, un traspaso pertenece a su dueño salvo que se envíe con shared=true.

La regla del escritor único, medida

Todas las escrituras pasan por una cola acotada de 1024 hacia un solo hilo del sistema operativo. Las lecturas usan un pool aparte, de solo lectura. Una ráfaga frena a sus productores, y no se pierde ninguna escritura.

  1. 1 escritor42/s23,9 ms
  2. 8 escritores295/s3,4 ms
  3. 32 escritores698/s1,43 ms
  4. 128 escritores700/s1,43 ms
  • El techo ronda las 700 escrituras por segundo, plano de 32 escritores en adelante. A un solo escritor lo limita fsync, no la CPU.
  • Medido en un disco local rápido. Un volumen en red o lento dará cifras bastante más bajas.
  • El test ataca el store directamente y se salta la entrada HTTP.
  • Reprodúcelo con cargo test -p ai-memory-store --test writer_throughput -- --ignored --nocapture.

Las páginas de sesión viejas se puntúan, y las frías se desalojan, se compactan o se fusionan. Cómo envejece la memoria.

El código, crate por crate.

Diez crates del producto, cada uno con una función y una API tipada, sin dependencias circulares.

CrateResponsabilidad
ai-memory-coreTipos de dominio, errores, ids. Sin IO.
ai-memory-storeSQLite, el actor escritor, el pool de lectores, el cálculo del decaimiento.
ai-memory-wikiEscrituras atómicas de markdown, el file watcher, git.
ai-memory-mcpTransporte MCP y router de herramientas.
ai-memory-webVistas web y API JSON de solo lectura. Las acciones de cuenta y aprobación llaman a rutas autenticadas.
ai-memory-hooksEsquemas de payload, el sanitizer, la entrada de /hook.
ai-memory-llmFrontera de autenticación con proveedores, traits de LLM y de embedder.
ai-memory-consolidateIngesta, lint, sweep y el pipeline de auto-improve.
ai-memory-workstreamAdaptadores de solo lectura para transcripciones nativas y lanzamientos.
ai-memory-cliEl binario ai-memory y sus subcomandos HTTP, que son finos.

25 herramientas MCP, pocas a propósito

Los hooks hacen la captura rutinaria, así que los agentes rara vez tienen que llamarlas a mano.

Recuperación (7)

  • memory_query
  • memory_recent
  • memory_read_page
  • memory_read_session_observations
  • memory_briefing
  • memory_explore
  • memory_status

Traspasos (4)

  • memory_handoff_begin
  • memory_handoff_list
  • memory_handoff_accept
  • memory_handoff_cancel

Mensajes entre proyectos (4)

  • memory_message_send
  • memory_message_list
  • memory_message_pop
  • memory_message_cancel

Escritura y mantenimiento (10)

  • memory_write_page
  • memory_patch_page
  • memory_delete_page
  • memory_restore_page
  • memory_consolidate
  • memory_auto_improve
  • memory_feedback
  • memory_lint
  • memory_forget_sweep
  • memory_install_self_routing

ARCHITECTURE.md, con los 16 invariantesDecisiones de diseño y opciones descartadas

Preguntas y respuestas

¿Dónde guarda ai-memory sus datos?

En un solo directorio de datos: un repositorio git de páginas markdown en wiki/, un índice SQLite derivado en db/, segmentos saneados del workstream en raw/, el modelo local de embeddings en models/, y los logs.

¿ai-memory necesita un LLM?

No. La captura, los resúmenes de sesión, los traspasos, la indexación, la búsqueda y el resumen inicial funcionan sin ningún proveedor configurado. La consolidación con LLM, la mejora automática y el rerank son opt-in.

¿Qué pasa si el índice SQLite se pierde o se corrompe?

Reindex reconstruye páginas, enlaces y búsqueda de texto desde Markdown. No recupera sesiones, observaciones, traspasos, usuarios, claves ni auditoría que solo existen en la base.

¿Cómo ordena los resultados la recuperación?

Se fusionan cinco flujos de candidatos: texto completo FTS5, coincidencias de entidades, vecinos del grafo, observaciones y vectores opcionales. Reciprocal Rank Fusion con k=60 los combina, seguido de un ajuste acotado por la autoridad de la fuente. El reranking con LLM es opcional.

¿Cuántas escrituras por segundo aguanta?

El store mide 42 escrituras por segundo con un escritor, 295 con 8, y un techo cercano a 700 de 32 escritores en adelante. Las cifras salen de un disco local rápido, y el test ataca el store directamente, sin la entrada HTTP.

Lee los archivos que escribe.

Instálalo, ejecuta una sesión y abre la carpeta de la wiki en tu editor.