Skip to main content
Glama

蒸留蔵 — distill-kura

Una memoria a largo plazo para agentes que se destila, no se acumula. El recuerdo funciona por significado, la escritura está controlada por evidencia, y un servidor puede contener varias memorias separadas — una por modo de agente — de modo que cambiar de modo cambia lo que el agente recuerda.

Se distribuye como un plugin de DeepSeek Harness, un servidor MCP para cualquier otro host, un servicio HTTP y una biblioteca de Python. Solo biblioteca estándar; sin base de datos vectorial, sin embeddings, sin framework.

        ┌── recall ──────────────────────────────────────────────┐
        │  question → whole index in one prompt → picked slugs   │
        │           → walk [[links]] → the neighbourhood         │  ~0.4 s
        └────────────────────────────────────────────────────────┘
        ┌── distil ──────────────────────────────────────────────┐
        │  journal → classed evidence → candidates → GATE        │
        │  → new? → composed → draft → judged → poured           │
        └────────────────────────────────────────────────────────┘

Por qué existe esto

Dos fallos matan la memoria a largo plazo de un agente, y la matan desde lados opuestos.

La recuperación por palabras clave pierde lo que necesitabas. Una pregunta sobre "chips de inferencia SSD" no comparte ninguna palabra con una memoria titulada "ejecutando el modelo de 2.6T desde un nivel SSD" — sin embargo, son el mismo tema. La búsqueda de palabras no devuelve nada; el agente responde desde la nada. La solución aquí no son los embeddings sino el reconocimiento: el índice completo (una línea por memoria, escrita como un disparador de reconocimiento) entra en un solo prompt, y un modelo pequeño nombra lo que es relevante para la pregunta. Un índice de ~500 memorias son alrededor de 6k tokens — un pequeño porcentaje de una ventana de contexto moderna, y reside en la caché de prefijo.

Escribirlo todo envenena el almacén. Un agente afirma algo; un destilador ingenuo registra la afirmación como un hecho; el siguiente agente la lee como verdad absoluta y la repite con más confianza. Ese bucle se refuerza a sí mismo, y las instrucciones del prompt no lo detienen — medido, no asumido. Así que la ruta de escritura está controlada por Python determinista: cada memoria candidata debe llevar citas que existan carácter por carácter en el material bruto, etiquetadas con su procedencia.

clase

qué es

qué autoriza

[USER]

las palabras del humano

"ellos decidieron", "ellos preguntaron"

[TOOL]

salida de máquina

números — la única fuente

[ACT]

una herramienta invocada

"esto se hizo"

[SELF]

la prosa del agente

un juicio, en primera persona, nunca un hecho desnudo

Una cita que no se encuentra textualmente se descarta. Un candidato sin ninguna cita superviviente se desecha. Un número sin un [TOOL] detrás se elimina. El texto que atribuye al humano una decisión, cuando no sobrevive ninguna cita [USER], se rechaza en la última puerta. Las ideas son bienvenidas — van a un archivo semilla, nunca al almacén, y se gradúan solo cuando la evidencia posterior las confirma.


Related MCP server: Memsolus MCP Server

Inicio rápido

git clone https://github.com/lna-lab/distill-kura && cd distill-kura
pip install -e .                       # or just run: python3 -m distill_kura.cli

cp kura.example.toml kura.toml         # edit: one model endpoint is enough to start
kura init main --path ~/kura/main      # create an empty store
kura serve                             # http://127.0.0.1:8085
curl -s -X POST localhost:8085/recall -H 'content-type: application/json' \
     -d '{"question":"what did we decide about the archive disk?","hops":1}'

Lleva el índice, para que el agente siempre sepa lo que se sabe:

kura weave                             # build the three-layer cloth
kura prefill                           # the block to put in the system prompt

Aliméntalo con las transcripciones de tu agente:

kura distill run      # drink a batch → candidates → gate → drafts
kura distill drafts   # look at what it wants to write
kura distill drain    # the scribe re-reads each draft cold: pour / fix / toss
kura distill night    # stay resident and do it whenever things go quiet

Nada entra en el almacén hasta drain (o un pour ejecutado a mano). Los borradores llevan su evidencia en un comentario HTML, para que siempre puedas ver por qué existe una memoria.


El mapa residente

El recuerdo por herramienta responde "¿qué sabes sobre X?" — pero solo una vez que el agente ha decidido preguntar. Nunca responde a la pregunta que el agente no piensa en hacer: ¿hay algo aquí en absoluto? Un agente que no puede ver el mapa no sabe lo que le falta, así que adivina, y una suposición segura sobre tu hogar es precisamente el fallo que este proyecto existe para prevenir.

Así que el índice también se lleva: un bloque permanente en el prompt del sistema, en cada turno.

kura weave      # re-weave the index into the three-layer cloth
kura prefill    # print the block a host should inject

Tres capas, porque el detalle solo compensa para cosas recientes

Una prueba A/B a ciegas — 20 preguntas, índice grueso vs índice reducido, puntuado sin saber cuál era cuál — decidió la forma:

banda

grueso

reducido

general

9

11

eventos recientes

