Engram

Servidor MCP autoalojado que brinda a los agentes de IA memoria persistente: fuente de verdad en Markdown, búsqueda híbrida BM25+embeddings, relaciones de grafo tipadas.

Documentación

Inkwell — Servidor MCP de Base de Conocimientos Persistente

License: MIT Docker Pulls Python 3.12+

Inkwell es un servidor de Protocolo de Contexto de Modelos autoalojado que brinda a los agentes de IA memoria persistente entre sesiones y proyectos. Tres cosas lo distinguen de otros servidores de memoria: los archivos Markdown simples son la fuente de verdad (el índice es una caché desechable que puedes eliminar y reconstruir), las entradas están conectadas mediante un grafo kb:// tipado en lugar de acumularse en una pila plana, y las actualizaciones son bi-temporales — reemplazar un hecho mantiene la versión anterior legible en lugar de sobrescribirla.

Docker Hub: foreigndmitryi/inkwell-memory · Sitio web: veronchenko.github.io/inkwell-memory

Antes llamado Engram. Renombrado en 0.14.0 — hay una docena de proyectos no relacionados llamados "Engram" y el nombre había dejado de ser localizable. No está afiliado con ninguno de ellos, ni con la distribución de teclado Engram. Consulta el registro de cambios para ver qué rompe el cambio de nombre.

Tabla de Contenidos

Concepto

Las conversaciones de los agentes terminan y se llevan su contexto consigo. Inkwell es la pieza que sobrevive: una base de conocimientos que un agente busca antes de actuar y en la que escribe después de resolver algo no obvio, para que la próxima sesión — el mismo proyecto o uno diferente — comience con lo que ya se aprendió en lugar de volver a deducirlo.

Almacena deliberadamente cero información descubrible. Si un hecho se puede extraer del código, el historial de git, los archivos de configuración o la documentación existente, no pertenece a Inkwell — para eso están los greps y las relecturas. Lo que pertenece es el tipo de conocimiento que una conversación perdería de otro modo: una decisión y las alternativas que descartó, la causa raíz de un error y su corrección, un procedimiento aprendido a las malas, una preferencia expresada una vez que debería mantenerse de ahí en adelante.

Dos cosas mantienen la base utilizable a medida que crece:

  • Atomicidad — una entrada, un hecho. remember advierte (sin bloquear) sobre encabezados Markdown, más de 3 párrafos o contenido que supere 512 B/1 KB, empujando los volcados de múltiples hechos de vuelta a entradas separadas enlazadas en lugar de un muro de texto que ninguna búsqueda clasificará bien.
  • El grafo, no una pila — las entradas se enlazan entre sí mediante referencias kb://uuid#type, de modo que los hechos relacionados (un proyecto central, sus características, un diagnóstico vinculado a uno de ellos) permanezcan navegables en ambas direcciones en lugar de vivir como filas aisladas.

