LLM Wiki — Obsidian 볼트를 LLM이 유지보수하는 지식 베이스로 운영하기
LLM wiki kit
First committed by cookyman74
Published in cookyman74/llmwiki-harness. Publisher page
46 GitHub stars
What it is
llmwiki-harness
AutoGineer overview, from the brain’s own files
llmwiki-harness is a framework designed to turn an Obsidian vault into a living, self-maintaining knowledge base. Unlike standard RAG systems that re-process information on every query, this harness uses LLMs to incrementally ingest, synthesize, and cross-reference information into a structured wiki. It implements a 4-tier memory model (Working, Episodic, Semantic, Procedural) to manage information decay, confidence scoring, and knowledge promotion. The system is built for Claude Code, utilizing a suite of specialized agents and skills to handle wiki operations, linting, and MoC (Map of Content) maintenance, ensuring the knowledge base grows in value over time.
How it works
Memory model: LLM wiki
AutoGineer overview, from the brain’s own files
The system organizes data into three storage layers: raw sources, the wiki, and the schema. It uses a 4-tier memory hierarchy where information is promoted from L1-working (temporary session scratchpad) to L2-episodic (session summaries), L3-semantic (facts and entities with confidence scores), and L4-procedural (repeated methods). The harness uses specialized agents for tasks like ingestion, synthesis, and linting, triggered by specific skills. It maintains an index.md for cataloging and a log.md for chronological tracking, while using frontmatter metadata to manage status, confidence, and decay.
| Folder | Role | Files |
|---|---|---|
| .claude | agent-config | 33 |
| .github | agent-config | 1 |
| raw | raw-sources | 7 |
| templates | templates | 11 |
| tests | tests | 3 |
| tools | scripts | 166 |
| wiki | wiki | 6 |
| develop_docs | folder | 44 |
| metrics | folder | 2 |
The agent writes
- .gitignore evidence: README.md
Requirements
Databases: PostgreSQL
Works with: Claude Code, OpenCode
Set it up
This brain runs code automatically: 2 hooks (claude-code). Review .claude/settings.json before opening the folder in Claude Code. No step below turns a hook on for you.
.claude/settings.json:python3 "$CLAUDE_PROJECT_DIR"/.claude/skills/wiki-lint/scripts/wiki-status-check.py.claude/settings.json:python3 "$CLAUDE_PROJECT_DIR"/.claude/skills/wiki-lint/scripts/stamp-updated.py
- Download the brain as a ZIP and unzip it where you keep your notes or project: https://mp-staging.autogineer.com/agent-brains/cookyman74/llmwiki-harness/download
Claude Code reads CLAUDE.md from this folder automatically.
cd llmwiki-harness && claude
AutoGineer scanned these files at commit 139bc84.
First committed by cookyman74. Published in cookyman74/llmwiki-harness. Licence: MIT License.
Usage
AutoGineer overview, from the brain’s own files
- Ingesting new research papers or meeting notes into the wiki
- Querying the wiki for synthesized answers based on accumulated knowledge
- Running automated linting to identify stale information or missing links
- Maintaining Map of Content (MoC) pages for navigation
- Compressing session scratchpads into episodic memory
- Calculating confidence scores for facts based on source evidence
- “Ingest the notes in raw/meetings/project-kickoff.md into the wiki.”
- The agent extracts key facts, updates relevant entity pages, links the source, and updates the index.md.
- “Run a wiki-lint to check for stale information.”
- The agent identifies pages with low confidence or faded decay classes and marks them as archive candidates.
Documentation by cookyman74
LLM Wiki — Obsidian 볼트를 LLM이 유지보수하는 지식 베이스로 운영하기
Image: CI Image: Platform Image: Python Image: License: MIT Image: Obsidian Image: Claude Code Image: PRs Welcome
Obsidian을 IDE로, LLM을 프로그래머로, 위키를 코드베이스로. 사용자는 소스를 큐레이션하고 질문하고, LLM이 요약·교차참조·정리·부기(bookkeeping)를 전부 한다.
👉 처음이라면 INTRO.md 부터 — 이게 뭐고 왜 쓰는지 3분 소개.
이 문서 하나만 따라 하면 빈 Obsidian 볼트에서 시작해 자기 유지보수(self-maintaining) LLM 위키 하네스를 그대로 재현할 수 있다.
대상 도구: Claude Code (CLI/데스크톱/IDE)
언어: 노트 본문 한국어 / 파일명 영문 kebab-case
버전: v2.1 (통합 계층 기억 + lazy 인제스트·모델 라우팅) — v1(평평 구조) → v2(4계층·신뢰도·망각) → v2.1(비용 최적화)
목차
핵심 아이디어
아키텍처 — 3계층 저장 + 4계층 기억
디렉토리 구조 전체
처음부터 재현하기 (Setup)
하네스 구성요소 — 에이전트·스킬·스크립트
사용법 — 5가지 오퍼레이션 6.5. 일상 응용 시나리오
v2 메커니즘 상세 7.5. 질의 리트리벌 최적화 (v0.8.4~v0.9.0)
Frontmatter 스키마 레퍼런스
스크립트 레퍼런스
Obsidian 설정 팁
하네스 진화·확장
트러블슈팅
설계 결정 요약
1. 핵심 아이디어
대부분의 "LLM + 문서" 경험은 RAG다: 파일을 올리면 LLM이 질문마다 관련 조각을 검색해 답을 만든다. 문제는 누적이 없다는 것 — 매 질문마다 지식을 처음부터 재발견한다.
LLM Wiki는 다르다. LLM이 원본 소스와 당신 사이에 영속적인 위키(구조화·상호링크된 마크다운 파일 모음)를 점진적으로 만들고 유지한다. 새 소스를 넣으면 LLM은:
소스를 읽고 핵심 정보를 추출
기존 위키에 통합 — 엔티티 페이지 갱신, 요약 수정, 새 데이터가 옛 주장과 충돌하면 표시
교차참조·모순 표시·종합을 한 번 컴파일해두고 계속 최신화
즉 위키는 복리로 쌓이는 산출물이다. 교차참조는 이미 걸려 있고, 모순은 이미 표시돼 있고, 종합은 이미 읽은 모든 것을 반영한다.
역할 분담:
사람: 소스 큐레이션, 탐색 방향 결정, 좋은 질문
LLM: 요약·교차참조·정리·부기 — 위키를 지치지 않고 유지 (한 번에 15개 파일 갱신)
관련 정신: Vannevar Bush의 Memex(1945) — 개인이 큐레이션하는 지식 저장소, 문서 간 연상 경로. 그가 못 푼 것 = "누가 유지보수하나?". LLM이 그 답이다.
2. 아키텍처
2-1. 3계층 저장 (Storage)
| 계층 | 위치 | 소유 | 규칙 |
|---|---|---|---|
| Raw sources | raw/ | 사용자 | 본문 immutable — 내용 수정 금지, 진실의 원천. 단 인제스트 완료 스탬프(ingested/wiki_source/ingest_status)는 맨 위 메타 블록만 예외(본문 무변경). |
| The wiki | wiki/ | LLM | LLM이 전부 생성·유지. 사용자는 읽기만. |
| The schema | CLAUDE.md | 공동 | 구조·규약·워크플로우의 정본. 함께 진화. |
2-2. 4계층 기억 (Memory Tiers) — v2 핵심
v1의 한계(모든 정보가 영원히 동등·평평한 구조·품질 통제 없음)를 풀기 위해, 인간 기억 구조를 본떠 정보에 등급·시간·신뢰도를 부여한다. 정보는 아래층(휘발·구체)에서 위층(영속·추상)으로 반복·시간·신뢰도에 따라 승격한다.
raw/ ──▶ L1-working ──▶ L2-episodic ──▶ L3-semantic ──▶ L4-procedural
소스 작업기억 일화기억 의미기억 절차기억
(불변) 세션 스크래치 세션·소스 증거 사실·엔티티(신뢰도) 방법 steps
세션종료시 비움 "언제 무엇을" 증류된 지식 반복된 절차| 계층 | 폴더 | 담는 것 | 대표 파일 |
|---|---|---|---|
| L1 작업기억 | wiki/L1-working/ | 현재 세션 관찰·스크래치 | (임시, 세션 종료 시 비움) |
| L2 일화기억 | wiki/L2-episodic/ | 세션 요약, 소스 증거 | session-YYYY-MM-DD.md, source-*.md |
| L3 의미기억 | wiki/L3-semantic/ | 사실·엔티티·개념 (신뢰도 부여) | fact-*.md, entity-*.md, concept-*.md |
| L4 절차기억 | wiki/L4-procedural/ | 반복 관찰된 방법 (steps) | procedure-*.md |
| MoC (네비) | wiki/moc/ | 큐레이션 주제 지도 | home-moc.md, {topic}-moc.md |
승격 규칙:
L1 → L2 (세션 종료 시): L1 관찰을 3–5줄로 압축 →
session-*.md저장 → L1 비움L2 → L3 (lint 시): 같은 주장이 3회 이상 등장 →
fact-*.md로 승격 (모순 있으면 보류)L3 → L4 (lint 시): 같은 절차가 2회 이상 관찰 →
procedure-*.md로 추출
2-3. 특수 파일 두 개
index.md— 내용 지향. 위키 전체 카탈로그(페이지 + 한 줄 요약). 인제스트마다 자동 갱신. 질의 시 여기부터 읽어 관련 페이지를 찾는다.log.md— 시간 지향. append-only 기록. 각 항목## [YYYY-MM-DD] <op> | <제목>프리픽스 고정 →grep "^## \[" log.md | tail -5로 최근 이력 조회.
index.md vs MoC 차이: index는 "빠짐없이"(전수·기계적·평면), MoC는 "이해되게"(선별·큐레이션·계층). 둘 다 유지하되 역할을 섞지 않는다.
3. 디렉토리 구조 전체
llmwiki.obsidian/
├── CLAUDE.md # ★ 스키마 — 매 세션 로딩되는 정본 (규약·신뢰도·망각·관계 규칙)
├── CLAUDE.local.md # 개인 프로필 (gitignore — 공유 안 됨)
├── README.md # 이 문서
├── index.md # 전수 카탈로그 (자동 갱신)
├── log.md # 시간순 append-only 로그
│
├── raw/ # 원본 소스 (본문 immutable, 인제스트 스탬프만 예외)
│ ├── assets/ # 다운로드한 이미지
│ ├── meetings/ # 회의록 (verbal 소스)
│ ├── notes/ # 데일리 노트 (스크래치 — pending 스캔 제외)
│ └── ... # 자유 분류 (lecture/·article/·books/ 등)
│
├── wiki/ # LLM 소유 — 4계층 기억
│ ├── L1-working/ # 세션 스크래치 (종료 시 비움)
│ ├── L2-episodic/ # session-*.md, source-*.md
│ ├── L3-semantic/ # fact-*.md, entity-*.md, concept-*.md (신뢰도)
│ ├── L4-procedural/ # procedure-*.md (steps)
│ └── moc/ # 네비게이션 지도 (home-moc.md 현관 + {topic}-moc.md)
│
├── templates/ # Obsidian 템플릿
│ ├── meeting.md # 회의록 (→ raw/meetings/)
│ ├── daily.md # 오늘의 노트 (→ raw/notes/)
│ └── seeds/ # 빈 시드 (index·log·home-moc — 배포본 초기화용)
│
├── metrics/ # 비용대비효과 측정
│ ├── ingest-cost.csv # 문서당 토큰·페이지·모델 원장 (gitignore)
│ └── cost-report.py # 모델가중 비용 리포트
│
└── .claude/ # 하네스
├── settings.json # 훅 (SessionStart 자동 점검 + PostToolUse updated 스탬프)
├── agents/ # 전문가 정의 (누가) — 6개
│ ├── wiki-ingestor.md (model: sonnet)
│ ├── wiki-synthesizer.md
│ ├── wiki-linter.md
│ ├── wiki-cartographer.md
│ ├── wiki-consolidator.md
│ └── meeting-scribe.md (model: sonnet)
└── skills/ # 워크플로우 정의 (어떻게)
├── wiki-ops/ # ★ 오케스트레이터 (진입점)
├── wiki-ingest/ # 인제스트 절차 (lazy)
│ └── scripts/ # concept-index.py
├── wiki-query/ # 질의 절차
├── wiki-lint/ # 점검 절차
│ └── scripts/ # link-audit.py, decay.py, lint-due.py, search.py,
│ # ingest-status.py, wiki-status-check.py
├── wiki-moc/ # MoC 절차
├── wiki-consolidate/ # 통합·배치병합 절차
│ └── scripts/ # confidence.py, list-claims.py
├── weekly-review/ # 주간 리뷰 자동화
└── meeting-minutes/ # 녹음 → 전사 → 회의록 (로컬/OpenAI 이중 백엔드)
├── scripts/ # transcribe.py, apikey.py
└── references/ # backend-setup.md4. 처음부터 재현하기 (Setup)
세 갈래가 있다. 하네스 repo를 받았다면 방법 C가 가장 빠르다.
방법 C — git clone로 하네스 배포본 받기 (가장 빠름)
누군가 공유한 하네스 repo(구조·스킬만, 콘텐츠 제외)를 받아 바로 운영을 시작한다.
git clone <하네스-repo-URL> my-wiki && cd my-wiki개인 프로필 작성 —
CLAUDE.local.md를 만들어 자기 소개를 적는다(gitignore라 공유 안 됨). Claude가 세션마다 로딩해 설명 톤을 맞춘다:# CLAUDE.local.md ## 목적 / 사용자 프로필 - 역할: (백엔드 개발자 / 데이터 사이언티스트 / …) - 스택: (언어·프레임워크·인프라) - 관심/학습: (현재 파고드는 주제)시드 복사 — 빈 색인·로그·현관 MoC를 제자리로:
cp templates/seeds/index.md templates/seeds/log.md . cp templates/seeds/home-moc.md wiki/moc/Claude Code 실행 →
/hooks한 번 열기(훅 로드) → Obsidian에서 볼트 열기.raw/에 첫 소스를 넣고 "인제스트해줘" → 위키가 자란다.
업데이트 받기:
git pull. 하네스(스킬·에이전트·스크립트)만 갱신되고 내 콘텐츠는 그대로다. 내가 하네스를 고쳐 재배포:git add .claude/ CLAUDE.md README.md templates/ && git commit && git push— 콘텐츠·프로필은.gitignore라 안 올라간다. 볼트 밖(다른 프로젝트·Codex·Cursor 등)에서도 위키를 쓰려면: MCP 서버를 등록한다 — 설치·사용 가이드. 볼트에는 아무것도 설치하지 않는다(5-5 참고).
방법 A — myharness 팩토리로 자동 생성 (권장)
이 하네스는 myharness 플러그인(에이전트 팀 + 스킬 자동 구성 메타 스킬)으로 만들어졌다.
Obsidian 볼트 생성 — Obsidian에서 새 볼트를 만든다 (예:
llmwiki.obsidian).Claude Code를 볼트 디렉토리에서 실행 —
cd <볼트경로> && claude./init실행 (선택) — 기본 CLAUDE.md·규약 스캐폴딩.myharness 실행 — LLM Wiki 아이디어 문서를 인자로 넘겨 하네스 구성 요청:
/myharness:myharness <LLM Wiki 패턴 설명 + "MoC 네비게이션 포함" 요청>myharness가 Phase 0~7로 에이전트·스킬·스크립트·CLAUDE.md·훅을 생성한다.
v2 업그레이드 — 개선안(신뢰도·덮어쓰기·망각·4계층·엔티티·자동화)을 다시 myharness에 넘겨 아키텍처 변경을 요청하면 이 문서의 v2 구조로 확장된다.
방법 B — 수동 재현 (구조를 직접 만들기)
myharness 없이 파일을 직접 만들 때. 볼트 루트에서:
1) 디렉토리 스캐폴딩
mkdir -p raw/assets
mkdir -p wiki/L1-working wiki/L2-episodic wiki/L3-semantic wiki/L4-procedural wiki/moc
mkdir -p .claude/agents
mkdir -p .claude/skills/wiki-ops
mkdir -p .claude/skills/wiki-ingest
mkdir -p .claude/skills/wiki-query
mkdir -p .claude/skills/wiki-lint/scripts
mkdir -p .claude/skills/wiki-moc
mkdir -p .claude/skills/wiki-consolidate/scripts
# 빈 폴더가 git/OneDrive에서 유지되도록
find raw wiki -type d -exec touch {}/.gitkeep \;2) 파일 작성 — 아래 5장·8장·9장의 내용을 각 경로에 만든다:
CLAUDE.md(스키마 — 8장 frontmatter + 7장 규칙).claude/agents/*.md(5개 전문가 — 5-1장).claude/skills/*/SKILL.md(6개 스킬 — 5-2장)스크립트 10개 (9장) — 작성 후
chmod +x.claude/settings.json(훅 — 7-6장)index.md,log.md,wiki/moc/home-moc.md(시드)
3) 활성화
# 스크립트 실행권한
chmod +x .claude/skills/wiki-lint/scripts/*.sh .claude/skills/wiki-lint/scripts/*.py
chmod +x .claude/skills/wiki-consolidate/scripts/*.sh .claude/skills/wiki-consolidate/scripts/*.py
chmod +x .claude/skills/wiki-ingest/scripts/*.sh metrics/cost-report.pyClaude Code에서
/hooks를 한 번 열어 새 훅을 로드한다 (세션 중 추가된 훅은 설정 watcher가 즉시 못 잡는다 —/hooks열기 또는 재시작 필요).
사전 요구사항
Claude Code 설치
python3 (모든 결정적 스크립트 + 훅 — 표준 라이브러리만 사용)
(선택) Obsidian — 위키를 사람이 브라우징. 그래프 뷰로 위키 형태를 본다.
크로스플랫폼: 모든 스크립트·훅이 python3 전용이다(bash·grep·awk·jq·rg 불필요). 따라서:
macOS·Linux — 그대로 작동 (python3 기본/쉬운 설치).
Windows — 네이티브로 작동 (python3만 PATH에 있으면 됨; WSL·Git Bash 불필요). 단 훅 명령이
python3를 부르므로 Windows에서python만 있으면python3별칭을 잡아주거나 PATH에python3확보.줄바꿈은
.gitattributes가 LF로 정규화(Windows CRLF 손상 방지).
5. 하네스 구성요소
핵심 설계: 에이전트(누가) + 스킬(어떻게) 분리. 에이전트는 역할·원칙·프로토콜을, 스킬은 절차·템플릿을 담는다.
실행 모드: 전문가 풀 (서브 에이전트 디스패치). 오퍼레이션마다 전문가 1명을 호출한다 — 동시 협업 팀이 아니다. 한 소스 인제스트는 교차참조·신뢰도 일관성을 위해 단일 에이전트가 통째로 처리한다(분할하면 페이지 충돌).
5-1. 에이전트 (6명)
| 에이전트 | 역할 | 사용 스킬 | 모델 |
|---|---|---|---|
| wiki-ingestor | 소스 인제스트 (lazy) — L2 증거 + 신규 L3 초안만. 병합·신뢰도·덮어쓰기·관계는 lint 배치로 지연 | wiki-ingest, wiki-moc | sonnet |
| wiki-synthesizer | 질의 응답 — index→MoC→L3 탐색, 신뢰도·최신성 반영 인용 답변, 환류 | wiki-query, wiki-moc | opus |
| wiki-linter | 건강 검진 — 링크·망각·신뢰도 감사, 승격 후보, 모순 검사 | wiki-lint, wiki-consolidate, wiki-moc | opus |
| wiki-cartographer | MoC 네비게이션 — 허브 생성·갱신, L3/L4 편입, 도달성 점검 | wiki-moc | opus |
| wiki-consolidator | 기억 통합 — L1→L2 압축, L2→L3→L4 승격, 신뢰도 재계산 + lazy 후속 배치 병합(기존 페이지 통합·관계 구조화·중복 초안 정리) | wiki-consolidate, wiki-moc | opus |
| meeting-scribe | 전사문 → 회의록 — 결정·액션·미결 분리, 근거 있을 때만 발언 귀속. 2만 자 전사문을 격리 컨텍스트에서 소비 | meeting-minutes | sonnet |
모델 라우팅(v2.1): 인제스트는 추출·파일쓰기 위주라 sonnet(빈번한 경로를 싸게). 병합 판단·종합·감사 같은 고추론은 나머지 4개 에이전트가 opus로. 측정상 인제스트 페이지당 실질비용 ~4.6×↓·지연 ~3×↓.
각 에이전트 정의 파일(.claude/agents/{name}.md)의 frontmatter는 연결 계약을 담는다:
---
name: wiki-ingestor
description: <언제 이 에이전트를 쓰나 — pushy하게>
tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch
model: sonnet # 인제스트=sonnet, 나머지 에이전트=opus (모델 라우팅)
skills: [wiki-ingest, wiki-moc] # 이 에이전트가 쓰는 스킬 (구성 자기평가용)
---본문 섹션: 핵심 역할 · 작업 원칙 · 입력/출력 프로토콜 · 이전 산출물이 있을 때 · 에러 핸들링 · 협업.
5-2. 스킬 (8개)
| 스킬 | 유형 | 하는 일 |
|---|---|---|
| wiki-ops | 오케스트레이터 (진입점) | Phase 0 컨텍스트 확인 → 라우팅 → 오퍼레이션 흐름 조율 |
| wiki-ingest | 워크플로우 | (lazy) 소스 → L2 증거 + 신규 L3 초안 (병합·신뢰도·관계·승격은 lint 지연) |
| wiki-query | 워크플로우 | 탐색 → 신뢰도 반영 인용 답변 → 환류 |
| wiki-lint | 워크플로우 | 스크립트 검사 → 망각·신뢰도·supersession 감사 → 배치 승격 → 추론 검사 |
| wiki-moc | 워크플로우 | MoC 허브 구조·계층·편입·도달성 |
| wiki-consolidate | 워크플로우 | 4계층 승격 (L1→L2→L3→L4) + lazy 후속 배치 병합(신뢰도·관계·기존 통합) |
| weekly-review | 워크플로우 | 주간 리뷰 자동 생성 — 완료·미결·stale·다음주 우선순위 → query 페이지 파일링 |
| meeting-minutes | 워크플로우 | 녹음 → 전사 → 회의록. 회의 민감도로 백엔드 분기(로컬 온디바이스 / OpenAI API) |
오케스트레이터 frontmatter는 orchestrates: 배열로 조율하는 에이전트를 선언:
---
name: wiki-ops
description: <pushy — 인제스트·질의·린트·MoC·통합 + 후속 키워드>
orchestrates: [wiki-ingestor, wiki-synthesizer, wiki-linter, wiki-cartographer, wiki-consolidator]
---5-3. 스크립트 (10개, 결정적 — LLM 토큰 0)
계산은 스크립트가, 의미 판단만 LLM이. 상세는 9장.
| 스크립트 | 위치 | 용도 |
|---|---|---|
confidence.py | wiki-consolidate/scripts | 소스 수·유형 → 신뢰도 점수 |
list-claims.py | wiki-consolidate/scripts | L2 주장(claim::) 수집 → 배치 병합·승격 |
concept-index.py | wiki-ingest/scripts | 기존 L3/L4 카탈로그 (본문 Read 없이 신규/기존 판별 — lazy의 핵심) |
decay.py | wiki-lint/scripts | Ebbinghaus 망각 보존율 계산·스캔 |
link-audit.py | wiki-lint/scripts | 끊긴 wikilink + 고아 + 누락 타겟(stub_targets) |
lint-due.py | wiki-lint/scripts | 마지막 lint 경과일 + L1 미압축 수 |
ingest-status.py | wiki-lint/scripts | raw 인제스트 상태 (done/pending) |
wiki-status-check.py | wiki-lint/scripts | SessionStart 훅 — lint 경과·L1·미인제스트 알림 |
search.py | wiki-lint/scripts | grep 기반 위키 본문 검색 |
cost-report.py | metrics/ | 문서당 토큰·모델가중 비용 리포트 |
transcribe.py | meeting-minutes/scripts | 녹음 전사 (로컬/OpenAI) — ffmpeg 정규화·청크·타임스탬프 |
apikey.py | meeting-minutes/scripts | OpenAI 키 해석·키체인 저장·인증 테스트 |
5-4. 회의록 파이프라인 — 외부 전송을 코드로 막는다
meeting-minutes는 다른 스킬과 성격이 하나 다르다. 오디오를 외부로 보낼지 말지라는 되돌릴 수 없는 결정을 포함한다.
판정은 회의 성격으로 한다 — 인사·평가·심사·계약·개인정보·보안·고객사 기밀은 로컬 온디바이스(mlx-whisper), 일반 업무회의·기술 논의·일정 조율만 OpenAI API. 애매하면 로컬이다. 오분류 비용이 비대칭이기 때문이다: 로컬 오분류는 시간만 더 들지만, OpenAI 오분류는 되돌릴 수 없다(삭제해도 캐시·색인이 남을 수 있다).
이 규칙을 SKILL.md에만 적으면 잊힌다. 그래서 스크립트가 --confirm-upload 없이는 openai 백엔드를 실행 자체를 거부한다. 플래그를 붙이는 행위가 곧 판정을 마쳤다는 기록이 된다.
$ transcribe.py --backend openai --input 회의.m4a
openai 백엔드는 오디오를 외부 서버로 전송한다.
민감 회의(인사·평가·심사·계약·개인정보)라면 --backend local 을 쓰라.
exit=1 # 네트워크 호출 0회산출물은 둘로 나뉜다. 전사 원문은 raw/meetings/transcripts/에 근거로 보존하고, 회의록만 raw/meetings/에 남겨 위키로 인제스트한다. 63분 녹음은 2만 자를 넘어 회의록의 가독성을 파괴하고 인제스트 토큰을 낭비한다. 회의록 작성은 meeting-scribe에 위임해 메인 컨텍스트가 전사문으로 오염되지 않게 한다.
화자 분리는 지원하지 않는다. Whisper 계열은 "누가 말했는지"를 출력하지 않는다.
meeting-scribe는 근거(호명·자기소개·역할 명시)가 있을 때만 발언을 귀속하고, 나머지는 화자 없이 기록한다. 심사·평가 회의에서 잘못된 발언 귀속은 내용 누락보다 해롭기 때문이다.
5-5. MCP 서버 (tools/llmwiki-mcp/) — 볼트 밖에서 위키 쓰기
지금까지의 구성요소는 모두 볼트 안에서 도는 Claude Code를 전제한다. 그런데 위키가 가장 아쉬운 순간은 대개 볼트 밖이다 — 다른 저장소에서 코드를 고치는 중, Codex CLI로 작업하는 중, Cursor에서 문서를 쓰는 중. 그때 위키를 열어 읽는 대신 에이전트가 위키에서 답을 찾게 하는 것이 이 서버다.
설치·사용법은 별도 문서에 있다 →
tools/llmwiki-mcp/docs/install-and-usage.ko.md(준비물, 3분 빠른 시작, 클라이언트 8종 등록, 사용법, 환경변수, 문제 해결, 업데이트·제거)
obsidian-llmwiki-mcp는 볼트를 읽기 전용으로 여는 MCP 서버다(Node ≥20, 사전 설치물은 Node 하나). 7.5장의 리트리벌(렉시컬 seed → 관계 1홉 확장 → MoC 멤버 → 옵션 BM25 rerank → claims 팩)을 도구 4개로 노출한다 — wiki_expand(진입점) · wiki_pack(주장·신뢰도 팩) · wiki_read_page(전문) · wiki_search(fallback). Claude Code(다른 프로젝트)·Codex·Gemini·agy·Cursor·Windsurf·Claude Desktop·VS Code 8종이 같은 서버를 등록해 쓴다. 등록은 클라이언트마다 한 줄이고, 스니펫은 서버의 print-config 가 만들어 준다.
볼트 안에서는 아무것도 바뀌지 않는다. wiki-query·wiki-ops는 지금처럼 search.py·scope-expand.py를 직접 부른다. 서버는 같은 규칙을 옮긴 것이고, 두 경로가 같은 결과를 낸다는 것을 패리티 테스트가 지킨다 — 볼트 안이든 밖이든 같은 답을 받는다.
위키는 읽기만 한다. 이 서버에는 파일을 쓰는 코드가 없고, 네트워크 연결도 LLM 호출도 하지 않는다. 인제스트·파일링·린트는 계속 볼트 하네스의 일이다. 그래서 설치·제거가 볼트에 아무 흔적을 남기지 않는다.
영문 상세 레퍼런스(도구 계약·상한·보안 경계)는 tools/llmwiki-mcp/README.md, 서버를 고칠 때 지켜야 할 규칙과 설계·검토 기록은 CLAUDE.md의 동기 규칙과 develop_docs/v0.8.6/에 있다.
6. 사용법 — 5가지 오퍼레이션
모든 작업의 진입점은 wiki-ops 오케스트레이터다. 위키 관련 요청을 하면 자동 트리거되고, 알맞은 전문가로 라우팅한다. 자연어로 요청하면 된다.
6-1. Ingest (소스 인제스트)
언제: 새 소스를 위키에 넣을 때.
1. raw/ 에 소스 파일을 넣는다 (예: raw/attention-is-all-you-need.md)
— Obsidian Web Clipper로 웹 기사를 markdown으로 저장하면 편하다.
2. Claude Code에서: "raw/attention-is-all-you-need.md 인제스트해줘"LLM이 하는 일 (v2.1 lazy — 싸고 빠르게):
소스 읽기 (본문 immutable) + 유형 판별 (공식/코드/일반/구두) + 중복 스탬프 체크
기존 개념은
concept-index.py카탈로그로만 파악 (페이지 본문 Read 안 함 — 위키가 커도 O(1))wiki/L2-episodic/source-*.md증거 페이지 — 핵심 사실 전부claim::로 (재등장 신호)신규 개념만
wiki/L3-semantic/초안 생성 (confidence 0.6 고정). 기존과 겹치면 손대지 않음신규 L3만 MoC에 가볍게 편입 +
index.md·log.md+ raw 맨 위 스탬프신규 페이지·claim 수 보고 + "병합·신뢰도·관계·승격은 다음 lint 배치" 명시
왜 lazy? v2는 인제스트마다 기존 페이지를 전수 Read하고 병합·관계까지 해서 위키가 클수록 토큰이 O(n)로 폭증했다. v2.1은 인제스트를 증거 남기기로 가볍게 하고, 병합은 본질적으로 효율적인 누적 후 lint 배치로 옮겼다(→ §6-5, §7).
6-2. Query (질의)
언제: 위키에 질문하거나 비교·분석이 필요할 때.
"우리 스택에서 PostgreSQL을 왜 쓰지? 근거랑 신뢰도까지"
"transformer와 RNN 비교표 만들어줘"LLM이 하는 일:
index.md→ 관련 MoC → L3 페이지 탐색 (없으면search.py)confidence·status·last_confirmed확인stale 페이지는 주근거로 안 씀 (superseded_by 따라 현재 페이지로)
각 주장에 신뢰도 + 출처 인용 병기
재사용 가치 있는 답은 위키에 환류 제안 → 승인 시 L3에 저장 (탐색이 복리로 쌓임)
6-3. Lint (건강 검진)
언제: 주기적으로, 또는 SessionStart 훅이 "3일+ 경과" 알릴 때.
"위키 점검해줘" / "위키 린트"LLM이 하는 일 (6단계):
스크립트:
link-audit.py(끊긴 링크·고아) +decay.py(망각 보존율)망각 처리: faded(R<0.3) 페이지 → 재확인 또는 아카이브 후보 (자동 삭제 금지)
신뢰도·supersession 감사: confidence 정합, stale 짝 링크 확인
통합 승격: L2→L3, L3→L4 후보 제안
추론 검사: 모순, 낡은 주장, 누락 개념, 빠진 관계
보고: 심각도 정렬 수리 목록 + 새 질문·소스 제안
lint 후 반드시
## [날짜] lint | ...를 log에 남긴다 — 자동화 훅이 경과일을 이 항목으로 계산한다.
6-4. MoC (네비게이션 정리)
언제: 주제 지도를 만들거나 갱신할 때.
"llmops 관련 MoC 만들어줘" / "네비게이션 정리해줘"LLM이 하는 일: wiki/moc/{topic}-moc.md 허브 생성/갱신, home-moc 계층 유지, 새 L3/L4 페이지 편입, 모든 L3/L4 페이지가 ≥1 MoC에서 도달 가능한지 점검(고아 방지).
6-5. Consolidate (기억 통합)
언제: 세션 마무리 시(L1→L2), 또는 lint 중(L2→L3→L4).
"세션 마무리하자" / "L1 압축해줘" / "통합해줘"LLM이 하는 일:
L1→L2: L1 관찰 3–5줄 압축 →
session-YYYY-MM-DD.md→ L1 비움L2→L3: 같은 주장 3회+ →
fact-*.md승격 (모순 시 보류)L3→L4: 같은 절차 2회+ →
procedure-*.md추출배치 병합 (lazy 인제스트 후속, v2.1): lazy가 미룬 일을 lint에서 일괄 — 신규 개념 ↔ 기존 페이지 병합,
sources:추가·신뢰도 재계산(claim 재등장 카운트),## 관계구조화, 중복 초안 정리. 병합은 여러 소스가 쌓인 뒤 한 번에 보는 게 효율적(소스마다 전수 스캔 회피).
6.5 일상 응용 시나리오 (단순 Q&A를 넘어)
단순 질문은 이 위키의 일부만 쓴다. 핵심 가치는 인제스트→축적→복리. 하루 업무 3블록 + 주간 리뷰에 매핑한 응용방안(외부 PKM/LLM-wiki 사례 리서치 기반).
① 회의 → 회의록 파이프라인
회의 직후 인제스트 → action item·결정사항을 claim으로 자동 추출.
회의 전 3분 브리핑 — "이 안건 지난 논의 뭐였지?" → 질의유형 라우팅으로 즉답(빠른 사실브리핑).
결정 로그(ADR) — 결정 번복 시 supersession(
status: stale+superseded_by)으로 "왜 바꿨나" 이력 보존.
② 학습 → 지식 복리 + 자동 복습
아티클/강의 인제스트 → concept 페이지 축적(흩어진 북마크 대신 연결된 지식).
신뢰도(confidence)로 이해도 추적 — 1소스 0.6="얕게 봄", 3소스 0.95="여러 각도 확인".
망각(forgetting)이 복습 엔진 — 보존율 하락 시 lint가 "복습 대상" 표시(Ebbinghaus). 일반 PKM엔 없는 기능.
③ 개발 → 운영지식·트러블슈팅 축적
트러블슈팅 로그 — 장애·해결 인제스트 → 같은 절차 2회+ 시 L4 procedure 자동 승격(런북화).
기술결정 기록 — "왜 X 대신 Y" concept + supersession.
운영지식(llmops·모니터링) — entity/procedure로 축적.
④ 주간 리뷰 (최고 ROI)
완료·미결(open loops)·stale·다음주 우선순위를 한 장으로 종합 → "몇 시간→몇 분". weekly-review 스킬로 자동화(/weekly-review, 금요일). 회고·계획·상급자 보고 초안을 한 번에.
이 위키만의 차별점 (일반 Notion+AI 대비)
| 기능 | 일상 용도 |
|---|---|
| 질의유형 라우팅 | 회의 전 3분 브리핑(빠름) |
| confidence | 보고 신뢰도·이해도 추적 |
| forgetting | 자동 복습 큐(학습) |
| supersession | 결정 번복 이력(ADR) |
| L3→L4 승격 | 반복 절차→런북 |
| session 압축 | 매일 작업 로그 자동 |
참고: Karpathy LLM Wiki(지식=컴파일된 코드) · AI Second Brain(회의노트→action item·주간리뷰 자동화) · living knowledge base. 상세 매핑은 위키 페이지
concept-wiki-daily-usage.
7. v2 메커니즘 상세
v2.1 타이밍 주의: 아래 신뢰도·덮어쓰기·관계는 개념이고, v2.1에서는 인제스트가 아니라 lint 배치 시점에 계산·구조화된다(lazy). 인제스트는 신규 개념에 confidence 0.6만 고정으로 붙이고, 재계산·병합·관계는 미룬다.
7-1. 신뢰도 점수 (Confidence)
주장의 확실성을 0.0~1.0으로. 소스 수·유형에서 결정적으로 계산 (confidence.py).
| 조건 | 점수 |
|---|---|
| 소스 1개 | 0.60 |
| 소스 2개 | 0.85 |
| 소스 3개 이상 | 0.95 |
| 소스 0개 (미확인) | 0.30 |
| + 공식 문서/코드 포함 | +0.10 |
| − 구두 정보(slack/회의록) | −0.10 |
최종값은 [0.0, 1.0]로 클램프. L3/L4 페이지 frontmatter confidence:에 기록하고, 질의 답변에 병기한다.
python3 .claude/skills/wiki-consolidate/scripts/confidence.py --count 3 --official # → 1.0
python3 .claude/skills/wiki-consolidate/scripts/confidence.py --kinds official,normal,verbal # → 0.957-2. 덮어쓰기 (Supersession)
새 정보가 옛 정보와 다르면 삭제하지 않고 명시 대체:
옛 페이지:
status: stale+superseded_by: [[새-페이지]]새 페이지:
supersedes: [[옛-페이지]]서로 링크, 타임스탬프 기록 → 이력 보존
어느 쪽이 맞는지 불명한 단순 상충은 대체가 아니라
> [!warning] 상충콜아웃으로 두 출처를 병기한다.
7-3. 망각 (Forgetting) — Ebbinghaus 곡선
시간이 지나면 정보의 보존율이 지수적으로 감쇠한다. 재확인하면 리셋.
보존율 R = exp(−Δt / S) — Δt = 마지막 확인 후 경과일, S = 안정성(decay_class가 결정).
| decay_class | S(일) | 성격 |
|---|---|---|
| architecture | 365 | 핵심 설계 결정 — 천천히 망각 |
| procedure | 365 | L4 절차 — 오래 감 |
| concept / semantic | 120 | 의미 개념 |
| entity | 90 | 엔티티 |
| episodic | 21 | 세션·소스 기록 — 바램 |
| transient | 7 | 일시적 버그·일회 관찰 — 빠르게 망각 |
| (default) | 90 |
보존율 밴드: R≥0.5 fresh / 0.3≤R<0.5 aging(재확인 권장) / R<0.3 faded(아카이브 후보 — 자동 삭제 금지).
리셋: 재확인 시 last_confirmed: 오늘 → Δt=0 → R=1.0.
lint가 decay.py --scan으로 faded 페이지를 표시한다.
7-4. 통합 계층 (Consolidation Tiers)
2-2장 참조. 요지: 반복·시간·신뢰도로 정보를 차등. 자주 확인되는 것은 위로 올라가 오래 살고(L4 절차), 한 번 스친 것은 아래에서 망각된다(L1/transient). 사람 기억이 그렇게 작동한다.
7-5. 엔티티 관계 (Entity Relations)
엔티티 페이지 ## 관계 섹션에 구조화된 관계를 기록 (Obsidian 인라인 필드 :: — Dataview 질의 가능):
## 관계
- caused :: [[incident-x]] (sources: 3, confidence: 0.9)
- depends_on :: [[postgres]] (sources: 1, confidence: 0.6)
- fixed :: [[bug-123]] (sources: 2, confidence: 0.85)관계 유형: uses · depends_on · contradicts · caused · fixed · supersedes. 각 관계에 소스 수·신뢰도 병기.
7-6. 자동화 (Automation)
정직한 한계: Claude Code 훅은 셸만 실행 — LLM lint를 스스로 못 돌린다. 그래서 훅은 조건 검사 + 알림까지만 한다.
두 개의 훅 (.claude/settings.json):
SessionStart 훅 —
wiki-status-check.py세션 시작 시 1회 실행 (Stop 훅은 매 턴 발화 = 스팸이라 회피)
lint-due.py로 마지막 lint 3일+ 경과 또는 L1 미압축 감지해당 시 모델 컨텍스트에 알림 주입 → Claude가 능동으로 lint/consolidate 제안
아무것도 안 걸리면
{}(조용)
PostToolUse 훅 —
updated:스탬프Write|Edit로.md파일을 건드리면 frontmatterupdated:를 오늘로 자동 갱신
진짜 자율 백그라운드 lint를 원하면 → Claude Code /schedule (클라우드 크론 에이전트)로 별도 배선. 예: "매주 월요일 위키 lint 돌려줘".
7.5 질의 리트리벌 최적화 (v0.8.4~v0.9.0)
질의 응답이 질의당 52~62k 토큰을 쓰던 문제(index 통독 + 광역 MoC 스윕)를 결정적 그래프 스코프 + 질의유형 라우팅으로 최적화했다. A/B 9라운드 실측·매 릴리즈 외부감사(agy). 상세: develop_docs/v0.8.3/TECH-SUMMARY.md, develop_docs/v0.8.5/COMBO.md, 실측 원장 metrics/ab-results.csv.
핵심 이동
[구식] 질의 → index(218줄) 통독 → MoC 다수 → 페이지 12~19 full-read → 종합
[신식] 질의 → scope-expand.py(0토큰): lexical seed → 관계 1홉 확장 → (rerank) → claims 팩
→ synthesizer: 팩 1-read → 부족분만 full-read → 종합적용 기술과 근거자료
| 기술 | 근거 | 우리 구현 |
|---|---|---|
| 그래프 확장 스코프 | GraphRAG — 지식그래프 엣지 탐색 | scope-expand.py expand: [[링크]] 파싱, lexical seed→관계 1홉(아웃·인·MoC멤버). 순수 lexical이 못 닿는 관계연결 페이지 도달 |
| claims 컨텍스트 팩 | Parent-Document Retriever(small-to-big) | 팩(claims)=small-side, 페이지 full=parent. 팩 1-read로 다중 페이지 대체 |
| 질의유형 라우팅 | Adaptive-RAG(질의복잡도 라우팅) | 조회=seed·사실브리핑=rerank+팩·절차=full-read. 하나의 전략은 만능 아님 |
| BM25 rerank | Anthropic Contextual Retrieval(reranking 실패 49→67%↓) | 임베딩 없이 BM25(0토큰)로 확장 pool을 질의관련도 top-N 축소 |
| 팩에 관계 포함 (v0.8.6) | 관계질의=관계 실린 사실브리핑 | pack이 ## 관계(uses/depends_on) 줄도 추출(+300토큰). 관계타겟(connector 등)을 새 라우트 없이 커버 |
요약: 우리 claims 팩 = parent-retriever의 small-side였고, rerank·라우팅이 빠진 조각이었다. Adaptive-RAG로 질의유형을 나누고, Contextual Retrieval의 reranking을 BM25로 얹어 완성.
질의유형별 라우팅 (파라미터)
| 유형 | 스코프 명령 | 전달 |
|---|---|---|
| 단일조회 | scope-expand.py expand … --max 6 | seed 목록 |
| 사실브리핑·비교 | … --max 20 --rerank 11 | claims 팩 |
| 절차·how-to | … --max 8(rerank 안 함) | 후보 full-read(팩 없음) |
실측 결과 (동일조건 A/B)
| 질의유형 | 구식(baseline) | 신식 | 개선 |
|---|---|---|---|
| 사실브리핑 | 50.6k / 14 tool | 22.7k / 1 tool | 토큰 −55%·tool −93% |
| 절차·how-to | 39.5k / 8 | ~38k / 10 | 동률(절차는 스코핑 이득 없음 — 본질적으로 다페이지 세부 필요) |
교훈 (실측 검증)
관계 도달은 lexical로 안 됨 → 그래프 1홉 확장 필수.
팩은 사실질의에만 이득 → 절차질의는 full-read 라우팅.
rerank는 최대 레버지만 다이얼 → 조이면 싸지고 recall 준다(11이 균형).
recall의 진짜 레버는
--max가 아니라 키워드 품질(엔티티 포함).절차질의 비용은 근본적 → 스코핑으로 못 줄임. 반복비용은 환류 캐시(query 페이지)로만.
관계질의는 새 유형 아님 → 팩에 관계 실으면 사실브리핑 라우트로 커버.
전체 근거자료·구현 상세·A/B 원장:
develop_docs/v0.8.3/TECH-SUMMARY.md. 관련 리서치 — GraphRAG · Parent-Document Retriever · Adaptive-RAG · Anthropic Contextual Retrieval · Contextual Compression · Self-RAG · Stop-RAG · AB-RAG.
8. Frontmatter 스키마 레퍼런스
모든 위키 페이지 상단에 YAML frontmatter. 파일이 type:을 가져야 위키 페이지로 인식된다(스크립트가 CLAUDE.md 같은 비-페이지를 걸러냄).
---
type: working | episodic | session | source | fact | entity | concept | procedure | moc | index | log | query
title: <한국어 제목>
aliases: [] # 영문 파일명의 한국어 라벨/별칭
tags: [] # 소문자, 예: [llm, training]
created: YYYY-MM-DD
updated: 2026-09-09
# --- L3/L4 전용 (신뢰도·망각) ---
confidence: 0.0~1.0 # confidence.py로 계산
sources: [소스-슬러그, …] # 근거 소스 (개수가 신뢰도 결정)
last_confirmed: YYYY-MM-DD # 재확인마다 갱신 → 망각 리셋
decay_class: architecture | procedure | concept | entity | episodic | transient
status: active | stale # 대체된 정보는 stale (삭제 안 함)
superseded_by: [[새-페이지]] # (옛 페이지에) 대체됨
supersedes: [[옛-페이지]] # (새 페이지에) 대체함
# --- source 페이지 전용 ---
source_url: <URL 또는 raw 경로>
source_kind: official | code | normal | verbal
---raw 파일 인제스트 스탬프 (raw/ 원본 맨 위에만 추가 — 본문 무변경, 완료 표시·중복 방지):
---
ingested: YYYY-MM-DD
wiki_source: [[source-<slug>]] # 생성된 L2 증거 페이지
ingest_status: done
---raw 본문은 immutable이지만 이 상태 스탬프는 예외. ingest-status.py가 이 표시로 done/pending을 판별한다.
규약 요약:
본문 한국어, 파일명 영문 kebab-case (
[[wikilinks]]깔끔)[[wikilinks]]양방향, 없는 페이지 링크는 스텁으로 남김모든 L3/L4 페이지는 ≥1 MoC 도달 가능 (고아 방지)
소스 immutable, 충돌은 병기 또는 supersession
파일 이동·이름변경은 승인 후 (wikilink 깨짐)
9. 스크립트 레퍼런스
confidence.py
# 소스 수 + 유형으로 신뢰도 계산
python3 .claude/skills/wiki-consolidate/scripts/confidence.py --count 2 # 0.85
python3 .claude/skills/wiki-consolidate/scripts/confidence.py --count 1 --official # 0.7
python3 .claude/skills/wiki-consolidate/scripts/confidence.py --kinds official,normal # count=2, +official → 0.95
python3 .claude/skills/wiki-consolidate/scripts/confidence.py --count 3 --json # {"score":0.95,...}소스 유형: official|code(+0.1) · verbal(−0.1) · normal.
decay.py
# 단일 페이지 보존율
python3 .claude/skills/wiki-lint/scripts/decay.py --class architecture --last 2026-01-01 # "0.57 fresh"
python3 .claude/skills/wiki-lint/scripts/decay.py --class transient --last 2026-07-01 # "0.04 faded"
# 위키 전체 스캔 — faded/aging 페이지 나열
python3 .claude/skills/wiki-lint/scripts/decay.py --scan . --json--today YYYY-MM-DD로 기준일 지정 가능(기본 오늘). last_confirmed 없으면 updated: 사용.
link-audit.py
python3 .claude/skills/wiki-lint/scripts/link-audit.py . # 사람이 읽는 리포트
python3 .claude/skills/wiki-lint/scripts/link-audit.py . --json # {broken, orphans, ...}broken: 대상 페이지가 없는
[[wikilink]]((page,target) 중복 제거)orphans: inbound 링크 0인 페이지 (단, index/log/working/episodic/session/source 유형은 제외 — 정상적으로 inbound 0)
stub_targets: 없는 페이지를 가리키는 링크를 참조 페이지 수(inbound)순으로 집계 → 여러 페이지가 가리키는 스텁 = 누락 개념 최우선 작성 후보. (의도된 스텁과 오타 broken을 구분하는 신호)
HTML 주석·코드펜스 안의 링크는 무시.
type:있는 파일만 페이지로 취급.
lint-due.py
python3 .claude/skills/wiki-lint/scripts/lint-due.py . 3 # 임계 3일
# 출력: "DUE 5" | "OK 2" | "NEVER" + "L1:<미압축 페이지 수>"log.md의 마지막 ## [날짜] lint 항목으로 경과일 계산.
wiki-status-check.py
SessionStart 훅이 호출. lint-due.py 결과로 알림 JSON을 만든다. DUE거나 L1>0이면 {"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"..."}}, 아니면 {}.
search.py
python3 .claude/skills/wiki-lint/scripts/search.py "transformer" # wiki/ 전체 grep (rg 미의존)list-claims.py
python3 .claude/skills/wiki-consolidate/scripts/list-claims.py . # L2-episodic의 claim:: 라인 수집같은 주장이 3회+ 등장하는지 LLM이 클러스터링하는 입력(배치 병합·승격).
concept-index.py
python3 .claude/skills/wiki-ingest/scripts/concept-index.py . # 기존 L3/L4 카탈로그
# 출력: slug | title | aliases | confidence (frontmatter만, 한 줄씩)lazy 인제스트의 핵심 — 45개 페이지 본문을 Read하는 대신 이 한 출력만 보고 개념이 기존인지 신규인지 판별한다(토큰 O(1) 유지).
cost-report.py
python3 metrics/cost-report.py # 문서당 토큰·페이지 효율 표
python3 metrics/cost-report.py --by-model # opus vs sonnet 비교 (모델가중 wcost)metrics/ingest-cost.csv(오케스트레이터가 인제스트마다 append)를 읽어 tok/page·모델가중 비용을 낸다. v2/v2.1 비용대비효과 추적용. MODEL_PRICE 상대단가 opus 5·sonnet 1·haiku 0.25.
ingest-status.py
python3 .claude/skills/wiki-lint/scripts/ingest-status.py . # raw/ 인제스트 상태
# 출력: DONE <date> <file> | PENDING <file> + "ingested: N pending: M"raw 파일 맨 위 스탬프(ingest_status: done)를 읽어 인제스트 완료/대기를 판별. raw 본문은 immutable — 스탬프는 맨 위 메타 블록만 추가(본문 무변경). Obsidian에서 각 소스에 완료 표시가 보이고, 중복 인제스트를 막는다. wiki_source 필드는 생성된 L2 증거 페이지로 클릭 이동. 미인제스트 소스는 SessionStart 훅도 알린다.
환경 주의: 스크립트는 grep·python3만 의존한다.
rg(ripgrep)는 비로그인 셸 PATH에 없는 경우가 많아 쓰지 않는다.
10. Obsidian 설정 팁
Web Clipper — 브라우저 확장. 웹 기사를 markdown으로 변환해
raw/에 빠르게 저장.이미지 로컬 다운로드 — Settings → Files and links → Attachment folder path를
raw/assets/로. Settings → Hotkeys에서 "Download attachments for current file"을 단축키(예: Ctrl+Shift+D)로 바인딩. 클리핑 후 눌러 이미지 로컬 저장 → LLM이 이미지를 직접 참조 가능(끊기는 URL 대신).단, LLM은 인라인 이미지가 섞인 md를 한 번에 못 읽는다 — 텍스트 먼저 읽고, 필요한 이미지만 별도로 본다.
그래프 뷰 — 위키 형태(허브·고아)를 보는 최고의 도구.
Dataview 플러그인 — frontmatter(confidence·tags·sources·관계
::)로 동적 테이블·리스트 생성.Marp 플러그인 — 위키 내용에서 슬라이드 덱 직접 생성.
git — 위키는 결국 markdown git 레포. 버전 이력·브랜치·협업 무료.
템플릿 (회의록·오늘의 노트)
templates/에 두 템플릿이 있다. Obsidian 코어 플러그인으로 연결한다.
회의록 — templates/meeting.md → raw/meetings/
성격: 회의는 구두 소스(
source_kind: verbal) — 인제스트 시 신뢰도 −0.1.섹션: 안건 / 논의·결정 / 액션. frontmatter=메타(date·attendees), 본문=내용, 파일명=제목(중복 없음).
연결: 설정 → 코어 플러그인 Templates 켜기 → 템플릿 폴더
templates→ 새 노트에서Cmd+P→ "Insert template" → meeting.흐름: 회의 중 기록 →
raw/meetings/에 저장 → "인제스트해줘" → 결정·액션이 위키에 통합(ingest-status가 자동으로 pending 감지).
오늘의 노트 — templates/daily.md → raw/notes/
성격: 개인 스크래치(할 일·배운 것). 지식이 아니라 타임라인 → 인제스트해도 L2-episodic 기록만, L3 개념 생성 안 함.
섹션: 할 일 / 한 일·배운 것 / 메모. 파일명=날짜.
연결: 설정 → 코어 플러그인 Daily notes 켜기 → New file location
raw/notes· Template file locationtemplates/daily· Date formatYYYY-MM-DD→ 달력 아이콘/"Open today".주의:
raw/notes/는 인제스트 pending 스캔에서 제외돼 있다(매일 노트가 알림을 시끄럽게 안 만들게). 특정 날 노트를 위키에 넣고 싶으면 수동 인제스트.
동적 템플릿: 날짜 자동·참석자 입력이 필요하면 Templater 커뮤니티 플러그인.
{{date}}→<% tp.date.now("YYYY-MM-DD") %>, 입력받기<% tp.system.prompt("제목") %>. 폴더 템플릿으로raw/meetings/·raw/notes/에 새 노트 만들 때 자동 적용도 가능.
11. 하네스 진화·확장
하네스는 정적 산출물이 아니라 진화하는 시스템이다.
피드백 반영 경로:
피드백 유형 수정 대상 결과물 품질 해당 에이전트의 스킬 ( .claude/skills/*/SKILL.md)에이전트 역할 에이전트 정의 ( .claude/agents/*.md)워크플로우 순서 오케스트레이터 ( wiki-ops/SKILL.md)트리거 누락 스킬 description 신뢰도 규칙 confidence.py(base_for·모디파이어)망각 속도 decay.pySTABILITY 딕셔너리승격 임계 wiki-consolidate/SKILL.md(3회/2회)모든 변경은
CHANGELOG.md(하네스 변경 이력)에 기록 — 하네스가 어떻게 진화했는지 추적, 퇴행 방지. (2026-09-11 에CLAUDE.md에서 분리 — CLAUDE.md 는 현재 규칙만 둔다)재-myharness: 큰 아키텍처 변경은
/myharness:myharness에 개선안을 넘겨 자동 확장.update인자로 팩토리 정본 변경을 빌드된 하네스에 재전파(사용자 수정 보존).
튜닝 예시 — 망각을 더 느리게:
# .claude/skills/wiki-lint/scripts/decay.py 의 STABILITY 수정
STABILITY = { "architecture": 730, ... } # 365 → 730일12. 트러블슈팅
| 증상 | 원인 | 해결 |
|---|---|---|
| SessionStart 알림이 안 뜬다 | 세션 중 추가된 훅을 watcher가 미로드 | Claude Code에서 /hooks 한 번 열기 또는 재시작 |
updated: 자동 스탬프 안 됨 | 위와 동일 (훅 미로드) | /hooks 열기 |
| 스크립트 "command not found: rg" | 비로그인 셸 PATH에 rg 없음 | 이미 grep 기반이라 무관 — 커스텀 스크립트 추가 시 rg 대신 grep 사용 |
link-audit.py가 CLAUDE.md를 고아로 잡음 | 구버전 | 최신 버전은 type: 없는 파일 제외 — 스크립트 갱신 |
| 볼트가 비어 보임 (파일 없음) | OneDrive 클라우드 미동기 | Finder에서 "이 기기에 항상 유지" 또는 OneDrive 동기 강제 |
| 위키 페이지가 검색 안 됨 | frontmatter type: 누락 | 모든 페이지에 type: 부여 (스크립트가 페이지 판별 기준으로 씀) |
| decay.py가 페이지를 스캔 안 함 | last_confirmed·updated 둘 다 없음 | frontmatter에 날짜 필드 추가 |
검증 명령 모음:
# 링크 정합
python3 .claude/skills/wiki-lint/scripts/link-audit.py .
# 스크립트 문법
for s in $(find .claude/skills -name '*.sh'); do bash -n "$s"; done
for p in $(find .claude/skills -name '*.py'); do python3 -m py_compile "$p"; done
# 훅 JSON 유효성
jq -e '.hooks' .claude/settings.json13. 설계 결정 요약
| 결정 | 이유 |
|---|---|
| 전문가 풀(서브 에이전트), 팀 아님 | 오퍼레이션은 서로 다른 시점에 1명씩 실행 — 동시 협업 불필요. 인제스트는 단일 에이전트가 통째로(교차참조 일관성) |
| 계산은 스크립트, 판단은 LLM | 링크·신뢰도·망각은 결정적 → 스크립트가 공짜로. LLM 예산은 의미 검사(모순·승격 동치)에만 |
| grep 기반 스크립트 | rg는 비로그인 셸 PATH에 없는 경우가 많음 |
| SessionStart 훅 (Stop 아님) | Stop은 매 턴 발화=스팸. SessionStart는 세션당 1회 |
| 훅은 알림까지만 | 훅은 셸만 실행 — LLM lint 자동 실행 불가. 진짜 자율은 /schedule |
| stale 마킹, 삭제 안 함 | 이력 보존 — 언제 무엇이 왜 바뀌었는지 추적 |
| 단일 런타임 (Claude Code) | Codex 미사용 — AGENTS.md/.codex 중복 동기 부담 회피 |
| index.md + MoC 병존 | index=전수(기계적), MoC=큐레이션(계층). 임베딩 RAG 없이 수백 페이지 항해 |
| lazy 인제스트 (v2.1) | 인제스트는 증거+신규초안만, 병합·신뢰도·관계·승격은 lint 배치로. eager는 위키 클수록 O(n) 토큰 폭증 — 병합은 누적 후 일괄이 효율적 |
| 모델 라우팅 (v2.1) | 인제스트=sonnet(기계적·빈번), 나머지=opus(고추론). 측정 페이지당 실질비용 ~4.6×↓·지연 ~3×↓ |
| 비용 원장 (v2.1) | metrics/ — 문서당 토큰·모델가중 비용 추적. 최적화 효과를 숫자로 검증 |
| raw/notes 스캔 제외 | 데일리 노트는 스크래치 — 매일 pending 알림 스팸 방지, 넣고 싶은 날만 수동 인제스트 |
부록 — 빠른 시작 (TL;DR)
1. Obsidian 볼트 생성, Claude Code를 볼트에서 실행
2. /hooks 한 번 열어 훅 로드
3. raw/ 에 첫 소스 넣기 (Web Clipper 추천)
4. "이 소스 인제스트해줘" → L2 증거 + L3 사실(신뢰도) 생성
5. "llmops MoC 만들어줘" → 네비게이션 지도
6. "위키에 ~ 질문" → 신뢰도 포함 인용 답변
7. "위키 린트" → 망각·모순·승격 점검
8. "세션 마무리" → L1→L2 압축
9. Obsidian 그래프 뷰로 위키 형태 브라우징현재 상태는
CLAUDE.md(스키마), 하네스 변경 이력은CHANGELOG.md, 위키 타임라인은log.md가 정본이다.
develop_docs/v0.8.6/DESIGN.md
설계서 — llmwiki MCP 서버 (Node.js 포팅)
PRD:
develop_docs/v0.8.6/PRD.md정본 알고리즘:
.claude/skills/wiki-lint/scripts/search.py,scope-expand.py(v0.8.5 combo, A/B 5라운드 검증)작성일: 2026-09-07
1. 개요 — 구성과 데이터 흐름
[클라이언트: Claude Code(타 프로젝트) / Codex CLI / Gemini CLI / agy / Cursor / Windsurf
/ Claude Desktop / VS Code / 자체 에이전트(MCP 클라이언트 SDK)]
│ MCP (stdio, JSON-RPC) — 클라이언트마다 등록 문법만 다르고 서버는 동일 바이너리
▼
npx -y obsidian-llmwiki-mcp --root <볼트> ← tools/llmwiki-mcp (TypeScript, 읽기 전용, 의존 2개)
│
├─ wiki_search ── search.ts (search.py --files 포팅: lexical 파일 랭킹)
├─ wiki_expand ── expand.ts (scope-expand expand: seed→1홉→MoC Top-K [→BM25 rerank])
├─ wiki_pack ── pack.ts (scope-expand pack: claims·conf·status·관계 팩)
└─ wiki_read_page ── read.ts (절차 질의용 전문 read, wiki/ 하위로 제한)
│
▼ fs.readFile / readdir 만 사용 (쓰기 API 0개)
<볼트>/wiki/**/*.md (L2·L3·L4·moc — index.md·log.md는 wiki/ 밖이라 스코프 제외, Python과 동일)질의 1건의 표준 흐름(라우팅은 클라이언트 몫, 도구 description이 안내):
| 질의유형 | 호출 순서 | 근거(v0.8.5) |
|---|---|---|
| 단일조회 | wiki_expand(kw, max=6) → seed만 보고 답 | 최저비용 |
| 사실브리핑·비교 | wiki_expand(kw, max=20, rerank=11) → wiki_pack(slugs) 1회 | 팩 1-read로 충분, rerank 11이 균형 |
| 절차·how-to | wiki_expand(kw, max=8) → 후보를 wiki_read_page로 정독 | 팩=오버헤드, rerank는 needed 페이지 탈락 |
2. 패키지 구조
tools/llmwiki-mcp/
├── package.json name: llmwiki-mcp · bin: llmwiki-mcp · files: [dist, README.md]
├── tsconfig.json target ES2022 · module NodeNext · strict
├── src/
│ ├── vault.ts walkMd()·read()·frontmatter()·field() — 공통 파서
│ ├── graph.ts buildGraph() — slug→{type,aliases,out,in,text}, alias→slug
│ ├── search.ts filesMode() — search.py --files
│ ├── expand.ts lexicalSeeds()·expand()·MEMBER_K
│ ├── bm25.ts scoreText()·bm25Rank()
│ ├── pack.ts pack()
│ ├── read.ts readPage() — slug 검증·경로 제한
│ ├── format.ts Python stdout과 동일한 텍스트 렌더러(패리티용)
│ ├── tools.ts 도구 4개 계약(수기 JSON Schema 부분집합·description·instructions) + 입력 정규화·검증·상한
│ ├── server.ts 저수준 Server: tools/list·tools/call 핸들러(once.ts 함수 재사용), stdio 기동, DEBUG 타이밍
│ ├── print-config.ts 클라이언트별 등록 스니펫 생성(출력만, 파일 쓰기 없음)
│ └── cli.ts 인자 파싱(--root/--version/--selftest/--once/print-config) → server 기동
├── test/
│ ├── unit/ countSub·frontmatter·LINK·aliases·정렬 비교함수
│ └── fixtures/vault/ 합성 볼트(콘텐츠 무관·한국어·BOM·이모지·코드펜스·별칭링크 케이스)
└── README.md 설치·등록 매트릭스 8종·도구 계약·한계
tests/parity.py (저장소 루트, 기존 smoke.py 옆) Python↔Node diff저장소는 하네스(
llmwiki-harness). 볼트에는 설치하지 않는다 — 볼트는--root데이터일 뿐.런타임 의존성은
@modelcontextprotocol/sdk하나. 빌드 산출물dist/를 퍼블리시.P2 결정(2026-09-09, 실측 근거): 원안은
McpServer+ zod 였으나, 인프로세스 클라이언트로tools/list를 덤프해 보니 SDK 1.30 의 zod4 경로(z4mini.toJSONSchema)가$schema·additionalProperties:false·execution:{taskSupport}를 자동 삽입해 §3 "스키마 부분집합" 규칙을 어겼다. 저수준Server(setRequestHandler(ListTools/CallTool)) 에 수기 JSON Schema(src/tools.ts)를 주면 쓴 그대로 나간다 → 채택. 잃는 것: SDK 의structuredContent↔outputSchema자동 검증(단위 테스트 P2-09 로 대체)과 zod 입력 검증(런타임 정규화·검증 함수로 대체 — 원래 §3 이 요구한 방식). zod 는 런타임 의존에서 제거(SDK 내부 의존으로만 존재).Node ≥ 20 (lookbehind·
\p{}·fs.promises안정). 개발 환경 v24.
3. 도구 계약
공통: 모든 도구는 content[0].text에 사람이 읽는 텍스트를 반환한다. structuredContent(+ 도구별 outputSchema)는 LLMWIKI_STRUCTURED=1 일 때만 함께 반환한다 — 아래 'P4-27+ 결정' 참조. Python 스크립트와의 바이트 동일 보장은 --once CLI 에 있다(패리티 테스트 대상). MCP 응답은 wiki_expand 에 suggested_next: … 한 줄을 덧붙이고 200KB 예산을 적용한다. 텍스트는 패리티·사람 가독용, JSON은 에이전트 파싱용. 오류는 MCP isError: true + 한 줄 메시지.
동일성의 정의: Python stdout 전체(줄 구분 \n, 마지막 개행 포함)와 --once 출력이 바이트 동일. MCP text도 같은 문자열(개행 제거 안 함). Windows에서도 \n 고정(Python 쪽은 sys.stdout.reconfigure(newline="\n")을 patch 범위에 포함 — §7). 예외는 rerank 점수 열 하나(§7 허용오차).
structuredContent는 MCP 2025-06-18 스펙·TS SDK 표준 필드다(외부리뷰 2026-09-09에서 "비표준" 지적 → SDK 문서로 반증·기각). LLMWIKI_STRUCTURED=1 일 때 각 도구에 outputSchema를 선언한다(P4-27+ 이후 기본은 미선언·텍스트만) — 선언 시 SDK가 전송 전 검증하고, 검증 클라이언트는 불일치 결과를 거부하므로 스키마와 실제 JSON을 단위 테스트로 맞춘다. 구형 클라이언트는 content[0].text만 보므로 텍스트가 1차 표현이다.
입력 내결함성(외부리뷰 #6 반영). LLM 클라이언트의 흔한 변형을 도구 진입점에서 정규화한다: terms가 문자열이면 공백 분할 → 배열; slug/slugs 항목은 양끝 공백·[[·]]·.md·wiki/…/ 접두를 제거. 정규화 후 검증 실패는 isError + 어떤 입력이 왜 거부됐는지 한 줄. 정규화는 런타임(핸들러 첫 줄)에서 하고 스키마에는 드러내지 않는다 — 아래 호환 규칙 때문.
다중 클라이언트 호환 규칙(2026-09-09 재검토). 서버 하나가 Claude Code·Codex·Gemini CLI·agy·Cursor 등에서 그대로 동작해야 한다.
JSON Schema 부분집합만.
inputSchema·outputSchema는type: object|array|string|integer|boolean,properties,required,items,enum,description,minimum/maximum,minItems/maxItems만 사용. 금지:anyOf/oneOf/allOf,$ref/$defs,const,default,additionalProperties,format, Zodpreprocess/transform/union이 만들어내는 스키마. Gemini 계열이 취약하고 Codex는 엄격 검증. CI에서tools/list결과를 덤프해 금지 키워드 grep.도구 이름
^[a-z][a-z0-9_]{0,63}$(OpenAI 함수명 규칙 교집합). 현행 4개 모두 적합.description은 영문 먼저 + 한국어 한 줄, ≤ 500자. 클라이언트가 매 턴 도구 설명을 모델에 싣는다 → 4도구 합계 ≤ 2,000자. 각 description 마지막 줄은 그 도구의 라우팅 위치 한 줄(예:
wiki_pack— "Use after wiki_expand(rerank=11) for factual briefings; do not read_page if claims suffice"). 전체 라우팅 표는 서버instructions에만.instructions에 의존하지 않는다. Claude Code는 모델에 노출하지만 Codex·Gemini·Cursor는 미확인 → description 한 줄 +suggested_next로도 라우팅이 성립해야 한다(PRD 지표 "규칙 파일 없이 준수").prompts/resources는 선택 기능. 클라이언트 지원이 갈리므로 필수 경로에 두지 않는다. v1은 tools만.
structuredContent를 못 읽는 클라이언트는content[0].text로 동작. 텍스트가 1차 표현인 이유.P4-27+ 결정(2026-09-10, E2E 실측 근거) — 구조화 출력은 기본 off, opt-in. P2 에서는
structuredContent+outputSchema를 항상 반환하기로 했으나, Claude Code 2.1.267 실클라이언트 E2E 에서 클라이언트가structuredContentJSON 을 모델에 넘기고, 우리 structuredContent 가text와rows/pages를 이중으로 담아 모델 입력이 텍스트 대비 2.06~4.24배(pack 9,715B → 20,015B)임을 확인했다. 이 서버의 소비자는 LLM 이고 리트리벌 설계의 토큰 절감(A/B −55%)은 텍스트(TSV) 기준이므로 기본은 텍스트만 보낸다.text만 빼는 안(1안)은 기각 — JSON 행 표현 자체가 TSV 보다 무겁다(expand 2.6배). MCP 스펙상 outputSchema 선언 = structuredContent 전송 의무라 둘은LLMWIKI_STRUCTURED=1로 함께 켠다. 응답 JSON 전체 200KB 예산은 두 모드 모두 적용(기본 모드는 JSON 이스케이프로 부푼 envelope 을 재측정·축소 — 외부리뷰 P4-27 MAJOR). 텍스트는 작은 응답에서 두 모드 바이트 동일, envelope 을 넘는 큰 응답에서만 opt-in 쪽이 더 짧다(text 가 structuredContent 에 한 번 더 실리므로 — 의도된 차이, 테스트 고정). outputSchema 검증(fail-closed)은 opt-in 경로에 유지. opt-in 모드의content[0].text가 structuredContent 의 JSON 직렬화가 아니라 TSV 인 것은 스펙 권고(SHOULD)와 다른 의도된 예외(텍스트 클라이언트·Python 패리티가 이 텍스트에 의존).--once패리티 무영향.stdout 순수성. transport 외 stdout 쓰기 0.
console.logESLint 금지, smoke가 기동 직후 stdout 첫 바이트가{인지 검사.
3.1 wiki_search — lexical 파일 랭킹 (search.py --files)
| 입력 | 타입 | 기본 | 설명 |
|---|---|---|---|
terms | string[] (1~10) | — | OR 검색어. 소문자화·공백만인 항목 제거 |
top | int 1~50 | 8 | 상한(fill 아님) |
출력 텍스트: 줄당 "<distinct>/<total>\t<slug>\t<type>", 없으면 "no matches for: <terms>".
JSON: {rows:[{distinct,total,slug,type}]}.
description 요지: "팩·확장 결과가 빈약할 때의 fallback. 보통은 wiki_expand를 먼저 쓴다."
3.2 wiki_expand — 그래프 확장 스코프 (+rerank)
| 입력 | 타입 | 기본 | 설명 |
|---|---|---|---|
terms | string[] (1~10) | — | 키워드 |
max | int 1~50 | 15 | 확장 pool 상한 |
top_seed | int 1~20 | 6 | lexical seed 수 |
rerank | int 0~50 | 0 | 0=미적용. 사실브리핑은 11 권장 |
출력 텍스트(rerank=0): "<tier>\t<refs>\t<slug>\t<type>", tier ∈ seed/1hop/moc.
출력 텍스트(rerank>0): "<tier>\t<score:.1f>\t<slug>\t<type>".
seed 없음: "no lexical seed for: <terms>".
JSON: {rows:[{tier,refs?,score?,slug,type}], suggested_next: "wiki_pack"|"wiki_read_page"|"answer"} — suggested_next는 라우팅 힌트(rerank>0→pack, max≤6→answer, 그 외→read_page).
description에 §1의 라우팅 표를 그대로 수록한다(클라이언트가 SKILL.md 없이도 규칙을 안다).
3.3 wiki_pack — claims 컨텍스트 팩
| 입력 | 타입 | 설명 |
|---|---|---|
slugs | string[] (1~30) | 확장 결과 slug |
출력 텍스트: slug마다
## <slug> [<type> · conf <confidence|-> · <status|active>]
- <claim>… (claim:: 없으면 "- (요약) <첫 실문단>")
- 관계) <pred :: [[target]] …>
<빈 줄>없는 slug는 "## <slug>\n(없음)\n".
JSON: {pages:[{slug,type,confidence,status,claims[],summary?,relations[]}]}.
description 요지: "confidence를 답에 병기하고, status: stale이면 답에 쓰지 말고 superseded_by를 wiki_read_page로 따라가 active를 우선하라. claims로 충분하면 full-read 금지."
3.4 wiki_read_page — 전문 read (절차 질의)
| 입력 | 타입 | 설명 |
|---|---|---|
slug | string | 파일명(확장자 없음) |
검증(P2 개정 2026-09-09): 길이 1~120, /·\·..·제어문자(\p{Cc}) 불포함 — 원안의 문자 클래스 ^[\p{L}\p{N}._\- ]+$ 는 기호 포함 파일명(zz-🦀-crab)을 거부해 wiki_expand → wiki_pack 흐름을 끊었다(P2 단위테스트 검출). 경계 보장은 문자 클래스가 아니라 walk 인덱스 조회 + realpath/path.relative 판정이 맡는다. wiki/** 아래에서 slug 일치 파일을 찾아(walk 순서·마지막 승) realpath가 <root>/wiki/ 밖이면 거부.
없는 slug: 그래프의 alias2slug(소문자 키)로 1회 리다이렉트 시도(Python pack에는 없는 동작이지만 read_page는 신규 도구라 패리티 대상 아님). 그래도 없으면 isError: true + "page not found: <slug>".
출력: 파일 전문(frontmatter 포함). JSON: {slug, resolved_from_alias?, path(상대), frontmatter:{type,confidence,status,superseded_by?,last_confirmed?}, text}.
description 요지: "절차·how-to 또는 팩이 불충분한 특정 주장 확인에만. 사실브리핑에서 남발 금지."
3.5 서버 메타
name: llmwiki,version은 package.json.instructions(MCP 서버 수준 안내)에 세 줄: 읽기 전용 · 라우팅 표 · 신뢰도/stale 규약.기동 시
<root>/wiki존재 확인, 없으면 stderr 한 줄 + exit 2.--selftest: 픽스처 없이 root의 페이지 수·MoC 수·빌드 시간(ms)·프로세스 기동→ready(ms) 를 출력하고 종료(설치 확인·Codex 타임아웃 판단용).print-config --client <claude-code|codex|gemini|agy|cursor|windsurf|claude-desktop|vscode> --root <볼트> [--windows] [--global]: 해당 클라이언트의 등록 명령(CLI형) 또는 JSON/TOML 조각(설정형)을 stdout에 출력. 파일에 쓰지 않는다 — 클라이언트 설정 파일은 타 서버의 비밀키를 담고 있어 자동 편집이 위험.--global은npm i -g설치 전제로npx -y대신llmwiki-mcp직접 실행 형태로 출력.
4. 알고리즘 포팅 대응표 (정본 = Python)
원칙: 랭킹 규칙을 바꾸지 않는다. 아래는 의미가 갈릴 수 있는 지점만 고정한다.
| # | Python | TypeScript | 비고 |
|---|---|---|---|
| 1 | os.walk + sorted(files); 디렉터리 순서는 OS 의존 | readdir({withFileTypes}) 후 디렉터리·파일 모두 이름 정렬(코드포인트) 순회 | Python 쪽도 패리티 픽스처 기준으로 디렉터리 순서를 정렬하도록 소폭 수정(§7). 중복 slug는 마지막 승 |
| 2 | open(encoding="utf-8-sig", errors="replace") — 텍스트 모드 universal newlines: \r\n·\r → \n 자동 변환 | readFile → UTF-8 디코드, 선행 제거, 잘못된 바이트는 U+FFFD(TextDecoder 기본), \r\n→\n 후 잔여 \r→\n | ⚠ 외부리뷰 #3: 변환 누락 시 CRLF 파일에서 dl·avgdl·count가 어긋나 BM25·lexical 불일치. 유니코드 NFC/NFD는 양쪽 모두 정규화 안 함(Python 정본이 안 하므로; 패리티 유지). 한계에 기재 |
| 3 | frontmatter: 첫 줄 ---, 이후 200줄 내 닫는 --- | 동일. split("\n") 기준(#2에서 개행 정규화 완료) | .gitattributes가 LF 강제하나 볼트는 사용자 파일이라 CRLF 허용 → 픽스처에 CRLF 파일 포함 |
| 4 | field: ^name:\s*(.+)$ MULTILINE, strip() | new RegExp("^"+name+":\\s*(.+)$","m"), trim() | .+는 줄 내(JS .도 개행 불일치) |
| 5 | type 기본값 — build_graph(expand)·search.py 는 부모 디렉터리명, do_pack 헤더는 ? (field(fm,"type") or "?") | 동일하게 비대칭 유지 — graph/search 는 dirname, pack 헤더는 ? | Python 정본의 비대칭(P0 외부리뷰 지적). 픽스처 q14: search 는 L4-procedural, pack 은 [? · conf - · active] |
| 6 | aliases 파싱: strip("[] ") 후 [^\[\],]+ findall, 각 strip().strip("'\"") | 동일 순서. strip("[] ")는 양끝에서 [·]·공백 문자 집합 제거임(문자열이 아님) | 헬퍼 stripChars(s, "[] ") |
| 7 | `LINK = (?<!!)[[([^] | #]+)` | 동일, V8 lookbehind 지원. g 플래그 matchAll |
| 8 | 링크 정규화: 원문 slug 존재 → 그대로, 아니면 alias2slug[lower]; 자기링크 제외 | 동일 | alias 등록은 setdefault(먼저 등록한 것이 이김) → Map.has 체크 후 set |
| 9 | str.lower() | toLowerCase() | 한국어·ASCII 동일. 특수 케이스(İ 등) 무시 |
| 10 | hay.count(t) — 비중첩 부분문자열 수 | countSub(hay,t): indexOf 루프, i += t.length | split(t).length-1은 빈 문자열 예외 → 사용 금지 |
| 11 | lexical 정렬 (-distinct, -total, slug) — Python 문자열 비교는 코드포인트 순 | 비교함수 동일 순서, 마지막 slug는 cmpCodePoint(a,b) 헬퍼(codePointAt 순회) | JS <는 UTF-16 코드유닛 비교라 non-BMP(이모지) vs U+E000~FFFF에서 역전(외부리뷰 #9). localeCompare 금지 |
| 12 | expand: cand[n]=[tier,refs], seed는 [0,99], bump는 tier=min·refs+=1 | 동일 | seed refs 99는 정렬용 |
| 13 | MoC 멤버 정렬 (-lex, m) 후 MEMBER_K=6 | 동일 | |
| 14 | tier1 필터 lex>0 or refs>=2; 최종 정렬 (tier, -lex, -refs, slug) → [:max] | 동일 | |
| 15 | _score_text: \]\([^)]*\)→], https?://\S+→"", lower | 동일 regex(g) | \S 의미 동일 |
| 16 | BM25: terms 중복제거·길이<2 제외, N=전체, avgdl=문자 길이 평균, idf=log((N-df+.5)/(df+.5)+1), df=t in tx | 동일. Math.log. dl은 문자열 length(UTF-16 코드유닛) vs Python 코드포인트 | ⚠ 서로게이트 쌍(이모지 등)에서 dl 차이 → [...tx].length로 코드포인트 수 사용 |
| 17 | rerank 정렬 (-score, slug), 출력 score:.1f | fmt1(x) 전용 헬퍼(toFixed 직접 사용 금지) | 확인됨(2026-09-09): 정확한 tie에서 다름 — 0.25 → Python 0.2(half-even) / JS toFixed 0.3(큰 쪽). fmt1: x*10이 정확히 .5로 끝나면 half-even, 아니면 toFixed(1). 단위 테스트에 0.25·0.35·2.45·0.0·음수 케이스. 추가로 Math.log(V8) vs math.log(libm)가 1 ULP 다를 수 있어 .x5 경계에서 플랫폼별 뒤집힘 가능(외부리뷰 #5) → 점수 열은 바이트 동일 대상에서 제외, §7 허용오차 |
| 17b | 미매치 메시지: search.py no matches for: {소문자화 terms} / scope-expand.py no lexical seed for: {원본 terms} | 각각 동일 — search는 소문자, expand는 원본 대소문자 유지 | 두 스크립트가 다르다(외부리뷰 #7). 통일하지 않고 그대로 재현. 픽스처에 대문자 질의 포함 |
| 18 | pack claims: ^-?\s*claim::\s*(.+)$ MULTILINE, 코드펜스 무시 없음(문서 전체 스캔) | 동일(gm). 관계 추출(#20)과 달리 펜스 토글을 적용하지 않는다 | 비대칭이지만 정본 동작(외부리뷰 #8). "일관성" 명목의 수정 금지. 픽스처에 펜스 안 claim:: 케이스 |
| 19 | pack 요약: text.split("---",2)[-1] 후 첫 줄 중 `t[0] not in "#!> | -"and notstartswith("[")` | split("---")는 Python maxsplit=2와 다름 → 헬퍼로 앞 2개 구분자만 분리 |
| 20 | 관계: -\s*([\w-]+\s*::\s*\[\[[^\]]+\]\].*)$, 코드펜스 토글, claim 접두 제외 | [\p{L}\p{N}_-]+ + u 플래그 | Python \w=유니코드. JS \w=ASCII → 그대로 쓰면 한국어 술어 탈락 |
| 21 | --top-seed·--max·--rerank 기본 6·15·0 | 동일 |
이 표는 test/unit의 케이스 목록이기도 하다. 각 행에 대응하는 단위 테스트를 둔다.
5. 보안·격리
쓰기 API 0개.
fsimport는readFile·readdir·stat·realpath만. CI에서grep -E "writeFile|appendFile|unlink|rename|mkdir|rm(Sync)?\(" src/가 0건이어야 통과.순회 단계 심볼릭 링크 차단(외부리뷰 #1, BLOCKER).
read_page만 검증하면 부족하다 —buildGraph의walkMd가wiki/leak.md → ../CLAUDE.local.md같은 링크를 읽어 그래프에 적재하면wiki_search·wiki_pack으로 유출된다.walkMd는readdir({withFileTypes})에서 심볼릭 링크 엔트리(파일·디렉터리 모두)를 건너뛰고, 추가로 각.md의realpath가<root>/wiki/하위가 아니면 제외한다(stderr 경고 1줄, 내용 로그 금지). Python 정본은 이 검증이 없으나 픽스처에는 심볼릭 링크를 두지 않으므로 패리티에 영향 없음. 실 볼트 한계에 "wiki/ 안 심볼릭 링크는 무시됨" 기재.경로 제한. 모든 파일 접근은
<root>/wiki/하위 실경로만.wiki_read_page는 §3.4 검증.--root자체는realpath로 정규화. 접두 비교는 문자열startsWith가 아니라path.relative(wikiReal, targetReal)이..로 시작하지 않고 절대경로가 아닌지로 판정(Windows 구분자·대소문자 무시 FS·wiki2/같은 접두 우회 방지).입력 상한. terms ≤10개·각 ≤64자, slugs ≤30, 응답 텍스트 ≤ 200KB UTF-8 바이트(코드포인트 경계 보존, 초과 시 절단 +
truncated: true). pack 의structuredContent.pages도 같은 예산(P2 리뷰: text 만 자르면 우회).자원 상한(P2 리뷰). 파일 1개 ≤16MiB, 파일 수 ≤20,000 — 초과 시 결과를 조용히 바꾸지 않고
VaultLimitError(도구 isError /--onceexit 1). 동시 도구 호출 ≤4(세마포어).TOCTOU 완화(P2 리뷰).
read()는O_NOFOLLOW로 열어 realpath 검사 뒤 최종 구성요소가 링크로 바뀌어도 따라가지 않는다(POSIX; Windows 는 상수 없음). 상위 디렉터리 교체 경쟁은 로컬 단일 사용자 도구 범위에서 수용 — 원격/멀티테넌트 노출 시 재검토.읽기 전용 가드는 허용목록. CI 가
src/의fs.*/fh.*멤버를 추출해 readFile·readdir·stat·realpath·open(읽기 플래그)·close·constants 외면 실패. 대괄호 접근·동적 접근 금지.print-config 안전. 서버 이름
^[A-Za-z][A-Za-z0-9_-]{0,63}$(셸·TOML 삽입), root 개행·NUL 거부. Windows 출력은 볼트 경로를 명령 인자에 넣지 않는다(cmd /c가&·|·%VAR%해석) — env 전달만. CLI 형의--env값은 cmd.exe 인용(큰따옴표).%는 이스케이프 불가(대화형 cmd 는 따옴표 안에서도 확장,%%는 배치 전용) →%·!가 든 경로는 CLI 형 등록을 거부하고 JSON 설정형(env)을 안내한다.볼트 루트 검증(P2 2차 리뷰).
resolveRoot를 서버·--selftest·--once가 공유: root realpath,wiki/는 비링크 디렉터리이고realpath(wiki) == <rootReal>/wiki—root/wiki → 외부링크가 walkMd 경계를 통째로 우회하던 결함 차단. 오류 메시지는 입력 문자열만 반영(realpath 비노출),--selftest는 basename+해시(--show-root로 전체).원시 입력 가드. terms/slugs 문자열 ≤4,096자·배열 ≤256항목을 분할·순회 전에 검사. 볼트: 파일 ≤20,000·디렉터리 ≤5,000·깊이 ≤32·누적 텍스트 ≤512MiB·파일 ≤16MiB.
--once계약. Python 패리티 도구이므로 200KB 절단을 적용하지 않는다. P2-33 "같은 코드 경로" = 절단 전 리트리벌 텍스트 동일.콘텐츠 비유출. 패키지
files화이트리스트(dist/,README.md). CI에서npm pack --dry-run목록에.md가 README 외 0개.로그. stdout은 MCP 전용. 진단은 stderr, 기본 quiet.
LLMWIKI_DEBUG=1이면 도구별 소요(ms)만 — 질의어·페이지 내용은 로그 금지.
6. 성능
v1: 호출마다
buildGraph(Python과 동일 동작). 실 볼트 315 페이지 기준 Python <1s → Node 동급 예상. 파일 read는fs.promises.readFile을 동시성 32로 병렬(순서는 정렬된 목록 기준으로 재조립). 파일을 조용히 스킵하지 않는다(Python 과 결과가 달라지므로 — 외부리뷰 #12). 대신 P2 리뷰 반영으로 16MiB 초과 시 명시적 오류(VaultLimitError)로 실패한다 — 결과를 바꾸지 않으면서 무제한 read 를 막는 절충(§5). stdio 서버는 단일 클라이언트라 이벤트 루프 블로킹은 수용.v1.1(2026-09-10 구현 — P4, 외부리뷰 1차 반영): 프로세스 내 캐시
src/cache.ts. 호출 시walkMd(경계 검사 포함) +lstat스캔으로 변경 감지 → 변경 파일만 재파싱, 그래프는 통째 재구성(인링크 때문). 패리티는 캐시 on/off 양쪽 실행(픽스처 56 · 실볼트 20 · 퍼징 200, 전부 동일 — CI 에 on/off 두 단계로 고정).캐시 키 = 볼트 realpath + 파일별
(경로, dev, ino, mode, size, mtimeNs, ctimeNs).ctime이 핵심이다 — 내용·권한·이름이 바뀌면 커널이 올리고 userland 가 되돌릴 수 없어서cp -p·rsync --times·touch -t로 mtime·size 를 복원해도 적중하지 않는다(codex 1차 BLOCKER-1).dev·ino·mode가 들어가므로 파일이 다른 파일·심볼릭 링크로 교체돼도 미스다(codex 1차 BLOCKER-2). Node 의ctime은 POSIX·NTFS 모두 상태 변경 시각이다(생성 시각은birthtime— Node v24 공식 문서 "Stat time values"). 1차 반영 때 "Windows ctime = 생성 시각" 이라 적은 것은 오류였고 2차 리뷰(codex B3)가 그 문장을 근거로 삼았다 → 정정. 방어가 실제로 성립하지 않는 곳은 FAT/exFAT·일부 네트워크 FS(변경 시각 없음/약함)이며 README 한계에LLMWIKI_CACHE=0권고로 기재.순회는 캐시하지 않는다. 심볼릭 링크 스킵·realpath 경계(§5)는 호출마다 그대로 수행되고 캐시는 그 뒤에 붙는다 — 캐시 적중이 보안 규칙을 우회할 수 없다.
타임스탬프 해상도 방어: 스냅샷에 최근 2s(
FRESH_WINDOW_MS) 안에 수정된 파일이 있으면 '불안정'으로 보고 저장도, 기존 캐시 사용도 하지 않는다(그래프 적중·텍스트 재사용 모두 금지, 전량 재독 — codex 2차 BLOCKER-1: 저장만 막고 적중은 허용하던 구멍). 단FUTURE_SKEW_MS(5s)보다 더 미래인 mtime 은 시계 차이로 보고 캐시를 막지 않는다 — 막으면 미래 타임스탬프 파일 하나가 그 볼트의 캐시를 영구 무력화한다(agy 1차 BLOCKER-1).파생값도 캐시한다(P4-13+): lex haystack·bm25
scoreText·dl은 term 과 무관해 노드 수명 동안 재사용한다(WeakMap). 예산은 그래프를 새로 조립할 때 리셋한다(agy 1차 BLOCKER-2: 전역 카운터가 계속 늘면 상한 초과 후 파생 캐시가 영구히 멈춘다). 측정 분해에서 buildGraph 는 호출 비용의 29% 뿐이라 그래프만 캐시하면 ROI 가 나지 않는다.메모리: 텍스트 캐시 root 당 256MiB — 넘으면 그래프도 저장하지 않는다(그래프가 본문을 쥐고 있어 텍스트 상한을 우회하던 구멍, codex 2차 MAJOR-1). 파생 메모 128MiB 는 살아 있는 전 root 의 합으로 계산하고, 저장된 그래프의 노드에만 매단다(세대 번호로 확인). 볼트 4개까지 LRU 로 유지(
MAX_ROOTS)하되 전 root 텍스트 합 512MiB(TOTAL_TEXT_BUDGET_BYTES)를 넘으면 가장 오래 안 쓴 다른 root 를 비운다(codex 3차 MAJOR-2). 누적 상한MAX_TOTAL_BYTES는 캐시 적중분까지 읽는 즉시 센다(codex 3차 MAJOR-1). 상한은 전부 문자열 payload 기준 논리 상한이며 RSS 상한이 아니다. 스냅샷 lstat 은 동시성 64 풀(agy 3차 MINOR-1). 프로세스 종료 시 소멸, 디스크 캐시 없음.상위 디렉터리 교체 경쟁(codex 2차 BLOCKER-2)은 캐시가 늘리지 않는다: walk 뒤에 상위 디렉터리가 외부 링크로 바뀌어 한 호출이 외부 본문을 읽어도, 그 본문은 외부 파일의
dev/ino로 키가 잡힌다. 다음 호출에서 교체가 유지되면 walkMd 의 realpath 검사가 그 파일을 빼고, 원복되면 신원이 달라 미스가 난다 — 어느 쪽이든 캐시된 외부 본문은 다시 제공되지 않는다. 노출 범위는 캐시가 없을 때의 한 호출과 같고, 그 잔여 위험 자체는 P2-42+ 가 로컬 단일 사용자 범위에서 수용한 것이다(Node 에openat계열 API 가 없어 구성요소 고정 순회는 불가).스위치·기본값:
LLMWIKI_CACHE=0이면 stat 스캔조차 하지 않고 v1 경로,=1이면 강제로 켠다. 미지정이면 서버는 켜고--once·--selftest는 끈다(배선 점검 2026-09-10: 1회성 프로세스는 적중 기회 없이 stat 스캔만 더해져 1,000p cold 가 +7.7% 느려졌고,--selftest의buildGraph_ms의미가 바뀌었다). CI 패리티 ON 단계는LLMWIKI_CACHE=1로 캐시 경로를 강제한다.실측(인프로세스 median of 10): 309p off 48.4 → 2회차 9.2ms(-81.6%) · 1,000p off 195.4 → 26.4ms(-87.0%) · 2,000p off 379.5 → 48.9ms. warm 의 고정 비용은 walk+lstat 스캔(309p 6.1 · 1,000p 19.3 · 2,000p 35.6ms)이다.
OneDrive 온디맨드 파일(클라우드 전용 상태)은 첫 read가 느릴 수 있음 → README 한계에 기재.
7. 패리티 테스트 (tests/parity.py)
for mode in [search --files, expand, expand --rerank 11, pack]:
for q in QUERIES(14): # 픽스처 볼트 대상(test/fixtures/queries.json), 한국어·영문·혼합·대문자·미매치 포함. P0에서 12→14(q13 MoC-as-seed, q14 type 기본값)
# Python·Node 실행은 concurrent.futures 로 병렬(직렬 56회 ≈7s → P0 리뷰 지적)
py = run(python3 scope-expand.py|search.py … --root fixtures/vault)
node= run(node dist/cli.js --root fixtures/vault --once <tool> <json>) # --once: 서버 없이 도구 1회 실행 후 텍스트 출력
assert py == node (바이트 비교, 실패 시 unified diff 출력)
# 예외: expand --rerank 모드는 파서 기반 — tier·slug·type 열과 **행 순서**는 정확 일치,
# score 열은 |py−node| ≤ 0.05 허용(1 ULP log 차이 흡수, 외부리뷰 #5). 순서 역전은 실패.실 볼트 로컬 패리티(외부리뷰 #10):
python tests/parity.py --vault <경로>— 대표 질의 5개를 같은 방식으로 diff. 볼트가 없으면 스킵(CI). 릴리즈 체크리스트 항목이며 결과를 릴리즈 노트에 1줄 기록.픽스처 볼트
tools/llmwiki-mcp/test/fixtures/vault/wiki/— 페이지 ≈25개(L2 5·L3 15·moc 3·L4 2). 케이스: BOM, CRLF, 별칭 링크, 이미지 임베드, 코드펜스 안 가짜 관계, 코드펜스 안claim::(#18 비대칭), 이모지 본문(dl 차이), non-BMP 문자 slug(#11 정렬),claim::없음 페이지, stale+superseded 쌍, 중복 slug(디렉터리 다른 동명 파일), 큰 MoC(멤버 10+), 대문자 질의어(#17b). 심볼릭 링크는 두지 않는다(git 이식성·Python 미검증).Python 소폭 수정 1건(정본 유지 범위):
walk_md(scope-expand.py)·files_mode/line_mode(search.py)의os.walk에서 디렉터리 순회도 정렬(dirs.sort())해 OS 무관 결정성 확보 + stdoutnewline="\n"고정. 랭킹 규칙 무변경. smoke.py 통과 확인. 실 볼트에서 수정 전후 대표 질의 출력 동일함을 확인해 회귀 없음을 기록.CI: 기존
smoke잡 옆에parity잡(동일 OS 매트릭스, setup-node 20 + setup-python).npm ci && npm run build && python tests/parity.py.
8. 등록 매트릭스·클라이언트 안내
문법은 2026-09-09 로컬 실측(agy mcp add --help, codex mcp add --help 0.153.4, ~/.gemini/settings.json, ~/.cursor/mcp.json) 기준. print-config가 아래를 생성한다. <VAULT>는 절대경로. 인용은 print-config 가 처리한다 — POSIX 는 위험 문자가 있을 때만 작은따옴표($·백틱·! 완전 차단), 안전한 경로는 인용 없이 그대로.
# Claude Code — 사용자 범위(모든 프로젝트에서 보임)
claude mcp add --scope user llmwiki -- npx -y obsidian-llmwiki-mcp --root "<VAULT>"
# Codex CLI (0.153.4 실측 — P3) — `-c mcp_servers.<name>.startup_timeout_sec=60` 을 add 와 함께 주면
# "invalid transport" 로 **실패**한다(-c 가 command 없는 테이블을 먼저 만든다). 플래그 없이 등록하고
# 타임아웃이 필요하면 config.toml 을 편집한다. npx 콜드스타트 실측 5.8s(캐시 비운 tarball) < 기본 10s.
codex mcp add llmwiki -- npx -y obsidian-llmwiki-mcp --root "<VAULT>"
# 또는 ~/.codex/config.toml
# [mcp_servers.llmwiki]
# command = "npx"
# args = ["-y", "obsidian-llmwiki-mcp", "--root", "<VAULT>"]
# startup_timeout_sec = 60
# agy — 플래그는 name 앞, '-'로 시작하는 인자 앞에 '--'
agy mcp add llmwiki -- npx -y obsidian-llmwiki-mcp --root "<VAULT>"
# Gemini CLI — ~/.gemini/settings.json (또는 gemini mcp add llmwiki npx -y obsidian-llmwiki-mcp --root "<VAULT>")
{ "mcpServers": { "llmwiki": { "command": "npx",
"args": ["-y", "obsidian-llmwiki-mcp", "--root", "<VAULT>"] } } }
# Cursor(~/.cursor/mcp.json) · Windsurf(~/.codeium/windsurf/mcp_config.json) · Claude Desktop(claude_desktop_config.json)
{ "mcpServers": { "llmwiki": { "command": "npx", "args": ["-y", "obsidian-llmwiki-mcp"],
"env": { "LLMWIKI_ROOT": "<VAULT>" } } } } # env 블록 지원 → 경로 인용 문제 회피
# VS Code (Copilot) — .vscode/mcp.json 은 최상위 키가 "servers"
{ "servers": { "llmwiki": { "type": "stdio", "command": "npx",
"args": ["-y", "obsidian-llmwiki-mcp", "--root", "<VAULT>"] } } }
# Windows — JSON 설정형 클라이언트는 npx 직접 실행 불가 → cmd 래핑
{ "command": "cmd", "args": ["/c", "npx", "-y", "obsidian-llmwiki-mcp", "--root", "<VAULT>"] }
# 콜드스타트·타임아웃 회피 대안 — 전역 설치 후 직접 실행
npm i -g obsidian-llmwiki-mcp → command: "llmwiki-mcp", args: ["--root", "<VAULT>"]
# 자체 에이전트 — MCP 클라이언트 SDK(stdio). LangGraph는 langchain-mcp-adapters로 동일 command/args 지정클라이언트 규칙 스니펫(선택). 원본 하나 templates/mcp-client-guide.md(라우팅 표 §1 + 규약 3줄: 신뢰도 병기·stale은 superseded_by 추적·읽기 전용, 파일링은 볼트 wiki-ops) → 파생:
Claude Code:
~/.claude/skills/llmwiki-query/SKILL.md(트리거 "위키에 뭐라고", "llmwiki 참고")Codex:
~/.codex/AGENTS.md조각 · Gemini:~/.gemini/GEMINI.md조각 · Cursor:.cursor/rules/llmwiki.mdcagy: 스킬/플러그인 체계 확인 후 결정(미확인) — 없으면 규칙 없이 서버 자기서술로만. 없어도 동작이 요구사항(PRD ②·지표 "규칙 파일 없이 준수")이며 스니펫은 준수율 보조.
볼트 안
wiki-query·wiki-ops는 변경 없음(계속 Python 스크립트 직접 호출). MCP는 볼트 밖 전용.
9. 배포·버전·롤백
단계: P1 포팅+단위+패리티 → P2 MCP 서버+
--once+Inspector 확인 → P3 README·스킬·npm publish 0.1.0·CI → P4(후속) 캐시 v1.1.버전: 하네스 태그
v0.11.0(외부 인터페이스 신설). npm은 독립 semver, 랭킹 규칙 변경 시 npm minor + 하네스 동시 태그.동기 규칙(CLAUDE.md에 추가): "리트리벌 규칙 변경은 Python 스크립트·TS 포팅·패리티 픽스처 3점을 한 PR에서 함께 고친다."
롤백(P3 실증): 클라이언트별 제거 →
claude mcp remove <name>·codex mcp remove <name>·agy mcp remove <name>· JSON 설정형(gemini·cursor·windsurf·claude-desktop·vscode)은 해당mcpServers/servers블록 삭제. 전역 설치는npm rm -g obsidian-llmwiki-mcp. 규칙 스니펫은~/.claude/skills/llmwiki-query/·~/.agents/skills/llmwiki-query/·~/.codex/AGENTS.md·~/.gemini/GEMINI.md·.cursor/rules/llmwiki.mdc에서 제거. 배포 철회는npm deprecate obsidian-llmwiki-mcp@<ver> "<사유>"(설치는 계속 가능하되 경고), 되돌릴 수 없는 삭제는 72시간 내npm unpublish뿐이므로 원칙적으로 deprecate + 다음 patch 로 대응. 볼트 하네스는 영향 없음(Python 경로 독립).
10. 열린 결정 (착수 전 확정)
| 항목 | 기본안 | 대안 |
|---|---|---|
npm 이름 — 확정 2026-09-09(P0-01): llmwiki-mcp | llmwiki-mcp(미등록 재확인 2026-09-09) | @cookyman/llmwiki-mcp 스코프 |
wiki_read_page 전문 상한 — 확정 2026-09-09(P0-04): 200KB 절단 | 200KB 절단 | 절 단위 페이징(후속) |
| Python 디렉터리 정렬 수정 — 확정 2026-09-09(P0-03): 포함 | 포함(정본 결정성 확보) | 픽스처를 단일 디렉터리로 제한해 회피 |
--once CLI 모드 — 확정 2026-09-09(P0-02): 포함 | 포함(패리티·디버그용) | Inspector로만 검증 |
| 구현 언어·정본(외부리뷰 #4) — 확정 2026-09-09: TS 포팅 | TS 포팅 + Python 정본 유지(구현 2벌, 패리티 CI). 근거: Codex CLI·Gemini CLI·Claude Code가 npm 패키지라 대상 머신에 Node가 보장되고 Python/uv는 보장되지 않음 → "사전 설치물 0개" 충족은 Node만 가능 | (a) FastMCP + uvx — 기각(Python 런타임 비보장) (b) TS 단일 정본 수렴 — 규칙 변경 빈도 높으면 v1.x 재검토 |
11. 외부리뷰 반영 기록 (agy, 2026-09-09)
| # | 심각도 | 판정 | 반영 위치 |
|---|---|---|---|
| 1 심볼릭 링크 순회 유출 | BLOCKER | 수용 | §5 |
2 structuredContent 비표준 | BLOCKER | 기각 — MCP 2025-06-18·TS SDK 표준(outputSchema 동반). 대신 outputSchema 선언 의무화 | §3 공통 |
| 3 CRLF universal newlines·NFC | BLOCKER | CRLF 수용 / NFC 기각(Python도 안 함 → 패리티 유지, 한계 기재) | §4 #2 |
| 4 uvx/FastMCP 대안·2벌 부채 | MAJOR | 사용자 결정으로 상신 — 기술적으로 타당한 대안. 문서의 선택은 사용자 스택 선호 기반 | §10 |
| 5 log 1 ULP → 점수 flaky | MAJOR | 수용 — rerank 점수 열 허용오차 | §4 #17, §7 |
| 6 입력 변형 내결함성 | MAJOR | 수용 | §3 공통 |
| 7 미매치 메시지 대소문자 | MAJOR | 수용 — 그대로 재현 | §4 #17b |
| 8 claims 펜스 비대칭 | MAJOR | 수용 — 수정 금지 명기 | §4 #18 |
| 9 코드포인트 정렬 | MINOR | 수용 | §4 #11 |
| 10 실 볼트 패리티 자동화 | MINOR | 수용 — --vault 모드 | §7 |
| 11 read_page 부재·alias | MINOR | 수용 | §3.4 |
| 12 파일 크기 상한·비동기 | MINOR | 비동기 수용 / 크기 상한 기각(패리티 파괴) | §6 |
12. 다중 클라이언트 재검토 (2026-09-09, 사용자 요구)
"Claude Code만이 아니라 Codex·Gemini(agy)·Cursor 등도 손쉽게 설치해 써야 한다"는 요구로 재검토. 변경 요지:
대상 클라이언트 8종을 PRD §1 표로 명시하고 그 표를 인수 매트릭스로 삼음(5종 필수).
서버를 자기서술로 설계 — 라우팅 규약을 instructions·description·
suggested_next3중으로 심어 클라이언트 규칙 파일 없이 동작. 규칙 스니펫은 선택(§8).스키마 부분집합 제한·도구명 규칙·description 길이 상한·stdout 순수성 등 호환 규칙 신설(§3 공통).
print-config서브커맨드(출력만)·--global대안·Windowscmd /c·Codexstartup_timeout_sec실측 반영(§3.5·§8).열린 결정 #4(언어)를 Node 확정으로 종결 — 근거는 클라이언트 런타임 보장(§10).
282 files
- .claude/agents/meeting-scribe.md
- .claude/agents/wiki-cartographer.md
- .claude/agents/wiki-consolidator.md
- .claude/agents/wiki-ingestor.md
- .claude/agents/wiki-linter.md
- .claude/agents/wiki-synthesizer.md
- .claude/settings.json
- .claude/skills/meeting-minutes/SKILL.md
- .claude/skills/meeting-minutes/references/auto-watch.md
- .claude/skills/meeting-minutes/references/backend-setup.md
- .claude/skills/meeting-minutes/scripts/apikey.py
- .claude/skills/meeting-minutes/scripts/pending-recordings.py
- .claude/skills/meeting-minutes/scripts/transcribe.py
- .claude/skills/weekly-review/SKILL.md
- .claude/skills/wiki-consolidate/SKILL.md
- .claude/skills/wiki-consolidate/scripts/confidence.py
- .claude/skills/wiki-consolidate/scripts/list-claims.py
- .claude/skills/wiki-ingest/SKILL.md
- .claude/skills/wiki-ingest/scripts/concept-index.py
- .claude/skills/wiki-ingest/scripts/normalize-stamps.py
- .claude/skills/wiki-lint/SKILL.md
- .claude/skills/wiki-lint/scripts/decay.py
- .claude/skills/wiki-lint/scripts/ingest-status.py
- .claude/skills/wiki-lint/scripts/link-audit.py
- .claude/skills/wiki-lint/scripts/lint-due.py
- .claude/skills/wiki-lint/scripts/scope-expand.py
- .claude/skills/wiki-lint/scripts/search.py
- .claude/skills/wiki-lint/scripts/stamp-updated.py
- .claude/skills/wiki-lint/scripts/validate-pages.py
- .claude/skills/wiki-lint/scripts/wiki-status-check.py
- .claude/skills/wiki-moc/SKILL.md
- .claude/skills/wiki-ops/SKILL.md
- .claude/skills/wiki-query/SKILL.md
- .gitattributes
- .github/workflows/ci.yml
- .gitignore
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CHANGELOG.md
- CLAUDE.md
- INTRO.md
- LICENSE
- README.md
- develop_docs/v0.8.3/AB-TEST.md
- develop_docs/v0.8.3/DESIGN.md
- develop_docs/v0.8.3/PRD.md
- develop_docs/v0.8.3/TECH-SUMMARY.md
- develop_docs/v0.8.3/ab-score.py
- develop_docs/v0.8.5/COMBO.md
- develop_docs/v0.8.6/DESIGN.md
- develop_docs/v0.8.6/PRD.md
- develop_docs/v0.8.6/RELEASE-NOTES-v0.11.0.md
- develop_docs/v0.8.6/todo/00-README.md
- develop_docs/v0.8.6/todo/P0-prepare.md
- develop_docs/v0.8.6/todo/P1-port-retrieval.md
- develop_docs/v0.8.6/todo/P2-mcp-server.md
- develop_docs/v0.8.6/todo/P3-release-clients.md
- develop_docs/v0.8.6/todo/P4-cache-followup.md
- develop_docs/v0.8.6/todo/baseline/.gitkeep
- develop_docs/v0.8.6/todo/evidence/.gitkeep
- develop_docs/v0.8.6/todo/review/.gitkeep
- develop_docs/v0.8.6/todo/review/P0-agy-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P0-prompt.txt
- develop_docs/v0.8.6/todo/review/P1-agy-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P1-codex-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P1-codex-r2-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P1-prompt.txt
- develop_docs/v0.8.6/todo/review/P2-agy-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P2-agy-r2-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P2-codex-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P2-codex-r2-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P2-codex-r3-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P2-prompt.txt
- develop_docs/v0.8.6/todo/review/P2-tools-list.json
- develop_docs/v0.8.6/todo/review/P3-codex-2026-09-09.md
- develop_docs/v0.8.6/todo/review/P3-prompt.txt
- develop_docs/v0.8.6/todo/review/P4-27-agy-2026-09-10.md
- develop_docs/v0.8.6/todo/review/P4-27-codex-2026-09-10.md
- develop_docs/v0.8.6/todo/review/P4-27-prompt.txt
- develop_docs/v0.8.6/todo/review/P4-agy-2026-09-10.md
- develop_docs/v0.8.6/todo/review/P4-agy-r3-2026-09-10.md
- develop_docs/v0.8.6/todo/review/P4-codex-2026-09-10.md
- develop_docs/v0.8.6/todo/review/P4-codex-r2-2026-09-10.md
- develop_docs/v0.8.6/todo/review/P4-codex-r3-2026-09-10.md
- develop_docs/v0.8.6/todo/review/P4-prompt-r2.txt
- develop_docs/v0.8.6/todo/review/P4-prompt-r3.txt
- develop_docs/v0.8.6/todo/review/P4-prompt.txt
- metrics/ab-results.csv
- metrics/cost-report.py
- raw/.gitkeep
- raw/article/.gitkeep
- raw/assets/.gitkeep
- raw/books/.gitkeep
- raw/lecture/.gitkeep
- raw/meetings/.gitkeep
- raw/notes/.gitkeep
- templates/clients/build.py
- templates/clients/claude-skill/SKILL.md
- templates/clients/codex-AGENTS.md
- templates/clients/cursor-llmwiki.mdc
- templates/clients/gemini-GEMINI.md
- templates/daily.md
- templates/mcp-client-guide.md
- templates/meeting.md
- templates/seeds/home-moc.md
- templates/seeds/index.md
- templates/seeds/log.md
- tests/parity.py
- tests/parity_fuzz.py
- tests/smoke.py
- tools/llmwiki-mcp/LICENSE
- tools/llmwiki-mcp/README.md
- tools/llmwiki-mcp/docs/install-and-usage.ko.md
- tools/llmwiki-mcp/eslint.config.js
- tools/llmwiki-mcp/package-lock.json
- tools/llmwiki-mcp/package.json
- tools/llmwiki-mcp/scripts/dump-tools-list.mjs
- tools/llmwiki-mcp/scripts/gen-pylower-table.py
- tools/llmwiki-mcp/scripts/readonly-guard.py
- tools/llmwiki-mcp/src/bm25.ts
- tools/llmwiki-mcp/src/cache.ts
- tools/llmwiki-mcp/src/cli.ts
- tools/llmwiki-mcp/src/contracts.ts
- tools/llmwiki-mcp/src/expand.ts
- tools/llmwiki-mcp/src/format.ts
- tools/llmwiki-mcp/src/graph.ts
- tools/llmwiki-mcp/src/once.ts
- tools/llmwiki-mcp/src/pack.ts
- tools/llmwiki-mcp/src/print-config.ts
- tools/llmwiki-mcp/src/pylower-table.ts
- tools/llmwiki-mcp/src/read.ts
- tools/llmwiki-mcp/src/root.ts
- tools/llmwiki-mcp/src/search.ts
- tools/llmwiki-mcp/src/server.ts
- tools/llmwiki-mcp/src/tools.ts
- tools/llmwiki-mcp/src/vault.ts
- tools/llmwiki-mcp/test/fixtures/.gitkeep
- tools/llmwiki-mcp/test/fixtures/expected/q01-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q01-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q01-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q01-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q02-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q02-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q02-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q02-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q03-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q03-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q03-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q03-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q04-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q04-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q04-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q04-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q05-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q05-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q05-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q05-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q06-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q06-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q06-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q06-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q07-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q07-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q07-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q07-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q08-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q08-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q08-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q08-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q09-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q09-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q09-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q09-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q10-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q10-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q10-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q10-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q11-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q11-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q11-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q11-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q12-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q12-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q12-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q12-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q13-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q13-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q13-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q13-search.txt
- tools/llmwiki-mcp/test/fixtures/expected/q14-expand.txt
- tools/llmwiki-mcp/test/fixtures/expected/q14-pack.txt
- tools/llmwiki-mcp/test/fixtures/expected/q14-rerank.txt
- tools/llmwiki-mcp/test/fixtures/expected/q14-search.txt
- tools/llmwiki-mcp/test/fixtures/gen-expected.py
- tools/llmwiki-mcp/test/fixtures/make-fixture.py
- tools/llmwiki-mcp/test/fixtures/queries.json
- tools/llmwiki-mcp/test/fixtures/vault/index.md
- tools/llmwiki-mcp/test/fixtures/vault/log.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L2-episodic/dup-note.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L2-episodic/query-search-briefing.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L2-episodic/session-2026-09-01.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L2-episodic/source-latency-review.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L2-episodic/source-northwind-kickoff.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-alias-target.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-chunking.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-emoji-notes.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-evaluation-harness.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-linker.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-prompt-caching-crlf.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-reranking.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-uppercase-term.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/concept-vector-index.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/dup-note.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/entity-northwind-search.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/entity-northwind-team.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/fact-latency-budget-old.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/fact-latency-budget.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/zz-🦀-crab.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L3-semantic/zz-₩-won.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L4-procedural/procedure-deploy-index.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/L4-procedural/procedure-no-type.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/moc/home-moc.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/moc/search-moc.md
- tools/llmwiki-mcp/test/fixtures/vault/wiki/moc/team-moc.md
- tools/llmwiki-mcp/test/perf/bench.py
- tools/llmwiki-mcp/test/perf/cache-bench.mjs
- tools/llmwiki-mcp/test/perf/make-synthetic-vault.py
- tools/llmwiki-mcp/test/perf/stage-bench.mjs
- tools/llmwiki-mcp/test/unit/golden.test.ts
- tools/llmwiki-mcp/test/unit/p1-01-walkmd-symlink.test.ts
- tools/llmwiki-mcp/test/unit/p1-09-pylower-unicode-version.test.ts
- tools/llmwiki-mcp/test/unit/p1-29-count-sub.test.ts
- tools/llmwiki-mcp/test/unit/p1-30-fmt1.test.ts
- tools/llmwiki-mcp/test/unit/p1-31-cmp-codepoint.test.ts
- tools/llmwiki-mcp/test/unit/p1-32-decode-text.test.ts
- tools/llmwiki-mcp/test/unit/p1-33-frontmatter.test.ts
- tools/llmwiki-mcp/test/unit/p1-34-parse-aliases.test.ts
- tools/llmwiki-mcp/test/unit/p1-35-link-re.test.ts
- tools/llmwiki-mcp/test/unit/p1-36-split-n.test.ts
- tools/llmwiki-mcp/test/unit/p1-37-extract-relations.test.ts
- tools/llmwiki-mcp/test/unit/p1-38-extract-claims.test.ts
- tools/llmwiki-mcp/test/unit/p1-39-cplen-bm25.test.ts
- tools/llmwiki-mcp/test/unit/p1-40-alias-first-wins.test.ts
- tools/llmwiki-mcp/test/unit/p1-41-dup-slug.test.ts
- tools/llmwiki-mcp/test/unit/p1-42b-pack-type-default.test.ts
- tools/llmwiki-mcp/test/unit/p1-rows-4-9-12-15-17b-21.test.ts
- tools/llmwiki-mcp/test/unit/p2-09-output-schema.test.ts
- tools/llmwiki-mcp/test/unit/p2-11-23-input-normalization-limits.test.ts
- tools/llmwiki-mcp/test/unit/p2-12-13-14-schema-names-descriptions.test.ts
- tools/llmwiki-mcp/test/unit/p2-15-27-03-cli.test.ts
- tools/llmwiki-mcp/test/unit/p2-21-symlink-leak.test.ts
- tools/llmwiki-mcp/test/unit/p2-22-path-escape.test.ts
- tools/llmwiki-mcp/test/unit/p2-26-print-config-snapshots.test.ts
- tools/llmwiki-mcp/test/unit/p2-33-once-vs-mcp.test.ts
- tools/llmwiki-mcp/test/unit/p2-helpers.ts
- tools/llmwiki-mcp/test/unit/p2-review-print-config.test.ts
- tools/llmwiki-mcp/test/unit/p2-review-server-vault-cli.test.ts
- tools/llmwiki-mcp/test/unit/p2-review-tools.test.ts
- tools/llmwiki-mcp/test/unit/p2-review2-root-limits-guards.test.ts
- tools/llmwiki-mcp/test/unit/p2-review3-envelope-budget.test.ts
- tools/llmwiki-mcp/test/unit/p2-review3-pack-input-budget.test.ts
- tools/llmwiki-mcp/test/unit/p2-review3-shq-single-quote.test.ts
- tools/llmwiki-mcp/test/unit/p2-review3-suggested-next-hint.test.ts
- tools/llmwiki-mcp/test/unit/p2-review4-field-envelope.test.ts
- tools/llmwiki-mcp/test/unit/p3-ajv-cross-check.test.ts
- tools/llmwiki-mcp/test/unit/p3-client-guide.test.ts
- tools/llmwiki-mcp/test/unit/p3-contracts.test.ts
- tools/llmwiki-mcp/test/unit/p4-12-lex-index.test.ts
- tools/llmwiki-mcp/test/unit/p4-27-default-mode-guards.test.ts
- tools/llmwiki-mcp/test/unit/p4-27-text-only-default.test.ts
- tools/llmwiki-mcp/test/unit/p4-cache-default.test.ts
- tools/llmwiki-mcp/test/unit/p4-cache.test.ts
- tools/llmwiki-mcp/test/unit/pkg-name.test.ts
- tools/llmwiki-mcp/test/unit/scaffold.test.ts
- tools/llmwiki-mcp/tsconfig.build.json
- tools/llmwiki-mcp/tsconfig.json
- wiki/.gitkeep
- wiki/L1-working/.gitkeep
- wiki/L2-episodic/.gitkeep
- wiki/L3-semantic/.gitkeep
- wiki/L4-procedural/.gitkeep
- wiki/moc/.gitkeep
Advantages
- Provides persistent, cumulative knowledge storage rather than re-discovering information on every query. evidence: README.md
- Implements a structured memory hierarchy with confidence scoring and decay management. evidence: CLAUDE.md
Limitations
- Requires manual curation of raw sources and adherence to specific frontmatter schemas. evidence: CLAUDE.md
- The system relies on specific agent-based workflows that require Claude Code to function as intended. evidence: README.md
Security
Risk level: Low risk
This brain runs
Hooks (2)
.claude/settings.json(SessionStart):python3 "$CLAUDE_PROJECT_DIR"/.claude/skills/wiki-lint/scripts/wiki-status-check.py.claude/settings.json(PostToolUse):python3 "$CLAUDE_PROJECT_DIR"/.claude/skills/wiki-lint/scripts/stamp-updated.py
Agent instructions that run or fetch something (22)
.claude/skills/meeting-minutes/SKILL.md:python3 .claude/skills/meeting-minutes/scripts/pending-recordings.py ..claude/skills/meeting-minutes/SKILL.md:`python3 .claude/skills/meeting-minutes/scripts/transcribe.py --check` 로 백엔드 가용성을 먼저 본다..claude/skills/meeting-minutes/SKILL.md:python3 $S/transcribe.py --backend local \.claude/skills/meeting-minutes/SKILL.md:python3 $S/transcribe.py --backend openai --confirm-upload \.claude/skills/meeting-minutes/SKILL.md:python3 .claude/skills/meeting-minutes/scripts/apikey.py status # 현재 출처 확인.claude/skills/meeting-minutes/SKILL.md:python3 .claude/skills/meeting-minutes/scripts/apikey.py set-keychain # 키체인에 저장.claude/skills/meeting-minutes/SKILL.md:python3 .claude/skills/meeting-minutes/scripts/apikey.py migrate # 레거시 파일 → 키체인.claude/skills/meeting-minutes/SKILL.md:| 증상 | 원인 | 대응 | |---|---|---| | `ffmpeg 없음` | 미설치 | `brew install ffmpeg` | | `로컬 전사 엔진이 없다` | mlx-whisper 미설치 | `python3 -m pip install mlx-whisper` | | openai 백엔드가 거부됨 | `--confirm-upload` 누락 | 판정을 다시 하라..claude/skills/weekly-review/SKILL.md:python3 .claude/skills/wiki-lint/scripts/scope-expand.py expand \.claude/skills/weekly-review/SKILL.md:python3 .claude/skills/wiki-lint/scripts/scope-expand.py pack $(cat /tmp/wr_cands.txt | cut -f3) > /tmp/wr_pack.md.claude/skills/wiki-consolidate/SKILL.md:`python3 .claude/skills/wiki-consolidate/scripts/list-claims.py .` — L2 전체의 `claim::` 라인 수집..claude/skills/wiki-consolidate/SKILL.md:`python3 .claude/skills/wiki-consolidate/scripts/list-claims.py .`로 L2 전체 claim 수집 + `python3 .claude/skills/wiki-ingest/scripts/concept-index.py .`로 기존 L3 카탈로그..claude/skills/wiki-consolidate/SKILL.md:승격·재확인 시 `python3 .claude/skills/wiki-consolidate/scripts/confidence.py --kinds <official,normal,verbal,…>` (또는 `--count N --official/--verbal`)로 점수를 구해 frontmatter `confidence:`에 기록..claude/skills/wiki-ingest/SKILL.md:python3 .claude/skills/wiki-ingest/scripts/concept-index.py ..claude/skills/wiki-lint/SKILL.md:python3 .claude/skills/wiki-lint/scripts/validate-pages.py . --json.claude/skills/wiki-lint/SKILL.md:python3 .claude/skills/wiki-lint/scripts/link-audit.py . --json.claude/skills/wiki-lint/SKILL.md:python3 .claude/skills/wiki-lint/scripts/decay.py --scan . --json.claude/skills/wiki-lint/SKILL.md:python3 .claude/skills/wiki-lint/scripts/search.py "<query>".claude/skills/wiki-ops/SKILL.md:python3 .claude/skills/wiki-lint/scripts/lint-due.py . 3.claude/skills/wiki-ops/SKILL.md:python3 .claude/skills/wiki-lint/scripts/ingest-status.py . # 미인제스트 raw 소스 (pending).claude/skills/wiki-ops/SKILL.md:리포트: `python3 metrics/cost-report.py` — 페이지당·소스100줄당 토큰, 낭비율, 총계.CLAUDE.md:미인제스트 raw 조회: `python3 .claude/skills/wiki-lint/scripts/ingest-status.py`.
- Low risk: network-instructions (.claude/skills/meeting-minutes/SKILL.md:130)
- Low risk: scripts-present (.claude/skills/meeting-minutes/scripts/apikey.py)
- Low risk: scripts-present (.claude/skills/meeting-minutes/scripts/pending-recordings.py)
- Low risk: scripts-present (.claude/skills/wiki-ingest/scripts/concept-index.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/decay.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/ingest-status.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/link-audit.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/lint-due.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/scope-expand.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/search.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/stamp-updated.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/validate-pages.py)
- Low risk: scripts-present (.claude/skills/wiki-lint/scripts/wiki-status-check.py)
Attribution and licence
- First committed by
cookyman74
- Publisher
- Justin (Community)
- Source
- cookyman74/llmwiki-harness · commit 139bc84
- Licence
- MIT License (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- cookyman74
AutoGineer is not affiliated with or endorsed by cookyman74.
Download
The ZIP holds the files AutoGineer serves, with ATTRIBUTION.md and the licence. Download llmwiki-harness.zip