altair823 5596d41565 chore: bump version 0.32.0 → 0.33.0
28.4k 문서 도그푸딩이 드러낸 다섯 결함(#228–#232)을 전부 처리한 릴리스.
다섯 건 모두 단위 테스트가 잡지 못하는 종류였다 — 규모에서만 드러나는 성능
붕괴, 조용히 사라지는 내용, 멈춘 것처럼 보이는 진행 표시.

minor 트리거는 두 가지다. #232 의 parser_version cascade
(pdf-text-v1 → pdf-text-v2, 기존 색인 PDF 재처리 유발)와 신규 config 키
([ingest.pdf.ocr] render_library / render_dpi). 나머지 셋은 additive wire
변경 + 관측성 개선이라 자체로는 patch 급이다.

  #232  스캔 PDF 를 페이지 렌더링으로 OCR — CCITTFax/JBIG2/Flate/JPX 가
        조용히 버려지던 것을 pdfium 런타임 로드로 커버. 없으면 DCTDecode
        폴백 + 왜 건너뛰었는지 명시. 단일 바이너리 유지.
        한국어 CCITT 스캔 CER 12.6~15.7% (이 릴리스 이전엔 본문 0자).
  #229  chunks_fts 삭제를 rowid 조회로 (V016) — 문서 200건 삭제
        1590초 → 2.0초. 검색 결과 불변, 재색인 불필요.
  #230  Lance fragment 압축 + 삭제 배치화 — 2.8만 문서 색인 속도가 분당
        32~36건으로 평탄 유지(이전 30.7 → 4.3 단조 하락), 15 GB → 2.8 GB.
  #228  삭제 sweep 을 진행바·ndjson 로그에 노출 — 무표시 구간이 hang 으로
        오인되던 것. sweep 이 취소 플래그도 보게 했다.
  #231  derivation cache 배칭 + 계측 — 가설은 재현되지 않았다(히트 139초
        vs 우회 1180초). 이슈 스스로 예측한 대로 #229 가 해소했다.

도그푸딩 evidence 는 tasks/HOTFIXES.md 2026-08-16 / 2026-08-17 항목.
사용자 영향 설명은 docs/release-notes/v0.33.0-draft.md.

곁들여, `cargo clippy --workspace --all-targets -- -D warnings` 가 main 에서
실패하고 있던 것을 고쳤다(툴체인 상승으로 새 lint 둘이 기존 코드에 걸림).
방치하면 새 위반이 그 그늘에 숨는다는 것을 실제로 겪었다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017c9JwQq8ZkGvYjpKXMiDhF
2026-08-17 06:23:20 +09:00

kebab — Local-first Knowledge Base + RAG

kebab 는 개인용 로컬 knowledge base + RAG 도구다. Markdown · PDF · 이미지 · 소스코드를 한 곳에 색인하고, 하이브리드 의미 검색과 근거 인용을 포함한 LLM 답변을 단일 binary 로 제공한다. 모든 추론은 로컬 (Ollama + fastembed) 에서 돌아간다.

📍 어느 문서가 현재 진실인지 한눈에: DOCS.md (문서 지도 / Source-of-Truth 인덱스).

Quick start

사전 요구는 두 가지뿐이다.

  • Rust toolchain ≥ 1.85 (workspace 가 edition 2024 사용). rustup.
  • Ollamakebab ask 와 이미지/PDF OCR 가 사용. 공식 설치 안내 참고 후 ollama serve 실행. 기본 LLM family 는 gemma4 (ollama pull gemma4:e4b) — OCR/caption 도 같은 family 라 모델 하나면 된다. CPU-only 환경이면 소형 모델 (예: gemma3:4b) 을 권장.
# 1) 빌드 + 설치 (~/.cargo/bin/kebab)
git clone https://gitea.altair823.xyz/altair823-org/kebab.git
cd kebab
cargo install --path crates/kebab-cli --locked

# 2) 데이터 디렉토리 + config.toml 생성 (XDG 경로)
kebab init

# 3) config 최소 손보기 — workspace.root (색인할 폴더) 와 LLM endpoint
${EDITOR:-vi} ~/.config/kebab/config.toml

# 4) 색인 (Markdown · PDF · 이미지 · 소스코드 한 번에)
kebab ingest

# 5) 검색 (hybrid = lexical + vector RRF, citation 포함)
kebab search "Markdown chunking 규칙"

# 6) 질문 (RAG 답변 + 근거 인용, Ollama 필요)
kebab ask "내 KB 설계에서 저장소 전략은?"

