Skip to main content
Glama
lna-lab

distill-kura

by lna-lab

蒸留蔵 — 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 typepinned_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는 개수, 죽은 링크, 고립된(어떤 기억도 링크하지 않는) 기억, 내용 드리프트, 읽 수 없는 태그 줄, 기억이 가리키는 매니페스트가 없어진 것, 학습된 프로필 상태, 그리고 저장소의 네 단위가 나란히 무게 — 메모리 개수, 인덱스 토큰, 내용 토큰, 바이트 — limitpressureNone으로 둔 채 보고합니다. 시스템이 필요로 하는 눈이 있습니다. 저장소가 가득 찼을 때 어떤 일이 일어나는 것은 아직 정해지지 않았습니다. 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>

하나의 기억 전체와 함께 그 tagsannotations를 반환

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) 링크가 걸린 기억), 인덱스 드리프트, 읽 수 없는 태그 줄, 기억이 가리키는 매니페스트가 사라진 것, 학습된 프로필의 상태, 그리고 스토어 용량을 네 단위가 나란히 — 기억 수, 인덱스 토큰, 본문 토큰, 바이트 — limitpressureNone으로 두고 보고합니다. 그것이 신진대사가 필요한 언어입니다. 스토어가 가득 찼을 때 벌어질 일은 아직 정해지지 않았습니다. 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>

기억 하나를 완전하게 표시, 해당 tagsannotations 포함

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.

Install Server
A
license - permissive license
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • 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
    8
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    An agentic memory system that enables AI assistants to store, search, and manage persistent memories with semantic understanding using natural language instructions.
  • 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.
    16
    MIT

View all related MCP servers

Related MCP Connectors

  • Persistent memory for AI agents — verbatim conversations, searchable by meaning.

  • Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.

  • Persistent memory and knowledge graphs for AI agents. Hybrid search, context checkpoints, and more.

View all MCP Connectors

Latest Blog Posts

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/lna-lab/distill-kura'

If you have feedback or need assistance with the MCP directory API, please join our Discord server