obsidian:~/vault$ search --hybrid obsidian

Example vault location

#

words: 10082 read_time: 51m updated: 2026-03-05 07:05
$ retriever search --hybrid obsidian

Wichtigste Erkenntnisse

Context Engineering, nicht Notizen machen. Der Wert eines Obsidian-Vaults für KI liegt nicht in den Notizen selbst, sondern in der Abrufschicht, die sie abfragbar macht. Ein Vault mit 16.000 Dateien ohne Abrufmechanismus ist eine schreibgeschützte Datenbank. Ein Vault mit 200 Dateien mit hybrider Suche und MCP-Integration ist eine KI-Wissensbasis. Die Abrufinfrastruktur ist das Produkt. Die Notizen sind das Rohmaterial.

Hybrides Retrieval schlägt reine Stichwort- oder reine semantische Suche. BM25 erfasst exakte Bezeichner und Funktionsnamen. Vektorsuche erfasst Synonyme und konzeptuelle Übereinstimmungen über verschiedene Terminologien hinweg. Reciprocal Rank Fusion (RRF) vereint beide Ansätze, ohne dass eine Score-Kalibrierung erforderlich ist. Keine der beiden Methoden allein deckt beide Fehlermodi ab. Forschung zu MS MARCO Passage Ranking bestätigt dieses Muster: Hybrides Retrieval übertrifft konsistent jede einzelne Methode.1 Der Deep Dive zum hybriden Retriever behandelt die RRF-Mathematik, durchgerechnete Beispiele mit realen Zahlen, Fehlermodus-Analyse und einen interaktiven Fusion-Rechner.

MCP gibt KI-Tools direkten Vault-Zugriff. Model Context Protocol (MCP)-Server stellen den Retriever als Tool bereit, das Claude Code, Codex CLI, Cursor und andere KI-Tools direkt aufrufen können. Der Agent fragt den Vault ab, erhält bewertete Ergebnisse mit Quellenangabe und nutzt den Kontext, ohne ganze Dateien laden zu müssen. Der MCP-Server ist ein dünner Wrapper um die Abruf-Engine.

Local-first bedeutet keine API-Kosten und volle Privatsphäre. Der gesamte Stack läuft auf einer einzigen Maschine: SQLite für die Speicherung, Model2Vec für Embeddings, FTS5 für die Stichwortsuche, sqlite-vec für Vektor-KNN. Keine Cloud-Dienste, keine API-Aufrufe, keine Netzwerkabhängigkeit. Persönliche Notizen verlassen niemals den Rechner. Das vollständige Neu-Embedding von 49.746 Chunks würde bei OpenAI-API-Preisen etwa 0,30 $ kosten, doch die eigentlichen Kosten sind Latenz, Preisgabe der Privatsphäre und die Netzwerkabhängigkeit eines Systems, das offline funktionieren sollte.2

Inkrementelle Indexierung hält das System in unter 10 Sekunden aktuell. Der Vergleich der Dateiänderungszeiten erkennt Änderungen. Nur geänderte Dateien werden neu aufgeteilt und neu eingebettet. Eine vollständige Neuindexierung dauert auf Apple M-Serie-Hardware etwa vier Minuten. Inkrementelle Aktualisierungen bei den Bearbeitungen eines typischen Tages laufen in unter zehn Sekunden. Das System bleibt ohne manuelles Eingreifen aktuell.

Die Architektur skaliert von 200 bis über 20.000 Notizen. Das gleiche dreischichtige Design (Aufnahme, Abruf, Integration) funktioniert bei jeder Vault-Größe. Beginnen Sie mit einer reinen BM25-Suche über einen kleinen Vault. Fügen Sie Vektorsuche hinzu, wenn Stichwort-Kollisionen zum Problem werden. Fügen Sie RRF-Fusion hinzu, wenn Sie sowohl exakte als auch semantische Treffer benötigen. Jede Schicht ist unabhängig nutzbar und unabhängig entfernbar.


Wie Sie diesen Leitfaden nutzen

Dieser Leitfaden behandelt das vollständige System. Ihr Einstiegspunkt hängt davon ab, wo Sie stehen:

Sie sind… Beginnen Sie hier Dann erkunden Sie
Neu bei Obsidian + KI Warum Obsidian für KI-Infrastruktur, Schnellstart Vault-Architektur, MCP-Server-Architektur
Bestehender Vault, KI-Zugriff gewünscht MCP-Server-Architektur, Claude Code-Integration Embedding-Modelle, Volltextsuche
Aufbau eines Abrufsystems Die vollständige Abruf-Pipeline, Reciprocal Rank Fusion Performance-Optimierung, Fehlerbehebung
Team- oder Unternehmenskontext Entscheidungsrahmen, Knowledge-Graph-Muster Entwickler-Workflow-Rezepte, Migrationsleitfaden

Abschnitte mit der Kennzeichnung Contract enthalten Implementierungsdetails, Konfigurationsblöcke und Fehlermodi. Abschnitte mit der Kennzeichnung Narrative konzentrieren sich auf Konzepte, Architekturentscheidungen und die Begründung hinter Designentscheidungen. Abschnitte mit der Kennzeichnung Recipe bieten schrittweise Anleitungen.


Warum Obsidian für KI-Infrastruktur

Die These dieses Leitfadens: Obsidian-Vaults sind das beste Substrat für persönliche KI-Wissensbasen, weil sie lokal-zuerst, im Klartext, graphstrukturiert sind und Sie als Benutzer jede Schicht des Stacks kontrollieren.

Was Obsidian der KI bietet, was Alternativen nicht bieten

Klartext-Markdown-Dateien. Jede Notiz ist eine .md-Datei in Ihrem Dateisystem. Kein proprietäres Format, kein Datenbankexport, keine API erforderlich, um den Inhalt zu lesen. Jedes Tool, das Dateien lesen kann, kann Ihren Vault lesen. grep, ripgrep, Pythons pathlib, SQLite FTS5 — sie alle arbeiten direkt mit den Quelldateien. Wenn Sie ein Abrufsystem bauen, indexieren Sie Dateien, keine API-Antworten. Der Index ist immer konsistent mit der Quelle, weil die Quelle das Dateisystem ist.

Local-first-Architektur. Der Vault liegt auf Ihrem Rechner. Kein Server, keine Cloud-Sync-Abhängigkeit, keine API-Ratenbegrenzungen, keine Nutzungsbedingungen, die regeln, wie Sie Ihre eigenen Inhalte verarbeiten. Sie können Ihre Notizen einbetten, indexieren, aufteilen und durchsuchen, ohne einen externen Dienst zu benötigen. Das ist für KI-Infrastruktur relevant, weil die Abruf-Pipeline so schnell läuft, wie Ihre Festplatte es zulässt, nicht so schnell, wie ein API-Endpunkt antwortet. Es ist auch für den Datenschutz relevant: Persönliche Notizen mit Zugangsdaten, Gesundheitsdaten, Finanzinformationen und privaten Reflexionen verlassen niemals Ihren Rechner.

Graphstruktur durch Wiki-Links. Obsidians [[wiki-link]]-Syntax erzeugt einen gerichteten Graphen über Notizen hinweg. Eine Notiz über die OAuth-Implementierung verlinkt auf Notizen über Token-Rotation, Sitzungsverwaltung und API-Sicherheit. Die Graphstruktur kodiert von Menschen kuratierte Beziehungen zwischen Konzepten. Vektor-Embeddings erfassen semantische Ähnlichkeit, aber Wiki-Links erfassen beabsichtigte Verbindungen, die der Autor beim Nachdenken über das Thema hergestellt hat. Der Graph ist ein Signal, das Embeddings nicht replizieren können.

Plugin-Ökosystem. Obsidian verfügt über mehr als 1.800 Community-Plugins. Dataview fragt Ihren Vault wie eine Datenbank ab. Templater generiert Notizen aus Vorlagen mit JavaScript-Logik. Git-Integration synchronisiert Ihren Vault mit einem Repository. Linter erzwingt Formatierungskonsistenz. Diese Plugins fügen dem Vault Struktur hinzu, ohne das zugrunde liegende Klartext-Format zu ändern. Das Abrufsystem indexiert die Ausgabe dieser Plugins, nicht die Plugins selbst.

Über 5 Millionen Benutzer. Obsidian hat eine große aktive Community, die Vorlagen, Workflows, Plugins und Dokumentation erstellt. Wenn Sie auf ein Problem mit der Vault-Organisation oder Plugin-Konfiguration stoßen, hat wahrscheinlich bereits jemand eine Lösung dokumentiert. Die Community produziert auch Obsidian-nahe Tools: MCP-Server, Indexierungsskripte, Publishing-Pipelines und API-Wrapper.

Was ein Dateisystem allein nicht bietet

Ein Verzeichnis mit Markdown-Dateien hat den Klartext-Vorteil, aber es fehlen drei Dinge, die Obsidian hinzufügt:

  1. Bidirektionale Links. Obsidian verfolgt Backlinks automatisch. Wenn Sie von Notiz A auf Notiz B verlinken, zeigt Notiz B an, dass Notiz A darauf verweist. Das Graph-Panel visualisiert Verbindungscluster. Dieses bidirektionale Bewusstsein sind Metadaten, die ein reines Dateisystem nicht bereitstellt.

  2. Live-Vorschau mit Plugin-Rendering. Dataview-Abfragen, Mermaid-Diagramme und Callout-Blöcke werden in Echtzeit gerendert. Das Schreiberlebnis ist reichhaltiger als in einem Texteditor, während das Speicherformat reiner Klartext bleibt. Sie schreiben und organisieren in einer komfortablen Umgebung; das Abrufsystem indexiert das rohe Markdown.

  3. Community-Infrastruktur. Plugin-Entdeckung, Theme-Marktplatz, Sync-Dienst (optional), Publish-Dienst (optional) und ein Dokumentations-Ökosystem. Sie können jede einzelne Funktion mit eigenständigen Tools nachbilden, aber Obsidian bündelt sie zu einem kohärenten Workflow.

Was Obsidian NICHT tut (und was Sie selbst bauen)

Obsidian enthält keine Abrufinfrastruktur. Es hat eine einfache Suche (Volltext, Dateiname, Tag), aber keine Embedding-Pipeline, keine Vektorsuche, kein Fusion-Ranking, keinen MCP-Server, keine Zugangsdatenfilterung, keine Chunking-Strategie und keine Integrationshaken für externe KI-Tools. Dieser Leitfaden behandelt die Infrastruktur, die Sie auf Obsidian aufbauen. Der Vault ist das Substrat. Die Abruf-Pipeline, der MCP-Server und die Integrationshaken sind die Infrastruktur.

Die hier beschriebene Architektur ist Markdown-first, nicht Obsidian-exklusiv. Wenn Sie Logseq, Foam, Dendron oder ein einfaches Verzeichnis mit Markdown-Dateien verwenden, funktioniert die Abruf-Pipeline identisch. Der Chunker liest .md-Dateien. Der Embedder verarbeitet Textzeichenketten. Der Indexer schreibt in SQLite. Keine dieser Komponenten hängt von Obsidian-spezifischen Funktionen ab. Obsidians Beitrag ist die Schreib- und Organisationsumgebung, die die Markdown-Dateien produziert, die der Retriever indexiert.


Schnellstart: Erster AI-verbundener Vault

Dieser Abschnitt verbindet einen Vault in fünf Minuten mit einem AI-Tool. Sie installieren Obsidian, erstellen einen Vault, installieren einen MCP-Server und führen Ihre erste Abfrage aus. Der Schnellstart verwendet einen Community-MCP-Server für sofortige Ergebnisse. Spätere Abschnitte behandeln den Aufbau einer benutzerdefinierten Retrieval-Pipeline für den Produktionseinsatz.

Voraussetzungen

  • macOS, Linux oder Windows
  • Node.js 18+ (für den MCP-Server)
  • Claude Code, Codex CLI oder Cursor installiert

Schritt 1: Vault erstellen

Laden Sie Obsidian von obsidian.md herunter und erstellen Sie einen neuen Vault. Wählen Sie einen Speicherort, den Sie sich merken können — der MCP-Server benötigt den absoluten Pfad.

# Example vault location
~/Documents/knowledge-base/

Fügen Sie einige Notizen hinzu, damit der Retriever etwas zum Durchsuchen hat. Bereits 10–20 Notizen reichen aus, um Ergebnisse zu sehen. Jede Notiz sollte eine .md-Datei mit einem aussagekräftigen Titel und mindestens einem Absatz Inhalt sein.

Schritt 2: MCP-Server installieren

Mehrere Community-MCP-Server bieten sofortigen Vault-Zugriff. Das Ökosystem ist im Zeitraum 2025–2026 erheblich gewachsen:

Server Autor Transport Plugin erforderlich Hauptfunktion
obsidian-mcp-server StevenStavrakis STDIO Nein Leichtgewichtig, dateibasiert
mcp-obsidian MarkusPfundstein STDIO Local REST API Vollständige Vault-CRUD-Operationen via REST
obsidian-mcp-tools jacksteamdev STDIO Ja (Plugin) Semantische Suche + Templater
obsidian-claude-code-mcp iansinnott WebSocket Ja (Plugin) Auto-Discovery für Claude Code
obsidian-mcp-server cyanheads STDIO Local REST API Tags, Frontmatter-Verwaltung

Für den Schnellstart ist die einfachste Option ein dateibasierter Server, der .md-Dateien direkt liest:

npm install -g obsidian-mcp-server

Schritt 3: Ihr AI-Tool konfigurieren

Claude Code — fügen Sie Folgendes zu ~/.claude/settings.json hinzu:

{
  "mcpServers": {
    "obsidian": {
      "command": "obsidian-mcp-server",
      "args": ["--vault", "/absolute/path/to/your/vault"]
    }
  }
}

Codex CLI — fügen Sie Folgendes zu .codex/config.toml hinzu:

[mcp_servers.obsidian]
command = "obsidian-mcp-server"
args = ["--vault", "/absolute/path/to/your/vault"]

Cursor — fügen Sie Folgendes zu .cursor/mcp.json hinzu:

{
  "mcpServers": {
    "obsidian": {
      "command": "obsidian-mcp-server",
      "args": ["--vault", "/absolute/path/to/your/vault"]
    }
  }
}

Schritt 4: Erste Abfrage ausführen

Öffnen Sie Ihr AI-Tool und stellen Sie eine Frage, die Ihre Vault-Notizen beantworten können:

Search my Obsidian vault for notes about [topic you wrote about]

Das AI-Tool ruft den MCP-Server auf, der Ihren Vault durchsucht und passende Inhalte zurückgibt. Sie sollten Ergebnisse mit Dateipfaden und relevanten Auszügen sehen.

Was Sie gerade aufgebaut haben

Sie haben eine lokale Wissensbasis über ein Standardprotokoll mit einem AI-Tool verbunden. Der MCP-Server liest Ihre Vault-Dateien, führt eine einfache Suche durch und gibt Ergebnisse zurück. Dies ist die minimale funktionsfähige Version.

Was dieser Schnellstart NICHT bietet: - Hybrides Retrieval (BM25 + Vektorsuche + RRF-Fusion) - Embedding-basierte semantische Suche - Credential-Filterung - Inkrementelle Indizierung - Hook-basierte automatische Kontexteinspeisung

Der Rest dieses Leitfadens behandelt den Aufbau jeder dieser Funktionen. Der Schnellstart beweist das Konzept. Die vollständige Pipeline liefert Retrieval in Produktionsqualität.


Entscheidungsrahmen: Obsidian vs. Alternativen

Nicht jeder Anwendungsfall benötigt Obsidian. Dieser Abschnitt zeigt auf, wann Obsidian das richtige Fundament ist, wann es überdimensioniert ist und wann eine andere Lösung besser passt.

Entscheidungsbaum

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.

Vergleichsmatrix

Kriterium Obsidian Notion Apple Notes Einfaches Dateisystem CLAUDE.md
Lokal-zuerst Ja Nein (Cloud) Teilweise (iCloud) Ja Ja
Klartext Ja (Markdown) Nein (Blöcke) Nein (proprietär) Ja Ja
Graphstruktur Ja (Wiki-Links) Teilweise (Erwähnungen) Nein Nein Nein
AI-indizierbar Direkter Dateizugriff API erforderlich Export erforderlich Direkter Dateizugriff Bereits im Kontext
Plugin-Ökosystem 1.800+ Plugins Integrationen Keine N/A N/A
Offlinefähig Vollständig Nur gecachtes Lesen Teilweise Vollständig Vollständig
Skaliert auf 10.000+ Notizen Ja Ja (mit API) Verschlechtert sich Ja Nein (einzelne Datei)
Kosten Kostenlos (Kern) ab 10 $/Monat Kostenlos Kostenlos Kostenlos

Wann Obsidian überdimensioniert ist

  • Einzelprojekt-Kontext. Wenn die AI nur Kontext zum aktuellen Codebase benötigt, verwenden Sie CLAUDE.md, AGENTS.md oder Dokumentation auf Projektebene. Diese Dateien werden mit dem Repository mitgeführt und automatisch geladen.
  • Strukturierte Daten. Wenn der Inhalt aus Tabellen, Datensätzen oder Schemata besteht, verwenden Sie eine Datenbank. Obsidian-Notizen sind primär für Fließtext konzipiert. Dataview kann Frontmatter-Felder abfragen, aber eine echte Datenbank bewältigt strukturierte Abfragen besser.
  • Temporäre Recherche. Wenn die Notizen nach Projektende verworfen werden, ist ein Arbeitsverzeichnis mit Markdown-Dateien einfacher. Bauen Sie keine Retrieval-Infrastruktur für kurzlebige Inhalte auf.

Wann Obsidian die richtige Wahl ist

  • Wissen, das über Monate oder Jahre wächst. Der Wert steigt mit wachsendem Korpus. Ein Vault mit 200 Notizen, der sechs Monate lang täglich abgefragt wird, liefert mehr Wert als ein Vault mit 5.000 Notizen, der einmal abgefragt wird.
  • Mehrere Domänen in einem Korpus. Ein Vault mit Notizen zu Programmierung, Architektur, Sicherheit, Design und persönlichen Projekten profitiert von domänenübergreifendem Retrieval, das eine projektspezifische CLAUDE.md nicht bieten kann.
  • Datenschutzsensible Inhalte. Der Lokal-zuerst-Ansatz bedeutet, dass die Retrieval-Pipeline niemals Inhalte an externe Dienste sendet. Der Vault enthält alles, was Sie hineinlegen — einschließlich Inhalte, die Sie nicht auf einen Cloud-Dienst hochladen würden.

Mentales Modell: Drei Schichten

Das System besteht aus drei Schichten, die unabhängig voneinander arbeiten, sich aber in Kombination gegenseitig verstärken. Jede Schicht hat eine eigene Zuständigkeit und einen eigenen Fehlermodus.

┌─────────────────────────────────────────────────────┐
                 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 bestimmt, was in den Vault gelangt. Ohne Kuratierung sammelt der Vault Rauschen an: Screenshots von Tweets, kopierte Artikel ohne Anmerkungen, halbfertige Gedanken ohne Kontext. Die Intake-Schicht ist für die Qualitätskontrolle am Eingangspunkt verantwortlich. Eine Bewertungs-Pipeline, Tagging-Konvention oder ein manueller Überprüfungsprozess — jeder Mechanismus, der sicherstellt, dass der Vault Inhalte enthält, die es wert sind, abgerufen zu werden.

Retrieval macht den Vault abfragbar. Dies ist der Motor: Notizen in Sucheinheiten aufteilen (Chunking), Chunks in den Vektorraum einbetten (Embeddings), für Keyword- und semantische Suche indexieren und Ergebnisse mit RRF fusionieren. Die Retrieval-Schicht verwandelt ein Verzeichnis von Dateien in eine abfragbare Wissensdatenbank. Ohne diese Schicht ist der Vault nur durch manuelles Durchsuchen und einfache Suche navigierbar, aber nicht programmatisch für AI-Tools zugänglich.

Integration verbindet die Retrieval-Schicht mit AI-Tools. Ein MCP-Server stellt Retrieval als aufrufbares Tool bereit. Hooks injizieren Kontext automatisch. Skills erfassen neues Wissen zurück in den Vault. Die Integrationsschicht ist die Schnittstelle zwischen der Wissensdatenbank und den AI-Agenten, die sie nutzen.

Die Schichten sind bewusst entkoppelt. Die Intake-Bewertungs-Pipeline weiß nichts über Embeddings. Der Retriever weiß nichts über Signal-Routing-Regeln. Der MCP-Server weiß nichts darüber, wie Notizen erstellt wurden. Diese Entkopplung bedeutet, dass Sie jede Schicht unabhängig verbessern können. Ersetzen Sie das Embedding-Modell, ohne die Intake-Pipeline zu ändern. Fügen Sie eine neue MCP-Fähigkeit hinzu, ohne den Retriever zu modifizieren. Ändern Sie die Signal-Bewertungsheuristiken, ohne den Index anzufassen.


Vault-Architektur für AI-Nutzung

Ein für AI-Retrieval optimierter Vault folgt anderen Konventionen als ein für persönliches Durchsuchen optimierter Vault. Dieser Abschnitt behandelt die Ordnerstruktur, das Notiz-Schema, frontmatter-Konventionen und die spezifischen Muster, die die Retrieval-Qualität verbessern.

Ordnerstruktur

Verwenden Sie nummerierte Präfixe für Ordner auf oberster Ebene, um eine vorhersehbare organisatorische Hierarchie zu schaffen. Die Nummern implizieren keine Priorität — sie gruppieren verwandte Bereiche und machen die Struktur übersichtlich.

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

Ordner, die indexiert werden sollten: Alles, was Markdown-Prosa enthält — Projekte, Bereiche, Ressourcen, Signale, tägliche Notizen.

Ordner, die von der Indexierung ausgeschlossen werden sollten: Templates (sie enthalten Platzhaltervariablen, keinen Inhalt), Anhänge (Binärdateien), Obsidian-Konfiguration und alle Ordner mit sensiblen Inhalten, die nicht im Retrieval-Index erscheinen sollen.

Die .indexignore-Datei

Erstellen Sie eine .indexignore-Datei im Vault-Stammverzeichnis, um Pfade explizit vom Retrieval-Index auszuschließen. Die Syntax entspricht .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/

Der Indexer liest diese Datei vor dem Scannen und überspringt übereinstimmende Pfade vollständig. Dateien in ausgeschlossenen Pfaden werden nie in Chunks aufgeteilt, nie eingebettet und erscheinen nie in Suchergebnissen.

Notiz-Schema

Jede Notiz sollte YAML-frontmatter haben. Der Retriever verwendet frontmatter-Felder zum Filtern und zur Kontextanreicherung:

---
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
---

Erforderliche Felder für Retrieval:

  • title — Wird in der Suchergebnis-Anzeige und als Überschriftenkontext für BM25 verwendet
  • type — Ermöglicht typgefilterte Abfragen („zeige nur MOCs” oder „nur Signale”)
  • tags — Im FTS5-Überschriftenkontext mit einer Gewichtung von 0,3 indexiert, was Keyword-Treffer liefert, auch wenn der Text andere Terminologie verwendet

Optionale, aber wertvolle Felder:

  • domain — Ermöglicht domänenbezogene Abfragen („nur in Sicherheits-Notizen suchen”)
  • source — Quellenangabe für erfasste Inhalte; der Retriever kann Quell-URLs in die Ergebnisse einbeziehen
  • status — Erlaubt das Ausschließen archivierter oder entwurfsbezogener Notizen aus der aktiven Suche

Chunking-Konventionen

