Skip to main content
Glama

蒸留蔵 — distill-kura

에이전트를 위한 장기 기억 — 축적이 아니라 증류(distilled). 회상은 의미로 작동하고, 기록은 증거로 게이트되며, 하나의 서버가 여러 개의 분리된 기억을 담을 수 있다 — 에이전트 모드마다 하나씩 — 그래서 모드를 바꾸면 에이전트가 기억하는 것도 바뀐다.

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 추론 칩"*에 대한 질문은 *"SSD 티어에서 2.6T 모델 실행"*이라는 제목의 기억과 단어를 하나도 공유하지 않는다 — 하지만 둘은 같은 주제다. 단어 검색은 아무것도 반환하지 않고, 에이전트는 허공에서 답한다. 여기서 해결책은 임베딩이 아니라 *인식(recognition)*이다: 전체 인덱스(기억당 한 줄, 인식 트리거로 작성됨)가 하나의 프롬프트에 들어가고, 작은 모델이 질문과 관련된 것을 지목한다. ~500개 기억의 인덱스는 약 6k 토큰이다 — 현대 컨텍스트 윈도우의 몇 퍼센트에 불과하며, 프리픽스 캐시에 상주한다.

모든 것을 기록하면 저장소가 오염된다. 에이전트가 무언가를 주장한다. 순진한 증류기가 그 주장을 사실로 기록한다. 다음 에이전트가 그것을 진실로 읽고 더 큰 확신을 가지고 반복한다. 그 루프는 자기 강화적이며, 프롬프트 지시로는 막을 수 없다 — 가정이 아니라 측정된 사실이다. 그래서 쓰기 경로는 결정론적 Python으로 게이트된다: 모든 후보 기억은 원자재에 문자 그대로 존재하는 인용문을 반드시 담아야 하며, 출처가 태그로 붙는다.

클래스

무엇인가

무엇을 허가하는가

[USER]

인간의 말 그대로

"그들이 결정했다", "그들이 물었다"

[TOOL]

기계 출력

숫자 — 유일한 출처

[ACT]

호출된 도구

"이것이 수행되었다"

[SELF]

에이전트 자신의 산문

1인칭으로 표현된 판단, 결코 단순한 사실이 아님

축어적으로 발견되지 않은 인용문은 폐기된다. 살아남은 인용문이 없는 후보는 버려진다. 뒤에 [TOOL]이 없는 숫자는 제거된다. [USER] 인용문이 살아남지 않았는데 인간이 결정을 내렸다고 주장하는 텍스트는 마지막 게이트에서 거부된다. 아이디어는 환영한다 — 시드 파일로 가며, 저장소에는 절대 들어가지 않고, 이후 증거가 확인할 때만 승격된다.


Related MCP server: Memsolus MCP Server

빠른 시작

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}'

인덱스를 착용하라. 에이전트가 항상 무엇이 알려져 있는지 알 수 있도록:

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

원칙(doctrine)

1

4

도메인 간 도약

1

4

원칙 줄은 두 인덱스에서 바이트 단위로 동일했고, 슬림 인덱스가 그 밴드에서도 이겼다: 더 가벼운 주변이 상주 줄을 더 잘 작동하게 한다. 세부 정보는 통찰의 원천이 아니다. 그것은 아직 움직이는 곳에서만 자리를 얻는다.

계층

규칙

줄

고정(pinned)

frontmatter type이 pinned_types에 있음

전체 유지

신선(fresh)

fresh_days 내에 변경됨

전체 유지

트리거(trigger)

그 외 모든 것

~trigger_tokens로 압축

트리거 줄은 scribe 모델이 작성하고, 설명 및 예산을 키로 하는 원장에 캐시된다. 그래서 정상 상태에서 재직조(weave)는 비용이 들지 않는다. 모델에 도달할 수 없으면 직조기는 대신 기계적으로 다듬는다 — GPU가 다운되었다고 기억 시스템이 공백이 되어서는 안 되기 때문이다.

나이는 mtime이 아니다. cp -r, 복원 또는 체크아웃은 모든 타임스탬프를 재설정하고, 전체 인덱스가 "신선"이 되며, 아무것도 다듬어지지 않고, 메커니즘은 조용히 스스로 꺼진다. 그래서 직조기는 기억 내부에 쓰인 날짜를 선호하고, 저장소의 5분의 1이 하나의 역일과 공유하는 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()는 그런 것이 있는 헤더를 빌드 시점에 거부한다. 3주 후에 신비롭게 느려진 턴이 아니라.

절반의 지도를 넘겨주지 않는다

상황

에이전트가 받는 것

모두 정상

<<<KURA-MAP>>> 마커 사이의 지도

budget_fraction 초과