clone 없이 git URL 로 바로 설치할 수도 있다: cargo install --git https://gitea.altair823.xyz/altair823-org/kebab.git --bin kebab --locked. 업데이트는 동일 명령에 --force. 제거는 cargo uninstall kebab-cli (데이터는 보존 — 데이터까지 지우려면 kebab reset --all --yes).

설치 없이 dev 흐름으로 돌려볼 때는 cargo run --release -p kebab-cli -- <subcommand>. 격리된 임시 워크스페이스로 검증하는 절차는 docs/SMOKE.md (--config <path> 로 분리).

핵심 기능

하이브리드 검색 + citation

lexical (FTS5 BM25) 과 vector (cosine) 두 채널을 RRF fusion 으로 합쳐 검색한다. 모든 hit 은 출처 위치를 매체별로 정확히 담는다 — Markdown/코드는 line, 이미지는 region, PDF 는 page. --tag · --media · --lang · --path-glob 등 다양한 필터와 --max-tokens · --cursor 같은 agent budget flag 를 지원한다.

파생물 캐시 (자동)

embedding 벡터뿐 아니라 이미지/PDF 의 OCR·caption 결과까지 내용 해시 로 캐싱한다 (derivation_cache). 재색인·갱신 시 내용이 같으면 임베딩 재계산은 물론 비싼 OCR·vision 호출도 건너뛴다 (vision 산출물을 버전-캐스케이드에서 분리). 캐시 키에 모델·버전이 포함돼 버전 변경 시 자동 무효화된다 (cascade 안전). 별도 설정 없이 투명하게 동작한다. (현재 TTL/LRU 자동 정리는 미구현 — 누적된 캐시는 kebab reset 으로만 정리.)

외부 계산 + 로컬 검색 워크플로

search/ask 는 원본 파일 없이 KB 산출물만으로 동작한다 (청크 본문이 SQLite 에 저장되고 문서 경로는 상대경로로 기록됨). 비싼 색인(임베딩·OCR)을 성능 좋은 머신에서 수행한 뒤, 두 산출물만 다른 머신으로 복사하면 그대로 검색·질문할 수 있다.

무엇을 복사하나 — [storage] 에서 정의된 두 경로:

복사 대상 config 키 ([storage]) 기본 경로 내용
kebab.sqlite sqlite = "{data_dir}/kebab.sqlite" {data_dir}/kebab.sqlite 문서·청크·본문·FTS5·메타
lancedb/ vector_dir = "{data_dir}/lancedb" {data_dir}/lancedb/ 임베딩 벡터