Der Retriever teilt an H2-Überschriftengrenzen (##) in Chunks auf. Das bedeutet, dass Ihre Notizstruktur die Retrieval-Granularität direkt beeinflusst:

Gut für Retrieval:

## 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...

Drei H2-Abschnitte erzeugen drei unabhängig durchsuchbare Chunks. Jeder Chunk hat genügend Kontext, damit das Embedding seine Bedeutung erfassen kann. Eine Abfrage zu „Behandlung abgelaufener Token” trifft gezielt den dritten Chunk.

Schlecht für Retrieval:

# 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...

Ein langer Abschnitt ohne H2-Überschriften erzeugt einen einzigen großen Chunk. Das Embedding mittelt über alle Themen im Abschnitt. Eine Abfrage zu einem beliebigen Unterthema trifft die gesamte Notiz gleichermaßen.

Faustregel: Wenn ein Abschnitt mehr als ein Konzept behandelt, teilen Sie ihn in H2-Unterabschnitte auf. Der Chunker erledigt den Rest.

Was nicht in Notizen gehört

Inhalte, die die Retrieval-Qualität verschlechtern:

  • Roh kopierte vollständige Artikel ohne Anmerkungen. Der Retriever indexiert die Keywords des Originalartikels und verwässert Ihren Vault mit Inhalten, die Sie nicht geschrieben haben. Fügen Sie stattdessen eine Zusammenfassung hinzu, extrahieren Sie Kernaussagen oder verlinken Sie auf die Quell-URL.
  • Screenshots ohne Textbeschreibung. Der Retriever indexiert Markdown-Text. Ein Bild ohne Alt-Text oder umgebende Beschreibung ist sowohl für BM25 als auch für die Vektorsuche unsichtbar.
  • Zugangsdaten. API-Schlüssel, Token, Passwörter, Verbindungszeichenfolgen. Selbst mit Credential Filtering ist der sicherste Ansatz, niemals Geheimnisse in Notizen einzufügen. Verweisen Sie stattdessen namentlich darauf („das Cloudflare API-Token in ~/.env”).
  • Automatisch generierte Inhalte ohne Kuratierung. Wenn ein Tool eine Notiz generiert (Meeting-Transkript, Readwise-Highlights, RSS-Import), überprüfen und annotieren Sie diese, bevor sie in den permanenten Vault gelangt. Unkuratierte Auto-Importe erhöhen das Volumen, ohne den abrufbaren Wert zu steigern.

Plugin-Ökosystem für AI Workflows

Obsidian-Plugins, die die Vault-Qualität für AI-Retrieval verbessern, lassen sich in drei Kategorien einteilen: strukturelle (erzwingen Konsistenz), abfragende (machen Metadaten zugänglich) und synchronisierende (halten den Vault aktuell).

Essenzielle Plugins

Dataview. Ermöglicht Abfragen Ihres Vaults wie eine Datenbank mithilfe von frontmatter-Feldern. Erstellen Sie dynamische Indizes: „alle Notizen mit dem Tag security, die in den letzten 30 Tagen aktualisiert wurden” oder „alle Projektnotizen mit Status active.” Dataview unterstützt das Retrieval nicht direkt, hilft Ihnen aber dabei, Lücken in der Abdeckung Ihres Vaults zu identifizieren und Notizen zu finden, die aktualisiert werden müssen.

TABLE type, domain, updated
FROM "03-resources"
WHERE status = "active"
SORT updated DESC
LIMIT 20

Templater. Erstellt Notizen aus Vorlagen mit dynamischen Feldern. Stellen Sie sicher, dass jede neue Notiz mit korrektem frontmatter beginnt, indem Sie eine Vorlage verwenden, die die Felder created, type und domain vorausfüllt. Konsistentes frontmatter verbessert die Retrieval-Filterung.

<%* /* 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. Erzwingt Formatierungsregeln im gesamten Vault. Eine konsistente Überschriftenhierarchie (H1 für Titel, H2 für Abschnitte, H3 für Unterabschnitte) stellt sicher, dass der Chunker vorhersagbare Ergebnisse liefert. Linter-Regeln, die für das Retrieval relevant sind:

  • Überschriften-Inkrementierung: erzwingt aufeinanderfolgende Überschriftenebenen (kein Sprung von H1 zu H3)
  • YAML-Titel: Übereinstimmung mit dem Dateinamen
  • Nachgestellte Leerzeichen: entfernen (vermeidet FTS5-Tokenisierungsartefakte)
  • Aufeinanderfolgende Leerzeilen: auf 1 begrenzen (sauberere Chunks)

Git-Integration. Versionskontrolle für Ihren Vault. Verfolgen Sie Änderungen über die Zeit, synchronisieren Sie zwischen Geräten und stellen Sie versehentlich gelöschte Dateien wieder her. Git liefert außerdem mtime-Daten, die der Indexer für die inkrementelle Änderungserkennung verwendet.

Plugins, die die Indexierung unterstützen

Smart Connections. Ein Obsidian-Plugin, das AI-gestützte semantische Suche direkt in Obsidian bietet. Smart Connections v4 erstellt standardmäßig lokale Embeddings — sobald Ihr Vault indexiert ist, funktionieren semantische Verbindungen und Nachschlagen vollständig offline ohne API-Aufrufe.21 Während das Retrieval-System in diesem Leitfaden extern von Obsidian läuft (als Python-Pipeline), ist Smart Connections nützlich, um semantische Zusammenhänge beim Schreiben zu erkunden. Die beiden Systeme indexieren denselben Inhalt, dienen aber unterschiedlichen Anwendungsfällen: Smart Connections für die Entdeckung im Editor, der externe Retriever für die Integration von AI-Tools über MCP.

Metadata Menu. Bietet strukturierte frontmatter-Bearbeitung mit Autovervollständigung für Feldwerte. Reduziert Tippfehler in den Feldern type, domain und tags. Konsistente Metadaten verbessern die Genauigkeit der Retrieval-Filterung.

Plugins, die die Indexierung beeinträchtigen

Excalidraw. Speichert Zeichnungen als JSON, eingebettet in Markdown-Dateien. Das JSON ist syntaktisch gültiges Markdown, erzeugt aber beim Chunking und Embedding unbrauchbare Ergebnisse. Schließen Sie Excalidraw-Dateien über .indexignore oder durch Filterung nach Dateierweiterung vom Index aus.

Kanban. Speichert den Board-Zustand als speziell formatiertes Markdown. Das Format ist für die Kanban-Darstellung konzipiert, nicht für Prosa-Retrieval. Der Chunker erzeugt Fragmente von Kartentiteln und Metadaten, die sich schlecht einbetten lassen. Schließen Sie Kanban-Boards vom Index aus.

Calendar. Erstellt tägliche Notizen mit minimalem Inhalt (oft nur eine Datumsüberschrift). Leere oder nahezu leere Notizen erzeugen Chunks niedriger Qualität. Wenn Sie tägliche Notizen verwenden, schreiben Sie substanziellen Inhalt hinein oder schließen Sie den Ordner für tägliche Notizen vom Index aus.

Plugin-Konfiguration, die relevant ist

Dateiwiederherstellung → Aktiviert. Schützt vor versehentlichem Löschen von Notizen. Steht nicht in direktem Zusammenhang mit dem Retrieval, ist aber für eine Wissensbasis, auf die Sie sich verlassen, unverzichtbar.

Strikte Zeilenumbrüche → Deaktiviert. Markdown-standardmäßige Zeilenumbrüche (doppelter Zeilenumbruch für Absätze) erzeugen sauberere Chunks als Obsidians strikter Modus (einfacher Zeilenumbruch für <br>).

Standardspeicherort für neue Dateien → Festgelegter Ordner. Leiten Sie neue Dateien nach 00-inbox/ weiter, damit unkategorisierte Notizen die Domain-Ordner nicht verunreinigen. Die Inbox ist ein Staging-Bereich; Dateien werden nach der Sichtung in Domain-Ordner verschoben.

Wiki-link-Format → Kürzester Pfad wenn möglich. Kürzere Link-Ziele sind für den Retriever beim Indexieren der Link-Struktur einfacher aufzulösen.


Embedding-Modelle: Auswahl und Konfiguration

Das Embedding-Modell wandelt Textabschnitte in numerische Vektoren für die semantische Suche um. Die Modellwahl bestimmt die Abrufqualität, Indexgröße, Embedding-Geschwindigkeit und Laufzeitabhängigkeiten. Dieser Abschnitt erklärt, warum Model2Vec’s potion-base-8M die Standardwahl ist und wann Sie Alternativen wählen sollten.

Warum Model2Vec potion-base-8M

Modell: minishlab/potion-base-8M Parameter: 7,6 Millionen Dimensionen: 256 Größe: ~30 MB Abhängigkeiten: model2vec (nur numpy, kein PyTorch) Inferenz: Nur CPU, statische Wort-Embeddings (keine Attention-Schichten)

Model2Vec destilliert das Wissen eines Sentence Transformers in statische Token-Embeddings. Anstatt Attention-Schichten über die Eingabe laufen zu lassen (wie es BERT, MiniLM und andere Transformer-Modelle tun), erzeugt Model2Vec Vektoren durch gewichtete Mittelung vorberechneter Token-Embeddings.3 Die praktische Konsequenz: Die Embedding-Geschwindigkeit ist 50–500x schneller als bei Transformer-basierten Modellen, da keine sequentielle Berechnung stattfindet.

Auf der MTEB-Benchmark-Suite erreicht potion-base-8M 89 % der Leistung von all-MiniLM-L6-v2 (50,03 vs. 56,09 im Durchschnitt).4 Die Qualitätslücke von 11 % ist der Kompromiss für die Geschwindigkeits- und Einfachheitsvorteile. Bei kurzen Markdown-Abschnitten (durchschnittlich 200–400 Wörter in einem typischen Vault) ist der Qualitätsunterschied weniger ausgeprägt als bei längeren Dokumenten, da beide Modelle bei kurzem, fokussiertem Text zu ähnlichen Repräsentationen konvergieren.

Konfiguration

# 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. Das Modell wird erst bei der ersten Verwendung geladen, nicht beim Import. Der Import des Embedder-Moduls kostet nichts, wenn der Retriever im BM25-only-Fallback-Modus arbeitet (z. B. wenn das Embedding-venv nicht installiert ist).

Isolierte virtuelle Umgebung. Das Modell läuft in einem dedizierten venv (z. B. ~/.claude/venvs/memory/), um Abhängigkeitskonflikte mit dem Rest der Toolchain zu vermeiden. Die Funktion _activate_venv() fügt die site-packages des venv zur Laufzeit zu sys.path hinzu.

# Create isolated venv
python3 -m venv ~/.claude/venvs/memory
~/.claude/venvs/memory/bin/pip install model2vec

Stapelverarbeitung. Der Embedder verarbeitet Texte in Stapeln von 64, um den Overhead von Model2Vec zu amortisieren. Der Indexer übergibt Abschnitte an embed_batch(), anstatt jeweils einen Abschnitt einzeln zu embedden.

Wann Sie Alternativen wählen sollten

Modell Dim Größe Geschwindigkeit Qualität (MTEB) Geeignet für
potion-base-8M 256 30 MB 500x 50,03 Standard: lokal, schnell, kein GPU
potion-base-32M 256 120 MB 400x 52,46 Höhere Qualität, weiterhin statisch
potion-retrieval-32M 256 120 MB 400x 36,35 (Retrieval) Retrieval-optimiert, statisch
all-MiniLM-L6-v2 384 80 MB 1x 56,09 Höhere Qualität, weiterhin lokal
nomic-embed-text-v1.5 768 270 MB 0,5x 62,28 Beste lokale Qualität
text-embedding-3-small 1536 API N/A 62,30 API-basiert, höchste Qualität

Wählen Sie potion-base-32M, wenn Sie eine bessere Qualität als potion-base-8M wünschen, ohne die Familie der statischen Embeddings zu verlassen. Das im Januar 2025 veröffentlichte Modell verwendet ein größeres Vokabular, destilliert aus baai/bge-base-en-v1.5, und erreicht einen MTEB-Durchschnitt von 52,46 (5 % Verbesserung gegenüber potion-base-8M), bei gleicher 256-dimensionaler Ausgabe und reiner numpy-Abhängigkeit.18 Die 4x größere Modelldatei erhöht den Speicherverbrauch, aber die Embedding-Geschwindigkeit bleibt um Größenordnungen schneller als bei Transformer-Modellen.

Wählen Sie potion-retrieval-32M, wenn Ihr primärer Anwendungsfall Retrieval ist (was bei der Vault-Suche der Fall ist). Diese Variante ist aus potion-base-32M speziell für Retrieval-Aufgaben feinabgestimmt und erreicht 36,35 auf den MTEB-Retrieval-Benchmarks gegenüber 33,52 für das Basismodell.18 Der MTEB-Gesamtdurchschnitt sinkt auf 49,73, da das Fine-Tuning allgemeine Leistung gegen Retrieval-spezifische Verbesserungen eintauscht.

Wählen Sie all-MiniLM-L6-v2, wenn die Abrufqualität wichtiger ist als Geschwindigkeit und Sie PyTorch installiert haben. Die 384-dimensionalen Vektoren vergrößern die SQLite-Datenbank um ca. 50 % im Vergleich zu 256-dimensionalen Vektoren. Die Embedding-Geschwindigkeit sinkt von <1 Minute auf ~10 Minuten für einen vollständigen Reindex von 15.000 Dateien auf M-Series-Hardware.

Wählen Sie nomic-embed-text-v1.5, wenn Sie die bestmögliche lokale Abrufqualität benötigen und langsamere Indexierung akzeptieren. Die 768-dimensionalen Vektoren verdreifachen ungefähr die Datenbankgröße. Erfordert PyTorch und eine moderne CPU oder GPU.

Wählen Sie text-embedding-3-small, wenn Netzwerklatenz und Datenschutz akzeptable Kompromisse sind. Die API erzeugt die qualitativ hochwertigsten Embeddings, führt aber eine Cloud-Abhängigkeit ein, verursacht Kosten pro Token (0,02 $/Million Token) und sendet Ihre Inhalte an die Server von OpenAI.

Bleiben Sie bei potion-base-8M in allen anderen Fällen. Der Geschwindigkeitsvorteil ist entscheidend für iterative Indexierung (Reindex während der Entwicklung), die reine numpy-Abhängigkeit vermeidet die Komplexität der PyTorch-Installation, und die 256-dimensionalen Vektoren halten die Datenbank kompakt.

Quantisierung und Dimensionsreduktion

Model2Vec v0.5.0+ unterstützt das Laden von Modellen mit reduzierter Präzision und Dimensionen.18 Dies ist nützlich für den Einsatz auf eingeschränkter Hardware oder zur Reduzierung der Datenbankgröße, ohne das Modell wechseln zu müssen:

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)

Quantisierte Modelle behalten nahezu identische Abrufqualität bei einem Bruchteil des Speicherbedarfs. Die Dimensionsreduktion folgt einer Matryoshka-artigen Trunkierung — die ersten N Dimensionen tragen die meiste Information. Eine Reduktion von 256 auf 128 Dimensionen halbiert den Vektorspeicher bei minimalem Qualitätsverlust für die Kurztext-Suche.

Stand Mai 2025 unterstützt Model2Vec auch BPE- und Unigram-Tokenizer (zusätzlich zu WordPiece), was die Menge der Sentence Transformers erweitert, die in statische Modelle destilliert werden können.20

Fine-Tuning für Vault-spezifische Embeddings

Model2Vec v0.4.0+ unterstützt das Training benutzerdefinierter Klassifikationsmodelle auf Basis statischer Embeddings, und v0.7.0 fügt Vokabular-Quantisierung und konfigurierbares Pooling für die Destillation hinzu.20 Dies ist relevant für Vaults mit spezialisiertem Vokabular (medizinische Notizen, juristische Referenzen, domänenspezifischer Fachjargon), bei denen die Standard-potion-Modelle semantische Nuancen möglicherweise nicht erfassen:

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")

Für die meisten Vaults liefert das Standard-potion-base-8M eine ausreichende Abrufqualität. Fine-Tuning lohnt sich nur, wenn die Suche konsistent domänenspezifische Zusammenhänge verfehlt, die ein allgemeines Modell nicht erfassen kann.

Modell-Hash-Tracking

Der Indexer speichert einen Hash, der aus dem Modellnamen und der Vokabulargröße abgeleitet wird. Wenn Sie das Embedding-Modell wechseln, erkennt der Indexer die Diskrepanz beim nächsten inkrementellen Durchlauf und löst automatisch einen vollständigen Reindex aus.

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]

Dies verhindert das Mischen von Vektoren verschiedener Modelle in derselben Datenbank, was zu unsinnigen cosine similarity-Werten führen würde.

Fehlermodi

Fehler beim Modell-Download. Der erste Durchlauf lädt das Modell von Hugging Face herunter. Wenn der Download fehlschlägt (Netzwerkproblem, Unternehmens-Firewall), fällt der Retriever auf den BM25-only-Modus zurück. Das Modell wird nach dem ersten Download lokal zwischengespeichert.

Dimensionsinkongruenz. Wenn Sie das Modell wechseln, ohne die Datenbank zu leeren, haben die gespeicherten Vektoren eine andere Dimension als neue Embeddings. Der Indexer erkennt dies über den Modell-Hash und löst einen vollständigen Reindex aus. Wenn die Hash-Prüfung fehlschlägt (benutzerdefiniertes Modell ohne korrekten Hash), gibt sqlite-vec bei KNN-Abfragen mit nicht übereinstimmenden Dimensionen einen Fehler aus.

Speicherdruck bei großen Vaults. Das Embedding von 50.000+ Abschnitten in einem einzigen Stapel kann erheblichen Speicher beanspruchen. Der Indexer verarbeitet in Stapeln von 64, um den Spitzenspeicherverbrauch zu begrenzen. Wenn der Speicher weiterhin ein Problem darstellt, reduzieren Sie die Stapelgröße.


Volltextsuche mit FTS5

Die FTS5-Erweiterung von SQLite bietet Volltextsuche mit BM25-Ranking. FTS5 ist die Schlüsselwort-Suchkomponente der hybriden Retrieval-Pipeline. Dieser Abschnitt behandelt die FTS5-Konfiguration, wann BM25 besonders gut abschneidet und welche spezifischen Fehlermodi auftreten können.

Virtuelle FTS5-Tabelle

CREATE VIRTUAL TABLE chunks_fts USING fts5(
    chunk_text,
    section,
    heading_context,
    content=chunks,
    content_rowid=id
);

Content-Sync-Modus. Der Parameter content=chunks weist FTS5 an, direkt auf die chunks-Tabelle zu verweisen, anstatt eine Kopie des Textes zu speichern. Dies halbiert den Speicherbedarf, bedeutet aber, dass FTS5 manuell synchronisiert werden muss, wenn Chunks eingefügt, aktualisiert oder gelöscht werden.

Spalten. Drei Spalten werden indiziert: - chunk_text — Der Hauptinhalt jedes Chunks (BM25-Gewichtung: 1.0) - section — Der H2-Überschriftentext (BM25-Gewichtung: 0.5) - heading_context — Notiztitel, Tags und Metadaten (BM25-Gewichtung: 0.3)

BM25-Ranking

BM25 bewertet Dokumente anhand von Termfrequenz, inverser Dokumentfrequenz und Dokumentlängen-Normalisierung. Die Hilfsfunktion bm25() in FTS5 akzeptiert spaltenweise Gewichtungen:

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;

Die Spaltengewichtungen (1.0, 0.5, 0.3) bedeuten: - Ein Schlüsselwort-Treffer in chunk_text trägt am meisten zum Score bei - Ein Treffer in section (Überschrift) trägt halb so viel bei - Ein Treffer in heading_context (Titel, Tags) trägt 30 % bei

Diese Gewichtungen sind anpassbar. Wenn Ihr Vault aussagekräftige Überschriften hat, die die Inhaltsqualität zuverlässig vorhersagen, erhöhen Sie die section-Gewichtung. Wenn Ihre Tags umfassend und präzise sind, erhöhen Sie die heading_context-Gewichtung.

Wann BM25 überlegen ist

BM25 glänzt bei Abfragen, die exakte Bezeichner enthalten:

  • Funktionsnamen: _rrf_fuse, embed_batch, get_stale_files
  • CLI-Flags: --incremental, --vault, --model
  • Konfigurationsschlüssel: bm25_weight, max_tokens, batch_size
  • Fehlermeldungen: SQLITE_LOCKED, ConnectionRefusedError
  • Spezifische Fachbegriffe: PostToolUse, PreToolUse, AGENTS.md

Bei solchen Abfragen findet BM25 den exakten Treffer sofort. Die Vektorsuche würde semantisch verwandte Inhalte zurückliefern, könnte aber den exakten Treffer niedriger ranken als eine konzeptuelle Diskussion.

Wann BM25 versagt

BM25 versagt bei Abfragen, die andere Begriffe verwenden als die gespeicherten Inhalte:

  • Abfrage: „how to handle authentication failures” → Der Vault enthält Notizen über „login error recovery” und „session expiration handling.” BM25 findet keine Treffer, weil die Schlüsselwörter nicht übereinstimmen.
  • Abfrage: „what is the best way to manage state” → Der Vault enthält Notizen über „Redux store patterns” und „context providers.” BM25 findet nichts, weil „State Management” durch spezifische Technologienamen ausgedrückt wird.

BM25 versagt auch bei Schlüsselwort-Kollisionen in großem Maßstab. In einem Vault mit 15.000 Dateien liefert eine Suche nach „configuration” Hunderte von Notizen, weil nahezu jede Projektnotiz „Configuration” erwähnt. Die Ergebnisse sind technisch korrekt, aber praktisch nutzlos — das Ranking kann nicht bestimmen, welche „Configuration”-Notiz für die aktuelle Abfrage relevant ist.

FTS5-Tokenizer

FTS5 verwendet standardmäßig den unicode61-Tokenizer, der ASCII- und Unicode-Text verarbeitet. Für Vaults mit umfangreichem CJK-Inhalt (Chinesisch, Japanisch, Koreanisch) sollten Sie den trigram-Tokenizer in Betracht ziehen:

-- For CJK-heavy vaults
CREATE VIRTUAL TABLE chunks_fts USING fts5(
    chunk_text, section, heading_context,
    content=chunks, content_rowid=id,
    tokenize='trigram'
);

Der Standard-Tokenizer unicode61 trennt an Wortgrenzen, was bei Sprachen ohne Leerzeichen zwischen Wörtern schlecht funktioniert. Der trigram-Tokenizer teilt alle drei Zeichen auf und ermöglicht so Teilzeichenkettensuche — auf Kosten der Indexgröße (ca. 3-mal größer).

Wartung

FTS5 erfordert eine explizite Synchronisierung, wenn sich die zugrunde liegende chunks-Tabelle ändert:

# After inserting chunks
cursor.execute("""
    INSERT INTO chunks_fts(chunks_fts)
    VALUES('rebuild')
""")

Der rebuild-Befehl rekonstruiert den FTS5-Index aus der Inhaltstabelle. Führen Sie ihn nach Massenimports (vollständige Neuindizierung) aus, aber nicht nach einzelnen inkrementellen Aktualisierungen — verwenden Sie dafür INSERT INTO chunks_fts(rowid, chunk_text, section, heading_context), um einzelne Zeilen zu synchronisieren.


Vektorsuche mit sqlite-vec

Die sqlite-vec-Erweiterung bringt vektorbasierte KNN-Suche (K-Nearest Neighbors) in SQLite. Dieser Abschnitt behandelt die sqlite-vec-Konfiguration, die Embedding-Pipeline von der Notiz zum durchsuchbaren Vektor und die spezifischen Abfragemuster.

Virtuelle sqlite-vec-Tabelle

CREATE VIRTUAL TABLE chunk_vecs USING vec0(
    id INTEGER PRIMARY KEY,
    embedding float[256]
);

Das vec0-Modul speichert 256-dimensionale Float-Vektoren als gepackte Binärdaten. Die id-Spalte ist 1:1 mit der chunks-Tabelle verknüpft und ermöglicht Joins zwischen Vektorergebnissen und Chunk-Metadaten.

Embedding-Pipeline

Die Pipeline verläuft von der Notiz zum durchsuchbaren Vektor:

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

Vektor-Serialisierung

Das struct-Modul von Python serialisiert Float-Vektoren für die sqlite-vec-Speicherung:

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-Abfrage

Eine Vektorsuchabfrage erzeugt ein Embedding der Eingabeabfrage und findet dann die K nächsten Chunks nach Kosinus-Distanz:

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

Der MATCH-Operator in sqlite-vec führt eine approximierte Nächste-Nachbarn-Suche durch. Der k-Parameter steuert, wie viele Ergebnisse zurückgegeben werden. Die distance-Spalte enthält die Kosinus-Distanz (0 = identisch, 2 = entgegengesetzt).

Wann die Vektorsuche überlegen ist

Die Vektorsuche glänzt bei Abfragen, bei denen das Konzept wichtiger ist als die spezifischen Wörter:

  • Abfrage: „how to handle authentication failures” → Findet Notizen über „login error recovery” (gleicher semantischer Raum, unterschiedliche Schlüsselwörter)
  • Abfrage: „what patterns exist for caching” → Findet Notizen über „memoization,” „Redis TTL strategies” und „HTTP cache headers” (verwandte Konzepte, diverse Terminologie)
  • Abfrage: „approaches to testing asynchronous code” → Findet Notizen über „pytest-asyncio fixtures,” „mock event loops” und „async test patterns” (gleiches Konzept, ausgedrückt durch Implementierungsdetails)

Wann die Vektorsuche versagt

Die Vektorsuche hat Schwierigkeiten mit exakten Bezeichnern:

  • Abfrage: _rrf_fuse → Liefert Notizen über „fusion algorithms” und „rank merging”, rankt aber die tatsächliche Funktionsdefinition möglicherweise niedriger als konzeptuelle Diskussionen
  • Abfrage: PostToolUse → Liefert Notizen über „tool lifecycle hooks” und „post-execution handlers” anstelle des spezifischen Hook-Namens

Die Vektorsuche hat auch Schwierigkeiten mit strukturierten Daten. JSON-Konfigurationsdateien, YAML-Blöcke und Code-Snippets erzeugen Embeddings, die strukturelle Muster erfassen, anstatt semantische Bedeutung. Eine JSON-Datei mit "review": true wird anders eingebettet als eine Prosadiskussion über Code-Review.

Graceful Degradation

Falls sqlite-vec nicht geladen werden kann (fehlende Erweiterung, inkompatible Plattform, beschädigte Bibliothek), fällt der Retriever auf reine BM25-Suche zurück:

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

Der Retriever prüft vec_available, bevor er Vektorabfragen versucht. Wenn deaktiviert, verwenden alle Suchen ausschließlich BM25, und der RRF-Fusionsschritt wird übersprungen.


Reciprocal Rank Fusion (RRF)

RRF führt zwei Ranglisten zusammen, ohne dass eine Kalibrierung der Bewertungen erforderlich ist. Dieser Abschnitt behandelt den Algorithmus, eine nachvollzogene Beispielabfrage, die Abstimmung des k-Parameters und warum RRF gegenüber Alternativen bevorzugt wird. Einen interaktiven Rechner mit bearbeitbaren Rängen, Szenario-Voreinstellungen und einem visuellen Architektur-Explorer finden Sie im Hybrid-Retriever-Deep-Dive.

Der Algorithmus

RRF weist jedem Dokument eine Bewertung zu, die ausschließlich auf seiner Rangposition in jeder Liste basiert:

score(d) = Σ (weight_i / (k + rank_i))

Dabei gilt: - k ist eine Glättungskonstante (60, nach Cormack et al.1) - rank_i ist der 1-basierte Rang des Dokuments in Ergebnisliste i - weight_i ist ein optionaler Multiplikator pro Liste (Standard 1.0)

Dokumente, die in mehreren Listen gut platziert sind, erhalten höhere fusionierte Bewertungen. Dokumente, die nur in einer Liste erscheinen, erhalten eine Bewertung aus dieser einzelnen Quelle.

Warum RRF gegenüber Alternativen

Gewichtete lineare Kombination erfordert die Kalibrierung von BM25-Bewertungen gegen Kosinus-Distanzen. BM25-Bewertungen sind unbegrenzt und skalieren mit der Korpusgröße. Kosinus-Distanzen sind begrenzt auf [0, 2]. Die Kombination erfordert eine Normalisierung, und die Normalisierungsparameter sind datensatzabhängig. RRF verwendet ausschließlich Rangpositionen, die unabhängig von der Bewertungsmethode stets Ganzzahlen ab 1 sind.

Gelernte Fusionsmodelle erfordern gelabelte Trainingsdaten — Abfrage-Dokument-Relevanzpaare. Für eine persönliche Wissensdatenbank existieren solche Trainingsdaten nicht. Sie müssten Hunderte von Abfrage-Dokument-Paaren manuell bewerten, um ein brauchbares Modell zu trainieren. RRF funktioniert ohne jegliche Trainingsdaten.

Condorcet-Abstimmungsmethoden (Borda-Zählung, Schulze-Methode) sind theoretisch elegant, aber deutlich komplexer in Implementierung und Abstimmung. Das ursprüngliche RRF-Paper zeigte, dass RRF Condorcet-Methoden bei TREC-Evaluierungsdaten übertrifft.1

Fusion in der Praxis

Abfrage: „how does the review aggregator handle disagreements”

BM25 platziert review-aggregator.py auf Position 3 (exakte Schlüsselwortübereinstimmungen bei „review”, „aggregator”, „disagreements”), setzt jedoch zwei Konfigurationsdateien höher (sie stimmen stärker mit „review” überein). Die Vektorsuche platziert denselben Chunk auf Position 1 (semantische Übereinstimmung bei Konfliktlösung). Nach der 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

Chunks, die in beiden Listen gut platziert sind, steigen an die Spitze. Chunks, die nur in einer Liste erscheinen, erhalten eine Einzelquellen-Bewertung und fallen hinter doppelt platzierte Ergebnisse zurück. Die eigentliche Logik zur Konfliktlösung gewinnt, weil beide Methoden sie gefunden haben — BM25 über Schlüsselwörter, die Vektorsuche über Semantik.

Für die vollständige schrittweise Nachverfolgung mit RRF-Mathematik pro Rang können Sie verschiedene k-Werte im interaktiven RRF-Rechner ausprobieren.

Implementierung

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

Abstimmung von k

Die k-Konstante steuert, wie viel Gewicht den höchstplatzierten Ergebnissen im Vergleich zu niedriger platzierten Ergebnissen gegeben wird:

  • Niedriges k (z. B. 10): Höchstplatzierte Ergebnisse dominieren. Rang 1 erhält 1/11 = 0,091, Rang 10 erhält 1/20 = 0,050 (1,8-facher Unterschied). Geeignet, wenn Sie darauf vertrauen, dass die einzelnen Ranker das Spitzenergebnis richtig einordnen.
  • Standard k (60): Ausgewogen. Rang 1 erhält 1/61 = 0,0164, Rang 10 erhält 1/70 = 0,0143 (1,15-facher Unterschied). Rangunterschiede werden komprimiert, wodurch dem Erscheinen in mehreren Listen mehr Gewicht verliehen wird.
  • Hohes k (z. B. 200): Das Erscheinen in beiden Listen ist deutlich wichtiger als die Rangposition. Rang 1 erhält 1/201, Rang 10 erhält 1/210 — nahezu identisch. Verwenden Sie dies, wenn die einzelnen Ranker verrauschte Rankings erzeugen, aber die listenübergreifende Übereinstimmung zuverlässig ist.

Beginnen Sie mit k=60. Das ursprüngliche RRF-Paper stellte fest, dass dieser Wert über diverse TREC-Datensätze hinweg robust ist. Optimieren Sie erst, nachdem Sie Fehlerfälle bei Ihrer eigenen Abfrageverteilung gemessen haben.

Gleichstandsauflösung

Wenn zwei Chunks identische RRF-Bewertungen haben (selten, aber möglich bei gleichem Rang in einer Liste und keinem Erscheinen in der anderen), lösen Sie den Gleichstand wie folgt auf:

  1. Bevorzugen Sie Chunks, die in beiden Listen erscheinen, gegenüber Chunks, die nur in einer Liste erscheinen
  2. Bei Chunks in beiden Listen bevorzugen Sie denjenigen mit dem niedrigeren kombinierten Rang
  3. Bei Chunks in nur einer Liste bevorzugen Sie denjenigen mit dem niedrigeren Rang in dieser Liste

Die vollständige Retrieval-Pipeline

Dieser Abschnitt verfolgt eine Abfrage vom Eingang bis zum Ausgang durch die gesamte Pipeline: BM25-Suche, Vektorsuche, RRF-Fusion, Token-Budget-Kürzung und Kontextaufbau.

Durchgängiger Ablauf

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

Gesamtlatenz: ~23ms für eine Datenbank mit 49.746 Chunks auf Apple M3 Pro Hardware.

Die Such-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-Kürzung

Der Parameter max_tokens verhindert, dass der Retriever mehr Kontext zurückgibt, als das KI-Tool verarbeiten kann. Die Schätzung verwendet 4 Zeichen pro Token (eine vernünftige Annäherung für englische Prosa). Die Ergebnisse werden gierig gekürzt: Ergebnisse werden in der Rangfolge hinzugefügt, bis das Budget erschöpft ist.

Dies ist eine konservative Strategie. Ein ausgefeilterer Ansatz würde die Qualitätsbewertung einzelner Ergebnisse berücksichtigen und kürzere, qualitativ hochwertigere Ergebnisse gegenüber längeren, qualitativ niedrigeren bevorzugen. Der gierige Ansatz ist einfacher und funktioniert in der Praxis gut, da die RRF-Rangfolge die Ergebnisse bereits nach Relevanz ordnet.

Datenbankschema (vollständig)

-- 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
);

Pfad zur schrittweisen 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

Der Retriever prüft die verfügbaren Fähigkeiten bei der Initialisierung und passt seine Abfragestrategie entsprechend an. Eine fehlende Komponente verschlechtert die Qualität, verursacht aber keine Fehler. Der einzige harte Fehler ist eine fehlende Datenbankdatei.

Produktionsstatistiken

Gemessen an einem Vault mit 16.894 Dateien, 49.746 Chunks, 83 MB SQLite-Datenbank, Apple M3 Pro:

Metrik Wert
Dateien gesamt 16.894
Chunks gesamt 49.746
Datenbankgröße 83 MB
BM25-Abfragelatenz (p50) 12ms
Vektor-Abfragelatenz (p50) 8ms
RRF-Fusionslatenz 3ms
Durchgängige Suchlatenz (p50) 23ms
Vollständige Neuindexierung ~4 Minuten
Inkrementelle Neuindexierung <10 Sekunden
Embedding-Modell potion-base-8M (256-dim)
BM25-Kandidatenpool 30
Vektor-Kandidatenpool 30
Standard-Ergebnislimit 10
Standard-Token-Budget 4.000 Tokens

Content-Hashing und Änderungserkennung

Der Indexer muss wissen, welche Dateien sich seit dem letzten Indexierungslauf geändert haben. Dieser Abschnitt behandelt den Mechanismus zur Änderungserkennung und die Hashing-Strategie.

Vergleich der Datei-Änderungszeit

Der Indexer speichert mtime_ns (Datei-Änderungszeit in Nanosekunden) für jeden Chunk in der chunks-Tabelle. Bei einem inkrementellen Lauf führt der Indexer folgende Schritte aus:

  1. Durchsucht den Vault nach allen .md-Dateien in erlaubten Ordnern
  2. Liest die mtime_ns jeder Datei aus dem Dateisystem
  3. Vergleicht mit der gespeicherten mtime_ns in der Datenbank
  4. Identifiziert drei Kategorien:
  5. Neue Dateien: Pfad existiert im Dateisystem, aber nicht in der Datenbank
  6. Geänderte Dateien: Pfad existiert in beiden, aber mtime_ns unterscheidet sich
  7. Gelöschte Dateien: Pfad existiert in der Datenbank, aber nicht im Dateisystem
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)

Warum mtime und nicht Content-Hash

Content-Hashing (SHA-256 des Dateiinhalts) wäre zuverlässiger als der mtime-Vergleich — es würde Fälle erkennen, in denen eine Datei berührt wurde, ohne sich zu ändern (z. B. wenn git checkout die ursprüngliche mtime wiederherstellt). Allerdings erfordert Hashing das Lesen jeder Datei bei jedem inkrementellen Lauf. Bei 16.894 Dateien dauert das Lesen der Dateiinhalte 2-3 Sekunden. Das Lesen der mtimes aus dem Dateisystem dauert <100ms.

Der Kompromiss: Der mtime-Vergleich löst gelegentlich eine unnötige Neuindexierung unveränderter Dateien aus (falsch-positive Ergebnisse), übersieht aber niemals tatsächliche Änderungen. Falsch-positive Ergebnisse kosten einige zusätzliche Embedding-Aufrufe pro Lauf. Der Geschwindigkeitsunterschied (100ms gegenüber 3 Sekunden) macht mtime zur pragmatischen Wahl für ein System, das bei jeder KI-Interaktion ausgeführt wird.

Umgang mit Löschungen

Wenn eine Datei aus dem Vault gelöscht wird, entfernt der Indexer alle zugehörigen Chunks aus der Datenbank:

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],
    )

FTS5-Content-Sync-Tabellen erfordern eine explizite Löschung über INSERT INTO chunks_fts(chunks_fts, rowid, ...) VALUES('delete', ?, ...) für jede entfernte Zeile. Der Indexer behandelt dies als Teil des Dateientfernungsprozesses.


Inkrementelle vs. vollständige Neuindizierung

Der Indexer unterstützt zwei Modi: inkrementell (schnell, für den täglichen Gebrauch) und vollständig (langsam, gelegentlich). Dieser Abschnitt behandelt, wann Sie welchen Modus verwenden sollten, die Idempotenz-Garantien und die Wiederherstellung bei Datenkorruption.

Inkrementelle Neuindizierung

Wann verwenden: Tägliche Indizierung nach dem Bearbeiten von Notizen. Der Standardmodus.

Was passiert: 1. Vault nach Dateiänderungen durchsuchen (mtime-Vergleich) 2. Chunks gelöschter Dateien entfernen 3. Geänderte Dateien neu aufteilen und neu einbetten 4. Neue Chunks für neue Dateien einfügen 5. FTS5-Index synchronisieren

Typische Dauer: <10 Sekunden für die Bearbeitungen eines Tages bei einem Vault mit 16.000 Dateien.

python index_vault.py --incremental

Vollständige Neuindizierung

Wann verwenden: - Nach dem Wechsel des Embedding-Modells (Model-Hash-Abweichung erkannt) - Nach einer Schema-Migration (neue Spalten, geänderte Indizes) - Nach einer Datenbankkorruption (Integritätsprüfung fehlgeschlagen) - Wenn die inkrementelle Indizierung unerwartete Ergebnisse liefert

Was passiert: 1. Alle vorhandenen Daten löschen (Chunks, Vektoren, FTS5-Einträge) 2. Gesamten Vault durchsuchen 3. Alle Dateien in Chunks aufteilen 4. Alle Chunks einbetten (Embeddings erzeugen) 5. FTS5-Index von Grund auf neu erstellen

Typische Dauer: ~4 Minuten für 16.894 Dateien auf Apple M3 Pro.

python index_vault.py --full

Idempotenz

Beide Modi sind idempotent: Die zweimalige Ausführung desselben Befehls erzeugt dasselbe Ergebnis. Der Indexer löscht vorhandene Chunks einer Datei, bevor neue eingefügt werden. Eine erneute inkrementelle Indizierung einer bereits aktuellen Datenbank erzeugt daher null Änderungen. Eine erneute vollständige Indizierung erzeugt eine identische Datenbank.

Wiederherstellung bei Korruption

Wenn die SQLite-Datenbank beschädigt wird (Stromausfall während eines Schreibvorgangs, Festplattenfehler, Prozessabbruch während einer Transaktion):

# Check integrity
sqlite3 vectors.db "PRAGMA integrity_check;"

# If corruption detected, full reindex rebuilds from source files
python index_vault.py --full

Die Quelle der Wahrheit sind immer die Vault-Dateien, nicht die Datenbank. Die Datenbank ist ein abgeleitetes Artefakt, das jederzeit neu erstellt werden kann. Dies ist eine entscheidende Designeigenschaft: Sie müssen die Datenbank niemals sichern.

Das --incremental-Flag

Wenn der Indexer mit --incremental ausgeführt wird:

  1. Model-Hash-Prüfung. Gespeicherten Model-Hash mit dem aktuellen Modell vergleichen. Bei Abweichung automatisch in den vollständigen Neuindizierungsmodus wechseln und den Benutzer warnen.
  2. Datei-Scan. Erlaubte Ordner durchlaufen, Dateipfade und mtimes erfassen.
  3. Änderungserkennung. Mit gespeicherten Daten vergleichen.
  4. Batch-Verarbeitung. Geänderte Dateien in Stapeln von 64 neu aufteilen und neu einbetten.
  5. Fortschrittsanzeige. Anzahl der verarbeiteten Dateien und verstrichene Zeit ausgeben.
  6. Kontrolliertes Herunterfahren. SIGINT abfangen und die aktuelle Datei vor dem Stoppen zu Ende verarbeiten.

Credential-Filterung und Datengrenzen

Persönliche Notizen enthalten Geheimnisse: API-Schlüssel, Bearer-Token, Datenbank-Verbindungsstrings, private Schlüssel, die während Debugging-Sitzungen eingefügt wurden. Der Credential-Filter verhindert, dass diese in den Retrieval-Index gelangen.

Das Problem

Eine Notiz über das Debugging einer OAuth-Integration könnte Folgendes enthalten:

The token was: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
I used this curl command:
  curl -H "Authorization: Bearer sk-ant-api03-abc123..."

Ohne Filterung würden sowohl das JWT als auch der API-Schlüssel in Chunks aufgeteilt, eingebettet und in der Datenbank gespeichert. Eine Suche nach „authentication” würde den Chunk mit echten Geheimnissen zurückgeben. Schlimmer noch: Wenn der Retriever Ergebnisse über MCP an ein KI-Tool weitergibt, erscheinen die Geheimnisse im Kontextfenster der KI und möglicherweise in den Protokollen des Tools.

Musterbasierte Filterung

Der Credential-Filter wird vor der Speicherung auf jeden Chunk angewendet und gleicht 25 herstellerspezifische Muster sowie generische Muster ab:

Herstellerspezifische Muster:

Muster Beispiel Regex
OpenAI API-Schlüssel sk-... sk-[a-zA-Z0-9_-]{20,}
Anthropic API-Schlüssel 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-Schlüssel sk_live_... [sr]k_(live\|test)_[a-zA-Z0-9]{24,}
Cloudflare-Token ... Verschiedene Muster

Generische Muster:

Muster Erkennung
JWT-Token eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+
Bearer-Token Bearer\s+[a-zA-Z0-9_\-\.]+
Private Schlüssel -----BEGIN (RSA\|EC\|OPENSSH) PRIVATE KEY-----
Base64 mit hoher Entropie Zeichenketten mit >4,5 Bit/Zeichen Entropie, 40+ Zeichen
Passwortzuweisungen password\s*[:=]\s*["'][^"']+["']

Filter-Implementierung

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

Zentrale Designentscheidungen:

  1. Filtern vor dem Einbetten. Der bereinigte Text wird eingebettet. Die Vektordarstellung kodiert niemals Credential-Muster. Eine Suche nach „API-Schlüssel” gibt Notizen zurück, die API-Schlüsselverwaltung besprechen, nicht Notizen, die tatsächliche Schlüssel enthalten.

  2. Ersetzen, nicht entfernen. Das [REDACTED:pattern-name]-Token bewahrt den semantischen Kontext des umgebenden Textes. Das Embedding erfasst, dass „hier etwas Credential-artiges stand”, ohne das Credential selbst zu kodieren.

  3. Muster protokollieren, nicht Werte. Der Filter protokolliert, welche Muster erkannt wurden (z. B. „Scrubbed 2 credential(s) from oauth-debug.md [jwt, bearer-token]”), aber niemals den Credential-Wert selbst.

Pfadbasierter Ausschluss

Die .indexignore-Datei bietet einen grobkörnigen Ausschluss nach Pfad. Der Credential-Filter bietet feinkörnige Bereinigung innerhalb indizierter Dateien. Beide sind notwendig:

  • .indexignore für ganze Ordner, die bekanntermaßen sensible Inhalte enthalten (Gesundheitsnotizen, Finanzunterlagen, Karrieredokumente)
  • Credential-Filter für Geheimnisse, die versehentlich in ansonsten indizierbaren Inhalten eingebettet sind

Datenklassifizierung

Für Vaults mit vielfältigen Inhalten empfiehlt es sich, Notizen nach Sensibilität zu klassifizieren:

Stufe Beispiele Indizieren? Filtern?
Öffentlich Blog-Entwürfe, technische Notizen Ja Ja
Intern Projektpläne, Architekturentscheidungen Ja Ja
Sensibel Gehaltsdaten, Gesundheitsdaten Nein (.indexignore) Nicht zutreffend
Eingeschränkt Credentials, private Schlüssel Nein (.indexignore) Nicht zutreffend

MCP-Server-Architektur

Model Context Protocol (MCP)-Server stellen den Retriever als Werkzeug bereit, das KI-Agenten aufrufen können. Dieser Abschnitt behandelt das Server-Design, den Funktionsumfang und die Berechtigungsgrenzen.

Protokollwahl: STDIO vs. HTTP

MCP unterstützt zwei Transportmodi:

STDIO — Das KI-Tool startet den MCP-Server als Kindprozess und kommuniziert über stdin/stdout. Dies ist der Standardmodus für lokale Tools. Claude Code, Codex CLI und Cursor unterstützen alle STDIO-MCP-Server.

{
  "mcpServers": {
    "obsidian": {
      "command": "python",
      "args": ["/path/to/obsidian_mcp.py"],
      "env": {
        "VAULT_PATH": "/path/to/vault",
        "DB_PATH": "/path/to/vectors.db"
      }
    }
  }
}

HTTP — Der MCP-Server läuft als eigenständiger HTTP-Dienst. Nützlich für Fernzugriff, Multi-Client-Konfigurationen oder Team-Setups, bei denen der Vault auf einem gemeinsamen Server liegt.

{
  "mcpServers": {
    "obsidian": {
      "url": "http://localhost:3333/mcp"
    }
  }
}

Empfehlung: Verwenden Sie STDIO für persönliche Vaults. Es ist einfacher, sicherer (keine Netzwerkexposition) und der Server-Lebenszyklus wird vom KI-Tool verwaltet. Verwenden Sie HTTP nur, wenn mehrere Tools oder mehrere Rechner gleichzeitigen Zugriff auf denselben Vault benötigen.

Entwicklung der MCP-Spezifikation. Die MCP-Spezifikation vom Juni 2025 führte OAuth 2.1-Autorisierung, strukturierte Tool-Ausgaben (typisierte Rückgabe-Schemas) und Elicitation (vom Server initiierte Benutzerabfragen) ein. Das Release vom November 2025 lieferte Streamable HTTP als erstklassigen Transportmodus, .well-known-URL-Erkennung für automatisches Durchsuchen von Server-Fähigkeiten, strukturierte Tool-Annotationen, die deklarieren, ob ein Tool nur lesend oder verändernd arbeitet, sowie ein SDK-Stufen-Standardisierungssystem.1619 Das nächste Spezifikations-Release (voraussichtlich Mitte 2026) schlägt asynchrone Operationen für lang laufende Aufgaben, domänenspezifische Protokollerweiterungen für Branchen wie Gesundheitswesen und Finanzen sowie Agent-zu-Agent-Kommunikationsstandards für Multi-Agent-Workflows vor.19 Für persönliche Vault-Server bleibt STDIO der einfachste Weg. Der Streamable-HTTP-Transport und die .well-known-Erkennung kommen hauptsächlich Enterprise-HTTP-Deployments mit Multi-Tenant-Routing und Load Balancing zugute. Beobachten Sie die MCP-Roadmap für Aktualisierungen, die Ihre Transportwahl beeinflussen.

Fähigkeiten-Design

Der MCP-Server sollte einen minimalen Satz von Tools bereitstellen:

search — Das primäre Tool. Führt Hybrid Retrieval durch und gibt sortierte Ergebnisse zurück.

{
  "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 — Liest den vollständigen Inhalt einer bestimmten Notiz anhand des Dateipfads. Nützlich, wenn der Agent den kompletten Kontext eines Suchergebnisses einsehen möchte.

{
  "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 — Listet Notizen auf, die einem Filter entsprechen (nach Ordner, Tag, Typ oder Zeitraum). Nützlich zur Exploration, wenn der Agent keine spezifische Suchanfrage hat.

{
  "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 — Ein Komfort-Tool, das eine Suche durchführt und die Ergebnisse als Kontextblock formatiert, der sich zur Einspeisung in eine Konversation eignet.

{
  "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 }
  }
}

Berechtigungsgrenzen

Der MCP-Server sollte strikte Grenzen durchsetzen:

  1. Nur lesend. Der Server liest den Vault und die Index-Datenbank. Er erstellt, ändert oder löscht keine Notizen. Schreiboperationen (Erfassen neuer Notizen) werden von separaten Hooks oder Skills verarbeitet, nicht vom MCP-Server.

  2. Auf den Vault beschränkt. Der Server liest nur Dateien innerhalb des konfigurierten Vault-Pfads. Path-Traversal-Versuche (../../etc/passwd) müssen abgewiesen werden.

  3. Credential-gefilterte Ausgabe. Selbst wenn die Datenbank bereits vorgefilterte Inhalte enthält, wenden Sie Credential-Filterung auf die Ausgabe als Defense-in-Depth-Maßnahme an.

  4. Token-limitierte Antworten. Erzwingen Sie max_tokens bei allen Tool-Antworten, um zu verhindern, dass das KI-Tool übermäßig große Kontextblöcke erhält.

Fehlerbehandlung

MCP-Tools sollten strukturierte Fehlermeldungen zurückgeben, die dem KI-Tool bei der Wiederherstellung helfen:

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-Integration

Claude Code ist der primäre Nutzer des Obsidian-Retrieval-Systems. Dieser Abschnitt behandelt die MCP-Konfiguration, Hook-Integration und das obsidian_bridge.py-Muster.

MCP-Konfiguration

Fügen Sie den Obsidian-MCP-Server zu ~/.claude/settings.json hinzu:

{
  "mcpServers": {
    "obsidian": {
      "command": "python",
      "args": ["/path/to/obsidian_mcp.py"],
      "env": {
        "VAULT_PATH": "/absolute/path/to/vault",
        "DB_PATH": "/absolute/path/to/vectors.db"
      }
    }
  }
}

Starten Sie Claude Code nach dem Hinzufügen der Konfiguration neu. Der MCP-Server wird als Kindprozess gestartet. Überprüfen Sie, ob er läuft:

> What tools do you have from the obsidian MCP server?

Claude Code sollte die verfügbaren Tools auflisten (obsidian_search, obsidian_read_note usw.).

Hook-Integration

Hooks erweitern das Verhalten von Claude Code an definierten Lebenszyklus-Punkten. Zwei Hooks sind für die Obsidian-Integration relevant:

PreToolUse-Hook — Fragt den Vault ab, bevor der Agent einen Tool-Aufruf verarbeitet. Speist relevanten Kontext automatisch ein.

#!/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 — Erfasst bedeutsame Tool-Ausgaben und schreibt sie zurück in den Vault für zukünftiges Retrieval.

#!/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

Das obsidian_bridge.py-Muster

Ein Bridge-Modul stellt eine Python-API bereit, die Hooks und Skills aufrufen können:

# 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)

Der /capture-Skill

Ein Claude Code-Skill zum Erfassen von Erkenntnissen zurück in den Vault:

/capture "OAuth token rotation requires both access and refresh token invalidation"
  --domain security
  --tags oauth,tokens

Der Skill erstellt eine neue Notiz in 00-inbox/ mit korrektem Frontmatter und löst eine inkrementelle Neuindizierung aus, sodass die neue Notiz sofort durchsuchbar ist.

Kontextfenster-Verwaltung

Die Integration sollte das Kontextfenster von Claude Code berücksichtigen:

  • Begrenzen Sie eingespeisten Kontext auf 1.500–2.000 Token pro Abfrage. Mehr konkurriert mit dem Arbeitsgedächtnis des Agenten.
  • Quellenangaben einschließen. Geben Sie immer den Dateipfad und die Abschnittsüberschrift an, damit der Agent die Quelle referenzieren kann.
  • Chunk-Text kürzen. Lange Chunks sollten mit ... gekürzt statt vollständig weggelassen werden. Die ersten 300–500 Zeichen enthalten üblicherweise die wesentlichen Informationen.
  • Nicht bei jedem Tool-Aufruf einspeisen. Der PreToolUse-Hook sollte Kontext selektiv basierend auf dem aufgerufenen Tool einspeisen. Leseoperationen benötigen keinen Vault-Kontext. Schreib- und Bearbeitungsoperationen profitieren davon.

Codex CLI-Integration

Codex CLI verbindet sich über config.toml mit MCP-Servern. Das Integrationsmuster unterscheidet sich von Claude Code in der Konfigurationssyntax und der Art der Anweisungsübermittlung.

MCP-Konfiguration

Fügen Sie Folgendes zu .codex/config.toml oder ~/.codex/config.toml hinzu:

[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-Muster

Codex CLI liest AGENTS.md für projektbezogene Anweisungen. Fügen Sie Hinweise zur Vault-Suche hinzu:

## 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"

Unterschiede zu Claude Code

Funktion Claude Code Codex CLI
MCP-Konfiguration settings.json config.toml
Hooks ~/.claude/hooks/ Nicht unterstützt
Skills ~/.claude/skills/ Nicht unterstützt
Anweisungsdatei CLAUDE.md AGENTS.md
Genehmigungsmodi --dangerously-skip-permissions suggest / auto-edit / full-auto

Wichtiger Unterschied: Codex CLI unterstützt keine Hooks. Das Muster zur automatischen Kontextinjektion (PreToolUse-Hook) ist nicht verfügbar. Fügen Sie stattdessen explizite Anweisungen in AGENTS.md ein, die den Agenten auffordern, vor Arbeitsbeginn den Vault zu durchsuchen.


Cursor und andere Tools

Cursor und andere KI-Tools, die MCP unterstützen, können sich mit demselben Obsidian-MCP-Server verbinden. Dieser Abschnitt behandelt die Konfiguration für gängige Tools.

Cursor

Fügen Sie Folgendes zu .cursor/mcp.json in Ihrem Projektstammverzeichnis hinzu:

{
  "mcpServers": {
    "obsidian": {
      "command": "python",
      "args": ["/path/to/obsidian_mcp.py"],
      "env": {
        "VAULT_PATH": "/absolute/path/to/vault",
        "DB_PATH": "/absolute/path/to/vectors.db"
      }
    }
  }
}

Die .cursorrules-Datei von Cursor kann Anweisungen zur Nutzung des Vaults enthalten:

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.

Kompatibilitätsmatrix

Tool MCP-Unterstützung Transport Konfigurationsort
Claude Code Vollständig STDIO ~/.claude/settings.json
Codex CLI Vollständig STDIO .codex/config.toml
Cursor Vollständig STDIO .cursor/mcp.json
Windsurf Vollständig STDIO .windsurf/mcp.json
Continue.dev Teilweise HTTP ~/.continue/config.json
Zed In Entwicklung STDIO Einstellungs-UI

Fallback für Tools ohne MCP

Für Tools, die MCP nicht unterstützen, kann der Retriever als CLI eingebunden werden:

# 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

Das CLI gibt strukturierten Text aus, der manuell in die Eingabe eines beliebigen KI-Tools eingefügt werden kann. Dies ist weniger elegant als eine MCP-Integration, funktioniert aber universell.


Prompt-Caching aus strukturierten Notizen

Strukturierte Notizen im Vault können als wiederverwendbare Kontextblöcke dienen, die den Token-Verbrauch über KI-Interaktionen hinweg reduzieren. Dieser Abschnitt behandelt das Design von Cache-Schlüsseln und die Verwaltung des Token-Budgets.

Das Muster

Anstatt bei jeder Interaktion nach Kontext zu suchen, können Sie Kontextblöcke aus gut strukturierten Vault-Notizen vorab erstellen und zwischenspeichern:

# 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
    },
}

Cache-Invalidierung

Die Cache-Invalidierung basiert auf zwei Signalen:

  1. TTL-Ablauf. Jeder Kontextblock hat eine Gültigkeitsdauer (Time-to-Live). Wenn die TTL abläuft, wird der Block durch erneute Abfrage des Vaults neu erstellt.
  2. Erkennung von Vault-Änderungen. Wenn der Indexer Änderungen an Dateien erkennt, die zu einem zwischengespeicherten Kontextblock beigetragen haben, wird der Block sofort invalidiert.

Token-Budget-Verwaltung

Eine Sitzung beginnt mit einem Gesamtbudget für den Kontext. Zwischengespeicherte Blöcke verbrauchen einen Teil dieses Budgets:

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)

Die zwischengespeicherten Blöcke werden beim Sitzungsstart geladen. Dynamische Suchergebnisse füllen das verbleibende Budget auf Basis einzelner Abfragen. Dieser hybride Ansatz gibt dem Agenten eine Grundlage häufig benötigten Kontexts und bewahrt gleichzeitig Budget für spezifische Abfragen.

Vorher/Nachher: Token-Verbrauch

Ohne Caching: Jede relevante Abfrage löst eine Vault-Suche aus, die 1.500–2.000 Token an Kontext liefert. Bei 10 Abfragen in einer Sitzung verbraucht der Agent 15.000–20.000 Token an Vault-Kontext.

Mit Caching: Drei vorab erstellte Kontextblöcke verbrauchen insgesamt 4.500 Token. Zusätzliche Suchen fügen 1.500–2.000 Token pro einzigartiger Abfrage hinzu. Bei 10 Abfragen, von denen 6 durch zwischengespeicherte Blöcke abgedeckt werden, verbraucht der Agent 4.500 + (4 × 1.500) = 10.500 Token — ungefähr die Hälfte des Verbrauchs ohne Caching.


PostToolUse-Hooks zur Kontextkomprimierung

Tool-Ausgaben können umfangreich sein: Stack-Traces, Dateilisten, Testergebnisse. Ein PostToolUse-Hook kann diese Ausgaben komprimieren, bevor sie Platz im Kontextfenster beanspruchen.

Das Problem

Ein Bash-Tool-Aufruf, der Tests ausführt, könnte Folgendes zurückgeben:

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

Die vollständige Ausgabe umfasst 5.000 Token, aber die relevante Information steckt in 2 Zeilen: 200 bestanden, 1 fehlgeschlagen.

Hook-Implementierung

#!/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

Verhinderung rekursiver Auslösung

Ein Komprimierungs-Hook, der Ausgaben erzeugt, könnte sich selbst auslösen, wenn keine Schutzmaßnahme vorhanden ist:

# Guard against recursive invocation
if [ -n "$COMPRESS_HOOK_ACTIVE" ]; then
    exit 0
fi
export COMPRESS_HOOK_ACTIVE=1

Komprimierungsheuristiken

Ausgabetyp Erkennung Komprimierungsstrategie
Testergebnisse Schlüsselwörter PASSED / FAILED Pass/Fail zählen, nur Fehler anzeigen
Dateilisten ls oder find im Befehl Auf die ersten 20 Einträge kürzen + Gesamtanzahl
Stack-Traces Schlüsselwort Traceback Ersten und letzten Frame + Fehlermeldung beibehalten
Git-Status modified: / new file: Anzahl nach Status zusammenfassen
Build-Ausgabe warning: / error: Info-Zeilen entfernen, Warnungen/Fehler beibehalten

Pipeline für Signalaufnahme und Triage

Die Aufnahmeschicht bestimmt, was in den Vault gelangt. Ohne Kuratierung sammelt der Vault Rauschen an. Dieser Abschnitt behandelt die Bewertungs-Pipeline, die Signale in Domänenordner weiterleitet.

Quellen

Signale stammen aus mehreren Kanälen:

  • RSS-Feeds: Technische Blogs, Sicherheitshinweise, Release Notes
  • Lesezeichen: Browser-Lesezeichen, gespeichert über Obsidian Web Clipper oder Bookmarklet
  • Newsletter: Wichtige Auszüge aus E-Mail-Newslettern
  • Manuelle Erfassung: Notizen, die beim Lesen, in Gesprächen oder bei Recherchen erstellt wurden
  • Tool-Ausgaben: Bedeutsame AI-Tool-Ausgaben, erfasst über Hooks

Bewertungsdimensionen

Jedes Signal wird in vier Dimensionen bewertet (jeweils 0,0 bis 1,0):

Dimension Frage Niedriger Wert (0,0–0,3) Hoher Wert (0,7–1,0)
Relevanz Bezieht sich dies auf meine aktiven Domänen? Tangential, außerhalb des Umfangs Direkt relevant für aktuelle Arbeit
Handlungsfähigkeit Kann ich diese Information nutzen? Reine Theorie, keine Anwendung Spezifische Technik oder Muster, die ich anwenden kann
Tiefe Wie substanziell ist der Inhalt? Schlagzeilen, oberflächliche Zusammenfassung Detaillierte Analyse mit Beispielen
Autorität Wie glaubwürdig ist die Quelle? Anonymer Blog, nicht verifiziert Primärquelle, peer-reviewed, anerkannter Experte

Gesamtbewertung und Weiterleitung

composite = (relevance * 0.35) + (actionability * 0.25) +
            (depth * 0.25) + (authority * 0.15)
Bewertungsbereich Aktion
0,55+ Automatische Weiterleitung in den Domänenordner
0,40 – 0,55 In Warteschlange für manuelle Überprüfung
< 0,40 Verwerfen (nicht speichern)

Domänenweiterleitung

Signale mit einer Bewertung über 0,55 werden anhand von Schlüsselwortabgleich und Themenklassifikation in einen von 12 Domänenordnern weitergeleitet:

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

Produktionsstatistiken

Über 14 Monate Betrieb:

Metrik Wert
Insgesamt verarbeitete Signale 7.771
Automatisch weitergeleitet (>0,55) 4.832 (62 %)
Zur Überprüfung eingereiht (0,40–0,55) 1.543 (20 %)
Verworfen (<0,40) 1.396 (18 %)
Aktive Domänenordner 12
Durchschnittliche Signale pro Tag ~18

Knowledge-Graph-Muster

Obsidians wiki-link-Graph kodiert Beziehungen zwischen Notizen. Dieser Abschnitt behandelt Link-Semantik, Graph-Traversierung zur Kontexterweiterung und Anti-Muster, die die Graphqualität verschlechtern.

Jeder wiki-link erzeugt eine gerichtete Kante im Graphen. Obsidian verfolgt sowohl Vorwärtslinks als auch Backlinks:

  • Vorwärtslink: Notiz A enthält [[Note B]] → A verlinkt auf B
  • Backlink: Notiz B zeigt, dass Notiz A sie referenziert

Der Graph kodiert verschiedene Arten von Beziehungen je nach Kontext:

Link-Muster Semantik Beispiel
Inline-Link „Steht in Beziehung zu” „Siehe [[OAuth Token Rotation]] für Details”
Header-Link „Hat Unterthema” „## Verwandt\n- [[Token Rotation]]\n- [[Session Management]]”
Tag-ähnlicher Link „Ist kategorisiert als” „[[type/reference]]”
MOC-Link „Ist Teil von” Eine Maps of Content-Notiz, die verwandte Notizen auflistet

Maps of Content (MOCs)

MOCs sind Indexnotizen, die verwandte Notizen in einer navigierbaren Struktur organisieren:

---
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 verbessern das Retrieval auf zwei Arten:

  1. Direkter Treffer. Eine Suche nach „Authentication Overview” trifft den MOC selbst und liefert dem Agenten eine kuratierte Liste verwandter Notizen.
  2. Kontexterweiterung. Nach dem Auffinden einer bestimmten Notiz kann der Retriever prüfen, ob die Notiz in MOCs vorkommt, und die Struktur des MOC in die Ergebnisse einbeziehen, wodurch der Agent eine Übersicht über das breitere Thema erhält.

Graph-Traversierung zur Kontexterweiterung

Eine zukünftige Erweiterung des Retrievers: Nach dem Auffinden der besten Ergebnisse den Kontext durch Verfolgen von Links erweitern:

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)

Dies ist im aktuellen Retriever nicht implementiert, stellt jedoch eine natürliche Erweiterung der Graphstruktur dar.

Anti-Muster

Verwaiste Cluster. Gruppen von Notizen, die untereinander verlinkt sind, aber keine Verbindungen zum Rest des Vaults haben. Das Graph-Panel in Obsidian macht diese als isolierte Inseln sichtbar. Verwaiste Cluster deuten auf fehlende MOCs oder fehlende domänenübergreifende Links hin.

Tag-Wildwuchs. Inkonsistente Verwendung von Tags oder Erstellung zu vieler feingranularer Tags. Ein Vault mit 500 einzigartigen Tags über 5.000 Notizen hat im Durchschnitt 1 Notiz pro 10 Tags — die Tags sind zum Filtern nicht nützlich. Konsolidieren Sie auf 20–50 übergeordnete Tags, die Ihren Domänenordnern entsprechen.

Link-lastige, inhaltsarme Notizen. Notizen, die ausschließlich aus wiki-links ohne Prosatext bestehen. Diese Notizen werden schlecht indexiert, da der Chunker keinen Text zum Einbetten (Embedding) hat. Fügen Sie mindestens einen Absatz Kontext hinzu, der erklärt, warum die verlinkten Notizen zusammenhängen.

Bidirektionale Links für alles. Nicht jede Erwähnung muss ein wiki-link sein. Die beiläufige Erwähnung von „OAuth” erfordert kein [[OAuth 2.0 Overview]]. Reservieren Sie wiki-links für beabsichtigte, navigierbare Beziehungen, bei denen ein Klick auf den Link nützlichen Kontext liefern würde.


Entwickler-Workflow-Rezepte

Praktische Workflows, die Vault-Retrieval mit täglichen Entwicklungsaufgaben kombinieren.

Morgendliches Kontextladen

Beginnen Sie den Tag, indem Sie relevanten Kontext laden:

Search my vault for notes about [current project] updated in the last week

Der Retriever gibt aktuelle Notizen zu Ihrem aktiven Projekt zurück und bietet Ihnen eine schnelle Auffrischung darüber, wo Sie aufgehört haben. Effektiver als das erneute Lesen der Commit-Nachrichten von gestern.

Wissenserfassung während des Programmierens

Während Sie ein Feature implementieren, erfassen Sie Erkenntnisse, ohne den Editor zu verlassen:

/capture "FastAPI dependency injection with async generators requires yield,
not return. The generator is the dependency lifecycle."
  --domain programming
  --tags fastapi,dependency-injection

Die erfasste Erkenntnis wird sofort indexiert und steht für zukünftiges Retrieval zur Verfügung. Über Monate hinweg bauen diese Mikro-Erfassungen einen Korpus implementierungsspezifischen Wissens auf.

Projekt-Kickoff

Beim Start eines neuen Projekts oder Features:

  1. Durchsuchen Sie den Vault: „Was weiß ich über [Technologie/Muster]?”
  2. Überprüfen Sie die Top-5-Ergebnisse auf frühere Entscheidungen und Fallstricke
  3. Prüfen Sie, ob ein MOC für die Domäne existiert; falls nicht, erstellen Sie einen
  4. Suchen Sie nach Fehlermodi: „Probleme mit [Technologie]”

Debugging mit Vault-Suche

Bei einem Fehler oder unerwartetem Verhalten:

Search my vault for [error message or symptom]

Frühere Debugging-Notizen enthalten oft die Ursache und Lösung. Dies ist besonders wertvoll bei wiederkehrenden Problemen über Projekte hinweg — der Vault erinnert sich an das, was Sie vergessen.

Vorbereitung auf Code-Reviews

Vor der Überprüfung eines PR:

Search my vault for patterns and conventions about [module being changed]

Der Vault liefert frühere Entscheidungen, architektonische Einschränkungen und Codierungsstandards, die für den zu überprüfenden Code relevant sind. Das Review wird durch institutionelles Wissen informiert, nicht nur durch den Diff.

Leistungsoptimierung

Dieser Abschnitt behandelt Optimierungsstrategien für verschiedene Vault-Größen und Nutzungsmuster.

Verwaltung der Indexgröße

Vault-Größe Chunks DB-Größe Vollständige Neuindizierung Inkrementell
500 Notizen ~1.500 3 MB 15 Sekunden <1 Sekunde
2.000 Notizen ~6.000 12 MB 45 Sekunden 2 Sekunden
5.000 Notizen ~15.000 30 MB 2 Minuten 4 Sekunden
15.000 Notizen ~50.000 83 MB 4 Minuten <10 Sekunden
50.000 Notizen ~150.000 250 MB 15 Minuten 30 Sekunden

Ab 50.000+ Notizen sollten Sie Folgendes in Betracht ziehen: - Erhöhung der Batch-Größe von 64 auf 128 für schnelleres Embedding - Verwendung des WAL-Modus (Standard) für gleichzeitigen Zugriff - Durchführung der vollständigen Neuindizierung außerhalb der Hauptnutzungszeiten

Abfrageoptimierung

WAL-Modus. Der Write-Ahead-Logging-Modus von SQLite ermöglicht gleichzeitige Lesezugriffe, während der Indexer schreibt:

db.execute("PRAGMA journal_mode=WAL")

Dies ist entscheidend, wenn der MCP-Server Abfragen verarbeitet, während der Indexer ein inkrementelles Update durchführt.

Connection-Pooling. Der MCP-Server sollte Datenbankverbindungen wiederverwenden, anstatt pro Abfrage eine neue Verbindung zu öffnen. Eine einzelne langlebige Verbindung mit WAL-Modus unterstützt gleichzeitige Lesezugriffe.

# 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. Das mmap_size-Pragma weist SQLite an, Memory-Mapped I/O für die Datenbankdatei zu verwenden. Bei einer 83 MB großen Datenbank eliminiert das Mapping der gesamten Datei in den Arbeitsspeicher die meisten Festplattenzugriffe.

FTS5-Optimierung. Führen Sie nach einer vollständigen Neuindizierung Folgendes aus:

INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');

Dies führt die internen B-Tree-Segmente von FTS5 zusammen und reduziert die Abfragelatenz für nachfolgende Suchen.

Skalierungs-Benchmarks

Gemessen auf Apple M3 Pro, 36 GB RAM, NVMe SSD:

Operation 500 Notizen 5K Notizen 15K Notizen 50K Notizen
BM25-Abfrage 2ms 5ms 12ms 25ms
Vektorabfrage 1ms 3ms 8ms 20ms
RRF-Fusion <1ms <1ms 3ms 5ms
Vollständige Suche 3ms 8ms 23ms 50ms

Alle Benchmarks umfassen Datenbankzugriff, Abfrageausführung und Ergebnisformatierung. Die Netzwerklatenz für die MCP STDIO-Kommunikation fügt 1–2ms hinzu.


Fehlerbehebung

Index-Drift

Symptom: Die Suche liefert veraltete Ergebnisse oder übersieht kürzlich hinzugefügte Notizen.

Ursache: Der inkrementelle Indexer wurde nach dem Hinzufügen von Notizen nicht ausgeführt, oder die mtime einer Datei wurde nicht aktualisiert (z. B. von einem anderen Rechner synchronisiert mit beibehaltenen Zeitstempeln).

Lösung: Führen Sie eine vollständige Neuindizierung durch: python index_vault.py --full

Wechsel des Embedding-Modells

Symptom: Nach dem Wechsel des Embedding-Modells liefert die Vektorsuche unsinnige Ergebnisse.

Ursache: Alte Vektoren (vom vorherigen Modell) werden mit neuen Abfragevektoren verglichen. Die Dimensionen oder die Vektorraum-Semantik sind inkompatibel.

Lösung: Der Indexer sollte die Modell-Hash-Abweichung erkennen und automatisch eine vollständige Neuindizierung auslösen. Falls nicht, löschen Sie die Datenbank manuell und indizieren Sie neu:

rm vectors.db
python index_vault.py --full

FTS5-Wartung

Symptom: FTS5-Abfragen liefern nach vielen inkrementellen Updates falsche oder unvollständige Ergebnisse.

Ursache: Interne FTS5-Segmente können nach vielen kleinen Updates fragmentiert werden.

Lösung: Neuaufbau und Optimierung:

INSERT INTO chunks_fts(chunks_fts) VALUES('rebuild');
INSERT INTO chunks_fts(chunks_fts) VALUES('optimize');

MCP-Timeout

Symptom: Das AI-Tool meldet, dass der MCP-Server eine Zeitüberschreitung hatte.

Ursache: Die erste Abfrage löst das Laden des Modells aus (Lazy Initialization), was 2–5 Sekunden dauert. Das Standard-MCP-Timeout des AI-Tools ist möglicherweise kürzer.

Lösung: Wärmen Sie das Modell beim Serverstart vor:

# In MCP server initialization
retriever = HybridRetriever(db_path, vault_path)
retriever.search("warmup", limit=1)  # Trigger model load

SQLite-Dateisperren

Symptom: SQLITE_BUSY- oder SQLITE_LOCKED-Fehler.

Ursache: Mehrere Prozesse schreiben gleichzeitig in die Datenbank. Der WAL-Modus erlaubt gleichzeitige Lesezugriffe, aber nur einen Schreibzugriff.

Lösung: Stellen Sie sicher, dass nur ein Prozess (der Indexer) in die Datenbank schreibt. Der MCP-Server und die Hooks sollten nur lesen. Falls Sie gleichzeitige Schreibzugriffe benötigen, verwenden Sie den WAL-Modus und setzen Sie ein Busy-Timeout:

db.execute("PRAGMA busy_timeout=5000")  # Wait up to 5 seconds

sqlite-vec wird nicht geladen

Symptom: Die Vektorsuche ist deaktiviert; der Retriever arbeitet nur im BM25-Modus.

Ursache: Die sqlite-vec-Erweiterung ist nicht installiert, wird im Bibliothekspfad nicht gefunden oder ist mit der SQLite-Version inkompatibel.

Lösung:

# Install via pip
pip install sqlite-vec

# Or compile from source
git clone https://github.com/asg017/sqlite-vec
cd sqlite-vec && make

Überprüfen Sie, ob die Erweiterung geladen wird:

import sqlite3
db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
db.load_extension("vec0")
print("sqlite-vec loaded successfully")

Speicherprobleme bei großen Vaults

Symptom: Speicherüberlauf-Fehler während der vollständigen Neuindizierung eines großen Vaults (50.000+ Notizen).

Ursache: Die Embedding-Batch-Größe ist zu groß, oder alle Dateiinhalte werden gleichzeitig in den Arbeitsspeicher geladen.

Lösung: Reduzieren Sie die Batch-Größe und verarbeiten Sie Dateien inkrementell:

BATCH_SIZE = 32  # Reduce from 64

Stellen Sie außerdem sicher, dass der Indexer Dateien einzeln verarbeitet (jede Datei lesen, in Chunks aufteilen und Embeddings erstellen, bevor die nächste bearbeitet wird), anstatt alle Dateien gleichzeitig in den Arbeitsspeicher zu laden.


Migrationsanleitung

Von Apple Notes

  1. Exportieren Sie Apple Notes über die Option „Alle exportieren” (macOS) oder verwenden Sie ein Migrationstool wie apple-notes-liberator
  2. Konvertieren Sie HTML-Exporte in Markdown mit markdownify oder pandoc
  3. Verschieben Sie die konvertierten Dateien in den 00-inbox/-Ordner Ihres Vaults
  4. Überprüfen Sie jede Notiz und fügen Sie frontmatter hinzu
  5. Verschieben Sie Notizen in die entsprechenden Domänenordner

Von Notion

  1. Exportieren Sie aus Notion: Einstellungen → Exportieren → Markdown & CSV
  2. Entpacken Sie den Export in den 00-inbox/-Ordner Ihres Vaults
  3. Beheben Sie Notion-spezifische Markdown-Artefakte:
  4. Notion verwendet - [ ] für Checklisten — dies ist Standard-Markdown
  5. Notion fügt Eigenschaftstabellen als HTML ein — konvertieren Sie diese zu YAML-frontmatter
  6. Notion bettet Bilder als relative Pfade ein — kopieren Sie Bilder in Ihren Anhänge-Ordner
  7. Fügen Sie Standard-frontmatter hinzu (type, domain, tags)
  8. Ersetzen Sie Notion-Seitenlinks durch Obsidian wiki-links

Von Google Docs

  1. Verwenden Sie Google Takeout, um alle Dokumente zu exportieren
  2. Konvertieren Sie .docx-Dateien in Markdown: pandoc -f docx -t markdown input.docx -o output.md
  3. Stapelkonvertierung: for f in *.docx; do pandoc -f docx -t markdown "$f" -o "${f%.docx}.md"; done
  4. Verschieben Sie die Dateien in den Vault, fügen Sie frontmatter hinzu und organisieren Sie sie in Ordnern

Von reinem Markdown (ohne Obsidian)

Wenn Sie bereits ein Verzeichnis mit Markdown-Dateien haben:

  1. Öffnen Sie das Verzeichnis als Obsidian-Vault (Obsidian → Vault öffnen → Ordner öffnen)
  2. Fügen Sie .obsidian/ zu .gitignore hinzu, falls das Verzeichnis versionskontrolliert ist
  3. Erstellen Sie frontmatter-Vorlagen und wenden Sie diese auf bestehende Dateien an
  4. Beginnen Sie, Notizen mit [[wiki-links]] zu verknüpfen, während Sie lesen und organisieren
  5. Führen Sie den Indexer sofort aus — das Retrieval-System funktioniert ab dem ersten Tag

Von einem anderen Retrieval-System

Wenn Sie von einem anderen Embedding-/Suchsystem migrieren:

  1. Versuchen Sie nicht, Vektoren zu migrieren. Verschiedene Modelle erzeugen inkompatible Vektorräume. Führen Sie eine vollständige Neuindizierung mit dem neuen Modell durch.
  2. Migrieren Sie den Inhalt, nicht den Index. Die Vault-Dateien sind die Quelle der Wahrheit. Der Index ist ein abgeleitetes Artefakt.
  3. Überprüfen Sie nach der Migration. Führen Sie 10–20 Abfragen durch, deren Antworten Sie kennen, und überprüfen Sie, ob die Ergebnisse Ihren Erwartungen entsprechen.

Änderungsprotokoll

Datum Änderung
03.03.2026 Aktualisierung der MCP-Spezifikationsentwicklung (Nov 2025 ausgeliefert: Streamable HTTP, .well-known, Tool-Annotationen). Hinzufügung von Model2Vec Fine-Tuning und BPE/Unigram-Tokenizer-Unterstützung. Hinzufügung der Community-MCP-Server-Vergleichstabelle. Aktualisierung von Smart Connections auf v4.
02.03.2026 Hinzufügung von potion-base-32M und potion-retrieval-32M zum Modellvergleich. Hinzufügung des Abschnitts zu Quantisierung/Dimensionsreduktion. Hinzufügung der Anmerkung zur MCP-Spezifikationsentwicklung.
01.03.2026 Erstveröffentlichung

Referenzen


  1. Cormack, G.V., Clarke, C.L.A., und Buettcher, S. Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods. SIGIR, 2009. Führt RRF mit k=60 als parameterfreie Methode zur Kombination von Ranglisten ein. 

  2. OpenAI Embeddings Pricing. text-embedding-3-small: 0,02 $ pro Million Tokens. Geschätzte Vault-Kosten pro vollständiger Neuindexierung: ~0,30 $. 

  3. van Dongen, T. et al. Model2Vec: Turn any Sentence Transformer into a Small Fast Model. arXiv, 2025. Beschreibt den Destillationsansatz zur Erzeugung statischer Embeddings aus Sentence Transformers. 

  4. MTEB: Massive Text Embedding Benchmark. potion-base-8M erreicht einen Durchschnitt von 50,03 gegenüber 56,09 für all-MiniLM-L6-v2 (89 % Erhaltungsrate). 

  5. SQLite FTS5 Extension. FTS5 bietet Volltextsuche mit BM25-Ranking und konfigurierbaren Spaltengewichtungen. 

  6. sqlite-vec: A vector search SQLite extension. Stellt vec0-virtuelle Tabellen für KNN-Vektorsuche innerhalb von SQLite bereit. 

  7. Robertson, S. und Zaragoza, H. The Probabilistic Relevance Framework: BM25 and Beyond. Foundations and Trends in Information Retrieval, 2009. 

  8. Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. EMNLP, 2020. Dichte Repräsentationen übertreffen BM25 um 9–19 % bei Open-Domain-Fragebeantwortung. 

  9. Reimers, N. und Gurevych, I. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. EMNLP, 2019. Grundlegende Arbeit zu dichter semantischer Ähnlichkeit. 

  10. Luan, Y. et al. Sparse, Dense, and Attentional Representations for Text Retrieval. TACL, 2021. Hybrid Retrieval übertrifft konsistent Einzelmodalitäts-Ansätze auf MS MARCO. 

  11. SQLite Write-Ahead Logging. WAL-Modus für gleichzeitige Lesezugriffe mit einem einzelnen Schreiber. 

  12. Gao, Y. et al. Retrieval-Augmented Generation for Large Language Models: A Survey. arXiv, 2024. Überblick über RAG-Architekturen und Chunking-Strategien. 

  13. Thakur, N. et al. BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models. NeurIPS, 2021. 

  14. Model2Vec: Distill a Small Fast Model from any Sentence Transformer. Minish Lab, 2024. 

  15. Obsidian Documentation. Offizielle Dokumentation für Obsidian. 

  16. Model Context Protocol Specification. Der MCP-Standard zur Verbindung von KI-Tools mit Datenquellen. 

  17. Produktionsdaten des Autors. 16.894 Dateien, 49.746 Chunks, 83,56 MB SQLite-Datenbank, 7.771 verarbeitete Signale über 14 Monate. Abfragelatenz gemessen über time.perf_counter()

  18. Model2Vec Potion Models. Minish Lab, 2025. Potion-base-32M (MTEB 52,46), potion-retrieval-32M (MTEB Retrieval 36,35) und v0.5.0+-Funktionen für Quantisierung/Dimensionsreduktion. 

  19. Update on the Next MCP Protocol Release. Die Veröffentlichung vom November 2025 brachte Streamable-HTTP-Transport, .well-known-URL-Erkennung, strukturierte Tool-Annotationen und SDK-Tier-Standardisierung. Nächste Veröffentlichung voraussichtlich Mitte 2026 mit asynchronen Operationen, domänenspezifischen Erweiterungen und Agent-zu-Agent-Kommunikation. 

  20. Model2Vec Releases. v0.4.0 (Feb. 2025): Unterstützung für Training/Feinabstimmung. v0.5.0 (Apr. 2025): Backend-Neuschreibung, Quantisierung, Dimensionsreduktion. v0.7.0 (Okt. 2025): Vokabular-Quantisierung, BPE/Unigram-Tokenizer-Unterstützung. 

  21. Smart Connections for Obsidian. Smart Connections v4: Local-First-KI-Embeddings, semantische Suche funktioniert nach der ersten Indexierung offline. 

VAULT obsidian.md INDEXED