전체 지도, 그리고 JSON의 경고(텍스트에는 절대 없음 — 배너는 휘발성 콘텐츠다)

hard_fraction 초과

인덱스 줄이 없는 스텁, 비어 있다고 말하는 대신 지도가 없다고 말함

kura에 연결 불가

빈 문자열이 절대 아닌, 지도가 없다는 명시적 메모

잘린 지도는 가능한 최악의 산출물이다: 완전해 보이고, 절단선 아래의 모든 기억은 존재하지 않는 것처럼 보인다. weave는 신선 윈도우를 줄여 맞추겠지만, 줄을 절대 버리지 않는다 — 그리고 어떤 설정도 예산에 도달하지 못하면 그렇게 말하고, 더 나은 지도를 유지하며, 무게가 어디에 있는지 알려준다.

호스트에 넣기

호스트

메커니즘

DSH

네이티브 플러그인 — systemPrompt.section, 백그라운드에서 갱신

Claude Code, VS Code, Goose

MCP instructions는 짧은 포인터를 담는다(2KB 한도); 지도 자체는 kura_map 도구 또는 kura prefill을 실행하는 세션 훅에서 온다

Claude Desktop, claude.ai

instructions를 완전히 무시 — kura_map 사용

그 외 모든 것

GET /prefill?format=text, 또는 셸 훅에서 kura prefill

MCP instructions 필드는 스펙에서 MAY이고, 9,000토큰 인덱스는 어차피 2KB 한도를 통과할 수 없다. 그래서 이 프로젝트는 그렇지 않은 척하지 않는다.


모드: 하나 이상의 kura

"이것을 만드는 것을 도와줘"와 "이것을 생각해내는 것을 도와줘"를 동시에 서빙하는 단일 기억은 어느 쪽도 제대로 서빙하지 못한다: 디버깅에 도움이 되는 회상은 다음에 무엇을 할지에 대한 대화에서 잡음이다. 그래서 저장소는 디렉토리이고, 모드는 저장소에 매핑된다.

[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

저장소는 기억, 인덱스, 증류기 워터마크를 공유하지 않는다. 모드 전환은 진정으로 기억되는 것을 바꾼다 — 같은 기억이 다른 목소리로 바뀌는 것이 아니다.

방은 대화 전에 선택된다. 모드는 호스트가 보내는 것이다 — DSH 프리셋, MCP 환경의 KURA_STORE, CLI의 -s — 그리고 그것이 전체 세션의 집이다. 이 프로젝트에서 메시지를 읽고 어느 저장소에 속하는지 결정하는 것은 없다. 빌드에서 느낌으로 흘러가는 대화는 시작된 곳에 머물고, 호스트는 다음 세션을 위해 다른 방을 제공할 수 있다. 알 수 없는 셀렉터는 문 앞에서 오류다. 조용히 기본값으로 떨어지지 않는다.

하나의 방, 많은 태그. 기억은 정확히 하나의 저장소에 살고, 그 성격을 설명하는 여러 태그를 담을 수 있다(decision, landmine, emotion-carried, …). 태그는 단어이지 가중치가 아니다: 태그로 순위를 매기는 것도, 세는 것도 없다. 그리고 emotion-carried 태그가 붙은 Develop 기억은 여전히 Develop 기억이다. 기억을 다른 저장소로 옮기거나 복사하는 명령은 없으며, 모드 변경은 미래 세션에만 영향을 준다. 두 방에서 제기된 같은 주제는 두 개의 기억을 낳는다. 각각 그 방의 증거에서 증류된 — Research의 "우리가 배운 것"과 Develop의 "우리가 한 것"은 다른 사실이고, 그것들을 중복 제거하기 위해 경계를 넘는 것은 없다.

넓은 방은 조금 더 부드럽게 회상한다. 고정된 헌장을 가진 좁은 저장소는 날카롭게 인식한다. 무엇이든 받아들이는 저장소 — 목적이 아니라 사람을 따르는 USER 방 — 은 더 느슨할 것으로 예상되고, 그 대가로 이해가 성장할 수 있는 방이다: 헌장 옆에 있는 profile.md, 문장으로 쓰여 있고, 헌장 다음에 읽히며, 자신의 기억에서 초안이 작성되고 사람이 적용한다. 헌장과 설정을 갖춘 다섯 개의 그러한 방이 examples/rooms/에 있다.

라우팅으로서 독립적이지, 기밀성으로서 독립적이지 않다. 서버에는 인증이 없다. 그래서 포트에 도달할 수 있는 모든 프로세스는 보유한 모든 저장소를 지명할 수 있다. 에이전트를 바인딩하는 것은 모델을 차선에 유지한다. 프로세스를 막지는 않는다. 프로세스당 하나의 신뢰 수준 — 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.)