{data_dir}[storage].data_dir (예: ~/.local/share/kebab). models/(model_dirassets/(asset_dir)는 복사 불필요 — 모델은 각 머신이 자기 캐시를 받고, asset 원본 바이트는 검색·질문에 쓰이지 않는다 (단일파일/stdin 색인의 원본 재읽기·재색인까지 보존하려면 assets/ 도 함께 복사).

# ingest 가 끝난(쓰기 없는) 상태에서 복사
rsync -a <src-data_dir>/kebab.sqlite  user@server:<dst-data_dir>/
rsync -a <src-data_dir>/lancedb/      user@server:<dst-data_dir>/lancedb/

조건: 양쪽 동일 kebab 버전 + 동일 임베딩 모델/차원 ([models.embedding].model·dimensions). provider 는 달라도 됨 (예: fastembedollama — 같은 모델이면 벡터 호환). 복사는 반드시 ingest 가 돌지 않을 때.

멀티미디어 색인

Markdown · PDF · 이미지(OCR + caption) · 소스코드(Rust/Python/TS/JS/Go/Java/Kotlin/C/C++ AST) · 리소스(YAML/Dockerfile/TOML/JSON/XML 등)를 확장자에 따라 자동으로 적절한 chunker 에 라우팅한다. embedded text 가 없는 scanned PDF 는 [ingest.pdf.ocr] 로 page-단위 OCR (opt-in; 인코딩 무관하게 읽으려면 render_library 에 libpdfium 지정). 전체 확장자→chunker 매핑은 docs/ARCHITECTURE.md.

RAG (근거 인용 + 거절)

검색 결과를 근거로 LLM 답변을 생성하고 [#번호] 인용을 단다. 근거가 부족하면 답을 지어내지 않고 거절한다. compound 질문은 --multi-hop 으로 분해→synthesize. 답변의 groundedness 는 mDeBERTa XNLI 로 검증할 수 있다 ([rag] nli_threshold, default off).

명령

명령 동작
kebab init XDG 경로에 데이터 디렉토리 + config.toml 생성
kebab ingest [<path>] 워크스페이스 스캔 후 새/변경 문서 색인 (idempotent · incremental, --force-reingest 로 강제 재처리). 미지원 확장자는 자동 skip. 진행바는 현재 파일명 · 느린 phase(ocr/caption/embed)+모델명 · 경과초(Ns) · 문서별 청크 수 · phase별 소요시간(parse/chunk/ocr/caption/embed/store)과 임베딩 캐시 적중(cache 히트/전체 소요)을 표시하고, 종료 시 최장 소요 파일 top-5 를 요약한다 (--jsonasset_phase/asset_chunked/asset_timings 이벤트로, 사람용 요약은 미출력)
kebab ingest-file <path> 단일 파일 ingest (workspace 외부 가능 — _external/ 로 deterministic copy)
kebab ingest-stdin --title <T> stdin 의 markdown 본문 ingest
kebab search --mode {lexical,vector,hybrid} "<query>" [flags] 검색 (default hybrid = RRF fusion, citation 포함). 출처 필터 --source <id> ([[workspace.sources]] id) · --source-type {markdown,note,paper,reference,inbox} (둘 다 repeatable/comma-sep, OR). 그 외 필터/budget flag 는 --help
kebab ask "<query>" [flags] RAG 답변 + 근거 인용 (Ollama 필요). --explain · --stream · --multi-hop
kebab list docs 색인된 문서 목록
kebab inspect doc <id> / inspect chunk <id> raw record 보기
kebab fetch chunk|doc|span <id> [flags] indexed corpus 에서 verbatim text fetch
kebab eval run | aggregate | compare | variants golden query 회귀 측정 + 변형 일관성 진단. compare --max-drop <낙폭> 은 어떤 지표든 그 이상 떨어지면 exit 1 — 절대 하한이 아니라 델타 예산이다 (없으면 delta 만 출력하고 항상 exit 0)
kebab schema [--json] introspection — wire schemas / capabilities / models / stats
kebab doctor 설정 / 모델 / DB 헬스 체크. vector_store 체크는 Lance fragment·버전 수를 정보성으로 보여준다(종료 코드에 영향 없음). fts_shadow 체크는 어휘 인덱스가 원본과 어긋났는지 보며, 어긋나면 exit 3 — 이 상태에서는 문서 삭제가 엉뚱한 인덱스 행을 지운다. pdf_render 체크는 스캔 PDF 페이지 렌더러(pdfium)가 있는지 정보성으로 알려준다
kebab mcp MCP stdio server (search / bulk_search / ask / fetch / schema / doctor / ingest_file / ingest_stdin)
kebab reset [--all | --data-only | --vector-only | --config-only | --orphans-only] [--yes] XDG 데이터 wipe (irreversible)

모든 명령에 --json 플래그가 있고, 출력은 frozen wire schema v1 을 따른다 (schema_version 항상 포함). --json 모드에서 fatal error 는 stderr 에 error.v1 ndjson 으로 emit (exit code 0/1/2/3 불변). 글로벌 flag: --readonly (write-path 비활성화), --quiet (human stderr 억제), env KEBAB_PROGRESS=plain. 전체 flag·wire 의미는 kebab <cmd> --helpdocs/wire-schema/v1/. 외부 agent 통합(Claude Code skill / MCP)은 docs/mcp-usage.mdintegrations/.

Configuration

~/.config/kebab/config.tomlkebab init 가 XDG 경로에 생성한다. 핵심 노브만 정리한다 (전체 절은 생성된 파일 주석 참고, 예시는 docs/SMOKE.md).

[workspace]
root = "~/KnowledgeBase"   # 색인할 폴더. 절대 / tilde / env / 상대 경로 가능.
                          # 상대 경로의 base 는 config.toml 위치 (cwd 무관).
                          # 단일 root 는 implicit `default` source 로 정규화된다.

# 멀티소스 (선택) — 출처별로 검색을 좁히려면 root 대신 명명 source 를 선언한다.
# 각 source 의 id 가 모든 문서에 stamp 되고, `kebab search --source <id>` 로 필터.
# trust_level / source_type 은 frontmatter 가 없을 때의 source 기본값
# (우선순위: frontmatter > source 기본값 > 하드코딩 Primary/Markdown).
# [[workspace.sources]]
# id = "notes"
# root = "~/KnowledgeBase/notes"
# [[workspace.sources]]
# id = "jira"
# root = "~/exports/jira"
# trust_level = "secondary"   # 낮은 신뢰 출처 — `--trust-min primary` 로 배제 가능.

[models.embedding]
provider = "fastembed"            # "fastembed"(기본, onnxruntime) / "ollama"(원격 HTTP)
                                  # / "none"(lexical-only).
model = "multilingual-e5-large"   # 다국어 sentence embedding (1024-dim).
                                  # 첫 ingest 시 ONNX (~1.3GB) 자동 다운로드.
                                  # ollama 는 "snowflake-arctic-embed-l-v2.0"
                                  # (설명형 query 의 recall 보강) 도 지원 — 아래 참고.
dimensions = 1024                 # config 와 LanceDB stored dim 불일치 시 검색 0건.
# endpoint = "http://127.0.0.1:11434"  # provider="ollama" 전용 HTTP endpoint.
                                  # 생략 시 [models.llm].endpoint 로 폴백.
                                  # fastembed provider 는 무시.

arctic-embed-l-v2.0 (설명형 query recall 보강): 기본 e5-large 대신 Snowflake arctic-embed-l-v2.0 임베더를 쓸 수 있다 (1024-dim, opt-in). 측정에서 설명형/약어/영문 용어 query 의 recall@10 이 e5 대비 향상됐다. 두 경로:

# ollama 백엔드 — 원격/로컬 Ollama 데몬에 위임 (POST /api/embed):
[models.embedding]
provider = "ollama"
model    = "snowflake-arctic-embed2"          # Ollama 모델 태그 (ollama pull 필요)
endpoint = "http://127.0.0.1:11434"           # 생략 시 [models.llm].endpoint

⚠️ e5 → arctic 전환은 embedding_version cascade 를 트리거한다 (모델이 다르면 벡터도 다름). 기존 e5 KB 와 혼용 불가 — 전환 시 재색인 필요 (kebab reset 후 재 ingest). 기본값은 e5 라 기존 사용자는 영향 없음.


[models.llm]
endpoint = "http://localhost:11434"   # Ollama host:port
model = "gemma4:e4b"
# request_timeout_secs = 300          # 큰 모델은 늘림. 0 은 disable 이 아니라 "즉시 timeout".

[search]
stale_threshold_days = 30   # search hit / citation 의 stale 플래그 기준 (0 = off).

[rag]
prompt_template_version = "rag-v4"   # 각 근거의 source/trust 라벨로 low-trust 출처 discount + 답변 언어 = 질문 언어. rag-v3 는 legacy.
nli_threshold = 0.0                  # >0 (예: 0.5) 면 mDeBERTa XNLI groundedness 검증.
  • [ingest] (v0.28.0) — 모든 형식 ingest 설정의 우산. 병렬도(max_parallel_extractors/max_parallel_embeddings/watch_filesystem, ← 옛 [indexing])와 형식별 하위 절([ingest.chunking] ← 옛 [chunking], [ingest.code], [ingest.image.ocr] ← 옛 [image.ocr], [ingest.pdf.ocr] ← 옛 [pdf.ocr])이 전부 이 아래로 모인다. 기존 v2 config.toml 은 그대로 둬도 로드 시 메모리에서 자동 변환되며, 파일을 새 레이아웃으로 갱신하려면 kebab config migrate (값·주석 보존).

  • [ingest.chunking] — 청크 크기·오버랩·heading 존중. chunker_version 기본 "md-heading-v2" (v0.30.0). max_chunk_tokens (default 4000, byte/3 토큰) — 이 값을 넘는 청크는 줄(→UTF-8 char) 경계로 분할해 각 조각이 예산 이하가 되게 한다. 거대 list/code/log 덤프가 한 청크로 임베더 컨텍스트를 초과하던 문제를 막는다(미분할 청크는 v0.29.0 md-heading-v1 과 출력 동일). 이 값을 바꾸면 markdown 자산이 자동 재청크된다.

  • 파생물 캐시 — embedding 결과를 내용 해시로 자동 캐싱한다 (위 「핵심 기능」 참고). 설정 항목 없음.

  • [ingest.code] — code ingest 의 skip 정책 (skip_generated_header, max_file_bytes, extra_skip_globs). .gitignore 자동 honor, .kebabignore 는 추가 layer.

  • [ingest.ocr] (config schema v5) — image/pdf OCR 가 공유하는 엔진 설정의 단일 출처 (engine/model/endpoint/languages/max_pixels/request_timeout_secs + paddle 모델 경로·튜닝 키). 여기에 한 번 적어 두면 image·pdf 양쪽에 적용되고, 각 미디어 블록([ingest.image.ocr]/[ingest.pdf.ocr])이 자기 키로 override 한다 (우선순위: 미디어 블록 > [ingest.ocr] > 내장 기본값). 옛 v4 config.toml 의 image/pdf 에 중복돼 있던 OCR 엔진 키는 로드 시 자동으로 이 블록으로 통합된다 (effective 값 불변, 자동 재색인 없음). env override 도 KEBAB_OCR_* 하나로 통합 (양쪽 미디어에 적용).

  • [ingest.image.ocr] — 이미지 OCR. on/off 토글(enabled, default off / opt-in)은 미디어별이며, 엔진 설정은 [ingest.ocr] 에서 상속하되 이 블록에서 override 할 수 있다. engine 으로 백엔드 선택: "ollama-vision" (default, 원격 vision LM) 또는 "paddle-onnx" (PP-OCRv5 ONNX 를 in-process 로 실행, Python 런타임 불필요, 큰 페이지 CPU <4초, 오프라인). paddle-onnx 는 워크스페이스에 번들된 모델을 쓰며 det_model/rec_model/dict 로 경로 override, score_thresh(0.3)/unclip_ratio(1.5)/max_boxes(1000) 로 검출 튜닝 가능. engine 또는 모델을 바꾸면 영향 이미지가 자동 재색인된다.

  • [ingest.pdf.ocr] — scanned PDF 의 page-단위 OCR (default off / opt-in, page 당 ~수십 초 cost). on/off 토글(enabled/always_on)과 PDF 고유 키(valid_ratio_threshold/min_char_count/lang_hint)는 미디어별이고, 엔진 설정은 [ingest.ocr] 에서 상속하되 이 블록에서 override 한다(PDF 기본 모델은 qwen2.5vl:3b, 이미지의 gemma4:e4b 와 다름 — 미디어별 기본값 보존). 활성화 후 옛 색인분은 kebab ingest --force-reingest 로 재처리.

    스캔본을 제대로 읽으려면 페이지 렌더러가 필요하다. render_librarylibpdfium 경로를 적거나 로더가 찾는 곳에 두면, 페이지 이미지가 어떤 인코딩이든(CCITTFax·JBIG2·Flate·JPX, 배경+마스크 분리 구조 포함) OCR 된다. 없으면 단일 DCTDecode(JPEG) 이미지 페이지만 OCR 되고 나머지는 본문 없이 색인되며, 그 건수가 ingest 요약의 ocr-skipped--jsonocr_skipped_pages 에 찍힌다. kebab doctorpdf_render 가 지금 어느 쪽인지 알려준다. render_dpi 는 렌더 해상도 요청(기본 300)이고 실제로는 max_pixels 가 이긴다 — PDF 기본값 max_pixels = 2048 이면 A4 는 175 DPI 언저리에서 잘린다. 300 을 실제로 쓰려면 max_pixels 를 3500 이상으로 올려야 하고, 그만큼 큰 이미지를 OCR 엔진이 받는다. 다만 OCR 엔진(ollama-vision·paddle-onnx 둘 다)이 max_pixels 를 256~4096 으로 다시 조인다 — 그보다 크게 적어도 4096 이 상한이다. pdfium 은 공유 라이브러리로만 배포돼서 바이너리에 넣지 않았다 — kebab 자체는 단일 실행 파일 그대로다.

  • --config <path> — 임시 워크스페이스 / 격리 테스트용 (CLI honor).

  • kebab config migrate — 새 버전에서 추가된 config 섹션을 기존 config.toml 에 설명 주석과 함께 채워 넣는다 (사용자가 손본 값·주석·순서는 보존, 멱등, 변경 시 자동 .bak 백업). --dry-run 으로 변경 미리보기. kebab doctor 가 갱신 필요 시 안내한다. kebab init 으로 새로 생성되는 config.toml 도 섹션별 주석을 포함한다.

  • KEBAB_* env — 런타임 override용 ~22개 키만 노출. 엔드포인트(KEBAB_MODELS_LLM_ENDPOINT, KEBAB_MODELS_EMBEDDING_ENDPOINT, KEBAB_OCR_ENDPOINT), 모델명/프로바이더(KEBAB_MODELS_LLM_MODEL, KEBAB_MODELS_EMBEDDING_MODEL, KEBAB_MODELS_EMBEDDING_PROVIDER, KEBAB_MODELS_LLM_PROVIDER, KEBAB_MODELS_NLI_MODEL), 경로(KEBAB_WORKSPACE_ROOT, KEBAB_STORAGE_DATA_DIR), 병렬도(KEBAB_INDEXING_MAX_PARALLEL_EXTRACTORS, KEBAB_INDEXING_MAX_PARALLEL_EMBEDDINGS), 청킹(KEBAB_CHUNKING_TARGET_TOKENS, KEBAB_CHUNKING_OVERLAP_TOKENS), OCR 토글/엔진/언어(KEBAB_IMAGE_OCR_ENABLED, KEBAB_PDF_OCR_ENABLED, KEBAB_OCR_ENGINE, KEBAB_OCR_MODEL, KEBAB_OCR_LANGUAGES), 기타(KEBAB_IMAGE_CAPTION_ENABLED, KEBAB_SEARCH_DEFAULT_K, KEBAB_RAG_PROMPT_TEMPLATE_VERSION). 나머지 세부 튜닝 키(score_gate, rrf_k, temperature 등)는 config.toml 전용. 특수: KEBAB_READONLY=1(write-path 비활성), KEBAB_PROGRESS=plain(non-TTY 진행 출력), KEBAB_EVAL_GOLDEN(eval golden set 경로).

  • XDG layout: ~/.config/kebab/, ~/.local/share/kebab/, ~/.cache/kebab/, ~/.local/state/kebab/.

아키텍처

flowchart TB
    user(["사용자"])

    subgraph UI["UI binary"]
        cli["kebab CLI"]
    end

    subgraph App["Facade"]
        app["kebab-app"]
    end

    subgraph Pipeline["도메인 + 파이프라인"]
        parse["parse-md / parse-pdf / parse-image / parse-code"]
        chunker["chunker (md / pdf / code-AST / manifest)"]
        embedder["embedder (fastembed multilingual-e5-large)"]
        retriever["retriever (lexical / vector / hybrid RRF)"]
        rag["RAG pipeline"]
    end

    subgraph Store["저장소"]
        sqlite[("SQLite + FTS5")]
        lance[("LanceDB")]
        assets[("asset bytes")]
    end

    subgraph External["외부"]
        fs[("workspace files")]
        ollama[("Ollama HTTP")]
    end

    user --> cli
    cli --> app

    app --> parse
    app --> chunker
    app --> embedder
    app --> retriever
    app --> rag

    fs --> parse
    parse -. vision OCR / caption .-> ollama
    parse --> sqlite
    parse --> assets

    chunker --> sqlite
    embedder --> lance
    retriever --> sqlite
    retriever --> lance

    rag --> retriever
    rag --> ollama

핵심 설계 (요약 — 상세는 docs/ARCHITECTURE.md):

  • crate facadekebab-app 가 유일한 facade다. UI binary (kebab-cli) 는 store / parse / search / llm / rag 를 직접 참조하지 않는다 (frozen 설계 §8). 각 user-facing 엔트리는 *_with_config(cfg, …) 동반 함수로 explicit config 를 thread 한다.
  • chunk_id 는 위치 기반 — chunk 의 정체성은 문서 내 위치(ordinal + span)다. 반면 파생물 캐시 키는 내용 해시라, 내용이 같으면 위치·문서가 달라도 동일 캐시를 재사용한다.
  • wire schema v1 — 모든 --json 출력은 schema_version 을 담는 frozen contract다. 깨는 변경은 *.v2 major bump을 요구한다.
  • versioning cascadeparser_version / chunker_version / embedding_version / prompt_template_version / index_version 변경은 downstream record(청크·임베딩·캐시·eval)를 무효화한다.

crate-level 의존성 그래프 · 디렉토리 트리 · 확장자→chunker 전체 매핑 · 핵심 기술 결정은 docs/ARCHITECTURE.md, 진척도는 HANDOFF.md.

비-목표

다중 사용자 SaaS / K8s / 원격 vector DB / enterprise RBAC / 실시간 협업 / agent 임의 파일 수정 / multi-workspace / LLM-as-judge eval / CLIP 시각 embedding — frozen 설계 §0 / §11 참조.

버전 / 라이선스 / 참고

Description
Single-user, local-first knowledge base + RAG in Rust. Hybrid search, grounded answers, fully local inference.
Readme 30 MiB
Languages
Rust 100%