4

1

doctrina

1

4

saltos entre dominios

1

4

Las líneas de doctrina eran idénticas byte a byte en ambos índices, y el índice reducido aún ganó esa banda: un entorno más ligero hace que las líneas permanentes funcionen mejor. El detalle no es la fuente de la perspicacia. Gana su lugar solo donde las cosas aún se están moviendo.

capa

regla

línea

fijado

frontmatter type en pinned_types

se mantiene completo

reciente

cambiado dentro de fresh_days

se mantiene completo

disparador

todo lo demás

comprimido a ~trigger_tokens

Las líneas de disparador las escribe el modelo scribe y se cachean en un libro mayor con clave en la descripción y el presupuesto, de modo que un re-tejido en estado estacionario no cuesta nada. Sin modelo accesible, el telar recorta mecánicamente en su lugar — un sistema de memoria no debe quedarse en blanco porque una GPU esté caída.

La edad no es mtime. cp -r, una restauración o un checkout restablecen cada marca de tiempo, todo el índice se vuelve "reciente", nada se recorta, y el mecanismo se ha apagado silenciosamente. Así que el telar prefiere una fecha escrita dentro de la memoria, y desconfía de cualquier mtime que una quinta parte del almacén comparta con un día calendario.

Dónde va, y por qué es una decisión de caché

- id: kura
  name: distill-kura
  config: { store: eq, promptOrder: -50 }   # before the persona

Una caché de prefijo se pierde desde el primer byte cambiado en adelante — medido en un servidor local: un preámbulo idéntico de 4.029 tokens se re-preció de 0.68 s a 0.14 s, añadir al final se mantiene en 0.14 s, y una palabra añadida al frente cuesta toda la caché (0.66 s). La persona normalmente lleva un reloj, así que cambia cada minuto; el mapa es el bloque más grande del prompt y cambia unas pocas veces al día. La cosa grande y estable va delante de la cosa que hace tictac.

El bloque en sí, por tanto, no contiene fecha, ni reloj, ni contador — y build() rechaza un encabezado que los tenga, en tiempo de construcción en lugar de a través de turnos misteriosamente lentos tres semanas después.

Nunca entrega medio mapa

situación

lo que recibe el agente

todo bien

el mapa, entre los marcadores <<<KURA-MAP>>>

por encima de budget_fraction

el mapa completo, y una advertencia en el JSON (nunca en el texto — un banner es contenido volátil)

por encima de hard_fraction

un stub sin líneas de índice, que dice que el mapa falta en lugar de estar vacío

kura inalcanzable

una nota explícita de que el mapa falta, nunca una cadena vacía

Un mapa truncado es el peor artefacto disponible: parece completo, y cada memoria por debajo del corte parece no existir. weave acortará la ventana de recientes para que quepa, pero nunca eliminará una línea — y si ningún ajuste alcanza el presupuesto, lo dice, conserva el mejor mapa y te dice dónde está el peso.

Cómo llevarlo a un host

host

mecanismo

DSH

plugin nativo — una systemPrompt.section, actualizada en segundo plano

Claude Code, VS Code, Goose

MCP instructions lleva un puntero corto (límite de 2KB); el mapa en sí viene de la herramienta kura_map o de un hook de sesión que ejecuta kura prefill

Claude Desktop, claude.ai

ignora instructions por completo — usa kura_map

cualquier otra cosa

GET /prefill?format=text, o kura prefill en un hook de shell

El campo instructions de MCP es un MAY en la especificación, y un índice de 9.000 tokens no puede viajar a través de un límite de 2KB de todos modos, así que este proyecto no finge lo contrario.


Modos: más de un kura

Una única memoria que sirve tanto para "ayúdame a construir esto" como para "ayúdame a pensar esto" no sirve bien a ninguna: el recuerdo que te ayuda a depurar es ruido en una conversación sobre qué hacer a continuación. Así que un almacén es un directorio, y un modo se asigna a un almacén.

[stores.maker]
path = "~/kura/maker"
label = "maker mode — building things"

[stores.eq]
path = "~/kura/eq"
label = "EQ mode — talking things through"

[modes]
maker = "maker"
eq    = "eq"

Cada ruta toma un selector, así que un proceso sirve a todos:

curl -s -X POST localhost:8085/recall -d '{"question":"...","mode":"eq"}'
curl -s localhost:8085/index?store=maker
curl -s localhost:8085/s/eq/doctor          # path form, for clients that only vary a base URL

Los almacenes no comparten memorias, ni índice, ni marca de agua del destilador. Cambiar de modo cambia genuinamente lo que se recuerda — no la misma memoria con una voz diferente.

La sala se elige antes de la conversación. Un modo es lo que envía el host — un preset de DSH, KURA_STORE en un entorno MCP, -s en la CLI — y es el hogar de toda la sesión. Nada en este proyecto lee un mensaje y decide a qué almacén pertenece; una conversación que se desvía de construir a sentir se queda donde empezó, y el host puede ofrecer otra sala para la siguiente sesión. Un selector desconocido es un error en la puerta, nunca una caída silenciosa al valor por defecto.