Características

  • Búsqueda híbrida — SQLite FTS5 (BM25, stemming de Porter) fusionado con similitud de coseno sobre incrustaciones locales Model2Vec y un canal de coincidencia exacta ponderado por IDF sobre título/etiquetas mediante Fusión de Rango Recíproco; encuentra entradas por significado o por un nombre propio literal que BM25/incrustaciones por sí solos diluirían entre distractores léxicamente similares, con cero dependencia de la nube
  • Relaciones de grafo tipadas — enlaces kb://uuid#type entre entradas, resueltos en ambas direcciones (salientes + enlaces de retroceso) en cada recall, con un segundo salto opcional (hops=2) para ver cómo dos entradas se conectan a través de una intermedia
  • Tipos de entrada impuestos por esquemahub, decision, diagnostic, feature, procedure, integration, pattern, snippet, preference, idea — declarados en schema.json y expuestos al cliente como una enumeración, de modo que no se pueda escribir un tipo inválido; filtrables en búsqueda/lista
  • Pase de integridad doctor — una verificación impulsada por esquema sobre los archivos Markdown para detectar enlaces colgantes y reemplazados, tipos no declarados, campos de plantilla faltantes, supernodos y colisiones de etiquetas/tipos
  • Membresía estructural part_of — vincula una entrada de detalle (decision, diagnostic, feature, procedure, integration, ...) a su centro, impuesta por tipo mediante el esquema; filtrable en search/list, agrupada junto con los enlaces de retroceso kb:// en el resumen recall de un centro
  • Versionado bi-temporalremember(..., supersede=True) crea una nueva versión en lugar de sobrescribir; las versiones antiguas permanecen en el historial (include_superseded=True) en lugar de perderse
  • Detección de duplicados y sugerencias de enlacesremember compara títulos casi idénticos para evitar entradas duplicadas, y devuelve suggested_links (coincidencias por similitud de incrustaciones) para que los hechos relacionados se referencien cruzadamente en lugar de quedar huérfanos
  • Salvaguardas de atomicidad — advertencias no bloqueantes sobre antipatrones estructurales (encabezados, >3 párrafos, contenido sobredimensionado) para que la base se mantenga con un hecho por entrada a medida que escala
  • Panel de control web — vista de grafo dirigido por fuerzas, búsqueda híbrida y un panel CRUD sobre la misma base de conocimientos que usan las herramientas MCP (ver Panel de Control)
  • Tres transportes — stdio (gestionado por el agente), SSE, http-transmisible — para que el mismo servidor funcione para un agente local único o un despliegue multiagente compartido
  • Markdown como fuente de verdad — el índice SQLite es una caché reconstruible; elimínalo y ejecuta rebuild, nunca se pierde ningún dato

Comparación

InkwellMem0Zep / GraphitiLangMem
Fuente de verdadArchivos Markdown en discoBase de datos vectorial / API gestionadaGrafo de conocimiento temporalAlmacén vectorial (respaldado por LangChain)
BúsquedaBM25 + incrustaciones locales Model2Vec (fusión RRF)Similitud vectorialRecorrido de grafo + incrustacionesSimilitud vectorial
RelacionesEnlaces kb://uuid#type explícitos, escritos por el agenteImplícitas (hechos extraídos por LLM)Aristas de grafo temporal extraídas automáticamenteNinguna incorporada
Modelo temporalvalid_at/supersede bi-temporal en escrituraSobrescritura de hechosGrafo temporal nativo (aristas bi-temporales)Ninguna incorporada
DespliegueAutoalojado, imagen Docker única, sin dependencia de la nubeAPI alojada o autoalojada + base de datos vectorialAutoalojado, requiere Neo4jBiblioteca, sin servidor
Centro de diseñoDeliberadamente mínimo — cero información descubrible, el agente decide qué vale la pena conservarExtracción automática de hechos de conversacionesExtracción automática de entidades/relacionesPrimitivas de memoria componibles para agentes LangGraph

Inkwell intercambia la extracción automática (Mem0, Zep) por una base de conocimientos atómica, explícitamente enlazada y curada por el agente — sin canalización de ingesta impulsada por LLM, sin dependencia de base de datos de grafo, y el Markdown en disco permanece legible para humanos y diferenciable.

Medido Frente a una Wiki Markdown Simple

Inkwell fue comparado con la misma base de conocimientos empaquetada como una wiki Markdown ordinaria — un archivo por tema, organizado en carpetas por proyecto y categoría (decisión, diagnóstico, característica, procedimiento, ...), cada proyecto con una página de índice y enlaces cruzados entre páginas relacionadas, navegado con Read/Grep/Glob/Bash. Mismo contenido, dos formas de encontrarlo — para una cobertura de hechos equivalente, los search/recall de Inkwell usaron:

InkwellWikiMejora
Llamadas a herramientas104186-44%
Tokens totales3.87M5.91M-35%
Costo$1.31$1.62-19%
Tiempo de pared (suma)577s760s-24%
Tasa de hechos1.0000.964+3.7%

32 preguntas (de un solo salto, de múltiples saltos, negativas, translingüísticas, de reemplazo) sobre 5,070 entradas — 70 hechos curados en 4 proyectos ficticios más 5,000 entradas distractoras de texto real, de modo que la recuperación tenga que funcionar a una escala que no cabe en el contexto de un agente:

