From 24e9f739ddd4d846721d86ac4e61827a3f24d390 Mon Sep 17 00:00:00 2001 From: altair823 Date: Sat, 2 May 2026 13:43:24 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20CLAUDE.md=20README=20sync=20rule=20+=20?= =?UTF-8?q?README=20=ED=98=84=ED=96=89=ED=99=94=20(P5=20/=20P6=20/=20P7=20?= =?UTF-8?q?/=20P9-1=20=EB=B0=98=EC=98=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLAUDE.md 에 새 절 \"User-facing docs (README)\" 추가: - Implementation PR 이 README 를 갱신, spec PR 은 안 건드림. - 3 surface (CLI / TUI / Configuration) 마다 README 의 어느 행을 손대야 하는지 명시. - Phase status table 갱신 의무 (⏳ → ✅). - HOTFIXES detail / version cascade / per-task spec rationale 는 README out of scope. 같은 PR 에서 README 의 stale 부분 한꺼번에 정리: - 상태 line: P0–P5 + P6 + P7 + P9-1 완료 + post-merge hotfix 다수 반영. - 명령 표: kebab tui 추가, ingest/search 가 markdown/image/PDF 모두 처리한다고 갱신, eval 상태 ✅. - 핵심 결정: OCR Tesseract → Ollama-vision (HOTFIXES P6-2), Image caption 추가, PDF parser lopdf + chunker_version per-medium 명시 (HOTFIXES P7-3), TUI/Desktop 진행 상태. - Phase 로드맵: P5/P6/P7 ✅ 완료, P8 ⏸ 보류, P9 🟡 진행 (1/5). - 디렉토리 구조: kebab-eval / kebab-parse-image / kebab-parse-pdf / kebab-tui crate 추가, p6/p7 task 카운트 갱신. - 빌드 + 실행: kebab tui 사용법 + 두 example 바이너리 (gen_smoke_pdf / gen_smoke_png) 안내 추가. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 14 ++++++++++++++ README.md | 56 ++++++++++++++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0f4b7a8..adbf26d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -74,6 +74,20 @@ The migration from the old `kb` name lives in commits `911fb49 / f1a448d / f9714 `docs/SMOKE.md` walks through running the full pipeline against an isolated TempDir KB via `--config /tmp/kebab-smoke/config.toml`. Use this instead of touching `~/.local/share/kebab/` when verifying a fresh clone or a CLI flag change. Most CLI regressions surface here, not in unit tests (see HOTFIXES.md). +## User-facing docs (README) + +`README.md` is the user's first stop. Every PR that adds or changes user-visible surface MUST update the README in the same PR — never as a follow-up. The three surfaces: + +- **CLI** — any new `kebab `, new flag, new `--json` field, or changed exit-code semantics. Update the command table near the top of the README and add an entry to the "빌드 + 실행" section if the new flow needs a different invocation pattern. +- **TUI** — any new pane, key binding, or run-time behavior visible to a `kebab tui` user. The README's TUI section names what the shell can do today; a new pane (search / ask / inspect / desktop) flips its row from ⏳ to ✅ and adds the key bindings users need to know. +- **Configuration** — any new `config.toml` field, env var (`KEBAB_*`), default value change, or XDG path. Update the config example block in `docs/SMOKE.md` AND the README's "핵심 결정" / "빌드 + 실행" rows that reference it. + +The README is also the place where the phase status table lives — flip the relevant row's status (⏳ → ✅) when a phase epic completes. `tasks/INDEX.md` tracks per-component progress; the README tracks per-phase user-visible promises. + +Spec PRs (`spec/*` branches) do not touch the README. Implementation PRs (`feat/*`) do. If a feature ships behind a flag that's off-by-default, mention the flag explicitly so a user reading only the README knows the surface exists but is gated. + +Out of scope for the README: HOTFIXES detail (those live in `tasks/HOTFIXES.md`), version cascade mechanics (CLAUDE.md owns those), per-task spec rationale (those live in `tasks/p/`). + ## Remote Git remote is Gitea: `https://gitea.altair823.xyz/altair823-org/kebab.git`. PRs are created via the Gitea REST API (`POST /repos/altair823-org/kebab/pulls`) — `gh` CLI does not work against this host. Auth uses `~/.netrc` (populated via `git credential fill`). diff --git a/README.md b/README.md index 9af3f77..9c10af7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # kebab — Local-first Knowledge Base -> **상태:** P0–P4 구현 완료 (31 component task 중 17 완료) + 3건 post-merge hotfix 적용. `kebab index` / `kebab search --mode {lexical,vector,hybrid}` / `kebab ask` 모두 실 동작. 다음 단계 = P5 (eval suite). 자세한 진행 상황은 [tasks/INDEX.md](tasks/INDEX.md), 머지 후 발견된 버그와 fix는 [tasks/HOTFIXES.md](tasks/HOTFIXES.md). +> **상태:** P0–P5 + P6 + P7 + P9-1 (Library 패널) 구현 완료 + post-merge hotfix 다수 (storage UNIQUE bug, vector store orphan cleanup, chunker_version per-medium 등). `kebab ingest` 가 markdown / image / PDF 모두 처리, `kebab search --mode {lexical,vector,hybrid}` / `kebab ask` 가 매체 가로질러 결과 + page citation 반환. `kebab tui` 가 Library 패널 제공 (search / ask / inspect 패널은 P9-2/3/4 예정). 다음 단계 = P9-2 (TUI search) 또는 P8 (audio — 시스템 dep brainstorm 필요해 보류). 자세한 진행 상황은 [tasks/INDEX.md](tasks/INDEX.md), 머지 후 발견된 버그와 fix는 [tasks/HOTFIXES.md](tasks/HOTFIXES.md). `kebab` 는 개인용 로컬 knowledge base + RAG 도구다. Markdown / PDF / 이미지 / 음성을 한 곳에 색인하고, 의미 검색 + citation 포함 LLM 답변을 단일 binary 로 제공한다. 모든 추론은 로컬 (Ollama / fastembed / whisper.cpp) 에서 돌아간다. @@ -13,13 +13,14 @@ | 명령 | 동작 | 상태 | |------|------|------| | `kebab init` | XDG 경로에 데이터 디렉토리 + config.toml 생성 | ✅ P0 | -| `kebab ingest []` | Markdown 색인 (idempotent). PDF/이미지/음성은 P6+. | ✅ P3-5 | -| `kebab search --mode {lexical,vector,hybrid} ""` | 검색 — citation 포함, hybrid는 RRF fusion | ✅ P3-5 | +| `kebab ingest []` | Markdown / 이미지 / PDF 색인 (idempotent). 음성은 P8 (보류). | ✅ P3-5 / P6-4 / P7-3 | +| `kebab search --mode {lexical,vector,hybrid} ""` | 검색 — citation 포함, hybrid는 RRF fusion. PDF chunk 의 citation 은 page 단위. | ✅ P3-5 / P7-3 | | `kebab list docs` | 색인된 문서 목록 | ✅ P3-5 | | `kebab inspect doc ` / `kebab inspect chunk ` | raw record 보기 | ✅ P3-5 | | `kebab ask ""` | RAG 답변 + 근거 인용. 근거 부족 시 거절. Ollama 필요. | ✅ P4-3 | | `kebab doctor` | 설정/모델/DB 헬스 체크 | ✅ P0 | -| `kebab eval run / compare` | golden query 회귀 측정 | ⏳ P5 | +| `kebab tui` | Ratatui 셸 — Library 패널 (search/ask/inspect 패널은 P9-2/3/4 예정) | ✅ P9-1 | +| `kebab eval run / compare` | golden query 회귀 측정 | ✅ P5 | 기계 친화 모드: 모든 명령에 `--json` 플래그. 출력은 frozen wire schema v1 (`schema_version` 필드 항상 포함, 예: `ingest_report.v1`, `search_hit.v1`, `answer.v1`, `doctor.v1`). @@ -37,10 +38,12 @@ | Markdown parser | `pulldown-cmark` | | embedding | `fastembed-rs` (`multilingual-e5-small`, 384d) | | LLM | Ollama HTTP (default `qwen2.5:7b-instruct` ─ 사용자 환경에 맞춰 `gemma4:26b` 등으로 교체 가능) | -| 음성 ASR | `whisper.cpp` (via `whisper-rs`) — P8 | -| OCR | Tesseract (default) + macOS Apple Vision sidecar (feature gate) — P6 | -| TUI | Ratatui + crossterm — P9 | -| Desktop | Tauri 2 + `pdfjs-dist` (native PDF render backend 금지) — P9 | +| 음성 ASR | `whisper.cpp` (via `whisper-rs`) — P8 (보류, 시스템 dep brainstorm 후) | +| OCR | Ollama vision LM (default `gemma4:e4b`) — `OcrEngine` trait 으로 Tesseract / Apple Vision 등 future swap 가능 (HOTFIXES P6-2) | +| Image caption | Ollama vision LM, runtime gate `image.caption.enabled` (default OFF) — P6-3 | +| PDF parser | `lopdf` per-page 텍스트 추출, `chunker_version = "pdf-page-v1"` 가 PDF 자산에 하드코딩 (HOTFIXES P7-3) — P7-1/7-2/7-3 | +| TUI | Ratatui + crossterm — P9-1 (Library 패널), P9-2/3/4 진행 예정 | +| Desktop | Tauri 2 + `pdfjs-dist` (native PDF render backend 금지) — P9-5 | | citation 형식 | URI fragment (`path#L12-L34`, W3C Media Fragments) | | ID 생성 | `blake3(canonical_json(tuple))[..32]` hex | | RRF fusion_score | `[0, 1]` 정규화 — `2 / (k_rrf + 1)` 로 나눠 mode 간 비교 가능 (post-merge hotfix) | @@ -85,15 +88,15 @@ UI → store/llm/parse 직접 의존 금지. 모든 user-facing 진입은 `kebab | **P2** | SQLite FTS5 lexical 검색 + citation | `kebab-search` (lexical) | P1 | ✅ 완료 | | **P3** | Local embedding + LanceDB + hybrid (RRF) + kebab-app wiring | `kebab-embed`, `kebab-embed-local`, `kebab-store-vector`, `kebab-search` | P2 | ✅ 완료 | | **P4** | Local LLM + RAG + grounded answer | `kebab-llm`, `kebab-llm-local`, `kebab-rag` | P3 | ✅ 완료 | -| **P5** | Golden query / regression eval | `kebab-eval` | P4 | ⏳ 다음 | -| **P6** | 이미지 ingestion (OCR + caption) | `kebab-parse-image` | P5 | ⏳ | -| **P7** | PDF text + page citation | `kebab-parse-pdf` | P5 | ⏳ | -| **P8** | 음성 transcription + timestamp citation | `kebab-parse-audio` | P5 | ⏳ | -| **P9** | TUI + desktop app | `kebab-tui`, `kebab-desktop` | P5 | ⏳ | +| **P5** | Golden query / regression eval | `kebab-eval` | P4 | ✅ 완료 | +| **P6** | 이미지 ingestion (OCR + caption) | `kebab-parse-image` | P5 | ✅ 완료 (4/4 component, OCR/caption Ollama-vision) | +| **P7** | PDF text + page citation | `kebab-parse-pdf` | P5 | ✅ 완료 (3/3 component, page-level chunker + ingest wiring) | +| **P8** | 음성 transcription + timestamp citation | `kebab-parse-audio` | P5 | ⏸ 보류 (whisper-rs 시스템 dep brainstorm 필요) | +| **P9** | TUI + desktop app | `kebab-tui`, `kebab-desktop` | P5 | 🟡 진행 (1/5 component — P9-1 Library 완료, P9-2/3/4/5 예정) | P0~P5 직렬. P6~P9 P5 이후 병렬 가능. -각 phase 는 component-level 단위로 더 분해되어 있다 (총 31 component task — P3-5 app-wiring 추가). 자세한 분해는 [tasks/INDEX.md](tasks/INDEX.md). 머지 후 발견된 버그/fix 의 dated 로그는 [tasks/HOTFIXES.md](tasks/HOTFIXES.md). +각 phase 는 component-level 단위로 더 분해되어 있다 (총 33 component task — P3-5 / P6-4 / P7-3 / 등 후속 추가 포함). 자세한 분해는 [tasks/INDEX.md](tasks/INDEX.md). 머지 후 발견된 버그/fix 의 dated 로그는 [tasks/HOTFIXES.md](tasks/HOTFIXES.md). --- @@ -122,9 +125,9 @@ kebab/ │ ├── p3/p3-1 … p3-5 # (5 — p3-5 = app-wiring, post-spec 추가) │ ├── p4/p4-1 … p4-3 # (3) │ ├── p5/p5-1, p5-2 # (2) -│ ├── p6/p6-1 … p6-3 # (3) -│ ├── p7/p7-1, p7-2 # (2) -│ ├── p8/p8-1, p8-2 # (2) +│ ├── p6/p6-1 … p6-4 # (4 — p6-4 = image-ingest-wiring 후속 추가) +│ ├── p7/p7-1 … p7-3 # (3 — p7-3 = pdf-ingest-wiring 후속 추가) +│ ├── p8/p8-1, p8-2 # (2 — 보류) │ └── p9/p9-1 … p9-5 # (5) ├── crates/ │ ├── kebab-core/ kebab-parse-types/ kebab-config/ # 도메인 + 설정 (P0) @@ -138,7 +141,11 @@ kebab/ │ ├── kebab-store-vector/ # LanceDB VectorStore (P3-3) │ ├── kebab-llm/ kebab-llm-local/ # LanguageModel trait + Ollama adapter (P4-1, P4-2) │ ├── kebab-rag/ # RAG pipeline (P4-3) -│ ├── kebab-app/ # facade (P0 시그니처 + P3-5 본체) +│ ├── kebab-eval/ # golden query runner + metrics (P5-1, P5-2) +│ ├── kebab-parse-image/ # ImageExtractor + Ollama OCR + caption (P6) +│ ├── kebab-parse-pdf/ # lopdf per-page text extractor (P7-1) +│ ├── kebab-app/ # facade (P0 시그니처 + P3-5/P6-4/P7-3 본체) +│ ├── kebab-tui/ # Ratatui shell + Library 패널 (P9-1) │ └── kebab-cli/ # binary (P0 → 핫픽스로 --config flag wiring 강화) ├── migrations/ # SQLite refinery V001/V002/V003 └── fixtures/ # 테스트 fixture 트리 @@ -155,20 +162,23 @@ cargo build --release # 첫 실행 — XDG 경로에 config.toml 생성 ./target/release/kebab init -# config 손보고 +# config 손보고 — `[workspace] include` 에 *.md / *.png / *.pdf 등 추가, OCR 활성화 등 ${EDITOR:-vi} ~/.config/kebab/config.toml -# 색인 +# 색인 (Markdown / 이미지 / PDF 모두 한 번에) ./target/release/kebab ingest -# 검색 +# 검색 (citation 의 source_span 이 매체별로 line / region / page) ./target/release/kebab search "Markdown chunking 규칙" --mode hybrid -# 질문 (Ollama 필요) +# 질문 (Ollama 필요, PDF 인용 시 page 번호 surface) ./target/release/kebab ask "내 KB 설계에서 저장소 전략은?" + +# Ratatui 셸 (Library 패널 — j/k 이동, f 필터, q 종료) +./target/release/kebab tui ``` -워크스페이스를 격리해서 직접 돌려보는 패턴은 [docs/SMOKE.md](docs/SMOKE.md) 참조 — `--config ` 로 임시 디렉토리에 격리된 KB 를 만들 수 있다. +워크스페이스를 격리해서 직접 돌려보는 패턴은 [docs/SMOKE.md](docs/SMOKE.md) 참조 — `--config ` 로 임시 디렉토리에 격리된 KB 를 만들 수 있다. 이미지 / PDF fixture 가 필요하면 두 example 바이너리 (`cargo run --release --example gen_smoke_pdf -p kebab-parse-pdf` / `gen_smoke_png -p kebab-parse-image`) 로 reportlab / qpdf 같은 시스템 dep 없이 in-tree 생성 가능. ---