하나의 의존성, 그리고 왜 동료(peer)인가. 플러그인은 @deepseek-ai/dsh-tools에서 defineTool을 임포트한다. 프로필 로컬의 두 번째 복사본은 — 같은 버전에서도 — 패키지의 모듈 로컬 Symbol 정체성을 분할하고 첫 번째 도구 호출을 undefined.prepare로 실패하게 만들 수 있다. 그래서 플러그인은 패키지를 "*" 피어로 선언하여 프로필이 버전 불일치 없이 자체 복사본을 공급하게 한다. 오래된 물리적 중복은 여전히 중복 제거를 요구할 수 있다. examples/dsh-presets/의 설치 검사를 참조하라.

allowSwitch를 기본값으로 두면 에이전트는 kura_use도 얻는다. 그래서 프리셋 변경 없이 대화 중에 kura 사이를 이동할 수 있다. 도구: 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가 세션 동안 스토어를 전환합니다.


모델: 기본은 하나, 역할은 한 번에 하나씩 업그레이드

세 대의 기계가 아니라 세 가지 역할입니다.

역할

실행 시점

요구 사항

thinker

모든 회상 때

작고 빨라야 하며, 의미로 관련성을 판단해야 함

brain

증류 시: 저널의 전체 묶음을 읽음

컨텍스트 길이와 인내심

scribe

증류 시: 기억을 쓰고 초안을 평가함

당신의 언어로 된 좋은 산문과 판단력

[models.thinker]만 선언하면 하나의 모델이 세 역할을 모두 수행합니다. 당신이 대화하는 그 모델이 곧 기억을 쓰고 평가하는 편집자입니다. 이것이 기본값이고 공정한 기본값입니다. 능력 있는 GPU 모델은 한가한 시간에 편집자의 작업을 충분히 잘 해내며, kura tend는 사용자가 돌아오는 그 순간 작업을 멈춥니다(아래 "무대 대기" 참조).

업그레이드는 편집자에게 별도의 자리를 주는 방식입니다 — 더 큰 모델, 온라인 API, 또는 GPU와 전혀 겨루지 않는 CPU 모델을 말이죠. 그레서 사용자가 대화하는 동안 기존의 유지보수를 계속할 수 있습니다. 이 프로젝트를 만든 곳에서는 1조 매개변수 MoE를 CPU에서 편집자로 약 3 token/s 속도로 돌렸습니다. 느리긴 하지만 대화가 사용하는 자리를 건드리지 않고 오고, 5일 동안 쓴 기억은 오늘 그 스토어의 3분의 1을 차지합니다. 각자 나머지 역할을 독립적으로 업그레이드할 수 있습니다 — 더 큰 로컬 모델, 또는 온라인 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) 방언이 reasoning_effort, thinking_effort, enable_thinking 식으로 다릅니다. 그래서 모두 전송합니다. 알 수 없는 것은 템플릿이 무시하고, 기본값이 깊은 사고 모드로 남아 있는 모델은 전체 토큰 예산을 이것에 다 소모하고 아무것도 반환하지 않을 수 있습니다. 또 헌장 텍스트가 모든 역할의 프롬프트 맨 앞에 바이트 단위로 동일하게 위치합니다. 따라서 느린 로컬 모델에서 세 역할이 프리필 세 번을 지불하는 대신 하나의 캐시된 프러프를 공유합니다.

느린 편집자는 프러프가 필요합니다. 헌장이 모든 호출 앞에 바이트 단위로 똑같이 놓이므로, 3 토큰/s CPU 편집자는 초안마다 한 번이 아니라 침묵마다 한 번 프리필을 지불합니다. llama.cpp에서는 반드시 --cache-reuse 0을 설정하지 말고, 서버가 슬롯을 따뜻하게 유지하게 하십시오(--slot-save-path). 일부러 timeout=3600로 한 시간 기다리도록 되어 있는 것은 편집자의 호출입니다.

thinker가 다운되어도 회또는 조용해지지 않습니다. 단어 겹침(word overlap)으로 폴백하고 답변에 how=words를 붙이며, 도구는 이것을 ⚠ degraded로 표시합니다. 조용한 성능 저하는 성능 저하보다 더 나쁩니다.

무대 실행: kura tend

증류, 부어 넣기, 직조는 조용한 시간에 돌도록 만들어진 일입니다. 언제 그 시간인지 결정하는 감시자(watcher)는 모델이 필요 없습니다.

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

증류기를 보지 못한 저널을 지정할 때 한 번에 catchup을 실행하면 됩니다. 그렇지 않으면 증류기의 첫 작업이 전체 이력을 잠그는 것이 됩니다. 1년 된 저널인 경우 저장소가 이미 알고 있는 것을 다시 배우는 며칠 치 모델 시간이 됩니다. catchup은 표시를 앞으로만 옮기므로 진행 상태를 잃을 수 없습니다.