Una sala, muchas etiquetas. Una memoria vive en exactamente un almacén y puede llevar varias etiquetas que describen su carácter (decision, landmine, emotion-carried, …). Las etiquetas son palabras, no pesos: nada las clasifica, nada las cuenta, y una memoria de Develop etiquetada como emotion-carried sigue siendo una memoria de Develop. No hay ningún comando que mueva o copie una memoria a otro almacén, y un cambio de modo afecta solo a sesiones futuras. El mismo tema planteado en dos salas produce dos memorias, cada una destilada de la evidencia de esa sala — el "lo que aprendimos" de Research y el "lo que hicimos" de Develop son hechos diferentes, y nada cruza el límite para deduplicarlos.

Una sala amplia recuerda un poco más suavemente. Los almacenes estrechos con estatutos fijos reconocen con nitidez. Se espera que un almacén que acepta cualquier cosa — una sala USER que sigue a la persona en lugar de un propósito — sea más flexible, y a cambio es aquel cuya comprensión puede crecer: un profile.md junto a su estatuto, en frases, leído después del estatuto, redactado a partir de sus propias memorias y aplicado por una persona. Cinco salas así, con sus estatutos y una configuración, están en examples/rooms/.

Independiente como enrutamiento, no como confidencialidad. El servidor no tiene autenticación, así que cualquier proceso que pueda alcanzar su puerto puede nombrar cualquier almacén que contenga. Vincular un agente mantiene un modelo en su carril; no mantiene a un proceso fuera. Un nivel de confianza por proceso — docs/TRUST.md es corto y vale la pena leerlo antes de que entre un almacén privado. También cubre los dos límites que son fáciles de pasar por alto: dos almacenes que beben de una misma raíz de diario, y dos almacenes detrás de un mismo endpoint de modelo.

Con DeepSeek Harness

DSH cambia persona y herramientas según el preset del agente. distill-kura cambia memoria según el almacén. Vincúlalos y un cambio de preset mueve todo el yo:

# .agent-presets/eq/agent.cordis.yml
- id: kura-eq
  name: distill-kura
  config:
    url: http://127.0.0.1:8085
    store: eq            # this preset's memory
    readonly: true       # the CLIENT's own switch: do not even offer a write tool
    # (the store's own `write_policy` is the authority; this just keeps the tool
    #  out of the model's hands. Naming a store already binds the preset.)

Una dependencia, y por qué es un peer. El plugin importa defineTool de @deepseek-ai/dsh-tools. Una segunda copia local al perfil puede dividir la identidad Symbol local del paquete — incluso en la misma versión — y hacer que la primera llamada a la herramienta falle en undefined.prepare. Por lo tanto, el plugin declara el paquete como un peer "*" para que el perfil suministre su copia sin un desajuste de versión. Una copia física obsoleta aún puede requerir deduplicación; consulta las comprobaciones de instalación en examples/dsh-presets/.

Deja allowSwitch en su valor por defecto y el agente también obtiene kura_use, para que pueda moverse entre kura a mitad de conversación sin un cambio de preset. Herramientas: kura_recall, kura_read, kura_doctor, kura_list, kura_use y kura_remember (solo cuando el almacén es escribible). El cableado completo, incluido el puente MCP y la regla de reino isolate para filas de servicio, está en examples/dsh-presets/.

Persona es el negocio del anfitrión, no el nuestro. Este proyecto nunca renderiza ni inyecta una persona; solo registra, por almacén, qué archivo de persona le corresponde, legible en GET /profile?store=eq para que las dos mitades puedan mantenerse sincronizadas por quien sea dueño del preajuste. Las instrucciones de agente también permanecen con el mecanismo AGENTS.md del anfitrión; consulte AGENTS.md en este repositorio para las convenciones que un agente que trabaje en este código base debe seguir.

Con cualquier host MCP

{ "mcpServers": { "kura": {
    "command": "python3", "args": ["-m", "distill_kura.mcp"],
    "env": { "KURA_URL": "http://127.0.0.1:8085", "KURA_STORE": "eq", "KURA_READONLY": "1" }
}}}

Deje KURA_STORE sin definir para el modo libre: las herramientas aceptan un argumento opcional store y kura_use cambia para la sesión.


Modelos: uno por defecto, mejore un rol a la vez

Tres roles, no tres máquinas:

rol

cuándo se ejecuta

quiere

thinker

cada recuerdo

pequeño y rápido; debe juzgar relevancia por significado

brain

destilando: lee un lote completo de diario

longitud de contexto y paciencia

scribe

destilando: escribe la memoria, luego juzga borradores

buena prosa en su idioma, juicio

Declare solo [models.thinker] y un modelo hace los tres — el modelo con el que habla también es el editor que escribe y juzga sus memorias. Ese es el valor predeterminado y es uno justo: un modelo GPU capaz hace el trabajo del editor lo suficientemente bien en sus minutos inactivos, y kura tend lo detiene en el momento en que usted regresa (consulte "Sin supervisión" más abajo).

