distill-kura
蒸留蔵 — 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 |
| las palabras del humano | "ellos decidieron", "ellos preguntaron" |
| salida de máquina | números — la única fuente |
| una herramienta invocada | "esto se hizo" |
| 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:8085curl -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 promptAlimé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 quietNada 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 injectTres 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 | se mantiene completo |
reciente | cambiado dentro de | se mantiene completo |
disparador | todo lo demás | comprimido a ~ |
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 personaUna 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 |
por encima de | el mapa completo, y una advertencia en el JSON (nunca en el texto — un banner es contenido volátil) |
por encima de | 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 |
Claude Code, VS Code, Goose | MCP |
Claude Desktop, claude.ai | ignora |
cualquier otra cosa |
|
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 URLLos 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 |
| cada recuerdo | pequeño y rápido; debe juzgar relevancia por significado |
| destilando: lee un lote completo de diario | longitud de contexto y paciencia |
| 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 testEjecute 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 scratchEsa 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 |
|
|
|
|
|
|
| el índice crudo |
| el bloque residente, listo para inyectar ( |
| una memoria completa, con sus |
| salud de un almacén ( |
| almacenes, modos, y qué modelo llena cada rol |
| la carta del almacén, el perfil aprendido con su estado (ausente / presente / roto), y un puntero a su persona (nunca renderizado aquí) |
| 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 runsale 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.jsonMedido aquí, con los fixtures incluidos y el estimador integrado:
corpus |
|
| 0.18 |
| 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/2Eso 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; |
Node | 20+, solo para el plugin DSH |
| solo para leer archivos de sesión DSH |
endpoint de modelo | cualquier cosa que responda a |
"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 pluginLa 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 toolskura_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.
| Name | Required | Description | Default |
|---|---|---|---|
| store | No | Which kura. Omit for the current one. |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| store | No | Which kura. Omit for the current one. |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | Yes | Memory slug, without .md | |
| store | No | Which kura. Omit for the current one. |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| hops | No | How many [[link]] hops to walk (default 1) | |
| store | No | Which kura to ask (store or mode name). Omit for the current one. | |
| question | Yes | What you want to remember, as a natural question |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| store | Yes | Store or mode name |
TDQS
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.
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.
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.
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.
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.
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.
6 tool updates
v0.1.0- First observed
kura_doctor - First observed
kura_list - First observed
kura_map - First observed
kura_read - First observed
kura_recall - First observed
kura_use
TDQS
Scored across 6 tools
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.
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.
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.
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
Related MCP Connectors
- RecallOAuthdev.recallmem
Long-term memory for AI agents: learns what is true about each person and answers with sources.
- memoryOAuthcom.humaux
Persistent long-term memory for AI agents: semantic search, knowledge graph, and task canvas.
Memory system for AI agents with semantic search. Store and recall memories with ease.
Long-term memory and a knowledge graph for AI agents: recall, notes, secrets and data sources.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides 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-

Memsolus MCP Serverofficial
AlicenseAqualityDmaintenanceProvides 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.147 npmMIT- AlicenseNot gradedqualityDmaintenanceEnables AI agents to store, search, and recall semantic memories with three memory types (semantic, episodic, procedural) and auto-consolidation, compounding intelligence over time.7 npmMIT
- AlicenseAqualityBmaintenanceProvides long-term memory for agents with meaning-based recall, evidence-gated writing, and separate stores per agent mode.6MIT