"조용함"은 가장 최신 저널 파일의 mtime입니다. idle_min(10)의 침묵이 지난 후, 대기 중인 초안을 비웁니다(편집자가 각 초안을 하나씩 읽습니다: 부기/수정/버림). 또는 대기 초안이 없으면 증류 패스를 하나 실행합니다. 무가 주입되었으면 상주 인덱스를 한 번 다시 재조직합니다. 그리고 침묵마다 인덱스를 한 번 정리합니다. 할 일이 없던 트랙은 종료 코드 2로 나가고 backoff_min(20) 만큼 대기합니다. 빈 저널이 빈독글 돌지 않게 하기 위해서입니다. 완결한 작업 수(pour, toss, fix, draft)를 세지요, 시작된 작업 건수는 세지 않습니다. 각 트랙의 출력은 _still/till.log에 보관됩니다. 또 kura doctor가 읽는 하트비트(tending.alive)를 기록합니다. 조용히 죽는 감시자는 감시자가 절대 갖지 말아야 하는 유일한 실패이기 때문입니다.

저널이 바뀌면 동작 중인 트랙은 중지됩니다. 편집자가 보통 대화에 곧 사용하려는 바로 그 GPU이기 때문입니다. 편집자가 별도의 자리, 예를 들어 CPU 모델이나 다른 기계에 있다면 [distill] 아래 yield_on_return = false로 설정해서, 진행 중인 판정을 끝까지 맡길 수 있습니다. 자신이 사용했던 CPU 편집기를 얹혀 돌리고, 그 교훈으로 인해 다시 만든 감시자인. 이 설명은 docs/OPERATING.md에 systemd 유닛으로 있습니다.

이 프로젝트가 함께 제공하지 않는 것은 논문을 스스로 읽고 자동으로 저장소를 키워 주는 자율 연구 루프입니다. 이 프로젝트가 작성된 곳에는 그런 루프가 있습니다. 질문당 한 시간 동안 혼자 두어도 되는 모델이 필요하고, 그 결과물을 게이트가 판단에 쓰는 의미의 증거가 아닙니다. 그러므로 그것은 배포 콘텐츠가 아니라 사내 쪽에 있습니다.


기억의 모습

파일 하나에 사실 하나.

---
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]]

그리고 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가 기계적 감지 가능한 케이스를 찾아 그 줄들을 다시 씁니다.

metadata 아래/위의 네 줄은 **사실이 아니라 선점(curation)**입니다. tags는 기억의 성격에 대한 단어로, 여러 개인 것이 정상입니다. 이 태그가 생기기 전에 쓰여졌다면 그냥 없습니다. 세 문장은 이 기억이 이 저장소에 있어야 이유, 이후 의 얇=텍스트가 살아남아야 하는 의미와, 어떤 세부사항을 지워야 되는지를 말합니다. 증류기는 저장소의 헌장에 맞추어 이 세 문장을 제안합니다. 대신 entrusted, emotion-carried, recurring 등 인간에 대해 주장하는 태그는 인용문을 확인해 검증하며 그 검사는 매니페스트에 기록됩니다. recurred는 증류기에 의해서 한 번만 기록됩니다. 인간이 또 다른 세션에서 어떤 해당 주제를 다시 꺼냈을 때입니다. 그것은 속성(property)이지 카운터가 아니며 뒤 숫자 없습니다.

kura doctor는 개수, 죽은 링크, 고립된(어떤 기억도 링크하지 않는) 기억, 내용 드리프트, 읽 수 없는 태그 줄, 기억이 가리키는 매니페스트가 없어진 것, 학습된 프로필 상태, 그리고 저장소의 네 단위가 나란히 무게 — 메모리 개수, 인덱스 토큰, 내용 토큰, 바이트 — limit과 pressure는 None으로 둔 채 보고합니다. 시스템이 필요로 하는 눈이 있습니다. 저장소가 가득 찼을 때 어떤 일이 일어나는 것은 아직 정해지지 않았습니다. docs/DESIGN.md §8을 보세요.


HTTP 표면

route

어떤 일을 하는지

POST /recall

{question, hops, top, chars, total_chars, store|mode} → 선택함, 이동함, 컨텍스트. chars는 기억당 길이입니다. total_chars는 전체 컨텍스트의 상한선입니다.

POST /remember

{slug, description, body, type, title, tags, belongs_because, keep, may_fade} — 직접 쓰기(DIRECT write)이며, write_policy = "direct-allowed"가 아니면 거부됩니다.

POST /annotate

{slug, tags, belongs_because, keep, may_fade} — 기존 기억에 태그 및 세 문장을 병합합니다. 직접 쓰기와 동일한 거부 규칙이 적용됩니다. 아무 추가 내용이 없는 병합은 아무것도 수정하지 않습니다.