La ruta de mejora es darle al editor su propio asiento — un modelo más grande, una API en línea, o un modelo de CPU que no compite por la GPU en absoluto, para que el mantenimiento pueda continuar mientras usted habla. La casa donde se construyó esto ejecuta un MoE de 1 billón de parámetros en CPU a aproximadamente 3 tokens por segundo como editor: lento, pero nunca toca el asiento que la conversación usa, y las memorias que escribió durante cinco días son un tercio del almacén hoy. Mejore cualquiera de los otros roles de forma independiente — un modelo local más grande, o una API en línea (cualquier /chat/completions compatible con OpenAI; la clave se lee de una variable de entorno que usted nombra, nunca se almacena en la configuración):

[models.thinker]                       # always-on, local, small
url = "http://127.0.0.1:8000/v1"
model = "local-small"

[models.scribe]                        # upgrade just the writing
url = "https://api.example.com/v1"
model = "big-model"
api_key_env = "EXAMPLE_API_KEY"

Dos cosas que esto maneja por usted: los dialectos de esfuerzo de razonamiento difieren según la familia de modelos (reasoning_effort, thinking_effort, enable_thinking), por lo que todos se envían — uno desconocido es ignorado por la plantilla, mientras que un modelo dejado en pensamiento profundo por defecto puede gastar todo su presupuesto razonando y no devolver nada. Y el texto de la carta se coloca byte-idéntico al inicio del prompt de cada rol, de modo que en un modelo local lento los tres roles comparten un prefijo en caché en lugar de pagar tres prefills.

Un editor lento necesita el prefijo. La carta se encuentra byte-idéntica al inicio de cada llamada, por lo que un editor de CPU a 3 tok/s paga su prefill una vez por silencio, no una vez por borrador; en llama.cpp, mantenga --cache-reuse 0 fuera de la mesa para modelos recurrentes y deje que el servidor mantenga sus ranuras calientes (--slot-save-path). Las llamadas del editor son las que esperan una hora (timeout=3600) a propósito.

Si el thinker está caído, el recuerdo no se queda en silencio — cae a la superposición de palabras y etiqueta la respuesta como how=words, que las herramientas muestran como ⚠ degradado. La degradación silenciosa es peor que la degradación.

Sin supervisión: kura tend

El destilador, el vertedor y el telar están destinados a ejecutarse en las horas tranquilas, y el vigilante que decide cuándo es eso no necesita modelo:

kura distill catchup -s maker   # first: start from today, do not drink a year of history
kura tend -s maker              # stays resident; one process per store
kura tend -s maker --once       # one tick, for a scheduler or a test

Ejecute catchup una vez cuando apunte un destilador a un diario que nunca ha visto — de lo contrario, su primer acto es beber toda la historia, que para un diario de un año son días de tiempo de modelo gastados en reaprender lo que el almacén ya puede saber. Solo mueve las marcas hacia adelante, por lo que nunca puede perder progreso.

"Tranquilo" es el mtime del archivo de diario más reciente. Después de idle_min (10) de silencio, drena los borradores en espera (el editor lee cada uno en frío: verter / arreglar / desechar), o ejecuta una pasada de destilación cuando no hay ninguno; cuando algo se vertió, re-teje el mapa residente una vez; y ordena el índice una vez por silencio. Una pista que no tenía nada que hacer sale con código 2 y descansa durante backoff_min (20), por lo que un diario vacío no gira. Cuenta trabajo — vertido, desechado, arreglado, redactado — nunca lanzamientos. La salida de cada pista se mantiene en _still/tend.log. Y escribe un latido que kura doctor lee (tending.alive), porque un vigilante que muere en silencio es el único fallo que un vigilante no debe tener.

Cuando el diario cambia, una pista en ejecución se detiene: el editor suele ser la misma GPU con la que usted está a punto de hablar. Con el editor en un asiento separado — un modelo de CPU, otra máquina — establezca yield_on_return = false bajo [distill] y un veredicto en vuelo se deja terminar. Este es el vigilante con el que la casa ejecutó su editor de CPU durante cinco días, reconstruido con las lecciones que enseñó; docs/OPERATING.md tiene la unidad systemd.

Lo que este proyecto no incluye: un bucle de investigación autónomo que lea artículos y haga crecer el almacén por sí mismo. La casa tiene uno; necesita un modelo que pueda dejarse solo durante una hora por pregunta, y sus resultados no son evidencia en el sentido que la puerta usa. Se mantiene en el lado de la casa de la línea.


Cómo se ve una memoria

Un archivo, un hecho.

---
name: archive-on-slow-disk
description: the archive lives on the slow disk; the fast one stays scratch
metadata:
  type: project          # user | feedback | project | reference
  tags: ["decision", "landmine"]
  evidence_manifest: sha256:…
belongs_because: this store keeps how the machine is laid out and why
keep: which disk, and the reason
may_fade: the df figures from that afternoon
---

The archive goes on the slow disk. The fast disk is scratch space.

**Why:** the other way round burns write endurance for nothing.
**How to apply:** check which disk a target directory is on before writing there.
Related: [[disk-layout]]

Y una línea en MEMORY.md:

- [Archive on the slow disk](archive-on-slow-disk.md) — the archive lives on the slow disk; the fast one stays scratch

