Obsidian MCP + 하이브리드 검색: 2026 레퍼런스
# MCP를 통해 Obsidian을 Claude 및 다른 에이전트와 연결하세요. 서버 설정, 하이브리드 BM25 + 벡터 검색, 작동하는 설정 파일을 포함한 16,894개 파일 볼트 인덱싱을 다룹니다.
Obsidian은 단순한 노트 앱이 아닙니다. local-first 방식의 일반 텍스트, 그래프 구조 markdown corpus이며, 검색 인프라를 더하면 AI context 저장소가 됩니다. 파일 16,894개. chunk 49,746개. 23ms 쿼리. API 호출 0회. 83 MB SQLite 파일 1개. 이 가이드는 vault(Obsidian 보관소) 아키텍처부터 hybrid 검색, MCP 통합, 운영 워크플로까지 전체 시스템을 다룹니다.
핵심 요점
노트 작성이 아니라 컨텍스트 엔지니어링입니다. AI를 위한 Obsidian vault의 가치는 노트 자체가 아니라 노트를 쿼리할 수 있게 만드는 검색 계층에 있습니다. 검색 기능이 없는 16,000개 파일의 vault는 쓰기 전용 데이터베이스입니다. hybrid 검색과 MCP 통합을 갖춘 200개 파일의 vault는 AI 지식 베이스입니다. 검색 인프라가 곧 제품입니다. 노트는 원재료입니다.
Hybrid 검색은 순수 키워드 검색이나 순수 시맨틱 검색보다 뛰어납니다. BM25는 정확한 식별자와 함수 이름을 포착합니다. 벡터 검색은 서로 다른 용어 사이의 동의어와 개념적 일치를 포착합니다. Reciprocal Rank Fusion (RRF)은 점수 보정 없이 두 결과를 병합합니다. 어느 한 방법만으로는 두 가지 실패 모드를 모두 해결할 수 없습니다. MS MARCO passage ranking 연구도 이 패턴을 확인합니다. hybrid 검색은 각각의 방법을 단독으로 사용할 때보다 일관되게 더 뛰어난 성능을 보입니다.3 hybrid retriever 심층 분석에서는 RRF 수식, 실제 수치를 사용한 예제, 실패 모드 분석, 대화형 fusion 계산기를 다룹니다.
MCP를 사용하면 AI 도구가 vault에 직접 접근할 수 있습니다. Model Context Protocol (MCP) 서버는 retriever를 Claude Code, Codex CLI, Cursor 및 기타 AI 도구가 직접 호출할 수 있는 도구로 노출합니다. 에이전트는 vault를 쿼리하고, 출처 정보가 포함된 순위 결과를 받은 뒤 전체 파일을 불러오지 않고 컨텍스트를 활용합니다. MCP 서버는 검색 엔진을 얇게 감싼 래퍼입니다.
Local-first는 API 비용이 전혀 없고 완전한 프라이버시를 제공합니다. 전체 스택은 단일 머신에서 실행됩니다. 저장소에는 SQLite, embeddings에는 Model2Vec, 키워드 검색에는 FTS5, 벡터 KNN에는 sqlite-vec를 사용합니다. 클라우드 서비스도, API 호출도, 네트워크 의존성도 없습니다. 개인 노트는 절대 머신 밖으로 나가지 않습니다. 49,746개 chunk를 전체 재-embedding하는 비용은 OpenAI API 가격 기준으로 약 $0.30이지만, 진짜 비용은 오프라인에서도 작동해야 하는 시스템의 지연 시간, 프라이버시 노출, 네트워크 의존성입니다.4
증분 인덱싱으로 시스템을 10초 이내에 최신 상태로 유지합니다. 파일 수정 시간을 비교해 변경 사항을 감지합니다. 수정된 파일만 다시 chunking하고 다시 embedding합니다. Apple M-series 하드웨어에서 전체 재인덱싱에는 약 4분이 걸립니다. 일반적인 하루 편집에 대한 증분 업데이트는 10초 이내에 실행됩니다. 수동 개입 없이 시스템을 최신 상태로 유지합니다.
이 아키텍처는 200개부터 20,000개 이상의 노트까지 확장됩니다. 동일한 3계층 설계(수집, 검색, 통합)는 어떤 vault 규모에서도 작동합니다. 작은 vault에서는 BM25 전용 검색으로 시작하세요. 키워드 충돌이 문제가 되면 벡터 검색을 추가하세요. 정확한 일치와 시맨틱 일치가 모두 필요할 때 RRF fusion을 추가하세요. 각 계층은 독립적으로 유용하며 독립적으로 제거할 수도 있습니다.
이 가이드 사용 방법
이 가이드는 전체 시스템을 다룹니다. 시작점은 현재 상황에 따라 달라집니다.
| 현재 상황 | 여기서 시작 | 이어서 살펴볼 내용 |
|---|---|---|
| Obsidian + AI를 처음 사용함 | AI 인프라를 위한 Obsidian, Obsidian MCP 설정 | Vault 아키텍처, MCP 서버 아키텍처 |
| 기존 vault가 있고 AI 접근을 원함 | MCP 서버 아키텍처, Claude Code 통합 | Embedding 모델, Full-Text 검색 |
| 검색 시스템을 구축 중임 | 완전한 검색 파이프라인, Reciprocal Rank Fusion | 성능 튜닝, 문제 해결 |
| 팀 또는 엔터프라이즈 환경임 | 의사결정 프레임워크, 지식 그래프 패턴 | 개발자 워크플로 레시피, 마이그레이션 가이드 |
Contract로 표시된 섹션에는 구현 세부 사항, 설정 블록, 실패 모드가 포함됩니다. Narrative로 표시된 섹션은 개념, 아키텍처 결정, 설계 선택의 근거에 중점을 둡니다. Recipe로 표시된 섹션은 단계별 워크플로를 제공합니다.
AI 인프라를 위한 Obsidian을 선택하는 이유
이 가이드의 핵심 주장입니다. Obsidian vault는 local-first, plaintext, 그래프 구조를 갖추고 있으며 사용자가 스택의 모든 계층을 제어할 수 있으므로 개인 AI 지식 베이스에 가장 적합한 기반입니다.
Obsidian이 다른 대안과 달리 AI에 제공하는 것
Plaintext markdown 파일. 모든 노트는 파일 시스템에 있는 .md 파일입니다. 독점 포맷도, 데이터베이스 내보내기도, 콘텐츠를 읽기 위한 API도 필요하지 않습니다. 파일을 읽을 수 있는 모든 도구는 vault를 읽을 수 있습니다. grep, ripgrep, Python의 pathlib, SQLite FTS5는 모두 소스 파일에서 직접 작동합니다. 검색 시스템을 구축할 때 인덱싱하는 대상은 API 응답이 아니라 파일입니다. 소스가 파일 시스템이므로 인덱스는 항상 소스와 일관성을 유지합니다.
Local-first 아키텍처. vault는 사용자 머신에 존재합니다. 서버도, 클라우드 동기화 의존성도, API rate limit도, 자신의 콘텐츠 처리 방식을 제한하는 서비스 약관도 없습니다. 외부 서비스 없이 노트를 embedding, 인덱싱, chunking, 검색할 수 있습니다. 이는 검색 파이프라인이 API endpoint의 응답 속도가 아니라 디스크가 허용하는 속도로 실행된다는 점에서 AI 인프라에 중요합니다. 프라이버시 측면에서도 중요합니다. 자격 증명, 건강 데이터, 금융 정보, 개인적인 성찰이 담긴 개인 노트는 절대 머신 밖으로 나가지 않습니다.
wiki-link를 통한 그래프 구조. Obsidian의 [[wiki-link]] 문법은 노트 전체에 걸쳐 방향성 그래프를 생성합니다. OAuth 구현에 관한 노트는 token rotation, session management, API security에 관한 노트로 연결됩니다. 그래프 구조는 개념 간에 사람이 직접 선별한 관계를 인코딩합니다. 벡터 embeddings는 시맨틱 유사성을 포착하지만, wiki-link는 작성자가 주제를 생각하면서 만든 의도적인 연결을 포착합니다. 그래프는 embeddings가 복제할 수 없는 신호입니다.
플러그인 생태계. Obsidian에는 2,500개 이상의 커뮤니티 플러그인이 있습니다(플러그인 수는 2025년 중반의 1,800개 이상에서 증가해 2026년 3월에 2,500개를 넘어섰습니다). Dataview는 vault를 데이터베이스처럼 쿼리합니다. Templater는 JavaScript 로직으로 템플릿에서 노트를 생성합니다. Git 통합은 vault를 repository와 동기화합니다. Linter는 형식 일관성을 강제합니다. Bases core plugin(v1.9.10에서 도입됨)은 frontmatter 속성을 필드로 사용해 vault 파일 위에 테이블, 갤러리, 캘린더, kanban board 같은 데이터베이스형 뷰를 추가하며, .base 파일로 저장합니다.15 이 플러그인들은 기반 plaintext 형식을 바꾸지 않고 vault에 구조를 더합니다. 검색 시스템은 플러그인 자체가 아니라 플러그인의 결과물을 인덱싱합니다.
500만 명 이상의 사용자. Obsidian에는 템플릿, 워크플로, 플러그인, 문서를 만드는 대규모 활성 커뮤니티가 있습니다. vault 구성이나 플러그인 설정에서 문제가 발생하면 누군가가 해결책을 문서화했을 가능성이 높습니다. 커뮤니티는 MCP 서버, 인덱싱 스크립트, 퍼블리싱 파이프라인, API 래퍼 같은 Obsidian 인접 도구도 만듭니다.
파일 시스템만으로는 제공되지 않는 것
markdown 파일 디렉터리는 plaintext의 장점이 있지만 Obsidian이 추가하는 다음 3가지 요소가 없습니다.
-
양방향 링크. Obsidian은 backlink를 자동으로 추적합니다. Note A에서 Note B로 링크하면 Note B에는 Note A가 이를 참조한다는 정보가 표시됩니다. 그래프 패널은 연결 클러스터를 시각화합니다. 이러한 양방향 인식은 원시 파일 시스템이 제공하지 않는 메타데이터입니다.
-
플러그인 렌더링을 포함한 라이브 미리보기. Dataview 쿼리, Mermaid 다이어그램, callout 블록이 실시간으로 렌더링됩니다. 저장 형식은 plaintext로 유지하면서도 작성 경험은 텍스트 에디터보다 풍부합니다. 풍부한 환경에서 작성하고 구성하며, 검색 시스템은 원시 markdown을 인덱싱합니다.
-
커뮤니티 인프라. 플러그인 탐색, 테마 마켓플레이스, 동기화 서비스(선택 사항), 퍼블리시 서비스(선택 사항), 문서 생태계가 있습니다. 독립형 도구로 개별 기능은 무엇이든 복제할 수 있지만, Obsidian은 이를 일관된 워크플로로 패키징합니다.
Obsidian이 하지 않는 것과 직접 구축하는 것
Obsidian에는 검색 인프라가 포함되어 있지 않습니다. 기본 검색(full-text, 파일명, 태그)은 제공하지만 embedding 파이프라인, 벡터 검색, fusion ranking, MCP 서버, credential filtering, chunking 전략, 외부 AI 도구를 위한 통합 hook은 제공하지 않습니다. 이 가이드는 Obsidian 위에 구축하는 인프라를 다룹니다. vault는 기반입니다. 검색 파이프라인, MCP 서버, 통합 hook이 인프라입니다.
여기서 설명하는 아키텍처는 markdown-first이며 Obsidian 전용이 아닙니다. Logseq, Foam, Dendron 또는 일반 markdown 파일 디렉터리를 사용하더라도 검색 파이프라인은 동일하게 작동합니다. chunker는 .md 파일을 읽습니다. embedder는 텍스트 문자열을 처리합니다. indexer는 SQLite에 기록합니다. 이 구성 요소들은 어느 것도 Obsidian 전용 기능에 의존하지 않습니다. Obsidian의 기여는 retriever가 인덱싱하는 markdown 파일을 만들어 내는 작성 및 구성 환경입니다.
Obsidian MCP 설정
Model Context Protocol (MCP)은 Claude Code, Codex CLI, Cursor 및 기타 AI 도구가 Obsidian vault에 직접 접근할 수 있게 해주는 표준 인터페이스입니다. 이 섹션에서는 5분 안에 vault를 AI 도구에 연결합니다. Obsidian을 설치하고, vault를 만들고, MCP 서버를 설치한 뒤 첫 쿼리를 실행하게 됩니다. 빠른 시작에서는 즉시 결과를 확인할 수 있도록 커뮤니티 MCP 서버를 사용합니다. 이후 섹션에서는 프로덕션 환경용 맞춤 검색 파이프라인을 구축하는 방법을 다룹니다.
사전 준비 사항
- macOS, Linux 또는 Windows
- Node.js 18+ (MCP 서버용)
- Obsidian 1.12+ (CLI 통합용, 1.13.7은 현재 공개 데스크톱 릴리스입니다 – stable과 beta가 통합되었고, 1.13 라인은 2026년 7월 30일 Catalyst를 벗어났습니다. 이전 버전도 MCP 전용 설정에서는 사용할 수 있습니다)
- Claude Code, Codex CLI 또는 Cursor 설치
1단계: vault 만들기
obsidian.md에서 Obsidian을 다운로드하고 새 vault를 만드세요. 나중에 기억할 수 있는 위치를 선택하세요. MCP 서버에는 절대 경로가 필요합니다.
# Example vault location
~/Documents/knowledge-base/
검색기가 처리할 수 있도록 몇 개의 노트를 추가하세요. 10~20개의 노트만 있어도 결과를 확인하기에 충분합니다. 각 노트는 의미 있는 제목과 최소 한 문단의 내용을 담은 .md 파일이어야 합니다.
2단계: MCP 서버 설치하기
여러 커뮤니티 MCP 서버가 즉시 vault에 접근할 수 있도록 제공합니다. 생태계는 2025~2026년 동안 크게 성장했습니다. 주목할 만한 서버로는 MCPVault(npm @bitbonsai/mcpvault, 리포지토리 bitbonsai/mcpvault)가 있으며, 현재 v0.15.0입니다(npm 기준 2026년 8월 14일 검증). 이는 아래의 MarkusPfundstein/mcp-obsidian과는 별도 프로젝트이며, 이름이 바뀐 것이 아닙니다. v0.11.0(2026년 3월)에서는 frontmatter와 해시태그를 개수와 함께 검사하는 list_all_tags, 점 표기가 있는 폴더 처리 개선, .base/.canvas 지원을 추가했습니다. 2026년 7월 23일에 같은 날 배포된 세 개의 패치는 적용할 가치가 있습니다. v0.12.3은 wiki_link 도구를 추가하여 [[Document Name]], [[Name|Display]], 테이블에서 이스케이프된 [[Name\|Display]], #fragment 형식을 해석하고, 노트 내용과 해석된 경로 및 모호한 대안을 반환합니다. 이를 통해 에이전트는 다시 검색하는 대신 vault 자체의 링크 그래프를 따라갈 수 있습니다. 또한 기본 경로 필터를 통해 모든 도구에서 .trash/를 제외합니다. v0.12.4는 wiki_link를 [[folder/Note]] 같은 경로 지정 링크까지 확장했습니다. v0.12.2는 $ 치환 패턴이 포함된 삽입으로 patch_note가 손상되는 문제를 막고, 실수로 vault 접두사가 포함된 경로를 정규화합니다. 경로 필터의 제한된 디렉터리 차단 목록에 대해 중간 심각도의 권고 사항 2건(GHSA-9c83-rr99-vfwj 및 GHSA-j99q-93c9-h869)이 공개되었지만, 두 문제 모두 0.12 라인보다 훨씬 이전인 0.11.4 및 0.11.5에서 해결되었습니다. 따라서 모든 0.12.x 릴리스에는 이 문제가 없습니다.13
2026년 4월 변화 — 선호되는 브리지로서의 Obsidian CLI: Obsidian 1.12.0은 기본 CLI를 도입했으며, 공개 1.12.7 설치 프로그램(2026년 3월 23일)에는 독립 실행형 바이너리, TUI, 소켓 파일 개선 사항이 포함되어 터미널 워크플로를 더 쉽게 설치하고 실행할 수 있게 했습니다.16 1.13 라인은 2026년 7월 30일 1.13.4로 공개 채널에 도달했습니다. 이는 설정, 이미지, URI 보안 릴리스이며 1.12.x CLI 기능 범위를 넘어서는 새로운 AI 또는 자동화 기능은 없습니다(변경 사항은 changelog 행을 참조하세요).2526 커뮤니티 도구는 Local REST API 플러그인(
mcp-obsidian의 기반)을 사용하던 방식에서 더 빠르고 안정적인 CLI 기반 통합으로 활발히 전환하고 있습니다.MarkusPfundstein/mcp-obsidian리포지토리는 여전히 유지 관리되고 있으며, 2026년 5월까지의 커밋에서search_by_tag,get_frontmatter등의 도구가 추가되었습니다. 다만 태그된 릴리스는 제공하지 않으므로 고정된 커밋에서 설치하세요. 이 서버는 여전히 Local-REST-API 기반입니다. 새 설정에서는 CLI 브리지가 대체로 더 빠르고 안정적이므로, 이를 우선하거나 아래에 나열된 더 새로운 커뮤니티 대안을 사용하세요.20 권장 설정은 이 가이드 뒤쪽의 “AI 워크플로를 위한 Obsidian CLI” 섹션을 참조하세요.
| 서버 | 작성자 | 전송 방식 | 플러그인 필요 여부 | 주요 기능 |
|---|---|---|---|---|
obsidian-mcp (npm obsidian-mcp) |
StevenStavrakis | STDIO | 아니요 | 가볍고 파일 기반 |
| mcp-obsidian | MarkusPfundstein | STDIO | Local REST API | REST를 통한 전체 vault CRUD, search_by_tag/get_frontmatter 포함 — 활발히 유지 관리됨(2026년 5월까지 커밋), 태그된 릴리스 없음, 커밋 고정 필요20 |
| obsidian-mcp-tools | jacksteamdev | STDIO | 예(플러그인) | 시맨틱 검색 + Templater |
| obsidian-claude-code-mcp | iansinnott | WebSocket | 예(플러그인) | Claude Code용 자동 검색 |
obsidian-mcp-server (npm obsidian-mcp-server) |
cyanheads | STDIO | Local REST API | 태그, frontmatter 관리 — CLI 플래그가 아니라 OBSIDIAN_API_KEY/OBSIDIAN_BASE_URL로 설정 |
| Hybrid Search MCP | community | STDIO | 아니요 | BM25 + 시맨틱 검색 MCP 서버 + CLI. 커뮤니티 유지 관리 프로젝트이므로 도입 전에 최근 커밋을 확인하세요. |
빠른 시작에서는 .md 파일을 직접 읽는 파일 기반 서버가 가장 간단한 선택입니다. npm 이름 충돌에 유의하세요. 파일 기반 서버는 npm의 obsidian-mcp(StevenStavrakis)입니다. npm obsidian-mcp-server는 cyanheads의 REST-API 기반 서버이며 Local REST API 플러그인과 API 키가 필요합니다. 이 둘을 혼동하면 시작할 수 없는 서버를 설치하게 되는 경우가 많습니다.
npm install -g obsidian-mcp
3단계: AI 도구 설정하기
Claude Code — claude mcp add로 서버를 등록하세요(Claude Code은 사용자 범위의 경우 ~/.claude.json, 프로젝트 범위의 경우 .mcp.json에 MCP 서버를 저장합니다. mcpServers 블록을 조용히 무시하는 ~/.claude/settings.json에는 저장하지 않습니다).
# User scope (all your projects)
claude mcp add obsidian -s user -- npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/your/vault
# Or project scope, shared with the repo (writes .mcp.json)
claude mcp add obsidian -s project -- npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/your/vault
Codex CLI — ~/.codex/config.toml에 추가하세요.
[mcp_servers.obsidian]
command = "npx"
args = ["-y", "obsidian-mcp@2", "serve", "--vault", "notes=/absolute/path/to/your/vault"]
Cursor — .cursor/mcp.json에 추가하세요.
{
"mcpServers": {
"obsidian": {
"command": "npx",
"args": ["-y", "obsidian-mcp@2", "serve", "--vault", "notes=/absolute/path/to/your/vault"]
}
}
}
4단계: 첫 쿼리 실행하기
AI 도구를 열고 vault 노트가 답할 수 있는 질문을 해보세요.
Search my Obsidian vault for notes about [topic you wrote about]
AI 도구는 MCP 서버를 호출하고, 서버는 vault를 검색하여 일치하는 콘텐츠를 반환합니다. 파일 경로와 관련 발췌문이 포함된 결과가 표시되어야 합니다.
연결 후 Claude가 할 수 있는 일
정확한 도구 이름은 서버마다 다르지만, 핵심 기능 범위는 구현 전반에서 일관됩니다.
| 기능 | 일반적인 도구 | 에이전트가 이를 활용하는 방식 |
|---|---|---|
| vault 검색 | obsidian_search / search |
쿼리와 일치하는 노트를 찾고 파일 경로 및 출처 정보와 함께 순위가 매겨진 발췌문을 반환합니다 |
| 전체 노트 읽기 | obsidian_read_note / read_note |
검색 발췌문만으로 충분하지 않을 때 전체 노트 내용을 가져옵니다 |
| 목록 및 탐색 | obsidian_list_notes / list_notes |
특정 쿼리가 없을 때 폴더, 태그 또는 날짜 범위별로 노트를 탐색합니다 |
| 형식화된 컨텍스트 가져오기 | obsidian_get_context |
토큰 예산에 맞춘 주제별 컨텍스트 블록을 반환하며, 대화에 바로 주입할 수 있습니다 |
실제로는 Claude가 출처 정보와 함께 노트의 질문에 답하고, 이전 결정과 참고 자료를 코딩 세션으로 가져오며, 전체 파일을 컨텍스트에 로드하지 않고도 vault 구조를 탐색합니다. 일부 커뮤니티 서버는 쓰기 작업(생성, 추가, 태그 및 frontmatter 관리)도 제공합니다. 하지만 이 가이드 뒤에서 만드는 맞춤 서버는 의도적으로 읽기 전용이며, 노트 생성은 대신 hooks가 처리합니다.
자세히 알아보기: 도구 및 권한 설계는 MCP 서버 아키텍처, hooks와 브리지 패턴은 Claude Code 통합, 다른 에이전트는 Codex CLI 통합 및 Cursor와 기타 도구를 참조하세요.
방금 구축한 것
표준 프로토콜을 통해 로컬 knowledge base를 AI 도구에 연결했습니다. MCP 서버는 vault 파일을 읽고 기본 검색을 수행한 뒤 결과를 반환합니다. 이것이 최소 실행 가능 버전입니다.
이 빠른 시작에서 제공하지 않는 기능: - Hybrid retrieval(BM25 + vector search + RRF fusion) - Embedding 기반 시맨틱 검색 - Credential filtering - 증분 인덱싱 - Hook 기반 자동 컨텍스트 주입
이 가이드의 나머지 부분에서는 각 기능을 구축하는 방법을 다룹니다. 빠른 시작은 개념을 입증합니다. 전체 파이프라인은 프로덕션 수준의 검색 기능을 제공합니다.
AI 워크플로를 위한 Obsidian CLI
Obsidian 1.12(2026년 2월)에는 AI 워크플로를 위한 새로운 통합 접점을 제공하는 내장 명령줄 인터페이스가 도입되었으며, 1.13.7까지 최신 상태를 유지하고 있습니다(1.13 계열은 2026년 7월 30일 공개 채널에 도달했으며, 이후 새로운 CLI 기능은 추가되지 않았습니다).162526 CLI는 Obsidian GUI를 원격으로 제어하는 도구입니다. Obsidian이 실행 중이어야 하며, 첫 명령 시 자동으로 실행될 수도 있습니다. Settings > General > Command line interface에서 활성화하세요.
AI 인프라에서 CLI가 중요한 이유
CLI는 이전에는 GUI나 plugin API를 통해서만 가능했던 Obsidian 네이티브 작업에 프로그래밍 방식으로 접근할 수 있게 해줍니다. AI 워크플로에 중요한 기능은 다음과 같습니다.
- 스크립트와 hook에서 검색.
obsidian search "query"와obsidian search:context "query"를 사용하면 모든 셸 스크립트, hook 또는 자동화 파이프라인에서 vault를 검색할 수 있습니다.search:context변형은 주변 문맥과 함께 일치하는 줄을 반환하므로, 결과를 AI 프롬프트에 제공할 때 유용합니다. - 일일 노트 자동화.
obsidian daily는 오늘의 일일 노트를 열거나 생성합니다. 셸 스크립팅과 결합하면 자동화된 일일 브리핑 워크플로를 구현할 수 있습니다. hook이 AI 생성 요약을 일일 노트에 추가할 수 있습니다. - 템플릿 기반 노트 생성.
obsidian template list와obsidian template create는 Templater 또는 core template을 기반으로 노트를 생성하므로, AI agent가 markdown 파일을 직접 작성하지 않고도 구조화된 vault 항목을 만들 수 있습니다. - property 관리.
obsidian property set과obsidian property get은 frontmatter property를 읽고 쓰므로, 스크립트가 YAML를 파싱하지 않고도 metadata를 업데이트할 수 있습니다. - plugin 제어.
obsidian plugin enable/disable/list는 plugin을 프로그래밍 방식으로 관리하므로, 배치 작업 중 indexing plugin을 전환할 때 유용합니다. - task 관리.
obsidian task list/add/complete는 구조화된 task 접근을 제공하므로, vault에서 작업 항목을 관리하는 AI agent에 유용합니다.
AI 접근을 위한 CLI와 MCP 비교
CLI와 MCP server는 서로 다른 역할을 수행하며, 경쟁 관계가 아니라 상호 보완적입니다.
| 측면 | Obsidian CLI | MCP Server |
|---|---|---|
| 호출 주체 | 셸 스크립트, hook, cron job | AI agent(Claude Code, Codex, Cursor) |
| protocol | POSIX process(stdin/stdout/stderr) | MCP(JSON-RPC over STDIO or HTTP) |
| 강점 | Obsidian 네이티브 작업(template, plugin, property) | 맞춤형 retrieval(embeddings, BM25, RRF fusion) |
| 제한 사항 | vector search 및 embedding pipeline 없음 | Obsidian 내부 작업에 접근할 수 없음 |
| 적합한 용도 | 자동화 스크립트, intake pipeline, hook 작업 | 세션 중 실시간 AI agent query |
권장 사항: intake 자동화(노트 생성, property 관리, Obsidian 네이티브 검색 실행)에는 CLI를 사용하고, retrieval(embeddings를 활용한 hybrid search)에는 MCP를 사용하세요. UserPromptSubmit hook은 더 무거운 hybrid retrieval을 실행하기 전에 빠른 사전 확인으로 obsidian search:context를 호출할 수 있습니다(tool-scoped hook event는 주입할 수 없습니다. stdout이 model에 도달하지 않기 때문입니다).
예시: CLI 기반 intake hook
#!/bin/bash
# Hook: append today's signals to daily note via CLI
DATE=$(date +%Y-%m-%d)
SUMMARY="$1"
obsidian daily # ensure daily note exists
obsidian file append "Daily Notes/${DATE}.md" "## AI Summary\n${SUMMARY}"
Obsidian Agent Plugin
Obsidian plugin 중에는 AI coding agent를 vault UI에 직접 내장하여, 외부 MCP server 설정의 대안을 제공하는 범주가 점점 늘고 있습니다. 이러한 plugin은 외부 도구에서 연결하는 대신 Obsidian sidebar 안에서 AI agent를 실행합니다.
Claudian
Claudian은 Claude Code를 vault 내 AI collaborator로 내장합니다. vault directory는 Claude의 working directory가 되어 파일 읽기 및 쓰기, 검색, Bash command, multi-step workflow를 포함한 완전한 agentic 기능을 제공합니다.17
AI 인프라를 위한 주요 기능은 다음과 같습니다.
- 문맥 인식 프롬프트. 현재 포커스된 노트를 자동으로 첨부하고,
@notename파일 멘션, tag 기반 제외, editor 선택 영역을 문맥으로 지원합니다. - vision 지원. drag-and-drop, 붙여넣기 또는 파일 경로를 통해 이미지를 분석할 수 있으므로, vault에 저장된 screenshot과 diagram을 처리할 때 유용합니다.
- slash command.
/command로 실행되는 재사용 가능한 prompt template을 만들어 표준화된 vault 작업을 수행할 수 있습니다. - permission mode. safety blocklist와 vault confinement을 갖춘 YOLO(auto-approve), Safe(각 작업 승인), Plan(plan-only) mode를 제공합니다.
Agent Client
Agent Client는 Agent Client Protocol(ACP)을 통해 Claude Code, Codex CLI, Gemini CLI를 통합된 Obsidian sidebar로 가져옵니다.18
주요 기능은 다음과 같습니다.
- multi-agent 전환. 같은 panel에서 Claude Code, Codex 또는 Gemini CLI와 대화하고, 필요에 따라 agent를 전환할 수 있습니다.
- 노트 멘션.
@notename을 사용해 prompt에 노트 내용을 포함할 수 있으며, Claudian과 유사하지만 agent에 종속되지 않습니다. - 셸 실행. 대화에서 바로 terminal command를 실행할 수 있습니다. 대화를 벗어나지 않고 script, git command 또는 모든 terminal 작업을 수행할 수 있습니다.
- 작업 승인. 파일 읽기, 편집, command 실행을 세밀하게 제어할 수 있습니다.
agent plugin과 외부 MCP를 사용해야 할 때
| 시나리오 | Agent plugin | 외부 MCP |
|---|---|---|
| AI 지원을 받아 vault 노트 작성 및 편집 | 더 적합 — agent가 editor 문맥을 인식함 | 가능하지만 editor 인식 없음 |
| 여러 repo에 걸친 code 개발 | 제한적 — vault 범위로 한정됨 | 더 적합 — 전체 filesystem을 포함한 project 범위 |
| 대규모 indexed corpus에서 retrieval | 기본 검색만 가능 | 완전한 hybrid retrieval pipeline |
| 노트 작성 세션 중 빠른 vault Q&A | 이상적 — 문맥 전환 불필요 | terminal로 전환해야 함 |
권장 사항: vault 중심 워크플로(노트 작성, 정리, 요약)에는 agent plugin을 사용하세요. AI agent에 전체 retrieval pipeline과 vault 외부 codebase 접근이 필요한 개발 워크플로에는 외부 MCP server를 사용하세요. 두 접근 방식은 함께 사용할 수 있습니다. 노트 작업에는 Obsidian 내부에서 Claudian을 실행하고, 개발에는 외부에서 MCP와 함께 Claude Code를 실행하세요.
의사결정 프레임워크: Obsidian vs 대안
모든 사용 사례에 Obsidian이 필요한 것은 아니에요. 이 섹션에서는 언제 Obsidian이 적합한 기반인지, 언제 과한 선택인지, 언제 다른 도구가 더 잘 맞는지 정리해요.
의사결정 트리
START: What is your primary content type?
│
├─ Structured data (tables, records, schemas)
│ → Use a database. SQLite, PostgreSQL, or a spreadsheet.
│ → Obsidian is for prose, not tabular data.
│
├─ Ephemeral context (current project, temporary notes)
│ → Use CLAUDE.md / AGENTS.md in the project repo.
│ → These travel with the code and reset per project.
│
├─ Team wiki (shared documentation, onboarding)
│ → Evaluate Notion, Confluence, or a shared git repo.
│ → Obsidian vaults are personal-first. Team sync is possible
│ but not native.
│
└─ Growing personal knowledge corpus
│
├─ < 50 notes
│ → A folder of markdown files + grep is sufficient.
│ → Obsidian adds value mainly through the link graph,
│ which needs density to be useful.
│
├─ 50 - 500 notes
│ → Obsidian adds value. Wiki-links create a navigable graph.
│ → BM25-only search (FTS5) is sufficient at this scale.
│ → Skip vector search and RRF until keyword collisions appear.
│
├─ 500 - 5,000 notes
│ → Full hybrid retrieval becomes valuable. Keyword collisions
│ increase. Semantic search catches queries that BM25 misses.
│ → Add vector search + RRF fusion at this scale.
│
└─ 5,000+ notes
→ Full pipeline is essential. BM25-only returns too much noise.
→ Credential filtering becomes critical (more notes = more
accidentally pasted secrets).
→ Incremental indexing matters (full reindex takes minutes).
→ MCP integration pays dividends on every AI interaction.
비교 매트릭스
| 기준 | Obsidian | Notion | Apple Notes | 일반 파일시스템 | CLAUDE.md |
|---|---|---|---|---|---|
| Local-first | 예 | 아니요(클라우드) | 부분적(iCloud) | 예 | 예 |
| Plaintext | 예(markdown) | 아니요(블록) | 아니요(독점 형식) | 예 | 예 |
| Graph 구조 | 예(wiki-link) | 부분적(멘션) | 아니요 | 아니요 | 아니요 |
| AI 인덱싱 가능 | 직접 파일 접근 | API 필요 | 내보내기 필요 | 직접 파일 접근 | 이미 컨텍스트에 있음 |
| Plugin 생태계 | 2,500개 이상 plugins | 통합 기능 | 없음 | N/A | N/A |
| 오프라인 사용 가능 | 전체 가능 | 캐시된 읽기 전용 | 부분적 | 전체 가능 | 전체 가능 |
| 10K+ 노트까지 확장 | 예 | 예(API 사용 시) | 성능 저하 | 예 | 아니요(단일 파일) |
| 비용 | 무료(핵심 기능) | 월 $10 이상 | 무료 | 무료 | 무료 |
Obsidian이 과한 경우
- 단일 프로젝트 컨텍스트. AI가 현재 코드베이스에 대한 컨텍스트만 필요하다면
CLAUDE.md,AGENTS.md, 또는 프로젝트 수준 문서에 넣으세요. 이 파일들은 repo와 함께 이동하며 자동으로 로드돼요. - 구조화된 데이터. 콘텐츠가 표, 레코드, 스키마라면 데이터베이스를 사용하세요. Obsidian 노트는 prose 중심이에요. Dataview로 frontmatter 필드를 쿼리할 수는 있지만, 구조화된 쿼리는 실제 데이터베이스가 더 잘 처리해요.
- 임시 리서치. 프로젝트가 끝난 뒤 노트를 버릴 예정이라면 markdown 파일을 둔 임시 디렉터리가 더 단순해요. 일시적인 콘텐츠를 위해 retrieval 인프라를 만들지 마세요.
Obsidian이 적합한 경우
- 몇 달 또는 몇 년에 걸쳐 쌓이는 지식. 코퍼스가 커질수록 가치가 복리처럼 늘어나요. 6개월 동안 매일 쿼리하는 200개 노트 vault가 한 번만 쿼리하는 5,000개 노트 vault보다 더 큰 가치를 제공해요.
- 하나의 코퍼스에 여러 도메인이 있는 경우. 프로그래밍, 아키텍처, 보안, 디자인, 개인 프로젝트에 대한 노트가 들어 있는 vault는 프로젝트별
CLAUDE.md로는 제공할 수 없는 도메인 간 retrieval의 이점을 얻어요. - 프라이버시에 민감한 콘텐츠. Local-first는 retrieval 파이프라인이 콘텐츠를 외부 서비스로 보내지 않는다는 뜻이에요. vault에는 클라우드 서비스에 업로드하고 싶지 않은 콘텐츠를 포함해, 사용자가 넣는 모든 내용이 들어가요.
Mental Model: 3개 계층
이 시스템에는 독립적으로 작동하지만 결합되면 효과가 커지는 3개의 계층이 있어요. 각 계층은 다루는 관심사와 실패 모드가 달라요.
┌─────────────────────────────────────────────────────┐
│ INTEGRATION LAYER │
│ MCP servers, hooks, skills, context injection │
│ Concern: delivering context to AI tools │
│ Failure: wrong context, too much context, stale │
└──────────────────────┬──────────────────────────────┘
│ query + ranked results
┌──────────────────────┴──────────────────────────────┐
│ RETRIEVAL LAYER │
│ BM25, vector KNN, RRF fusion, token budget │
│ Concern: finding the right content for any query │
│ Failure: wrong ranking, missed results, slow queries │
└──────────────────────┬──────────────────────────────┘
│ chunked, embedded, indexed
┌──────────────────────┴──────────────────────────────┐
│ INTAKE LAYER │
│ Note creation, signal triage, vault organization │
│ Concern: what enters the vault and how it's stored │
│ Failure: noise, duplicates, missing structure │
└─────────────────────────────────────────────────────┘
Intake는 무엇이 vault에 들어오는지 결정해요. 큐레이션이 없으면 vault에는 노이즈가 쌓여요. 예를 들어 트윗 스크린샷, 주석 없이 복사해 붙여 넣은 글, 맥락 없는 미완성 생각 같은 것들이에요. Intake 계층은 항목이 들어오는 시점의 품질 관리를 담당해요. 점수화 파이프라인, 태깅 규칙, 수동 리뷰 프로세스처럼 vault에 retrieval할 가치가 있는 콘텐츠가 들어가도록 보장하는 모든 메커니즘이 여기에 해당해요.
Retrieval은 vault를 쿼리 가능하게 만들어요. 이 계층은 엔진이에요. 노트를 검색 단위로 chunking하고, chunk를 벡터 공간에 embeddings로 만들고, 키워드 검색과 의미 검색을 위해 인덱싱하고, RRF로 결과를 결합해요. Retrieval 계층은 파일 디렉터리를 쿼리 가능한 지식 베이스로 바꿔요. 이 계층이 없으면 vault는 수동 탐색과 기본 검색으로는 둘러볼 수 있지만, AI 도구가 프로그래밍 방식으로 접근할 수는 없어요.
Integration은 retrieval 계층을 AI 도구에 연결해요. MCP 서버는 retrieval을 호출 가능한 도구로 노출해요. Hooks는 컨텍스트를 자동으로 주입해요. Skills는 새로운 지식을 다시 vault에 캡처해요. Integration 계층은 지식 베이스와 이를 소비하는 AI agents 사이의 인터페이스예요.
계층들은 의도적으로 분리되어 있어요. Intake 점수화 파이프라인은 embeddings에 대해 아무것도 몰라요. Retriever는 신호 라우팅 규칙에 대해 아무것도 몰라요. MCP 서버는 노트가 어떻게 생성되었는지 아무것도 몰라요. 이렇게 분리되어 있기 때문에 어떤 계층이든 독립적으로 개선할 수 있어요. Intake 파이프라인을 바꾸지 않고 embedding 모델을 교체할 수 있어요. Retriever를 수정하지 않고 새로운 MCP 기능을 추가할 수 있어요. 인덱스를 건드리지 않고 신호 점수화 휴리스틱을 바꿀 수 있어요.
AI 활용에 맞춘 볼트 아키텍처
AI 검색에 최적화된 볼트는 개인 브라우징에 최적화된 볼트와 다른 규칙을 따릅니다. 이 섹션에서는 폴더 구조, 노트 스키마, frontmatter 규칙, 검색 품질을 높이는 구체적인 패턴을 다룹니다.
폴더 구조
최상위 폴더에는 번호 접두사를 사용해 예측 가능한 구성 계층을 만드세요. 번호는 우선순위를 뜻하지 않습니다. 관련 영역을 묶고 구조를 훑어보기 쉽게 만드는 역할을 합니다.
vault/
├── 00-inbox/ # Unsorted captures, pending triage
├── 01-projects/ # Active project notes
├── 02-areas/ # Ongoing areas of responsibility
├── 03-resources/ # Reference material by topic
│ ├── programming/
│ ├── security/
│ ├── ai-engineering/
│ ├── design/
│ └── devops/
├── 04-archive/ # Completed projects, old references
├── 05-signals/ # Scored signal intake
│ ├── ai-tooling/
│ ├── security/
│ ├── systems/
│ └── ...12 domain folders
├── 06-daily/ # Daily notes (if used)
├── 07-templates/ # Note templates (excluded from index)
├── 08-attachments/ # Images, PDFs (excluded from index)
├── .obsidian/ # Obsidian config (excluded from index)
└── .indexignore # Paths to exclude from retrieval index
인덱싱해야 하는 폴더: 프로젝트, 영역, 리소스, 신호, 일일 노트처럼 markdown 산문이 들어 있는 모든 폴더입니다.
인덱싱에서 제외해야 하는 폴더: 템플릿(콘텐츠가 아니라 placeholder 변수가 들어 있음), 첨부 파일(binary 파일), Obsidian 설정, 그리고 검색 인덱스에 넣고 싶지 않은 민감한 콘텐츠가 들어 있는 모든 폴더입니다.
.indexignore 파일
볼트 루트에 .indexignore 파일을 만들어 검색 인덱스에서 제외할 경로를 명시하세요. 문법은 .gitignore와 같습니다.
# Obsidian internal
.obsidian/
# Templates contain placeholders, not content
07-templates/
# Binary attachments
08-attachments/
# Personal health/medical notes
02-areas/health/
# Financial records
02-areas/finance/personal/
# Career documents (resumes, salary data)
02-areas/career/private/
인덱서는 스캔하기 전에 이 파일을 읽고, 일치하는 경로는 완전히 건너뜁니다. 제외된 경로의 파일은 chunking되지 않고, embeddings도 생성되지 않으며, 검색 결과에도 나타나지 않습니다.
노트 스키마
모든 노트에는 YAML frontmatter가 있어야 합니다. retriever는 필터링과 컨텍스트 보강에 frontmatter 필드를 사용합니다.
---
title: "OAuth Token Rotation Patterns"
type: note # note | signal | project | moc | daily
domain: security # primary domain for routing
tags:
- authentication
- oauth
- token-management
created: 2026-01-15
updated: 2026-02-28
source: "" # URL if captured from external source
status: active # active | archived | draft
---
검색에 필요한 필드:
title— 검색 결과 표시와 BM25용 제목 컨텍스트에 사용됩니다type— 유형별 필터링 쿼리를 가능하게 합니다(“MOC만 보여줘” 또는 “signals만”)tags— FTS5 제목 컨텍스트에 0.3 가중치로 인덱싱되어, 본문에서 다른 용어를 쓰더라도 키워드 매칭을 제공합니다
선택 사항이지만 유용한 필드:
domain— 도메인 범위 쿼리를 가능하게 합니다(“security 노트만 검색”)source— 캡처한 콘텐츠의 출처입니다. retriever가 결과에 소스 URL을 포함할 수 있습니다status— 보관되었거나 초안 상태인 노트를 활성 검색에서 제외할 수 있습니다
Chunking 규칙
retriever는 H2(##) 제목 경계에서 chunking합니다. 즉, 노트 구조가 검색 단위의 세밀함에 직접 영향을 줍니다.
검색에 좋은 구조:
## Token Rotation Strategy
The rotation interval depends on the threat model...
## Implementation with refresh_token
The OAuth 2.0 refresh token flow requires...
## Error Handling: Expired Tokens
When a token expires mid-request...
3개의 H2 섹션은 독립적으로 검색 가능한 3개의 chunk를 만듭니다. 각 chunk는 embeddings가 의미를 포착하기에 충분한 컨텍스트를 갖습니다. “expired token handling”에 대한 쿼리는 특히 세 번째 chunk와 매칭됩니다.
검색에 좋지 않은 구조:
# OAuth Notes
Token rotation depends on threat model. The OAuth 2.0 refresh
token flow requires storing the refresh token securely. When a
token expires mid-request, the client should retry after refresh.
The rotation interval is typically 15-30 minutes for access tokens
and 7-30 days for refresh tokens...
H2 제목이 없는 긴 섹션 하나는 큰 chunk 하나를 만듭니다. embeddings는 섹션 안의 모든 주제를 평균화합니다. 어떤 하위 주제에 대한 쿼리든 전체 노트와 비슷하게 매칭됩니다.
경험칙: 한 섹션이 하나보다 많은 개념을 다룬다면 H2 하위 섹션으로 나누세요. 나머지는 chunker가 처리합니다.
노트에 넣지 말아야 할 것
검색 품질을 떨어뜨리는 콘텐츠는 다음과 같습니다.
- 주석 없이 전체 글을 그대로 복사해 붙여 넣은 원문. retriever는 원문 글의 키워드를 인덱싱하기 때문에, 직접 작성하지 않은 콘텐츠로 볼트가 희석됩니다. 대신 요약을 추가하거나, 핵심 포인트를 추출하거나, 소스 URL로 링크하세요.
- 텍스트 설명이 없는 스크린샷. retriever는 markdown 텍스트를 인덱싱합니다. alt text나 주변 설명이 없는 이미지는 BM25와 vector search 모두에서 보이지 않습니다.
- 자격 증명 문자열. API 키, 토큰, 비밀번호, 연결 문자열입니다. credential filtering을 사용하더라도 가장 안전한 방법은 노트에 secrets를 절대 붙여 넣지 않는 것입니다. 대신 이름으로 참조하세요(예: “
~/.env에 있는 Cloudflare API token”). - 큐레이션되지 않은 자동 생성 콘텐츠. 도구가 노트를 생성했다면(회의 transcript, Readwise highlights, RSS import), 영구 볼트에 들어가기 전에 검토하고 주석을 추가하세요. 큐레이션되지 않은 자동 import는 검색 가능한 가치를 더하지 않고 양만 늘립니다.
AI Workflow를 위한 Plugin Ecosystem
AI 검색 품질을 높이는 Obsidian plugins는 세 가지 범주로 나눌 수 있습니다. 구조화(일관성 강제), 쿼리(메타데이터 노출), 동기화(볼트를 최신 상태로 유지)입니다.
필수 Plugins
Dataview. frontmatter 필드를 사용해 볼트를 데이터베이스처럼 쿼리합니다. “최근 30일 동안 업데이트된 security 태그가 있는 모든 노트”나 “상태가 active인 모든 프로젝트 노트” 같은 동적 인덱스를 만들 수 있습니다. Dataview가 검색에 직접 도움이 되지는 않지만, 볼트의 커버리지 공백을 파악하고 업데이트가 필요한 노트를 찾는 데 도움이 됩니다.
TABLE type, domain, updated
FROM "03-resources"
WHERE status = "active"
SORT updated DESC
LIMIT 20
Templater. 동적 필드가 있는 템플릿으로 노트를 만듭니다. created, type, domain 필드를 미리 채우는 템플릿을 사용하면 모든 새 노트가 올바른 frontmatter로 시작하도록 할 수 있습니다. 일관된 frontmatter는 검색 필터링을 개선합니다.
<%* /* New Resource Note Template */ %>
---
title: "<% tp.file.cursor() %>"
type: note
domain: <% tp.system.suggester(["programming", "security", "ai-engineering", "design", "devops"], ["programming", "security", "ai-engineering", "design", "devops"]) %>
tags: []
created: <% tp.date.now("YYYY-MM-DD") %>
updated: <% tp.date.now("YYYY-MM-DD") %>
source: ""
status: active
---
## Key Points
## Details
## References
Linter. 볼트 전체에 포맷 규칙을 적용합니다. 일관된 제목 계층 구조(제목은 H1, 섹션은 H2, 하위 섹션은 H3)는 chunker가 예측 가능한 결과를 만들도록 합니다. 검색에 중요한 Linter 규칙은 다음과 같습니다.
- 제목 증가: 순차적인 제목 수준을 강제합니다(H1에서 H3로 건너뛰지 않음)
- YAML 제목: 파일 이름과 일치시킵니다
- 후행 공백: 제거합니다(FTS5 토큰화 아티팩트를 방지)
- 연속 빈 줄: 1개로 제한합니다(더 깔끔한 chunks)
Git integration. 볼트를 위한 버전 관리입니다. 시간에 따른 변경 사항을 추적하고, 여러 머신 간에 동기화하며, 실수로 삭제한 내용을 복구할 수 있습니다. Git은 indexer가 증분 변경 감지에 사용하는 mtime 데이터도 제공합니다.
Indexing에 도움이 되는 Plugins
Smart Connections. Obsidian 자체에서 AI 기반 의미 검색을 제공하는 Obsidian plugin입니다. Smart Connections v4는 기본적으로 로컬 embeddings를 생성합니다. 볼트가 인덱싱되고 나면 의미 연결과 조회가 API 호출 없이 완전히 오프라인으로 작동합니다.11 v4.5.0(2026년 5월 5일)에서는 footer connections가 Smart Connections Core의 일부가 되어, 모든 설치 환경에서 사이드 패널을 열지 않고도 footer에 관련 노트 연결을 표시할 수 있습니다. 최근 v4 릴리스에는 connection lists용 graph views, 설정 가능한 dock locations, 중단된 indexing 실행 이후의 개선된 block-embedding 복구, 그리고 Smart Connections, Smart Chat, Smart Composer가 상태를 공유할 수 있게 하는 cross-plugin 환경인 “Substrate”도 추가되었습니다.21 이 가이드의 검색 시스템은 Obsidian 외부에서 실행되지만(Python pipeline으로 실행), Smart Connections는 글을 쓰는 동안 의미 관계를 탐색하는 데 유용합니다. 두 시스템은 같은 콘텐츠를 인덱싱하지만 서로 다른 용도를 제공합니다. Smart Connections는 에디터 안에서 발견을 돕고, 외부 retriever는 MCP를 통한 AI tool 통합을 담당합니다.
2026년 4월에 출시된 AI-native plugins. 새로운 커뮤니티 plugins의 흐름은 Claude Code / Codex / Gemini-CLI workflow를 직접 겨냥합니다.
| Plugin | 출시 | 기능 |
|---|---|---|
| Cortex | 4월 4일 | Claude Code 기반 볼트 agent입니다. 볼트를 단순한 노트 저장소가 아니라 agent workspace로 다룹니다 |
| VaultSearch | 4월 7일 | Local-first hybrid search: BM25 + semantic + fuzzy(이 가이드의 검색 스택과 직접 겹칩니다) |
| LLM Wiki | 4월 9일 | 볼트를 비공개로 쿼리할 수 있는 지식 베이스로 바꿉니다 |
| Drift | 4월 11일 | AI 기반 Obsidian 편집을 위한 VS Code 스타일 diff viewer입니다. Claude Code workflows에 맞춰져 있습니다 |
| EngramQuest | 4월 11일 | 노트에서 기억력 챌린지를 생성합니다. Claude Code / Gemini CLI / Cursor용 “AI Skills”를 제공합니다 |
| Hybrid Search MCP | 3월(여전히 신규) | BM25 + semantic search를 갖춘 MCP server + CLI입니다. AI assistants를 위해 설계되었습니다 |
이를 새롭게 떠오르는 영역으로 보세요. 이 중 몇 가지는 앞으로 몇 분기 안에 Smart Connections나 Obsidian core로 통합되거나 흡수될 가능성이 큽니다. 지금 하나를 고른다면 VaultSearch와 Hybrid Search MCP가 이 가이드의 외부 retriever와 철학적으로 가장 가깝습니다.
Dataview 참고: 오래된 Obsidian query plugin인 Dataview는 2025년 4월에 0.5.70을 마지막으로 릴리스했으며, 이후 사실상 정체된 상태입니다. 새 작업에는 Obsidian의 내장 Bases 기능(1.9+)이 암묵적인 후속 기능이자 권장 경로입니다.
Metadata Menu. 필드 값 자동 완성을 포함한 구조화된 frontmatter 편집을 제공합니다. type, domain, tags 필드의 오타를 줄입니다. 일관된 메타데이터는 검색 필터링 정확도를 높입니다.
Indexing에 해로운 Plugins
Excalidraw. 그림을 markdown 파일에 포함된 JSON로 저장합니다. JSON는 문법적으로 유효한 markdown이지만, chunking 및 embedding 시 불필요한 결과를 만듭니다. .indexignore를 통해 Excalidraw 파일을 인덱스에서 제외하거나 파일 확장자로 필터링하세요.
Kanban. 보드 상태를 특수한 형식의 markdown으로 저장합니다. 이 형식은 Kanban 렌더링을 위해 설계된 것이지, prose 검색을 위한 것이 아닙니다. chunker는 카드 제목과 메타데이터 조각을 만들지만, 이는 embedding 품질이 좋지 않습니다. Kanban 보드는 인덱스에서 제외하세요.
Calendar. 최소한의 콘텐츠만 있는 일일 노트를 만듭니다(대개 날짜 제목만 있음). 비어 있거나 거의 비어 있는 노트는 품질이 낮은 chunks를 만듭니다. 일일 노트를 사용한다면 그 안에 실질적인 내용을 작성하거나, 일일 노트 폴더를 인덱스에서 제외하세요.
중요한 Plugin 설정
File recovery → Enabled. 실수로 노트를 삭제하는 상황을 방지합니다. 검색과 직접 관련되지는 않지만, 의존하는 지식 베이스에는 중요합니다.
Strict line breaks → Disabled. Markdown 표준 줄바꿈(문단 구분에는 이중 줄바꿈)이 Obsidian의 strict mode(<br>에 단일 줄바꿈 사용)보다 더 깔끔한 chunks를 만듭니다.
Default new file location → Designated folder. 새 파일을 00-inbox/로 보내면 분류되지 않은 노트가 domain folders를 오염시키지 않습니다. inbox는 임시 준비 영역이며, 파일은 triage 후 domain folders로 이동합니다.
Wiki-link format → Shortest path when possible. 더 짧은 link targets는 link structure를 인덱싱할 때 retriever가 더 쉽게 해석할 수 있습니다.
Embedding Models: 선택과 설정
Embedding model은 텍스트 chunks를 semantic search에 사용할 숫자 vectors로 변환합니다. 어떤 model을 선택하느냐에 따라 retrieval 품질, index 크기, embedding 속도, runtime dependencies가 달라집니다. 이 섹션에서는 Model2Vec의 potion-base-8M을 기본 선택으로 쓰는 이유와 alternatives를 선택해야 하는 경우를 설명합니다.
Model2Vec potion-base-8M을 선택하는 이유
Model: minishlab/potion-base-8M
Parameters: 7.6 million
Dimensions: 256
Size: ~30 MB
Dependencies: model2vec (numpy only, no PyTorch)
Inference: CPU-only, static word embeddings (no attention layers)
Model2Vec은 sentence transformer의 지식을 static token embeddings로 distill합니다. BERT, MiniLM, 기타 transformer models처럼 입력에 attention layers를 실행하는 대신, Model2Vec은 미리 계산된 token embeddings의 가중 평균으로 vectors를 생성합니다.5 실제 효과는 분명합니다. sequential computation이 없기 때문에 embedding 속도가 transformer 기반 models보다 50-500배 빠릅니다.
현재 Model2Vec results page에서 potion-base-8M은 all-MiniLM-L6-v2의 all-task score 대비 약 92%에 도달합니다(51.32 vs 55.80). 그러면서도 속도는 몇 자릿수 더 빠르게 유지합니다.6 남는 품질 격차는 속도와 단순성의 이점을 얻기 위한 trade-off입니다. 짧은 markdown chunks(일반적인 vault에서 평균 200-400단어)에서는 긴 문서보다 품질 차이가 덜 두드러집니다. 짧고 초점이 명확한 텍스트에서는 두 models 모두 비슷한 representations로 수렴하기 때문입니다.
설정
# embedder.py
DEFAULT_MODEL = "minishlab/potion-base-8M"
EMBEDDING_DIM = 256
class Model2VecEmbedder:
def __init__(self, model_name=DEFAULT_MODEL):
self._model_name = model_name
self._model = None
def _ensure_model(self):
if self._model is not None:
return
_activate_venv() # Add isolated venv to sys.path
from model2vec import StaticModel
self._model = StaticModel.from_pretrained(self._model_name)
def embed_batch(self, texts):
self._ensure_model()
vecs = self._model.encode(texts)
return [v.tolist() for v in vecs]
Lazy loading. model은 import 시점이 아니라 처음 사용할 때 로드됩니다. retriever가 BM25-only fallback mode로 동작할 때(예: embedding venv가 설치되지 않은 경우) embedder module을 import해도 비용이 들지 않습니다.
분리된 virtual environment. model은 전용 venv(예: ~/.claude/venvs/memory/)에서 실행되어 나머지 toolchain과의 dependency conflicts를 피합니다. _activate_venv() function은 runtime에 venv의 site-packages를 sys.path에 추가합니다.
# Create isolated venv
python3 -m venv ~/.claude/venvs/memory
~/.claude/venvs/memory/bin/pip install model2vec
Batch processing. embedder는 Model2Vec의 overhead를 amortize하기 위해 texts를 64개씩 batch로 처리합니다. indexer는 chunk를 하나씩 embedding하지 않고 embed_batch()에 chunks를 전달합니다.
Alternatives를 선택해야 하는 경우
| Model | Dim | Size | Speed | Quality (MTEB) | Best for |
|---|---|---|---|---|---|
| potion-base-8M | 256 | 30 MB | 500x | 51.32 | 기본값: local, fast, no GPU |
| potion-base-32M | 256 | 120 MB | 400x | 52.83 | 더 높은 품질, 여전히 static |
| potion-retrieval-32M | 256 | 120 MB | 400x | 35.06 (retrieval) | Retrieval에 최적화된 static |
| potion-multilingual-128M | 256 | ~500 MB | 300x | — | Multilingual vaults (101 languages) |
| all-MiniLM-L6-v2 | 384 | 80 MB | 1x | 55.80 | 더 높은 품질, 여전히 local |
| nomic-embed-text-v1.5 | 768 | 270 MB | 0.5x | 62.28 | 최고의 local 품질 |
| text-embedding-3-small | 1536 | API | N/A | 62.30 | API 기반, 최고 품질 |
potion-base-32M을 선택하세요 static embedding 계열을 벗어나지 않으면서 potion-base-8M보다 더 나은 품질을 원할 때 적합합니다. baai/bge-base-en-v1.5에서 distill한 더 큰 vocabulary를 사용해 52.83 all-task score를 달성합니다(potion-base-8M보다 약 3% 높음). 동시에 동일한 256-dimensional output과 numpy-only dependency를 유지합니다.8 model file이 4배 커져 memory usage는 늘어나지만, embedding 속도는 여전히 transformer models보다 몇 자릿수 빠릅니다.
potion-retrieval-32M을 선택하세요 주요 use case가 retrieval일 때 적합합니다(vault search가 여기에 해당합니다). 이 variant는 retrieval tasks를 위해 potion-base-32M에서 특별히 fine-tuned되었으며, Model2Vec의 retrieval benchmark table에서 35.06점을 기록합니다. potion-base-32M은 32.67점입니다.8 trade-off는 general-purpose embedding quality가 아니라 retrieval에 최적화되어 있다는 점입니다.
potion-multilingual-128M을 선택하세요 vault에 여러 언어의 notes가 포함되어 있을 때 적합합니다. 2025년 5월에 released된 이 101-language model은 multilingual tasks에서 가장 성능이 좋은 static embedding model이며, 다른 potion models와 동일한 numpy-only dependency를 유지하면서 모든 언어의 텍스트에 대해 embeddings를 생성합니다.12 더 큰 model file(~500 MB)은 cross-lingual capability를 얻기 위한 trade-off입니다. 영어 content와 함께 일본어, 중국어, 독일어 또는 기타 비영어 notes가 있을 때 사용하세요.
all-MiniLM-L6-v2를 선택하세요 속도보다 retrieval 품질이 더 중요하고 PyTorch가 설치되어 있을 때 적합합니다. 384-dimensional vectors는 256-dim vectors와 비교해 SQLite database size를 약 50% 늘립니다. M-series hardware에서 15,000 files 전체를 reindex할 때 embedding 속도는 1분 미만에서 약 10분으로 느려집니다.
nomic-embed-text-v1.5를 선택하세요 가능한 최고의 local retrieval 품질이 필요하고 느린 indexing을 감수할 수 있을 때 적합합니다. 768-dimensional vectors는 database size를 대략 3배로 늘립니다. PyTorch와 최신 CPU 또는 GPU가 필요합니다.
text-embedding-3-small을 선택하세요 network latency와 privacy를 trade-offs로 받아들일 수 있을 때 적합합니다. API는 가장 높은 품질의 embeddings를 생성하지만, cloud dependency와 per-token cost($0.02/million tokens)가 생기며 content가 OpenAI의 servers로 전송됩니다.
그 외의 모든 경우에는 potion-base-8M을 유지하세요. 속도 이점은 iterative indexing(개발 중 reindex)에 중요하고, numpy-only dependency는 PyTorch 설치 복잡성을 피하게 해주며, 256-dimensional vectors는 database를 compact하게 유지합니다.
Quantization 및 Dimensionality Reduction
Model2Vec v0.5.0+는 reduced precision과 dimensions로 models를 로드하는 기능을 지원합니다.8 이는 제한된 hardware에 deployment하거나 models를 바꾸지 않고 database size를 줄일 때 유용합니다:
from model2vec import StaticModel
# Load with int8 quantization (25% of original size)
model = StaticModel.from_pretrained("minishlab/potion-base-8M", quantize=True)
# Load with reduced dimensions (e.g., 128 instead of 256)
model = StaticModel.from_pretrained("minishlab/potion-base-8M", dimensionality=128)
Quantized models는 memory footprint를 크게 줄이면서도 거의 동일한 retrieval 품질을 유지합니다. Dimensionality reduction은 Matryoshka-style truncation을 따릅니다. 즉, 처음 N dimensions가 가장 많은 정보를 담습니다. 256에서 128 dimensions로 줄이면 short-text retrieval에서 품질 손실을 최소화하면서 vector storage를 절반으로 줄일 수 있습니다.
Model2Vec v0.8.x는 tokenizer/persistence internals를 업데이트하고, Python 3.9 support를 deprecate하며, published results를 더 최신 MTEB tables로 refresh합니다. production indexer를 upgrade하기 전에는 model2vec을 pin하거나 test하세요. embedding model name이 그대로여도 library upgrade로 model-loading paths가 바뀔 수 있기 때문입니다.10
Vault별 Embeddings를 위한 Fine-Tuning
Model2Vec v0.4.0+는 static embeddings 위에서 custom classification models를 training하는 기능을 지원하고, v0.7.0은 vocabulary quantization과 distillation을 위한 configurable pooling을 추가하며, v0.8.x는 tokenizer와 persistence behavior를 refactor합니다.10 이는 default potion models가 semantic nuances를 충분히 포착하지 못할 수 있는 specialized vocabulary(의료 notes, 법률 references, domain-specific jargon)가 있는 vaults에 관련됩니다:
from model2vec import StaticModel
from model2vec.train import train_model
# Fine-tune on vault-specific data
model = StaticModel.from_pretrained("minishlab/potion-base-8M")
trained_model = train_model(model, train_texts, train_labels)
trained_model.save_pretrained("./vault-embeddings")
대부분의 vault에서는 default potion-base-8M이 충분한 retrieval 품질을 제공합니다. Fine-tuning은 general-purpose model이 포착하지 못하는 domain-specific connections를 retrieval이 반복적으로 놓칠 때만 할 만합니다.
Model Hash Tracking
indexer는 model name과 vocabulary size에서 파생된 hash를 저장합니다. embedding model을 바꾸면 indexer가 다음 incremental run에서 mismatch를 감지하고 자동으로 full reindex를 trigger합니다.
def _compute_model_hash(self):
"""Hash model name + vocab size for compatibility tracking."""
key = f"{self._model_name}:{self._model.vocab_size}"
return hashlib.sha256(key.encode()).hexdigest()[:16]
이렇게 하면 서로 다른 models에서 나온 vectors가 같은 database에 섞이는 일을 막을 수 있습니다. 섞이면 cosine similarity scores가 의미 없는 값이 됩니다.
Failure Modes
Model download failure. 첫 실행에서는 Hugging Face에서 model을 다운로드합니다. download가 실패하면(network issue, corporate firewall) retriever는 BM25-only mode로 fallback합니다. 첫 download 이후 model은 local에 cached됩니다.
Dimension mismatch. database를 지우지 않고 models를 바꾸면 저장된 vectors의 dimension이 새 embeddings와 달라집니다. indexer는 model hash를 통해 이를 감지하고 full reindex를 trigger합니다. hash check가 실패하면(proper hash가 없는 custom model) sqlite-vec는 dimension이 맞지 않는 KNN queries에서 error를 냅니다.
대규모 vault의 memory pressure. 50,000개 이상의 chunks를 단일 batch로 embedding하면 상당한 memory를 사용할 수 있습니다. indexer는 peak memory usage를 제한하기 위해 64개씩 batch로 처리합니다. memory가 여전히 문제라면 batch size를 줄이세요.
FTS5를 사용한 Full-Text Search
SQLite의 FTS5 확장은 BM25 순위를 사용한 Full-Text Search를 제공합니다. FTS5는 hybrid 검색 파이프라인의 키워드 검색 구성 요소입니다. 이 섹션에서는 FTS5 설정, BM25가 뛰어난 경우, 그리고 구체적인 실패 모드를 다룹니다.
FTS5 Virtual Table
CREATE VIRTUAL TABLE chunks_fts USING fts5(
chunk_text,
section,
heading_context,
content=chunks,
content_rowid=id
);
Content-sync 모드. content=chunks 매개변수는 FTS5가 텍스트의 중복 복사본을 저장하는 대신 chunks 테이블을 직접 참조하도록 합니다. 이렇게 하면 저장 공간 요구량이 절반으로 줄지만, chunk가 삽입, 업데이트, 삭제될 때 FTS5를 수동으로 동기화해야 합니다.
컬럼. 3개의 컬럼이 인덱싱됩니다.
- chunk_text — 각 chunk의 기본 콘텐츠(BM25 가중치: 1.0)
- section — H2 heading 텍스트(BM25 가중치: 0.5)
- heading_context — 노트 제목, 태그, metadata(BM25 가중치: 0.3)
BM25 순위
BM25는 term frequency, inverse document frequency, document length normalization을 기준으로 문서 순위를 매깁니다. FTS5의 bm25() 보조 기능은 컬럼별 가중치를 받습니다.
SELECT
c.id, c.file_path, c.section, c.chunk_text,
bm25(chunks_fts, 1.0, 0.5, 0.3) AS score
FROM chunks_fts
JOIN chunks c ON chunks_fts.rowid = c.id
WHERE chunks_fts MATCH ?
ORDER BY score
LIMIT 30;
컬럼 가중치(1.0, 0.5, 0.3)의 의미는 다음과 같습니다.
- chunk_text의 키워드 일치가 점수에 가장 크게 기여합니다
- section(heading)의 일치는 그 절반만큼 기여합니다
- heading_context(제목, 태그)의 일치는 30%만큼 기여합니다
이 가중치는 조정할 수 있습니다. vault에 콘텐츠 품질을 강하게 예측하는 설명적인 heading이 있다면 section 가중치를 높이세요. 태그가 포괄적이고 정확하다면 heading_context 가중치를 높이세요.
BM25가 이기는 경우
BM25는 정확한 식별자가 포함된 쿼리에서 뛰어납니다.
- 기능 이름:
_rrf_fuse,embed_batch,get_stale_files - CLI 플래그:
--incremental,--vault,--model - 설정 키:
bm25_weight,max_tokens,batch_size - 오류 메시지:
SQLITE_LOCKED,ConnectionRefusedError - 특정 전문 용어:
PostToolUse,PreToolUse,AGENTS.md
이런 쿼리에서는 BM25가 정확한 일치를 즉시 찾습니다. 벡터 검색은 의미적으로 관련된 콘텐츠를 반환하겠지만, 정확한 일치를 개념적 논의보다 낮게 순위 매길 수도 있습니다.
BM25가 실패하는 경우
BM25는 저장된 콘텐츠와 다른 용어를 사용하는 쿼리에서 실패합니다.
- 쿼리: “how to handle authentication failures” → Vault에는 “login error recovery”와 “session expiration handling”에 관한 노트가 있습니다. 키워드가 다르기 때문에 BM25는 일치시키지 못합니다.
- 쿼리: “what is the best way to manage state” → Vault에는 “Redux store patterns”와 “context providers”에 관한 노트가 있습니다. “state management”가 특정 기술 이름으로 표현되어 있기 때문에 BM25는 놓칩니다.
BM25는 규모가 커질 때 키워드 충돌에서도 실패합니다. 15,000개 파일이 있는 vault에서 “configuration”을 검색하면 거의 모든 프로젝트 노트가 configuration을 언급하기 때문에 수백 개의 노트가 일치합니다. 결과는 기술적으로 맞지만 실제로는 쓸모가 없습니다. 순위 시스템이 현재 쿼리와 관련 있는 “configuration” 노트가 무엇인지 판단할 수 없기 때문입니다.
FTS5 Tokenizer
FTS5는 기본적으로 ASCII와 Unicode 텍스트를 처리하는 unicode61 tokenizer를 사용합니다. CJK(중국어, 일본어, 한국어) 콘텐츠가 많은 vault라면 trigram tokenizer를 고려하세요.
-- For CJK-heavy vaults
CREATE VIRTUAL TABLE chunks_fts USING fts5(
chunk_text, section, heading_context,
content=chunks, content_rowid=id,
tokenize='trigram'
);
기본 unicode61 tokenizer는 단어 경계를 기준으로 분리하므로, 단어 사이에 공백이 없는 언어에서는 잘 작동하지 않습니다. trigram tokenizer는 3글자마다 분리해 substring matching을 가능하게 하지만, index 크기가 커지는 대가가 있습니다(대략 3배 더 큽니다).
유지 관리
FTS5는 기반 chunks 테이블이 변경될 때 명시적인 동기화가 필요합니다.
# After inserting chunks
cursor.execute("""
INSERT INTO chunks_fts(chunks_fts)
VALUES('rebuild')
""")
rebuild 명령은 콘텐츠 테이블에서 FTS5 index를 다시 구성합니다. 대량 삽입(full reindex) 후에는 실행하되, 개별 incremental 업데이트 후에는 실행하지 마세요. 그런 경우에는 INSERT INTO chunks_fts(rowid, chunk_text, section, heading_context)를 사용해 개별 row를 동기화하세요.
sqlite-vec를 사용한 Vector Search
sqlite-vec 확장은 SQLite에 vector KNN (K-Nearest Neighbors) 검색을 제공합니다. 이 섹션에서는 sqlite-vec 설정, 노트에서 검색 가능한 vector로 이어지는 embedding 파이프라인, 그리고 구체적인 쿼리 패턴을 다룹니다.
sqlite-vec Virtual Table
CREATE VIRTUAL TABLE chunk_vecs USING vec0(
id INTEGER PRIMARY KEY,
embedding float[256]
);
vec0 모듈은 256차원 float vector를 packed binary data로 저장합니다. id 열은 chunks 테이블과 1:1로 매핑되어 vector 결과와 chunk metadata를 조인할 수 있게 합니다.
Embedding Pipeline
파이프라인은 노트에서 검색 가능한 vector까지 다음 흐름으로 이어집니다.
Note (.md file)
→ Chunker: split at H2 boundaries
→ Chunks (30-2000 chars each)
→ Credential filter: scrub secrets
→ Embedder: Model2Vec encode
→ Vectors (256-dim float arrays)
→ sqlite-vec: store as packed binary
→ Ready for KNN queries
Vector Serialization
Python의 struct 모듈은 float vector를 sqlite-vec 저장용으로 직렬화합니다.
import struct
def _serialize_vector(vec):
"""Pack float list into binary for sqlite-vec."""
return struct.pack(f"{len(vec)}f", *vec)
def _deserialize_vector(blob, dim=256):
"""Unpack binary blob to float list."""
return list(struct.unpack(f"{dim}f", blob))
KNN Query
vector search 쿼리는 입력 쿼리를 embedding한 다음, cosine distance 기준으로 가장 가까운 K개의 chunk를 찾습니다.
def _vector_search(self, query_text, limit=30):
query_vec = self.embedder.embed_batch([query_text])[0]
packed = _serialize_vector(query_vec)
results = self.db.execute("""
SELECT
cv.id,
cv.distance,
c.file_path,
c.section,
c.chunk_text
FROM chunk_vecs cv
JOIN chunks c ON cv.id = c.id
WHERE embedding MATCH ?
AND k = ?
ORDER BY distance
""", [packed, limit]).fetchall()
return results
sqlite-vec의 MATCH 연산자는 approximate nearest neighbor search를 수행합니다. k 매개변수는 반환할 결과 수를 제어합니다. distance 열에는 cosine distance가 들어갑니다(0 = 동일, 2 = 반대).
Distance Constraints를 사용한 KNN Pagination
sqlite-vec v0.1.7부터 KNN 쿼리는 WHERE distance < ? 제약을 지원하므로, 이전 페이지를 다시 스캔하지 않고도 큰 결과 집합을 cursor 기반으로 pagination할 수 있습니다.14 이후 v0.1.8 및 v0.1.9 stable 릴리스는 새로운 query model 릴리스라기보다 packaging 및 DELETE 버그 수정 릴리스이므로, 이 pagination 패턴의 기능 경계는 여전히 v0.1.7입니다.23
앞으로는 v0.1.10-alpha 라인(2026년 3월 31일 - 5월 18일)이 sqlite-vec를 brute-force KNN 너머로 처음 확장합니다. 이 라인은 approximate-nearest-neighbor index type을 도입합니다. 여기에는 rescore, 기본으로 활성화되지 않는 실험적 ivf(inverted-file) index, 그리고 vector를 메모리에 상주시킬 수 없을 만큼 큰 vault를 위한 disk 기반 DiskANN index가 포함됩니다.23 이런 변화는 매우 큰 vault의 scaling 방식을 바꿀 수 있지만, 0.1.10 라인은 아직 pre-release (alpha) 상태입니다. 따라서 ANN indexing은 실험적인 것으로 보고, stable 0.1.10이 출시되기 전까지 production vault에서는 stable v0.1.9 brute-force KNN 경로를 기반으로 계속 구축하세요.
def _paginated_vector_search(self, query_vec, page_size=20, max_distance=None):
"""Paginate through KNN results using distance constraints."""
packed = _serialize_vector(query_vec)
constraint = f"AND distance < {max_distance}" if max_distance else ""
results = self.db.execute(f"""
SELECT cv.id, cv.distance, c.file_path, c.chunk_text
FROM chunk_vecs cv
JOIN chunks c ON cv.id = c.id
WHERE embedding MATCH ?
AND k = ?
{constraint}
ORDER BY distance
""", [packed, page_size]).fetchall()
# Use last result's distance as cursor for next page
next_cursor = results[-1][1] if results else None
return results, next_cursor
이는 큰 k를 가져온 뒤 Python에서 잘라내던 이전 패턴을 대체하며, 큰 vault에서 탐색적 쿼리를 실행할 때 메모리 사용량을 줄여 줍니다.
vec0 Tables의 DELETE Support
sqlite-vec v0.1.7은 vec0 virtual table에 native DELETE support를 추가했고, v0.1.9는 12자를 초과하는 metadata text 열과 관련된 DELETE 오류 경로를 수정했습니다.1423 이전에는 vector를 제거하려면 테이블을 drop한 뒤 다시 만들어야 했습니다. 이제 indexer의 file-removal 경로는 vector를 직접 삭제할 수 있습니다.
# Before v0.1.7: required workaround (drop + recreate, or mark as inactive)
# After v0.1.7: direct DELETE works
db.execute("DELETE FROM chunk_vecs WHERE id = ?", [chunk_id])
이로써 노트가 삭제되거나 이동될 때 incremental reindexing이 단순해집니다. indexer는 더 이상 shadow “active IDs” 테이블을 유지하거나 batch rebuild를 수행할 필요가 없습니다.
Vector Search가 유리한 경우
Vector search는 특정 단어보다 개념이 더 중요한 쿼리에서 강점을 보입니다.
- Query: “how to handle authentication failures” → “login error recovery”에 대한 노트를 찾습니다(같은 semantic space, 다른 keyword)
- Query: “what patterns exist for caching” → “memoization”, “Redis TTL strategies”, “HTTP cache headers”에 대한 노트를 찾습니다(관련 개념, 다양한 terminology)
- Query: “approaches to testing asynchronous code” → “pytest-asyncio fixtures”, “mock event loops”, “async test patterns”에 대한 노트를 찾습니다(같은 개념이 구현 세부 사항으로 표현됨)
Vector Search가 실패하는 경우
Vector search는 정확한 identifier에 약합니다.
- Query:
_rrf_fuse→ “fusion algorithms”와 “rank merging”에 대한 노트를 반환하지만, 실제 function definition은 개념적 논의보다 낮게 ranking될 수 있습니다 - Query:
PostToolUse→ 특정 hook name보다는 “tool lifecycle hooks”와 “post-execution handlers”에 대한 노트를 반환합니다
Vector search는 structured data에도 약합니다. JSON 설정 파일, YAML block, code snippet은 semantic meaning보다 structural pattern을 포착하는 embedding을 생성합니다. "review": true가 있는 JSON 파일은 code review에 대한 prose 논의와 다르게 embedding됩니다.
Graceful Degradation
sqlite-vec 로드에 실패하면(missing extension, incompatible platform, corrupted library), retriever는 BM25-only search로 fallback합니다.
class VectorIndex:
def __init__(self, db_path):
self.db = sqlite3.connect(db_path)
self._vec_available = False
try:
self.db.enable_load_extension(True)
self.db.load_extension("vec0")
self._vec_available = True
except Exception:
pass # BM25-only mode
@property
def vec_available(self):
return self._vec_available
retriever는 vector query를 시도하기 전에 vec_available을 확인합니다. 비활성화되어 있으면 모든 검색은 BM25만 사용하고, RRF fusion 단계는 건너뜁니다.
Reciprocal Rank Fusion (RRF)
RRF는 점수 보정 없이 순위가 매겨진 두 목록을 병합합니다. 이 섹션에서는 알고리즘, 실제 쿼리 추적 예시, k 매개변수 튜닝, 그리고 RRF를 다른 대안 대신 선택한 이유를 다룹니다. 순위를 편집할 수 있는 인터랙티브 계산기, 시나리오 프리셋, 시각적 아키텍처 탐색기는 hybrid retriever 심층 분석을 참고하세요.
알고리즘
RRF는 각 목록에서 문서가 차지한 순위 위치만을 기준으로 각 문서에 점수를 부여합니다.
score(d) = Σ (weight_i / (k + rank_i))
여기서:
- k는 평활화 상수입니다(60, Cormack et al.3을 따름)
- rank_i는 결과 목록 i에서 문서의 1부터 시작하는 순위입니다
- weight_i는 목록별 선택적 배수입니다(기본값 1.0)
여러 목록에서 높은 순위를 받은 문서는 더 높은 융합 점수를 받습니다. 한 목록에만 나타나는 문서는 해당 단일 소스에서만 점수를 받습니다.
대안 대신 RRF를 선택한 이유
가중 선형 결합은 BM25 점수를 cosine distances와 보정해야 합니다. BM25 점수는 상한이 없고 corpus 크기에 따라 스케일이 달라집니다. Cosine distances는 [0, 2] 범위로 제한됩니다. 둘을 결합하려면 정규화가 필요하며, 정규화 매개변수는 데이터셋에 따라 달라집니다. RRF는 순위 위치만 사용하며, 순위는 점수 산정 방식과 관계없이 항상 1부터 시작하는 정수입니다.
학습된 융합 모델은 라벨링된 학습 데이터, 즉 쿼리-문서 관련성 쌍이 필요합니다. 개인 knowledge base에는 이런 학습 데이터가 없습니다. 유용한 모델을 학습하려면 수백 개의 쿼리-문서 쌍을 직접 판정해야 합니다. RRF는 학습 데이터 없이 작동합니다.
Condorcet voting 방식(Borda count, Schulze method)은 이론적으로는 우아하지만 구현하고 튜닝하기가 더 복잡합니다. 원래 RRF 논문은 TREC 평가 데이터에서 RRF가 Condorcet 방식보다 더 뛰어난 성능을 보인다고 밝혔습니다.3
실제 Fusion
쿼리: “how does the review aggregator handle disagreements”
BM25는 review-aggregator.py를 3위에 배치합니다(“review,” “aggregator,” “disagreements”에 대한 정확한 키워드 일치). 하지만 “review”가 더 두드러지게 일치하는 두 설정 파일을 더 높은 순위에 둡니다. Vector search는 같은 chunk를 1위에 배치합니다(충돌 해결에 대한 의미적 일치). RRF fusion 이후 결과는 다음과 같습니다.
| Chunk | BM25 | Vec | Fused Score |
|---|---|---|---|
| review-aggregator.py “Disagreement Resolution” | #3 | #1 | 0.0323 |
| code-review-patterns.md “Multi-Reviewer” | #4 | #2 | 0.0317 |
| deliberation-config.json “Review Weights” | #1 | — | 0.0164 |
두 목록에서 모두 높은 순위를 받은 chunk가 상위로 올라옵니다. 한 목록에만 나타나는 chunk는 단일 소스 점수만 받아, 두 목록 모두에서 순위가 매겨진 결과보다 아래로 내려갑니다. 실제 의견 불일치 해결 로직이 이기는 이유는 두 방식이 모두 그것을 찾아냈기 때문입니다. BM25는 키워드를 통해, vector search는 의미를 통해 찾아냈습니다.
순위별 RRF 계산을 포함한 전체 단계별 추적은 interactive RRF calculator에서 여러 k 값을 바꿔 보며 확인할 수 있습니다.
구현
RRF_K = 60
def _rrf_fuse(self, bm25_results, vec_results,
bm25_weight=1.0, vec_weight=1.0):
"""Fuse BM25 and vector results using Reciprocal Rank Fusion."""
scores = {}
for rank, r in enumerate(bm25_results, start=1):
cid = r["id"]
if cid not in scores:
scores[cid] = {
"rrf_score": 0.0,
"file_path": r["file_path"],
"section": r["section"],
"chunk_text": r["chunk_text"],
"bm25_rank": None,
"vec_rank": None,
}
scores[cid]["rrf_score"] += bm25_weight / (self._rrf_k + rank)
scores[cid]["bm25_rank"] = rank
for rank, r in enumerate(vec_results, start=1):
cid = r["id"]
if cid not in scores:
scores[cid] = {
"rrf_score": 0.0,
"file_path": r["file_path"],
"section": r["section"],
"chunk_text": r["chunk_text"],
"bm25_rank": None,
"vec_rank": None,
}
scores[cid]["rrf_score"] += vec_weight / (self._rrf_k + rank)
scores[cid]["vec_rank"] = rank
fused = sorted(
scores.values(),
key=lambda x: x["rrf_score"],
reverse=True,
)
return fused
k 튜닝
k 상수는 상위 순위 결과와 하위 순위 결과에 각각 얼마나 많은 가중치를 줄지 제어합니다.
- 낮은 k(예: 10): 상위 순위 결과가 지배합니다. 1위 점수는 1/11 = 0.091이고, 10위 점수는 1/20 = 0.050입니다(1.8배 차이). 개별 ranker가 최상위 결과를 정확히 찾는다고 신뢰할 수 있을 때 좋습니다.
- 기본 k(60): 균형 잡힌 값입니다. 1위 점수는 1/61 = 0.0164이고, 10위 점수는 1/70 = 0.0143입니다(1.15배 차이). 순위 차이가 압축되어 여러 목록에 함께 나타나는 것에 더 많은 가중치가 부여됩니다.
- 높은 k(예: 200): 두 목록에 모두 나타나는지가 순위 위치보다 훨씬 더 중요해집니다. 1위 점수는 1/201이고, 10위 점수는 1/210으로 거의 같습니다. 개별 ranker의 순위가 noisy하지만 목록 간 일치가 신뢰할 만할 때 사용하세요.
k=60으로 시작하세요. 원래 RRF 논문은 이 값이 다양한 TREC 데이터셋에서 견고하다는 점을 확인했습니다. 직접 사용하는 쿼리 분포에서 실패 사례를 측정한 뒤에만 튜닝하세요.
동점 처리
두 chunk의 RRF 점수가 동일한 경우(드물지만 한 목록에서 같은 순위를 받고 다른 목록에는 나타나지 않으면 가능함), 다음 기준으로 동점을 처리합니다.
- 한 목록에만 나타나는 chunk보다 두 목록에 모두 나타나는 chunk를 우선합니다
- 두 목록에 모두 나타나는 chunk끼리는 합산 순위가 더 낮은 chunk를 우선합니다
- 한 목록에만 나타나는 chunk끼리는 해당 목록에서 순위가 더 낮은 chunk를 우선합니다
전체 Retrieval Pipeline
이 섹션에서는 입력부터 출력까지 전체 pipeline을 따라 query가 어떻게 처리되는지 살펴봅니다. BM25 search, vector search, RRF fusion, token budget truncation, context assembly 순서로 이어집니다.
End-to-End 흐름
User query: "PostToolUse hook for context compression"
│
├─ BM25 Search (FTS5)
│ → MATCH "PostToolUse hook context compression"
│ → Top 30 results ranked by BM25 score
│ → 12ms
│
├─ Vector Search (sqlite-vec)
│ → Embed query with Model2Vec
│ → KNN k=30 on chunk_vecs
│ → Top 30 results ranked by cosine distance
│ → 8ms
│
└─ RRF Fusion
→ Merge 60 candidates (may overlap)
→ Score by rank position
→ Top 10 results
→ 3ms
│
└─ Token Budget
→ Truncate to max_tokens (default 4000)
→ Estimate at 4 chars per token
→ Return results with metadata
→ <1ms
총 latency: 약 23ms입니다. Apple M3 Pro hardware에서 49,746개 chunk database를 기준으로 측정했습니다.
Search API
class HybridRetriever:
def search(self, query, limit=10, max_tokens=4000,
bm25_weight=1.0, vec_weight=1.0):
"""
Search the vault using hybrid BM25 + vector retrieval.
Args:
query: Search query text
limit: Maximum results to return
max_tokens: Token budget for total result text
bm25_weight: Weight for BM25 results in RRF
vec_weight: Weight for vector results in RRF
Returns:
List of SearchResult with file_path, section,
chunk_text, rrf_score, bm25_rank, vec_rank
"""
# BM25 search
bm25_results = self._bm25_search(query, limit=30)
# Vector search (if available)
if self.index.vec_available:
vec_results = self._vector_search(query, limit=30)
fused = self._rrf_fuse(
bm25_results, vec_results,
bm25_weight, vec_weight,
)
else:
fused = bm25_results # BM25-only fallback
# Token budget truncation
results = []
token_count = 0
for r in fused[:limit]:
chunk_tokens = len(r["chunk_text"]) // 4
if token_count + chunk_tokens > max_tokens:
break
results.append(r)
token_count += chunk_tokens
return results
Token Budget Truncation
max_tokens parameter는 retriever가 AI tool이 사용할 수 있는 양보다 많은 context를 반환하지 않도록 막아 줍니다. 추정에는 token당 4글자를 사용합니다. 이는 English prose에 적당한 근사치입니다. 결과는 greedy 방식으로 잘립니다. 순위가 높은 결과부터 budget이 소진될 때까지 추가합니다.
이는 보수적인 전략입니다. 더 정교한 접근법이라면 result별 quality score를 고려해 길고 품질이 낮은 결과보다 짧고 품질이 높은 결과를 우선할 수 있습니다. greedy approach는 더 단순하고 실제로도 잘 작동합니다. RRF ranking이 이미 relevance 기준으로 결과를 정렬하기 때문입니다.
Database Schema (전체)
-- Chunk content and metadata
CREATE TABLE chunks (
id INTEGER PRIMARY KEY,
file_path TEXT NOT NULL,
section TEXT NOT NULL,
chunk_text TEXT NOT NULL,
heading_context TEXT DEFAULT '',
mtime_ns INTEGER NOT NULL,
embedded_at REAL NOT NULL
);
CREATE INDEX idx_chunks_file ON chunks(file_path);
CREATE INDEX idx_chunks_mtime ON chunks(mtime_ns);
-- FTS5 for BM25 search (content-synced to chunks table)
CREATE VIRTUAL TABLE chunks_fts USING fts5(
chunk_text, section, heading_context,
content=chunks, content_rowid=id
);
-- sqlite-vec for vector KNN search
CREATE VIRTUAL TABLE chunk_vecs USING vec0(
id INTEGER PRIMARY KEY,
embedding float[256]
);
-- Model metadata for compatibility tracking
CREATE TABLE model_meta (
key TEXT PRIMARY KEY,
value TEXT
);
Graceful Degradation Path
Full pipeline: BM25 + Vector + RRF → Best results
No sqlite-vec: BM25 only → Good results (no semantic)
No model download: BM25 only → Good results (no semantic)
No FTS5: Vector only → Decent results (no keyword)
No database: Error → Prompt user to run indexer
retriever는 초기화 시 capability를 확인하고 query strategy를 조정합니다. component가 없으면 quality는 낮아지지만 error가 발생하지는 않습니다. 유일한 hard failure는 database file이 없는 경우입니다.
Production Stats
16,894개 file, 49,746개 chunk, 83 MB SQLite database, Apple M3 Pro 기준으로 측정했습니다.
| Metric | Value |
|---|---|
| 전체 file | 16,894 |
| 전체 chunk | 49,746 |
| Database size | 83 MB |
| BM25 query latency (p50) | 12ms |
| Vector query latency (p50) | 8ms |
| RRF fusion latency | 3ms |
| End-to-end search latency (p50) | 23ms |
| Full reindex time | 약 4분 |
| Incremental reindex time | <10초 |
| Embedding model | potion-base-8M (256-dim) |
| BM25 candidate pool | 30 |
| Vector candidate pool | 30 |
| Default result limit | 10 |
| Default token budget | 4,000 tokens |
Content Hashing과 Change Detection
indexer는 마지막 index run 이후 어떤 file이 변경되었는지 알아야 합니다. 이 섹션에서는 change detection mechanism과 hashing strategy를 다룹니다.
File Modification Time 비교
indexer는 모든 chunk에 대해 chunks table에 mtime_ns(file modification time, nanoseconds 단위)를 저장합니다. incremental run에서 indexer는 다음을 수행합니다.
- 허용된 folder 안의 모든
.mdfile을 vault에서 scan합니다. - filesystem에서 각 file의
mtime_ns를 읽습니다. - database에 저장된
mtime_ns와 비교합니다. - 세 가지 category를 식별합니다.
- New files: path가 filesystem에는 있지만 database에는 없습니다.
- Changed files: path가 양쪽에 모두 있지만
mtime_ns가 다릅니다. - Deleted files: path가 database에는 있지만 filesystem에는 없습니다.
def get_stale_files(self, vault_mtimes):
"""Find files whose mtime changed or are new."""
stored = dict(self.db.execute(
"SELECT DISTINCT file_path, mtime_ns FROM chunks"
).fetchall())
stale = []
for path, mtime in vault_mtimes.items():
if path not in stored or stored[path] != mtime:
stale.append(path)
return stale
def get_deleted_files(self, vault_paths):
"""Find files in database that no longer exist in vault."""
stored_paths = set(r[0] for r in self.db.execute(
"SELECT DISTINCT file_path FROM chunks"
).fetchall())
return stored_paths - set(vault_paths)
Content Hash가 아니라 mtime을 쓰는 이유
Content hashing(file contents의 SHA-256)은 mtime comparison보다 더 안정적입니다. file이 실제로 바뀌지 않았는데 touched된 경우도 감지할 수 있습니다. 예를 들어 git checkout이 원래 mtime을 복원하는 경우입니다. 하지만 hashing은 incremental run마다 모든 file을 읽어야 합니다. 16,894개 file의 contents를 읽는 데는 2-3초가 걸립니다. filesystem에서 mtime을 읽는 데는 <100ms가 걸립니다.
trade-off는 이렇습니다. mtime comparison은 변경되지 않은 file을 불필요하게 re-indexing하는 경우(false positive)가 가끔 있지만, 실제 변경을 놓치지는 않습니다. false positive는 run마다 embedding call 몇 개가 더 드는 정도입니다. 속도 차이(100ms vs 3초) 때문에 매 AI interaction마다 실행되는 system에서는 mtime이 실용적인 선택입니다.
Deletion 처리
vault에서 file이 삭제되면 indexer는 해당 file의 모든 chunk를 database에서 제거합니다.
def remove_file(self, file_path):
"""Remove all chunks and vectors for a file."""
chunk_ids = [r[0] for r in self.db.execute(
"SELECT id FROM chunks WHERE file_path = ?",
[file_path],
).fetchall()]
for cid in chunk_ids:
self.db.execute(
"DELETE FROM chunk_vecs WHERE id = ?", [cid]
)
self.db.execute(
"DELETE FROM chunks WHERE file_path = ?",
[file_path],
)
DELETE FROM chunk_vecs statement는 sqlite-vec v0.1.7부터 native로 작동하며, v0.1.9에서는 metadata text column이 더 긴 vec0 table에 대한 DELETE operation bug fix가 포함되었습니다.1423 이전 version에서는 workaround가 필요했습니다. 예를 들어 virtual table을 drop한 뒤 다시 만들거나, 외부 “active IDs” set을 유지해야 했습니다. pre-0.1.9 version을 실행 중이라면 metadata-heavy schema에서 direct delete에 의존하기 전에 upgrade하세요.
FTS5 content-sync table은 제거된 각 row에 대해 INSERT INTO chunks_fts(chunks_fts, rowid, ...) VALUES('delete', ?, ...)를 통해 명시적으로 delete해야 합니다. indexer는 file removal process의 일부로 이를 처리합니다.
증분 재색인과 전체 재색인
인덱서는 두 가지 모드를 지원합니다. 증분 모드(빠르고 일상적으로 사용)와 전체 모드(느리고 가끔 사용)입니다. 이 섹션에서는 각 모드를 언제 사용해야 하는지, 멱등성 보장, 손상 복구를 다룹니다.
증분 재색인
사용 시점: 노트를 편집한 뒤 매일 인덱싱할 때 사용합니다. 기본 모드입니다.
수행 작업: 1. 저장소에서 파일 변경 사항을 스캔합니다(mtime 비교) 2. 삭제된 파일의 chunks를 삭제합니다 3. 변경된 파일을 다시 chunking하고 다시 embedding합니다 4. 새 파일의 새 chunks를 삽입합니다 5. FTS5 인덱스를 동기화합니다
일반적인 소요 시간: 16,000개 파일이 있는 저장소에서 하루치 편집분 기준 <10초입니다.
python index_vault.py --incremental
전체 재색인
사용 시점: - embedding 모델을 변경한 뒤(모델 해시 불일치 감지) - 스키마 마이그레이션 뒤(새 컬럼, 변경된 인덱스) - 데이터베이스 손상 뒤(무결성 검사 실패) - 증분 인덱싱이 예상과 다른 결과를 만들 때
수행 작업: 1. 기존 데이터를 모두 삭제합니다(chunks, vectors, FTS5 entries) 2. 전체 저장소를 스캔합니다 3. 모든 파일을 chunking합니다 4. 모든 chunks를 embedding합니다 5. FTS5 인덱스를 처음부터 빌드합니다
일반적인 소요 시간: Apple M3 Pro에서 16,894개 파일 기준 약 4분입니다.
python index_vault.py --full
멱등성
두 모드는 모두 멱등적입니다. 같은 명령을 두 번 실행해도 같은 결과가 나옵니다. 인덱서는 새 chunks를 삽입하기 전에 해당 파일의 기존 chunks를 삭제하므로, 이미 최신 상태인 데이터베이스에 증분 인덱싱을 다시 실행하면 변경 사항이 0개입니다. 전체 인덱싱을 다시 실행하면 동일한 데이터베이스가 생성됩니다.
손상 복구
SQLite 데이터베이스가 손상된 경우(쓰기 중 전원 손실, 디스크 오류, 트랜잭션 도중 프로세스 종료):
# Check integrity
sqlite3 vectors.db "PRAGMA integrity_check;"
# If corruption detected, full reindex rebuilds from source files
python index_vault.py --full
진실의 원천은 항상 데이터베이스가 아니라 저장소 파일입니다. 데이터베이스는 언제든 다시 빌드할 수 있는 파생 산출물입니다. 이는 중요한 설계 속성입니다. 데이터베이스를 백업할 필요가 없습니다.
--incremental 플래그
인덱서가 --incremental로 실행될 때:
- 모델 해시 검사. 저장된 모델 해시를 현재 모델과 비교합니다. 다르면 자동으로 전체 재색인 모드로 전환하고 사용자에게 경고합니다.
- 파일 스캔. 허용된 폴더를 순회하며 파일 경로와 mtimes를 수집합니다.
- 변경 감지. 저장된 데이터와 비교합니다.
- 배치 처리. 변경된 파일을 64개 단위 배치로 다시 chunking하고 다시 embedding합니다.
- 진행 상황 보고. 처리한 파일 수와 경과 시간을 출력합니다.
- 정상 종료. SIGINT를 받으면 현재 파일 처리를 마친 뒤 중지합니다.
자격 증명 필터링과 데이터 경계
개인 노트에는 비밀 정보가 들어 있습니다. API 키, bearer tokens, 데이터베이스 연결 문자열, 디버깅 세션 중 붙여 넣은 private keys 등이 그렇습니다. 자격 증명 필터는 이런 정보가 검색 인덱스에 들어가지 않도록 막습니다.
문제
OAuth 통합을 디버깅하는 노트에는 다음과 같은 내용이 있을 수 있습니다.
The token was: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
I used this curl command:
curl -H "Authorization: Bearer sk-ant-api03-abc123..."
필터링이 없으면 JWT와 API 키가 모두 chunking되고 embedding된 뒤 데이터베이스에 저장됩니다. “authentication”을 검색하면 실제 비밀 정보가 들어 있는 chunk가 반환됩니다. 더 나쁜 경우, retriever가 MCP를 통해 결과를 AI 도구에 전달하면 비밀 정보가 AI의 컨텍스트 창에 들어가고, 잠재적으로 도구 로그에도 남습니다.
패턴 기반 필터링
자격 증명 필터는 저장 전 모든 chunk에서 실행되며, 25개의 벤더별 패턴과 일반 패턴을 매칭합니다.
벤더별 패턴:
| 패턴 | 예시 | Regex |
|---|---|---|
| OpenAI API key | sk-... |
sk-[a-zA-Z0-9_-]{20,} |
| Anthropic API key | sk-ant-api03-... |
sk-ant-api\d{2}-[a-zA-Z0-9_-]{20,} |
| GitHub PAT | ghp_... |
gh[ps]_[a-zA-Z0-9]{36,} |
| AWS Access Key | AKIA... |
AKIA[0-9A-Z]{16} |
| Stripe key | sk_live_... |
[sr]k_(live\|test)_[a-zA-Z0-9]{24,} |
| Cloudflare token | ... |
다양한 패턴 |
일반 패턴:
| 패턴 | 감지 방식 |
|---|---|
| JWT tokens | eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+ |
| Bearer tokens | Bearer\s+[a-zA-Z0-9_\-\.]+ |
| Private keys | -----BEGIN (RSA\|EC\|OPENSSH) PRIVATE KEY----- |
| 고엔트로피 base64 | 엔트로피가 >4.5 bits/char이고 40자 이상인 문자열 |
| Password assignments | password\s*[:=]\s*["'][^"']+["'] |
필터 구현
def clean_content(text):
"""Scrub credentials from text before indexing."""
result = ScanResult(is_clean=True, match_count=0, patterns=[])
for pattern in CREDENTIAL_PATTERNS:
matches = pattern.regex.findall(text)
if matches:
text = pattern.regex.sub(
f"[REDACTED:{pattern.name}]", text
)
result.is_clean = False
result.match_count += len(matches)
result.patterns.append(pattern.name)
return text, result
주요 설계 선택:
-
embedding 전에 필터링합니다. 정리된 텍스트가 embedding 대상입니다. vector 표현은 자격 증명 패턴을 절대 인코딩하지 않습니다. “API key”를 쿼리하면 실제 키가 들어 있는 노트가 아니라 API key 관리에 대해 다루는 노트가 반환됩니다.
-
삭제하지 않고 대체합니다.
[REDACTED:pattern-name]토큰은 주변 텍스트의 의미적 맥락을 보존합니다. embedding은 자격 증명처럼 보이는 무언가가 이 위치에 있었다는 점을 포착하지만, 자격 증명 자체는 인코딩하지 않습니다. -
값이 아니라 패턴을 기록합니다. 필터는 어떤 패턴이 매칭되었는지 기록합니다(예: “Scrubbed 2 credential(s) from oauth-debug.md [jwt, bearer-token]”). 하지만 자격 증명 값은 절대 기록하지 않습니다.
경로 기반 제외
.indexignore 파일은 경로 기준의 큰 단위 제외를 제공합니다. 자격 증명 필터는 인덱싱되는 파일 내부에서 세밀한 정리를 제공합니다. 둘 다 필요합니다.
.indexignore는 민감한 콘텐츠가 들어 있다고 알고 있는 전체 폴더에 사용합니다(건강 노트, 재무 기록, 커리어 문서)- 자격 증명 필터는 원래는 인덱싱할 수 있는 콘텐츠에 실수로 포함된 비밀 정보에 사용합니다
데이터 분류
다양한 콘텐츠가 들어 있는 저장소라면 민감도에 따라 노트를 분류하는 방식을 고려하세요.
| 수준 | 예시 | 인덱싱? | 필터링? |
|---|---|---|---|
| 공개 | 블로그 초안, 기술 노트 | 예 | 예 |
| 내부 | 프로젝트 계획, 아키텍처 결정 | 예 | 예 |
| 민감 | 급여 데이터, 건강 기록 | 아니요(.indexignore) | N/A |
| 제한 | 자격 증명, private keys | 아니요(.indexignore) | N/A |
MCP 서버 아키텍처
Model Context Protocol (MCP) 서버는 AI 에이전트가 호출할 수 있는 도구로 retriever를 노출합니다. 이 섹션에서는 서버 설계, 기능 범위, 권한 경계를 다룹니다.
프로토콜 선택: STDIO vs HTTP
MCP는 2가지 전송 모드를 지원합니다.
STDIO — AI 도구가 MCP 서버를 하위 프로세스로 실행하고 stdin/stdout을 통해 통신합니다. 이는 로컬 도구의 표준 모드입니다. Claude Code, Codex CLI, Cursor는 모두 STDIO MCP 서버를 지원합니다.
{
"mcpServers": {
"obsidian": {
"command": "python",
"args": ["/path/to/obsidian_mcp.py"],
"env": {
"VAULT_PATH": "/path/to/vault",
"DB_PATH": "/path/to/vectors.db"
}
}
}
}
HTTP — MCP 서버가 독립형 HTTP 서비스로 실행됩니다. 원격 액세스, 다중 클라이언트 구성, 또는 vault가 공유 서버에 있는 팀 구성에 유용합니다.
{
"mcpServers": {
"obsidian": {
"url": "http://localhost:3333/mcp"
}
}
}
권장 사항: 개인 vault에는 STDIO를 사용하세요. 더 단순하고 안전하며(네트워크에 노출되지 않음), AI 도구가 서버 수명 주기를 관리합니다. 여러 도구 또는 여러 컴퓨터에서 동일한 vault에 동시에 액세스해야 할 때만 HTTP를 사용하세요.
MCP 사양의 발전. 2025년 6월 MCP 사양에는 OAuth 2.1 인증, 구조화된 도구 출력(타입이 지정된 반환 스키마), elicitation(서버가 시작하는 사용자 프롬프트)이 추가되었습니다. 2025년 11월 릴리스에는 1급 전송 모드인 Streamable HTTP, 자동 서버 기능 탐색을 위한
.well-knownURL 검색, 도구가 읽기 전용인지 변경 작업을 수행하는지 선언하는 구조화된 도구 주석, SDK 티어 표준화 시스템이 포함되었습니다.79 다음 개정도 이제 구체화되었습니다. 2026-07-28 사양은 2026년 5월 21일 Release Candidate에 진입했습니다. 이는 출시 이후 가장 큰 MCP 개정입니다. 주요 변경 사항은 stateless 프로토콜 코어(initialize핸드셰이크와Mcp-Session-Id헤더가 제거되어 서버가 연결별 세션 상태를 더 이상 추적하지 않음), MCP Apps(서버가 sandboxed 클라이언트 iframe에 표시되는 서버 렌더링 HTML를 반환할 수 있음), experimental core에서 공식 확장으로 승격된 Tasks(장기 실행 작업을 위한tasks/get,tasks/update,tasks/cancel), 강화된 OAuth 2.0 / OIDC 인증, 12개월 기능 지원 중단 수명 주기 정책입니다. 이는 일정대로 2026년 7월 28일 개정으로 출시되었으며, 현재 Current 사양입니다(2026년 8월 14일 확인).24 개인 vault 서버에는 STDIO가 여전히 가장 단순한 경로이며, stateless 코어 덕분에 단일 사용자 STDIO 서버는 더 가벼워졌습니다. Streamable HTTP 전송,.well-known검색, MCP Apps는 주로 다중 테넌트 라우팅과 로드 밸런싱을 사용하는 엔터프라이즈 HTTP 배포에 유용합니다. 전송 선택에 영향을 주는 업데이트는 MCP 로드맵에서 확인하세요.
기능 설계
MCP 서버는 최소한의 도구 세트를 노출해야 합니다.
search — 기본 도구입니다. hybrid retrieval을 실행하고 순위가 매겨진 결과를 반환합니다.
{
"name": "obsidian_search",
"description": "Search the Obsidian vault using hybrid BM25 + vector retrieval",
"parameters": {
"query": { "type": "string", "description": "Search query" },
"limit": { "type": "integer", "default": 5 },
"max_tokens": { "type": "integer", "default": 2000 }
}
}
read_note — 경로로 특정 노트의 전체 콘텐츠를 읽습니다. 에이전트가 검색 결과의 전체 맥락을 확인하려 할 때 유용합니다.
{
"name": "obsidian_read_note",
"description": "Read the full content of a note by file path",
"parameters": {
"file_path": { "type": "string", "description": "Relative path within vault" }
}
}
list_notes — 필터(폴더, 태그, 유형 또는 날짜 범위)를 기준으로 일치하는 노트를 나열합니다. 에이전트에 구체적인 쿼리가 없을 때 탐색에 유용합니다.
{
"name": "obsidian_list_notes",
"description": "List notes matching filters",
"parameters": {
"folder": { "type": "string", "description": "Folder path within vault" },
"tag": { "type": "string", "description": "Tag to filter by" },
"limit": { "type": "integer", "default": 20 }
}
}
get_context — 검색을 실행하고 대화에 삽입하기 적합한 context 블록으로 결과를 형식화하는 편의 도구입니다.
{
"name": "obsidian_get_context",
"description": "Get formatted context from vault for a topic",
"parameters": {
"topic": { "type": "string", "description": "Topic to get context for" },
"max_tokens": { "type": "integer", "default": 2000 }
}
}
권한 경계
MCP 서버는 엄격한 경계를 적용해야 합니다.
-
읽기 전용. 서버는 vault와 index database를 읽습니다. 노트를 생성, 수정 또는 삭제하지 않습니다. 새 노트 캡처 같은 쓰기 작업은 MCP 서버가 아닌 별도의 hooks 또는 skills에서 처리합니다.
-
Vault 범위 제한. 서버는 구성된 vault 경로 내의 파일만 읽습니다. 경로 탐색 시도(
../../etc/passwd)는 거부해야 합니다. -
credential 필터링 출력. database에 이미 필터링된 콘텐츠가 있더라도, 심층 방어 조치로 출력 시 credential 필터링을 적용하세요.
-
토큰 제한 응답. AI 도구가 지나치게 큰 context 블록을 받지 않도록 모든 도구 응답에
max_tokens를 적용하세요.
오류 처리
MCP 도구는 AI 도구의 복구를 돕는 구조화된 오류 메시지를 반환해야 합니다.
def search(self, query, limit=5, max_tokens=2000):
if not self.db_path.exists():
return {
"error": "Index database not found. Run the indexer first.",
"suggestion": "python index_vault.py --full"
}
results = self.retriever.search(query, limit, max_tokens)
if not results:
return {
"results": [],
"message": f"No results found for '{query}'. Try broader terms."
}
return {
"results": [
{
"file_path": r["file_path"],
"section": r["section"],
"text": r["chunk_text"],
"score": round(r["rrf_score"], 4),
}
for r in results
],
"count": len(results),
"query": query,
}
Claude Code 통합
Claude Code은 Obsidian 검색 시스템의 주요 소비자입니다. 이 섹션에서는 MCP 설정, hook 통합, obsidian_bridge.py 패턴을 다룹니다.
MCP 설정
claude mcp add로 사용자 지정 서버를 등록하세요(사용자 범위는 ~/.claude.json에 기록되고, -s project는 공유 가능한 .mcp.json에 기록됩니다. ~/.claude/settings.json은 MCP 설정 위치가 아닙니다):
claude mcp add obsidian -s user \
-e VAULT_PATH=/absolute/path/to/vault \
-e DB_PATH=/absolute/path/to/vectors.db \
-- python /path/to/obsidian_mcp.py
직접 작성하고 싶다면, 이에 해당하는 .mcp.json 항목은 다음과 같습니다.
{
"mcpServers": {
"obsidian": {
"command": "python",
"args": ["/path/to/obsidian_mcp.py"],
"env": {
"VAULT_PATH": "/absolute/path/to/vault",
"DB_PATH": "/absolute/path/to/vectors.db"
}
}
}
}
설정을 추가한 뒤 Claude Code을 다시 시작하세요. MCP 서버는 하위 프로세스로 시작됩니다. 실행 중인지 확인하세요.
> What tools do you have from the obsidian MCP server?
Claude Code에는 사용 가능한 도구(obsidian_search, obsidian_read_note 등)가 표시되어야 합니다.
Hook 통합
Hook은 정의된 수명 주기 지점에서 Claude Code의 동작을 확장합니다. Obsidian 통합과 관련된 hook은 2개입니다.
Hook은 설정에서 등록됩니다(~/.claude/settings.json의 hooks 키 아래에 이벤트 이름과 matcher를 지정). 또한 stdin으로 JSON 페이로드를 받습니다. Claude Code이 자동으로 검색하는 hooks 디렉터리는 없으며, 도구 세부 정보는 $1/$2 인수로 전달되지 않습니다.
UserPromptSubmit hook — 프롬프트를 제출할 때 vault를 조회하고 관련 컨텍스트를 주입합니다(이 이벤트의 stdout은 대화에 추가됩니다).
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [{ "type": "command", "command": "/path/to/obsidian-context.sh" }]
}
]
}
}
#!/bin/bash
# obsidian-context.sh — read the JSON payload from stdin
PROMPT=$(jq -r '.prompt // empty')
[ -z "$PROMPT" ] && exit 0
CONTEXT=$(python /path/to/retriever.py search "$PROMPT" --limit 3 --max-tokens 1500)
if [ -n "$CONTEXT" ]; then
printf 'Relevant vault context:\n%s\n' "$CONTEXT" # stdout -> added as context
fi
PostToolUse hook — 중요한 도구 출력을 나중에 검색할 수 있도록 vault에 다시 저장합니다(관심 있는 도구에서만 실행되도록 matcher와 함께 등록합니다).
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|Bash",
"hooks": [{ "type": "command", "command": "/path/to/capture-insight.sh" }]
}
]
}
}
#!/bin/bash
# capture-insight.sh — tool name and response arrive as stdin JSON
PAYLOAD=$(cat)
TOOL_NAME=$(printf '%s' "$PAYLOAD" | jq -r '.tool_name')
OUTPUT=$(printf '%s' "$PAYLOAD" | jq -r '.tool_response // "" | tostring')
if [ ${#OUTPUT} -gt 500 ]; then
python /path/to/capture.py --text "$OUTPUT" --source "claude-code-$TOOL_NAME"
fi
obsidian_bridge.py 패턴
브리지 모듈은 hook과 skill이 호출할 수 있는 Python API을 제공합니다.
# obsidian_bridge.py
from retriever import HybridRetriever
_retriever = None
def get_retriever():
global _retriever
if _retriever is None:
_retriever = HybridRetriever(
db_path="/path/to/vectors.db",
vault_path="/path/to/vault",
)
return _retriever
def search_vault(query, limit=5, max_tokens=2000):
"""Search vault and return formatted context."""
retriever = get_retriever()
results = retriever.search(query, limit, max_tokens)
if not results:
return ""
lines = ["## Vault Context\n"]
for r in results:
lines.append(f"**{r['file_path']}** — {r['section']}")
lines.append(f"> {r['chunk_text'][:500]}")
lines.append("")
return "\n".join(lines)
/capture Skill
인사이트를 vault에 다시 저장하는 Claude Code skill입니다.
/capture "OAuth token rotation requires both access and refresh token invalidation"
--domain security
--tags oauth,tokens
이 skill은 적절한 frontmatter와 함께 00-inbox/에 새 노트를 만들고 증분 reindex를 실행하므로, 새 노트를 즉시 검색할 수 있습니다.
사용자 지정 명령 패턴
Claude Code skill은 vault 작업을 이름이 지정된 명령으로 감쌀 수 있습니다. 실무자들은 vault를 읽기 소스이자 쓰기 대상으로 다루는 Obsidian 전용 명령 라이브러리를 구축했습니다.
신호 스캔. /scan-intel 명령은 외부 소스를 조회하고 개인 연구 관심사에 따라 발견 항목을 점수화한 뒤, 기준을 통과한 신호를 frontmatter가 포함된 vault 노트로 작성합니다.
/scan-intel --topics "agent infrastructure, security" --lookback 7d
이 명령은 설정된 소스(arXiv, HN, RSS)에서 데이터를 가져오고, 점수 모델(관련성, 실행 가능성, 깊이, 권위)을 적용한 뒤, 통과한 신호를 주제별 vault 폴더에 작성합니다. vault는 자동화된 인텔리전스 파이프라인의 다운스트림 소비자가 됩니다.
Captain’s log. /captains-log 명령은 모든 리포지터리의 일일 git 활동을 집계하고, 내린 결정, 깨달은 점, 열린 스레드를 포함한 구조화된 저널 항목을 vault에 작성합니다.
/captains-log
이 명령은 GitHub에서 commit 기록을 가져와 리포지터리별로 그룹화하고, 서술형 저널 항목으로 구성합니다. 시간이 지나면 일일 로그는 무엇을 출시했고 그 이유가 무엇인지 검색할 수 있는 기록을 만듭니다.
Obsidian 캡처. /obsidian-capture 명령은 현재 Claude Code 세션에서 나온 인사이트를 가져와 적절한 metadata와 함께 vault에 직접 작성합니다.
/obsidian-capture "SAST gates in agent loops increase security degradation"
--folder AI-Tools --tags security,agents
이 패턴은 모든 vault 작업으로 확장할 수 있습니다. 예를 들어 MOC 생성, 프로젝트 상태 노트 업데이트, 관련 신호 연결, 누적된 일일 로그로 주간 다이제스트 생성 등이 있습니다.
커뮤니티 사례. 실무자들은 명령 라이브러리를 공개하고 있습니다. 한 개발자는 일일 검토, 프로젝트 계획, 연구 캡처, 콘텐츠 워크플로를 다루는 22개의 맞춤형 Obsidian + Claude Code 명령을 공유했습니다.1 또 다른 개발자는 코드 분석을 바탕으로 vault에 다이어그램 노트를 생성하는 “Visual Explainer” skill을 만들었습니다.2 명령은 다양하지만 아키텍처는 일관됩니다. Claude Code skill이 인터페이스가 되고, vault 노트가 저장 계층이 되며, 검색 인프라가 쿼리 엔진이 됩니다.
Context Window 관리
통합 시 Claude Code의 context window를 고려해야 합니다.
- 쿼리당 주입 컨텍스트를 1,500~2,000 token으로 제한하세요. 이보다 많으면 agent의 작업 메모리와 경쟁하게 됩니다.
- 출처 정보를 포함하세요. agent가 출처를 참조할 수 있도록 항상 파일 경로와 섹션 제목을 포함하세요.
- chunk 텍스트를 잘라내세요. 긴 chunk는 완전히 생략하지 말고
...로 잘라내야 합니다. 보통 처음 300~500자가 핵심 정보를 담고 있습니다. - 모든 프롬프트에 주입하지 마세요. 주입은 stdout이 모델에 도달하는 이벤트인
UserPromptSubmit을 통해 실행되므로, 이 지점에서 예산을 관리해야 합니다. 짧은 대화형 프롬프트는 건너뛰고, 프롬프트에서 코드, 파일 또는 과거 결정을 언급할 때만 주입하며, 주입 블록에 상한을 두세요. PreToolUse 같은 도구 범위 이벤트는 게이트 처리나 로깅에 사용할 수 있지만 stdout은 모델에 도달하지 않습니다.
Codex CLI 통합
Codex CLI는 config.toml을 통해 MCP 서버에 연결합니다. 통합 패턴은 설정 문법과 지침 전달 방식에서 Claude Code과 다릅니다.
MCP 설정
~/.codex/config.toml에 추가하세요(Codex는 $CODEX_HOME/config.toml을 읽으며, 프로젝트 수준 지침은 프로젝트 설정 파일이 아닌 AGENTS.md에 작성해야 합니다).
[mcp_servers.obsidian]
command = "python"
args = ["/path/to/obsidian_mcp.py"]
[mcp_servers.obsidian.env]
VAULT_PATH = "/absolute/path/to/vault"
DB_PATH = "/absolute/path/to/vectors.db"
AGENTS.md 패턴
Codex CLI는 프로젝트 수준 지침으로 AGENTS.md를 읽습니다. vault 검색 지침을 포함하세요.
## Available Tools
### Obsidian Vault (MCP: obsidian)
Use the `obsidian_search` tool to find relevant context from the knowledge base.
Search the vault when you need:
- Background on a concept or pattern
- Prior decisions or rationale
- Reference material for implementation
Example queries:
- "authentication patterns in FastAPI"
- "how does the review aggregator work"
- "sqlite-vec configuration"
Claude Code과의 차이점
| 기능 | Claude Code | Codex CLI |
|---|---|---|
| MCP 설정 | claude mcp add → ~/.claude.json / 프로젝트 .mcp.json |
~/.codex/config.toml |
| Hooks | 설정 등록 방식, 31개 수명 주기 이벤트, stdin JSON | 지원됨(안정적인 인터페이스, 자체 이벤트 세트) |
| Skills | ~/.claude/skills/ |
~/.codex/skills/(안정적) |
| 지침 파일 | CLAUDE.md |
AGENTS.md |
| 권한 인터페이스 | 모드: Manual / acceptEdits / auto(Pro/Max/Team에서는 2026년 8월 14일부터 기본값) / plan / bypassPermissions | 승인 정책 untrusted / on-request / never × sandbox read-only / workspace-write / danger-full-access(--full-auto는 v0.147.0에서 제거됨) |
핵심 차이점: 이제 두 도구 모두 hooks와 skills를 지원하지만 형태는 다릅니다. Codex는 Claude Code의 권한 모드 대신 승인 정책을 OS 수준 sandbox 모드와 결합하며, hook 이벤트도 다릅니다. 패턴을 이식하세요. 즉, 작업 전에 vault를 조회하고 작업 후에 캡처하되 설정 자체를 그대로 옮기지는 마세요. Codex에서 지속적인 search-the-vault-first 지침을 둘 올바른 위치는 여전히 AGENTS.md입니다.
Cursor 및 기타 도구
MCP을 지원하는 Cursor 및 기타 AI 도구는 동일한 Obsidian MCP 서버에 연결할 수 있습니다. 이 섹션에서는 일반적인 도구의 설정 방법을 다룹니다.
Cursor
프로젝트 루트의 .cursor/mcp.json에 다음을 추가하세요.
{
"mcpServers": {
"obsidian": {
"command": "python",
"args": ["/path/to/obsidian_mcp.py"],
"env": {
"VAULT_PATH": "/absolute/path/to/vault",
"DB_PATH": "/absolute/path/to/vectors.db"
}
}
}
}
Cursor의 .cursorrules 파일에는 vault를 사용하도록 지시하는 내용을 포함할 수 있습니다.
When working on implementation tasks, search the Obsidian vault
for relevant context before writing code. Use the obsidian_search
tool with descriptive queries about the concept you're implementing.
호환성 매트릭스
| 도구 | MCP 지원 | 전송 방식 | 설정 위치 |
|---|---|---|---|
| Claude Code | 전체 | STDIO | claude mcp add → ~/.claude.json / 프로젝트 .mcp.json |
| Codex CLI | 전체 | STDIO | ~/.codex/config.toml |
| Cursor | 전체 | STDIO | .cursor/mcp.json |
| Windsurf | 전체 | STDIO | ~/.codeium/windsurf/mcp_config.json |
| Continue.dev | 전체 | STDIO + HTTP | ~/.continue/config.yaml (mcpServers) |
| Zed | 전체 (context servers) | STDIO | settings.json (context_servers) |
| Claudian (Obsidian plugin) | 해당 없음 (내장) | Claude Code CLI | Obsidian plugin 설정 |
| Agent Client (Obsidian plugin) | 해당 없음 (내장) | ACP | Obsidian plugin 설정 |
MCP을 지원하지 않는 도구를 위한 대안
MCP을 지원하지 않는 도구의 경우 retriever를 CLI로 감쌀 수 있습니다.
# Search from command line
python retriever_cli.py search "query text" --limit 5
# Output formatted for copy-paste into any tool
python retriever_cli.py context "query text" --format markdown
CLI는 모든 AI 도구의 입력란에 수동으로 붙여 넣을 수 있는 구조화된 텍스트를 출력합니다. MCP 통합만큼 깔끔하지는 않지만 어디서나 사용할 수 있습니다.
구조화된 노트에서 Prompt Caching 만들기
vault의 구조화된 노트는 AI 상호작용 전반에서 토큰 사용량을 줄이는 재사용 가능한 컨텍스트 블록으로 활용할 수 있습니다. 이 섹션에서는 캐시 키 설계와 token budget 관리 방법을 다룹니다.
패턴
매 상호작용마다 컨텍스트를 검색하는 대신, 잘 구조화된 vault 노트로 컨텍스트 블록을 미리 만들고 캐시합니다.
# cache_keys.py
CONTEXT_BLOCKS = {
"auth-patterns": {
"vault_query": "authentication patterns implementation",
"max_tokens": 1500,
"ttl_hours": 24, # Rebuild daily
},
"api-conventions": {
"vault_query": "API design conventions REST patterns",
"max_tokens": 1000,
"ttl_hours": 168, # Rebuild weekly
},
"project-architecture": {
"vault_query": "current project architecture decisions",
"max_tokens": 2000,
"ttl_hours": 12, # Rebuild twice daily
},
}
캐시 무효화
캐시 무효화는 다음 2가지 신호를 기반으로 합니다.
- TTL 만료. 각 컨텍스트 블록에는 time-to-live가 있습니다. TTL이 만료되면 vault를 다시 쿼리해 블록을 다시 생성합니다.
- Vault 변경 감지. indexer가 캐시된 컨텍스트 블록에 기여한 파일의 변경을 감지하면 해당 블록은 즉시 무효화됩니다.
Token Budget 관리
세션은 전체 컨텍스트 budget으로 시작합니다. 캐시된 블록은 그 budget의 일부를 사용합니다.
Total context budget: 8,000 tokens
├─ System prompt: 1,500 tokens
├─ Cached blocks: 3,000 tokens (pre-loaded)
├─ Dynamic search: 2,000 tokens (on-demand)
└─ Conversation: 1,500 tokens (remaining)
캐시된 블록은 세션 시작 시 로드됩니다. 동적 검색 결과는 쿼리별로 남은 budget을 채웁니다. 이 hybrid 방식은 agent에게 자주 필요한 컨텍스트의 기준선을 제공하면서도 구체적인 쿼리를 위한 budget을 보존합니다.
캐싱 전후 토큰 사용량
캐싱 없이: 관련 쿼리마다 vault 검색이 실행되어 1,500-2,000토큰의 컨텍스트를 반환합니다. 세션에서 10개의 쿼리를 실행하면 agent는 vault 컨텍스트에 15,000-20,000토큰을 사용합니다.
캐싱 사용: 미리 생성한 컨텍스트 블록 3개는 총 4,500토큰을 사용합니다. 추가 검색은 고유 쿼리마다 1,500-2,000토큰을 더합니다. 10개 쿼리 중 6개가 캐시된 블록으로 처리되면 agent는 4,500 + (4 * 1,500) = 10,500토큰을 사용합니다. 이는 캐싱하지 않았을 때 사용량의 대략 절반입니다.
상세한 출력의 압축 요약 캡처하기
도구 출력은 상세할 수 있습니다. 예를 들어 stack trace, 파일 목록, 테스트 결과 등이 있습니다. hook은 모델이 이미 본 내용을 줄일 수 없습니다. PostToolUse가 실행될 때는 전체 출력이 이미 context window에 들어가 있으며, hook이 출력하는 내용으로 이를 대체할 수 없습니다. hook이 할 수 있는 일은 압축된 요약을 vault에 기록하는 것입니다. 그러면 이후 세션에서는 5,000토큰짜리 원본을 다시 실행하거나 읽는 대신 2줄짜리 결론을 검색할 수 있습니다. 이는 세션 간 메모리를 위한 캡처 패턴으로 봐야 하며, 세션 내 컨텍스트 절약 방법은 아닙니다. 세션 내에서는 /compact, 범위를 정한 프롬프트, 덜 상세한 출력을 요청하는 것이 실질적인 방법입니다.
문제
테스트를 실행하는 Bash 도구 호출은 다음을 반환할 수 있습니다.
PASSED tests/test_auth.py::test_login_success
PASSED tests/test_auth.py::test_login_failure
PASSED tests/test_auth.py::test_token_refresh
PASSED tests/test_auth.py::test_session_expiry
... (200 more lines)
FAILED tests/test_api.py::test_rate_limit_exceeded
전체 출력은 5,000토큰이지만, 핵심 신호는 2줄에 있습니다. 200개 통과, 1개 실패입니다.
Hook 구현
Bash matcher를 사용하는 PostToolUse에 등록합니다(설정에 등록되며, stdin JSON — 위의 Hook Integration 참고).
#!/bin/bash
# summarize-and-capture.sh — write a compressed summary to the vault
PAYLOAD=$(cat)
OUTPUT=$(printf '%s' "$PAYLOAD" | jq -r '.tool_response // "" | tostring')
# Only summarize large outputs
[ ${#OUTPUT} -lt 2000 ] && exit 0
if printf '%s' "$OUTPUT" | grep -q "PASSED\|FAILED"; then
PASSED=$(printf '%s' "$OUTPUT" | grep -c "PASSED")
FAILED=$(printf '%s' "$OUTPUT" | grep -c "FAILED")
SUMMARY="Tests: $PASSED passed, $FAILED failed"
[ "$FAILED" -gt 0 ] && SUMMARY="$SUMMARY
$(printf '%s' "$OUTPUT" | grep 'FAILED')"
python /path/to/capture.py --text "$SUMMARY" --source "test-run-summary"
fi
exit 0
각 hook 호출은 새 프로세스이므로 재귀 방어 장치가 필요 없습니다. hook 자체의 쓰기 작업은 다시 hook을 실행하지 않으며, export된 변수도 다음 호출까지 유지되지 않습니다.
압축 휴리스틱
| 출력 유형 | 감지 | 압축 전략 |
|---|---|---|
| 테스트 결과 | PASSED / FAILED 키워드 |
통과/실패 수를 세고 실패 항목만 표시 |
| 파일 목록 | 명령의 ls 또는 find |
처음 20개 항목과 전체 개수만 표시 |
| Stack trace | Traceback 키워드 |
첫 번째와 마지막 frame 및 오류 메시지 유지 |
| Git 상태 | modified: / new file: |
상태별 개수 요약 |
| 빌드 출력 | warning: / error: |
info 줄을 제거하고 warning/error 유지 |
신호 수집 및 분류 파이프라인
수집 계층은 어떤 정보가 vault에 들어오는지 결정합니다. 선별하지 않으면 vault에는 잡음이 쌓입니다. 이 섹션에서는 신호를 도메인 폴더로 전달하는 점수 산정 파이프라인을 다룹니다.
소스
신호는 여러 채널에서 들어옵니다.
- RSS 피드: 기술 블로그, 보안 권고, 릴리스 노트
- Web Clipper를 통한 북마크: 공식 Obsidian Web Clipper 확장 프로그램(Chrome, Firefox, Safari)은 브라우저에서 콘텐츠를 캡처할 때 가장 충실도가 높은 수집 경로입니다. 2026년 4월 릴리스 주기에서 AI 워크플로에 훨씬 더 유용해졌습니다.22
- 1.4.0 (4월 9일): 대화형 YouTube 트랜스크립트 UI — 동영상을 고정하고, 트랜스크립트를 훑어보고, 자동 스크롤하며, 현재 위치를 강조할 수 있습니다. 또한 원클릭 캡처를 바로 Reader 모드로 보내는 기본 “Open in Reader” 기능도 추가되었습니다.
- 1.5.0–1.5.1 (4월 15일): 하이라이트 뷰어 — vault 전체에서 캡처한 하이라이트를 탐색하고 검색할 수 있습니다. Reader로 전환할 때 페이드인 효과가 적용됩니다. YouTube 재생/일시 정지도 더 부드러워졌습니다. 1.5.1에서는 webpack 컴파일 회귀 문제가 수정되었습니다.
- 1.6.0–1.6.2 (4월 21일~23일): 모바일 지원을 포함한 Highlighter UX 개편이 이루어졌습니다. Defuddle 0.18은 LinkedIn, Threads, Bluesky, Discourse, Medium용 소스별 추출기를 추가합니다. 1.6.2에서는 Safari 임베디드 모드의 클립보드 회귀 문제가 수정되었습니다. 소스 도메인별로 템플릿을 구성하면 YouTube 트랜스크립트, GitHub README, 긴 형식의 아티클이 각각 적절한 이름의 노트에 저장되며, 아래 점수 산정 파이프라인에 필요한 frontmatter도 함께 적용됩니다.
- 뉴스레터: 이메일 뉴스레터에서 발췌한 핵심 내용
- 수동 캡처: 읽기, 대화 또는 조사 중에 작성한 노트
- 도구 출력: hooks를 통해 캡처한 중요한 AI 도구 출력
- iOS Share Extension: Obsidian의 iOS 앱은 2026년 초 업데이트를 통해 Safari, 소셜 네트워크 및 기타 앱의 콘텐츠를 Obsidian을 열지 않고도 vault에 바로 저장하는 Share Extension을 제공합니다. 1.13 라인에는
url을 포함한 템플릿 변수를 갖춘 구성 가능한 Share Sheet 대상이 추가되어, 캡처한 페이지의 소스 링크를 frontmatter에 자동으로 기록할 수 있습니다.19 따라서 모바일에서 마찰 없이 정보를 수집할 수 있습니다. Safari에서 아티클을 공유하면 점수 산정 준비가 된 vault 노트로 들어옵니다. - Obsidian CLI: Shell 스크립트와 hooks는
obsidian file create로 노트를 만들거나obsidian file append로 기존 노트에 내용을 추가할 수 있어, 데스크톱에서 자동화된 수집 파이프라인을 구성할 수 있습니다.
점수 산정 기준
각 신호는 4개 기준에서 각각 0.0~1.0점으로 평가됩니다.
| 기준 | 질문 | 낮은 점수 (0.0-0.3) | 높은 점수 (0.7-1.0) |
|---|---|---|---|
| 관련성 | 현재 활성 도메인과 관련이 있나요? | 부수적이거나 범위를 벗어남 | 현재 작업과 직접 관련됨 |
| 활용 가능성 | 이 정보를 활용할 수 있나요? | 순수 이론, 적용 방법 없음 | 적용할 수 있는 구체적인 기법 또는 패턴 |
| 깊이 | 콘텐츠가 얼마나 충실한가요? | 헤드라인, 얕은 요약 | 예시를 포함한 상세 분석 |
| 권위 | 소스의 신뢰도는 어느 정도인가요? | 익명 블로그, 검증되지 않음 | 1차 소스, 동료 심사, 인정받은 전문가 |
종합 점수 및 라우팅
composite = (relevance * 0.35) + (actionability * 0.25) +
(depth * 0.25) + (authority * 0.15)
| 점수 범위 | 작업 |
|---|---|
| 0.55+ | 도메인 폴더로 자동 라우팅 |
| 0.40 - 0.55 | 수동 검토 대기열에 추가 |
| < 0.40 | 삭제(저장하지 않음) |
도메인 라우팅
0.55점을 넘는 신호는 키워드 매칭과 토픽 분류에 따라 12개 도메인 폴더 중 하나로 라우팅됩니다.
05-signals/
├── ai-tooling/ # Claude, LLMs, AI development tools
├── security/ # Vulnerabilities, auth, cryptography
├── systems/ # Architecture, distributed systems
├── programming/ # Languages, patterns, algorithms
├── web/ # Frontend, backends, APIs
├── data/ # Databases, data engineering
├── devops/ # CI/CD, containers, infrastructure
├── design/ # UI/UX, product design
├── mobile/ # iOS, Android, cross-platform
├── career/ # Industry trends, hiring, growth
├── research/ # Academic papers, whitepapers
└── other/ # Signals that don't fit a domain
운영 통계
14개월간 운영한 결과입니다.
| 지표 | 값 |
|---|---|
| 처리한 총 신호 수 | 7,771 |
| 자동 라우팅(>0.55) | 4,832 (62%) |
| 검토 대기열(0.40-0.55) | 1,543 (20%) |
| 삭제(<0.40) | 1,396 (18%) |
| 활성 도메인 폴더 | 12 |
| 일평균 신호 수 | ~18 |
Knowledge Graph 패턴
Obsidian의 wiki-link 그래프는 노트 간 관계를 인코딩합니다. 이 섹션에서는 링크 의미 체계, 컨텍스트 확장을 위한 그래프 탐색, 그래프 품질을 떨어뜨리는 안티패턴을 다룹니다.
Backlink 의미 체계
모든 wiki-link는 그래프에 방향성이 있는 간선을 만듭니다. Obsidian은 정방향 링크와 backlink를 모두 추적합니다.
- 정방향 링크: 노트 A에
[[Note B]]가 있음 → A가 B에 연결됨 - Backlink: 노트 B에서 노트 A가 이를 참조하고 있음을 표시함
그래프는 컨텍스트에 따라 서로 다른 유형의 관계를 인코딩합니다.
| 링크 패턴 | 의미 | 예시 |
|---|---|---|
| 인라인 링크 | “관련이 있음” | “자세한 내용은 [[OAuth Token Rotation]]을 참조하세요” |
| 헤더 링크 | “하위 주제가 있음” | ”## Related\n- [[Token Rotation]]\n- [[Session Management]]” |
| 태그형 링크 | “다음으로 분류됨” | ”[[type/reference]]” |
| MOC 링크 | “일부임” | 관련 노트를 나열하는 Maps of Content 노트 |
Maps of Content (MOCs)
MOC는 관련 노트를 탐색 가능한 구조로 정리하는 인덱스 노트입니다.
---
title: "Authentication & Security MOC"
type: moc
domain: security
---
## Core Concepts
- [[OAuth 2.0 Overview]]
- [[JWT Token Anatomy]]
- [[Session Management Patterns]]
## Implementation Patterns
- [[OAuth Token Rotation]]
- [[Refresh Token Security]]
- [[PKCE Flow Implementation]]
## Failure Modes
- [[Token Expiry Handling]]
- [[Session Fixation Prevention]]
- [[CSRF Defense Strategies]]
MOC는 두 가지 방식으로 검색 성능을 높입니다.
- 직접 일치. “authentication overview”를 검색하면 MOC 자체와 일치하여, 에이전트에 관련 노트의 선별된 목록을 제공합니다.
- 컨텍스트 확장. 특정 노트를 찾은 뒤 retriever는 해당 노트가 MOC에 포함되어 있는지 확인하고 결과에 MOC 구조를 포함할 수 있습니다. 그러면 에이전트는 더 넓은 주제의 지도를 얻습니다.
컨텍스트 확장을 위한 그래프 탐색
retriever에 추가할 수 있는 향후 개선 사항입니다. 상위 결과를 찾은 후 링크를 따라가며 컨텍스트를 확장합니다.
def expand_context(results, depth=1):
"""Follow wiki-links from top results to find related context."""
expanded = set()
for result in results:
# Parse wiki-links from chunk text
links = extract_wiki_links(result["chunk_text"])
for link_target in links:
# Resolve link to file path
target_path = resolve_wiki_link(link_target)
if target_path and target_path not in expanded:
expanded.add(target_path)
# Include target's most relevant chunk
target_chunks = get_chunks_for_file(target_path)
# ... rank and include best chunk
return results + list(expanded_results)
현재 retriever에는 구현되어 있지 않지만, 그래프 구조를 자연스럽게 확장하는 방법입니다.
안티패턴
고립된 클러스터. 서로 연결되어 있지만 vault의 나머지 부분과는 연결되지 않은 노트 그룹입니다. Obsidian의 그래프 패널에서는 이런 그룹이 분리된 섬처럼 보입니다. 고립된 클러스터는 MOC 또는 도메인 간 링크가 누락되었음을 나타냅니다.
태그 확산. 태그를 일관성 없이 사용하거나 지나치게 세분화된 태그를 너무 많이 만드는 경우입니다. 5,000개 노트에 고유 태그가 500개인 vault는 태그 10개당 평균 노트 1개에 불과합니다. 이 태그는 필터링에 쓸모가 없습니다. 도메인 폴더에 매핑되는 상위 수준 태그 20~50개로 통합하세요.
링크는 많고 콘텐츠는 적은 노트. 산문 없이 wiki-link만으로 이루어진 노트입니다. chunker가 embeddings할 텍스트가 없으므로 이런 노트는 인덱싱 성능이 좋지 않습니다. 연결한 노트가 왜 관련 있는지 설명하는 컨텍스트를 최소한 한 문단 추가하세요.
모든 항목에 양방향 링크 사용. 모든 참조가 wiki-link일 필요는 없습니다. “OAuth”을 언급한다고 해서 [[OAuth 2.0 Overview]]가 반드시 필요한 것은 아닙니다. 링크를 클릭했을 때 유용한 컨텍스트를 제공하는, 의도적이고 탐색 가능한 관계에만 wiki-link를 사용하세요.
개발자 Workflow Recipes
Vault 검색을 일상적인 개발 작업과 결합하는 실용적인 workflow입니다.
아침 Context 로드
관련 context를 불러오며 하루를 시작하세요.
Search my vault for notes about [current project] updated in the last week
Retriever는 현재 작업 중인 프로젝트에 대한 최근 노트를 반환해, 어디까지 진행했는지 빠르게 다시 파악할 수 있게 해줘요. 어제의 commit 메시지를 다시 읽는 것보다 더 효과적입니다.
Coding 중 Research 캡처
기능을 구현하는 동안 editor를 벗어나지 않고 insight를 캡처하세요.
/capture "FastAPI dependency injection with async generators requires yield,
not return. The generator is the dependency lifecycle."
--domain programming
--tags fastapi,dependency-injection
캡처된 insight는 즉시 색인되어 나중에 검색할 수 있어요. 몇 달이 지나면 이런 작은 캡처들이 구현에 특화된 지식 corpus로 쌓입니다.
Project 시작
새 프로젝트나 기능을 시작할 때는 다음을 수행하세요.
- Vault를 검색하세요. “[technology/pattern]에 대해 내가 알고 있는 것은 무엇인가?”
- 상위 5개 결과를 검토해 이전 결정과 주의할 점을 확인하세요
- 해당 domain에 MOC가 있는지 확인하고, 없다면 새로 만드세요
- 실패 mode를 검색하세요. “[technology]의 문제점”
Vault Search로 Debugging하기
오류나 예상치 못한 동작을 만났을 때는 다음을 사용하세요.
Search my vault for [error message or symptom]
이전 debugging 노트에는 root cause와 fix가 들어 있는 경우가 많아요. 프로젝트 전반에서 반복되는 문제에 특히 유용합니다. Vault는 사용자가 잊은 내용을 기억해요.
Code Review 준비
PR을 review하기 전에 다음을 실행하세요.
Search my vault for patterns and conventions about [module being changed]
Vault는 review 대상 code와 관련된 이전 결정, architecture 제약, coding standards를 반환해요. Review는 단순히 diff만 보는 것이 아니라 조직의 축적된 지식을 바탕으로 진행됩니다.
Performance Tuning
이 섹션에서는 다양한 vault 크기와 사용 패턴에 맞는 최적화 전략을 다뤄요.
Index 크기 관리
| Vault 크기 | Chunks | DB 크기 | 전체 Reindex | 증분 |
|---|---|---|---|---|
| 500개 노트 | ~1,500 | 3 MB | 15초 | <1초 |
| 2,000개 노트 | ~6,000 | 12 MB | 45초 | 2초 |
| 5,000개 노트 | ~15,000 | 30 MB | 2분 | 4초 |
| 15,000개 노트 | ~50,000 | 83 MB | 4분 | <10초 |
| 50,000개 노트 | ~150,000 | 250 MB | 15분 | 30초 |
50,000개 이상의 노트에서는 다음을 고려하세요. - 더 빠른 embedding을 위해 batch size를 64에서 128로 늘리기 - 동시 access를 위해 WAL mode(기본값) 사용하기 - 사용량이 적은 시간에 전체 reindex 실행하기
Query 최적화
WAL mode. SQLite의 Write-Ahead Logging mode는 indexer가 쓰는 동안에도 동시에 읽을 수 있게 해줘요.
db.execute("PRAGMA journal_mode=WAL")
Indexer가 증분 update를 실행하는 동안 MCP 서버가 query를 처리해야 할 때 이 설정은 중요해요.
Connection pooling. MCP 서버는 query마다 새 connection을 여는 대신 database connection을 재사용해야 해요. WAL mode를 사용하는 하나의 오래 유지되는 connection만으로도 동시 read를 지원할 수 있습니다.
# MCP server initialization
db = sqlite3.connect(DB_PATH, check_same_thread=False)
db.execute("PRAGMA journal_mode=WAL")
db.execute("PRAGMA mmap_size=268435456") # 256 MB mmap
Memory-mapped I/O. mmap_size pragma는 SQLite에 database 파일에 memory-mapped I/O를 사용하라고 지시해요. 83 MB database라면 전체 파일을 memory에 mapping해 대부분의 disk read를 제거할 수 있습니다.
FTS5 최적화. 전체 reindex 후에는 다음을 실행하세요.
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');
이 작업은 FTS5의 내부 b-tree segment를 병합해 이후 search의 query latency를 줄여요.
Scaling Benchmark
Apple M3 Pro, 36 GB RAM, NVMe SSD에서 측정했습니다.
| Operation | 500개 노트 | 5K 노트 | 15K 노트 | 50K 노트 |
|---|---|---|---|---|
| BM25 query | 2ms | 5ms | 12ms | 25ms |
| Vector query | 1ms | 3ms | 8ms | 20ms |
| RRF fusion | <1ms | <1ms | 3ms | 5ms |
| Full search | 3ms | 8ms | 23ms | 50ms |
모든 benchmark에는 database access, query execution, result formatting이 포함돼요. MCP STDIO 통신의 network latency는 1-2ms가 추가됩니다.
Troubleshooting
Index Drift
증상: Search가 오래된 결과를 반환하거나 최근 추가된 노트를 찾지 못합니다.
원인: 노트를 추가한 뒤 incremental indexer가 실행되지 않았거나, 파일의 mtime이 update되지 않았습니다. 예를 들어 timestamp를 유지한 채 다른 machine에서 sync된 경우입니다.
해결: 전체 reindex를 실행하세요. python index_vault.py --full
Embedding Model 교체
증상: Embedding model을 변경한 뒤 vector search가 말이 안 되는 결과를 반환합니다.
원인: 이전 model의 old vector가 새 query vector와 비교되고 있습니다. Dimension이나 vector space semantics가 호환되지 않습니다.
해결: Indexer가 model hash mismatch를 감지해 자동으로 전체 reindex를 트리거해야 해요. 그렇지 않다면 database를 수동으로 지우고 reindex하세요.
rm vectors.db
python index_vault.py --full
FTS5 유지 관리
증상: 많은 incremental update 이후 FTS5 query가 부정확하거나 불완전한 결과를 반환합니다.
원인: 많은 작은 update 후 FTS5 내부 segment가 fragmented 상태가 될 수 있습니다.
해결: Rebuild하고 optimize하세요.
INSERT INTO chunks_fts(chunks_fts) VALUES('rebuild');
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');
MCP Timeout
증상: AI tool이 MCP 서버 timeout을 보고합니다.
원인: 첫 query가 model loading(lazy initialization)을 트리거하며, 이 작업은 2-5초가 걸립니다. AI tool의 기본 MCP timeout이 이보다 짧을 수 있습니다.
해결: Server startup 시 model을 미리 warm-up하세요.
# In MCP server initialization
retriever = HybridRetriever(db_path, vault_path)
retriever.search("warmup", limit=1) # Trigger model load
SQLite File Locks
증상: SQLITE_BUSY 또는 SQLITE_LOCKED 오류가 발생합니다.
원인: 여러 process가 동시에 database에 쓰고 있습니다. WAL mode는 동시 read를 허용하지만 writer는 하나만 허용합니다.
해결: 하나의 process(indexer)만 database에 쓰도록 하세요. MCP 서버와 hooks는 read만 해야 합니다. Concurrent write가 필요하다면 WAL mode를 사용하고 busy timeout을 설정하세요.
db.execute("PRAGMA busy_timeout=5000") # Wait up to 5 seconds
sqlite-vec가 로드되지 않음
증상: Vector search가 disabled되고 retriever가 BM25-only mode로 실행됩니다.
원인: sqlite-vec extension이 설치되지 않았거나, library path에서 찾을 수 없거나, SQLite version과 호환되지 않습니다.
해결:
# Install via pip
pip install sqlite-vec
# Or compile from source
git clone https://github.com/asg017/sqlite-vec
cd sqlite-vec && make
Extension이 로드되는지 확인하세요.
import sqlite3
db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
db.load_extension("vec0")
print("sqlite-vec loaded successfully")
대형 Vault Memory 문제
증상: 대형 vault(50,000개 이상 노트)를 전체 reindex하는 동안 out-of-memory 오류가 발생합니다.
원인: Embedding batch size가 너무 크거나, 모든 file content가 동시에 memory에 로드됩니다.
해결: Batch size를 줄이고 file을 incremental하게 처리하세요.
BATCH_SIZE = 32 # Reduce from 64
또한 indexer가 모든 file을 memory에 로드하는 대신, file을 하나씩 처리하는지 확인하세요. 즉, 각 file을 읽고, chunking하고, embedding한 뒤 다음 file로 넘어가야 합니다.
Migration Guide
Apple Notes에서 이전하기
- “Export All” option(macOS)으로 Apple Notes를 export하거나
apple-notes-liberator같은 migration tool을 사용하세요 markdownify또는pandoc을 사용해 HTML exports를 markdown으로 변환하세요- 변환된 file을 vault의
00-inbox/폴더로 이동하세요 - 각 노트를 review하고 frontmatter를 추가하세요
- 노트를 적절한 domain 폴더로 이동하세요
Notion에서 이전하기
- Notion에서 export하세요. Settings → Export → Markdown & CSV
- Export 파일의 압축을 vault의
00-inbox/폴더에 푸세요 - Notion 전용 markdown artifact를 수정하세요.
- Notion은 checklist에
- [ ]를 사용합니다. 이는 standard markdown입니다 - Notion은 property table을 HTML으로 포함합니다. 이를 YAML frontmatter로 변환하세요
- Notion은 image를 relative path로 embed합니다. Image를 attachments folder로 복사하세요
- Standard frontmatter(
type,domain,tags)를 추가하세요 - Notion page link를 Obsidian wiki-links로 바꾸세요
Google Docs에서 이전하기
- Google Takeout을 사용해 모든 document를 export하세요
.docxfile을 markdown으로 변환하세요.pandoc -f docx -t markdown input.docx -o output.md- Batch convert를 실행하세요.
for f in *.docx; do pandoc -f docx -t markdown "$f" -o "${f%.docx}.md"; done - Vault로 이동하고, frontmatter를 추가한 뒤 folder로 정리하세요
일반 Markdown에서 이전하기(Obsidian 없음)
이미 markdown file directory가 있다면 다음을 수행하세요.
- 해당 directory를 Obsidian vault로 여세요. Obsidian → Open Vault → Open folder
- Directory가 version-controlled 상태라면
.obsidian/을.gitignore에 추가하세요 - Frontmatter template을 만들고 기존 file에 적용하세요
- 읽고 정리하면서
[[wiki-links]]로 노트를 연결하기 시작하세요 - Indexer를 즉시 실행하세요. Retrieval system은 첫날부터 작동합니다
다른 Retrieval System에서 이전하기
다른 embedding/search system에서 migration하는 경우:
- Vector를 migration하려고 하지 마세요. 서로 다른 model은 호환되지 않는 vector space를 생성합니다. 새 model로 전체 reindex를 실행하세요.
- Index가 아니라 content를 migration하세요. Vault file이 source of truth입니다. Index는 파생 artifact입니다.
- Migration 후 verify하세요. 답을 알고 있는 query 10-20개를 실행하고, 결과가 기대와 일치하는지 확인하세요.
변경 이력
| 날짜 | 변경 사항 | 출처 |
|---|---|---|
| 2026-08-14 | 첫 종합 게이트 감사 — 전체 가이드를 평가자가 검토했으며, R1은 CRITICAL 3건과 MAJOR 5건을 포함해 8.29점을 받았습니다. 모두 이 행에서 수정했습니다. CRITICAL 항목은 독자에게 피해를 줄 수 있었습니다. 빠른 시작에서는 npm obsidian-mcp-server를 “가장 간단한 파일 기반 옵션”으로 설치하도록 안내했지만, 해당 패키지는 cyanheads의 REST-API 기반 서버입니다(Local REST API 플러그인과 OBSIDIAN_API_KEY 필요, --vault 플래그 없음). 파일 기반 서버는 npm obsidian-mcp(StevenStavrakis)입니다. 서버 표에도 같은 이름 충돌이 있었으며, 두 항목 모두 명시적인 npm 이름으로 수정했습니다. 두 Claude Code MCP 설정 블록은 Claude Code이 조용히 무시하는 ~/.claude/settings.json의 mcpServers를 안내하고 있었습니다. 이를 claude mcp add(사용자 범위 → ~/.claude.json)로 다시 작성하고 .mcp.json 프로젝트 범위 변형을 추가했으며, 호환성 매트릭스 셀도 수정했습니다. hook 예시는 위치 인수 $1/$2와 Claude Code에 존재한 적 없는 ~/.claude/hooks/pre-tool-use/ 자동 검색 디렉터리를 사용하고 있었습니다. 이를 jq로 stdin JSON를 읽는 설정 등록 hook으로 다시 작성했습니다. 컨텍스트 주입은 stdout이 실제로 컨텍스트에 추가되는 UserPromptSubmit으로 옮겼습니다. 또한 “PostToolUse 컨텍스트 압축” 섹션의 전제(모델이 보는 내용을 hook이 줄일 수 있다는 것)는 불가능하므로, 세션 간 재사용을 위해 압축 요약을 vault에 저장하는 방식으로 바꿨습니다. 불필요한 재귀 방지 장치도 제거했습니다(각 hook 호출은 새 프로세스입니다). MAJOR 항목: 1.13.4 → 1.13.7(manifest 검증, stable과 beta가 수렴함). MCP의 2026-07-28 사양 메모는 출시 후 17일이 지나도록 “최종 사양은 7월 28일 출시”라고 되어 있었습니다. Current 개정판으로 출시된 사실에 맞게 과거형으로 바꿨고, 9는 24을 가리키는 역사적 항목으로 다시 작성했습니다. Codex 비교는 제거된 suggest/auto-edit/full-auto 승인 모드와 “hooks/skills 미지원”을 안내하고 있었습니다. 둘 다 2026년 중반부터 안정적인 Codex 기능이므로 표와 단락을 다시 구성했습니다(CC 셀은 이제 8월 14일 자동 기본값을 포함한 실제 권한 모드를 명시합니다). Zed/Continue/Windsurf 매트릭스 행도 새로 고쳤습니다. 경미한 변경: .codex/config.toml 프로젝트 변형을 제거했습니다($CODEX_HOME 전용). mcpvault는 0.12.4 → 0.15.0으로 업데이트했고, 만료된 “as of” 기준점은 절대 날짜로 바꿨으며, 약속했던 1.13 iOS Share Sheet url 변수 통합도 수집 섹션에 반영했습니다. R2 검증에서는 수정 가장자리에 남은 흔적을 발견해 두 번째 패스에서 고쳤습니다. 빠른 시작의 Codex/Cursor 블록은 여전히 이름 충돌 바이너리를 호출하고 있었으므로, 세 도구 모두 설치된 패키지의 v2 문법에 맞춰 npx -y obsidian-mcp@2 serve로 변경했습니다. 다시 작성한 hook 섹션 아래에 PreToolUse가 컨텍스트를 주입한다는 문장이 하나 남아 있어 제거했고(주입 안내는 이제 일관되게 UserPromptSubmit을 사용합니다), 한 줄짜리 오류 4건(괄호 불균형, 오래된 1.13.4 참조, 13의 버전, 9에 남아 있던 로드맵 문장)도 수정했습니다. |
24 26 |
| 2026-08-07 | Obsidian 1.13이 공개 채널에 도달했습니다. 1.13.4는 2026년 7월 30일에 승격되었습니다(desktop-releases.json의 latestVersion 1.13.4, beta.latestVersion 1.13.6으로 manifest 검증). 본문의 “공개 채널은 1.12.7로 유지”라는 참조 3곳을 업데이트했습니다. 이제 일반 공개된 1.13 라인에는 설정 개편(별도 창, 이름/설명 검색, 키보드 + Vim 탐색), 파일별 탐색 및 Live Preview 크기 조절을 지원하는 전체 화면 이미지 뷰어, 검색 가능한 Bookmarks, Sync 다중 선택이 포함됩니다. 이 가이드 독자와 가장 관련 있는 변경은 Obsidian URI 보안입니다. obsidian:// 작업은 이제 허용 목록에 없으면 확인 대화 상자가 필요합니다. 이 가이드의 자동화 흐름은 MCP와 CLI를 사용하므로 영향을 받지 않습니다. 다만 URIs를 통해 Obsidian을 제어하는 모든 워크플로(Shortcuts, 스크립트, 기타 실행 도구)는 작업을 한 번 허용 목록에 추가해야 하며, 그렇지 않으면 매번 프롬프트가 표시됩니다. 개발자 관련 변경으로는 마이그레이션 가이드가 포함된 새 Settings API, 호환성이 깨지는 --callout-color 변경(이제 RGB 세 쌍이 아니라 유효한 CSS 색상이 필요하므로 테마와 스니펫을 업데이트해야 함), Electron 43.1.1, CodeMirror 및 Mermaid 11.13.0 업그레이드가 있습니다. AI, MCP, CLI 변경은 없습니다. Catalyst 추적은 1.13.6으로 이동합니다. |
26 |
| 2026-07-27 | 릴리스 점검 및 권고 수정. MCPVault는 7월 23일 같은 날 패치 3건을 통해 0.12.1 → 0.12.4로 이동했습니다. 7월 22일 점검에서 모두 누락된 이유는 다음 날에 배포되었기 때문입니다. v0.12.3은 wiki_link 도구를 추가합니다. [[Document Name]], [[Name\|Display]], 표에서 이스케이프된 형식, #fragment 형식을 해석하고, 내용과 해석된 경로 및 모호한 대안을 반환합니다. 또한 기본 경로 필터를 통해 모든 도구에서 .trash/를 제외합니다. v0.12.4는 이를 경로가 포함된 [[folder/Note]] 링크까지 확장합니다. v0.12.2는 patch_note가 $ 패턴 삽입을 손상시키는 문제를 수정하고, vault 접두사가 붙은 경로를 정규화하며, npm audit의 높은 심각도 문제를 해소합니다. MCP 서버 섹션과 [^24]는 이제 세 버전을 모두 설명합니다. 정정: 2026-07-07 행은 v0.12.1이 “중간 심각도의 경로 필터 권고 2건을 포함한다”고 했지만 사실이 아닙니다. GitHub Advisory API는 GHSA-9c83-rr99-vfwj의 취약 범위를 < 0.11.5, GHSA-j99q-93c9-h869를 < 0.11.4로 명시합니다. 둘 다 0.12 라인이 시작되기 전에 패치되었으므로, 해당 행이 작성될 당시 0.12.1은 이미 문제가 없었습니다. 본문과 각주에는 “현재 릴리스를 실행하세요”라는 표현이 열린 노출을 암시하지 않도록, 이제 최초 패치 버전을 명시합니다. 또한 Obsidian 1.13.4 desktop + mobile(7월 27일)은 Catalyst early access입니다. desktop-releases.json manifest는 여전히 latestVersion 1.12.7 및 beta.latestVersion 1.13.4를 보고하므로 공개 채널은 변하지 않았고, 여기의 버전 참조도 유지됩니다. 내용은 UX 수준의 변경(라이트박스 파일명 표시, Live Preview 이미지 정렬 및 여백, 멈춘 파일 저장 race, 설정 레이아웃)이며 AI, MCP, CLI 변경은 없습니다. |
13 26 |
| 2026-07-22 | 릴리스 점검, 워크플로 변경 없음. Obsidian 1.13.3 desktop + mobile(7월 21일)은 Catalyst early access 전용입니다. manifest 검증 결과 공개 채널은 1.12.7로 유지됩니다. 내용은 UX 수준(이미지 임베드 라이트박스/확대, Live Preview 줄 높이 수정, File Recovery 화살표 키, unique URI paneType 수정)이며 AI/MCP/CLI 변경은 없습니다. Catalyst 추적은 1.13.2 → 1.13.3으로 올립니다. 참고: 1.13.3은 해당 날짜의 점검이 끝난 뒤인 7월 21일 늦게 게시되었으므로, 이전 행의 “새 릴리스 없음”은 작성 당시 정확했습니다. Web Clipper 1.7.1(7월 22일, GitHub 릴리스): Import highlights, {{model}}/{{modelId}}/{{modelProvider}} Interpreter 템플릿 변수, 새로 고친 provider presets, Defuddle 0.19.2, 최근 Anthropic 모델을 위한 Interpreter 수정, 네이티브 Gemini API 키, DeepSeek 및 Azure OpenAI 처리가 포함됩니다. 스토어 배포는 GitHub 날짜보다 늦을 수 있습니다. 공식 MCP 서버 소식은 없으며 stateless 사양은 여전히 7월 28일 예정입니다. |
26 |
| 2026-07-21 | 정확성 수정: 공개 desktop 채널은 1.13.1이 아니라 1.12.7입니다. 2026-06-10 항목과 이후 본문 참조는 1.13.1을 공개 채널 릴리스로 취급했습니다. 그러나 1.13.1 changelog 페이지에는 Early access 배지가 있고, 공식 자동 업데이트 manifest(obsidianmd/obsidian-releases, desktop-releases.json)는 공개 latestVersion 1.12.7과 beta 채널의 1.13.2를 나열합니다. 전체 1.13.x 라인은 Catalyst 전용입니다. 본문 참조와 26를 수정했습니다. 2026-07-17 → 2026-07-21 릴리스 점검에서는 새 릴리스를 찾지 못했습니다. core는 1.13.2 Catalyst, Clipper는 1.7.0으로 유지되며, 공식 MCP 서버 소식은 없고 MCP stateless 사양은 여전히 7월 28일 예정입니다. |
26 |
| 2026-07-17 | 릴리스 점검, 워크플로 변경 없음. Obsidian 1.13.2(7월 14일)는 Catalyst early-access 전용입니다. 공개 채널은 1.13.1로 유지되므로 여기의 버전 참조도 현재 상태입니다. 가이드와 인접한 변경 한 가지는 iOS Share Sheet 템플릿의 새 url 변수입니다(공유된 링크를 노트에 삽입함). 1.13.2가 공개되면 캡처 경로 섹션에 반영할 예정입니다. Web Clipper 1.7.0(6월 16일, 이전에 확인되지 않음): Defuddle 0.19.0 업그레이드, {{content}}가 이제 ==highlight== 마커를 보존하며, highlights가 라이브 페이지와 Reader 보기 사이에서 유지됩니다. 공식 Obsidian MCP 서버나 AI 통합은 발표되지 않았으며, MCP 사양의 stateless 릴리스는 여전히 7월 28일 예정입니다. obsidian.md/changelog, github.com/obsidianmd/obsidian-clipper releases, blog.modelcontextprotocol.io를 기준으로 검증했습니다. |
|
| 2026-07-07 | 정확성 수정. MCPVault는 자체 프로젝트(npm @bitbonsai/mcpvault, repo bitbonsai/mcpvault)임을 명확히 했으며, 현재 v0.12.1입니다. 중간 심각도의 경로 필터 권고 2건(GHSA-9c83-rr99-vfwj, GHSA-j99q-93c9-h869)을 포함합니다. 이전 [^24] 링크는 잘못된 repo(MarkusPfundstein/mcp-obsidian)를 가리키고 있었습니다. MarkusPfundstein/mcp-obsidian의 상태도 수정했습니다. 이는 활발히 유지 관리되고 있으며(2026년 5월 15일까지 커밋, search_by_tag/get_frontmatter 추가), “2025년 6월부터 휴면” 상태가 아닙니다. 여전히 태그된 릴리스는 제공하지 않습니다. GitHub commit history, GitHub Security Advisories, npm을 기준으로 검증했습니다. |
|
| 2026-07-06 | 검색 용이성을 위한 편집 구조 변경: “Quick Start: First AI-Connected Vault”의 제목을 Obsidian MCP Setup(anchor #obsidian-mcp-setup)으로 바꾸고, MCP Server Architecture 섹션에 흩어져 있던 “연결 후 Claude가 할 수 있는 일” 기능 요약(검색, 읽기, 목록, 서식 있는 컨텍스트, 쓰기는 hooks가 처리하는 읽기 전용 경계)을 통합했습니다. 새 사실은 없으며 내부 링크를 업데이트했습니다. |
|
| 2026-06-10 | 버전 최신성 업데이트. Obsidian 1.13.1 desktop이 공개 채널에 도달했습니다(2026년 6월 9일). 이는 1.13.0 대비 설정 UX + CodeMirror 업그레이드이며 주요 AI/자동화 변경은 없습니다. 현재 버전 본문 참조를 1.13.0에서 1.13.1(공개, 2026년 6월 9일)로 옮겼습니다. | 26 |
| 2026-06-09 | 생태계 업데이트. MCP 2026-07-28 사양이 Release Candidate에 진입했습니다(2026년 5월 21일 발표). 이는 출시 이후 가장 큰 MCP 개정으로, stateless protocol core(initialize handshake와 Mcp-Session-Id 제거), MCP Apps(sandboxed iframes의 서버 렌더링 HTML), experimental core에서 공식 extension으로 승격되는 Tasks, OAuth 2.0/OIDC 강화, 12개월 deprecation-lifecycle 정책(최종 사양 2026년 7월 28일)을 포함합니다. MCP Spec Evolution 메모의 추정적인 “잠정적으로 2026년 중반” 로드맵 표현을 구체적인 RC로 대체했습니다. sqlite-vec v0.1.10-alpha(2026년 3월 31일 – 5월 18일)는 brute-force KNN을 넘어 approximate-nearest-neighbor index 유형(rescore, experimental ivf, disk-based DiskANN)을 추가합니다. 0.1.10 라인이 아직 pre-release이므로 향후/experimental 항목으로 표시했습니다. Obsidian 1.13.0 desktop(early access, 2026년 5월 28일)을 본문 전체의 현재 버전으로 업데이트했습니다. 이는 새 AI/자동화 기능이 없는 UX/보안/dev-tooling 릴리스입니다. |
24 23 25 |
| 2026-06-08 | 유지 관리 점검. Model2Vec v0.8.2(2026년 5월 29일)가 출시되었습니다. 학습용 frozen-weights 옵션, multiword-token 수정, 학습 리팩터링, non-quantized weight 처리 수정을 포함한 유지 관리 릴리스입니다. 각주를 업데이트했습니다. 기존 기준선보다 새로운 항목은 없습니다. Obsidian 최신 버전은 여전히 1.13.0(5월 28일, 아래에 이미 문서화됨)이고, sqlite-vec stable은 여전히 v0.1.9(v0.1.10은 여전히 alpha)이며, MCP 사양은 여전히 2025-11-25 개정판입니다. Model2Vec 버전 메모 외에 본문 변경은 없습니다. | 10 |
| 2026-05-28 | Obsidian 1.13.0 desktop + 1.13.0 mobile(Catalyst early-access)이 출시되었습니다. Desktop: 자체 창에서 열리고 내장 검색 및 키보드 탐색을 제공하는 개편된 Settings 패널, 작업 실행 전 확인 대화 상자를 표시하는 Obsidian URIs, 네트워크 드라이브에서 HTML 리소스를 로드하기 전의 새 경고, Bookmarks 보기의 Search, 향상된 editor 이미지 처리, File Explorer / Properties / Sync 개선, 다수의 개발자 API 및 버그 수정이 포함됩니다. Mobile: 구성 가능한 대상 위치가 있는 새 iOS Share Sheet, tab switcher에서의 탭 순서 변경, 분할 및 고정된 sidebar 크기 조절을 위한 tablet 길게 누르기 동작, table 보기에서 열 크기를 조절하는 Bases 메뉴 항목, iOS 및 search 버그 수정이 포함됩니다. AI 워크플로에 미치는 영향: Obsidian URIs의 확인 대화 상자는 URI 기반 MCP/agent 통합에 의도적인 게이트를 추가합니다. Bases 열 크기 조절 메뉴는 Bases를 agents가 쿼리하는 vault-front index로 더 유용하게 만듭니다. iOS Share Sheet의 구성 가능한 대상은 이미 기본 수집 경로로 문서화된 iPhone 캡처 경로를 Claude/Codex pipelines에 더 빠르게 연결할 수 있게 합니다. | |
| 2026-05-06 | 출처 검증된 최신성 갱신: Smart Connections v4.5.0은 footer connections를 Core로 옮겼습니다. sqlite-vec v0.1.8/v0.1.9 stable 릴리스는 packaging 및 DELETE 동작을 업데이트했습니다. Model2Vec v0.8.x는 tokenizer/persistence 내부와 benchmark tables를 업데이트했습니다. Obsidian CLI 연대기를 “1.12.7이 CLI를 도입”에서 “1.12.0이 CLI를 도입했고, 1.12.7은 설치/runtime packaging을 개선”으로 바로잡았습니다. | |
| 2026-04-27 | Web Clipper 4월 주기: 1.4.0(interactive YouTube transcript UI + Open in Reader 기본값), 1.5.0(Highlights viewer), 1.6.0(Highlighter UX 개편 + LinkedIn/Threads/Bluesky/Discourse/Medium용 Defuddle 0.18 source extractors), 1.6.1 + 1.6.2(Reader 및 Safari 수정). Web Clipper를 단순한 bookmark 언급이 아니라 AI 워크플로의 기본 browser-side 수집 경로로 재구성했습니다. 해당 기간에 Obsidian desktop, Sync 또는 Bases 릴리스는 없었습니다. | |
| 2026-04-16 | Smart Connections v4.3.0(graph view, 구성 가능한 dock, block-embedding recovery, Substrate cross-plugin env). 2026년 4월 AI-native plugin 물결(Cortex, VaultSearch, LLM Wiki, Drift, EngramQuest, Hybrid Search MCP)을 문서화했습니다. MarkusPfundstein/mcp-obsidian을 maintenance-mode(마지막 커밋 2025년 6월)로 표시했습니다. Dataview는 휴면 상태이며 Bases가 새 작업의 후속 도구입니다. Obsidian CLI 1.12.7은 계속 AI assistants를 위한 선호 bridge입니다. |
|
| 2026-04-01 | Obsidian CLI 섹션(v1.12의 AI 워크플로 명령)을 추가했습니다. agent plugin 섹션(Claudian, Agent Client)을 추가했습니다. vault 구성을 위한 Bases core plugin을 문서화했습니다. plugin 수를 2,500+로 업데이트했습니다. iOS Share Extension을 수집 소스로 추가했습니다. embedded agent plugins를 포함하도록 호환성 매트릭스를 업데이트했습니다. | |
| 2026-03-30 | MCPVault v0.11.0: list_all_tags 도구, .base/.canvas 지원, @bitbonsai/mcpvault로 이름 변경. Obsidian Desktop v1.12.7은 더 빠른 terminal interactions를 위해 CLI binary를 번들로 제공합니다. |
|
| 2026-03-23 | sqlite-vec v0.1.7 stable을 문서화했습니다. vec0 tables의 DELETE 지원, pagination을 위한 KNN distance constraints가 포함됩니다. 예정된 릴리스용 DiskANN approximate nearest neighbor index가 발표되었습니다. | |
| 2026-03-07 | embedding model 비교에 potion-multilingual-128M(101개 언어, 2025년 5월)을 추가했습니다. sqlite-vec은 v0.1.7-alpha.10(CI/CD 수정, 기능 변경 없음)입니다. MCP 사양과 retrieval 기법이 최신 상태임을 확인했습니다. | |
| 2026-03-03 | MCP spec evolution을 업데이트했습니다(2025년 11월 출시: Streamable HTTP, .well-known, tool annotations). Model2Vec fine-tuning 및 BPE/Unigram tokenizer 지원을 추가했습니다. 커뮤니티 MCP server 비교 표를 추가했습니다. Smart Connections를 v4로 업데이트했습니다. | |
| 2026-03-02 | model 비교에 potion-base-32M 및 potion-retrieval-32M을 추가했습니다. quantization/dimensionality reduction 섹션을 추가했습니다. MCP spec evolution 메모를 추가했습니다. | |
| 2026-03-01 | 최초 릴리스 |
참고 자료
-
Internet Vin, “Claude Code와 Obsidian에서 사용하는 22가지 명령,” 2026년 3월, x.com/internetvin/status/2026461256677245131. ↩
-
Nicopreme, slash 명령이 포함된 “Visual Explainer” agent skill, x.com/nicopreme/status/2023495040258261460. ↩
-
Cormack, G.V., Clarke, C.L.A., 및 Buettcher, S. Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods. SIGIR, 2009. 순위가 매겨진 목록을 결합하는 매개변수 없는 방법으로 k=60을 사용하는 RRF를 소개합니다. ↩↩↩
-
OpenAI Embeddings Pricing. text-embedding-3-small: 토큰 100만 개당 $0.02. 전체 재색인 시 예상 vault 비용: 약 $0.30. ↩
-
van Dongen, T. 외. Model2Vec: Turn any Sentence Transformer into a Small Fast Model. arXiv, 2025. sentence transformer에서 static embeddings를 생성하는 distillation 접근 방식을 설명합니다. ↩
-
potion-base-8M Model Card 및 Model2Vec results. 현재 공개된 표에 따르면 potion-base-8M은 51.32 Avg (All) / 51.08 Avg (MTEB)이고, all-MiniLM-L6-v2는 55.80 Avg (All) / 55.93 Avg (MTEB)입니다. 즉, 전체 작업 점수에서 약 92%를 유지합니다. ↩
-
Model Context Protocol Specification. AI 도구를 데이터 소스에 연결하기 위한 MCP 표준입니다. ↩
-
Model2Vec Potion Models, potion-base-32M, 및 potion-retrieval-32M. 현재 model card에 따르면 potion-base-32M은 52.83 Avg (All), potion-retrieval-32M은 retrieval 표에서 35.06을 기록합니다. ↩↩↩
-
Update on the Next MCP Protocol Release. 역사적으로 2025년 11월 릴리스에는 Streamable HTTP transport, .well-known URL discovery, structured tool annotations, 그리고 SDK tier 표준화가 포함되었습니다. 여기서 예고한 릴리스 주기는 2026년 7월 28일 개정판인 Current specification으로 마무리되었습니다(참조 24). ↩↩↩
-
Model2Vec Releases. v0.4.0(2025년 2월): training/fine-tuning 지원. v0.5.0(2025년 4월): backend 재작성, quantization, dimensionality reduction. v0.7.0(2025년 10월): vocabulary quantization, BPE/Unigram tokenizer 지원. v0.8.0/v0.8.1(2026년 3월): tokenizer 및 persistence 리팩터링, Python 3.9 지원 중단, MTEB V2 결과 업데이트, Windows path 호환성. v0.8.2(2026년 5월 29일): training용 frozen-weights 옵션과 multiword-token 수정, training 리팩터링, non-quantized weight 처리 수정을 추가한 유지보수 릴리스입니다. ↩↩↩
-
Smart Connections for Obsidian. Smart Connections v4: local-first AI embeddings를 제공하며, 초기 indexing 후에는 semantic search가 오프라인에서도 작동합니다. ↩
-
potion-multilingual-128M. Minish Lab, 2025년 5월. 101개 언어용 static embedding 모델이며, 성능이 가장 뛰어난 multilingual static embeddings입니다. 다른 potion 모델과 동일하게 numpy만 의존합니다. ↩
-
MCPVault —
bitbonsai/mcpvault. npm@bitbonsai/mcpvault, 최신 버전은 v0.15.0(2026-08-09 게시)입니다. 0.12.2–0.12.4 릴리스는 모두 2026-07-23에 배포되었습니다(0.12.2는 09:51, 0.12.4는 10:10. 0.12.3은 그 사이 repository changelog에 표시되지만 npm에는 게시되지 않았습니다).MarkusPfundstein/mcp-obsidian과는 별개의 프로젝트이며, 이름을 바꾼 프로젝트가 아닙니다. v0.11.0(2026년 3월)에서는 count와 함께 frontmatter 및 hashtags를 검색하는list_all_tags도구, 개선된 dotted-folder 처리,.base/.canvas파일 지원을 추가했습니다. 0.12.2–0.12.4의 내용은 유일한 릴리스 기록인 repository CHANGELOG.md에서 가져왔습니다. 이 repo의 GitHub releases endpoint는 빈 목록을 반환하므로, npm 게시 시각과 changelog가 주요 출처입니다. 0.12.2:patch_note가$',$&,$`,$$를 확장하지 않고newString을 문자 그대로 삽입합니다(issue #149 / PR #153). vault 접두사가 붙은 absolute 또는~/스타일 path를 vault-relative로 정규화합니다(issue #122 / PR #151). lockfile만 업데이트하여 npm audit의 high-severity 항목을 해결했습니다(PR #154). 0.12.3: 새wiki_link도구(PR #101)를 추가하고, 기본 path filter를 통해 모든 도구에서.trash/를 제외했습니다. 0.12.4:wiki_link가[[folder/Note]]같은 path-qualified link를 basename이 아닌 전체 vault-relative path로 해석합니다. 두 개의 medium-severity GitHub Security Advisories가 path filter에 영향을 줍니다. GHSA-9c83-rr99-vfwj는 제한된 directory를 vault root에서만 거부하고 중첩된 경로에서는 거부하지 않으며, GHSA-j99q-93c9-h869는 대소문자 및 후행 dot/space 동등성을 통한 deny-list 우회를 허용합니다. GitHub Advisory API에 따르면 취약 범위는 각각< 0.11.5및< 0.11.4이고, 최초 수정 버전은 각각 0.11.5 및 0.11.4입니다. 둘 다 0.12.0보다 앞서므로 0.12.1을 포함한 모든 0.12.x 릴리스는 이미 수정되었습니다. Advisory 범위와 npm timestamp는 2026-08-14에 다시 검증했습니다. ↩↩↩ -
sqlite-vec v0.1.7 Release. 2026년 3월 17일. 안정 릴리스: vec0 virtual table용 DELETE 지원, pagination을 위한 KNN distance constraints, fuzz testing 개선. 향후 릴리스용으로 DiskANN approximate nearest neighbor indexing을 발표했습니다. ↩↩↩
-
Introduction to Bases. Obsidian core plugin은 v1.9.10에서 도입되었습니다. frontmatter properties를 field로 사용해 vault 파일 위에 database와 유사한 view(table, gallery, calendar, kanban board)를 제공합니다. 파일은
.base형식으로 저장됩니다. ↩ -
Obsidian Desktop v1.12.0 Changelog 및 Obsidian Desktop v1.12.7 Changelog. v1.12.0에서는 terminal 기반 vault automation용 CLI를 도입했고, v1.12.7에서는 standalone binary, TUI, socket-file 동작으로 installation/runtime packaging을 개선했습니다. CLI documentation도 참고하세요. ↩↩
-
Claudian. vault에 Claude Code을 AI collaborator로 내장하는 Obsidian plugin입니다. sidebar chat, context-aware prompt, vision 지원, slash command, permission mode를 제공합니다. ↩
-
Agent Client. Agent Client Protocol(ACP)을 통해 Claude Code, Codex CLI, Gemini CLI용 통합 인터페이스를 제공하는 Obsidian plugin입니다. note mention, shell execution, action approval을 지원합니다. ↩
-
Obsidian iOS Changelog. 2026년 초 업데이트에는 다른 앱의 콘텐츠를 vault에 직접 저장하는 Share Extension, Daily Note 및 Bookmark widget 수정, View Note widget 새로고침 개선이 포함됩니다. ↩
-
MarkusPfundstein/mcp-obsidian. 활발히 유지 관리되고 있으며 2026년 5월 15일까지 commit이 있습니다. 최근에는
search_by_tag,get_frontmatter등을 포함한 도구 추가와 확장된 test coverage 작업이 이루어졌습니다(repository의 commit history 및tools.py를 기준으로 검증). tagged release는 여전히 제공하지 않으므로 pinned commit에서 설치하세요. Local-REST-API 기반입니다. forum discussion(2026년 4월)에서는 새 설정에 대해 first-class Obsidian CLI bridge(1.12.x)로 커뮤니티가 이전하는 흐름을 보고하지만, mcp-obsidian은 기존 REST-API deployment를 위한 작동하고 업데이트되는 선택지로 남아 있습니다. ↩↩ -
Smart Connections v4.5.0 Release. 2026년 5월 5일. footer connection이 Core 기능이 되었습니다. 최근 v4 릴리스에는 connection list용 graph view, 구성 가능한 connection-panel 위치, 개선된 block-embedding recovery, Substrate cross-plugin state, transformer fallback 수정, 중복 connection 계산 감소도 포함됩니다. ↩
-
obsidianmd/obsidian-clipper releases — Web Clipper 버전-기능 매핑의 주요 출처입니다. 2026년 4월 주기: 1.4.0(4월 9일, YouTube transcript UI + Open in Reader 기본값), 1.5.0(4월 15일, Highlights viewer + Reader fade-in), 1.5.1(4월 15일, webpack compilation 수정), 1.6.0(4월 21일, Highlighter UX + LinkedIn/Threads/Bluesky/Discourse/Medium extractor가 포함된 Defuddle 0.18), 1.6.1(4월 22일, Reader outline 수정 + highlights search), 1.6.2(4월 23일, Safari embedded-mode clipboard 수정). Mozilla Add-ons store 및 Chrome Web Store에도 교차 등록되어 있습니다. ↩
-
sqlite-vec v0.1.8, sqlite-vec v0.1.9, sqlite-vec v0.1.10-alpha.3, 및 sqlite-vec v0.1.10-alpha.4. v0.1.8은 npm packaging을 수정했고, v0.1.9는 12자보다 긴 metadata text column의 DELETE bug를 수정했습니다. v0.1.10-alpha.3은 적절한
INSERT OR REPLACE INTO지원을 추가합니다. v0.1.10-alpha.4(2026년 5월 18일)는 새로운 ivf/diskann 기능을 사용하는vec0table에서ALTER TABLE RENAME이 실패하는 문제와 DiskANN의 cached-statement cleanup bug를 수정합니다. 0.1.10 계열은 아직 prerelease입니다. ↩↩↩↩↩ -
MCP 2026-07-28 Specification Release Candidate. 2026년 5월 21일에 발표되었고, 최종 spec은 2026년 7월 28일에 배포되었습니다. 출시 이후 가장 큰 MCP 개정입니다. stateless protocol core(
initializehandshake 및Mcp-Session-Idheader 제거), MCP Apps(sandboxed client iframe의 server-rendered HTML), experimental core에서 공식 extension으로 승격된 Tasks(tasks/get,tasks/update,tasks/cancel), OAuth 2.0 / OIDC authorization 강화, 12개월 feature-deprecation lifecycle policy를 포함합니다. ↩↩↩↩↩ -
Obsidian Desktop v1.13.0 Changelog. Early access, 2026년 5월 28일. UX/security/developer-tooling 릴리스입니다. search 및 keyboard navigation을 갖추고 별도 window에서 열리는 개편된 Settings panel, Obsidian URI 실행 전 confirmation dialog, plugin developer용 새 Settings API, flatpak 설치용 CLI 수정이 포함됩니다. 1.12.x CLI surface를 넘어서는 주요 AI/automation 기능은 없습니다. ↩↩↩
-
Obsidian Changelog. Obsidian 1.13.1 desktop은 2026년 6월 9일 Catalyst early-access 릴리스로 배포되었습니다. 1.13.0에 대한 settings-UX 개선 및 CodeMirror upgrade이며, 새로운 AI/automation 기능은 없습니다. 1.13.1 changelog page 자체에는 “Early access” badge가 표시되어 있고, 공식 auto-update manifest(obsidianmd/obsidian-releases, desktop-releases.json)에는 public
latestVersion1.12.7 및 beta channel의 1.13.2가 나열되어 있습니다. 2026-07-21에 검증했습니다. 2026-07-27에 다시 검증한 결과, manifest는 여전히latestVersion1.12.7을 보고했고beta.latestVersion은 1.13.4였습니다.obsidian.md/changelog.xml의 Atom feed는 1.13.1부터 1.13.4까지 모든 1.13.x 항목에 “(Early access)” badge를 표시합니다. 가장 최신 “(Public)” 제목의 항목은 2026-03-23 날짜의 1.12.7이며,obsidian-releasesGitHub release list와 일치합니다. 2026-08-07에 다시 검증한 결과 manifest는 이제latestVersion1.13.4(2026년 7월 30일 public promotion) 및beta.latestVersion1.13.6을 보고합니다. 1.13 계열은 일반적으로 사용할 수 있으며, 위의 historical row는 각 날짜 기준 Catalyst 전용 기간을 정확히 설명합니다. 2026-08-14에 다시 검증한 결과 manifest는latestVersion1.13.7 및beta.latestVersion1.13.7을 보고합니다. stable과 beta가 수렴했습니다. ↩↩↩↩↩↩↩↩↩