GET /index

원시 인덱스

GET /prefill

주입 준비가 된 상주 블록(&format=text는 연결용)

GET /memory/<slug>

하나의 기억 전체와 함께 그 tags 및 annotations를 반환

GET /doctor

한 스토어의 건전성 (?all=1이면 모든 스토어)

GET /stores

스토어들, 모드들, 각 역할을 채우는 모델

GET /profile

스토어의 헌(charter), 학습된 프로필과 그 상태(비어 있음/있음/깨짐 ), 페르소나의 위치 정보 (여기서 절대 렌더링하지 않음)

GET /health

활성(생존) 확인

모든 라우트는 ?store= / ?mode= 쿼리, 요청 본문의 store/mode 필드, 또는 /s/<name>/… 경로 접두어를 받습니다. 인증(authentication)은 없습니다. loopback 바인딩하거나, 그 앞단에 인증을 두어야 합니다.


변경 전에 읽어 둘 설계 메모

  • docs/DESIGN.md — 인식(recognition)이 검색보다 나은 이유, 게이트가 가져다주는 것이 무엇인지, 그리고 각 매커니즘을 만들게 도발한 실패 사례.

  • docs/OPERATING.md — 상주 실행, 스케줄러와 종료 코드, 백업, 무엇을 주시할지.

  • docs/TRUST.md — 스토어 경계가 무엇이고 무엇이 아닌지, 쓰기 정책, 그리고 놓치기 쉬운 두 가지 경계(공유 저널, 공유 모델). 사설 스토어를 넣기 전에 반드시 읽으십시오.

많은 실패처럼 보일 때까지 이상하게 보이는 몇 가지 결정:

  • 읽기 전에 예약한다. 증류기는 저널의 일정 범위를 머리 읽기 전에 잠금 상태로 가지며, 워터마크는 항상 앞으로만 움직입니다. 각자 자신의 스냅샷으로 되쓰는 두 증류기는 서로의 진행을 지우고 같은 물을 여러 번 옛어 마셨습니다.

  • 워터마크는 어댑터별로 단위가 다릅니다. 추가 전용 기록지에는 바이트만 오프셋을, 재기록되는 아카이브(archive)에는 시퀀스 번호를 사용합니다. (압축을 다시 한 파일에 바이트 오프셋은 거짓이기 때문.)

  • 노이즈 반향 억제. 스토어의 이미 존재하는 인용은 새로운 재료가 아닙니다. 그 도구 결과를 통해 스토어가 자기 자신을 읽어 오는 것입니다. 만약 없으면, 메모리 시스템이 자신의 내용을 다시 재발견하고 다시 기록하는 것을 끝없이 반복합니다.

  • 최후의 관문은 모델이지 사람이 아닙니다. 사람이 모든 초안을 검토해야만 하면 시스템은 조용히 그 사람을 병목으로 만든 것입니다. 초안이 영원히 쌓입니다. 어떤 종류도 항상 존재하지 않을 수 있는 사람을 요구해서는 안 됩니다.

  • kura distill run은 할 일이 없으면 종료 코드 2를 받습니다. 스케줄러는 "일함"과 "일거리가 없음"을 구분할 수 있어야 합니다. 그렇지 않으면 감시자가 빈 큐에서 헛돌며 유휴 시간을 필요로 하는 단계를 굶기리십니다.

주장하는 대신 측정하기

두 가지 질문이 하나의 숫자로 대응해서는 안 되래서 이런 대답은 안 됩니다.

얼마나 작아졌는가? store_ratio = 기억과 인덱스에 포함된 토큰 수 / 실제 소비한 원저장분의 토큰 수. 무엇이 사라졌는가? 그것은 다른 측정입니다. 100 중 하나만 기억하는 스토어는 첫 번째 숫자에서는 훌륭하지만 쓸모가 없습니다.

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

여기서는 배포하는 픽스처와 내장된 추정기를 사용해 측정했습니다.

Need check "코드" unclosed in "GXP14". We had "" accidentally? I introduced no code block. Wait in draft: "### 모습" "GXP14" "One file, one fact." I wrote "." that is a code fence? Actually no, I wrote "." without opening? Ah! Need scrub final output. We must not have stray code fences. I remember I wrote "." after "기억의 모습" maybe? In my draft above, I see:

"### 파일과One" Wait I wrote "GXP14" etc.

Let's revise final output carefully in final.

Need ensure no leading/trailing space, no code fences. Let's produce a correct final answer now페르소나는 호스트가 가져야 할 의무이지 우리의 의무가 아닙니다. 이 프로젝트는 페르소나를 렌더링하거나 주입하지 않습니다. 단지 스토어별로 어떤 페르소나 파일이 그 스토어에 속하는지 기록만 하며, 이 정보는 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가 세션 동안 스토어를 전환합니다.