Esa línea es lo único que se lee cada vez. Es un disparador de reconocimiento, no un resumen: nombres propios, números, ⚠️ minas terrestres, la conclusión alcanzada. Si una línea pudiera intercambiarse con la línea de otra memoria y aún así leerse bien, no está haciendo su trabajo — kura distill tidy encuentra los casos mecánicamente detectables y los reescribe.

Las cuatro líneas bajo metadata/en la parte superior son curaduría, no hechos: tags son palabras sobre el carácter de la memoria — varias es normal, y una memoria escrita antes de que existieran simplemente no tiene ninguna — y las tres oraciones dicen por qué pertenece en este almacén, qué significado debe sobrevivir a cualquier adelgazamiento posterior, y qué detalle no necesita. El destilador las propone contra la carta del almacén; las etiquetas que afirman algo sobre el humano (entrusted, emotion-carried, recurred) se verifican contra las citas y la verificación se registra en el manifiesto. recurred se escribe una vez, por el destilador, cuando el humano vuelve a mencionar un tema desde otra sesión — es una propiedad, no un contador, y no hay número detrás.

kura doctor informa conteos, enlaces muertos, islas (memorias a las que nada enlaza), deriva del índice, líneas de etiqueta que no puede leer, manifiestos a los que una memoria apunta que ya no existen, el estado del perfil aprendido, y la capacidad del almacén en cuatro unidades lado a lado — memorias, tokens de índice, tokens de cuerpo, bytes — con limit y pressure dejados None. Es el ojo que el metabolismo necesita. Lo que sucede cuando un estante está lleno no está decidido aún: consulte docs/DESIGN.md §8.


La superficie HTTP

ruta

qué hace

POST /recall

{question, hops, top, chars, total_chars, store|mode} → seleccionado, recorrido, contexto. chars es por memoria; total_chars es un límite duro en todo el contexto

POST /remember

{slug, description, body, type, title, tags, belongs_because, keep, may_fade} — una escritura DIRECTA, rechazada a menos que write_policy = "direct-allowed"

POST /annotate

{slug, tags, belongs_because, keep, may_fade} — fusiona etiquetas / las tres oraciones en una memoria existente. La puerta directa: mismo rechazo que /remember. Una fusión que no agrega nada no toca nada

GET /index

el índice crudo

GET /prefill

el bloque residente, listo para inyectar (&format=text para un gancho)

GET /memory/<slug>

una memoria completa, con sus tags y annotations

GET /doctor

salud de un almacén (?all=1 para cada almacén)

GET /stores

almacenes, modos, y qué modelo llena cada rol

GET /profile

la carta del almacén, el perfil aprendido con su estado (ausente / presente / roto), y un puntero a su persona (nunca renderizado aquí)

GET /health

vivacidad

Cualquier ruta acepta ?store= / ?mode=, un campo store/mode en el cuerpo, o el prefijo de ruta /s/<name>/…. Sin autenticación: enlace a loopback, o ponga algo delante.


Notas de diseño que vale la pena leer antes de cambiar cosas

  • docs/DESIGN.md — por qué el reconocimiento supera a la búsqueda, qué compra la puerta, y el fallo que motivó cada mecanismo.

  • docs/OPERATING.md — ejecutarlo residente, programadores y códigos de salida, copias de seguridad, qué vigilar.

  • docs/TRUST.md — qué es y qué no es un límite de almacén, políticas de escritura, y los dos límites que son fáciles de pasar por alto (diarios compartidos, modelos compartidos). Léalo antes de que un almacén privado entre.

Algunas decisiones que parecen extrañas hasta que se topa con lo que previenen:

  • Reservar antes de beber. El destilador reclama un tramo de diario antes de leerlo, bajo un candado, y las marcas de agua solo avanzan. Dos destiladores cada uno escribiendo su propia instantánea borraron el progreso del otro y re-bebieron la misma agua una docena de veces.

  • Las marcas de agua son unidades por adaptador. Desplazamientos de bytes para transcripciones de solo anexo, números de secuencia para archivos que se reescriben (un desplazamiento de bytes en un archivo re-comprimido es una mentira).

  • Supresión de eco. Una cita que ya existe en el almacén no es material nuevo — es el almacén leyéndose a sí mismo a través de un resultado de herramienta. Sin esto, un sistema de memoria redescubre y re-registra sus propios contenidos para siempre.

  • La última puerta es un modelo, no un humano. Si una persona debe aprobar cada borrador, el sistema ha convertido silenciosamente a esa persona en su cuello de botella, y los borradores se acumulan para siempre. Nada en el bucle puede requerir a alguien que no esté siempre presente.

  • kura distill run sale con código 2 cuando no había nada que hacer. Un programador debe poder distinguir "hizo trabajo" de "no encontró nada", o un perro guardián gira en una cola vacía y mata de hambre los pasos que necesitan el tiempo de inactividad.

Medirlo, en lugar de afirmarlo

Dos preguntas se responden con un número y no deberían.