wiki/
├── Ledgerbird/                       )
├── Pipewren/                         )  4 curated projects — 70 real
├── Snipfox/                          )  decisions/diagnostics/features/
├── Featherstore/                     )  procedures/integrations/snippets
│   ├── README.md                        <- project index page, links to every entry below
│   ├── decision/
│   │   ├── offline-engine-duckdb-over-spark.md
│   │   ├── online-value-serialization-msgpack.md
│   │   └── ... (2 more)
│   ├── diagnostic/
│   │   ├── redis-memory-doubling-from-ttl-less-deprecated-feature-groups.md
│   │   └── training-serving-skew-from-tz-naive-event-timestamps.md
│   ├── feature/       (4 entries)
│   ├── integration/   (2 entries)
│   ├── procedure/     (1 entry)
│   └── snippet/       (1 entry)
├── _shared/                             cross-project patterns & preferences
└── haystack-project-00000.../00199/     200 distractor projects x 25 pages
    │                                     = 5,000 real-text (Wikipedia) pages
    ├── README.md                        <- same index-page shape as a real project
    ├── decision/   (2 entries)
    ├── feature/    (3 entries)
    ├── idea/       (7 entries)
    ├── pattern/    (4 entries)
    ├── procedure/  (1 entry)
    └── snippet/    (2 entries)

Cada carpeta de categoría es una lista plana de un archivo por entrada, y cada carpeta de proyecto (real o distractora) tiene su propia página de índice README.md que enlaza a todas ellas — estructuralmente idénticas, de modo que el brazo de la wiki no pueda distinguir un hecho curado de un distractor solo por la forma.

Un agente que ya sabe dónde mirar no necesita grep, releer y volver a grep su camino hasta allí — la ventaja de eficiencia se mantiene para una cobertura de hechos equivalente. La clasificación de recuperación también ha estado mejorando: agregar un canal de coincidencia exacta ponderado por IDF (abajo) movió MRR de 0.851 a 0.857 y recall@5 de 0.851 a 0.869, sin regresión en ningún idioma.

Patrones de Diseño

  • Fusión de Rango Recíproco — las clasificaciones de BM25 y de incrustaciones se calculan de forma independiente y se fusionan por posición de rango en lugar de puntuación bruta, evitando la necesidad de normalizar métricas de similitud incomparables.
  • Caché reconstruible sobre fuente de verdad — el índice SQLite se deriva completamente de los archivos Markdown (rebuild lo regenera desde cero); la base de datos nunca es la única copia de un hecho.
  • Versionado bi-temporalsupersede escribe una nueva entrada y apunta la anterior a ella mediante superseded_by, en lugar de sobrescribir en el lugar, de modo que el historial permanezca consultable (include_superseded).
  • Recorrido de grafo estilo HATEOAS — cada respuesta recall lleva sus propios enlaces kb:// salientes/entrantes, de modo que navegar por el grafo de conocimiento no requiera una consulta separada por salto.
  • Capa de dominio compartida, dos transportes — la API REST del panel de control y las herramientas MCP llaman a los mismos métodos KnowledgeBase/SQLiteBackend, de modo que haya exactamente una ruta de código para escrituras independientemente de qué superficie las haya activado.

Arquitectura

Markdown files  --->  Search index  --->  MCP  --->  Agent
(source of truth)     (SQLite FTS5 +      (server.py)  (Claude Code,
                        Model2Vec,                       ChatGPT, ...)
                        rebuildable cache)