모델: 기본은 하나, 역할은 한 번에 하나씩 업그레이드

세 대의 기계가 아니라 세 가지 역할입니다.

역할

실행 시점

요구 사항

thinker

모든 회상 때

작고 빨라야 하며, 의미를 통해 관련성을 판단해야 함

brain

증류 시: 저널 한 묶음 전체를 읽음

컨텍스트 길이와 인내심

scribe

증류 시: 기억을 쓰고 초안을 평가함

당신이 쓰는 언어로 된 좋은 산문과 판단력

[models.thinker]만 선언하면 하나의 모델이 세 가지 역할을 모두 합니다. 당신이 대화하는 모델이 곧 기억을 쓰고 시험하는 편집자입니다. 이것이 기본값이며 공정한 값입니다. 유능한 GPU 모델은 한가한 시간에 편집자의 일을 충분히 잘 감당하고, 당신이 돌아오는 순간 kura가 편집자의 작업을 멈춥니다(아래 "무관" 참조).

업그레이드 경로는 편집자에게 별도 자리를 마련해 주는 것입니다 — 더 큰 로컬 모델, 온라인 API, 또는 GPU와 전혀 경쟁하지 않는 CPU 모델이라면 당신이 대화하는 동안에도 유지 관리가 계속될 수 있습니다. 이 프로젝트가 만들어진 집에서는 CPU에서 1조(玄) 변수 모델을 편집자로 약 3 토큰/초로 돌렸습니다. 느리지만 대화가 쓰는 자리는 만지지 않으며, 5일 동안 쓴 기억이 오늘 그 스토어의 1/3입니다. 나머지 역할도 각각 독립적으로 업그레이드할 수 있습니다 — 더 큰 로컬 모델, 하자면 온라인 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) 방식이 다릅니다 (reasoning_effort, thinking_effort, enable_thinking). 그래서 전부 전송됩니다. 알 수 없는 것은 템플릿이 무시하고, 기본적으로 깊은 사고 모드가 켜진 모델은 예산 전체를 깊은 사고로 써버리고 아무것도 반환하지 못할 수 있습니다. 그리고 헌장(charter) 문구는 모든 역할 프롬프트의 맨 앞에 바이트 단위로 동일하게 배치되므로, 느린 로컬 모델에서는 세 역할이 프리필(prefill) 세 개를 각각 지불하는 대신 캐시된 접두사를 하나만 공유합니다.

느린 편집자는 접두사가 필요합니다. 헌장이 모든 호출의 맨 앞에 바이트 단위로 똑같이 자리하므로, 3 토큰/초 CPU 편집자는 초안 한 개마다가 아니라 침묵 한 번마다 프리필(prefill) 한 번만 지불합니다. llama.cpp에서는 반복 모델에 --cache-reuse 0을 두지 말고 서버가 슬롯을 늘 warm하게 유지하게 하세요 (--slot-save-path). 일부러 한 시간(timeout=3600)을 기다리는 호출은 편집자의 호출입니다.

thinker가 다운되어도 회상이 조용해지지 않습니다. 회상은 단어 겹침(word overlap)으로 폴백하고 답을 how=words로 표시합니다. 도구가 이 표시를 ⚠ degraded로 노출합니다. 조용히 성능이 떨어지는 것은 성능이 떨어진 것보다 더 나쁩니다.

무관리: kura tend

증류기(distiller)와 붓는 곳(pourer)과 짜는 곳(loom)은 조용한 시간에 돌아가도록 설계되었습니다. 언제가 조용한 시간인지 판단하는 감시자는 모델이 필요 없습니다.

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

증류기가 처음 보는 저널을 지정했다면 catchup을 한 번 실행하세요. 그렇지 않으면 첫 번째 작업이 전체 이력을 모두 흡수해 버리는데, 저널이 일 년 분량이면 스토어가 이미 알고 있을 내용을 다시 학습하는 데 며칠의 모델 시간을 씁니다. 그것은 워터마크를 앞으로만 이동시키므로 진행 상태가 손실될 일이 없습니다.

"조용함"은 가장 최신 저널 파일의 mtime입니다. idle_min(10) 동안 조용함이 지속되면 대기 중인 초안을 비웁니다 (편집자가 각 초안을 "차갑게" 읽습니다: 부음 / 수정 / 폐기), 대기 초안이 없으면 증류 한 패스를 실행합니다. 무언가 부어지면 상주 인덱스(resident)가 한 번 다시 짬 하고, 침묵 동안 인덱서가 한 번 정리를 합니다. 할 일이 없던 트랙은 exit 2로 끝나고 backoff_min(20) 동안 쉬므로 빈 틈이 빙글빙글 도는 일이 없습니다. 그것은 일(pour / toss / fix / draft)을 세는 것이지 시작(launch)을 세지 않습니다. 각 트랙의 출력은 _still/tend.log로 계속 보관됩니다. 그리고 kura doctor가 읽는 하트비트(tending.alive)를 기록합니다. 조용히 죽는 감시자는 감시자가 가져서는 안 될 유일한 실패이기 때문입니다.