¿Cuánto más pequeño? store_ratio = tokens en las memorias e índice / tokens del diario crudo realmente consumido. ¿Qué se perdió? Esa es una medición diferente, y un almacén que conserva una memoria de cada cien obtiene una puntuación hermosa en la primera mientras es inútil.

kura bench compress                       # what this store cost, from the distiller's own metrics
kura bench compress --tokenizer-command "./count-tokens"   # exact, not estimated
kura bench retention --questions bench/fixtures/questions.json

Medido aquí, con los fixtures incluidos y el estimador integrado:

corpus

store_ratio

scripts/demo-clean-room.sh (charla ordinaria, mayormente relleno)

0.18

bench/fixtures/corpus.jsonl (denso: cada línea es señal)

1.14

El segundo no es un error. En material donde no hay relleno, destilar no comprime — cada memoria añade su por qué y cómo aplicarla, y el almacén sale ligeramente más grande que la transcripción. La proporción es una propiedad del corpus, no de esta herramienta, por eso no hay un número destacado aquí y por eso el comando informa con qué contó.

La retención se puntúa sin modelo: cada hecho plantado lleva un marcador que debe aparecer en lo que devuelve la recuperación, por lo que la puntuación es reproducible en la máquina de otro. Los distractores invierten — un hecho marcado con must_not_store cuesta un punto si el almacén lo conservó, porque un sistema de memoria se juzga tanto por lo que rechaza como por lo que conserva.

score 1.0 (10/10)   decision 1/1  number 2/2  negation 1/1  reversal 1/1
                    conditional 1/1  landmine 1/1  returning 1/1  distractor 2/2

Eso son diez hechos plantados en un dispositivo de prueba sintético, destilados por un Qwen3.8-27B local (NVFP4) como cerebro y escriba con max_items = 8, coverage_passes = 2, y puntuados con el mismo modelo como pensador. Un modelo diferente dará una puntuación diferente: la puntuación mide un canalización-más-modelo, y el dispositivo de prueba existe para que el modelo sea lo único que varíe. Mide si un hecho es localizable, no si la respuesta se lee bien — juzgar la prosa necesita un modelo, y entonces el punto de referencia deja de ser reproducible.

kura distill run escribe una línea por lote en _still/metrics.jsonl, que es de donde proviene el lado bruto. El lado canónico cuenta solo memorias cuya evidencia manifiesta apunta a un lote registrado — dividir un almacén completo por el material bruto de unos pocos lotes es un número en la dirección equivocada por un orden de magnitud, y la primera versión de este comando hizo exactamente eso. Las memorias que preceden a los manifiestos se informan como unattributed, no se incluyen silenciosamente. El lado bruto es siempre la estimación del destilador en el momento de la bebida, así que con --tokenizer-command la proporción se etiqueta como mixed.

Contra qué se ejecuta esto

requisito

Python

3.11+ (sin dependencias; pip install -e ".[dev]" solo añade pytest)

Node

20+, solo para el plugin DSH

zstd

solo para leer archivos de sesión DSH

endpoint de modelo

cualquier cosa que responda a POST <url>/chat/completions con la forma de OpenAI

"Compatible con OpenAI" es más estricto que "cualquier proveedor". La API nativa de un proveedor necesita una puerta de enlace compatible con OpenAI delante; su propia URL no basta. Un servicio estricto también rechaza campos de nivel superior desconocidos, así que establece dialect = "openai" (o "generic") — el "vllm" predeterminado envía chat_template_kwargs, que los servidores locales quieren y uno estricto responde con 400. El cliente reintenta una vez con un cuerpo simple y registra por qué una llamada falló en lugar de colapsar cada causa en un None silencioso.

Pruebas

python3 -m pytest tests -q                              # 145 tests, no model required
cd dsh-plugin && npm test                               # 24 more for the plugin

La puerta se prueba de forma adversarial: cada caso es una forma en que un modelo real intentó colar algo. test_containment.py está escrito de la misma manera — cada caso es un intento de escape, no un camino feliz — porque protege un agujero que era real: un almacén solía responder por cualquier archivo cuya ruta pudieras deletrear. La prueba de extremo a extremo ejecuta un ciclo completo de destilación→drenaje contra un servidor de modelos con guion en un socket real.

Licencia

MIT.

Available Tools

6 tools
kura_doctorA

Health check of the kura: how many memories, resolved and dead [[links]], islands (memories nothing links to), index drift. Call when recall behaves oddly, or when asked about the memory system itself.

ParametersJSON Schema
NameRequiredDescriptionDefault
storeNoWhich kura. Omit for the current one.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It does well by naming the diagnostic nature ('health check'), the categories of data inspected, and the symptom-triggered use case. It does not explicitly state whether the tool is read-only or whether any repair/reindexing occurs, but 'health check' strongly implies diagnostic rather than mutating behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact: two sentences, front-loaded with the core purpose, followed by a concise list of diagnostic metrics and explicit usage triggers. Every clause earns its place, with no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with zero required parameters and a fully documented optional parameter, the description provides enough context to select and invoke the tool correctly. It explains what will be inspected and when to use it. The only gap is that it does not describe the return format or explicitly confirm the absence of side effects, but neither is critical for a diagnostic health-check tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the description provides no additional parameter-level meaning beyond what the schema already states. The optional 'store' parameter is fully documented in the schema, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb-resource pairing: 'Health check of the kura', and enumerates concrete diagnostic outputs (memory counts, resolved/dead links, islands, index drift). This clearly differentiates it from the sibling tools like kura_read or kura_recall, which focus on reading or retrieving memories rather than diagnosing system health.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use the tool: 'Call when recall behaves oddly, or when asked about the memory system itself.' This provides clear invocation context. However, it does not explicitly mention alternatives or when not to use it, so it stops just short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

