kura
蒸留蔵 — distill-kura
Долговременная память для агентов, которая дистиллируется, а не накапливается. Воспоминание работает по смыслу, запись ограничена доказательствами, и один сервер может хранить несколько отдельных воспоминаний — по одному на режим агента — так что переключение режима меняет то, что агент помнит.
Поставляется как плагин DeepSeek Harness, MCP-сервер для любого другого хоста, HTTP-сервис и Python-библиотека. Только стандартная библиотека; никакой векторной базы данных, никаких эмбеддингов, никакого фреймворка.
┌── 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 │
└────────────────────────────────────────────────────────┘Зачем это существует
Два сбоя убивают долговременную память агента, и они убивают её с противоположных сторон.
Поиск по ключевым словам упускает то, что было нужно. Вопрос о «чипах для инференса SSD» не имеет ни одного общего слова с воспоминанием под названием «запуск модели 2.6T с SSD-уровня» — и всё же это одна и та же тема. Поиск по словам ничего не возвращает; агент отвечает из ниоткуда. Решение здесь — не эмбеддинги, а распознавание: весь индекс (одна строка на воспоминание, записанная как триггер распознавания) помещается в один промпт, и небольшая модель называет то, что относится к вопросу. Индекс из ~500 воспоминаний — это около 6k токенов — несколько процентов современного контекстного окна, и он лежит в кэше префикса.
Запись всего подряд отравляет хранилище. Агент делает утверждение; наивный дистиллятор записывает утверждение как факт; следующий агент читает его как истину и повторяет с большей уверенностью. Этот цикл самоподкрепляющийся, и инструкции в промпте его не останавливают — это измерено, а не предположено. Поэтому путь записи ограничен детерминированным Python: каждая кандидатная память должна содержать цитаты, которые существуют символ-в-символ в исходном материале, с указанием, откуда они взялись.
класс | что это | что это разрешает |
| собственные слова человека | «они решили», «они попросили» |
| вывод машины | числа — единственный источник |
| инструмент, который был вызван | «это было сделано» |
| собственная проза агента | суждение от первого лица, никогда не голый факт |
Цитата, не найденная дословно, отбрасывается. Кандидат без выжившей цитаты
выбрасывается. Число без подкрепляющего [TOOL] удаляется. Текст, приписывающий человеку
решение, когда ни одна цитата [USER] не выжила, отклоняется на последнем рубеже. Идеи
приветствуются — они идут в файл семян, никогда в хранилище, и получают статус только когда
позднейшие доказательства их подтверждают.
Related MCP server: Synapto
Быстрый старт
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}'Носите индекс, чтобы агент всегда знал, что известно:
kura weave # build the three-layer cloth
kura prefill # the block to put in the system promptСкармливайте ему транскрипты вашего агента:
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Ничто не попадает в хранилище, пока не выполнен drain (или запущенный вручную pour). Черновики несут
свои доказательства в HTML-комментарии, так что вы всегда можете видеть, почему существует память.
Карта резидента
Вызов-по-инструменту отвечает на вопрос «что ты знаешь об X?» — но только после того, как агент решил спросить. Он никогда не отвечает на вопрос, который агент не догадывается задать: есть ли здесь вообще что-нибудь? Агент, который не видит карту, не знает, чего ему не хватает, поэтому он догадывается, а уверенная догадка о вашем хозяйстве — это именно тот сбой, который этот проект призван предотвратить.
Поэтому индекс также носится: постоянный блок в системном промпте, на каждом ходу.
kura weave # re-weave the index into the three-layer cloth
kura prefill # print the block a host should injectТри слоя, потому что детализация окупается только для недавнего
Слепой A/B-тест — 20 вопросов, полный индекс против урезанного, оценка без знания того, какой был какой — определил форму:
диапазон | полный | урезанный |
в целом | 9 | 11 |
недавние события | 4 | 1 |
доктрина | 1 | 4 |
кросс-доменные скачки | 1 | 4 |
Строки доктрины были побайтово идентичны в обоих индексах, и урезанный индекс всё равно выиграл этот диапазон: более лёгкое окружение заставляет постоянные строки работать лучше. Детализация — не источник понимания. Она оправдывает своё место только там, где вещи ещё движутся.
слой | правило | строка |
закреплённый | frontmatter | сохраняется полностью |
свежий | изменён в пределах | сохраняется полностью |
триггер | всё остальное | сжимается до ~ |
Строки триггеров пишутся моделью scribe и кэшируются в журнале с ключом по описанию и
бюджету, так что повторное плетение в стабильном состоянии ничего не стоит. Если модель
недоступна, ткацкий станок обрезает механически — система памяти не должна глохнуть
из-за того, что GPU лежит.
Возраст — это не mtime. cp -r, восстановление или checkout сбрасывают все временные метки, весь
индекс становится «свежим», ничего не обрезается, и механизм молча отключает сам себя.
Поэтому ткацкий станок предпочитает дату, записанную внутри памяти, и не доверяет любому mtime,
который пятая часть хранилища делит с одним календарным днём.
Куда это идёт, и почему это решение о кэше
- id: kura
name: distill-kura
config: { store: eq, promptOrder: -50 } # before the personaКэш префикса теряется с первого изменённого байта — измерено на одном локальном сервере: идентичный преамбул из 4 029 токенов переоценивается с 0,68 с до 0,14 с, добавление в конец остаётся 0,14 с, а одно слово, добавленное в начало, стоит всего кэша (0,66 с). Персона обычно несёт часы, так что она меняется каждую минуту; карта — это самый большой блок в промпте и меняется несколько раз в день. Большой стабильный блок идёт перед тем, что тикает.
Поэтому сам блок не содержит ни даты, ни часов, ни счётчика — и build()
отказывает заголовку, который их содержит, во время сборки, а не через таинственно медленные ходы
три недели спустя.
Она никогда не отдаёт полкарты
ситуация | что получает агент |
всё в порядке | карту, между маркерами |
свыше | всю карту и предупреждение в JSON (никогда в тексте — баннер — это изменчивое содержимое) |
свыше | заглушку без строк индекса, говорящую, что карта отсутствует, а не пуста |
kura недоступен | явное примечание, что карта отсутствует, никогда не пустую строку |
Усечённая карта — худший из доступных артефактов: она выглядит полной, и каждое воспоминание
ниже среза выглядит несуществующим. weave сократит окно свежести, чтобы вписаться, но
никогда не отбросит строку — и если ни одна настройка не достигает бюджета, он сообщает об этом,
сохраняет лучшую карту и показывает вам, где вес.
Как доставить её в хост
хост | механизм |
DSH | нативный плагин — |
Claude Code, VS Code, Goose | MCP |
Claude Desktop, claude.ai | игнорируют |
что угодно ещё |
|
Поле MCP instructions — это MAY в спецификации, и индекс на 9 000 токенов не может
пройти через лимит 2KB в любом случае, так что этот проект не притворяется иначе.
Режимы: больше одной куры
Одна память, которая служит и «помоги мне это построить», и «помоги мне это обдумать», не служит ни тому, ни другому хорошо: воспоминание, которое помогает вам отлаживать, — это шум в разговоре о том, что делать дальше. Поэтому хранилище — это каталог, а режим сопоставляется с хранилищем.
[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"Каждый маршрут принимает селектор, так что один процесс обслуживает их все:
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Хранилища не разделяют воспоминания, индекс и водяной знак дистиллятора. Переключение режима действительно меняет то, что запоминается, — а не ту же память другим голосом.
Независимость как маршрутизация, а не как конфиденциальность. У сервера нет аутентификации, так что
любой процесс, который может достичь его порта, может назвать любое хранилище, которое он держит. Привязка агента удерживает
модель в её полосе; она не удерживает процесс снаружи. Один уровень доверия на процесс —
docs/TRUST.md короткий, и его стоит прочитать, прежде чем в хранилище попадёт
приватное. Он также покрывает две границы, которые легко упустить: два хранилища, пьющие из
одного корня журнала, и два хранилища за одной конечной точкой модели.
С DeepSeek Harness
DSH переключает персону и инструменты по пресету агента. distill-kura переключает память по хранилищу. Свяжите их, и одно изменение пресета сдвигает всё «я» целиком:
# .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.)Оставьте allowSwitch по умолчанию, и агент также получит kura_use, так что он сможет
перемещаться между курами в середине разговора без смены пресета. Инструменты: kura_recall,
kura_read, kura_doctor, kura_list, kura_use и kura_remember (только когда
хранилище доступно для записи). Полная схема подключения, включая MCP-мост и правило области isolate
для сервисных строк, — в examples/dsh-presets/.
Персона — дело хоста, не наше. Этот проект никогда не рендерит и не внедряет
персону; он только записывает, по хранилищу, какой файл персоны принадлежит ему, доступный по
GET /profile?store=eq, чтобы две половины можно было держать в шаге тому, кто владеет
пресетом. Инструкции агента также остаются с механизмом AGENTS.md хоста — см.
AGENTS.md в этом репозитории для соглашений, которым должен следовать агент, работающий над
этой кодовой базой.
С любым 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" }
}}}Оставьте KURA_STORE неустановленным для свободного режима: инструменты принимают необязательный аргумент store, и
kura_use переключает для сессии.
Модели: одна по умолчанию, обновляйте роль за раз
Три роли, а не три машины:
роль | когда запускается | требования |
| каждый вызов воспоминания | маленькая и быстрая; должна судить о релевантности по смыслу |
| дистилляция: читает целую партию журнала | длина контекста и терпение |
| дистилляция: пишет память, затем оценивает черновики | хорошая проза на вашем языке, суждение |
Объявите только [models.thinker], и одна модель делает всё три. Обновите любую из
остальных независимо — более крупную локальную модель или онлайн-API (любой OpenAI-совместимый
/chat/completions; ключ читается из переменной окружения, которую вы называете, и никогда не
хранится в конфиге):
[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"Две вещи, которые это обрабатывает за вас: диалекты усилия рассуждения различаются по семействам моделей
(reasoning_effort, thinking_effort, enable_thinking), поэтому отправляются все из них
— неизвестная игнорируется шаблоном, а модель, оставленная на глубоком мышлении по
умолчанию, может потратить весь свой бюджет на рассуждение и ничего не вернуть. И текст устава
размещается побайтово идентично в начале промпта каждой роли, так что на медленной локальной
модели три роли разделяют один кэшированный префикс вместо трёх префиллов.
Если мыслитель недоступен, recall не замолкает — он откатывается к пересечению слов и помечает ответ how=words, который инструменты отображают как ⚠ degraded. Тихая деградация хуже деградации.
Как выглядит память
Один файл — один факт.
---
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
---
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]]И одна строка в MEMORY.md:
- [Archive on the slow disk](archive-on-slow-disk.md) — the archive lives on the slow disk; the fast one stays scratchЭта строка — единственное, что читается каждый раз. Это триггер распознавания, а не сводка: имена собственные, числа, ⚠️ мины, сделанный вывод. Если строку можно поменять местами со строкой другого воспоминания, и она по-прежнему будет читаться нормально, она не выполняет свою работу — kura distill tidy находит механически обнаруживаемые случаи и переписывает их.
kura doctor сообщает о количестве, битых ссылках, островах (воспоминаниях, на которые ничто не ссылается) и дрейфе индекса. Это глаз, необходимый метаболизму.
HTTP-поверхность
route | что делает |
|
|
|
|
| необработанный индекс |
| резидентный блок, готовый к внедрению ( |
| одно воспоминание полностью |
| здоровье одного хранилища ( |
| хранилища, режимы и какая модель выполняет какую роль |
| устав хранилища и указатель на его персону (здесь никогда не отображается) |
| живость |
Любой маршрут принимает ?store= / ?mode=, поле store/mode в теле или префикс пути /s/<name>/…. Без аутентификации: привяжитесь к loopback или поставьте что-то перед ним.
Заметки по дизайну, которые стоит прочитать перед изменениями
docs/DESIGN.md — почему распознавание лучше поиска, что даёт шлюз и какой сбой мотивировал каждый механизм.
docs/OPERATING.md — запуск в резидентном режиме, планировщики и коды выхода, резервное копирование, за чем следить.
docs/TRUST.md — что такое граница хранилища, а что нет, политики записи и две границы, которые легко упустить (общие журналы, общие модели). Прочтите, прежде чем создавать приватное хранилище.
Несколько решений, которые выглядят странно, пока не столкнёшься с тем, от чего они защищают:
Резервируй, прежде чем пить. Дистиллятор резервирует участок журнала до его чтения, под блокировкой, и водяные знаки движутся только вперёд. Два дистиллятора, каждый из которых записывал свой снимок, стирали прогресс друг друга и по дюжине раз перепивали одну и ту же воду.
Водяные знаки — это единицы на адаптер. Байтовые смещения для журналов с добавлением, порядковые номера для архивов, которые перезаписываются (байтовое смещение в пережатом файле — это ложь).
Подавление эха. Цитата, которая уже есть в хранилище, — это не новый материал; это хранилище читает само себя через результат инструмента. Без этого система памяти вечно переоткрывает и перезаписывает собственное содержимое.
Последний шлюз — это модель, а не человек. Если человек должен утверждать каждый черновик, система тихо делает этого человека своим узким местом, и черновики копятся вечно. Ничто в цикле не должно требовать того, кого нет рядом.
kura distill runзавершается с кодом 2, когда делать было нечего. Планировщик должен отличать «сделал работу» от «ничего не нашёл», иначе сторожевой пёс крутится в пустой очереди и морит голодом шаги, которым нужно время простоя.
Измеряем, а не заявляем
На два вопроса отвечают одним числом, и не следовало бы.
Насколько меньше? store_ratio = токены в воспоминаниях и индексе / токены реально потреблённого сырого журнала. Что потеряно? Это другое измерение, и хранилище, которое хранит одно воспоминание из ста, прекрасно набирает баллы по первому, оставаясь бесполезным.
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Измерено здесь, с поставляемыми фикстурами и встроенным оценщиком:
корпус |
|
| 0.18 |
| 1.14 |
Второе — не баг. На материале, где нет воды, дистилляция не сжимает — каждое воспоминание добавляет своё зачем и как применить, и хранилище получается чуть больше стенограммы. Коэффициент — свойство корпуса, а не этого инструмента, поэтому здесь нет ключевой цифры и поэтому команда сообщает, с чем она считала.
Удержание оценивается без модели: каждый посаженный факт несёт маркер, который должен появиться в том, что возвращает recall, поэтому оценка воспроизводима на чужой машине. Дистракторы инвертируются: факт, помеченный must_not_store, стоит очко, если хранилище его сохранило, потому что систему памяти судят и по тому, что она отклоняет, и по тому, что сохраняет.
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Это десять посаженных фактов в синтетической фикстуре, дистиллированных локальной Qwen3.8-27B (NVFP4) в роли мозга и писца с max_items = 8, coverage_passes = 2 и оценённых той же моделью в роли мыслителя. Другая модель даст другой балл: оценка измеряет конвейер-плюс-модель, и фикстура существует, чтобы модель была единственной переменной. Она измеряет, находим ли факт, а не хорошо ли читается ответ, — оценка прозы требует модели, и тогда бенчмарк перестаёт быть воспроизводимым.
kura distill run пишет по одной строке на пакет в _still/metrics.jsonl, откуда берётся сырая сторона. Каноническая сторона считает только те воспоминания, чей манифест свидетельств указывает на записанный пакет — делить всё хранилище на сырьё нескольких пакетов — это число не в ту сторону на порядок, и первая версия этой команды делала именно так. Воспоминания, предшествующие манифестам, помечаются как unattributed, а не молча включаются. Сырая сторона — это всегда оценка дистиллятора на момент питья, поэтому с --tokenizer-command коэффициент помечается как mixed.
С чем это работает
требование | |
Python | 3.11+ (без зависимостей; |
Node | 20+, только для плагина DSH |
| только для чтения архивов сессий DSH |
модельная конечная точка | всё, что отвечает на |
«Совместимость с OpenAI» уже, чем «любой провайдер». Собственному API вендора нужен совместимый с OpenAI шлюз перед ним; собственный URL не подойдёт. Строгий сервис также отклоняет неизвестные поля верхнего уровня, поэтому установите dialect = "openai" (или "generic") — по умолчанию "vllm" отправляет chat_template_kwargs, которые нужны локальным серверам, а строгий отвечает 400. Клиент повторяет попытку один раз с простым телом и записывает, почему вызов не удался, а не схлопывает все причины в молчаливый None.
Тесты
python3 -m pytest tests -q # 145 tests, no model required
cd dsh-plugin && npm test # 24 more for the pluginШлюз тестируется состязательно: каждый случай — это способ, которым реальная модель пыталась что-то протащить. test_containment.py написан так же — каждый случай это попытка побега, а не счастливый путь, — потому что он закрывает реальную дыру: хранилище отвечало за любой файл, путь к которому можно было произнести. Сквозной тест прогоняет полный цикл distil→drain против скриптованного модельного сервера на реальном сокете.
Лицензия
MIT.
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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
- AlicenseNot gradedqualityAmaintenanceProvides persistent, searchable memory for MCP-compatible agents, enabling recall by meaning, automatic decay, trust scoring, and cross-agent handoffs.4MIT

Hebbrix MCP Serverofficial
AlicenseAqualityAmaintenanceProvides long-term memory and a temporal knowledge graph for AI agents, enabling persistent memory and reasoning across sessions.261MIT- AlicenseNot gradedqualityAmaintenanceRole-aware long-term Agent memory with cross-session recall, durable writes, and multi-Agent project scope.Apache 2.0
Related MCP Connectors
Shared, governed long-term memory for AI agents across tools and sessions via MCP and REST.
Persistent memory for AI agents. Search, store, and recall across sessions.
Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kisaragi-mochi/distill-kura'
If you have feedback or need assistance with the MCP directory API, please join our Discord server