Los archivos Markdown en <data-path>/entries/ son la única fuente de verdad. El índice SQLite (search_backend.py) es una caché desechable construida a partir de ellos — BM25 + incrustaciones Model2Vec fusionadas mediante Fusión de Rango Recíproco, más el grafo de relaciones kb:// — y siempre se puede regenerar con rebuild. server.py expone ese índice a un agente como herramientas MCP (remember/recall/search/...); el panel de control es un punto de entrada alternativo en la misma capa, que accede al mismo KnowledgeBase/índice directamente a través de REST en lugar de MCP, de modo que remember/delete se comporten de manera idéntica ya sea que las llame un agente o las edite manualmente en el navegador.

  • src/server.py — Definiciones de herramientas MCP (remember, recall, search, list, tags, forget, rebuild, doctor), un proceso, transporte stdio/SSE/streamable-http
  • src/database.pyKnowledgeBase: CRUD de Markdown + frontmatter YAML, asignación de UUID, detección de duplicados, lógica de supersesión bi-temporal
  • src/schema.json + src/schema.py — la taxonomía de entradas y sus reglas por tipo como datos, más el cargador que las convierte en el enum entry_type contra el que valida el cliente MCP
  • src/doctor.py — la pasada de integridad basada en esquema compartida por la herramienta doctor, las advertencias de rebuild y la verificación de conformidad de remember
  • src/search_backend.pySQLiteBackend: BM25 (FTS5) fusionado con similitud coseno de Model2Vec mediante Reciprocal Rank Fusion, más extracción de relaciones/recorrido de grafo kb://; los embeddings se calculan de forma perezosa al escribir y se almacenan como columna BLOB
  • src/dashboard/ — un segundo proceso opcional (app.py FastAPI REST + /api/graph, static/index.html lienzo de grafo en JS puro, __main__.py su propio punto de entrada uvicorn) que reutiliza el mismo KnowledgeBase
  • plugins/inkwell-hooks/ — un plugin autocontenido instalable tanto en Claude Code como en Codex (.claude-plugin/plugin.json, SessionStart/Stop/SessionEnd + una compuerta PreToolUse de buscar-antes-de-recordar, más un agente inkwell-project-onboarder solo para Claude Code) que aplica mecánicamente el flujo de trabajo buscar-primero, recordar-después en lugar de depender solo de un prompt de sistema; listado como inkwell-hooks tanto en el .claude-plugin/marketplace.json de la raíz del repositorio (Claude Code) como en plugins/marketplace.json (Codex)

En Docker, el servidor MCP y el panel se ejecutan como dos procesos en un mismo contenedor (docker-entrypoint.sh), compartiendo el mismo volumen /knowledge; el contenedor se detiene si cualquiera de los dos procesos muere.

Inicio rápido

stdio

Tu agente gestiona el servidor. Recomendado para Claude Code, ChatGPT Desktop, Cursor.

claude mcp add --transport stdio inkwell -- \
  docker run -i --rm -v ./knowledge:/knowledge foreigndmitryi/inkwell-memory

SSE

Servidor persistente en la red. Comparte conocimiento entre múltiples agentes.

docker run -d --name inkwell \
  -p 8192 \
  -v ./knowledge:/knowledge \
  foreigndmitryi/inkwell-memory --transport sse

docker port inkwell 8192   # host port Docker assigned
claude mcp add --transport sse inkwell http://your-host:<port>/sse

-p 8192 (puerto de host omitido) hace que Docker elija un puerto efímero libre en el host en lugar de fallar cuando un puerto fijo como 8192 ya está ocupado por otro contenedor — comprueba la asignación real con docker port. Usa -p 8192:8192 en su lugar si necesitas que el puerto del host permanezca fijo.

HTTP

Sin estado, balanceable de carga.

docker run -d --name inkwell \
  -p 8192 \
  -v ./knowledge:/knowledge \
  foreigndmitryi/inkwell-memory --transport streamable-http

docker port inkwell 8192   # host port Docker assigned
claude mcp add --transport http inkwell http://your-host:<port>/mcp

Multi-tenant

Un servidor, varios equipos, cada uno aislado en su propia carpeta de datos y clave API. Establece INKWELL_MULTI_TENANT=1 (requiere INKWELL_PUBLIC_URL y INKWELL_ADMIN_API_KEY, y un transporte de red — nunca stdio); src/app.py sirve entonces MCP, la interfaz de administración y el panel desde un solo proceso. Aprovisiona un equipo con inkwell add-team <name> (ejecutado mediante docker exec, consulta src/cli.py) para obtener su clave API, y luego apunta el agente de cada equipo a /mcp con esa clave como token de portador:

claude mcp add --transport http inkwell https://your-host/mcp \
  --header "Authorization: Bearer <TEAM_API_KEY>"