kura_listA

List the kura this server holds and which agent mode each one belongs to. Call it when you are unsure which memory you are speaking from, or before switching.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It states the operation (list) and the output (kura and agent modes) but does not mention side effects, read-only nature, performance, or any edge cases. Adequate but not rich for a tool without annotation safety signals.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero wasted words. The first sentence states the core function; the second provides immediate usage context. Information is front-loaded and every word serves a purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-parameter list tool with no output schema, the description explains what is listed and exactly when to invoke it. It could mention what 'kura' refers to or if results are ordered, but the definition is sufficient for an agent to decide and call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the schema coverage is trivially 100%. Per the rubric, 0 params earns a baseline of 4. The description does not need to add parameter details since none exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'list', the resource 'kura', and what is listed (which agent mode each belongs to). It implies a distinction from siblings like kura_read or kura_recall by focusing on the server's collection and mode mapping, though it does not explicitly name alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: 'Call it when you are unsure which memory you are speaking from, or before switching.' It lacks explicit when-not-to-use or named alternative tools, but the usage context is concrete and helpful.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

kura_mapA

Show the whole index of the kura — every memory's one-line recognition trigger, in one answer. Use it when you need to see WHAT EXISTS rather than look something up: before claiming a topic was never discussed, when choosing which memory to open, or right after switching kura. It is a map, not the contents: open a memory with kura_read for the detail.

ParametersJSON Schema
NameRequiredDescriptionDefault
storeNoWhich kura. Omit for the current one.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the full burden. It clearly frames a display operation ('Show the whole index... in one answer') and sets output expectations ('map, not the contents'). It does not discuss permissions or exact formatting, but for a non-mutating index tool the core behavioral disclosure is present.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: the first states the action and scope, the second gives concrete use cases, and the third clarifies depth and names the sibling for details. It is front-loaded and free of filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a low-complexity tool with one optional parameter and no output schema, the description provides the essential context: what it returns, when to use it, what it is not, and where to go for detail. Nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the single 'store' parameter is already documented as 'Which kura. Omit for the current one.' The description adds no parameter-level detail beyond that, so it meets the baseline but does not exceed it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Show the whole index of the kura - every memory's one-line recognition trigger.' It also distinguishes itself from siblings by saying it is 'a map, not the contents' and explicitly directs details to kura_read, so an agent can tell it apart from the other tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use conditions ('when you need to see WHAT EXISTS... before claiming a topic was never discussed, when choosing which memory to open, or right after switching kura') and an explicit alternative ('open a memory with kura_read for the detail'). This is clear routing guidance rather than leaving usage to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

kura_readA

Read one whole memory from the kura by its slug (e.g. 'storage-doctrine'). Use after kura_recall when a summary is not enough and you need the full text.

ParametersJSON Schema
NameRequiredDescriptionDefault
slugYesMemory slug, without .md
storeNoWhich kura. Omit for the current one.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations available, the description carries the burden of behavior. It clearly indicates a read operation fetching the full memory text, which is sufficient for this simple tool. It could add detail about return format or failure behavior, but the core behavior is transparent enough.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The primary behavior is front-loaded, and the usage guidance, alternative, and selection condition are packed efficiently into the second sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-by-slug tool with only two parameters, no output schema, and full schema coverage, the description is complete. It tells the agent what it does, when to use it, and provides an example. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds a useful example slug ('storage-doctrine') but otherwise does not need to add much beyond what the schema already documents for 'slug' and 'store'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Read'), the resource ('one whole memory'), and the retrieval key ('by its slug'), with a concrete example. It also names the sibling tool it complements, distinguishing it from kura_recall without needing to inspect the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states when to use this tool: 'Use after kura_recall when a summary is not enough and you need the full text.' This directly routes the agent to the appropriate alternative and gives a clear selection condition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

kura_recallA

Recall from the kura — long-term memory retrieved by MEANING rather than keyword, then following [[links]] between memories. Call it whenever the question touches past decisions, measurements, people, machines, or anything done before — prefer it over guessing. An empty result means it is simply not remembered yet: say so plainly and never fill the gap with invention. Pass store to reach a different kura, or call kura_use to switch for the session.