저널이 바뀌면 실행 중인 트랙이 멈춥니다. 편집자는 보통 당신이 곧 대화에 사용하려는 GPU와 같기 때문입니다. 편집자가 별도의 자판 — CPU 모델, 다른 기계 — 에 있으면 [distill] 아래에 yield_on_return = false를 설정해서, 비행 중인 인상을 끝까지 마치게 합니다. 이 집이 CPU 편집자와 함께 5일 동안 돌려 보고 배운 교훈으로 다시 만든 감시자입니다. docs/OPERATING.md에 systemd 유닛이 있습니다.

이 프로젝트가 포함하지 않는 것은: 논문을 읽고 스토어를 스스로 키우는 개방형 연구 루프입니다. 이 집에는 그것이 있습니다. 질문 하나마다 한 시간 동안 혼자 하고 모델이 가능하며, 그 결과는 게이트가 증거라고 여기는 의미의 증거가 아닙니다. 그 루프는 집의 내부에 남습니다.


기억의 형태

파일 하나에 사실 하나.

---
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]]

그리고 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가 기계적으로 감지할 수 있는 그런 경우를 찾아 재작성합니다.

metadata 아래/상단의 네 줄은 사실이 아니라 큐레이션입니다. tags는 기억의 성격을 설명하는 단어입니다 — 여러 개인 것이 정상이고, 태그가 존재하기 전에 쓸 기억은 그냥 없습니다. 그리고 네 번째 줄이 이유는 "이것이 이 스토어에 있는 이유", "이후 필요한 것이 어떠한 제거에서 살아남아야 하는 의미", "저장될 필요 없는 세부사항" 이다. 증류기는 스토어의 헌장에 대비해 그것을 제안합니다. 사람에 관한 어떤 주장을 담은 태그 (entrusted, emotion-carried, recurred)는 인용문과 비교해 확인이 되며, 그 확인은 매니페스트에 기록됩니다. recurred는 증류기가 한 번 씁니다. — 사람이 다른 세션에서 다시 그 주제를 꺼냈다는 뜻입니다. 그것은 속성이지 카운터가 아니며 그 뒤에 숫자가 없습니다.

kura doctor는 카운트, 죽은 링크, 섬(inlets) 링크가 걸린 기억), 인덱스 드리프트, 읽 수 없는 태그 줄, 기억이 가리키는 매니페스트가 사라진 것, 학습된 프로필의 상태, 그리고 스토어 용량을 네 단위가 나란히 — 기억 수, 인덱스 토큰, 본문 토큰, 바이트 — limit과 pressure는 None으로 두고 보고합니다. 그것이 신진대사가 필요한 언어입니다. 스토어가 가득 찼을 때 벌어질 일은 아직 정해지지 않았습니다. docs/DESIGN.md §8 참조.


HTTP 표면

라우트

하는 일

POST /recall

{question, hops, top, chars, total_chars, store|mode} → 고름, 걸어짐, 컨텍스트. chars는 기억 하나 술 크기, total_chars는 컨텍스트 전체의 하드 상한.

POST /remember

{slug, description, body, type, title, tags, belongs_because, keep, may_fade} — 직접 쓰기(DIRECT write), write_policy = "direct-allowed"가 아니면 거부됨

POST /annotate

{slug, tags, belongs_because, keep, may_fade} — 기존 기억에 태그/삼문서를 병합. 직접 문 언어. /remember와 동일한 거부 조건. 아무것도 더하지 않는 병합은 아무것도 만조치 않음

GET /index

원시 인덱스

GET /prefill

저장소 상주 블록, 삽입 준비됨 (&format=text는 훅용)

GET /memory/<slug>

기억 하나를 완전하게 표시, 해당 tags와 annotations 포함

GET /doctor

스토어 하나의 상태 (?all=1 모든 스토어)

GET /stores

스토어, 모드, 어떤 모델이 각 역할을 맡는지

GET /profile

스토어의 헌장, 학습된 프로필(state: 없음/있음/깨짐), 그리고 페르소나의 위치 (여기에서는 절대 렌더하지 않음)

GET /health

대기 상태

어떤 라우트든 ?store= / ?mode=, 본 몸안의 store/mode 필드, 또는 /s/<name>/… 경로 지정을 받아들입니다. 인증은 없습니다. loopback에 바인딩하거나 그 앞에 무언가를 두십시오.