O como configuración mcpServers sin procesar (Claude Desktop y otros clientes):

{
  "mcpServers": {
    "inkwell": {
      "type": "http",
      "url": "https://your-host/mcp",
      "headers": {
        "Authorization": "Bearer <TEAM_API_KEY>"
      }
    }
  }
}

TeamTokenVerifier (src/server.py) aplica hash al token y lo busca en admin.db en cada solicitud — sin caché, por lo que una clave revocada deja de funcionar inmediatamente.

Búsqueda

Híbrida: SQLite FTS5 (stemming de Porter, BM25) fusionada con similitud coseno sobre embeddings locales de Model2Vec (minishlab/potion-multilingual-128M, sin dependencia de la nube) mediante Reciprocal Rank Fusion — de modo que una consulta que no comparte ninguna palabra literal con una entrada aún puede encontrarla por significado. Vuelve a solo palabras clave si el modelo de embeddings no puede cargarse. El índice sigue siendo un único archivo SQLite que puedes consultar con herramientas SQL estándar.

Herramientas

HerramientaDescripciónParámetros clave
rememberCrear o actualizar una entrada (upsert con detección de duplicados, o versionarla mediante supersede). entry_type es obligatorio, y part_of (UUIDs de hub) es obligatorio/opcional/rechazado según el tipo conforme a la regla membership del esquema. Devuelve size, atomicidad no bloqueante warnings (encabezados Markdown, >3 párrafos, >512 B / >1 KB), y suggested_links — entradas casi duplicadas/relacionadas (por similitud de embeddings) que vale la pena referenciar cruzadamente con un enlace kb://.title, content, tags, entry_type, entry_id, force, resource, supersede, part_of
recallLeer una entrada con sus relaciones de grafo (salientes + enlaces de retroceso). Devuelve size y last_modified. Los tipos de alto grado (hubs) devuelven in_digest — enlaces de retroceso agrupados por tipo de enlace, más miembros agrupados por part_of — en lugar de una lista truncada arbitrariamente.entry_id, relations_limit
searchBúsqueda híbrida de palabras clave + semántica, filtrable por etiquetas, entry_type exacto, y/o part_ofquery, tags, limit, include_superseded, entry_type, part_of
listExplorar entradas ordenadas por título, filtrable por etiquetas, entry_type exacto, y/o part_oftags, limit, include_superseded, entry_type, part_of
tagsListar todas las etiquetas con recuentos de entradas
forgetEliminar una entrada (archivo e índice). Advierte cuando otras entradas aún enlazan a ella.entry_id
rebuildReconstruir el índice de búsqueda a partir de archivos Markdown; también ejecuta doctor
doctorVerificar cada entrada contra schema.json: objetivos kb:// colgantes/supersedidos, tipos no declarados, campos obligatorios de frontmatter y cuerpo de plantilla faltantes, supernodos, colisiones de etiquetas/tipos

Esquema de entradas

La taxonomía de entradas y sus reglas por tipo viven en schema.json, no en Python: qué campos de frontmatter requiere un tipo, qué campos de cuerpo de plantilla debería llevar, si la búsqueda puede potenciarlo por uso, y si recall procesa sus enlaces de retroceso. entry_type se expone al cliente MCP como un enum construido a partir de ese esquema, de modo que un tipo no declarado se rechaza antes de que la llamada llegue al servidor.

Orden de resolución, gana el primero encontrado: <data-path>/schema.json, luego el src/schema.json empaquetado. Un archivo de usuario reemplaza por completo al empaquetado — nunca se fusionan, así que copia el predeterminado y edítalo. El esquema se lee una vez al inicio, por lo que editarlo requiere reiniciar el servidor. Las entradas escritas a mano aún pueden llevar un tipo no declarado; doctor informa de esos casos.

Panel