ParametersJSON Schema
NameRequiredDescriptionDefault
hopsNoHow many [[link]] hops to walk (default 1)
storeNoWhich kura to ask (store or mode name). Omit for the current one.
questionYesWhat you want to remember, as a natural question

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are absent, so the description carries the full burden of behavioral disclosure. It does reveal important behavior: it retrieves by meaning, follows links, and emphasizes not to fabricate when no result is found. However, it does not disclose potential side effects, rate limits, or what happens with the hops parameter (e.g., how deep the search goes and whether more hops affect latency). It also doesn't specify if the tool is read-only, though recall implies reading. Overall, it gives useful context but leaves some behavioral aspects unmentioned.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, dense paragraph but contains no filler. It front-loads the core purpose and usage guidance, then addresses edge cases and parameter use. It is appropriately sized for a tool with multiple interconnected behaviors (meaning-based recall, link-following, empty result handling). It could be slightly more structured (e.g., bullet points for handling empty results or parameter variants), but it is efficient and every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has 3 parameters (1 required), no output schema, and moderate complexity due to link-following and alternate stores, the description covers the essential aspects: what it does, when to use it, how to handle empty results, and how to use parameters. It does not explicitly describe return format (e.g., whether it returns text or a list of memories), but with no output schema, it could have provided more on that. Missing details on hops behavior and potential limitations are minor gaps. Overall, it is fairly complete for an agent to use it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents all three parameters (question, hops, store) with descriptions, and coverage is 100%, so the baseline for parameter semantics is 3. The description adds value by explaining the semantics of 'store' ('reach a different kura') and hints that 'question' should be phrased as a natural question. It also implies the meaning of 'hops' (following [[links]]). It doesn't detail the format or constraints beyond the schema, but it enriches the meaning of each parameter sufficiently.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Recall from the kura — long-term memory retrieved by MEANING rather than keyword, then following [[links]] between memories.' It differentiates itself from siblings by emphasizing meaning-based retrieval over keyword, which distinguishes it from tools like kura_read or kura_list. It also mentions specific use cases, making it easy for an agent to understand what it does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use this tool: 'Call it whenever the question touches past decisions, measurements, people, machines, or anything done before — prefer it over guessing.' It also explains what to do on empty results ('An empty result means it is simply not remembered yet: say so plainly and never fill the gap with invention') and mentions alternatives or related actions ('Pass store to reach a different kura, or call kura_use to switch for the session'). This provides clear guidance on selection and behavior.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

kura_useA

Switch which kura the following calls read from, for the rest of this session. Use when the conversation moves to a different mode of work (for example from building things to talking things through). Has no effect on a bridge that was bound to a single kura at startup — it will say so.

ParametersJSON Schema
NameRequiredDescriptionDefault
storeYesStore or mode name

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of behavioral disclosure. It does this well by revealing that the switch persists for the session, affects subsequent calls, and has no effect on a single-kura bridge (and that it will say so). It does not cover every possible error or side effect, but the key stateful behavior is disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences with no wasted words. The main effect and scope are front-loaded, the usage condition follows, and the edge case is placed last. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter state-switching tool with no annotations and no output schema, this description is complete enough. It explains what the tool does, when to invoke it, how long the effect lasts, and the one major exception an agent needs to know about.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% — 'store' is already described as 'Store or mode name.' The description adds some context by suggesting that stores correspond to modes of work, but it does not enumerate valid values or add meaningful parameter detail beyond the schema. This is the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Switch') and names both the resource ('which kura the following calls read from') and the scope ('rest of this session'). This clearly distinguishes it from the sibling read/analysis tools like kura_read and kura_map, which retrieve data rather than change the active context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says when to use it: 'Use when the conversation moves to a different mode of work,' with a concrete example. It also discloses a limitation about bridges bound to a single kura. It does not explicitly name sibling alternatives or state when not to use it, but the intended context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedkura_doctor
    • First observedkura_list
    • First observedkura_map
    • First observedkura_read
    • First observedkura_recall
    • First observedkura_use

TDQS

A4.3/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: reading a specific memory, recalling by meaning, viewing the index, health checking, listing available kuras, and switching the active kura. There is no overlap or ambiguity between them.

Naming Consistency5/5

All tools follow a consistent pattern: a 'kura_' prefix followed by a lowercase verb (read, recall, map, doctor, list, use). The naming is uniform, predictable, and readable.

Tool Count5/5

Six tools is well-scoped for a memory management server. Each tool covers an essential operation without redundancy, fitting the typical ideal range of 3-15 tools.

Completeness4/5

The set covers all core retrieval and management operations: listing, switching, recalling, reading, mapping, and health checking. It could benefit from a write/update operation, but the server appears intentionally read-focused, so the surface is nearly complete for its stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides AI agents with persistent, searchable memory that survives across conversations using semantic search, temporal versioning, and smart organization. Enables long-term context retention and cross-session continuity for AI assistants.
    14
    -
  • A
    license
    A
    quality
    D
    maintenance
    Provides persistent long-term memory for AI agents through semantic search and automated knowledge graph extraction. It enables agents to store, recall, and reason over facts, preferences, and relationships across multiple conversations and sessions.
    14
    7 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to store, search, and recall semantic memories with three memory types (semantic, episodic, procedural) and auto-consolidation, compounding intelligence over time.
    7 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Provides long-term memory for agents with meaning-based recall, evidence-gated writing, and separate stores per agent mode.
    6
    MIT