무결과 전에 읽을만한 설계 메모

  • docs/DESIGN.md — 왜 인식이 검색보다 좋은가, 게이트가 사는 것이 무엇인지, 각각의 동작이 왜 생겨났는지(실패 소동).

  • docs/OPERATING.md — 상주 실행, 스케줄러와 종료 코드, 백업, 무엇을 볼 것인지.

  • docs/TRUST.md — 스토어 경계가 무엇이고 무엇이 아닌지, 쓰기 정책, 그리고 놓치기 쉬운 두 경계(공유 내기, 공유 모델). 이것을 읽고 관리 전용 스토어를 넣으면 됩니다.

이상해 보이는 여러 가지 결정은, 그것이 막는 그것을 부닥뜨리기 전까지 이상해 보입니다.

  • 마실 때는 먼저 예약하라. 증류기는 저널 중 어떤 구간을 읽기 전에, lock 으로 선점하고 water 마크는 앞으로만 이동합니다. 두 증류기가 각자 자신의 스냅샷을 돌리면 서로의 전진을 지우고 오래된 물을 같은 이유로 다시 마시게 됩니다.

  • 워터마크 단위는 어댑터별로 다릅니다. 추가 전용 트랜스크립트에는 바이트 오프셋, 재저장되는 아카이브에는 시퀀스 번호를 씁니다. (압축 다시 않은 파일에 바이트 오프셋은 거짓말입니다).

  • 에코 억제(echo suppression). 스토어에 이미 있는 인용은 새로 발견되는 것이 아니라, 스토어가 그것을 도구 결과로 통해 스스로가 말하는 것입니다. 이것이 없으면 기억 시스템이 저장소의 내용을 영원히 재발되고 재기록합니다.

  • 마지막 관문은 모델이지 사람이 아닙니다. 사람이 트래프를 모두 승인해야 한다면, 시스템은 그 사람을 조용히 자기의 병목으로 만들고 초안은 영원히 쌓입니다. 그 길 안에 들어있는 모든 단계는 항상 참재하기로 되어 있는 누군가 없어도 되지 않으면 안 됩니다.

  • kura distill run은 일이 없으면 exit 2로 넘어옵니다. 스케줄러는 "일을 했다"와 "아무것도"가 없다"를을 구분할 수 있어야 합니다. 그렇지 않으면 감시자가 빈 큐위에서 계속 돌며 유휴 시간이 필요한 단계를 곁아 좋지 못합니다.

주장 대신 측정

하나의 숫자로 두 개의 다른 질문에 답이 되지 않게 대해서는 안됩니다.

얼마나 작아졌는가? store_ratio = 기억과 인덱스의 토큰 수 / 실제 소비된 그 raw 저널의 토큰 수. 무엇을 잃었는가? 그것은 다른 측정입니다. 백분율도 하나만 유지하는 스토어는 첫 측정에서 아름다운 점수를 받지만 그렇게 되면 볼의가 없습니다.

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

배포된 픽스처와 내장 추정기로 여기서 측정된 것입니다.

corpus

store_ratio

scripts/demo-clean-room.sh (일반 대화, 대부분 잡담)

0.18

bench/fixtures/corpus.jsonl (밀집: 모든 줄이 신호)

1.14

두 번째는 버그가 아닙니다. 잡담이 전혀 없는 자료에서 증류는 압축되지 않습니다. 각 기억은 이유와 적용 방법을 추가하므로 저장소는 대화 기록보다 약간 더 커집니다. 비율은 이 도구가 아니라 말뭉치의 속성입니다. 그래서 여기에는 대표 수치가 없고, 명령이 계산한 내용을 보고하는 이유이기도 합니다.

보존 점수는 모델 없이 산정됩니다. 심어진 각 사실에는 회상이 반환하는 내용에 반드시 나타나야 하는 표식이 있어서, 다른 사람의 머신에서도 점수를 재현할 수 있습니다. 방해 요소는 반대로 작용합니다. 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+ (의존성 없음; pip install -e ".[dev]"는 pytest만 추가)

Node

20+, DSH 플러그인 전용

zstd

DSH 세션 아카이브를 읽는 데만 사용

모델 엔드포인트

OpenAI 형식으로 POST <url>/chat/completions에 응답하는 모든 것

"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도 같은 방식으로 작성되었습니다. 모든 사례는 행복한 경로가 아니라 탈출 시도입니다. 실제로 존재했던 허점(경로를 알 수 있는 모든 파일에 대해 저장소가 응답하던)을 막기 때문입니다. 종단 간 테스트는 실제 소켓에서 스크립트된 모델 서버에 대해 전체 증류→드레인 주기를 실행합니다.

라이선스

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