Una interfaz web para explorar visualmente y editar a mano la misma base de conocimiento que usan las herramientas MCP — sin duplicación de protocolo, cada acción pasa por KnowledgeBase.

  • Grafo dirigido por fuerzas de todas las entradas y sus relaciones kb:// — haz clic en un nodo para inspeccionarlo, haz clic en una ficha de leyenda para filtrar por tipo (las coincidencias permanecen iluminadas, las demás se atenúan)
  • Búsqueda híbrida sobre el mismo índice BM25 + semántico que la herramienta MCP search, con filtros de etiqueta y entry_type
  • Panel CRUD para crear, editar, superseder o eliminar entradas sin tocar archivos Markdown a mano — las relaciones de grafo entrantes/salientes se muestran junto a los campos
  • Interfaz oscura, densa y sin adornos — una herramienta de mantenimiento, no una aplicación de consumo (consulta PRODUCT.md/DESIGN.md)

Deshabilitado por defecto (el contenedor solo ejecuta el servidor MCP). Actívalo como segundo proceso en el mismo contenedor:

docker run -d --name inkwell \
  -e INKWELL_ENABLE_DASHBOARD=1 \
  -p 8192 -p 8193 \
  -v ./knowledge:/knowledge \
  foreigndmitryi/inkwell-memory --transport sse

docker port inkwell 8193   # dashboard host port

O ejecútalo de forma independiente localmente: python -m dashboard (consulta Configuración para INKWELL_DASHBOARD_HOST/INKWELL_DASHBOARD_PORT).

Relaciones de grafo

Enlaza entradas con URLs kb://uuid#type en el contenido Markdown:

