Obsidian MCP + ハイブリッド検索:2026年版リファレンス
# アプリの基本は公式のObsidianドキュメントを参照し、MCP、ハイブリッド検索、16,894ファイルのAI vaultのインデックス作成にはBlakeのリファレンスを使います。
Obsidianは単なるノートアプリではありません。ローカルファーストのプレーンテキストで、グラフ構造を持つMarkdownコーパスです。検索基盤を加えることで、AIコンテキストの貯水池になります。 16,894ファイル。49,746チャンク。23msのクエリ。API呼び出しはゼロ。1つの83 MB SQLiteファイル。このガイドでは、vaultアーキテクチャからhybrid検索、MCP連携、運用ワークフローまで、システム全体を扱います。
重要ポイント
メモ取りではなく、Context engineeringです。 AIにとってObsidian vault(保管庫)の価値は、メモそのものではありません。メモを検索可能にするretrieval層にあります。retrievalなしの16,000ファイルのvaultは、書き込み専用データベースです。hybrid検索とMCP連携を備えた200ファイルのvaultは、AI知識ベースになります。retrieval基盤こそがプロダクトです。メモはその原材料です。
Hybrid retrievalは、純粋なキーワード検索や純粋なsemantic searchより優れています。 BM25は、正確な識別子や関数名を捉えます。Vector searchは、用語が違っても同義語や概念的な一致を捉えます。Reciprocal Rank Fusion (RRF)は、スコア調整を必要とせずに両方を統合します。どちらか一方だけでは、両方の失敗パターンをカバーできません。MS MARCOのpassage rankingに関する研究でも、この傾向が確認されています。hybrid retrievalは、単独の手法より一貫して高い性能を示します。3 hybrid retrieverの詳細解説では、RRFの数式、実際の数値を使った例、失敗パターンの分析、対話型のfusion計算機を扱っています。
MCPにより、AIツールがvaultへ直接アクセスできます。 Model Context Protocol (MCP)サーバーは、retrieverをツールとして公開します。Claude Code、Codex CLI、Cursor、その他のAIツールが、そのツールを直接呼び出せます。エージェントはvaultにクエリを投げ、出典付きのランキング結果を受け取り、ファイル全体を読み込まずにコンテキストを利用します。MCPサーバーは、retrieval engineを包む薄いラッパーです。
Local-firstなら、APIコストはゼロで、プライバシーも完全に保てます。 スタック全体は1台のマシン上で動作します。ストレージにはSQLite、embeddingsにはModel2Vec、キーワード検索にはFTS5、vector KNNにはsqlite-vecを使います。クラウドサービスも、API呼び出しも、ネットワーク依存もありません。個人メモがマシンの外へ出ることはありません。49,746チャンクをすべて再embedしても、OpenAI APIの価格ではおよそ$0.30です。しかし本当のコストは、レイテンシー、プライバシーの露出、そして本来オフラインで動くべきシステムがネットワークに依存することです。4
Incremental indexingにより、10秒未満でシステムを最新に保てます。 ファイルの更新時刻を比較して変更を検出します。変更されたファイルだけを再chunkingし、再embeddingします。Apple M-seriesハードウェアでは、完全なreindexに約4分かかります。一般的な1日の編集量であれば、incremental updateは10秒未満で完了します。手動操作なしで、システムを最新状態に保てます。
このアーキテクチャは、200件のメモから20,000件超のメモまでスケールします。 同じ3層設計(intake、retrieval、integration)は、どの規模のvaultでも機能します。小規模なvaultでは、BM25のみの検索から始めます。キーワードの衝突が問題になったらvector searchを追加します。正確な一致とsemanticな一致の両方が必要になったら、RRF fusionを追加します。各層は単独でも有用で、単独で取り外すこともできます。
このガイドの使い方
このガイドでは、システム全体を扱います。どこから始めるべきかは、現在の状況によって異なります。
| 該当する状況 | ここから開始 | 次に読む内容 |
|---|---|---|
| Obsidian + AIが初めて | AI InfrastructureにObsidianを使う理由, Quick Start | Vault Architecture, MCP Server Architecture |
| 既存のvaultがあり、AIアクセスを追加したい | MCP Server Architecture, Claude Code Integration | Embedding Models, Full-Text Search |
| retrieval systemを構築している | The Complete Retrieval Pipeline, Reciprocal Rank Fusion | Performance Tuning, Troubleshooting |
| チームまたはenterprise環境で使う | Decision Framework, Knowledge Graph Patterns | Developer Workflow Recipes, Migration Guide |
Contractと記されたセクションには、実装の詳細、設定ブロック、失敗パターンが含まれます。Narrativeと記されたセクションでは、概念、アーキテクチャ上の判断、デザイン選択の背景にある考え方に焦点を当てます。Recipeと記されたセクションでは、ステップごとのワークフローを示します。
AI InfrastructureにObsidianを使う理由
このガイドの主張は次のとおりです。Obsidian vaultは、個人向けAI知識ベースの土台として最適です。local-firstで、plaintextで、グラフ構造を持ち、ユーザーがスタックのすべての層を制御できるからです。
Obsidianが他の選択肢にはない形でAIに与えるもの
Plaintext markdownファイル。 すべてのメモは、ファイルシステム上の.mdファイルです。独自形式も、データベースエクスポートも、内容を読むためのAPIも必要ありません。ファイルを読めるツールなら、どれでもvaultを読めます。grep、ripgrep、Pythonのpathlib、SQLite FTS5。これらはすべて、ソースファイルに直接作用します。retrieval systemを構築するときにindexingするのは、API responsesではなくファイルです。ソースはファイルシステムなので、indexは常にソースと整合します。
Local-first architecture。 vaultは自分のマシン上にあります。サーバーも、クラウド同期への依存も、APIのレート制限も、自分のコンテンツ処理方法を制限する利用規約もありません。外部サービスなしで、メモをembed、index、chunk、searchできます。これはAI infrastructureにとって重要です。retrieval pipelineの速度は、API endpointの応答速度ではなく、ディスクの速度で決まるからです。プライバシーの面でも重要です。認証情報、健康データ、金融情報、個人的な考察を含むメモが、マシンの外へ出ることはありません。
wiki-linkによるグラフ構造。 Obsidianの[[wiki-link]]構文は、メモ間に有向グラフを作ります。OAuth実装に関するメモは、token rotation、session management、API securityに関するメモへリンクします。グラフ構造には、概念間の関係を人間が整理した結果がエンコードされています。Vector embeddingsはsemanticな類似性を捉えますが、wiki-linksは著者がそのトピックについて考えながら作った意図的なつながりを捉えます。このグラフは、embeddingsでは再現できないシグナルです。
Plugin ecosystem。 Obsidianには2,500以上のcommunity pluginsがあります(2026年3月時点。2025年半ばの1,800以上から増加)。Dataviewは、vaultをデータベースのようにクエリします。Templaterは、JavaScriptロジックを使ってテンプレートからメモを生成します。Git integrationは、vaultをリポジトリへ同期します。Linterは、フォーマットの一貫性を強制します。Bases core plugin(v1.9.10で導入)は、frontmatter propertiesをフィールドとして使い、vaultファイル上にデータベースのようなビュー(テーブル、ギャラリー、カレンダー、kanban boards)を追加します。保存形式は.baseファイルです。15 これらのpluginは、基盤となるplaintext形式を変えずにvaultへ構造を追加します。retrieval systemがindexingするのは、pluginそのものではなく、これらのpluginの出力です。
500万以上のユーザー。 Obsidianには、テンプレート、ワークフロー、plugin、ドキュメントを生み出す大規模で活発なコミュニティがあります。vaultの整理やplugin設定で問題に出会ったとき、誰かがすでに解決策を文書化している可能性が高いです。コミュニティはObsidian周辺ツールも生み出しています。MCP servers、indexing scripts、publishing pipelines、API wrappersなどです。
ファイルシステムだけでは得られないもの
markdownファイルのディレクトリにはplaintextの利点がありますが、Obsidianが追加する次の3つがありません。
-
双方向リンク。 Obsidianはbacklinksを自動で追跡します。Note AからNote Bへリンクすると、Note BにはNote Aが参照元として表示されます。グラフパネルでは、接続クラスターを可視化できます。この双方向の把握は、素のファイルシステムにはないメタデータです。
-
plugin rendering付きのlive preview。 Dataviewクエリ、Mermaid図、callout blocksはリアルタイムにレンダリングされます。保存形式はplaintextのまま、テキストエディタより豊かな執筆体験を得られます。豊かな環境で書き、整理し、retrieval systemは生のmarkdownをindexingします。
-
Community infrastructure。 Plugin discovery、theme marketplace、sync service(任意)、publish service(任意)、ドキュメントエコシステムがあります。個々の機能はスタンドアロンツールでも再現できますが、Obsidianはそれらを一貫したワークフローとしてまとめています。
Obsidianがしないこと(そして構築するもの)
Obsidianにはretrieval infrastructureは含まれていません。基本的な検索(full-text、filename、tag)はありますが、embedding pipeline、vector search、fusion ranking、MCP server、credential filtering、chunking strategy、外部AIツール向けのintegration hooksはありません。このガイドでは、Obsidianの上に構築するinfrastructureを扱います。 vaultは土台です。retrieval pipeline、MCP server、integration hooksがinfrastructureです。
ここで説明するアーキテクチャは、markdown-firstであり、Obsidian専用ではありません。 Logseq、Foam、Dendron、またはmarkdownファイルだけのプレーンなディレクトリを使っている場合でも、retrieval pipelineは同じように機能します。chunkerは.mdファイルを読みます。embedderはテキスト文字列を処理します。indexerはSQLiteへ書き込みます。これらのコンポーネントはいずれもObsidian固有の機能に依存しません。Obsidianの役割は、retrieverがindexingするmarkdownファイルを生み出すための執筆・整理環境を提供することです。
クイックスタート:初めてのAI接続済み保管庫(vault)
このセクションでは、5分で保管庫をAIツールに接続します。Obsidianをインストールし、保管庫を作成し、MCPサーバーをインストールして、最初のクエリを実行します。このクイックスタートでは、すぐに結果を得るためにコミュニティ製のMCPサーバーを使います。後のセクションでは、本番環境向けのカスタム検索パイプラインの構築を扱います。
前提条件
- macOS、Linux、またはWindows
- Node.js 18以上(MCPサーバー用)
- Obsidian 1.12以上(CLI連携用。MCPのみの構成であれば以前のバージョンでも動作します)
- Claude Code、Codex CLI、またはCursorがインストール済み
ステップ1:保管庫を作成する
obsidian.mdからObsidianをダウンロードし、新しい保管庫を作成します。覚えやすい場所を選んでください。MCPサーバーには絶対パスが必要です。
# Example vault location
~/Documents/knowledge-base/
検索対象になるメモをいくつか追加します。10〜20件のメモでも、結果を確認するには十分です。各メモは、意味のあるタイトルと少なくとも1段落の本文を含む.mdファイルにしてください。
ステップ2:MCPサーバーをインストールする
複数のコミュニティ製MCPサーバーを使うと、すぐに保管庫へアクセスできます。このエコシステムは2025〜2026年にかけて大きく成長しました。最近の注目すべき更新として、MCPVault v0.11.0(2026年3月)では、frontmatterとハッシュタグを件数付きでスキャンするlist_all_tags、ドットを含むフォルダー処理の改善、.baseファイルと.canvasファイルのサポートが追加されました。13 また、このパッケージはnpm上で@bitbonsai/mcpvaultに名称変更されています。
2026年4月の変化 — 推奨ブリッジとしてのObsidian CLI: Obsidian 1.12.0で正式なCLIが導入され、公開版1.12.7インストーラー(2026年3月23日)には、スタンドアロンバイナリ、TUI、ソケットファイルの改善が同梱され、ターミナルワークフローのインストールと実行が容易になりました。16 コミュニティツールは、
mcp-obsidianを支えていたLocal REST APIプラグインから、より高速で安定したCLIベースの連携へ積極的に移行しています。MarkusPfundstein/mcp-obsidianリポジトリは2025年6月以降コミットがなく、タグ付きリリースも一度もありません。メンテナンスモードと見なし、CLIベースのサーバー、または下に挙げる新しいコミュニティ代替を優先してください。20 推奨セットアップについては、このガイド後半の「AIワークフロー向けObsidian CLI」セクションをご覧ください。
| サーバー | 作者 | トランスポート | プラグイン要否 | 主な機能 |
|---|---|---|---|---|
| obsidian-mcp-server | StevenStavrakis | STDIO | なし | 軽量、ファイルベース |
| mcp-obsidian | MarkusPfundstein | STDIO | Local REST API | REST経由で保管庫の完全なCRUDに対応 — メンテナンスモード、2025年6月以降コミットなし20 |
| obsidian-mcp-tools | jacksteamdev | STDIO | あり(プラグイン) | セマンティック検索 + Templater |
| obsidian-claude-code-mcp | iansinnott | WebSocket | あり(プラグイン) | Claude Code向け自動検出 |
| obsidian-mcp-server | cyanheads | STDIO | Local REST API | タグ、frontmatter管理 |
| Hybrid Search MCP | community | STDIO | なし | BM25 + セマンティック検索のMCPサーバー + CLI。2026年4月時点で新しく、活発にメンテナンスされています。 |
クイックスタートでは、.mdファイルを直接読み取るファイルベースのサーバーが最も簡単です。
npm install -g obsidian-mcp-server
ステップ3:AIツールを設定する
Claude Code — ~/.claude/settings.jsonに追加します。
{
"mcpServers": {
"obsidian": {
"command": "obsidian-mcp-server",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
Codex CLI — .codex/config.tomlに追加します。
[mcp_servers.obsidian]
command = "obsidian-mcp-server"
args = ["--vault", "/absolute/path/to/your/vault"]
Cursor — .cursor/mcp.jsonに追加します。
{
"mcpServers": {
"obsidian": {
"command": "obsidian-mcp-server",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
ステップ4:最初のクエリを実行する
AIツールを開き、保管庫内のメモで答えられる質問をします。
Search my Obsidian vault for notes about [topic you wrote about]
AIツールはMCPサーバーを呼び出し、サーバーが保管庫を検索して一致する内容を返します。ファイルパスと関連する抜粋を含む結果が表示されるはずです。
ここまでで構築したもの
標準プロトコルを通じて、ローカルのナレッジベースをAIツールに接続しました。MCPサーバーは保管庫内のファイルを読み取り、基本的な検索を実行し、結果を返します。これが最小限の実用版です。
このクイックスタートで得られないもの: - ハイブリッド検索(BM25 + ベクトル検索 + RRF fusion) - embeddingsベースのセマンティック検索 - 認証情報フィルタリング - インクリメンタルインデックス - hookベースの自動コンテキスト注入
このガイドの残りでは、これらの機能を1つずつ構築していきます。クイックスタートは概念実証です。完全なパイプラインでは、本番品質の検索を実現します。
AIワークフロー向けObsidian CLI
Obsidian 1.12(2026年2月)では、AIワークフローの新しい連携面を開く組み込みコマンドラインインターフェースが導入されました。16 CLIはObsidian GUIのリモートコントロールとして機能します。Obsidianが起動している必要があります(初回コマンド時に自動起動することもあります)。Settings > General > Command line interfaceで有効にします。
AIインフラにとってCLIが重要な理由
CLIにより、これまでGUIやプラグインAPIが必要だったObsidianネイティブ操作に、プログラムからアクセスできます。AIワークフローで重要なのは、次の機能です。
- スクリプトやhookからの検索。
obsidian search "query"とobsidian search:context "query"を使うと、任意のシェルスクリプト、hook、自動化パイプラインから保管庫検索を実行できます。search:contextのバリアントは、一致した行とその周辺コンテキストを返すため、AIプロンプトに結果を渡す用途に役立ちます。 - デイリーノートの自動化。
obsidian dailyは今日のデイリーノートを開くか作成します。シェルスクリプトと組み合わせることで、自動デイリーブリーフィングワークフローが可能になります。たとえばhookで、AI生成の要約をデイリーノートに追記できます。 - テンプレートベースのノート作成。
obsidian template listとobsidian template createは、Templaterまたはコアテンプレートからノートを生成します。これにより、AIエージェントはmarkdownファイルを直接書き込まずに、構造化された保管庫エントリを作成できます。 - プロパティ管理。
obsidian property setとobsidian property getはfrontmatterプロパティを読み書きします。YAMLを解析せずに、スクリプトからメタデータを更新できます。 - プラグイン制御。
obsidian plugin enable/disable/listはプラグインをプログラムで管理します。バッチ操作中にインデックス作成プラグインを切り替える場合に便利です。 - タスク管理。
obsidian task list/add/completeは構造化されたタスクアクセスを提供します。保管庫内の作業項目を管理するAIエージェントに役立ちます。
AIアクセスにおけるCLIとMCP
CLIとMCPサーバーは異なる役割を担い、競合ではなく補完関係にあります。
| 観点 | Obsidian CLI | MCPサーバー |
|---|---|---|
| 呼び出し元 | シェルスクリプト、hook、cronジョブ | AIエージェント(Claude Code、Codex、Cursor) |
| プロトコル | POSIXプロセス(stdin/stdout/stderr) | MCP(STDIOまたはHTTP上のJSON-RPC) |
| 強み | Obsidianネイティブ操作(テンプレート、プラグイン、プロパティ) | カスタム検索(embeddings、BM25、RRF fusion) |
| 制約 | ベクトル検索なし、embeddingパイプラインなし | Obsidian内部操作にアクセスできない |
| 最適な用途 | 自動化スクリプト、取り込みパイプライン、hookアクション | セッション中のリアルタイムAIエージェントクエリ |
推奨: 取り込み自動化(ノート作成、プロパティ管理、Obsidianネイティブ検索の実行)にはCLIを使い、検索(embeddingsを使ったハイブリッド検索)にはMCPを使います。PreToolUse hookでは、ランク付けされた結果を得るために完全なMCP検索機へフォールバックする前の高速な事前チェックとして、obsidian search:contextを呼び出せます。
例:CLI駆動の取り込み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プラグイン
Obsidianプラグインの中で、AI coding agentをvault(Obsidianの保管庫)UIに直接組み込むカテゴリが広がっています。外部のMCPサーバー設定の代替となるものです。これらのプラグインは、外部ツールから接続するのではなく、Obsidianのサイドバー内でAI agentを実行します。
Claudian
Claudianは、Claude CodeをAIコラボレーターとしてvaultに組み込みます。vaultディレクトリがClaudeの作業ディレクトリになり、ファイルの読み書き、検索、bashコマンド、複数ステップのワークフローといった、完全なagentic capabilitiesを利用できます。17
AIインフラ向けの主な機能:
- コンテキスト対応プロンプト。 フォーカス中のノートを自動で添付し、@notenameによるファイル参照、タグベースの除外、エディタ上の選択範囲をコンテキストとしてサポートします。
- Visionサポート。 ドラッグ&ドロップ、貼り付け、ファイルパス経由で画像を分析できます。vaultに保存したスクリーンショットや図を処理する場合に便利です。
- Slash commands。 /commandで呼び出せる再利用可能なプロンプトテンプレートを作成し、標準化されたvault操作を実行できます。
- 権限モード。 YOLO(自動承認)、Safe(各アクションを承認)、Plan(計画のみ)モードがあり、安全用のブロックリストとvault内への制限を備えています。
Agent Client
Agent Clientは、Agent Client Protocol(ACP)を通じて、Claude Code、Codex CLI、Gemini CLIを統合されたObsidianサイドバーに取り込みます。18
主な機能:
- 複数agentの切り替え。 同じパネルからClaude Code、Codex、Gemini CLIとチャットでき、必要に応じてagentを切り替えられます。
- ノート参照。 Claudianと同様に、@notenameでノートの内容をプロンプトに含められますが、特定のagentに依存しません。
- Shell実行。 チャット内でターミナルコマンドをインライン実行できます。ビルドスクリプト、gitコマンド、その他のターミナル操作を会話から離れずに実行できます。
- アクション承認。 ファイル読み取り、編集、コマンド実行を細かく制御できます。
agentプラグインと外部MCPの使い分け
| シナリオ | agentプラグイン | 外部MCP |
|---|---|---|
| AI支援でvaultノートを書いたり編集したりする | より適しています。agentがエディタのコンテキストを把握できます | 動作しますが、エディタの認識はありません |
| 複数repoにまたがるコード開発 | 限定的です。vaultスコープになります | より適しています。プロジェクトスコープでfilesystem全体を扱えます |
| 大規模なindex済みcorpusからの検索 | 基本検索のみです | 完全なhybrid retrieval pipelineを利用できます |
| ノート作成中のすばやいvault Q&A | 理想的です。コンテキスト切り替えが不要です | ターミナルへ切り替える必要があります |
推奨: ノートの作成、整理、要約など、vault中心のワークフローにはagentプラグインを使います。AI agentが完全なretrieval pipelineとvault外のcodebaseへのアクセスを必要とする開発ワークフローには、外部MCPサーバーを使います。2つのアプローチは共存できます。ノート作業にはObsidian内でClaudianを実行し、開発には外部でClaude CodeとMCPを使えます。
判断フレームワーク: Obsidianと代替ツール
すべてのユースケースに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 | プレーンなFilesystem | CLAUDE.md |
|---|---|---|---|---|---|
| Local-first | はい | いいえ(cloud) | 一部(iCloud) | はい | はい |
| Plaintext | はい(markdown) | いいえ(blocks) | いいえ(独自形式) | はい | はい |
| Graph構造 | はい(wiki-links) | 一部(mentions) | いいえ | いいえ | いいえ |
| AIでindex可能 | 直接ファイルアクセス | APIが必要 | exportが必要 | 直接ファイルアクセス | すでにコンテキスト内 |
| プラグインエコシステム | 2,500以上のプラグイン | 連携機能 | なし | N/A | N/A |
| Offline対応 | 完全対応 | キャッシュ済みの読み取りのみ | 一部対応 | 完全対応 | 完全対応 |
| 10K以上のノートへのスケール | はい | はい(API使用時) | 劣化します | はい | いいえ(単一ファイル) |
| コスト | 無料(core) | $10/月以上 | 無料 | 無料 | 無料 |
Obsidianが過剰になる場合
- 単一プロジェクトのコンテキスト。 AIが現在のcodebaseについてのコンテキストだけを必要とするなら、
CLAUDE.md、AGENTS.md、またはプロジェクトレベルのドキュメントに入れます。これらのファイルはrepoと一緒に移動し、自動で読み込まれます。 - 構造化データ。 内容がテーブル、レコード、schemaである場合はdatabaseを使います。Obsidianのノートはprose-firstです。Dataviewでfrontmatterフィールドをqueryできますが、構造化queryは本物のdatabaseのほうが適しています。
- 一時的なリサーチ。 プロジェクト終了後にノートを破棄するなら、markdownファイルを置いたscratchディレクトリのほうがシンプルです。一時的なコンテンツのためにretrieval infrastructureを構築する必要はありません。
Obsidianが適している場合
- 数か月から数年にわたって知識を蓄積する。 corpusが成長するほど価値が積み上がります。毎日6か月queryされる200ノートのvaultは、一度しかqueryされない5,000ノートのvaultよりも価値があります。
- 複数ドメインを1つのcorpusにまとめる。 programming、architecture、security、デザイン、個人プロジェクトのノートを含むvaultでは、プロジェクト固有の
CLAUDE.mdでは得られないcross-domain retrievalの恩恵があります。 - Privacy-sensitiveなコンテンツ。 Local-firstであれば、retrieval pipelineがコンテンツを外部サービスへ送ることはありません。vaultには、cloudサービスへアップロードしたくない内容も含めて、入れたものがそのまま保存されます。
メンタルモデル: 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に入るかを決めます。curationがなければ、vaultにはノイズが蓄積します。tweetのスクリーンショット、注釈のないコピー&ペースト記事、コンテキストのない書きかけの思考などです。Intakeレイヤーは、入口の時点で品質管理を担います。スコアリングpipeline、タグ付け規約、手動レビューprocessなど、vaultにretrievalする価値のあるコンテンツが含まれるようにする仕組みです。
Retrievalは、vaultをquery可能にします。これがエンジンです。ノートを検索単位にchunkingし、chunkをvector spaceにembeddingsし、keyword検索とsemantic検索用にindexし、RRFで結果を統合します。Retrievalレイヤーは、ファイルのディレクトリをquery可能なknowledge baseに変換します。このレイヤーがなければ、vaultは手動ブラウズと基本検索では移動できますが、AIツールからprogrammaticallyにはアクセスできません。
Integrationは、retrievalレイヤーをAIツールにつなぎます。MCPサーバーは、retrievalを呼び出し可能なツールとして公開します。hooksはコンテキストを自動で注入します。Skillsは新しい知識をvaultへ戻して記録します。Integrationレイヤーは、knowledge baseと、それを利用するAI agentsの間にあるインターフェースです。
これらのレイヤーは、意図的にdecoupledされています。Intakeのスコアリングpipelineは、embeddingsについて何も知りません。Retrieverは、signal routing rulesについて何も知りません。MCPサーバーは、ノートがどのように作成されたかを知りません。このdecouplingにより、どのレイヤーも独立して改善できます。Intake pipelineを変えずにembedding modelを置き換えられます。Retrieverを修正せずに新しいMCP機能を追加できます。Indexに触れずにsignal scoring heuristicsを変更できます。
AIが利用しやすいVaultアーキテクチャ
AI検索に最適化した保管庫(Obsidianのvault)は、個人が閲覧しやすい保管庫とは異なる慣例に従います。このセクションでは、フォルダー構造、ノートスキーマ、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の本文を含むものすべてです。projects、areas、resources、signals、daily notesなどが該当します。
インデックス対象から除外すべきフォルダー: Templates(コンテンツではなくプレースホルダー変数を含むため)、attachments(バイナリファイル)、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— typeで絞り込んだクエリを可能にします(「MOCだけ表示」「signalsだけ表示」など)tags— FTS5の見出しコンテキストに0.3の重みでインデックスされるため、本文で別の用語を使っていてもキーワード一致を得られます
任意ですが価値の高いフィールド:
domain— domain単位のクエリを可能にします(「securityノートだけ検索」など)source— 取り込んだコンテンツの出典です。retrieverが結果にソースURLを含められますstatus— archivedやdraftのノートをアクティブな検索から除外できます
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つのチャンクが作られます。各チャンクには、embeddingが意味を捉えるのに十分なコンテキストがあります。「expired token handling」に関するクエリは、特に3つ目のチャンクに一致します。
検索に適さない構造:
# 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見出しのない長いセクションが1つだけあると、1つの大きなチャンクになります。embeddingはセクション内のすべてのトピックを平均化します。そのため、どのサブトピックに関するクエリでも、ノート全体に同じように一致してしまいます。
経験則: 1つのセクションで複数の概念を扱う場合は、H2サブセクションに分割しましょう。残りはchunkerが処理します。
ノートに入れるべきでないもの
検索品質を下げるコンテンツは次のとおりです。
- 記事全文を注釈なしでそのままコピー&ペーストしたもの。 retrieverは元記事のキーワードをインデックスするため、自分で書いていないコンテンツで保管庫が薄まってしまいます。代わりに、要約を追加する、要点を抽出する、またはソースURLにリンクしてください。
- テキスト説明のないスクリーンショット。 retrieverがインデックスするのはMarkdownテキストです。altテキストや周辺の説明がない画像は、BM25にもvector searchにも見えません。
- 認証情報の文字列。 APIキー、トークン、パスワード、接続文字列です。credential filteringがあっても、最も安全なのは秘密情報をノートに貼り付けないことです。代わりに、名前で参照してください(「
~/.envにあるCloudflare APIトークン」など)。 - キュレーションされていない自動生成コンテンツ。 ツールがノートを生成する場合(会議の文字起こし、Readwiseのハイライト、RSSインポートなど)、恒久的な保管庫に入れる前に確認し、注釈を加えてください。未整理の自動インポートは量を増やすだけで、検索できる価値は増やしません。
AIワークフロー向けプラグインエコシステム
AI検索のためにvaultの品質を高めるObsidianプラグインは、構造(整合性を強制する)、クエリ(metadataを可視化する)、sync(vaultを最新に保つ)の3つに分類できます。
必須プラグイン
Dataview。 frontmatterフィールドを使って、vaultをデータベースのようにクエリできます。「過去30日以内に更新されたsecurityタグ付きの全ノート」や「statusがactiveの全プロジェクトノート」といった動的インデックスを作成できます。Dataviewは検索そのものを直接改善するわけではありませんが、vaultのカバレッジの穴を見つけたり、更新が必要なノートを特定したりするのに役立ちます。
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。 vault全体にフォーマットルールを適用します。一貫した見出し階層(タイトルにH1、セクションにH2、サブセクションにH3)があると、chunkerが予測しやすい結果を生成できます。検索に関係するLinterルールは次のとおりです。
- 見出しの段階: 見出しレベルを順番どおりにする(H1からH3へ飛ばない)
- YAMLタイトル: ファイル名と一致させる
- 行末スペース: 削除する(FTS5のtokenizationアーティファクトを避ける)
- 連続する空行: 1つまでに制限する(chunkがきれいになる)
Git integration。 vaultのバージョン管理です。変更を時系列で追跡し、マシン間で同期し、誤削除から復旧できます。Gitは、indexerが増分変更検出に使うmtimeデータも提供します。
インデックス作成に役立つプラグイン
Smart Connections。 Obsidian内でAIによるセマンティック検索を提供するObsidianプラグインです。Smart Connections v4はデフォルトでローカルembeddingsを作成します。vaultのインデックス作成が終われば、semantic connectionsと検索はAPI callsなしで完全にオフライン動作します。11 v4.5.0(2026年5月5日)では、footer connectionsがSmart Connections Coreの一部になりました。そのため、どのインストールでもサイドパネルを開かずに、関連ノートのつながりをフッターに表示できます。最近のv4リリースでは、connection list向けのgraph view、設定可能なdock locations、中断されたインデックス作成後のblock-embedding復旧改善、そしてSmart Connections、Smart Chat、Smart Composerが状態を共有できるクロスプラグイン環境「Substrate」も追加されています。21 このガイドの検索システムはObsidian外部で動作します(Python pipelineとして実行)。それでもSmart Connectionsは、執筆中にセマンティックな関係を探索するうえで有用です。2つのシステムは同じコンテンツをインデックス化しますが、用途が異なります。Smart Connectionsはエディタ内での発見に、外部retrieverはMCP経由のAIツール統合に使います。
2026年4月に登場したAI-nativeプラグイン。 新しいコミュニティプラグインの波が、Claude Code / Codex / Gemini-CLIワークフローを直接ターゲットにしています。
| プラグイン | リリース | 機能 |
|---|---|---|
| Cortex | 4月4日 | Claude Codeで動くvault agent。vaultを単なるノート保管庫ではなく、agentワークスペースとして扱います |
| VaultSearch | 4月7日 | ローカルファーストのhybrid検索: BM25 + semantic + fuzzy(このガイドの検索スタックと直接重なります) |
| LLM Wiki | 4月9日 | vaultをプライベートにクエリ可能なナレッジベースに変えます |
| Drift | 4月11日 | AIによるObsidian編集向けのVS Code風diffビューア。Claude Codeワークフロー向けに位置づけられています |
| EngramQuest | 4月11日 | ノートから記憶チャレンジを生成します。Claude Code / Gemini CLI / Cursor向けの「AI Skills」も同梱されています |
| Hybrid Search MCP | 3月(まだ新しい) | BM25 + semantic検索を備えたMCP server + CLI。AIアシスタント向けに作られています |
これは新しく現れつつある領域として扱いましょう。今後数四半期で、これらのいくつかは統合されるか、Smart Connections / Obsidian coreに吸収される可能性があります。今日1つ選ぶなら、VaultSearchとHybrid Search MCPが、このガイドの外部retrieverに最も近い思想を持っています。
Dataviewメモ: Dataview(長く使われているObsidianクエリプラグイン)は、2025年4月に0.5.70を最後にリリースして以降、実質的に休止状態です。新しい作業では、Obsidian組み込みのBases機能(1.9+)が暗黙の後継であり、推奨される道筋です。
Metadata Menu。 フィールド値のautocomplete付きで、構造化されたfrontmatter編集を提供します。type、domain、tagsフィールドでの入力ミスを減らせます。一貫したmetadataは、検索フィルタリングの精度を高めます。
インデックス作成に悪影響を与えるプラグイン
Excalidraw。 図面をmarkdownファイル内のJSONとして保存します。JSONは構文上は有効なmarkdownですが、chunk化してembeddingするとノイズになります。.indexignoreを使うか、ファイル拡張子でフィルタリングして、Excalidrawファイルをインデックスから除外してください。
Kanban。 ボード状態を特殊なフォーマットのmarkdownとして保存します。この形式はKanban表示のために設計されており、文章検索向けではありません。chunkerはカードタイトルやmetadataの断片を生成しますが、うまくembeddingされません。Kanbanボードはインデックスから除外してください。
Calendar。 最小限の内容の日次ノートを作成します(多くの場合、日付の見出しだけです)。空またはほぼ空のノートは、低品質なchunkを生みます。日次ノートを使う場合は、実質的な内容を書くか、日次ノートフォルダをインデックスから除外してください。
重要なプラグイン設定
ファイル復元 → 有効。 誤ってノートを削除した場合に備えます。検索とは直接関係ありませんが、依存しているナレッジベースにとっては重要です。
Strict line breaks → 無効。 Markdown標準の改行(段落には空行を2つ)を使うほうが、Obsidianのstrict mode(<br>に単一改行)よりもきれいなchunkを生成できます。
Default new file location → 指定フォルダ。 新規ファイルを00-inbox/に送ることで、未分類ノートがdomainフォルダを汚さないようにします。inboxはステージング領域です。ファイルはトリアージ後にdomainフォルダへ移動します。
Wiki-link format → 可能な場合は最短パス。 リンク先が短いほど、link structureをインデックス化するときにretrieverが解決しやすくなります。
Embedding Models:選び方と設定
embedding modelは、テキストのチャンクをセマンティック検索用の数値ベクトルに変換します。どのモデルを選ぶかによって、検索品質、インデックスサイズ、embedding速度、実行時の依存関係が決まります。このセクションでは、Model2Vecのpotion-base-8Mをデフォルトにしている理由と、代替モデルを選ぶべき場面を説明します。
Model2Vec potion-base-8Mを選ぶ理由
Model: minishlab/potion-base-8M
Parameters: 7.6 million
Dimensions: 256
Size: ~30 MB
Dependencies: model2vec(numpyのみ、PyTorch不要)
Inference: CPUのみ、静的な単語embeddings(attention layersなし)
Model2Vecは、sentence transformerの知識を静的なtoken embeddingsへ蒸留します。BERT、MiniLM、その他のtransformer modelsのように入力に対してattention layersを実行するのではなく、Model2Vecは事前計算済みtoken embeddingsの重み付き平均でベクトルを生成します。5 実用上の結果として、逐次計算がないため、embedding速度はtransformer-based modelsより50〜500倍高速です。
現在のModel2Vec results pageでは、potion-base-8Mはall-MiniLM-L6-v2のall-task scoreの約92%(51.32対55.80)に達しながら、桁違いに高速です。6 残る品質差は、速度とシンプルさを得るためのトレードオフです。短いmarkdownチャンク(一般的な保管庫(Obsidianのvault)では平均200〜400語)では、長い文書ほど品質差は目立ちません。短く焦点の定まったテキストでは、どちらのモデルも似た表現に収束するためです。
設定
# 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]
遅延読み込み。 モデルはimport時ではなく、初回使用時に読み込まれます。retrieverがBM25-only fallback modeで動作する場合(たとえばembedding venvがインストールされていない場合)、embedder moduleをimportしてもコストはかかりません。
分離されたvirtual environment。 依存関係がtoolchainの他の部分と衝突しないよう、モデルは専用のvenv(例:~/.claude/venvs/memory/)で実行します。_activate_venv()関数は、実行時にvenvのsite-packagesをsys.pathへ追加します。
# Create isolated venv
python3 -m venv ~/.claude/venvs/memory
~/.claude/venvs/memory/bin/pip install model2vec
バッチ処理。 embedderはModel2Vecのオーバーヘッドをならすため、64件ずつテキストを処理します。indexerは、チャンクを1件ずつembeddingするのではなく、embed_batch()へ渡します。
代替モデルを選ぶタイミング
| Model | Dim | Size | Speed | Quality (MTEB) | 最適な用途 |
|---|---|---|---|---|---|
| potion-base-8M | 256 | 30 MB | 500x | 51.32 | デフォルト:ローカル、高速、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 | — | 多言語の保管庫(101言語) |
| all-MiniLM-L6-v2 | 384 | 80 MB | 1x | 55.80 | より高品質、引き続きローカル |
| nomic-embed-text-v1.5 | 768 | 270 MB | 0.5x | 62.28 | 最高のローカル品質 |
| text-embedding-3-small | 1536 | API | N/A | 62.30 | APIベース、最高品質 |
potion-base-32Mを選ぶのは、静的embeddingファミリーのまま、potion-base-8Mより高い品質が必要な場合です。baai/bge-base-en-v1.5から蒸留されたより大きな語彙を使い、同じ256次元の出力とnumpyのみの依存関係を保ったまま、52.83のall-task score(potion-base-8Mより約3%高い)を達成します。8 モデルファイルが4倍大きくなるためメモリ使用量は増えますが、embedding速度はtransformer modelsより桁違いに高速なままです。
potion-retrieval-32Mを選ぶのは、主な用途がretrieval(保管庫検索がまさにこれです)の場合です。このvariantはpotion-base-32Mからretrieval tasks向けにfine-tunedされており、Model2Vecのretrieval benchmark tableで35.06を記録しています。potion-base-32Mは32.67です。8 トレードオフとして、汎用的なembedding品質ではなくretrievalに最適化されています。
potion-multilingual-128Mを選ぶのは、保管庫に複数言語のノートが含まれる場合です。2025年5月にリリースされたこの101言語対応モデルは、多言語タスク向けの静的embedding modelとして最高性能で、他のpotion modelsと同じnumpyのみの依存関係を保ちながら、あらゆる言語のテキストに対してembeddingsを生成します。12 より大きなモデルファイル(約500 MB)は、cross-lingual capabilityのためのトレードオフです。英語コンテンツに加えて、日本語、中国語、ドイツ語、その他の非英語ノートがある場合に使います。
all-MiniLM-L6-v2を選ぶのは、速度よりretrieval品質が重要で、PyTorchがインストール済みの場合です。384次元ベクトルにより、256次元ベクトルと比べてSQLite database sizeは約50%増えます。M-series hardwareで15,000ファイルをfull reindexする場合、embedding速度は1分未満から約10分へ低下します。
nomic-embed-text-v1.5を選ぶのは、可能な限り最高のローカルretrieval品質が必要で、indexingが遅くなることを許容できる場合です。768次元ベクトルにより、database sizeはおおむね3倍になります。PyTorchと、modern CPUまたはGPUが必要です。
text-embedding-3-smallを選ぶのは、network latencyとprivacyを許容できるトレードオフとして扱える場合です。APIは最高品質のembeddingsを生成しますが、cloud dependency、tokenごとのコスト($0.02/million tokens)、そしてコンテンツがOpenAIのserversへ送信されることを伴います。
それ以外のすべてのケースではpotion-base-8Mのままにします。 反復的なindexing(開発中のreindex)では速度面の利点が重要で、numpyのみの依存関係によりPyTorchインストールの複雑さを避けられ、256次元ベクトルによってdatabaseをコンパクトに保てます。
Quantizationと次元削減
Model2Vec v0.5.0+は、精度と次元を削減したモデルの読み込みをサポートしています。8 制約のあるhardwareへdeploymentする場合や、モデルを切り替えずに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は、メモリフットプリントを大幅に削減しながら、ほぼ同等のretrieval品質を維持します。次元削減はMatryoshka-style truncationに従い、最初のN次元に最も多くの情報が含まれます。256次元から128次元へ減らすと、短文retrievalでは品質低下を最小限に抑えつつ、vector storageを半分にできます。
Model2Vec v0.8.xでは、tokenizer/persistence internalsが更新され、Python 3.9 supportがdeprecateされ、公開結果が新しいMTEB tablesに更新されています。本番indexerをupgradeする前にmodel2vecをpinまたはtestしてください。embedding model nameが同じでも、library upgradesによってmodel-loading pathsが変わることがあるためです。10
保管庫固有のEmbeddings向けFine-Tuning
Model2Vec v0.4.0+は、静的embeddingsの上にcustom classification modelsをtrainingする機能をサポートしています。v0.7.0ではvocabulary quantizationとdistillation用のconfigurable poolingが追加され、v0.8.xではtokenizerとpersistence behaviorがrefactorされています。10 これは、専門用語を含む保管庫(医療ノート、法的参照、domain-specific jargonなど)で関連します。こうした保管庫では、デフォルトのpotion modelsがsemantic nuancesを十分に捉えられない場合があります。
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")
ほとんどの保管庫では、デフォルトのpotion-base-8Mで十分なretrieval品質が得られます。Fine-tuningに価値があるのは、general-purpose modelでは捉えられないdomain-specific connectionsをretrievalが一貫して見逃す場合だけです。
Model Hash Tracking
indexerは、model nameとvocabulary sizeから導出したhashを保存します。embedding modelを変更すると、次回のincremental runでindexerが不一致を検出し、自動的にfull reindexを開始します。
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]
これにより、異なるモデル由来のベクトルが同じdatabase内で混在することを防げます。混在すると、cosine similarity scoresは意味をなさなくなります。
Failure Modes
Model download failure。 初回実行時に、モデルはHugging Faceからdownloadされます。downloadが失敗した場合(network issue、corporate firewallなど)、retrieverはBM25-only modeへfallbackします。初回download後、モデルはローカルにcacheされます。
Dimension mismatch。 databaseをclearせずにモデルを切り替えると、保存済みベクトルの次元が新しいembeddingsと異なります。indexerはmodel hashを使ってこれを検出し、full reindexを開始します。hash checkが失敗した場合(proper hashのないcustom modelなど)、sqlite-vecは次元不一致のKNN queriesでerrorになります。
大規模な保管庫でのmemory pressure。 50,000件以上のチャンクを単一batchでembeddingすると、かなりのメモリを消費する可能性があります。indexerはpeak memory usageを抑えるため、64件ずつbatch処理します。それでもメモリが問題になる場合は、batch sizeを減らしてください。
FTS5による全文検索
SQLiteのFTS5拡張は、BM25ランキングを使った全文検索を提供します。FTS5は、hybrid retrievalパイプラインにおけるキーワード検索のコンポーネントです。このセクションでは、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テーブルを直接参照させます。これにより保存容量は半分になりますが、チャンクの挿入、更新、削除時にはFTS5を手動で同期する必要があります。
カラム。 3つのカラムをインデックス化します。
- chunk_text:各チャンクの主要コンテンツ(BM25 weight: 1.0)
- section:H2見出しのテキスト(BM25 weight: 0.5)
- heading_context:ノートのタイトル、タグ、メタデータ(BM25 weight: 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_context(タイトル、タグ)での一致は、30%の寄与になります
これらの重みは調整できます。保管庫の見出しが説明的で、コンテンツ品質を強く予測できる場合は、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は、保存されているコンテンツと異なる用語を使ったクエリで失敗します。
- Query: “how to handle authentication failures” → 保管庫には「login error recovery」や「session expiration handling」に関するノートがあります。キーワードが異なるため、BM25は一致させられません。
- Query: “what is the best way to manage state” → 保管庫には「Redux store patterns」や「context providers」に関するノートがあります。「state management」が特定の技術名で表現されているため、BM25は取りこぼします。
BM25は、大規模になるとキーワード衝突でも失敗します。15,000ファイルの保管庫で「configuration」を検索すると、ほぼすべてのプロジェクトノートが設定に触れているため、数百件のノートに一致します。結果は技術的には正しいものの、実用上は役に立ちません。ランキングでは、どの「configuration」ノートが現在のクエリに関連しているかを判定できないためです。
FTS5 Tokenizer
FTS5はデフォルトでunicode61 tokenizerを使用し、ASCIIとUnicodeテキストを処理します。CJK(中国語、日本語、韓国語)コンテンツが多い保管庫では、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文字ごとに分割するため、インデックスサイズが大きくなる(おおよそ3倍)代わりに、部分文字列のマッチングが可能になります。
メンテナンス
基盤となるchunksテーブルが変更された場合、FTS5は明示的な同期を必要とします。
# After inserting chunks
cursor.execute("""
INSERT INTO chunks_fts(chunks_fts)
VALUES('rebuild')
""")
rebuildコマンドは、content tableからFTS5インデックスを再構築します。一括挿入(フル再インデックス)の後に実行してください。ただし、個別の差分更新の後には使いません。その場合は、INSERT INTO chunks_fts(rowid, chunk_text, section, heading_context)を使って個別行を同期します。
sqlite-vecによるVector Search
sqlite-vec拡張は、vector KNN(K-Nearest Neighbors)検索をSQLiteに持ち込みます。このセクションでは、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をパック済みバイナリデータとして保存します。id列はchunksテーブルと1:1で対応し、vector結果とchunkメタデータをjoinできるようにします。
Embeddingパイプライン
パイプラインは、ノートから検索可能な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シリアライズ
Pythonのstructモジュールは、sqlite-vec保存用にfloat vectorをシリアライズします。
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クエリ
vector searchクエリでは、入力クエリをembedしてから、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制約付きKNNページネーション
sqlite-vec v0.1.7以降、KNNクエリはWHERE distance < ?制約をサポートしており、大きな結果セットでも以前のページを再スキャンせずにカーソルベースでページネーションできます。14 その後のv0.1.8とv0.1.9の安定版リリースは、新しいクエリモデルのリリースではなく、パッケージングとDELETEのバグ修正リリースです。そのため、このページネーションパターンの機能境界はv0.1.7のままです。23
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側でsliceする従来のパターンを置き換えられます。大規模なvaultに対する探索的クエリで、メモリ使用量を削減できます。
vec0テーブルでのDELETEサポート
sqlite-vec v0.1.7ではvec0 virtual tableにnative DELETEサポートが追加され、v0.1.9では12文字を超えるメタデータテキスト列に関係するDELETEエラーパスが修正されました。1423 以前は、vectorを削除するにはテーブルをdropして再作成する必要がありました。現在は、indexerのファイル削除パスで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は、シャドウの「active IDs」テーブルやbatch rebuildを維持する必要がなくなりました。
Vector Searchが有効な場面
Vector searchは、具体的な単語よりも概念が重要なクエリで力を発揮します。
- Query: “how to handle authentication failures” → “login error recovery”に関するノートを見つけます(同じsemantic space、異なるキーワード)
- Query: “what patterns exist for caching” → “memoization”、”Redis TTL strategies”、”HTTP cache headers”に関するノートを見つけます(関連する概念、多様な用語)
- Query: “approaches to testing asynchronous code” → “pytest-asyncio fixtures”、”mock event loops”、”async test patterns”に関するノートを見つけます(実装詳細を通じて表現された同じ概念)
Vector Searchが失敗しやすい場面
Vector searchは、正確な識別子が苦手です。
- Query:
_rrf_fuse→ “fusion algorithms”や”rank merging”に関するノートを返しますが、実際の関数定義は概念的な議論より低くrankされる場合があります - Query:
PostToolUse→ 特定のhook名ではなく、”tool lifecycle hooks”や”post-execution handlers”に関するノートを返します
Vector searchはstructured dataも苦手です。JSON設定ファイル、YAMLブロック、コードスニペットでは、semantic meaningではなく構造パターンを捉えたembeddingsが生成されます。"review": trueを含むJSONファイルは、コードレビューについての文章による議論とは異なる形でembedされます。
Graceful Degradation
sqlite-vecの読み込みに失敗した場合(拡張がない、プラットフォーム非互換、ライブラリ破損など)、retrieverはBM25のみの検索に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 は、スコアの較正を必要とせずに、2つのランク付きリストを統合します。このセクションでは、アルゴリズム、実際のクエリトレース、k パラメータの調整、そして他の手法ではなく RRF を選ぶ理由を扱います。ランクを編集できるインタラクティブな計算ツール、シナリオプリセット、視覚的なアーキテクチャ探索については、hybrid retriever の詳細解説をご覧ください。
アルゴリズム
RRF は、各リスト内でのランク位置だけに基づいて、各ドキュメントにスコアを割り当てます。
score(d) = Σ (weight_i / (k + rank_i))
ここで:
- k は平滑化定数です(Cormack らに従い 603)
- rank_i は、結果リスト i におけるドキュメントの1始まりのランクです
- weight_i は任意のリスト別の倍率です(デフォルトは 1.0)
複数のリストで上位にランクされるドキュメントほど、統合後のスコアが高くなります。1つのリストにしか現れないドキュメントは、その単一ソースからのスコアだけを受け取ります。
代替手法ではなく RRF を使う理由
重み付き線形結合では、BM25 スコアと cosine distances を較正する必要があります。BM25 スコアには上限がなく、コーパスサイズに応じてスケールします。cosine distances は [0, 2] の範囲に収まります。両者を組み合わせるには正規化が必要であり、その正規化パラメータはデータセットに依存します。RRF はランク位置だけを使います。ランク位置は、スコアリング手法に関係なく、常に 1 から始まる整数です。
学習済みの融合モデルには、ラベル付きの訓練データ、つまりクエリとドキュメントの関連性ペアが必要です。個人のナレッジベースでは、この訓練データは存在しません。有用なモデルを訓練するには、数百件のクエリとドキュメントのペアを手作業で評価する必要があります。RRF は訓練データなしで機能します。
Condorcet voting 手法(Borda count、Schulze method)は理論的には洗練されていますが、実装と調整がより複雑です。元の RRF 論文では、TREC 評価データにおいて RRF が Condorcet 手法を上回ることが示されています。3
実践での融合
クエリ: “how does the review aggregator handle disagreements”
BM25 は review-aggregator.py を3位にランクします(”review,” “aggregator,” “disagreements” の完全なキーワード一致)が、2つの設定ファイルをそれより上位に置きます(それらは “review” により目立って一致するためです)。Vector search は同じチャンクを1位にランクします(conflict resolution の意味的な一致)。RRF で融合した後は次のようになります。
| チャンク | BM25 | Vec | 融合スコア |
|---|---|---|---|
| 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 |
両方のリストで上位に入るチャンクが先頭に浮上します。1つのリストにしか現れないチャンクは単一ソースのスコアだけになり、両方でランクされた結果より下に落ちます。実際の disagreement resolution logic が勝つのは、BM25 がキーワードを通じて、vector search が意味を通じて、どちらの手法もそれを見つけたためです。
ランクごとの RRF 計算を含む完全なステップごとのトレースは、インタラクティブな RRF 計算ツールで 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倍の差)。個々のランカーが最上位の結果を正しく出せると信頼できる場合に適しています。
- デフォルトの k(60): バランス型です。ランク1は 1/61 = 0.0164、ランク10は 1/70 = 0.0143 です(1.15倍の差)。ランク差が圧縮されるため、複数のリストに現れることの重みが増します。
- 高い k(例: 200): ランク位置よりも、両方のリストに現れることがはるかに重要になります。ランク1は 1/201、ランク10は 1/210 で、ほぼ同じです。個々のランカーの順位付けにノイズがある一方で、リスト間の一致は信頼できる場合に使います。
まずは k=60 から始めましょう。 元の RRF 論文では、この値が多様な TREC データセット全体で堅牢であることが示されています。調整は、自分のクエリ分布で失敗例を測定した後に行ってください。
タイブレーク
2つのチャンクの RRF スコアが同一になる場合(まれですが、片方のリストで同じランクにあり、もう一方には現れない場合に起こり得ます)、次の順でタイを解消します。
- 1つのリストにしか現れないチャンクよりも、両方のリストに現れるチャンクを優先します
- 両方のリストに現れるチャンク同士では、合計ランクが低いものを優先します
- 1つのリストにしか現れないチャンク同士では、そのリスト内でランクが低いものを優先します
完全な検索パイプライン
このセクションでは、クエリが入力から出力まで、BM25検索、ベクトル検索、RRF融合、token budgetの切り詰め、コンテキスト組み立てというパイプライン全体を通る流れを追います。
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
合計レイテンシ: 約23ms。Apple M3 Proハードウェア上の49,746チャンクのデータベースでの値です。
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の切り詰め
max_tokensパラメータは、AIツールが利用できる量を超えるコンテキストをretrieverが返さないようにします。推定には、1 tokenあたり4文字を使います(英語の文章では妥当な近似です)。結果は貪欲法で切り詰められます。つまり、予算が尽きるまで、ランキング順に結果を追加していきます。
これは保守的な戦略です。より高度な方法では、結果ごとの品質スコアを考慮し、長くて品質の低い結果よりも、短くて品質の高い結果を優先できます。貪欲法はより単純で、実運用でもうまく機能します。RRFランキングがすでに関連性の高い順に結果を並べているためです。
データベーススキーマ(完全版)
-- 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の経路
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は初期化時に機能を確認し、クエリ戦略を適応させます。コンポーネントが欠けている場合は品質が下がりますが、エラーにはなりません。唯一のハードフェイルは、データベースファイルが存在しない場合です。
本番環境での統計
16,894ファイル、49,746チャンク、83 MB SQLiteデータベース、Apple M3 Proのvaultで測定した結果です。
| 指標 | 値 |
|---|---|
| 総ファイル数 | 16,894 |
| 総チャンク数 | 49,746 |
| データベースサイズ | 83 MB |
| BM25クエリレイテンシ(p50) | 12ms |
| ベクトルクエリレイテンシ(p50) | 8ms |
| RRF融合レイテンシ | 3ms |
| End-to-end検索レイテンシ(p50) | 23ms |
| フル再index時間 | 約4分 |
| インクリメンタル再index時間 | <10秒 |
| Embeddingモデル | potion-base-8M (256-dim) |
| BM25候補プール | 30 |
| ベクトル候補プール | 30 |
| デフォルトの結果上限 | 10 |
| デフォルトのtoken budget | 4,000 tokens |
コンテンツHashingと変更検出
indexerは、前回のindex実行以降にどのファイルが変更されたかを把握する必要があります。このセクションでは、変更検出の仕組みとhashing戦略を扱います。
ファイル変更時刻の比較
indexerは、すべてのチャンクについてchunksテーブルにmtime_ns(ナノ秒単位のファイル変更時刻)を保存します。インクリメンタル実行では、indexerは次の処理を行います。
- 許可されたフォルダー内のすべての
.mdファイルをvaultからスキャンします - ファイルシステムから各ファイルの
mtime_nsを読み取ります - データベースに保存されている
mtime_nsと比較します - 3つのカテゴリを特定します。
- 新規ファイル: パスはファイルシステムに存在するが、データベースには存在しない
- 変更ファイル: パスは両方に存在するが、
mtime_nsが異なる - 削除ファイル: パスはデータベースに存在するが、ファイルシステムには存在しない
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(ファイル内容のSHA-256)は、mtime比較よりも信頼性が高くなります。たとえば、ファイルが触られたものの内容は変わっていない場合(git checkoutで元のmtimeに戻る場合など)も検出できます。ただし、hashingではインクリメンタル実行のたびに全ファイルを読む必要があります。16,894ファイルでは、ファイル内容の読み取りに2〜3秒かかります。ファイルシステムからmtimeを読むだけなら<100msです。
トレードオフはこうです。mtime比較では、変更されていないファイルを不要に再indexすることがたまにあります(false positive)が、実際の変更を見逃すことはありません。false positiveのコストは、実行ごとに追加のembedding呼び出しが数回発生する程度です。速度差(100ms対3秒)を考えると、AIとのやり取りごとに動くシステムでは、mtimeが現実的な選択です。
削除の処理
vaultからファイルが削除されると、indexerはそのファイルのすべてのチャンクをデータベースから削除します。
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文は、sqlite-vec v0.1.7以降ではネイティブに動作します。v0.1.9では、長いメタデータテキスト列を持つvec0テーブルに対するDELETE操作のバグ修正も入っています。1423 それ以前のバージョンでは、回避策(仮想テーブルを削除して再作成する、または外部の「active IDs」セットを維持する)が必要でした。pre-0.1.9版を実行している場合は、メタデータが多いスキーマで直接削除に依存する前にアップグレードしてください。
FTS5のcontent-syncテーブルでは、削除された各行に対してINSERT INTO chunks_fts(chunks_fts, rowid, ...) VALUES('delete', ?, ...)による明示的な削除が必要です。indexerは、ファイル削除プロセスの一部としてこれを処理します。
Incremental Reindex と Full Reindex
インデクサーは、incremental(高速で日常利用向け)と full(低速で必要時のみ)の2つのモードに対応しています。このセクションでは、それぞれを使うタイミング、冪等性の保証、破損時の復旧について説明します。
Incremental Reindex
使うタイミング: ノートを編集した後の日次インデックス作成に使います。デフォルトのモードです。
実行内容: 1. ファイル変更を検出するためにvaultをスキャンします(mtime比較) 2. 削除されたファイルのchunksを削除します 3. 変更されたファイルを再chunkingし、再embedします 4. 新しいファイルの新規chunksを挿入します 5. FTS5 indexを同期します
通常の所要時間: 16,000ファイルのvaultで1日分の編集なら10秒未満です。
python index_vault.py --incremental
Full Reindex
使うタイミング: - embedding modelを変更した後(model hashの不一致を検出した場合) - schema migrationの後(新しい列、変更されたindexes) - database corruptionの後(integrity checkが失敗した場合) - incremental indexingで予期しない結果が出る場合
実行内容: 1. 既存データをすべて削除します(chunks、vectors、FTS5 entries) 2. vault全体をスキャンします 3. すべてのファイルをchunkingします 4. すべてのchunksをembedします 5. FTS5 indexをゼロから構築します
通常の所要時間: Apple M3 Proで16,894ファイルなら約4分です。
python index_vault.py --full
冪等性
どちらのモードも冪等です。同じコマンドを2回実行しても、結果は同じになります。インデクサーは新しいchunksを挿入する前に、そのファイルの既存chunksを削除します。そのため、すでに最新のdatabaseに対してincremental indexingを再実行しても、変更は0件です。full indexingを再実行した場合も、同一のdatabaseが生成されます。
破損からの復旧
SQLite databaseが破損した場合(書き込み中の電源断、ディスクエラー、トランザクション中にプロセスがkillされた場合):
# Check integrity
sqlite3 vectors.db "PRAGMA integrity_check;"
# If corruption detected, full reindex rebuilds from source files
python index_vault.py --full
常に信頼すべき元データはdatabaseではなくvaultファイルです。databaseはいつでも再構築できる派生成果物にすぎません。これは重要な設計特性です。databaseをバックアップする必要はありません。
--incremental Flag
インデクサーを--incremental付きで実行すると、次の処理が行われます。
- Model hash check。 保存済みのmodel hashを現在のmodelと比較します。異なる場合は、自動的にfull reindex modeへ切り替え、ユーザーに警告します。
- File scan。 許可されたフォルダーを走査し、file pathsとmtimesを収集します。
- Change detection。 保存済みデータと比較します。
- Batch processing。 変更されたファイルを64件ずつのbatchで再chunkingし、再embedします。
- Progress reporting。 処理済みファイル数と経過時間を表示します。
- Graceful shutdown。 SIGINTを受け取った場合、現在のファイル処理を終えてから停止します。
Credential Filtering と Data Boundaries
個人ノートにはsecretが含まれます。API keys、bearer tokens、database connection strings、debugging session中に貼り付けたprivate keysなどです。credential filterは、これらがretrieval indexに入るのを防ぎます。
問題
OAuth 連携のdebuggingに関するノートには、次のような内容が含まれることがあります。
The token was: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
I used this curl command:
curl -H "Authorization: Bearer sk-ant-api03-abc123..."
filteringしない場合、JWTとAPI keyの両方がchunkingされ、embedされ、databaseに保存されます。”authentication”で検索すると、本物のsecretを含むchunkが返されます。さらに悪いことに、retrieverがMCP経由で結果をAI toolへ渡す場合、そのsecretはAIのcontext windowに入り、場合によってはtoolのlogsにも残ります。
Pattern-Based Filtering
credential filterは保存前にすべてのchunkで実行され、25個のvendor-specific patternsとgeneric patternsに一致するかを確認します。
Vendor-Specific Patterns:
| Pattern | 例 | 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 | ... |
さまざまなpatterns |
Generic Patterns:
| Pattern | Detection |
|---|---|
| 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のエントロピー、40文字以上のstrings |
| Password assignments | password\s*[:=]\s*["'][^"']+["'] |
Filter Implementation
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の前にfilterします。 embedされるのはcleaned textです。vector表現にcredential patternsがエンコードされることはありません。”API key”でqueryして返るのはAPI key管理について論じたノートであり、実際のkeysを含むノートではありません。
-
削除ではなく置換します。
[REDACTED:pattern-name]tokenにより、周囲のtextのsemantic contextが保たれます。embeddingは、credentialらしき何かがそこにあったことを捉えますが、credentialそのものはエンコードしません。 -
valuesではなくpatternsをlogします。 filterは一致したpatternsをlogします(例: “Scrubbed 2 credential(s) from oauth-debug.md [jwt, bearer-token]”)。ただし、credential valueは決してlogしません。
Path-Based Exclusion
.indexignoreファイルは、path単位の粗い除外を提供します。credential filterは、indexed files内で細かなscrubbingを行います。どちらも必要です。
.indexignoreは、sensitive contentを含むことが分かっているフォルダー全体に使います(health notes、financial records、career documents)- Credential filter は、通常はindex対象にできるcontentへ偶発的に埋め込まれたsecretsに使います
Data Classification
多様なcontentを含むvaultでは、sensitivityに応じてノートを分類することを検討してください。
| Level | 例 | Index? | Filter? |
|---|---|---|---|
| Public | Blog drafts、technical notes | Yes | Yes |
| Internal | Project plans、architecture decisions | Yes | Yes |
| Sensitive | Salary data、health records | No (.indexignore) | N/A |
| Restricted | Credentials、private keys | No (.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認可、構造化ツール出力(型付きの戻り値スキーマ)、エリシテーション(サーバー起点のユーザープロンプト)が追加されました。2025年11月のリリースでは、Streamable HTTPがファーストクラスのトランスポートモードとして提供され、サーバー機能を自動参照するための
.well-knownURLディスカバリ、ツールが読み取り専用か変更を伴うかを宣言する構造化ツールアノテーション、そしてSDKティア標準化システムが導入されました。79 次の仕様リリース(暫定的に2026年半ば)では、長時間実行タスク向けの非同期操作、医療や金融などの業界向けドメイン固有プロトコル拡張、マルチエージェントワークフロー向けのエージェント間通信標準が提案されています。9 個人用vaultサーバーでは、STDIOが引き続き最もシンプルな選択肢です。Streamable HTTPトランスポートと.well-knownディスカバリは、主にマルチテナントルーティングとロードバランシングを備えたエンタープライズ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 — 検索を実行し、その結果を会話に挿入しやすいコンテキストブロックとして整形する便利なツールです。
{
"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とインデックスデータベースを読み取ります。ノートの作成、変更、削除は行いません。書き込み操作(新しいノートの取り込み)は、MCPサーバーではなく、別のhooksやskillsで処理します。
-
Vaultスコープ限定。 サーバーは、設定されたvaultパス内のファイルだけを読み取ります。パストラバーサルの試行(
../../etc/passwd)は拒否しなければなりません。 -
credential filtering済みの出力。 データベースに事前フィルタリング済みの内容が含まれている場合でも、防御を多層化するため、出力時にcredential filteringを適用します。
-
トークン制限付きレスポンス。 AIツールが過度に大きなコンテキストブロックを受け取らないよう、すべてのツールレスポンスに
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 設定
Obsidian MCP サーバーを ~/.claude/settings.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 連携
Hooks は、定義されたライフサイクルの各時点で Claude Code の動作を拡張します。Obsidian 連携に関係する hook は2つあります。
PreToolUse hook — agent がツール呼び出しを処理する前に、vault をクエリします。関連するコンテキストを自動的に注入します。
#!/bin/bash
# ~/.claude/hooks/pre-tool-use/obsidian-context.sh
# Automatically inject vault context before tool execution
TOOL_NAME="$1"
PROMPT="$2"
# Only inject context for code-related tools
case "$TOOL_NAME" in
Edit|Write|Bash)
# Query the vault
CONTEXT=$(python /path/to/retriever.py search "$PROMPT" --limit 3 --max-tokens 1500)
if [ -n "$CONTEXT" ]; then
echo "---"
echo "Relevant vault context:"
echo "$CONTEXT"
echo "---"
fi
;;
esac
PostToolUse hook — 重要なツール出力を vault に取り込み、今後の検索に使えるようにします。
#!/bin/bash
# ~/.claude/hooks/post-tool-use/capture-insight.sh
# Capture significant outputs to vault (selective)
TOOL_NAME="$1"
OUTPUT="$2"
# Only capture substantial outputs
if [ ${#OUTPUT} -gt 500 ]; then
python /path/to/capture.py --text "$OUTPUT" --source "claude-code-$TOOL_NAME"
fi
obsidian_bridge.py パターン
ブリッジモジュールは、hooks や skills から呼び出せる 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/ に作成し、増分再インデックスを実行します。そのため、新しいノートはすぐに検索可能になります。
Custom Command パターン
Claude Code skills を使うと、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 activity を集約し、構造化されたジャーナルエントリとして vault に書き込みます。そこには、下した意思決定、気づき、未解決の論点も含まれます。
/captains-log
このコマンドは GitHub からコミット履歴を取得し、リポジトリごとにグループ化して、物語形式のジャーナルエントリとして整形します。時間が経つにつれて、日次ログは「何を出荷したのか」と「なぜそうしたのか」を検索できる記録になります。
Obsidian capture。 /obsidian-capture コマンドは、現在の Claude Code セッションで得た知見を取得し、適切なメタデータ付きで vault に直接書き込みます。
/obsidian-capture "SAST gates in agent loops increase security degradation"
--folder AI-Tools --tags security,agents
このパターンは、どのような vault 操作にも拡張できます。MOCs の作成、プロジェクト状況ノートの更新、関連シグナルのリンク、蓄積された日次ログからの週次ダイジェスト生成などです。
コミュニティ例。 実践者は、自身のコマンドライブラリを公開しています。ある開発者は、日次レビュー、プロジェクト計画、リサーチ記録、コンテンツワークフローを対象とする、Obsidian + Claude Code のカスタムコマンド22個を共有しました。1 別の開発者は、コード分析から vault 内に図解ノートを生成する「Visual Explainer」skill を構築しました。2 コマンドの内容はさまざまですが、アーキテクチャは一貫しています。インターフェースとしての Claude Code skills、ストレージ層としての vault ノート、クエリエンジンとしての検索インフラです。
Context Window 管理
連携では、Claude Code の context window に注意する必要があります。
- 注入するコンテキストは、クエリごとに1,500〜2,000トークンまでに制限します。 これを超えると、agent の作業記憶と競合します。
- ソース帰属を含めます。 agent がソースを参照できるように、必ずファイルパスとセクション見出しを含めてください。
- chunk text を切り詰めます。 長い chunk は完全に省略するのではなく、
...を使って切り詰めます。通常、最初の300〜500文字に重要な情報が含まれます。 - すべてのツール呼び出しで注入しないでください。 PreToolUse hook は、呼び出されるツールに応じて選択的にコンテキストを注入するべきです。読み取り操作には vault のコンテキストは不要です。Write や Edit 操作では役立ちます。
Codex CLI 連携
Codex CLI は、config.toml を通じて MCP サーバーに接続します。設定構文と指示の渡し方が、Claude Code とは異なります。
MCP 設定
.codex/config.toml または ~/.codex/config.toml に追加します。
[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 との違い
| Feature | Claude Code | Codex CLI |
|---|---|---|
| MCP config | settings.json |
config.toml |
| Hooks | ~/.claude/hooks/ |
非対応 |
| Skills | ~/.claude/skills/ |
非対応 |
| Instruction file | CLAUDE.md |
AGENTS.md |
| Approval modes | --dangerously-skip-permissions |
suggest / auto-edit / full-auto |
主な違い: Codex CLI は hooks に対応していません。自動コンテキスト注入パターン(PreToolUse hook)は利用できません。代わりに、作業を始める前に vault を検索するよう agent に伝える明示的な指示を 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ファイルには、保管庫を使うための指示を含められます。
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/settings.json |
| Codex CLI | 完全 | STDIO | .codex/config.toml |
| Cursor | 完全 | STDIO | .cursor/mcp.json |
| Windsurf | 完全 | STDIO | .windsurf/mcp.json |
| Continue.dev | 部分的 | HTTP | ~/.continue/config.json |
| Zed | 開発中 | STDIO | 設定UI |
| Claudian(Obsidian plugin) | N/A(組み込み) | Claude Code CLI | Obsidian plugin設定 |
| Agent Client(Obsidian plugin) | N/A(組み込み) | 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統合ほど洗練されてはいませんが、どこでも使える方法です。
構造化ノートによるプロンプトキャッシュ
保管庫内の構造化ノートは、AIとのやり取り全体でトークン使用量を減らす再利用可能なコンテキストブロックとして使えます。このセクションでは、キャッシュキー設計とトークン予算管理を扱います。
パターン
やり取りのたびにコンテキストを検索する代わりに、よく構造化された保管庫ノートからコンテキストブロックを事前に作成し、キャッシュします。
# 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の期限切れ。 各コンテキストブロックには有効期間があります。TTLが切れると、保管庫を再クエリしてブロックを再構築します。
- 保管庫の変更検出。 indexerがキャッシュ済みコンテキストブロックに寄与したファイルの変更を検出すると、そのブロックはただちに無効化されます。
トークン予算管理
セッションは、合計コンテキスト予算から始まります。キャッシュ済みブロックは、その予算の一部を消費します。
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)
キャッシュ済みブロックはセッション開始時に読み込まれます。動的な検索結果は、クエリごとに残りの予算を使って埋めます。このhybridアプローチにより、agentには頻繁に必要になるコンテキストの基礎が与えられつつ、特定のクエリ向けの予算も確保できます。
トークン使用量のBefore/After
キャッシュなし: 関連するクエリごとに保管庫検索が実行され、1,500〜2,000トークンのコンテキストが返ります。1セッションで10件のクエリがある場合、agentは15,000〜20,000トークンの保管庫コンテキストを消費します。
キャッシュあり: 事前作成された3つのコンテキストブロックが合計4,500トークンを消費します。追加検索では、ユニークなクエリごとに1,500〜2,000トークンが加わります。10件のクエリのうち6件がキャッシュ済みブロックでカバーされる場合、agentの消費量は4,500 + (4 * 1,500) = 10,500トークンとなり、キャッシュなしの場合のおよそ半分です。
コンテキスト圧縮のためのPostToolUse Hooks
ツール出力は冗長になりがちです。たとえば、スタックトレース、ファイル一覧、テスト結果などです。PostToolUse hookを使うと、これらの出力がコンテキストウィンドウの領域を消費する前に圧縮できます。
問題
テストを実行する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の実装
#!/bin/bash
# ~/.claude/hooks/post-tool-use/compress-output.sh
# Compress verbose tool outputs to preserve context window
TOOL_NAME="$1"
OUTPUT="$2"
OUTPUT_LEN=${#OUTPUT}
# Only compress large outputs
if [ "$OUTPUT_LEN" -lt 2000 ]; then
exit 0 # Pass through unchanged
fi
case "$TOOL_NAME" in
Bash)
# Compress test output
if echo "$OUTPUT" | grep -q "PASSED\|FAILED"; then
PASSED=$(echo "$OUTPUT" | grep -c "PASSED")
FAILED=$(echo "$OUTPUT" | grep -c "FAILED")
FAILURES=$(echo "$OUTPUT" | grep "FAILED")
echo "Tests: $PASSED passed, $FAILED failed"
if [ "$FAILED" -gt 0 ]; then
echo "Failures:"
echo "$FAILURES"
fi
fi
;;
esac
再帰的トリガーの防止
圧縮hookが出力を発すると、ガードしない限り自分自身をトリガーしてしまう可能性があります。
# Guard against recursive invocation
if [ -n "$COMPRESS_HOOK_ACTIVE" ]; then
exit 0
fi
export COMPRESS_HOOK_ACTIVE=1
圧縮ヒューリスティック
| 出力タイプ | 検出 | 圧縮戦略 |
|---|---|---|
| テスト結果 | PASSED / FAILEDキーワード |
成功/失敗を数え、失敗のみを表示 |
| ファイル一覧 | command内のlsまたはfind |
先頭20件 + 件数に切り詰め |
| スタックトレース | Tracebackキーワード |
最初と最後のフレーム + エラーメッセージを保持 |
| Git status | modified: / new file: |
status別に件数を要約 |
| ビルド出力 | warning: / error: |
情報行を削除し、警告/エラーを保持 |
シグナル取り込みとトリアージのパイプライン
取り込みレイヤーは、何を vault に入れるかを決めます。キュレーションがなければ、vault にはノイズが蓄積していきます。このセクションでは、シグナルをドメインフォルダへ振り分けるスコアリングパイプラインを扱います。
ソース
シグナルは複数のチャネルから入ってきます。
- RSS フィード: 技術ブログ、セキュリティ勧告、リリースノート
- Web Clipper 経由のブックマーク: 公式の Obsidian Web Clipper 拡張機能(Chrome、Firefox、Safari)は、ブラウザ側のキャプチャとして最も忠実度の高い取り込み経路です。2026年4月のリリースサイクルにより、AI ワークフローで実用性が大きく向上しました:22
- 1.4.0(4月9日): インタラクティブな YouTube transcript UI。動画を固定し、transcript をスクラブし、自動スクロールし、現在位置をハイライトできます。さらに、ワンクリックのキャプチャを Reader モードへ直接送る「Open in Reader」デフォルトも追加されました。
- 1.5.0–1.5.1(4月15日): Highlights viewer。vault 全体のキャプチャ済みハイライトを閲覧・検索できます。Reader へのフェードイン遷移、より滑らかな YouTube の再生/一時停止も追加されました。1.5.1 では webpack compilation regression が修正されています。
- 1.6.0–1.6.2(4月21–23日): モバイル対応を含む Highlighter UX の全面見直し。Defuddle 0.18 では LinkedIn、Threads、Bluesky、Discourse、Medium 向けのソース別 extractor が追加されました。1.6.2 では Safari embedded-mode clipboard regression が修正されています。 ソースドメインごとにテンプレートを設定し、YouTube transcripts、GitHub READMEs、長文記事が、それぞれ下のスコアリングパイプラインに適した frontmatter を持つ、わかりやすい名前のノートに入るようにします。
- ニュースレター: メールニュースレターからの重要な抜粋
- 手動キャプチャ: 読書中、会話中、調査中に書いたノート
- ツール出力: hooks 経由でキャプチャされた重要な AI ツール出力
- iOS Share Extension: Obsidian の iOS アプリ(2026年初頭に更新)には Share Extension が含まれており、Safari、ソーシャルネットワーク、その他のアプリからのコンテンツを、Obsidian を開かずに vault へ直接保存できます。19 これにより、モバイルで摩擦の少ない取り込み経路ができます。Safari から記事を共有すると、スコアリング可能な vault ノートとして届きます。
- Obsidian CLI: Shell scripts と hooks は、
obsidian file createでノートを作成したり、obsidian file appendで既存ノートに追記したりできます。これにより、デスクトップ上で自動取り込みパイプラインを構築できます。
スコアリングの軸
各シグナルは、4つの軸でスコアリングされます(それぞれ 0.0 から 1.0)。
| 軸 | 問い | 低スコア(0.0-0.3) | 高スコア(0.7-1.0) |
|---|---|---|---|
| 関連性 | 自分のアクティブなドメインに関係しているか? | 周辺的、スコープ外 | 現在の作業に直接関係する |
| 実行可能性 | この情報を使えるか? | 純粋な理論で、応用がない | 適用できる具体的な技法やパターンがある |
| 深さ | コンテンツにどれだけ実質があるか? | 見出し、浅い要約 | 例を含む詳細な分析 |
| 権威性 | ソースはどれだけ信頼できるか? | 匿名ブログ、未検証 | 一次ソース、査読済み、認知された専門家 |
複合スコアとルーティング
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 |
| 1日あたりの平均シグナル数 | 約18 |
Knowledge Graph パターン
Obsidian の wiki-link graph は、ノート間の関係をエンコードします。このセクションでは、リンクのセマンティクス、コンテキスト拡張のためのグラフ走査、そしてグラフ品質を下げるアンチパターンを扱います。
backlink のセマンティクス
すべての wiki-link は、グラフ内に有向エッジを作ります。Obsidian は forward links と backlinks の両方を追跡します。
- Forward link: Note A contains
[[Note B]]→ A links to B - Backlink: Note B shows that Note A references it
グラフは、文脈に応じて異なる種類の関係をエンコードします。
| リンクパターン | セマンティクス | 例 |
|---|---|---|
| インラインリンク | 「関連している」 | “See [[OAuth Token Rotation]] for details” |
| 見出しリンク | 「サブトピックを持つ」 | ”## Related\n- [[Token Rotation]]\n- [[Session Management]]” |
| タグ風リンク | 「分類されている」 | ”[[type/reference]]” |
| MOC link | 「一部である」 | 関連ノートを一覧化した Maps of Content ノート |
Maps of Content(MOCs)
MOCs は、関連ノートを移動しやすい構造へ整理するインデックスノートです。
---
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]]
MOCs は、retrieval に2つの形で役立ちます。
- 直接一致。 「authentication overview」を検索すると MOC 自体が一致し、agent に関連ノートのキュレーション済みリストを渡せます。
- コンテキスト拡張。 特定のノートが見つかった後、retriever はそのノートが MOCs に含まれているかを確認し、MOC の構造を結果に含められます。これにより、agent はより広いトピックの地図を得られます。
コンテキスト拡張のためのグラフ走査
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 のグラフパネルでは、こうしたクラスタが切り離された島として表示されます。孤立クラスタは、MOCs が不足しているか、ドメイン横断リンクが不足していることを示します。
タグの乱立。 タグを一貫性なく使ったり、細かすぎるタグを作りすぎたりすることです。5,000件のノートに 500個のユニークタグがある vault では、平均すると 10タグあたり 1ノートになります。これではタグはフィルタリングに役立ちません。ドメインフォルダに対応する 20〜50個の高レベルタグへ統合しましょう。
リンクは多いが内容が薄いノート。 prose がなく、wiki-links だけで構成されているノートです。この種のノートは、chunker が embedding するテキストを持たないため、インデックス品質が下がります。リンク先のノートがなぜ関連しているのかを説明する文脈を、少なくとも1段落追加してください。
あらゆるものへの双方向リンク。 すべての参照を wiki-link にする必要はありません。「OAuth」に軽く触れただけなら、[[OAuth 2.0 Overview]] は不要です。wiki-links は、クリックすると有用な文脈が得られる、意図的で移動可能な関係に限定しましょう。
開発者ワークフローのレシピ
vault(Obsidianの保管庫)検索と日々の開発タスクを組み合わせる実践的なワークフローです。
朝のコンテキスト読み込み
関連するコンテキストを読み込んで1日を始めます。
Search my vault for notes about [current project] updated in the last week
retrieverは、作業中のプロジェクトに関する最近のノートを返します。前回どこまで進めたかをすばやく思い出せます。昨日のコミットメッセージを読み返すより効果的です。
コーディング中のリサーチ記録
機能を実装している途中でも、エディタを離れずに気づきを記録できます。
/capture "FastAPI dependency injection with async generators requires yield,
not return. The generator is the dependency lifecycle."
--domain programming
--tags fastapi,dependency-injection
記録した気づきはすぐにindexされ、今後の検索で利用できるようになります。数か月かけて、こうした小さな記録が実装固有の知識コーパスを形成します。
プロジェクト開始
新しいプロジェクトや機能に着手するときは、次のように進めます。
- vaultを検索します: 「[technology/pattern]について何を知っているか?」
- 上位5件の結果を確認し、過去の判断や注意点を把握します
- その領域のMOCがあるか確認します。なければ作成します
- 失敗パターンを検索します: 「[technology]の問題」
Vault Searchでデバッグする
エラーや予期しない挙動に遭遇したときは、次のようにします。
Search my vault for [error message or symptom]
過去のデバッグノートには、根本原因と修正方法が含まれていることがよくあります。これは複数プロジェクトで繰り返し発生する問題に特に有効です。vaultは、忘れてしまうことを覚えていてくれます。
コードレビューの準備
PRをレビューする前に、次のようにします。
Search my vault for patterns and conventions about [module being changed]
vaultは、レビュー対象のコードに関連する過去の判断、アーキテクチャ上の制約、コーディング標準を返します。レビューはdiffだけでなく、組織的な知識に基づいたものになります。
パフォーマンスチューニング
このセクションでは、vaultのサイズや利用パターンに応じた最適化戦略を扱います。
Indexサイズの管理
| Vaultサイズ | チャンク数 | 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に増やす - 同時アクセスのためにWAL mode(デフォルト)を使用する - フルreindexは利用の少ない時間帯に実行する
Query最適化
WAL mode。 SQLiteのWrite-Ahead Logging modeでは、indexerが書き込み中でも並行して読み取りできます。
db.execute("PRAGMA journal_mode=WAL")
これは、indexerが差分更新を実行している間にMCPサーバーがクエリを処理する場合に重要です。
Connection pooling。 MCPサーバーは、クエリごとに新しい接続を開くのではなく、データベース接続を再利用するべきです。WAL modeの単一の長寿命接続で、並行読み取りをサポートできます。
# 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は、データベースファイルにmemory-mapped I/Oを使うようSQLiteに指示します。83 MBのデータベースであれば、ファイル全体をメモリにマッピングすることで、ほとんどのディスク読み取りをなくせます。
FTS5最適化。 フルreindexの後に、次を実行します。
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');
これによりFTS5内部のb-treeセグメントがマージされ、その後の検索でクエリレイテンシが低下します。
スケーリングベンチマーク
Apple M3 Pro、36 GB RAM、NVMe SSDで測定しました。
| 操作 | 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 |
すべてのベンチマークには、データベースアクセス、クエリ実行、結果フォーマットを含みます。MCP STDIO通信のネットワークレイテンシにより、1〜2msが追加されます。
トラブルシューティング
Index Drift
症状: 検索で古い結果が返る、または最近追加したノートが見つかりません。
原因: ノート追加後に差分indexerが実行されていないか、ファイルのmtimeが更新されていません(例: タイムスタンプを保持したまま別のマシンから同期された場合)。
修正: フルreindexを実行します: python index_vault.py --full
Embeddingモデルの切り替え
症状: embeddingモデルを変更した後、ベクトル検索が意味不明な結果を返します。
原因: 古いベクトル(以前のモデル由来)が、新しいクエリベクトルと比較されています。次元数またはベクトル空間の意味が互換性を持ちません。
修正: indexerがモデルハッシュの不一致を検出し、自動的にフルreindexをトリガーするべきです。そうならない場合は、手動でデータベースをクリアしてreindexします。
rm vectors.db
python index_vault.py --full
FTS5メンテナンス
症状: 多数の差分更新後に、FTS5クエリが不正確または不完全な結果を返します。
原因: 小さな更新を多数行ったことで、FTS5内部セグメントが断片化している可能性があります。
修正: rebuildとoptimizeを実行します。
INSERT INTO chunks_fts(chunks_fts) VALUES('rebuild');
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');
MCP Timeout
症状: AIツールが、MCPサーバーがタイムアウトしたと報告します。
原因: 最初のクエリでモデルの読み込み(遅延初期化)が発生し、2〜5秒かかります。AIツールのデフォルトのMCPタイムアウトがそれより短い可能性があります。
修正: サーバー起動時にモデルを事前に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エラーが発生します。
原因: 複数のプロセスが同時にデータベースへ書き込んでいます。WAL modeは並行読み取りを可能にしますが、writerは1つだけです。
修正: データベースへ書き込むプロセスは1つ(indexer)だけにしてください。MCPサーバーとhooksは読み取り専用にします。同時書き込みが必要な場合は、WAL modeを使用し、busy timeoutを設定します。
db.execute("PRAGMA busy_timeout=5000") # Wait up to 5 seconds
sqlite-vecが読み込まれない
症状: ベクトル検索が無効化され、retrieverがBM25-only modeで動作します。
原因: sqlite-vec拡張がインストールされていない、ライブラリパス上で見つからない、またはSQLiteのバージョンと互換性がありません。
修正:
# Install via pip
pip install sqlite-vec
# Or compile from source
git clone https://github.com/asg017/sqlite-vec
cd sqlite-vec && make
拡張が読み込めることを確認します。
import sqlite3
db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
db.load_extension("vec0")
print("sqlite-vec loaded successfully")
大規模Vaultのメモリ問題
症状: 大規模vault(50,000件以上のノート)のフルreindex中にout-of-memoryエラーが発生します。
原因: embeddingのbatch_sizeが大きすぎるか、すべてのファイル内容を同時にメモリへ読み込んでいます。
修正: batch_sizeを下げ、ファイルを差分的に処理します。
BATCH_SIZE = 32 # Reduce from 64
また、indexerがすべてのファイルをメモリに読み込むのではなく、1ファイルずつ処理していることも確認してください。各ファイルを読み込み、chunkingし、embeddingしてから次のファイルへ進む形です。
移行ガイド
Apple Notesから
- Apple Notesを「Export All」オプション(macOS)でエクスポートするか、
apple-notes-liberatorのような移行ツールを使用します markdownifyまたはpandocを使って、HTMLエクスポートをmarkdownに変換します- 変換したファイルをvaultの
00-inbox/フォルダへ移動します - 各ノートを確認し、frontmatterを追加します
- ノートを適切なドメインフォルダへ移動します
Notionから
- Notionからエクスポートします: Settings → Export → Markdown & CSV
- エクスポートを解凍し、vaultの
00-inbox/フォルダに配置します - Notion固有のmarkdown生成物を修正します。
- Notionはチェックリストに
- [ ]を使用します。これは標準のmarkdownです - NotionはプロパティテーブルをHTMLとして含めます。YAML frontmatterに変換します
- Notionは画像を相対パスとして埋め込みます。画像をattachmentsフォルダへコピーします
- 標準frontmatter(
type、domain、tags)を追加します - NotionページリンクをObsidian wiki-linksに置き換えます
Google Docsから
- Google Takeoutを使ってすべてのドキュメントをエクスポートします
.docxファイルをmarkdownに変換します:pandoc -f docx -t markdown input.docx -o output.md- 一括変換します:
for f in *.docx; do pandoc -f docx -t markdown "$f" -o "${f%.docx}.md"; done - vaultへ移動し、frontmatterを追加して、フォルダに整理します
プレーンMarkdownから(Obsidianなし)
すでにmarkdownファイルのディレクトリがある場合は、次のようにします。
- そのディレクトリをObsidian vaultとして開きます(Obsidian → Open Vault → Open folder)
- ディレクトリをバージョン管理している場合は、
.obsidian/を.gitignoreに追加します - frontmatterテンプレートを作成し、既存ファイルへ適用します
- 読みながら整理しつつ、
[[wiki-links]]でノートをリンクし始めます - すぐにindexerを実行します。検索システムは初日から機能します
別の検索システムから
別のembedding/searchシステムから移行する場合は、次のようにします。
- ベクトルを移行しようとしないでください。 モデルが異なると、互換性のないベクトル空間が生成されます。新しいモデルでフルreindexを実行してください。
- indexではなく、コンテンツを移行してください。 vaultファイルがsource of truthです。indexは派生物にすぎません。
- 移行後に検証してください。 答えが分かっているクエリを10〜20件実行し、結果が期待どおりか確認します。
変更履歴
| 日付 | 変更 |
|---|---|
| 2026-05-28 | Obsidian 1.13.0 desktop + 1.13.0 mobile(Catalyst early-access)がリリースされました。Desktop: 独立したウィンドウで開き、組み込み検索とキーボードナビゲーションを備えた新しい設定パネル、Obsidian URIs がアクション実行前に確認ダイアログを表示するようになりました。ネットワークドライブから HTML リソースを読み込む前の新しい警告、Bookmarks ビューへの検索追加、エディターでの画像処理の強化、File Explorer / Properties / Sync の改善、多数の開発者向け API とバグ修正も含まれます。Mobile: 設定可能な保存先を備えた新しい iOS Share Sheet、タブスイッチャーからのタブ並べ替え、タブレットで分割ペインや固定サイドバーのサイズを変更できる長押しジェスチャー、Bases のテーブルビューで列幅を変更するメニュー項目、iOS と検索のバグ修正が追加されました。AI ワークフローへの影響として、Obsidian URIs の確認ダイアログは、URI 駆動の MCP/agent 連携に意図的なゲートを追加します。Bases の列幅変更メニューにより、agent がクエリする vault フロントのインデックスとして Bases がより使いやすくなります。iOS Share Sheet の設定可能な保存先により、主要な取り込み経路として既に文書化されている iPhone のキャプチャ経路を、Claude/Codex パイプラインへより素早く接続できます。 |
| 2026-05-06 | ソース検証済みの最新性を更新しました。Smart Connections v4.5.0 ではフッターの connections が Core に移動しました。sqlite-vec v0.1.8/v0.1.9 の安定版リリースでは、パッケージングと DELETE 動作が更新されました。Model2Vec v0.8.x では tokenizer/永続化の内部実装とベンチマーク表が更新されました。Obsidian CLI の時系列を、「1.12.7 で CLI が導入された」から「1.12.0 で CLI が導入され、1.12.7 でインストール/runtime パッケージングが改善された」に修正しました。 |
| 2026-04-27 | Web Clipper の4月サイクル: 1.4.0(インタラクティブな 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 を、単なるブックマーク的な言及ではなく、AI ワークフローにおける主要なブラウザー側取り込み経路として位置づけ直しました。この期間中、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 プラグインの波(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 向けの推奨ブリッジであり続けます。 |
| 2026-04-01 | Obsidian CLI セクション(AI ワークフロー向け v1.12 コマンド)を追加しました。agent プラグインセクション(Claudian、Agent Client)を追加しました。vault 整理用の Bases core 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 操作用に CLI binary が同梱されました。 |
| 2026-03-23 | sqlite-vec v0.1.7 stable を文書化しました。vec0 テーブルの 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 仕様と検索技術が現行であることを確認しました。 |
| 2026-03-03 | MCP 仕様の進化を更新しました(2025年11月に出荷: Streamable HTTP、.well-known、tool annotations)。Model2Vec の fine-tuning と BPE/Unigram tokenizer 対応を追加しました。community MCP server 比較表を追加しました。Smart Connections を v4 に更新しました。 |
| 2026-03-02 | モデル比較に potion-base-32M と potion-retrieval-32M を追加しました。quantization/dimensionality reduction セクションを追加しました。MCP 仕様の進化に関する注記を追加しました。 |
| 2026-03-01 | 初回リリース |
参照
-
Internet Vin, “Obsidian と Claude Code で使っている22個のコマンド,” 2026年3月, x.com/internetvin/status/2026461256677245131. ↩
-
Nicopreme, slash commands 付きの「Visual Explainer」agent skill, x.com/nicopreme/status/2023495040258261460. ↩
-
Cormack, G.V., Clarke, C.L.A., and Buettcher, S. Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods. SIGIR, 2009. RRFを、順位付きリストを組み合わせるためのパラメーター不要の手法として、k=60とともに紹介しています。 ↩↩↩
-
OpenAI Embeddings Pricing. text-embedding-3-small: 100万トークンあたり$0.02。vaultの全再インデックスにかかる推定コストは約$0.30です。 ↩
-
van Dongen, T. et al. Model2Vec: Turn any Sentence Transformer into a Small Fast Model. arXiv, 2025. sentence transformerから静的embeddingsを生成する蒸留アプローチを説明しています。 ↩
-
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。現在のモデルカードでは、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 standardizationが提供されました。次回リリースは暫定的に2026年半ばで、async operations、domain-specific extensions、agent-to-agent communicationが予定されています。 ↩↩
-
Model2Vec Releases。v0.4.0(2025年2月): training/fine-tuning support。v0.5.0(2025年4月): backend rewrite、quantization、dimensionality reduction。v0.7.0(2025年10月): vocabulary quantization、BPE/Unigram tokenizer support。v0.8.0/v0.8.1(2026年3月): tokenizerとpersistenceのリファクタリング、Python 3.9 deprecation、MTEB V2 result updates、Windows path compatibility。 ↩↩
-
Smart Connections for Obsidian。Smart Connections v4: local-first AI embeddingsに対応し、初回インデックス作成後はsemantic searchをオフラインで利用できます。 ↩
-
potion-multilingual-128M。Minish Lab、2025年5月。101言語対応の静的embeddingモデルで、multilingual static embeddingsとして最高性能です。他のpotionモデルと同じく、依存関係はnumpyのみです。 ↩
-
MCPVault v0.11.0。2026年3月。frontmatterとhashtagsを件数付きでスキャンする新しい
list_all_tagsツールが追加されました。ドット付きフォルダーの扱い、.baseおよび.canvasファイル対応も改善されています。npmではパッケージ名が@bitbonsai/mcpvaultに変更されました。 ↩ -
sqlite-vec v0.1.7 Release。2026年3月17日。安定版リリースです。vec0仮想テーブルのDELETE対応、ページネーション向けのKNN距離制約、fuzz testingの改善が含まれています。DiskANN近似最近傍インデックスは将来リリース向けとして発表されました。 ↩↩↩
-
Introduction to Bases。Obsidian v1.9.10で導入されたコアプラグインです。frontmatterプロパティをフィールドとして使い、vaultファイル上にデータベース風のビュー(テーブル、ギャラリー、カレンダー、kanban boards)を作成できます。ファイルは
.base形式で保存されます。 ↩ -
Obsidian Desktop v1.12.0 ChangelogおよびObsidian Desktop v1.12.7 Changelog。v1.12.0では、ターミナルベースのvault自動化向けにCLIが導入されました。v1.12.7では、standalone binary、TUI、socket-file behaviorにより、インストールと実行時パッケージングが改善されています。CLI documentationもご覧ください。 ↩↩
-
Claudian。Claude Codeをvault内のAIコラボレーターとして組み込むObsidianプラグインです。サイドバーchat、context-aware prompts、vision support、slash commands、permission modesを提供します。 ↩
-
Agent Client。Agent Client Protocol (ACP)経由で、Claude Code、Codex CLI、Gemini CLI向けの統一インターフェースを提供するObsidianプラグインです。note mentions、shell execution、action approvalに対応しています。 ↩
-
Obsidian iOS Changelog。2026年初頭の更新には、他のアプリから直接vaultへコンテンツを保存するShare Extension、Daily NoteとBookmark widgetの修正、View Note widgetの更新改善が含まれます。 ↩
-
MarkusPfundstein/mcp-obsidian。最終コミットは2025年6月28日。タグ付きリリースはありません。フォーラムでの議論(2026年4月)では、Obsidian 1.12.xで第一級のCLIが提供されたため、コミュニティはCLIベースの統合へ移行していると報告されています。このガイドでは歴史的背景と既存セットアップのユーザー向けに残していますが、新規導入には推奨しません。 ↩↩
-
Smart Connections v4.5.0 Release。2026年5月5日。Footer connectionsがCore機能になりました。最近のv4リリースには、connection lists向けgraph views、設定可能なconnection-panel locations、改善されたblock-embedding recovery、Substrate cross-plugin state、transformer fallback fixes、重複したconnection calculationsの削減も含まれています。 ↩
-
obsidianmd/obsidian-clipper releases — Web Clipperのバージョンと機能の対応を確認する一次情報源です。2026年4月のサイクル: 1.4.0(4月9日、YouTube transcript UI + Open in Reader default)、1.5.0(4月15日、Highlights viewer + Reader fade-in)、1.5.1(4月15日、webpack compilation fix)、1.6.0(4月21日、Highlighter UX + Defuddle 0.18 with LinkedIn/Threads/Bluesky/Discourse/Medium extractors)、1.6.1(4月22日、Reader outline fixes + highlights search)、1.6.2(4月23日、Safari embedded-mode clipboard fix)。Mozilla Add-ons storeおよびChrome Web Storeにも掲載されています。 ↩
-
sqlite-vec v0.1.8、sqlite-vec v0.1.9、およびsqlite-vec v0.1.10-alpha.3。v0.1.8ではnpm packagingが修正されました。v0.1.9では、12文字を超えるmetadata text columnsに対するDELETE bugが修正されています。v0.1.10-alpha.3では適切な
INSERT OR REPLACE INTO対応が追加されていますが、prereleaseです。 ↩↩↩