This service runs on [Saturn](kb://a1b2c3d4-...#runs-on)
and depends on [PostgreSQL](kb://f9e8d7c6-...#depends-on).

recall devuelve ambas direcciones, más metadatos de tamaño:

{
  "id": "a1b2c3d4-...",
  "title": "My API Service",
  "content": "...",
  "tags": ["..."],
  "size": 1024,
  "last_modified": "2026-03-14",
  "relations": {
    "out": [{"type": "runs-on", "id": "e5f6...", "title": "Saturn"}],
    "in": [{"type": "depends-on", "id": "b7c8...", "title": "Frontend App"}]
  }
}

Como HATEOAS para el conocimiento — cada respuesta lleva los enlaces para navegar el grafo.

Ejemplos de uso

Almacenar conocimiento

Pide a tu agente:

"Recuerda que nuestra API se ejecuta en el puerto 8080 y depende de PostgreSQL 15."

Inkwell crea un archivo Markdown con un UUID único, lo indexa y confirma. El agente ahora puede recordar este dato en cualquier sesión futura.

Buscar

"¿Qué sabemos sobre PostgreSQL?"

Inkwell busca en todas las entradas por contenido, título y etiquetas. Los resultados se ordenan por relevancia.

Navegar el grafo

"¿Qué depende de PostgreSQL?"

Si las entradas enlazan al artículo de PostgreSQL con kb://uuid#depends-on, Inkwell devuelve todos los enlaces de retroceso — mostrando cada servicio que depende de él, sin que el agente tenga que buscar cada uno por separado.

Compartir conocimiento entre agentes

Inicia Inkwell con transporte SSE o HTTP. Múltiples agentes — incluso de diferentes proveedores (Claude, ChatGPT, Copilot) — se conectan al mismo servidor. Lo que un agente recuerda, todos los demás pueden recordarlo.

Agent A: "Remember that the deploy key rotates every 90 days."
Agent B: "When does the deploy key expire?"
→ Agent B finds the answer immediately.

Indica a tu agente

Añade esto a tu prompt de sistema o a las instrucciones del proyecto para que tu agente use Inkwell como reflejo, no como idea tardía:

Inkwell is your persistent memory. Using it is mandatory, not optional.

Inkwell stores ZERO discoverable information. If you can derive it from
code, git history, configuration files, or existing documentation, it
does not belong in Inkwell. Inkwell captures decisions and their context,
diagnostics and their root causes, procedures learned the hard way —
the kind of knowledge that is lost when a conversation ends.

Before working on any topic: search Inkwell first. Always. Even if you think you know.
Before answering a question about infrastructure or architecture: search first.
Before proposing a solution: check if a past decision exists in Inkwell.

After resolving a diagnostic: remember the root cause and the fix.
After executing a procedure: remember the steps.
After making an architecture decision: remember the choice and the rationale.
After discovering something about the infrastructure: remember it.

Un prompt de sistema es fácil de olvidar a mitad de sesión. plugins/inkwell-hooks/ incluye un plugin autocontenido (SessionStart, Stop, SessionEnd, PreToolUse handlers, más un agente inkwell-project-onboarder solo para Claude Code) que empuja mecánicamente al agente a buscar en Inkwell antes de empezar a trabajar y le recuerda remember los cambios no triviales antes de terminar, en lugar de depender de que recuerde esta sección sin que se le pida. Funciona tanto en Claude Code como en Codex — instala con /plugin marketplace add <this-repo> y luego /plugin install inkwell-hooks@inkwell-memory (Claude Code), o codex plugin marketplace add <this-repo>/plugins y luego codex plugin add inkwell-hooks@inkwell-memory (Codex) — consulta plugins/inkwell-hooks/README.md para ver qué hace cada hook y el flujo de instalación completo.

Desactivar la memoria automática integrada de Claude Code

Claude Code incluye su propia memoria automática (MEMORY.md bajo ~/.claude/projects/<project>/memory/, cargada en cada sesión). Ejecutarla junto a Inkwell significa que dos sistemas escriben notas superpuestas y compiten por la atención del agente, lo que estorba más de lo que ayuda. Desactívala en settings.json:

{
  "autoMemoryEnabled": false
}

O mediante variable de entorno (tiene prioridad sobre la configuración y el interruptor /memory): CLAUDE_CODE_DISABLE_AUTO_MEMORY=1. Consulta la documentación de memoria de Claude Code para más detalles.

Configuración

Todas las opciones tienen respaldos de variable de entorno INKWELL_*. Los argumentos de CLI tienen prioridad.

OpciónVariable de entornoPredeterminadoDescripción
--data-pathINKWELL_DATA_PATH/knowledgeRuta raíz para los datos de conocimiento
--transportINKWELL_TRANSPORTstdioTransporte MCP
--hostINKWELL_HOST0.0.0.0Dirección de escucha (SSE/HTTP)
--portINKWELL_PORT8192Puerto de escucha (SSE/HTTP)
--embedding-modelINKWELL_EMBEDDING_MODELminishlab/potion-multilingual-128MModelo Model2Vec para búsqueda semántica
INKWELL_ENABLE_DASHBOARDsin establecer (desactivado)Un valor verdadero (1/true/yes) inicia el panel como segundo proceso junto al servidor MCP
--host (panel)INKWELL_DASHBOARD_HOST0.0.0.0Dirección de escucha del panel
--port (panel)INKWELL_DASHBOARD_PORT8193Puerto de escucha del panel (se usa el primer puerto libre igual o superior a este)
INKWELL_QUERY_LOGsin establecer (desactivado)Ruta de archivo; cuando se establece, search/recall añaden un rastro JSONL de cada llamada para análisis de calidad de recuperación

Formato de almacenamiento

Las entradas son archivos Markdown con frontmatter YAML en <data-path>/entries/:

---
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
title: Entry Title
tags: [infrastructure, postgresql]
type: decision
resource: /path/to/relevant/file
---

Markdown content here...

type es obligatorio en cada llamada a remember (un campo dedicado, no parte de tags) — clasifica la entrada (hub, decision, diagnostic, procedure, preference, snippet, ...) y es filtrable mediante search/list. resource es opcional: una ruta canónica de archivo/carpeta que la entrada describe. Las entradas heredadas escritas antes de que existieran estos campos aún se leen correctamente.

El índice de búsqueda es una caché reconstruible en <data-path>/index/inkwell.db. Elimínalo y rebuild — nunca se pierden datos. rebuild también informa advertencias de conformidad con el esquema (falta type, resource malformado) en las entradas existentes.

Desarrollo

# Build
docker build -t inkwell .

# Test (separate Dockerfile — pytest/tests/ never ship in the production image)
docker build -f tests/Dockerfile -t inkwell-test .
docker run --rm inkwell-test

# Run locally (SSE)
docker run -d --name inkwell -p 8192 -v ./knowledge:/knowledge inkwell --transport sse

Licencia

MIT