obsidian:~/vault$ search --hybrid obsidian

Obsidian MCP + récupération hybride : référence 2026

# Connectez Obsidian à Claude et à d’autres agents via MCP : configuration du serveur, récupération hybride BM25 + vectorielle et indexation d’un vault de 16 894 fichiers — avec des configurations fonctionnelles.

author: words: 20668 read_time: 104m updated: 2026-08-16 11:28
$ retriever search --hybrid obsidian

Obsidian n’est pas une application de prise de notes. C’est un corpus Markdown en texte brut, local-first et structuré en graphe, qui devient un réservoir de contexte pour l’IA dès que vous lui ajoutez une infrastructure de recherche. 16 894 fichiers. 49 746 chunks. Requêtes en 23 ms. Zéro appel à API. Un fichier SQLite de 83 Mo. Ce guide couvre le système complet : de l’architecture du coffre Obsidian au hybrid retrieval, puis à l’intégration MCP et aux workflows opérationnels.


Points clés

De l’ingénierie de contexte, pas de la prise de notes. La valeur d’un vault Obsidian pour l’IA ne réside pas dans les notes elles-mêmes, mais dans la couche de retrieval qui permet de les interroger. Un vault de 16 000 fichiers dépourvu de retrieval est une base de données en écriture seule. Un vault de 200 fichiers avec une recherche hybrid et une intégration MCP constitue une base de connaissances pour l’IA. L’infrastructure de retrieval est le produit. Les notes en sont la matière première.

Le retrieval hybrid surpasse la recherche par mots-clés ou sémantique pure. BM25 repère les identifiants et les noms de fonctions exacts. La recherche vectorielle détecte les synonymes et les correspondances conceptuelles malgré des terminologies différentes. Reciprocal Rank Fusion (RRF) combine les deux sans nécessiter de calibrage des scores. Aucune de ces méthodes ne couvre, à elle seule, les deux modes de défaillance. Les recherches sur le classement de passages MS MARCO confirment ce constat : le retrieval hybrid surpasse systématiquement chaque méthode utilisée isolément.3 L’analyse approfondie du retriever hybrid détaille les calculs RRF, des exemples chiffrés réels, l’analyse des modes de défaillance et un calculateur de fusion interactif.

MCP offre aux outils d’IA un accès direct au vault. Les serveurs Model Context Protocol (MCP) exposent le retriever comme un outil que Claude Code, Codex CLI, Cursor et d’autres outils d’IA peuvent appeler directement. L’agent interroge le vault, reçoit des résultats classés avec attribution des sources, puis utilise ce contexte sans charger des fichiers entiers. Le serveur MCP est une fine couche d’encapsulation autour du moteur de retrieval.

Le local-first garantit zéro coût API et une confidentialité totale. L’ensemble de la stack s’exécute sur une seule machine : SQLite pour le stockage, Model2Vec pour les embeddings, FTS5 pour la recherche par mots-clés, sqlite-vec pour le KNN vectoriel. Aucun service cloud, aucun appel API, aucune dépendance réseau. Les notes personnelles ne quittent jamais la machine. La réintégration complète de 49 746 chunks coûterait environ 0,30 $ aux tarifs API d’OpenAI, mais les véritables coûts sont la latence, l’exposition de la confidentialité et la dépendance réseau pour un système qui devrait fonctionner hors ligne.4

L’indexation incrémentielle maintient le système à jour en moins de 10 secondes. La comparaison des dates de modification des fichiers détecte les changements. Seuls les fichiers modifiés sont de nouveau découpés et réintégrés. Une réindexation complète prend environ quatre minutes sur du matériel Apple M-series. Les mises à jour incrémentielles correspondant aux modifications d’une journée typique s’exécutent en moins de dix secondes. Le système reste à jour sans intervention manuelle.

L’architecture passe à l’échelle de 200 à plus de 20 000 notes. Cette même conception en trois couches (ingestion, retrieval, intégration) fonctionne quelle que soit la taille du vault. Commencez par une recherche reposant uniquement sur BM25 pour un petit vault. Ajoutez la recherche vectorielle lorsque les collisions de mots-clés deviennent problématiques. Ajoutez la fusion RRF lorsque vous avez besoin à la fois de correspondances exactes et sémantiques. Chaque couche est utile indépendamment et peut être retirée indépendamment.


Comment utiliser ce guide

Ce guide couvre l’ensemble du système. Votre point de départ dépend de votre situation :

Vous êtes… Commencez ici Explorez ensuite
Débutant avec Obsidian + IA Pourquoi Obsidian pour l’infrastructure IA, Configuration d’Obsidian MCP Architecture du vault, Architecture du serveur MCP
Vous avez déjà un vault et souhaitez un accès IA Architecture du serveur MCP, Intégration Claude Code Modèles d’embeddings, Recherche full-text
Vous construisez un système de retrieval Le pipeline de retrieval complet, Reciprocal Rank Fusion Réglage des performances, Dépannage
Contexte d’équipe ou d’entreprise Cadre de décision, Modèles de graphe de connaissances Recettes de workflows développeur, Guide de migration

Les sections marquées Contract comprennent des détails d’implémentation, des blocs de configuration et des modes de défaillance. Les sections marquées Narrative se concentrent sur les concepts, les décisions d’architecture et le raisonnement qui sous-tend les choix de conception. Les sections marquées Recipe proposent des workflows étape par étape.


Pourquoi Obsidian pour l’infrastructure IA

La thèse de ce guide : les vaults Obsidian constituent le meilleur substrat pour les bases de connaissances personnelles destinées à l’IA, car ils sont local-first, en plaintext, structurés en graphe, et l’utilisateur contrôle chaque couche de la stack.

Ce qu’Obsidian offre à l’IA et que les alternatives n’offrent pas

Des fichiers markdown en plaintext. Chaque note est un fichier .md dans votre système de fichiers. Aucun format propriétaire, aucune exportation de base de données, aucun API requis pour lire le contenu. Tout outil qui lit des fichiers peut lire votre vault. grep, ripgrep, le pathlib de Python, SQLite FTS5 — tous fonctionnent directement sur les fichiers source. Lorsque vous construisez un système de retrieval, vous indexez des fichiers, pas des réponses API. L’index est toujours cohérent avec la source, car la source est le système de fichiers.

Une architecture local-first. Le vault réside sur votre machine. Aucun serveur, aucune dépendance à la synchronisation cloud, aucune limite de débit API, aucune condition d’utilisation régissant la manière dont vous traitez votre propre contenu. Vous pouvez créer les embeddings, indexer, découper et rechercher dans vos notes sans aucun service externe. Cela importe pour l’infrastructure IA, car le pipeline de retrieval s’exécute à la vitesse permise par votre disque, et non à celle à laquelle répond un endpoint API. Cela compte également pour la confidentialité : les notes personnelles contenant des identifiants, des données de santé, des informations financières et des réflexions privées ne quittent jamais votre machine.

Une structure en graphe via les wiki-links. La syntaxe [[wiki-link]] d’Obsidian crée un graphe orienté entre les notes. Une note consacrée à l’implémentation de OAuth renvoie vers des notes sur la rotation des tokens, la gestion des sessions et la sécurité API. La structure en graphe encode des relations entre concepts sélectionnées par l’humain. Les embeddings vectoriels capturent la similarité sémantique, mais les wiki-links capturent des connexions intentionnelles établies par l’auteur lors de sa réflexion sur le sujet. Le graphe est un signal que les embeddings ne peuvent pas reproduire.

Un écosystème de plugins. Obsidian compte plus de 2 500 plugins communautaires (le total a franchi les 2 500 en mars 2026, contre plus de 1 800 à la mi-2025). Dataview interroge votre vault comme une base de données. Templater génère des notes à partir de modèles avec une logique JavaScript. L’intégration Git synchronise votre vault avec un dépôt. Linter applique une mise en forme cohérente. Le plugin central Bases (introduit dans la v1.9.10) ajoute des vues de type base de données — tableaux, galeries, calendriers et tableaux kanban — sur les fichiers du vault, en utilisant les propriétés frontmatter comme champs, enregistrées dans des fichiers .base.15 Ces plugins ajoutent de la structure au vault sans modifier le format plaintext sous-jacent. Le système de retrieval indexe la sortie de ces plugins, et non les plugins eux-mêmes.

Plus de 5 millions d’utilisateurs. Obsidian dispose d’une vaste communauté active produisant des modèles, des workflows, des plugins et de la documentation. Lorsqu’un problème d’organisation du vault ou de configuration de plugins se présente, quelqu’un a probablement déjà documenté une solution. La communauté produit également des outils gravitant autour d’Obsidian : des serveurs MCP, des scripts d’indexation, des pipelines de publication et des wrappers API.

Ce qu’un système de fichiers seul ne vous apporte pas

Un dossier de fichiers markdown présente l’avantage du plaintext, mais il lui manque trois éléments qu’Obsidian apporte :

  1. Des liens bidirectionnels. Obsidian suit automatiquement les backlinks. Lorsque vous créez un lien de la note A vers la note B, la note B indique que la note A la référence. Le panneau de graphe visualise les groupes de connexions. Cette connaissance bidirectionnelle est une métadonnée qu’un système de fichiers brut ne fournit pas.

  2. Un aperçu en direct avec le rendu des plugins. Les requêtes Dataview, les diagrammes Mermaid et les blocs callout s’affichent en temps réel. L’expérience d’écriture est plus riche que celle d’un éditeur de texte, tout en conservant un format de stockage plaintext. Vous écrivez et organisez dans un environnement riche ; le système de retrieval indexe le markdown brut.

  3. Une infrastructure communautaire. Découverte de plugins, marketplace de thèmes, service de synchronisation (facultatif), service de publication (facultatif) et écosystème documentaire. Vous pouvez reproduire toute fonctionnalité individuelle avec des outils autonomes, mais Obsidian les rassemble dans un workflow cohérent.

Ce qu’Obsidian ne fait PAS (et ce que vous construisez)

Obsidian n’inclut pas d’infrastructure de retrieval. Il propose une recherche basique (full-text, nom de fichier, tag), mais aucun pipeline d’embeddings, aucune recherche vectorielle, aucun classement par fusion, aucun serveur MCP, aucun filtrage des identifiants, aucune stratégie de chunking et aucun hook d’intégration pour des outils d’IA externes. Ce guide couvre l’infrastructure que vous construisez au-dessus d’Obsidian. Le vault est le substrat. Le pipeline de retrieval, le serveur MCP et les hooks d’intégration constituent l’infrastructure.

L’architecture décrite ici est markdown-first, et non exclusivement réservée à Obsidian. Si vous utilisez Logseq, Foam, Dendron ou un simple dossier de fichiers markdown, le pipeline de retrieval fonctionne de façon identique. Le chunker lit les fichiers .md. L’embedder traite des chaînes de texte. L’indexer écrit dans SQLite. Aucun de ces composants ne dépend de fonctionnalités propres à Obsidian. La contribution d’Obsidian est l’environnement d’écriture et d’organisation qui produit les fichiers markdown indexés par le retriever.

Configuration d’Obsidian MCP

Model Context Protocol (MCP) est l’interface standard qui donne à Claude Code, Codex CLI, Cursor et d’autres outils d’IA un accès direct à un vault Obsidian. Cette section permet de connecter un vault à un outil d’IA en cinq minutes. Vous allez installer Obsidian, créer un vault, installer un serveur MCP et exécuter votre première requête. Le démarrage rapide utilise un serveur MCP communautaire pour obtenir des résultats immédiatement. Les sections suivantes expliquent comment créer un pipeline de retrieval personnalisé pour une utilisation en production.

Prérequis

  • macOS, Linux ou Windows
  • Node.js 18+ (pour le serveur MCP)
  • Obsidian 1.12+ (pour l’intégration CLI ; 1.13.7 est la version publique actuelle pour ordinateur – les versions stable et bêta ont convergé, la branche 1.13 a quitté Catalyst le 30 juillet 2026 ; les versions antérieures fonctionnent pour les configurations utilisant uniquement MCP)
  • Claude Code, Codex CLI ou Cursor installé

Étape 1 : créer un vault

Téléchargez Obsidian depuis obsidian.md et créez un nouveau vault. Choisissez un emplacement dont vous vous souviendrez — le serveur MCP a besoin du chemin absolu.

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

Ajoutez quelques notes afin de fournir au retriever des éléments sur lesquels travailler. Même 10 à 20 notes suffisent pour observer des résultats. Chaque note doit être un fichier .md avec un titre explicite et au moins un paragraphe de contenu.

Étape 2 : installer un serveur MCP

Plusieurs serveurs MCP communautaires donnent un accès immédiat au vault. L’écosystème s’est considérablement développé entre 2025 et 2026. L’un des plus remarquables est MCPVault (npm @bitbonsai/mcpvault, dépôt bitbonsai/mcpvault), désormais en v0.15.0 (vérifié sur npm le 14 août 2026) — un projet distinct de MarkusPfundstein/mcp-obsidian ci-dessous, et non un changement de nom. Sa v0.11.0 (mars 2026) a ajouté list_all_tags pour analyser les frontmatter et hashtags avec leurs décomptes, amélioré la gestion des dossiers avec points, ainsi que la prise en charge de .base/.canvas. La série de trois correctifs publiés le même jour, le 23 juillet 2026, mérite d’être adoptée : v0.12.3 ajoute un outil wiki_link qui résout les formes [[Document Name]], [[Name|Display]], [[Name\|Display]] échappées dans les tableaux et #fragment, en renvoyant le contenu de la note, le chemin résolu et les éventuelles alternatives ambiguës — la primitive de retrieval qui permet à un agent de suivre le propre graphe de liens d’un vault au lieu de le rechercher de nouveau — et exclut .trash/ de chaque outil grâce au filtre de chemin par défaut ; v0.12.4 étend wiki_link aux liens avec chemin, tels que [[folder/Note]] ; v0.12.2 empêche patch_note de corrompre les insertions contenant des motifs de remplacement $ et normalise les chemins qui incluent accidentellement le préfixe du vault. Deux avis de sécurité de gravité moyenne (GHSA-9c83-rr99-vfwj et GHSA-j99q-93c9-h869) ont été publiés concernant sa liste de refus de répertoires restreints basée sur le filtre de chemin ; les deux ont été corrigés bien avant la branche 0.12, dans les versions 0.11.4 et 0.11.5 ; toute version 0.12.x en est donc exempte.13

Évolution d’avril 2026 — Obsidian CLI comme pont privilégié : Obsidian 1.12.0 a introduit CLI comme fonctionnalité native, et l’installateur public 1.12.7 (23 mars 2026) intégrait le binaire autonome + TUI + les améliorations du fichier socket qui ont facilité l’installation et l’exécution des workflows en terminal.16 La branche 1.13 a atteint le canal public en 1.13.4 le 30 juillet 2026 — une version consacrée aux paramètres, aux images et à la sécurité des URI, sans nouvelles capacités d’IA ou d’automatisation au-delà de la surface CLI de la 1.12.x (consultez la ligne du changelog pour savoir ce qu’elle modifie).2526 Les outils communautaires migrent activement du plugin Local REST API (qui alimentait mcp-obsidian) vers une intégration basée sur CLI, car elle est plus rapide et plus stable. Le dépôt MarkusPfundstein/mcp-obsidian est toujours maintenu — des commits jusqu’en mai 2026 ont ajouté des outils, dont search_by_tag et get_frontmatter — bien qu’il ne publie aucune version taguée (installez-le depuis un commit épinglé). Il reste basé sur Local REST API ; pour les nouvelles configurations, le pont CLI est généralement plus rapide et plus stable, privilégiez-le donc, ou les alternatives communautaires plus récentes listées ci-dessous.20 Consultez la section « Obsidian CLI pour les workflows d’IA » plus loin dans ce guide pour la configuration recommandée.

Serveur Auteur Transport Nécessite un plugin Fonctionnalité clé
obsidian-mcp (npm obsidian-mcp) StevenStavrakis STDIO Non Léger, basé sur les fichiers
mcp-obsidian MarkusPfundstein STDIO Local REST API CRUD complet du vault via REST, plus search_by_tag/get_frontmatteractivement maintenu (commits jusqu’en mai 2026) ; aucune version taguée, épinglez un commit20
obsidian-mcp-tools jacksteamdev STDIO Oui (plugin) Recherche sémantique + Templater
obsidian-claude-code-mcp iansinnott WebSocket Oui (plugin) Découverte automatique pour Claude Code
obsidian-mcp-server (npm obsidian-mcp-server) cyanheads STDIO Local REST API Tags, gestion des frontmatter — configuré via OBSIDIAN_API_KEY/OBSIDIAN_BASE_URL, et non avec des flags CLI
Hybrid Search MCP communauté STDIO Non Serveur MCP de recherche BM25 + sémantique + CLI. Maintenu par la communauté ; vérifiez les commits récents avant de l’adopter.

Pour le démarrage rapide, l’option la plus simple est un serveur basé sur les fichiers qui lit directement les fichiers .md. Attention à la collision de noms npm : le serveur basé sur les fichiers est npm obsidian-mcp (StevenStavrakis) ; npm obsidian-mcp-server est le serveur cyanheads adossé à REST-API, qui nécessite le plugin Local REST API et une clé API — une confusion fréquente qui laisse les lecteurs avec un serveur incapable de démarrer :

npm install -g obsidian-mcp

Étape 3 : configurer votre outil d’IA

Claude Code — enregistrez le serveur avec claude mcp add (Claude Code stocke les serveurs MCP dans ~/.claude.json pour la portée utilisateur ou dans le .mcp.json d’un projet — et non dans ~/.claude/settings.json, qui ignore silencieusement un bloc mcpServers) :

# User scope (all your projects)
claude mcp add obsidian -s user -- npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/your/vault

# Or project scope, shared with the repo (writes .mcp.json)
claude mcp add obsidian -s project -- npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/your/vault

Codex CLI — ajoutez-le à ~/.codex/config.toml :

[mcp_servers.obsidian]
command = "npx"
args = ["-y", "obsidian-mcp@2", "serve", "--vault", "notes=/absolute/path/to/your/vault"]

Cursor — ajoutez-le à .cursor/mcp.json :

{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": ["-y", "obsidian-mcp@2", "serve", "--vault", "notes=/absolute/path/to/your/vault"]
    }
  }
}

Étape 4 : exécuter votre première requête

Ouvrez votre outil d’IA et posez une question à laquelle les notes de votre vault peuvent répondre :

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

L’outil d’IA appelle le serveur MCP, qui recherche dans votre vault et renvoie le contenu correspondant. Vous devriez voir des résultats avec les chemins de fichiers et des extraits pertinents.

Ce que Claude peut faire une fois connecté

Les noms exacts des outils varient selon le serveur, mais les capacités principales restent cohérentes d’une implémentation à l’autre :

Capacité Outil typique Ce que l’agent en fait
Rechercher dans le vault obsidian_search / search Trouve les notes correspondant à une requête et renvoie des extraits classés avec les chemins de fichiers et l’attribution des sources
Lire une note complète obsidian_read_note / read_note Récupère le contenu complet d’une note lorsqu’un extrait de recherche ne suffit pas
Lister et parcourir obsidian_list_notes / list_notes Explore les notes par dossier, tag ou plage de dates lorsqu’il n’y a pas de requête précise
Obtenir du contexte formaté obsidian_get_context Renvoie un bloc de contexte structuré par sujet, dimensionné selon un budget de tokens, prêt à être injecté dans la conversation

En pratique : Claude répond aux questions à partir de vos notes avec attribution des sources, récupère les décisions antérieures et les documents de référence dans les sessions de développement, et explore la structure du vault sans charger des fichiers entiers dans le contexte. Certains serveurs communautaires exposent également des opérations d’écriture (création, ajout, gestion des tags et des frontmatter) ; le serveur personnalisé créé plus loin dans ce guide est délibérément en lecture seule, la création de notes étant gérée par des hooks.

Approfondissements : architecture de serveur MCP pour la conception des outils et des autorisations, intégration Claude Code pour les hooks et le modèle de pont, intégration Codex CLI et Cursor et autres outils pour les autres agents.

Ce que vous venez de créer

Vous avez connecté une base de connaissances locale à un outil d’IA via un protocole standard. Le serveur MCP lit les fichiers de votre vault, effectue une recherche basique et renvoie les résultats. C’est la version minimale viable.

Ce que ce démarrage rapide ne vous apporte PAS : - Retrieval hybride (recherche BM25 + vectorielle + fusion RRF) - Recherche sémantique basée sur les embeddings - Filtrage des identifiants - Indexation incrémentielle - Injection automatique de contexte basée sur des hooks

Le reste de ce guide explique comment créer chacune de ces capacités. Le démarrage rapide valide le concept. Le pipeline complet offre un retrieval de qualité production.


CLI Obsidian pour les workflows IA

Obsidian 1.12 (février 2026) a introduit une interface de ligne de commande intégrée qui ouvre une nouvelle surface d’intégration pour les workflows IA ; elle reste actuelle jusqu’à la version 1.13.7 (la branche 1.13 a atteint le canal public le 30 juillet 2026 ; aucune nouvelle capacité CLI depuis).162526 La CLI fait office de télécommande pour l’interface graphique d’Obsidian — Obsidian doit être en cours d’exécution (ou se lancera automatiquement lors de la première commande). Activez-la dans Paramètres > Général > Interface de ligne de commande.

Pourquoi la CLI est importante pour l’infrastructure IA

La CLI offre un accès programmatique aux opérations natives d’Obsidian qui nécessitaient auparavant l’interface graphique ou des API de plugins. Pour les workflows IA, les capacités clés sont les suivantes :

  • Recherche depuis des scripts et des hooks. obsidian search "query" et obsidian search:context "query" exécutent des recherches dans le vault depuis n’importe quel script shell, hook ou pipeline d’automatisation. La variante search:context renvoie les lignes correspondantes avec leur contexte environnant, ce qui est utile pour injecter les résultats dans des prompts IA.
  • Automatisation des notes quotidiennes. obsidian daily ouvre ou crée la note quotidienne du jour. Combinée à des scripts shell, cette commande permet de mettre en place des workflows de briefing quotidien automatisés — un hook peut ajouter des résumés générés par IA à la note quotidienne.
  • Création de notes basée sur des modèles. obsidian template list et obsidian template create génèrent des notes à partir de modèles Templater ou natifs, ce qui permet aux agents IA de créer des entrées structurées dans le vault sans écrire directement des fichiers Markdown.
  • Gestion des propriétés. obsidian property set et obsidian property get lisent et écrivent les propriétés du frontmatter, permettant de mettre à jour les métadonnées depuis des scripts sans analyser YAML.
  • Contrôle des plugins. obsidian plugin enable/disable/list gère les plugins par programmation, ce qui est utile pour activer ou désactiver les plugins d’indexation pendant les opérations par lots.
  • Gestion des tâches. obsidian task list/add/complete fournit un accès structuré aux tâches, utile pour les agents IA qui gèrent les éléments de travail dans le vault.

CLI et MCP pour l’accès IA

La CLI et les serveurs MCP remplissent des rôles distincts et sont complémentaires, non concurrents :

Aspect CLI Obsidian Serveur MCP
Appelant Scripts shell, hooks, tâches cron Agents IA (Claude Code, Codex, Cursor)
Protocole Processus POSIX (stdin/stdout/stderr) MCP (JSON-RPC sur STDIO ou HTTP)
Point fort Opérations natives d’Obsidian (modèles, plugins, propriétés) Recherche personnalisée (embeddings, BM25, fusion RRF)
Limitation Pas de recherche vectorielle ni de pipeline d’embeddings Pas d’accès aux opérations internes d’Obsidian
Idéal pour Scripts d’automatisation, pipelines d’ingestion, actions de hooks Requêtes d’agents IA en temps réel pendant les sessions

Recommandation : utilisez la CLI pour l’automatisation de l’ingestion (création de notes, gestion des propriétés, recherche native d’Obsidian) et MCP pour la recherche (recherche hybrid avec embeddings). Un hook UserPromptSubmit peut appeler obsidian search:context comme vérification préalable rapide avant l’exécution de la recherche hybrid plus lourde (les événements de hook à portée d’outil ne peuvent pas injecter de contenu — leur stdout n’atteint jamais le modèle).

Exemple : hook d’ingestion alimenté par la CLI

#!/bin/bash
# Hook: append today's signals to daily note via CLI
DATE=$(date +%Y-%m-%d)
SUMMARY="$1"
obsidian daily  # ensure daily note exists
obsidian file append "Daily Notes/${DATE}.md" "## AI Summary\n${SUMMARY}"

Plugins d’agents Obsidian

Une catégorie grandissante de plugins Obsidian intègre directement des agents de codage IA dans l’interface du vault, offrant une alternative à la configuration externe d’un serveur MCP. Ces plugins exécutent l’agent IA dans la barre latérale d’Obsidian plutôt que de se connecter depuis un outil externe.

Claudian

Claudian intègre Claude Code comme collaborateur IA dans le vault. Le dossier du vault devient le répertoire de travail de Claude, lui donnant toutes les capacités agentiques : lecture et écriture de fichiers, recherche, commandes Bash et workflows en plusieurs étapes.17

Fonctionnalités clés pour l’infrastructure IA : - Prompts sensibles au contexte. Attache automatiquement la note active, prend en charge les mentions de fichier @notename, l’exclusion basée sur les tags et la sélection dans l’éditeur comme contexte. - Prise en charge de la vision. Analysez des images par glisser-déposer, collage ou chemin de fichier — utile pour traiter les captures d’écran et diagrammes enregistrés dans le vault. - Commandes slash. Créez des modèles de prompts réutilisables déclenchés par /command, afin de standardiser les opérations du vault. - Modes d’autorisation. Les modes YOLO (approbation automatique), Safe (approbation de chaque action) et Plan (plan uniquement), avec une liste de blocage de sécurité et un confinement au vault.

Agent Client

Agent Client réunit Claude Code, Codex CLI et Gemini CLI dans une barre latérale Obsidian unifiée via l’Agent Client Protocol (ACP).18

Fonctionnalités clés : - Basculement multi-agent. Discutez avec Claude Code, Codex ou Gemini CLI depuis le même panneau, en changeant d’agent selon vos besoins. - Mentions de notes. Utilisez @notename pour inclure le contenu des notes dans les prompts, comme avec Claudian, mais indépendamment de l’agent. - Exécution shell. Exécutez des commandes de terminal directement dans le chat — scripts de build, commandes git ou toute autre opération de terminal, sans quitter la conversation. - Approbation des actions. Contrôle précis des lectures de fichiers, modifications et exécutions de commandes.

Quand utiliser des plugins d’agents plutôt qu’un MCP externe

Scénario Plugin d’agent MCP externe
Rédaction et modification de notes du vault avec assistance IA Mieux — l’agent voit le contexte de l’éditeur Fonctionne, mais sans visibilité sur l’éditeur
Développement de code sur plusieurs dépôts Limité — circonscrit au vault Mieux — circonscrit au projet, avec accès complet au système de fichiers
Recherche dans un vaste corpus indexé Recherche de base uniquement Pipeline complet de recherche hybrid
Questions-réponses rapides sur le vault pendant la prise de notes Idéal — aucun changement de contexte Nécessite de passer au terminal

Recommandation : utilisez les plugins d’agents pour les workflows centrés sur le vault (rédaction, organisation, synthèse de notes). Utilisez des serveurs MCP externes pour les workflows de développement où l’agent IA a besoin du pipeline complet de recherche et d’un accès aux bases de code en dehors du vault. Les deux approches peuvent coexister — exécutez Claudian dans Obsidian pour le travail sur les notes et Claude Code avec MCP en externe pour le développement.


Cadre de décision : Obsidian vs alternatives

Tous les cas d’usage n’ont pas besoin d’Obsidian. Cette section indique quand Obsidian est le bon socle, quand il est excessif, et quand une autre solution convient mieux.

Arbre de décision

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.

Matrice comparative

Critère Obsidian Notion Apple Notes Système de fichiers brut CLAUDE.md
Local-first Oui Non (cloud) Partiel (iCloud) Oui Oui
Texte brut Oui (markdown) Non (blocks) Non (propriétaire) Oui Oui
Structure en graphe Oui (wiki-links) Partiel (mentions) Non Non Non
Indexable par l’AI Accès direct aux fichiers API requis Export requis Accès direct aux fichiers Déjà dans le contexte
Écosystème de plugins 2 500+ plugins Intégrations Aucun N/A N/A
Utilisable hors ligne Complet Cache en lecture seule Partiel Complet Complet
Passe à l’échelle avec 10K+ notes Oui Oui (avec API) Se dégrade Oui Non (fichier unique)
Coût Gratuit (cœur) 10 $/mois+ Gratuit Gratuit Gratuit

Quand Obsidian est excessif

  • Contexte d’un seul projet. Si l’AI n’a besoin que du contexte de la base de code actuelle, placez-le dans CLAUDE.md, AGENTS.md ou dans une documentation au niveau du projet. Ces fichiers suivent le repo et sont chargés automatiquement.
  • Données structurées. Si le contenu se compose de tableaux, d’enregistrements ou de schémas, utilisez une base de données. Les notes Obsidian sont d’abord pensées pour la prose. Dataview peut interroger les champs frontmatter, mais une vraie base de données gère mieux les requêtes structurées.
  • Recherche temporaire. Si les notes seront supprimées une fois le projet terminé, un dossier de travail contenant des fichiers markdown est plus simple. Ne construisez pas d’infrastructure de retrieval pour du contenu éphémère.

Quand Obsidian est le bon choix

  • Connaissances accumulées sur des mois ou des années. La valeur se compose à mesure que le corpus grandit. Un vault de 200 notes interrogé quotidiennement pendant six mois apporte plus de valeur qu’un vault de 5 000 notes interrogé une seule fois.
  • Plusieurs domaines dans un même corpus. Un vault contenant des notes sur la programmation, l’architecture, la sécurité, le design et des projets personnels bénéficie d’un retrieval inter-domaines qu’un CLAUDE.md propre à un projet ne peut pas fournir.
  • Contenu sensible sur le plan de la confidentialité. Local-first signifie que le pipeline de retrieval n’envoie jamais le contenu à des services externes. Le vault contient tout ce que vous y mettez, y compris du contenu que vous ne téléverseriez pas vers un service cloud.

Modèle mental : trois couches

Le système comporte trois couches qui fonctionnent indépendamment, mais dont les effets se renforcent lorsqu’elles sont combinées. Chaque couche répond à une préoccupation différente et possède son propre mode de défaillance.

┌─────────────────────────────────────────────────────┐
                 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 détermine ce qui entre dans le vault. Sans curation, le vault accumule du bruit : captures d’écran de tweets, articles copiés-collés sans annotation, réflexions inachevées sans contexte. La couche intake est responsable du contrôle qualité au point d’entrée. Un pipeline de notation, une convention de tags ou un processus de revue manuelle : tout mécanisme garantissant que le vault contient du contenu qui mérite d’être retrouvé.

Retrieval rend le vault interrogeable. C’est le moteur : découper les notes en unités de recherche, intégrer les chunks dans un espace vectoriel via des embeddings, indexer pour la recherche par mots-clés et sémantique, fusionner les résultats avec RRF. La couche retrieval transforme un dossier de fichiers en base de connaissances interrogeable. Sans cette couche, le vault reste navigable par parcours manuel et recherche de base, mais il n’est pas accessible programmatiquement aux outils d’AI.

Integration connecte la couche retrieval aux outils d’AI. Un serveur MCP expose le retrieval comme outil appelable. Les hooks injectent automatiquement du contexte. Les skills capturent de nouvelles connaissances dans le vault. La couche integration est l’interface entre la base de connaissances et les agents AI qui la consomment.

Les couches sont découplées par conception. Le pipeline de notation intake ne sait rien des embeddings. Le retriever ne sait rien des règles de routage des signaux. Le serveur MCP ne sait rien de la manière dont les notes ont été créées. Ce découplage signifie que vous pouvez améliorer chaque couche indépendamment. Remplacez le modèle d’embedding sans changer le pipeline intake. Ajoutez une nouvelle capacité MCP sans modifier le retriever. Changez les heuristiques de notation des signaux sans toucher à l’index.


Architecture du coffre pour une consommation par l’IA

Un coffre optimisé pour la récupération par l’IA suit des conventions différentes de celles d’un coffre optimisé pour la navigation personnelle. Cette section couvre la structure des dossiers, le schéma des notes, les conventions de frontmatter et les patterns précis qui améliorent la qualité de la récupération.

Structure des dossiers

Utilisez des préfixes numérotés pour les dossiers de premier niveau afin de créer une hiérarchie d’organisation prévisible. Les numéros ne traduisent aucune priorité : ils regroupent des domaines liés et rendent la structure plus facile à parcourir.

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

Dossiers à indexer : tout ce qui contient de la prose markdown : projets, domaines, ressources, signaux, notes quotidiennes.

Dossiers à exclure de l’indexation : les modèles (ils contiennent des variables de remplacement, pas du contenu), les pièces jointes (fichiers binaires), la configuration Obsidian et tout dossier contenant du contenu sensible que vous ne souhaitez pas inclure dans l’index de récupération.

Le fichier .indexignore

Créez un fichier .indexignore à la racine du coffre pour exclure explicitement des chemins de l’index de récupération. La syntaxe correspond à celle de .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/

L’indexeur lit ce fichier avant l’analyse et ignore entièrement les chemins correspondants. Les fichiers situés dans les chemins exclus ne sont jamais découpés en chunks, jamais transformés en embeddings et n’apparaissent jamais dans les résultats de recherche.

Schéma des notes

Chaque note doit avoir un frontmatter YAML. Le récupérateur utilise les champs de frontmatter pour le filtrage et l’enrichissement du contexte :

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

Champs requis pour la récupération :

  • title — Utilisé dans l’affichage des résultats de recherche et comme contexte de titre pour BM25
  • type — Permet les requêtes filtrées par type (« affichez-moi uniquement les MOCs » ou « uniquement les signaux »)
  • tags — Indexé dans le contexte de titre FTS5 avec un poids de 0,3, ce qui fournit des correspondances par mots-clés même lorsque le corps utilise une terminologie différente

Champs facultatifs mais utiles :

  • domain — Permet les requêtes limitées à un domaine (« rechercher uniquement dans les notes de sécurité »)
  • source — Attribution du contenu capturé ; le récupérateur peut inclure les URL sources dans les résultats
  • status — Permet d’exclure les notes archivées ou brouillons de la recherche active

Conventions de chunking

Le récupérateur découpe les notes aux limites des titres H2 (##). Cela signifie que la structure de vos notes affecte directement la granularité de la récupération :

Adapté à la récupération :

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

Trois sections H2 produisent trois chunks consultables indépendamment. Chaque chunk dispose d’un contexte suffisant pour que l’embedding en capture le sens. Une requête sur la « gestion des tokens expirés » correspond précisément au troisième chunk.

Peu adapté à la récupération :

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

Une longue section sans titres H2 produit un seul gros chunk. L’embedding moyenne tous les sujets de la section. Une requête portant sur n’importe quel sous-sujet correspond à toute la note de la même manière.

Règle pratique : si une section couvre plus d’un concept, divisez-la en sous-sections H2. Le chunker gère le reste.

Ce qu’il ne faut pas mettre dans les notes

Contenu qui dégrade la qualité de la récupération :

  • Des copier-coller bruts d’articles entiers sans annotation. Le récupérateur indexe les mots-clés de l’article original, ce qui dilue votre coffre avec du contenu que vous n’avez pas écrit. Ajoutez plutôt un résumé, extrayez les points clés ou créez un lien vers l’URL source.
  • Des captures d’écran sans description textuelle. Le récupérateur indexe le texte markdown. Une image sans texte alternatif ni description environnante est invisible à la fois pour BM25 et pour la recherche vectorielle.
  • Des chaînes d’identifiants. Clés API, tokens, mots de passe, chaînes de connexion. Même avec le filtrage des identifiants, l’approche la plus sûre consiste à ne jamais coller de secrets dans les notes. Référencez-les plutôt par leur nom (« le token API Cloudflare dans ~/.env »).
  • Du contenu auto-généré sans curation. Si un outil génère une note (transcription de réunion, extraits Readwise, import RSS), relisez-la et annotez-la avant qu’elle n’entre dans le coffre permanent. Les imports automatiques non curés ajoutent du volume sans ajouter de valeur récupérable.

Écosystème de plugins pour les workflows AI

Les plugins Obsidian qui améliorent la qualité du vault pour la récupération AI relèvent de trois catégories : structurels (imposer la cohérence), requêtage (exposer les métadonnées) et synchronisation (maintenir le vault à jour).

Plugins essentiels

Dataview. Interroge votre vault comme une base de données à l’aide des champs de frontmatter. Créez des index dynamiques : « toutes les notes étiquetées security mises à jour au cours des 30 derniers jours » ou « toutes les notes de projet avec le statut active ». Dataview n’aide pas directement la récupération, mais il vous aide à repérer les lacunes dans la couverture de votre vault et à trouver les notes à mettre à jour.

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

Templater. Crée des notes à partir de modèles avec des champs dynamiques. Assurez-vous que chaque nouvelle note commence avec le bon frontmatter en utilisant un modèle qui préremplit les champs created, type et domain. Un frontmatter cohérent améliore le filtrage lors de la récupération.

<%* /* 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. Applique des règles de mise en forme à l’ensemble du vault. Une hiérarchie de titres cohérente (H1 pour le titre, H2 pour les sections, H3 pour les sous-sections) garantit que le chunker produit des résultats prévisibles. Règles Linter importantes pour la récupération :

  • Incrément des titres : imposer des niveaux de titres séquentiels (pas de passage direct de H1 à H3)
  • Titre YAML : correspondre au nom du fichier
  • Espaces en fin de ligne : supprimer (évite les artefacts de tokenisation FTS5)
  • Lignes vides consécutives : limiter à 1 (chunks plus propres)

Intégration Git. Contrôle de version pour votre vault. Suivez les modifications dans le temps, synchronisez entre machines et récupérez après des suppressions accidentelles. Git fournit aussi les données mtime que l’indexeur utilise pour la détection incrémentielle des changements.

Plugins qui aident l’indexation

Smart Connections. Un plugin Obsidian qui fournit une recherche sémantique alimentée par l’AI dans Obsidian lui-même. Smart Connections v4 crée des embeddings locaux par défaut : une fois votre vault indexé, les connexions sémantiques et la recherche fonctionnent entièrement hors ligne, sans appels API.11 v4.5.0 (5 mai 2026) intègre les connexions de pied de page à Smart Connections Core, ce qui permet à chaque installation d’afficher des connexions vers des notes liées dans le pied de page sans ouvrir de panneau latéral. Les versions v4 récentes ont aussi ajouté des vues graph pour les listes de connexions, des emplacements de dock configurables, une meilleure récupération des embeddings de blocs après des indexations interrompues, et « Substrate », un environnement inter-plugins permettant à Smart Connections, Smart Chat et Smart Composer de partager leur état.21 Bien que le système de récupération de ce guide soit externe à Obsidian (il s’exécute comme un pipeline Python), Smart Connections est utile pour explorer les relations sémantiques pendant l’écriture. Les deux systèmes indexent le même contenu, mais répondent à des cas d’usage différents : Smart Connections pour la découverte dans l’éditeur, le retriever externe pour l’intégration d’outils AI via MCP.

Plugins AI-native publiés en avril 2026. Une vague de nouveaux plugins communautaires cible directement le workflow Claude Code / Codex / Gemini-CLI :

Plugin Publié Ce qu’il fait
Cortex 4 avril Agent de vault alimenté par Claude Code : traite le vault comme un espace de travail d’agent, pas seulement comme un espace de stockage de notes
VaultSearch 7 avril Recherche hybrid locale d’abord : BM25 + sémantique + fuzzy (recouvrement direct avec la pile de récupération de ce guide)
LLM Wiki 9 avril Transforme votre vault en base de connaissances interrogeable en privé
Drift 11 avril Visionneuse de diff façon VS Code pour l’édition Obsidian alimentée par l’AI ; positionnée pour les workflows Claude Code
EngramQuest 11 avril Génère des défis de mémoire à partir des notes ; inclut des « AI Skills » pour Claude Code / Gemini CLI / Cursor
Hybrid Search MCP Mars (toujours récent) Serveur MCP + CLI avec BM25 + recherche sémantique : conçu spécialement pour les assistants AI

Considérez cela comme une surface émergente : plusieurs de ces plugins vont probablement se consolider ou être absorbés par Smart Connections / le cœur d’Obsidian au cours des prochains trimestres. Si vous devez en choisir un aujourd’hui, VaultSearch et Hybrid Search MCP sont les plus proches de la philosophie du retriever externe de ce guide.

Note Dataview : Dataview (le plugin de requêtes Obsidian établi de longue date) a publié sa dernière version, 0.5.70, en avril 2025 et est effectivement dormant depuis. Pour les nouveaux travaux, la fonctionnalité intégrée Bases d’Obsidian (1.9+) est le successeur implicite et la voie recommandée.

Metadata Menu. Fournit une édition structurée du frontmatter avec autocomplétion des valeurs de champs. Réduit les fautes de frappe dans les champs type, domain et tags. Des métadonnées cohérentes améliorent la précision du filtrage lors de la récupération.

Plugins qui nuisent à l’indexation

Excalidraw. Stocke les dessins sous forme de JSON intégré dans des fichiers markdown. Le JSON est un markdown syntaxiquement valide, mais produit du bruit lorsqu’il est chunké et intégré. Excluez les fichiers Excalidraw de l’index via .indexignore ou filtrez par extension de fichier.

Kanban. Stocke l’état des tableaux sous forme de markdown spécialement formaté. Le format est conçu pour le rendu Kanban, pas pour la récupération de prose. Le chunker produit des fragments de titres de cartes et de métadonnées qui ne s’intègrent pas bien. Excluez les tableaux Kanban de l’index.

Calendar. Crée des notes quotidiennes avec un contenu minimal (souvent seulement un en-tête de date). Les notes vides ou presque vides produisent des chunks de faible qualité. Si vous utilisez des notes quotidiennes, rédigez-y un contenu substantiel ou excluez le dossier des notes quotidiennes de l’index.

Configuration de plugins importante

Récupération de fichiers → Activée. Protège contre les suppressions accidentelles de notes. Pas directement lié à la récupération, mais crucial pour une base de connaissances dont vous dépendez.

Sauts de ligne stricts → Désactivés. Les sauts de ligne standard du markdown (double saut de ligne pour un paragraphe) produisent des chunks plus propres que le mode strict d’Obsidian (saut de ligne simple pour <br>).

Emplacement par défaut des nouveaux fichiers → Dossier désigné. Acheminez les nouveaux fichiers vers 00-inbox/ afin que les notes non catégorisées ne polluent pas les dossiers de domaine. La boîte de réception est une zone de préparation ; les fichiers sont déplacés vers les dossiers de domaine après triage.

Format wiki-link → Chemin le plus court si possible. Des cibles de lien plus courtes sont plus faciles à résoudre pour le retriever lors de l’indexation de la structure des liens.


Modèles d’embeddings : choix et configuration

Le modèle d’embedding convertit les fragments de texte en vecteurs numériques pour la recherche sémantique. Le choix du modèle détermine la qualité de récupération, la taille de l’index, la vitesse de génération des embeddings et les dépendances à l’exécution. Cette section explique pourquoi potion-base-8M de Model2Vec est le choix par défaut, et dans quels cas choisir des alternatives.

Pourquoi Model2Vec potion-base-8M

Modèle : minishlab/potion-base-8M Paramètres : 7,6 millions Dimensions : 256 Taille : ~30 MB Dépendances : model2vec (numpy uniquement, sans PyTorch) Inférence : CPU uniquement, embeddings de mots statiques (sans couches d’attention)

Model2Vec distille les connaissances d’un sentence transformer en embeddings de tokens statiques. Au lieu d’exécuter des couches d’attention sur l’entrée (comme le font BERT, MiniLM et d’autres modèles transformer), Model2Vec produit des vecteurs par moyenne pondérée d’embeddings de tokens pré-calculés.5 Conséquence pratique : la génération d’embeddings est 50 à 500 fois plus rapide que celle des modèles basés sur transformer, car il n’y a pas de calcul séquentiel.

Sur la page actuelle des résultats Model2Vec, potion-base-8M atteint environ 92 % du score toutes tâches de all-MiniLM-L6-v2 (51,32 contre 55,80), tout en restant plusieurs ordres de grandeur plus rapide.6 L’écart de qualité restant est le compromis associé aux gains de vitesse et de simplicité. Pour de courts fragments Markdown (200 à 400 mots en moyenne dans un vault typique), la différence de qualité est moins marquée que sur des documents plus longs, car les deux modèles convergent vers des représentations similaires pour des textes courts et ciblés.

Configuration

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

Chargement paresseux. Le modèle se charge à la première utilisation, et non au moment de l’import. Importer le module embedder ne coûte rien lorsque le retriever fonctionne en mode de repli BM25 uniquement (par exemple, lorsque le venv d’embedding n’est pas installé).

Environnement virtuel isolé. Le modèle s’exécute dans un venv dédié (par exemple, ~/.claude/venvs/memory/) afin d’éviter les conflits de dépendances avec le reste de la chaîne d’outils. La fonction _activate_venv() ajoute les site-packages du venv à sys.path à l’exécution.

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

Traitement par lots. L’embedder traite les textes par lots de 64 afin d’amortir le surcoût de Model2Vec. L’indexeur envoie les fragments à embed_batch() plutôt que de générer un embedding fragment par fragment.

Quand choisir des alternatives

Modèle Dim Taille Vitesse Qualité (MTEB) Idéal pour
potion-base-8M 256 30 MB 500x 51,32 Défaut : local, rapide, sans GPU
potion-base-32M 256 120 MB 400x 52,83 Qualité supérieure, toujours statique
potion-retrieval-32M 256 120 MB 400x 35,06 (retrieval) Statique optimisé pour la récupération
potion-multilingual-128M 256 ~500 MB 300x Vaults multilingues (101 langues)
all-MiniLM-L6-v2 384 80 MB 1x 55,80 Qualité supérieure, toujours local
nomic-embed-text-v1.5 768 270 MB 0,5x 62,28 Meilleure qualité locale
text-embedding-3-small 1536 API N/A 62,30 Basé sur API, qualité maximale

Choisissez potion-base-32M si vous voulez une meilleure qualité que potion-base-8M sans quitter la famille des embeddings statiques. Il utilise un vocabulaire plus large distillé depuis baai/bge-base-en-v1.5, avec un score toutes tâches de 52,83 (environ 3 % de plus que potion-base-8M), tout en conservant la même sortie à 256 dimensions et une dépendance à numpy uniquement.8 Le fichier de modèle 4 fois plus volumineux augmente l’utilisation mémoire, mais la vitesse de génération des embeddings reste plusieurs ordres de grandeur supérieure à celle des modèles transformer.

Choisissez potion-retrieval-32M si votre cas d’usage principal est la récupération (ce qui est le cas de la recherche dans un vault). Cette variante est fine-tunée à partir de potion-base-32M spécifiquement pour les tâches de récupération, avec un score de 35,06 dans le tableau de benchmark de récupération de Model2Vec contre 32,67 pour potion-base-32M.8 Le compromis est qu’elle est optimisée pour la récupération plutôt que pour une qualité d’embedding généraliste.

Choisissez potion-multilingual-128M si votre vault contient des notes dans plusieurs langues. Publié en mai 2025, ce modèle couvrant 101 langues est le modèle d’embedding statique le plus performant pour les tâches multilingues, générant des embeddings pour n’importe quel texte dans n’importe quelle langue tout en conservant la même dépendance à numpy uniquement que les autres modèles potion.12 Le fichier de modèle plus volumineux (~500 MB) est le compromis nécessaire pour la capacité interlingue. Utilisez-le si vous avez des notes en japonais, chinois, allemand ou dans d’autres langues non anglaises aux côtés de contenu en anglais.

Choisissez all-MiniLM-L6-v2 si la qualité de récupération compte davantage que la vitesse et que PyTorch est installé. Les vecteurs à 384 dimensions augmentent la taille de la base SQLite d’environ 50 % par rapport aux vecteurs à 256 dimensions. Sur du matériel M-series, la vitesse de génération des embeddings passe de moins de 1 minute à environ 10 minutes pour une réindexation complète de 15 000 fichiers.

Choisissez nomic-embed-text-v1.5 si vous avez besoin de la meilleure qualité de récupération locale possible et acceptez une indexation plus lente. Les vecteurs à 768 dimensions triplent approximativement la taille de la base de données. Nécessite PyTorch et un CPU moderne ou GPU.

Choisissez text-embedding-3-small si la latence réseau et la confidentialité sont des compromis acceptables. Le API produit les embeddings de meilleure qualité, mais introduit une dépendance cloud, un coût par token (0,02 $/million de tokens) et envoie votre contenu aux serveurs d’OpenAI.

Restez avec potion-base-8M dans tous les autres cas. L’avantage de vitesse est essentiel pour l’indexation itérative (réindexer pendant le développement), la dépendance à numpy uniquement évite la complexité d’installation de PyTorch, et les vecteurs à 256 dimensions gardent la base de données compacte.

Quantification et réduction de dimensionnalité

Model2Vec v0.5.0+ prend en charge le chargement de modèles avec une précision et des dimensions réduites.8 C’est utile pour un déploiement sur du matériel contraint ou pour réduire la taille de la base de données sans changer de modèle :

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)

Les modèles quantifiés conservent une qualité de récupération presque identique pour une fraction de l’empreinte mémoire. La réduction de dimensionnalité suit une troncature de style Matryoshka : les N premières dimensions portent le plus d’information. Passer de 256 à 128 dimensions divise par deux le stockage des vecteurs avec une perte de qualité minimale pour la récupération de textes courts.

Model2Vec v0.8.x met à jour les mécanismes internes de tokenizer/persistance, déprécie la prise en charge de Python 3.9 et actualise les résultats publiés vers les tableaux MTEB plus récents. Épinglez ou testez model2vec avant de mettre à niveau un indexeur de production, car les mises à jour de bibliothèque peuvent modifier les chemins de chargement des modèles même lorsque le nom du modèle d’embedding reste identique.10

Fine-tuning pour des embeddings spécifiques au vault

Model2Vec v0.4.0+ prend en charge l’entraînement de modèles de classification personnalisés au-dessus d’embeddings statiques, v0.7.0 ajoute la quantification du vocabulaire et le pooling configurable pour la distillation, et v0.8.x refactorise le comportement du tokenizer et de la persistance.10 C’est pertinent pour les vaults contenant un vocabulaire spécialisé (notes médicales, références juridiques, jargon propre à un domaine), lorsque les modèles potion par défaut risquent de ne pas capturer les nuances sémantiques :

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

Pour la plupart des vaults, potion-base-8M par défaut produit une qualité de récupération suffisante. Le fine-tuning ne vaut la peine que lorsque la récupération manque systématiquement des connexions propres au domaine qu’un modèle généraliste ne peut pas capturer.

Suivi du hash du modèle

L’indexeur stocke un hash dérivé du nom du modèle et de la taille du vocabulaire. Si vous changez de modèle d’embedding, l’indexeur détecte l’incompatibilité lors de la prochaine exécution incrémentale et déclenche automatiquement une réindexation complète.

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]

Cela évite de mélanger des vecteurs issus de modèles différents dans la même base de données, ce qui produirait des scores de cosine similarity dépourvus de sens.

Modes de défaillance

Échec du téléchargement du modèle. La première exécution télécharge le modèle depuis Hugging Face. Si le téléchargement échoue (problème réseau, pare-feu d’entreprise), le retriever repasse en mode BM25 uniquement. Le modèle est mis en cache localement après le premier téléchargement.

Incompatibilité de dimensions. Si vous changez de modèle sans vider la base de données, les vecteurs stockés ont une dimension différente des nouveaux embeddings. L’indexeur le détecte via le hash du modèle et déclenche une réindexation complète. Si la vérification du hash échoue (modèle personnalisé sans hash correct), sqlite-vec générera une erreur sur les requêtes KNN avec dimensions incompatibles.

Pression mémoire sur les grands vaults. Générer les embeddings de plus de 50 000 fragments en un seul lot peut consommer beaucoup de mémoire. L’indexeur traite les données par lots de 64 afin de limiter le pic d’utilisation mémoire. Si la mémoire reste problématique, réduisez la taille des lots.


Recherche plein texte avec FTS5

L’extension FTS5 de SQLite fournit une recherche plein texte avec classement BM25. FTS5 est le composant de recherche par mots-clés du pipeline de récupération hybride. Cette section couvre la configuration de FTS5, les cas où BM25 excelle et ses modes d’échec spécifiques.

Table virtuelle FTS5

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

Mode content-sync. Le paramètre content=chunks indique à FTS5 de référencer directement la table chunks plutôt que de stocker une copie du texte. Cela réduit de moitié les besoins de stockage, mais signifie que FTS5 doit être synchronisé manuellement lorsque des chunks sont insérés, mis à jour ou supprimés.

Colonnes. Trois colonnes sont indexées : - chunk_text — Le contenu principal de chaque chunk (poids BM25 : 1.0) - section — Le texte du titre H2 (poids BM25 : 0.5) - heading_context — Titre de la note, tags et métadonnées (poids BM25 : 0.3)

Classement BM25

BM25 classe les documents selon la fréquence des termes, la fréquence inverse des documents et la normalisation par longueur de document. La fonction auxiliaire bm25() de FTS5 accepte des poids par colonne :

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;

Les poids de colonnes (1.0, 0.5, 0.3) signifient : - Une correspondance de mot-clé dans chunk_text contribue le plus au score - Une correspondance dans section (titre) contribue moitié moins - Une correspondance dans heading_context (titre, tags) contribue à hauteur de 30 %

Ces poids sont ajustables. Si votre coffre contient des titres descriptifs qui prédisent fortement la qualité du contenu, augmentez le poids de section. Si vos tags sont complets et précis, augmentez le poids de heading_context.

Quand BM25 gagne

BM25 excelle avec les requêtes contenant des identifiants exacts :

  • Noms de fonctions : _rrf_fuse, embed_batch, get_stale_files
  • Indicateurs CLI : --incremental, --vault, --model
  • Clés de configuration : bm25_weight, max_tokens, batch_size
  • Messages d’erreur : SQLITE_LOCKED, ConnectionRefusedError
  • Termes techniques spécifiques : PostToolUse, PreToolUse, AGENTS.md

Pour ces requêtes, BM25 trouve immédiatement la correspondance exacte. La recherche vectorielle renverrait du contenu sémantiquement lié, mais pourrait classer la correspondance exacte plus bas qu’une discussion conceptuelle.

Quand BM25 échoue

BM25 échoue avec les requêtes qui utilisent une terminologie différente de celle du contenu stocké :

  • Requête : « how to handle authentication failures » → Le coffre contient des notes sur « login error recovery » et « session expiration handling ». BM25 ne trouve pas de correspondance, car les mots-clés diffèrent.
  • Requête : « what is the best way to manage state » → Le coffre contient des notes sur « Redux store patterns » et « context providers ». BM25 passe à côté, car « state management » est exprimé à travers des noms de technologies spécifiques.

BM25 échoue aussi avec les collisions de mots-clés à grande échelle. Dans un coffre de 15 000 fichiers, une recherche sur « configuration » correspond à des centaines de notes, car presque chaque note de projet mentionne la configuration. Les résultats sont techniquement corrects, mais inutilisables en pratique — le classement ne peut pas déterminer quelle note sur la « configuration » est pertinente pour la requête actuelle.

Tokenizer FTS5

FTS5 utilise par défaut le tokenizer unicode61, qui gère le texte ASCII et Unicode. Pour les coffres contenant beaucoup de contenu CJK (chinois, japonais, coréen), envisagez le tokenizer trigram :

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

Le tokenizer par défaut unicode61 segmente le texte aux limites des mots, ce qui fonctionne mal pour les langues sans espaces entre les mots. Le tokenizer trigram segmente tous les trois caractères, ce qui permet la correspondance de sous-chaînes au prix d’un index plus volumineux (environ 3x plus grand).

Maintenance

FTS5 nécessite une synchronisation explicite lorsque la table chunks sous-jacente change :

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

La commande rebuild reconstruit l’index FTS5 à partir de la table de contenu. Exécutez-la après des insertions en masse (réindexation complète), mais pas après des mises à jour incrémentales individuelles — pour celles-ci, utilisez INSERT INTO chunks_fts(rowid, chunk_text, section, heading_context) afin de synchroniser chaque ligne.


Recherche vectorielle avec sqlite-vec

L’extension sqlite-vec apporte la recherche vectorielle KNN (K-Nearest Neighbors) à SQLite. Cette section couvre la configuration de sqlite-vec, le pipeline d’embeddings depuis la note jusqu’au vecteur consultable, ainsi que les schémas de requête spécifiques.

Table virtuelle sqlite-vec

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

Le module vec0 stocke des vecteurs flottants à 256 dimensions sous forme de données binaires compactées. La colonne id correspond 1:1 à la table chunks, ce qui permet les jointures entre les résultats vectoriels et les métadonnées des chunks.

Pipeline d’embeddings

Le pipeline va de la note au vecteur consultable :

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

Sérialisation des vecteurs

Le module struct de Python sérialise les vecteurs flottants pour le stockage sqlite-vec :

import struct

def _serialize_vector(vec):
    """Pack float list into binary for sqlite-vec."""
    return struct.pack(f"{len(vec)}f", *vec)

def _deserialize_vector(blob, dim=256):
    """Unpack binary blob to float list."""
    return list(struct.unpack(f"{dim}f", blob))

Requête KNN

Une requête de recherche vectorielle intègre la requête d’entrée, puis trouve les K chunks les plus proches par distance cosinus :

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

L’opérateur MATCH dans sqlite-vec effectue une recherche approximative du plus proche voisin. Le paramètre k contrôle le nombre de résultats à renvoyer. La colonne distance contient la distance cosinus (0 = identique, 2 = opposé).

Pagination KNN avec contraintes de distance

Depuis sqlite-vec v0.1.7, les requêtes KNN prennent en charge les contraintes WHERE distance < ?, ce qui permet une pagination par curseur dans de grands ensembles de résultats sans rescanner les pages précédentes.14 Les versions stables ultérieures v0.1.8 et v0.1.9 sont des versions de packaging et de correction de bugs DELETE plutôt que de nouveaux modèles de requête ; v0.1.7 reste donc la frontière fonctionnelle pour ce schéma de pagination.23

À l’horizon, la ligne v0.1.10-alpha (31 mars – 18 mai 2026) est la première à faire évoluer sqlite-vec au-delà du KNN par force brute : elle introduit des types d’index approximative-nearest-neighbor — rescore, un index expérimental ivf (inverted-file) qui n’est pas activé par défaut, ainsi qu’un index DiskANN sur disque pour les coffres trop volumineux pour garder les vecteurs résidents en mémoire.23 Ces évolutions changeraient la trajectoire de passage à l’échelle pour les très grands coffres, mais la ligne 0.1.10 reste encore en préversion (alpha) — considérez l’indexation ANN comme expérimentale et continuez à construire sur le chemin KNN par force brute stable de v0.1.9 pour les coffres de production jusqu’à la publication d’une version stable 0.1.10.

def _paginated_vector_search(self, query_vec, page_size=20, max_distance=None):
    """Paginate through KNN results using distance constraints."""
    packed = _serialize_vector(query_vec)
    constraint = f"AND distance < {max_distance}" if max_distance else ""

    results = self.db.execute(f"""
        SELECT cv.id, cv.distance, c.file_path, c.chunk_text
        FROM chunk_vecs cv
        JOIN chunks c ON cv.id = c.id
        WHERE embedding MATCH ?
            AND k = ?
            {constraint}
        ORDER BY distance
    """, [packed, page_size]).fetchall()

    # Use last result's distance as cursor for next page
    next_cursor = results[-1][1] if results else None
    return results, next_cursor

Cela remplace le schéma précédent qui consistait à récupérer un grand k puis à découper les résultats dans Python, ce qui réduit l’utilisation mémoire pour les requêtes exploratoires sur de grands coffres.

Prise en charge de DELETE dans les tables vec0

sqlite-vec v0.1.7 a ajouté la prise en charge native de DELETE pour les tables virtuelles vec0, et v0.1.9 a corrigé un chemin d’erreur DELETE impliquant des colonnes de texte de métadonnées de plus de 12 caractères.1423 Auparavant, supprimer des vecteurs exigeait de supprimer puis de recréer la table. Désormais, le chemin de suppression de fichiers de l’indexeur peut supprimer les vecteurs directement :

# Before v0.1.7: required workaround (drop + recreate, or mark as inactive)
# After v0.1.7: direct DELETE works
db.execute("DELETE FROM chunk_vecs WHERE id = ?", [chunk_id])

Cela simplifie la réindexation incrémentale lorsque des notes sont supprimées ou déplacées. L’indexeur n’a plus besoin de maintenir une table fantôme « active IDs » ni de reconstruire par lots.

Quand la recherche vectorielle l’emporte

La recherche vectorielle excelle pour les requêtes où le concept compte davantage que les mots exacts :

  • Requête : “how to handle authentication failures” → Trouve des notes sur “login error recovery” (même espace sémantique, mots-clés différents)
  • Requête : “what patterns exist for caching” → Trouve des notes sur “memoization,” “Redis TTL strategies,” et “HTTP cache headers” (concepts liés, terminologie variée)
  • Requête : “approaches to testing asynchronous code” → Trouve des notes sur “pytest-asyncio fixtures,” “mock event loops,” et “async test patterns” (même concept exprimé par des détails d’implémentation)

Quand la recherche vectorielle échoue

La recherche vectorielle gère mal les identifiants exacts :

  • Requête : _rrf_fuse → Renvoie des notes sur “fusion algorithms” et “rank merging”, mais peut classer la définition réelle de la fonction plus bas que les discussions conceptuelles
  • Requête : PostToolUse → Renvoie des notes sur “tool lifecycle hooks” et “post-execution handlers” plutôt que le nom précis du hook

La recherche vectorielle gère aussi mal les données structurées. Les fichiers de configuration JSON, les blocs YAML et les extraits de code produisent des embeddings qui capturent des motifs structurels plutôt que le sens sémantique. Un fichier JSON avec "review": true produit un embedding différent d’une discussion en prose sur la revue de code.

Dégradation progressive

Si sqlite-vec ne parvient pas à se charger (extension manquante, plateforme incompatible, bibliothèque corrompue), le retriever bascule vers une recherche BM25 seule :

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

Le retriever vérifie vec_available avant de tenter des requêtes vectorielles. Lorsqu’elle est désactivée, toutes les recherches utilisent uniquement BM25, et l’étape de fusion RRF est ignorée.


Reciprocal Rank Fusion (RRF)

RRF fusionne deux listes classées sans nécessiter de calibration des scores. Cette section couvre l’algorithme, une trace de requête détaillée, le réglage du paramètre k, et pourquoi RRF est choisi plutôt que d’autres approches. Pour un calculateur interactif avec rangs modifiables, préréglages de scénarios et explorateur visuel d’architecture, consultez le deep dive sur le hybrid retriever.

L’algorithme

RRF attribue à chaque document un score fondé uniquement sur sa position de rang dans chaque liste :

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

Où : - k est une constante de lissage (60, d’après Cormack et al.3) - rank_i est le rang du document, indexé à partir de 1, dans la liste de résultats i - weight_i est un multiplicateur facultatif propre à chaque liste (1.0 par défaut)

Les documents bien classés dans plusieurs listes reçoivent des scores fusionnés plus élevés. Les documents qui n’apparaissent que dans une seule liste reçoivent un score provenant de cette seule source.

Pourquoi RRF plutôt que d’autres approches

La combinaison linéaire pondérée nécessite de calibrer les scores BM25 par rapport aux distances cosinus. Les scores BM25 ne sont pas bornés et varient avec la taille du corpus. Les distances cosinus sont bornées [0, 2]. Les combiner nécessite une normalisation, et les paramètres de normalisation dépendent du jeu de données. RRF n’utilise que les positions de rang, qui sont toujours des entiers commençant à 1, quelle que soit la méthode de scoring.

Les modèles de fusion appris nécessitent des données d’entraînement annotées — des paires requête-document avec un jugement de pertinence. Pour une base de connaissances personnelle, ces données d’entraînement n’existent pas. Vous devriez évaluer manuellement des centaines de paires requête-document pour entraîner un modèle utile. RRF fonctionne sans aucune donnée d’entraînement.

Les méthodes de vote Condorcet (Borda count, méthode de Schulze) sont élégantes sur le plan théorique, mais plus complexes à implémenter et à régler. L’article original sur RRF a montré que RRF surpasse les méthodes Condorcet sur les données d’évaluation TREC.3

Fusion en pratique

Requête : « how does the review aggregator handle disagreements »

BM25 classe review-aggregator.py en position 3 (correspondances exactes de mots-clés sur « review », « aggregator », « disagreements »), mais place deux fichiers de configuration plus haut (ils correspondent à « review » de façon plus marquée). La recherche vectorielle classe le même chunk en position 1 (correspondance sémantique sur la résolution de conflits). Après fusion RRF :

Chunk BM25 Vec Score fusionné
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

Les chunks bien classés dans les deux listes remontent en tête. Les chunks qui n’apparaissent que dans une seule liste obtiennent un score issu d’une seule source et passent sous les résultats classés dans les deux listes. La logique réelle de résolution des désaccords l’emporte parce que les deux méthodes l’ont trouvée — BM25 via les mots-clés, la recherche vectorielle via la sémantique.

Pour la trace complète pas à pas avec le calcul RRF rang par rang, essayez différentes valeurs de k dans le calculateur RRF interactif.

Implémentation

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

Régler k

La constante k contrôle le poids accordé aux résultats les mieux classés par rapport aux résultats moins bien classés :

  • k plus faible (par exemple, 10) : les résultats les mieux classés dominent. Le rang 1 marque 1/11 = 0.091, le rang 10 marque 1/20 = 0.050 (différence de 1,8x). Utile lorsque vous faites confiance aux rankers individuels pour placer le bon résultat en tête.
  • k par défaut (60) : équilibré. Le rang 1 marque 1/61 = 0.0164, le rang 10 marque 1/70 = 0.0143 (différence de 1,15x). Les écarts de rang sont comprimés, ce qui donne plus de poids au fait d’apparaître dans plusieurs listes.
  • k plus élevé (par exemple, 200) : apparaître dans les deux listes compte beaucoup plus que la position de rang. Le rang 1 marque 1/201, le rang 10 marque 1/210 — presque identique. À utiliser lorsque les rankers individuels produisent des classements bruités, mais que l’accord entre listes est fiable.

Commencez avec k=60. L’article original sur RRF a montré que cette valeur est robuste sur divers jeux de données TREC. Ne l’ajustez qu’après avoir mesuré les cas d’échec sur votre propre distribution de requêtes.

Départage des égalités

Lorsque deux chunks ont des scores RRF identiques (rare, mais possible avec le même rang dans une liste et aucune apparition dans l’autre), départagez-les ainsi :

  1. Préférez les chunks qui apparaissent dans les deux listes à ceux qui n’apparaissent que dans une seule
  2. Parmi les chunks présents dans les deux listes, préférez celui dont le rang combiné est le plus faible
  3. Parmi les chunks présents dans une seule liste, préférez celui dont le rang est le plus faible dans cette liste

Le pipeline complet de retrieval

Cette section suit une requête de l’entrée à la sortie dans tout le pipeline : recherche BM25, recherche vectorielle, fusion RRF, troncature du budget de tokens et assemblage du contexte.

Flux de bout en bout

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

Latence totale : ~23ms pour une base de données de 49 746 chunks sur du matériel Apple M3 Pro.

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

Troncature du budget de tokens

Le paramètre max_tokens empêche le retriever de renvoyer plus de contexte que l’outil d’IA ne peut en utiliser. L’estimation repose sur 4 caractères par token (une approximation raisonnable pour de la prose en anglais). Les résultats sont tronqués de façon gloutonne : les résultats sont ajoutés dans l’ordre du classement jusqu’à épuisement du budget.

C’est une stratégie conservatrice. Une approche plus sophistiquée tiendrait compte des scores de qualité par résultat et préférerait les résultats plus courts et de meilleure qualité aux résultats plus longs et de moindre qualité. L’approche gloutonne est plus simple et fonctionne bien en pratique, car le classement RRF ordonne déjà les résultats par pertinence.

Schéma de base de données (complet)

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

Chemin de dégradation progressive

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

Le retriever vérifie les capacités à l’initialisation et adapte sa stratégie de requête. Un composant manquant dégrade la qualité, mais ne provoque pas d’erreurs. Le seul échec bloquant est l’absence du fichier de base de données.

Statistiques de production

Mesuré sur un vault de 16 894 fichiers, 49 746 chunks, une base SQLite de 83 MB, Apple M3 Pro :

Métrique Valeur
Nombre total de fichiers 16 894
Nombre total de chunks 49 746
Taille de la base de données 83 MB
Latence de requête BM25 (p50) 12ms
Latence de requête vectorielle (p50) 8ms
Latence de fusion RRF 3ms
Latence de recherche de bout en bout (p50) 23ms
Durée de réindexation complète ~4 minutes
Durée de réindexation incrémentale <10 secondes
Modèle d’embedding potion-base-8M (256-dim)
Pool de candidats BM25 30
Pool de candidats vectoriels 30
Limite de résultats par défaut 10
Budget de tokens par défaut 4 000 tokens

Hachage du contenu et détection des changements

L’indexeur doit savoir quels fichiers ont changé depuis la dernière exécution de l’index. Cette section couvre le mécanisme de détection des changements et la stratégie de hachage.

Comparaison de l’heure de modification des fichiers

L’indexeur stocke mtime_ns (heure de modification du fichier en nanosecondes) pour chaque chunk dans la table chunks. Lors d’une exécution incrémentale, l’indexeur :

  1. Analyse le vault pour trouver tous les fichiers .md dans les dossiers autorisés
  2. Lit le mtime_ns de chaque fichier depuis le système de fichiers
  3. Compare cette valeur au mtime_ns stocké dans la base de données
  4. Identifie trois catégories :
  5. Nouveaux fichiers : le chemin existe dans le système de fichiers, mais pas dans la base de données
  6. Fichiers modifiés : le chemin existe dans les deux, mais mtime_ns diffère
  7. Fichiers supprimés : le chemin existe dans la base de données, mais pas dans le système de fichiers
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)

Pourquoi mtime, et non un hash du contenu

Le hachage du contenu (SHA-256 du contenu des fichiers) serait plus fiable que la comparaison de mtime : il détecterait les cas où un fichier a été touché sans être modifié (par exemple, un git checkout qui restaure le mtime d’origine). Toutefois, le hachage exige de lire chaque fichier à chaque exécution incrémentale. Pour 16 894 fichiers, la lecture du contenu des fichiers prend 2 à 3 secondes. La lecture des mtimes depuis le système de fichiers prend <100ms.

Le compromis : la comparaison de mtime déclenche parfois une réindexation inutile de fichiers inchangés (faux positifs), mais ne manque jamais les changements réels. Les faux positifs coûtent quelques appels d’embedding supplémentaires par exécution. L’écart de vitesse (100ms contre 3 secondes) fait de mtime le choix pragmatique pour un système qui s’exécute à chaque interaction avec l’IA.

Gestion des suppressions

Lorsqu’un fichier est supprimé du vault, l’indexeur retire tous ses chunks de la base de données :

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

L’instruction DELETE FROM chunk_vecs fonctionne nativement depuis sqlite-vec v0.1.7, avec une correction de bug en v0.1.9 pour les opérations DELETE sur les tables vec0 avec des colonnes de texte de métadonnées plus longues.1423 Les versions antérieures nécessitaient des contournements (supprimer et recréer la table virtuelle, ou maintenir un ensemble externe d’« ID actifs »). Si vous utilisez une version antérieure à 0.1.9, mettez-la à niveau avant de vous appuyer sur des suppressions directes dans des schémas riches en métadonnées.

Les tables FTS5 à synchronisation de contenu nécessitent une suppression explicite via INSERT INTO chunks_fts(chunks_fts, rowid, ...) VALUES('delete', ?, ...) pour chaque ligne retirée. L’indexeur gère cela dans le cadre du processus de suppression de fichier.


Réindexation incrémentale vs complète

L’indexeur prend en charge deux modes : incrémental (rapide, usage quotidien) et complet (lent, occasionnel). Cette section explique quand utiliser chacun d’eux, les garanties d’idempotence et la récupération après corruption.

Réindexation incrémentale

Quand l’utiliser : indexation quotidienne après modification de notes. C’est le mode par défaut.

Ce qu’elle fait : 1. Analyse le vault pour détecter les changements de fichiers (comparaison des mtimes) 2. Supprime les chunks des fichiers supprimés 3. Redécoupe en chunks et regénère les embeddings des fichiers modifiés 4. Insère de nouveaux chunks pour les nouveaux fichiers 5. Synchronise l’index FTS5

Durée typique : <10 secondes pour les modifications d’une journée dans un vault de 16 000 fichiers.

python index_vault.py --incremental

Réindexation complète

Quand l’utiliser : - Après avoir changé de modèle d’embedding (incompatibilité de hash de modèle détectée) - Après une migration de schéma (nouvelles colonnes, index modifiés) - Après une corruption de la base de données (échec du contrôle d’intégrité) - Quand l’indexation incrémentale produit des résultats inattendus

Ce qu’elle fait : 1. Supprime toutes les données existantes (chunks, vecteurs, entrées FTS5) 2. Analyse tout le vault 3. Découpe tous les fichiers en chunks 4. Génère les embeddings de tous les chunks 5. Reconstruit l’index FTS5 à partir de zéro

Durée typique : ~4 minutes pour 16 894 fichiers sur Apple M3 Pro.

python index_vault.py --full

Idempotence

Les deux modes sont idempotents : exécuter deux fois la même commande produit le même résultat. L’indexeur supprime les chunks existants d’un fichier avant d’en insérer de nouveaux ; ainsi, relancer l’indexation incrémentale sur une base de données déjà à jour ne produit aucun changement. Relancer l’indexation complète produit une base de données identique.

Récupération après corruption

Si la base de données SQLite est corrompue (coupure de courant pendant l’écriture, erreur disque, processus interrompu en pleine transaction) :

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

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

La source de vérité reste toujours les fichiers du vault, pas la base de données. La base de données est un artefact dérivé qui peut être reconstruit à tout moment. C’est une propriété de conception essentielle : vous n’avez jamais besoin de sauvegarder la base de données.

Le flag --incremental

Lorsque l’indexeur s’exécute avec --incremental :

  1. Vérification du hash de modèle. Compare le hash de modèle stocké au modèle actuel. S’ils diffèrent, bascule automatiquement en mode de réindexation complète et avertit l’utilisateur.
  2. Analyse des fichiers. Parcourt les dossiers autorisés, collecte les chemins de fichiers et les mtimes.
  3. Détection des changements. Compare avec les données stockées.
  4. Traitement par lots. Redécoupe en chunks et regénère les embeddings des fichiers modifiés par lots de 64.
  5. Rapport de progression. Affiche le nombre de fichiers traités et le temps écoulé.
  6. Arrêt contrôlé. Gère SIGINT en terminant le fichier en cours avant de s’arrêter.

Filtrage des identifiants et limites de données

Les notes personnelles contiennent des secrets : clés API, bearer tokens, chaînes de connexion à des bases de données, clés privées collées pendant des sessions de débogage. Le filtre d’identifiants empêche ces éléments d’entrer dans l’index de retrieval.

Le problème

Une note sur le débogage d’une intégration OAuth peut contenir :

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

Sans filtrage, le JWT comme la clé API seraient découpés en chunks, transformés en embeddings et stockés dans la base de données. Une recherche sur « authentication » renverrait le chunk contenant de vrais secrets. Pire encore, si le retriever transmet les résultats à un outil d’IA via MCP, les secrets apparaissent dans la fenêtre de contexte de l’IA et potentiellement dans les journaux de l’outil.

Filtrage basé sur des motifs

Le filtre d’identifiants s’exécute sur chaque chunk avant stockage, en recherchant 25 motifs propres à des fournisseurs ainsi que des motifs génériques :

Motifs propres aux fournisseurs :

Pattern Exemple Regex
Clé API OpenAI sk-... sk-[a-zA-Z0-9_-]{20,}
Clé API Anthropic sk-ant-api03-... sk-ant-api\d{2}-[a-zA-Z0-9_-]{20,}
PAT GitHub ghp_... gh[ps]_[a-zA-Z0-9]{36,}
AWS Access Key AKIA... AKIA[0-9A-Z]{16}
Clé Stripe sk_live_... [sr]k_(live\|test)_[a-zA-Z0-9]{24,}
Token Cloudflare ... Différents motifs

Motifs génériques :

Pattern Détection
Tokens JWT eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+
Bearer tokens Bearer\s+[a-zA-Z0-9_\-\.]+
Clés privées -----BEGIN (RSA\|EC\|OPENSSH) PRIVATE KEY-----
base64 à forte entropie Chaînes avec >4,5 bits/caractère d’entropie, 40+ caractères
Affectations de mot de passe password\s*[:=]\s*["'][^"']+["']

Implémentation du filtre

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

Choix de conception clés :

  1. Filtrer avant l’embedding. Le texte nettoyé est celui qui reçoit un embedding. La représentation vectorielle n’encode jamais les motifs d’identifiants. Une requête sur « clé API » renvoie des notes qui parlent de la gestion des clés API, pas des notes contenant de vraies clés.

  2. Remplacer, pas supprimer. Le token [REDACTED:pattern-name] préserve le contexte sémantique du texte environnant. L’embedding capture qu’« un élément ressemblant à un identifiant se trouvait ici », sans encoder l’identifiant lui-même.

  3. Journaliser les motifs, pas les valeurs. Le filtre journalise les motifs qui ont correspondu (par exemple, « Scrubbed 2 credential(s) from oauth-debug.md [jwt, bearer-token] »), mais jamais la valeur de l’identifiant.

Exclusion basée sur le chemin

Le fichier .indexignore fournit une exclusion grossière par chemin. Le filtre d’identifiants fournit un nettoyage fin à l’intérieur des fichiers indexés. Les deux sont nécessaires :

  • .indexignore pour les dossiers entiers dont vous savez qu’ils contiennent du contenu sensible (notes de santé, dossiers financiers, documents de carrière)
  • Filtre d’identifiants pour les secrets intégrés accidentellement dans du contenu qui peut par ailleurs être indexé

Classification des données

Pour les vaults contenant des contenus variés, envisagez de classer les notes selon leur sensibilité :

Niveau Exemples Indexer ? Filtrer ?
Public Brouillons de blog, notes techniques Oui Oui
Interne Plans de projet, décisions d’architecture Oui Oui
Sensible Données salariales, dossiers de santé Non (.indexignore) N/A
Restreint Identifiants, clés privées Non (.indexignore) N/A

Architecture du serveur MCP

Les serveurs Model Context Protocol (MCP) exposent le récupérateur comme un outil que les agents IA peuvent appeler. Cette section couvre la conception du serveur, la surface de capacités et les limites d’autorisation.

Choix du protocole : STDIO vs HTTP

MCP prend en charge deux modes de transport :

STDIO — L’outil IA lance le serveur MCP comme processus enfant et communique via stdin/stdout. Il s’agit du mode standard pour les outils locaux. Claude Code, Codex CLI et Cursor prennent tous en charge les serveurs MCP STDIO.

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

HTTP — Le serveur MCP s’exécute comme un service HTTP autonome. Utile pour l’accès distant, les configurations multi-clients ou les configurations d’équipe où le vault se trouve sur un serveur partagé.

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

Recommandation : utilisez STDIO pour les vaults personnels. C’est plus simple, plus sûr (aucune exposition réseau) et le cycle de vie du serveur est géré par l’outil IA. N’utilisez HTTP que lorsque plusieurs outils ou plusieurs machines nécessitent un accès simultané au même vault.

Évolution de la spécification MCP. La spécification MCP de juin 2025 a ajouté l’autorisation OAuth 2.1, les sorties d’outils structurées (schémas de retour typés) et l’élicitation (invites utilisateur initiées par le serveur). La version de novembre 2025 a livré Streamable HTTP comme mode de transport de première classe, la découverte d’URL .well-known pour la consultation automatique des capacités du serveur, des annotations d’outils structurées qui indiquent si un outil est en lecture seule ou modificateur, ainsi qu’un système de normalisation par niveaux SDK.79 La prochaine révision est désormais concrète : la spécification du 28-07-2026 est entrée en Release Candidate le 21 mai 2026 — la plus grande révision de MCP depuis son lancement. Ses principaux changements sont un cœur de protocole sans état (la poignée de main initialize et l’en-tête Mcp-Session-Id sont supprimés, de sorte que les serveurs ne suivent plus l’état de session par connexion), les Apps MCP (les serveurs peuvent renvoyer des HTML rendus côté serveur, affichés dans des iframes client isolées), le passage des Tasks du cœur expérimental à une extension officielle (tasks/get, tasks/update, tasks/cancel pour les opérations de longue durée), le renforcement de l’autorisation OAuth 2.0 / OIDC, et une politique de cycle de vie de dépréciation des fonctionnalités sur 12 mois. Elle a été livrée comme prévu avec la révision du 28 juillet 2026 — désormais la spécification Current (vérifiée le 14 août 2026).24 Pour les serveurs de vaults personnels, STDIO demeure l’option la plus simple, et le cœur sans état rend les serveurs STDIO mono-utilisateur encore plus légers. Le transport Streamable HTTP, la découverte .well-known et les Apps MCP profitent surtout aux déploiements HTTP d’entreprise avec routage multi-tenant et équilibrage de charge. Surveillez la feuille de route MCP afin de suivre les mises à jour susceptibles d’affecter votre choix de transport.

Conception des capacités

Le serveur MCP doit exposer un ensemble minimal d’outils :

search — L’outil principal. Exécute une récupération hybrid et renvoie des résultats classés.

{
  "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 — Lit le contenu complet d’une note spécifique à partir de son chemin. Utile lorsque l’agent souhaite consulter le contexte complet d’un résultat de recherche.

{
  "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 — Répertorie les notes correspondant à un filtre (par dossier, tag, type ou plage de dates). Utile pour l’exploration lorsque l’agent ne dispose pas d’une requête précise.

{
  "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 — Un outil pratique qui exécute une recherche et formate les résultats sous forme de bloc de contexte adapté à l’injection dans une conversation.

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

Limites d’autorisation

Le serveur MCP doit appliquer des limites strictes :

  1. Lecture seule. Le serveur lit le vault et la base de données d’index. Il ne crée, ne modifie ni ne supprime de notes. Les opérations d’écriture (capture de nouvelles notes) sont gérées par des hooks ou des skills distincts, et non par le serveur MCP.

  2. Limité au vault. Le serveur ne lit que les fichiers situés dans le chemin du vault configuré. Les tentatives de traversal de chemin (../../etc/passwd) doivent être rejetées.

  3. Sortie filtrée pour les identifiants. Même si la base de données contient du contenu préfiltré, appliquez un filtrage des identifiants en sortie comme mesure de défense en profondeur.

  4. Réponses limitées en tokens. Appliquez max_tokens à toutes les réponses d’outils afin d’empêcher l’outil IA de recevoir des blocs de contexte excessivement volumineux.

Gestion des erreurs

Les outils MCP doivent renvoyer des messages d’erreur structurés qui aident l’outil IA à se rétablir :

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

Intégration de Claude Code

Claude Code est le principal consommateur du système de récupération d’Obsidian. Cette section couvre la configuration de MCP, l’intégration des hooks et le modèle obsidian_bridge.py.

Configuration de MCP

Enregistrez le serveur personnalisé avec claude mcp add (la portée utilisateur écrit dans ~/.claude.json ; -s project écrit un .mcp.json partageable — ~/.claude/settings.json n’est pas une surface de configuration de MCP) :

claude mcp add obsidian -s user \
  -e VAULT_PATH=/absolute/path/to/vault \
  -e DB_PATH=/absolute/path/to/vectors.db \
  -- python /path/to/obsidian_mcp.py

L’entrée .mcp.json équivalente, si vous préférez l’écrire à la main :

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

Après avoir ajouté la configuration, redémarrez Claude Code. Le serveur MCP démarrera comme processus enfant. Vérifiez qu’il s’exécute :

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

Claude Code devrait lister les outils disponibles (obsidian_search, obsidian_read_note, etc.).

Intégration des hooks

Les hooks étendent le comportement de Claude Code à des points définis de son cycle de vie. Deux hooks sont pertinents pour l’intégration avec Obsidian :

Les hooks sont enregistrés dans les paramètres (~/.claude/settings.json, sous la clé hooks, avec un nom d’événement et un matcher) et reçoivent un payload JSON sur stdin — il n’existe aucun dossier de hooks que Claude Code découvre automatiquement, et les détails des outils n’arrivent jamais sous forme d’arguments $1/$2.

Hook UserPromptSubmit — interroge le vault lorsque vous soumettez un prompt et injecte le contexte pertinent (la sortie stdout de cet événement est ajoutée à la conversation) :

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [{ "type": "command", "command": "/path/to/obsidian-context.sh" }]
      }
    ]
  }
}
#!/bin/bash
# obsidian-context.sh — read the JSON payload from stdin
PROMPT=$(jq -r '.prompt // empty')
[ -z "$PROMPT" ] && exit 0
CONTEXT=$(python /path/to/retriever.py search "$PROMPT" --limit 3 --max-tokens 1500)
if [ -n "$CONTEXT" ]; then
    printf 'Relevant vault context:\n%s\n' "$CONTEXT"   # stdout -> added as context
fi

Hook PostToolUse — capture les sorties d’outils importantes dans le vault pour une récupération ultérieure (enregistré avec un matcher afin qu’il ne se déclenche que pour les outils qui vous intéressent) :

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|Bash",
        "hooks": [{ "type": "command", "command": "/path/to/capture-insight.sh" }]
      }
    ]
  }
}
#!/bin/bash
# capture-insight.sh — tool name and response arrive as stdin JSON
PAYLOAD=$(cat)
TOOL_NAME=$(printf '%s' "$PAYLOAD" | jq -r '.tool_name')
OUTPUT=$(printf '%s' "$PAYLOAD" | jq -r '.tool_response // "" | tostring')
if [ ${#OUTPUT} -gt 500 ]; then
    python /path/to/capture.py --text "$OUTPUT" --source "claude-code-$TOOL_NAME"
fi

Le modèle obsidian_bridge.py

Un module passerelle fournit une Python API que les hooks et les skills peuvent appeler :

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

La skill /capture

Une skill Claude Code permettant de capturer des idées dans le vault :

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

La skill crée une nouvelle note dans 00-inbox/ avec le frontmatter approprié et déclenche une réindexation incrémentielle afin que la nouvelle note soit immédiatement consultable.

Modèles de commandes personnalisées

Les skills Claude Code peuvent encapsuler les opérations du vault dans des commandes nommées. Des praticiens ont constitué des bibliothèques de commandes spécifiques à Obsidian qui traitent le vault à la fois comme source de lecture et cible d’écriture.

Analyse des signaux. Une commande /scan-intel interroge des sources externes, évalue les résultats selon des centres d’intérêt de recherche personnels et écrit les signaux admissibles sous forme de notes de vault avec frontmatter :

/scan-intel --topics "agent infrastructure, security" --lookback 7d

La commande récupère les données depuis les sources configurées (arXiv, HN, RSS), applique un modèle de scoring (pertinence, caractère actionnable, profondeur, autorité) et écrit les signaux retenus dans des dossiers de vault propres à chaque sujet. Le vault devient le consommateur en aval d’un pipeline automatisé de veille.

Journal de bord. Une commande /captains-log agrège l’activité git quotidienne de tous les dépôts, écrit une entrée de journal structurée dans le vault et inclut les décisions prises, les prises de conscience et les fils ouverts :

/captains-log

La commande récupère l’historique des commits depuis GitHub, les regroupe par dépôt et les met en forme sous la forme d’une entrée de journal narrative. Avec le temps, les journaux quotidiens créent une trace consultable de ce qui a été livré et pourquoi.

Capture Obsidian. Une commande /obsidian-capture prend une idée issue de la session Claude Code en cours et l’écrit directement dans le vault avec les métadonnées appropriées :

/obsidian-capture "SAST gates in agent loops increase security degradation"
  --folder AI-Tools --tags security,agents

Le modèle s’étend à toute opération sur le vault : création de MOC, mise à jour de notes d’état de projet, liaison de signaux associés ou génération de synthèses hebdomadaires à partir des journaux quotidiens accumulés.

Exemples de la communauté. Des praticiens publient leurs bibliothèques de commandes. Un développeur a partagé 22 commandes personnalisées Obsidian + Claude Code couvrant les revues quotidiennes, la planification de projets, la capture de recherches et les flux de contenu.1 Un autre a créé une skill « Visual Explainer » qui génère des notes de diagrammes dans le vault à partir d’analyses de code.2 Les commandes varient, mais l’architecture reste cohérente : les skills Claude Code comme interface, les notes du vault comme couche de stockage et l’infrastructure de récupération comme moteur de requête.

Gestion de la fenêtre de contexte

L’intégration doit tenir compte de la fenêtre de contexte de Claude Code :

  • Limitez le contexte injecté à 1 500-2 000 tokens par requête. Au-delà, il entre en concurrence avec la mémoire de travail de l’agent.
  • Incluez l’attribution des sources. Incluez toujours le chemin du fichier et le titre de section afin que l’agent puisse référencer la source.
  • Tronquez le texte des chunks. Les chunks longs doivent être tronqués avec ... plutôt qu’omis entièrement. Les 300-500 premiers caractères contiennent généralement l’information essentielle.
  • N’injectez pas de contexte à chaque prompt. L’injection s’exécute via UserPromptSubmit (l’événement dont stdout atteint le modèle) ; prévoyez donc ce budget à cet endroit : ignorez les prompts conversationnels courts, injectez uniquement lorsque le prompt mentionne du code, des fichiers ou des décisions passées, et plafonnez le bloc injecté. Les événements limités à un outil, tels que PreToolUse, peuvent filtrer ou journaliser, mais leur stdout n’atteint jamais le modèle.

Intégration de Codex CLI

Codex CLI se connecte aux serveurs MCP via config.toml. Le modèle d’intégration diffère de celui de Claude Code par la syntaxe de configuration et la transmission des instructions.

Configuration de MCP

Ajoutez ceci à ~/.codex/config.toml (Codex lit $CODEX_HOME/config.toml ; les instructions au niveau du projet appartiennent à AGENTS.md, et non à un fichier de configuration de projet) :

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

Modèles AGENTS.md

Codex CLI lit AGENTS.md pour les instructions au niveau du projet. Incluez des indications pour la recherche dans le vault :

## Available Tools

### Obsidian Vault (MCP: obsidian)
Use the `obsidian_search` tool to find relevant context from the knowledge base.
Search the vault when you need:
- Background on a concept or pattern
- Prior decisions or rationale
- Reference material for implementation

Example queries:
- "authentication patterns in FastAPI"
- "how does the review aggregator work"
- "sqlite-vec configuration"

Différences avec Claude Code

Fonctionnalité Claude Code Codex CLI
Configuration MCP claude mcp add~/.claude.json / .mcp.json de projet ~/.codex/config.toml
Hooks Enregistrés dans les paramètres, 31 événements de cycle de vie, stdin JSON Pris en charge (surface stable ; son propre ensemble d’événements)
Skills ~/.claude/skills/ ~/.codex/skills/ (stable)
Fichier d’instructions CLAUDE.md AGENTS.md
Surface d’autorisation Modes : Manual / acceptEdits / auto (par défaut sur Pro/Max/Team depuis le 14 août 2026) / plan / bypassPermissions Politique d’approbation untrusted / on-request / never × sandbox read-only / workspace-write / danger-full-access (--full-auto supprimé dans v0.147.0)

Différence essentielle : les deux outils prennent désormais en charge les hooks et les skills ; c’est leur forme qui diffère. Codex associe une politique d’approbation à un mode sandbox au niveau du système d’exploitation au lieu des modes d’autorisation de Claude Code, et ses événements de hooks diffèrent — portez le modèle (interroger le vault avant le travail, capturer après), pas la configuration. AGENTS.md reste le bon emplacement pour les instructions permanentes de recherche prioritaire dans le vault avec Codex.

Cursor et autres outils

Cursor et d’autres outils d’IA qui prennent en charge MCP peuvent se connecter au même serveur Obsidian MCP. Cette section couvre la configuration des outils courants.

Cursor

Ajoutez ceci à .cursor/mcp.json à la racine de votre projet :

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

Le fichier .cursorrules de Cursor peut inclure des instructions pour utiliser le vault :

When working on implementation tasks, search the Obsidian vault
for relevant context before writing code. Use the obsidian_search
tool with descriptive queries about the concept you're implementing.

Matrice de compatibilité

Outil Prise en charge de MCP Transport Emplacement de la configuration
Claude Code Complète STDIO claude mcp add~/.claude.json / .mcp.json du projet
Codex CLI Complète STDIO ~/.codex/config.toml
Cursor Complète STDIO .cursor/mcp.json
Windsurf Complète STDIO ~/.codeium/windsurf/mcp_config.json
Continue.dev Complète STDIO + HTTP ~/.continue/config.yaml (mcpServers)
Zed Complète (serveurs de contexte) STDIO settings.json (context_servers)
Claudian (plugin Obsidian) N/A (intégré) Claude Code CLI Paramètres du plugin Obsidian
Agent Client (plugin Obsidian) N/A (intégré) ACP Paramètres du plugin Obsidian

Solution de repli pour les outils sans MCP

Pour les outils qui ne prennent pas en charge MCP, le retriever peut être encapsulé dans un CLI :

# Search from command line
python retriever_cli.py search "query text" --limit 5

# Output formatted for copy-paste into any tool
python retriever_cli.py context "query text" --format markdown

Le CLI produit du texte structuré qui peut être collé manuellement dans l’entrée de n’importe quel outil d’IA. C’est moins élégant que l’intégration MCP, mais cela fonctionne partout.


Mise en cache des prompts à partir de notes structurées

Les notes structurées du vault peuvent servir de blocs de contexte réutilisables afin de réduire l’utilisation de tokens lors des interactions avec l’IA. Cette section couvre la conception des clés de cache et la gestion du budget de tokens.

Le modèle

Au lieu de rechercher le contexte à chaque interaction, créez au préalable des blocs de contexte à partir de notes bien structurées du vault, puis mettez-les en cache :

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

Invalidation du cache

L’invalidation du cache repose sur deux signaux :

  1. Expiration du TTL. Chaque bloc de contexte possède une durée de vie. Lorsque le TTL expire, le bloc est reconstruit en interrogeant à nouveau le vault.
  2. Détection des changements dans le vault. Lorsque l’indexeur détecte des modifications dans les fichiers ayant contribué à un bloc de contexte mis en cache, ce bloc est invalidé immédiatement.

Gestion du budget de tokens

Une session démarre avec un budget de contexte total. Les blocs mis en cache en consomment une partie :

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)

Les blocs mis en cache se chargent au démarrage de la session. Les résultats de recherche dynamiques remplissent le budget restant pour chaque requête. Cette approche hybride fournit à l’agent une base de contexte fréquemment nécessaire tout en préservant le budget pour les requêtes spécifiques.

Utilisation des tokens avant/après

Sans mise en cache : chaque requête pertinente déclenche une recherche dans le vault, renvoyant 1 500 à 2 000 tokens de contexte. Sur 10 requêtes dans une session, l’agent consomme 15 000 à 20 000 tokens de contexte du vault.

Avec mise en cache : trois blocs de contexte préconstruits consomment au total 4 500 tokens. Les recherches supplémentaires ajoutent 1 500 à 2 000 tokens par requête unique. Sur 10 requêtes, dont 6 sont couvertes par des blocs mis en cache, l’agent consomme 4 500 + (4 * 1 500) = 10 500 tokens — soit environ la moitié de l’utilisation sans cache.


Capture de résumés compressés de sorties verbeuses

Les sorties d’outils peuvent être verbeuses : traces de pile, listes de fichiers, résultats de tests. Un hook ne peut pas réduire ce que le modèle voit — lorsque PostToolUse se déclenche, la sortie complète est déjà dans la fenêtre de contexte, et rien de ce qu’affiche un hook ne la remplace. En revanche, un hook peut écrire un résumé compressé dans le vault, afin que les sessions futures récupèrent le verdict en deux lignes au lieu de relancer ou de relire l’original de 5 000 tokens. Considérez cela comme un modèle de capture pour la mémoire intersessions, et non comme un moyen d’économiser du contexte au sein d’une session (dans une session, les véritables leviers sont /compact, des prompts ciblés et la demande de sorties moins verbeuses).

Le problème

Un appel à l’outil Bash qui exécute des tests peut renvoyer :

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

La sortie complète fait 5 000 tokens, mais l’information utile tient en 2 lignes : 200 réussis, 1 échoué.

Implémentation du hook

Enregistré sur PostToolUse avec un matcher Bash (enregistré dans les paramètres, stdin JSON — voir l’intégration des hooks ci-dessus) :

#!/bin/bash
# summarize-and-capture.sh — write a compressed summary to the vault
PAYLOAD=$(cat)
OUTPUT=$(printf '%s' "$PAYLOAD" | jq -r '.tool_response // "" | tostring')

# Only summarize large outputs
[ ${#OUTPUT} -lt 2000 ] && exit 0

if printf '%s' "$OUTPUT" | grep -q "PASSED\|FAILED"; then
    PASSED=$(printf '%s' "$OUTPUT" | grep -c "PASSED")
    FAILED=$(printf '%s' "$OUTPUT" | grep -c "FAILED")
    SUMMARY="Tests: $PASSED passed, $FAILED failed"
    [ "$FAILED" -gt 0 ] && SUMMARY="$SUMMARY
$(printf '%s' "$OUTPUT" | grep 'FAILED')"
    python /path/to/capture.py --text "$SUMMARY" --source "test-run-summary"
fi
exit 0

Chaque invocation du hook correspond à un processus distinct ; aucun garde-fou contre la récursion n’est donc nécessaire — les propres écritures d’un hook ne le déclenchent pas à nouveau, et les variables exportées ne survivent jamais à l’invocation suivante.

Heuristiques de compression

Type de sortie Détection Stratégie de compression
Résultats de tests Mots-clés PASSED / FAILED Compter les réussites/échecs, n’afficher que les échecs
Listes de fichiers ls ou find dans la commande Tronquer aux 20 premières entrées + nombre total
Traces de pile Mot-clé Traceback Conserver la première et la dernière frame + le message d’erreur
Statut Git modified: / new file: Résumer les nombres par statut
Sortie de build warning: / error: Supprimer les lignes d’information, conserver les avertissements/erreurs

Pipeline d’entrée et de triage des signaux

La couche d’entrée détermine ce qui entre dans le vault. Sans curation, le vault accumule du bruit. Cette section couvre le pipeline de notation qui achemine les signaux vers les dossiers de domaine.

Sources

Les signaux proviennent de plusieurs canaux :

  • Flux RSS : Blogs techniques, avis de sécurité, notes de version
  • Signets via Web Clipper : L’extension officielle Obsidian Web Clipper (Chrome, Firefox, Safari) offre le chemin d’entrée le plus fidèle pour la capture côté navigateur. Le cycle de publication d’avril 2026 l’a rendue nettement plus utile pour les workflows d’IA :22
    • 1.4.0 (9 avr.) : Interface interactive de transcription YouTube — épinglez la vidéo, parcourez la transcription, faites défiler automatiquement et mettez en surbrillance la position actuelle. S’y ajoute une option par défaut « Open in Reader » qui envoie une capture en un clic directement dans le mode Reader.
    • 1.5.0–1.5.1 (15 avr.) : Visionneuse de surbrillances — parcourez et recherchez les surbrillances capturées dans tout le vault. Transition en fondu vers Reader. Lecture/pause YouTube plus fluide. La version 1.5.1 a corrigé une régression de compilation webpack.
    • 1.6.0–1.6.2 (21–23 avr.) : Refonte de l’UX du surligneur avec prise en charge mobile. Defuddle 0.18 ajoute des extracteurs spécifiques aux sources pour LinkedIn, Threads, Bluesky, Discourse et Medium. La version 1.6.2 corrige une régression du presse-papiers en mode intégré de Safari. Configurez des modèles par domaine source afin que les transcriptions YouTube, les README de GitHub et les articles longs soient chacun enregistrés dans une note au nom pertinent, avec le bon frontmatter pour le pipeline de notation ci-dessous.
  • Newsletters : Extraits clés de newsletters par e-mail
  • Capture manuelle : Notes rédigées pendant vos lectures, conversations ou recherches
  • Sortie d’outils : Sorties importantes d’outils d’IA capturées via des hooks
  • Extension de partage iOS : L’application iOS d’Obsidian (mise à jour début 2026) inclut une extension de partage qui enregistre du contenu depuis Safari, les réseaux sociaux et d’autres applications directement dans le vault sans ouvrir Obsidian ; la branche 1.13 ajoute des cibles configurables dans la feuille de partage avec des variables de modèle — dont url, afin qu’une page capturée enregistre automatiquement son lien source dans le frontmatter.19 Cela crée un chemin d’entrée mobile sans friction : partagez un article depuis Safari et il arrive sous forme de note dans le vault, prête à être notée.
  • Obsidian CLI : Les scripts shell et les hooks peuvent créer des notes via obsidian file create ou ajouter du contenu à des notes existantes via obsidian file append, ce qui permet des pipelines d’entrée automatisés sur ordinateur.

Dimensions de notation

Chaque signal est noté selon quatre dimensions (de 0,0 à 1,0 chacune) :

Dimension Question Score faible (0,0-0,3) Score élevé (0,7-1,0)
Pertinence Cela concerne-t-il mes domaines actifs ? Tangentiel, hors périmètre Directement pertinent pour le travail en cours
Applicabilité Puis-je utiliser cette information ? Théorie pure, sans application Technique ou modèle précis que je peux appliquer
Profondeur Quel est le niveau de substance du contenu ? Titres, résumé superficiel Analyse détaillée avec des exemples
Autorité Quelle est la crédibilité de la source ? Blog anonyme, non vérifié Source primaire, évaluée par les pairs, expert reconnu

Score composite et acheminement

composite = (relevance * 0.35) + (actionability * 0.25) +
            (depth * 0.25) + (authority * 0.15)
Plage de score Action
0,55+ Acheminement automatique vers le dossier de domaine
0,40 - 0,55 Mise en file pour révision manuelle
< 0,40 Abandon (ne pas stocker)

Acheminement par domaine

Les signaux dont le score dépasse 0,55 sont acheminés vers l’un des 12 dossiers de domaine selon la correspondance de mots-clés et la classification thématique :

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

Statistiques de production

Sur 14 mois de fonctionnement :

Indicateur Valeur
Nombre total de signaux traités 7 771
Acheminés automatiquement (>0,55) 4 832 (62 %)
Mis en file pour révision (0,40-0,55) 1 543 (20 %)
Abandonnés (<0,40) 1 396 (18 %)
Dossiers de domaine actifs 12
Nombre moyen de signaux par jour ~18

Modèles de graphe de connaissances

Le graphe de wiki-links d’Obsidian encode les relations entre les notes. Cette section couvre la sémantique des liens, la traversée du graphe pour étendre le contexte et les anti-modèles qui dégradent la qualité du graphe.

Chaque wiki-link crée une arête orientée dans le graphe. Obsidian suit à la fois les liens sortants et les backlinks :

  • Lien sortant : La note A contient [[Note B]] → A renvoie vers B
  • Backlink : La note B indique que la note A y fait référence

Le graphe encode différents types de relations selon le contexte :

Modèle de lien Sémantique Exemple
Lien en ligne « Est lié à » « Consultez [[OAuth Token Rotation]] pour plus de détails »
Lien d’en-tête « A pour sous-thème » « ## Related\n- [[Token Rotation]]\n- [[Session Management]] »
Lien de type tag « Est catégorisé comme » [[type/reference]]
Lien MOC « Fait partie de » Une note Map of Content qui liste des notes associées

Maps of Content (MOCs)

Les MOC sont des notes d’index qui organisent des notes associées dans une structure navigable :

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

Les MOC améliorent la récupération de deux manières :

  1. Correspondance directe. Une recherche de « authentication overview » correspond au MOC lui-même et fournit à l’agent une liste sélectionnée de notes associées.
  2. Extension du contexte. Après avoir trouvé une note précise, le retriever peut vérifier si elle apparaît dans des MOC et inclure la structure du MOC dans les résultats, donnant ainsi à l’agent une carte du sujet plus large.

Traversée du graphe pour étendre le contexte

Une amélioration future du retriever : après avoir trouvé les meilleurs résultats, étendez le contexte en suivant les liens :

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)

Cette fonctionnalité n’est pas implémentée dans le retriever actuel, mais elle constitue une extension naturelle de la structure du graphe.

Anti-modèles

Clusters orphelins. Groupes de notes qui se lient entre elles, mais n’ont aucune connexion avec le reste du vault. Le panneau de graphe d’Obsidian les rend visibles sous forme d’îlots déconnectés. Les clusters orphelins indiquent des MOC manquants ou l’absence de liens inter-domaines.

Prolifération de tags. Utiliser des tags de manière incohérente ou créer trop de tags très précis. Un vault comptant 500 tags uniques pour 5 000 notes compte en moyenne 1 note pour 10 tags — les tags ne sont pas utiles pour le filtrage. Regroupez-les en 20 à 50 tags de haut niveau correspondant à vos dossiers de domaine.

Notes riches en liens, pauvres en contenu. Notes composées uniquement de wiki-links, sans prose. Ces notes sont mal indexées, car le chunker n’a aucun texte à intégrer. Ajoutez au moins un paragraphe de contexte expliquant pourquoi les notes liées sont associées.

Liens bidirectionnels pour tout. Chaque référence n’a pas besoin d’être un wiki-link. Mentionner « OAuth » en passant ne nécessite pas [[OAuth 2.0 Overview]]. Réservez les wiki-links aux relations intentionnelles et navigables, pour lesquelles cliquer sur le lien fournirait un contexte utile.


Recettes de workflow développeur

Workflows pratiques qui combinent la récupération dans le coffre avec les tâches de développement quotidiennes.

Chargement du contexte matinal

Commencez la journée en chargeant le contexte pertinent :

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

Le retriever renvoie les notes récentes concernant votre projet actif, ce qui vous donne un rappel rapide de l’endroit où vous vous étiez arrêté. C’est plus efficace que de relire les messages de commit de la veille.

Capture de recherche pendant le codage

Pendant l’implémentation d’une fonctionnalité, capturez des informations sans quitter l’éditeur :

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

L’information capturée est immédiatement indexée et disponible pour une récupération future. Sur plusieurs mois, ces micro-captures constituent un corpus de connaissances propres à l’implémentation.

Lancement de projet

Lorsque vous démarrez un nouveau projet ou une nouvelle fonctionnalité :

  1. Recherchez dans le coffre : « Que sais-je sur [technologie/modèle] ? »
  2. Examinez les 5 premiers résultats pour retrouver les décisions antérieures et les pièges connus
  3. Vérifiez s’il existe un MOC pour le domaine ; sinon, créez-en un
  4. Recherchez les modes d’échec : « problèmes avec [technologie] »

Débogage avec la recherche dans le coffre

Lorsque vous rencontrez une erreur ou un comportement inattendu :

Search my vault for [error message or symptom]

Les notes de débogage précédentes contiennent souvent la cause racine et le correctif. C’est particulièrement utile pour les problèmes récurrents entre projets : le coffre retient ce que vous oubliez.

Préparation de revue de code

Avant de relire une PR :

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

Le coffre renvoie les décisions antérieures, les contraintes d’architecture et les standards de codage pertinents pour le code examiné. La revue s’appuie sur la connaissance institutionnelle, pas seulement sur le diff.


Optimisation des performances

Cette section couvre les stratégies d’optimisation pour différentes tailles de coffre et différents modèles d’utilisation.

Gestion de la taille de l’index

Taille du coffre Chunks Taille DB Réindexation complète Incrémental
500 notes ~1 500 3 MB 15 secondes <1 seconde
2 000 notes ~6 000 12 MB 45 secondes 2 secondes
5 000 notes ~15 000 30 MB 2 minutes 4 secondes
15 000 notes ~50 000 83 MB 4 minutes <10 secondes
50 000 notes ~150 000 250 MB 15 minutes 30 secondes

À partir de 50 000 notes, envisagez : - D’augmenter la taille de batch de 64 à 128 pour accélérer l’embedding - D’utiliser le mode WAL (par défaut) pour les accès concurrents - D’exécuter la réindexation complète pendant les heures creuses

Optimisation des requêtes

Mode WAL. Le mode Write-Ahead Logging de SQLite permet des lectures concurrentes pendant que l’indexeur écrit :

db.execute("PRAGMA journal_mode=WAL")

C’est essentiel lorsque le serveur MCP traite des requêtes pendant que l’indexeur exécute une mise à jour incrémentale.

Connection pooling. Le serveur MCP doit réutiliser les connexions à la base de données au lieu d’ouvrir une nouvelle connexion par requête. Une seule connexion durable avec le mode WAL prend en charge les lectures concurrentes.

# 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

I/O mappées en mémoire. Le pragma mmap_size indique à SQLite d’utiliser des I/O mappées en mémoire pour le fichier de base de données. Pour une base de données de 83 MB, mapper tout le fichier en mémoire élimine la plupart des lectures disque.

Optimisation FTS5. Après une réindexation complète, exécutez :

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

Cela fusionne les segments b-tree internes de FTS5, ce qui réduit la latence des requêtes pour les recherches suivantes.

Benchmarks de passage à l’échelle

Mesurés sur Apple M3 Pro, 36 GB de RAM, SSD NVMe :

Opération 500 notes 5K notes 15K notes 50K notes
Requête BM25 2ms 5ms 12ms 25ms
Requête vectorielle 1ms 3ms 8ms 20ms
Fusion RRF <1ms <1ms 3ms 5ms
Recherche complète 3ms 8ms 23ms 50ms

Tous les benchmarks incluent l’accès à la base de données, l’exécution des requêtes et la mise en forme des résultats. La latence réseau pour la communication STDIO de MCP ajoute 1 à 2ms.


Dépannage

Dérive de l’index

Symptôme : la recherche renvoie des résultats obsolètes ou ne trouve pas des notes récemment ajoutées.

Cause : l’indexeur incrémental n’a pas été exécuté après l’ajout de notes, ou le mtime d’un fichier n’a pas été mis à jour (par exemple, après une synchronisation depuis une autre machine avec conservation des timestamps).

Correctif : exécutez une réindexation complète : python index_vault.py --full

Changement de modèle d’embedding

Symptôme : après avoir changé de modèle d’embedding, la recherche vectorielle renvoie des résultats incohérents.

Cause : les anciens vecteurs (issus du modèle précédent) sont comparés aux nouveaux vecteurs de requête. Les dimensions ou la sémantique de l’espace vectoriel sont incompatibles.

Correctif : l’indexeur doit détecter la non-correspondance du hash du modèle et déclencher automatiquement une réindexation complète. Si ce n’est pas le cas, videz manuellement la base de données et réindexez :

rm vectors.db
python index_vault.py --full

Maintenance FTS5

Symptôme : les requêtes FTS5 renvoient des résultats incorrects ou incomplets après de nombreuses mises à jour incrémentales.

Cause : les segments internes de FTS5 peuvent se fragmenter après de nombreuses petites mises à jour.

Correctif : reconstruisez et optimisez :

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

Timeout MCP

Symptôme : l’outil d’AI indique que le serveur MCP a expiré.

Cause : la première requête déclenche le chargement du modèle (initialisation paresseuse), qui prend 2 à 5 secondes. Le timeout MCP par défaut de l’outil d’AI peut être plus court.

Correctif : préchauffez le modèle au démarrage du serveur :

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

Verrous de fichier SQLite

Symptôme : erreurs SQLITE_BUSY ou SQLITE_LOCKED.

Cause : plusieurs processus écrivent simultanément dans la base de données. Le mode WAL permet les lectures concurrentes, mais un seul écrivain.

Correctif : assurez-vous qu’un seul processus (l’indexeur) écrit dans la base de données. Le serveur MCP et les hooks doivent uniquement lire. Si vous avez besoin d’écritures concurrentes, utilisez le mode WAL et définissez un busy timeout :

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

sqlite-vec ne se charge pas

Symptôme : la recherche vectorielle est désactivée ; le retriever s’exécute en mode BM25 uniquement.

Cause : l’extension sqlite-vec n’est pas installée, est introuvable dans le chemin de bibliothèque, ou est incompatible avec la version de SQLite.

Correctif :

# Install via pip
pip install sqlite-vec

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

Vérifiez que l’extension se charge :

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

Problèmes de mémoire avec un grand coffre

Symptôme : erreurs de mémoire insuffisante pendant la réindexation complète d’un grand coffre (50 000 notes ou plus).

Cause : la taille de batch d’embedding est trop élevée, ou tout le contenu des fichiers est chargé simultanément en mémoire.

Correctif : réduisez la taille de batch et traitez les fichiers de manière incrémentale :

BATCH_SIZE = 32  # Reduce from 64

Assurez-vous aussi que l’indexeur traite les fichiers un par un (lecture, chunking et embedding de chaque fichier avant de passer au suivant), au lieu de charger tous les fichiers en mémoire.


Guide de migration

Depuis Apple Notes

  1. Exportez Apple Notes via l’option « Export All » (macOS) ou utilisez un outil de migration comme apple-notes-liberator
  2. Convertissez les exports HTML en markdown avec markdownify ou pandoc
  3. Déplacez les fichiers convertis dans le dossier 00-inbox/ de votre coffre
  4. Relisez et ajoutez un frontmatter à chaque note
  5. Déplacez les notes vers les dossiers de domaine appropriés

Depuis Notion

  1. Exportez depuis Notion : Settings → Export → Markdown & CSV
  2. Décompressez l’export dans le dossier 00-inbox/ de votre coffre
  3. Corrigez les artefacts markdown propres à Notion :
  4. Notion utilise - [ ] pour les checklists — c’est du markdown standard
  5. Notion inclut les tables de propriétés sous forme de HTML — convertissez-les en frontmatter YAML
  6. Notion intègre les images sous forme de chemins relatifs — copiez les images dans votre dossier de pièces jointes
  7. Ajoutez le frontmatter standard (type, domain, tags)
  8. Remplacez les liens de pages Notion par des wiki-links Obsidian

Depuis Google Docs

  1. Utilisez Google Takeout pour exporter tous les documents
  2. Convertissez les fichiers .docx en markdown : pandoc -f docx -t markdown input.docx -o output.md
  3. Conversion par lot : for f in *.docx; do pandoc -f docx -t markdown "$f" -o "${f%.docx}.md"; done
  4. Déplacez dans le coffre, ajoutez le frontmatter, organisez dans des dossiers

Depuis du markdown brut (sans Obsidian)

Si vous disposez déjà d’un répertoire de fichiers markdown :

  1. Ouvrez le répertoire comme coffre Obsidian (Obsidian → Open Vault → Open folder)
  2. Ajoutez .obsidian/ à .gitignore si le répertoire est versionné
  3. Créez des modèles de frontmatter et appliquez-les aux fichiers existants
  4. Commencez à lier les notes avec des [[wiki-links]] au fil de votre lecture et de votre organisation
  5. Exécutez l’indexeur immédiatement — le système de récupération fonctionne dès le premier jour

Depuis un autre système de récupération

Si vous migrez depuis un autre système d’embedding/recherche :

  1. N’essayez pas de migrer les vecteurs. Différents modèles produisent des espaces vectoriels incompatibles. Exécutez une réindexation complète avec le nouveau modèle.
  2. Migrez le contenu, pas l’index. Les fichiers du coffre sont la source de vérité. L’index est un artefact dérivé.
  3. Vérifiez après la migration. Exécutez 10 à 20 requêtes dont vous connaissez les réponses et vérifiez que les résultats correspondent à vos attentes.

Journal des modifications

Date Modification Source
2026-08-14 Premier audit holistique de validation — lecture de l’intégralité du guide par l’évaluateur ; R1 a obtenu 8,29 avec trois constats CRITICAL et cinq MAJOR, tous corrigés dans cette ligne. Les constats CRITICAL nuisaient au lecteur : le démarrage rapide installait npm obsidian-mcp-server comme « l’option la plus simple basée sur les fichiers » — ce package est le serveur soutenu par REST-API de cyanheads (nécessite le plugin Local REST API et OBSIDIAN_API_KEY ; aucun flag --vault), tandis que le serveur basé sur les fichiers est npm obsidian-mcp (StevenStavrakis) — le tableau des serveurs présentait la même collision de noms et les deux ont été corrigés avec des noms npm explicites ; les deux blocs de configuration de Claude Code MCP enseignaient mcpServers dans ~/.claude/settings.json, que Claude Code ignore silencieusement — réécrits avec claude mcp add (portée utilisateur → ~/.claude.json) et une variante de portée projet .mcp.json, avec correction de la cellule de la matrice de compatibilité ; les exemples de hooks utilisaient les arguments positionnels $1/$2 et un répertoire d’auto-détection ~/.claude/hooks/pre-tool-use/ — une interface que Claude Code n’a jamais proposée — réécrits en hooks enregistrés dans les paramètres lisant stdin JSON via jq (l’injection de contexte est déplacée vers UserPromptSubmit, dont stdout est réellement ajouté au contexte), et la prémisse de la section « Compression du contexte PostToolUse » (un hook réduisant ce que voit le modèle) est impossible — elle est reformulée comme capture d’un résumé compressé dans le vault afin de le réutiliser entre les sessions, avec suppression du garde-fou de récursion inutile (chaque invocation de hook est un nouveau processus). MAJOR : 1.13.4 → 1.13.7 (vérifié par le manifeste, stable et bêta convergentes) ; la note de spécification MCP du 2026-07-28 disait encore « la spécification finale sort le 28 juillet » dix-sept jours après sa publication comme révision Current (mise au passé ; 9 réécrite comme élément historique, pointant vers 24) ; la comparaison avec Codex enseignait les modes d’approbation supprimés suggest/auto-edit/full-auto et indiquait que « hooks/skills ne sont pas pris en charge » — les deux sont des surfaces Codex stables depuis mi-2026, tableau et paragraphe reconstruits (la cellule CC nomme désormais les véritables modes d’autorisation, y compris le mode automatique par défaut du 14 août) ; lignes de matrice Zed/Continue/Windsurf actualisées. Mineurs : abandon de la variante projet .codex/config.toml ($CODEX_HOME uniquement), mcpvault 0.12.4 → 0.15.0, ancres « as of » expirées rendues absolues, et intégration dans la section d’intake de la variable url de la Share Sheet iOS 1.13 promise. La vérification R2 a confirmé les corrections, mais détecté des résidus à leurs limites, corrigés lors d’un second passage : les blocs Codex/Cursor du démarrage rapide invoquaient encore le binaire en collision (désormais npx -y obsidian-mcp@2 serve dans les trois outils, conformément à la syntaxe v2 du package installé), une phrase indiquant que PreToolUse injecte du contexte subsistait sous la section de hooks réécrite (les indications d’injection passent désormais systématiquement par UserPromptSubmit), et quatre lignes brèves (parenthèse déséquilibrée, référence obsolète à 1.13.4, version de 13, phrase restante de feuille de route dans 9). 24 26
2026-08-07 Obsidian 1.13 a atteint le canal public : 1.13.4 a été promu le 30 juillet 2026 (vérifié par le manifeste : desktop-releases.json latestVersion 1.13.4, beta.latestVersion 1.13.6). Les trois références du corps indiquant que « le canal public reste en 1.12.7 » sont mises à jour. Ce que livre la branche 1.13, désormais disponible pour tous : une refonte des paramètres (fenêtre distincte, recherche par nom/description, navigation au clavier + Vim), un visualiseur d’images en plein écran avec navigation par fichier et contrôles de redimensionnement en Live Preview, des Bookmarks consultables par recherche, la sélection multiple dans Sync et — surtout pour le public de ce guide — la sécurité des URI Obsidian : les actions obsidian:// nécessitent désormais une boîte de dialogue de confirmation sauf si elles sont placées sur liste d’autorisation. Le parcours d’automatisation de ce guide passe par MCP et le CLI, qui ne sont pas affectés, mais tout flux pilotant Obsidian par URI (Shortcuts, scripts, autres lanceurs) doit désormais autoriser ses actions une fois, sinon une invite apparaîtra à chaque fois. Côté développeur : un nouveau API dans Settings avec guide de migration, une modification incompatible de --callout-color (nécessite des couleurs CSS valides, et non plus des triplets RGB — les thèmes et snippets doivent être mis à jour), Electron 43.1.1, mises à niveau de CodeMirror et Mermaid 11.13.0. Aucun changement concernant l’IA, MCP ou CLI. Le suivi Catalyst passe à 1.13.6. 26
2026-07-27 Passage en revue des versions + correction d’un avis. MCPVault est passé de 0.12.1 à 0.12.4 dans trois correctifs publiés le 23 juillet, tous manqués par le passage du 22 juillet car ils sont arrivés le lendemain. v0.12.3 ajoute un outil wiki_link — résout les formes [[Document Name]], [[Name\|Display]], échappées pour les tableaux et avec #fragment, en renvoyant le contenu ainsi que le chemin résolu et les alternatives ambiguës — et exclut .trash/ de chaque outil grâce au filtre de chemins par défaut ; v0.12.4 l’étend aux liens qualifiés par chemin [[folder/Note]] ; v0.12.2 corrige patch_note qui corrompait les insertions de motifs $, normalise les chemins préfixés par le vault et élimine les constats npm audit de gravité élevée. La section du serveur MCP et [^24] décrivent désormais ces trois versions. Correction : la ligne du 2026-07-07 indiquait que v0.12.1 « comportait deux avis de sécurité de gravité moyenne concernant le filtre de chemins ». Ce n’était pas le cas. L’avis API de GitHub donne à GHSA-9c83-rr99-vfwj une plage vulnérable de < 0.11.5 et à GHSA-j99q-93c9-h869 < 0.11.4 — tous deux étaient corrigés avant l’ouverture de la branche 0.12, donc 0.12.1 était déjà saine lorsque cette ligne a été écrite. Le corps et la note de bas de page indiquent désormais les premières versions corrigées au lieu de laisser « exécuter une version actuelle » suggérer une exposition ouverte. Aussi : Obsidian 1.13.4 sur ordinateur + mobile (27 juillet) est un accès anticipé Catalyst ; le manifeste desktop-releases.json indique toujours latestVersion 1.12.7 avec beta.latestVersion 1.13.4, donc le canal public n’a pas bougé et les références de version restent valides ici. Le contenu relève de l’UX (affichage du nom de fichier dans la lightbox, alignement et marge des images en Live Preview, condition de course lors de l’enregistrement d’un fichier bloqué, disposition des paramètres) sans changement d’IA, de MCP ou de CLI. 13 26
2026-07-22 Passage en revue des versions, aucun changement de workflow. Obsidian 1.13.3 sur ordinateur + mobile (21 juillet) est uniquement un accès anticipé Catalyst — le canal public vérifié par manifeste reste en 1.12.7 ; le contenu relève de l’UX (lightbox/zoom d’images intégrées, correction de hauteur de ligne en Live Preview, touches fléchées de File Recovery, correction de paneType URI unique), sans changement d’IA/MCP/CLI. Le suivi Catalyst passe de 1.13.2 à 1.13.3. Note : 1.13.3 a été publié plus tard le 21 juillet, après la clôture du passage en revue de ce jour-là — « aucune nouvelle version » dans la ligne précédente était exact au moment de sa rédaction. Web Clipper 1.7.1 (22 juillet, version GitHub) : importation des surlignages, variables de modèle Interpreter {{model}}/{{modelId}}/{{modelProvider}}, presets de fournisseurs actualisés, Defuddle 0.19.2, corrections d’Interpreter pour les modèles Anthropic récents, clés API Gemini natives, gestion de DeepSeek et Azure OpenAI ; les déploiements sur les stores peuvent être postérieurs à la date GitHub. Aucune actualité officielle du serveur MCP ; la spécification sans état restait prévue pour le 28 juillet. 26
2026-07-21 Correction d’exactitude : le canal public sur ordinateur est en 1.12.7, et non en 1.13.1. L’entrée du 2026-06-10 (et les références dans le corps depuis lors) traitait 1.13.1 comme une version du canal public ; la page de changelog de 1.13.1 porte le badge Early access, et le manifeste officiel de mise à jour automatique (obsidianmd/obsidian-releases, desktop-releases.json) liste 1.12.7 comme latestVersion publique avec 1.13.2 sur le canal bêta — toute la branche 1.13.x est réservée à Catalyst. Références du corps et 26 corrigées. Le passage en revue des versions du 2026-07-17 au 2026-07-21 n’a trouvé aucune nouvelle version : le cœur reste en 1.13.2 Catalyst, Clipper en 1.7.0, aucune actualité officielle du serveur MCP, et la spécification sans état de MCP restait prévue pour le 28 juillet. 26
2026-07-17 Passage en revue des versions, aucun changement de workflow. Obsidian 1.13.2 (14 juillet) est uniquement un accès anticipé Catalyst — le canal public reste en 1.13.1, donc les références de version restent actuelles ici ; son unique élément adjacent au guide est une nouvelle variable url dans le modèle de Share Sheet iOS (insère le lien partagé dans la note), qui sera intégrée à la section du chemin de capture lorsque 1.13.2 deviendra publique. Web Clipper 1.7.0 (16 juin, précédemment non recensé) : mise à niveau vers Defuddle 0.19.0, {{content}} préserve désormais les marqueurs ==highlight==, et les surlignages persistent entre la page en direct et la vue Reader. Aucun serveur Obsidian MCP officiel ni intégration IA n’a été annoncé ; la sortie sans état de la spécification MCP restait prévue pour le 28 juillet. Vérifié auprès d’obsidian.md/changelog, des versions github.com/obsidianmd/obsidian-clipper et de blog.modelcontextprotocol.io.
2026-07-07 Corrections d’exactitude. MCPVault est précisé comme son propre projet (npm @bitbonsai/mcpvault, dépôt bitbonsai/mcpvault), désormais en v0.12.1, comportant deux avis de sécurité de gravité moyenne relatifs au filtre de chemins (GHSA-9c83-rr99-vfwj, GHSA-j99q-93c9-h869) — le lien [^24] précédent pointait vers le mauvais dépôt (MarkusPfundstein/mcp-obsidian). Statut de MarkusPfundstein/mcp-obsidian corrigé : le projet est activement maintenu (commits jusqu’au 15 mai 2026, ajoutant search_by_tag/get_frontmatter), et non « inactif depuis juin 2025 » ; il ne publie toujours aucune version taguée. Vérifié auprès de l’historique des commits GitHub, des Security Advisories GitHub et de npm.
2026-07-06 Restructuration éditoriale pour faciliter la trouvabilité : « Quick Start: First AI-Connected Vault » renommé en Configuration d’Obsidian MCP (ancre #obsidian-mcp-setup) et ajout d’un résumé des capacités « Ce que Claude peut faire une fois connecté » (recherche, lecture, liste, contexte formaté ; limite en lecture seule, les écritures étant gérées par les hooks) consolidé depuis la section Architecture du serveur MCP. Aucun fait nouveau ; liens internes mis à jour.
2026-06-10 Mise à jour de la version. Obsidian 1.13.1 sur ordinateur a atteint le canal public (9 juin 2026) — une amélioration de l’UX des paramètres + CodeMirror par rapport à 1.13.0, sans changement majeur d’IA/automatisation. Les références aux versions actuelles dans le corps sont passées de 1.13.0 à 1.13.1 (publique, 9 juin 2026). 26
2026-06-09 Actualisation de l’écosystème. La spécification MCP 2026-07-28 est entrée en Release Candidate (annoncée le 21 mai 2026) — la plus importante révision de MCP depuis son lancement : cœur de protocole sans état (supprime la négociation initialize et Mcp-Session-Id), Apps MCP (interfaces HTML rendues côté serveur dans des iframes sandboxées), Tasks passant du cœur expérimental à une extension officielle, durcissement de OAuth 2.0/OIDC et politique de cycle de dépréciation sur 12 mois (spécification finale le 28 juillet 2026) ; le cadrage spéculatif de feuille de route « provisoirement mi-2026 » dans la note d’évolution de la spécification MCP est remplacé par cette RC concrète. sqlite-vec v0.1.10-alpha (31 mars – 18 mai 2026) ajoute des types d’index de plus proches voisins approximatifs (rescore, ivf expérimental, DiskANN sur disque) au-delà du KNN en force brute — signalés comme à venir/expérimentaux puisque la branche 0.1.10 est encore une préversion. Obsidian 1.13.0 sur ordinateur (accès anticipé, 28 mai 2026) est devenue la version actuelle dans toutes les références du corps ; il s’agit d’une version UX/sécurité/outillage développeur sans nouvelles capacités d’IA/automatisation. 24 23 25
2026-06-08 Vérification de maintenance. Model2Vec v0.8.2 (29 mai 2026) est sorti : une version de maintenance ajoutant une option de poids gelés pour l’entraînement, ainsi que des corrections de jetons multi-mots, une refactorisation de l’entraînement et des corrections de gestion des poids non quantifiés ; note de bas de page mise à jour. Rien d’autre de plus récent que la base existante : la dernière version d’Obsidian reste 1.13.0 (28 mai, déjà documentée ci-dessous), sqlite-vec stable reste en v0.1.9 (v0.1.10 est encore alpha) et la spécification MCP reste la révision du 2025-11-25. Aucun changement dans le corps hormis la note de version Model2Vec. 10
2026-05-28 Obsidian 1.13.0 sur ordinateur + 1.13.0 sur mobile (accès anticipé Catalyst) publiés. Ordinateur : panneau Settings remanié, s’ouvrant dans sa propre fenêtre avec recherche intégrée et navigation au clavier ; les URI Obsidian affichent désormais une boîte de dialogue de confirmation avant de déclencher des actions ; nouvel avertissement avant le chargement de ressources HTML depuis des lecteurs réseau ; ajout de Search à la vue Bookmarks ; gestion améliorée des images dans l’éditeur ; améliorations de File Explorer / Properties / Sync ; nombreux correctifs de API développeur et de bugs. Mobile : nouvelle Share Sheet iOS avec emplacements cibles configurables ; réorganisation des onglets depuis le sélecteur d’onglets ; gestes d’appui long sur tablette pour redimensionner les divisions et les barres latérales épinglées ; Bases gagne une entrée de menu pour redimensionner les colonnes dans les vues de tableau ; corrections de bugs iOS et de recherche. Implications pour les workflows IA : la boîte de dialogue de confirmation des URI Obsidian ajoute une validation délibérée aux intégrations MCP/agents pilotées par URI ; le menu de redimensionnement des colonnes de Bases rend Bases plus exploitable comme index frontal du vault interrogé par les agents ; la cible configurable de la Share Sheet iOS accélère le raccordement du chemin de capture iPhone (déjà documenté comme intake principal) aux pipelines Claude/Codex.
2026-05-06 Actualisation des sources vérifiées : Smart Connections v4.5.0 a déplacé les connexions de pied de page dans Core ; les versions stables sqlite-vec v0.1.8/v0.1.9 ont actualisé le packaging et le comportement DELETE ; Model2Vec v0.8.x a mis à jour les internes du tokenizer/de la persistance et les tableaux de benchmarks ; correction de la chronologie CLI d’Obsidian de « 1.12.7 a introduit CLI » à « 1.12.0 a introduit CLI, 1.12.7 a amélioré le packaging d’installation/d’exécution ».
2026-04-27 Cycle d’avril de Web Clipper : 1.4.0 (interface interactive de transcription YouTube + Open in Reader par défaut), 1.5.0 (visionneuse de Highlights), 1.6.0 (refonte de l’UX Highlighter + extracteurs de sources Defuddle 0.18 pour LinkedIn/Threads/Bluesky/Discourse/Medium), 1.6.1 + 1.6.2 (correctifs Reader et Safari). Repositionnement de Web Clipper comme chemin d’intake principal côté navigateur pour les workflows IA, plutôt que comme simple mention de bookmark. Aucune version d’Obsidian sur ordinateur, de Sync ou de Bases dans cette période.
2026-04-16 Smart Connections v4.3.0 (vue graphique, dock configurable, récupération des block-embeddings, environnement inter-plugin Substrate). Documentation de la vague de plugins natifs IA d’avril 2026 (Cortex, VaultSearch, LLM Wiki, Drift, EngramQuest, Hybrid Search MCP). Signalement de MarkusPfundstein/mcp-obsidian comme étant en mode maintenance (dernier commit en juin 2025). Dataview est inactif ; Bases est le successeur pour les nouveaux travaux. Obsidian CLI 1.12.7 demeure le pont privilégié pour les assistants IA.
2026-04-01 Ajout d’une section Obsidian CLI (commandes v1.12 pour les workflows IA). Ajout d’une section sur les plugins d’agents (Claudian, Agent Client). Documentation du plugin principal Bases pour l’organisation du vault. Mise à jour du nombre de plugins à plus de 2 500. Ajout de l’extension de partage iOS comme source d’intake. Mise à jour de la matrice de compatibilité avec les plugins d’agents embarqués.
2026-03-30 MCPVault v0.11.0 : outil list_all_tags, prise en charge de .base/.canvas, renommé en @bitbonsai/mcpvault. Obsidian Desktop v1.12.7 intègre le binaire CLI pour des interactions terminal plus rapides.
2026-03-23 Documentation de sqlite-vec v0.1.7 stable : prise en charge de DELETE pour les tables vec0, contraintes de distance KNN pour la pagination. Index de plus proches voisins approximatifs DiskANN annoncé pour une prochaine version.
2026-03-07 Ajout de potion-multilingual-128M (101 langues, mai 2025) à la comparaison des modèles d’embeddings. sqlite-vec en v0.1.7-alpha.10 (correctifs CI/CD, aucune modification de fonctionnalité). Spécification MCP et techniques de retrieval confirmées à jour.
2026-03-03 Mise à jour de l’évolution de la spécification MCP (novembre 2025 livré : Streamable HTTP, .well-known, annotations d’outils). Ajout du fine-tuning Model2Vec et de la prise en charge du tokenizer BPE/Unigram. Ajout d’un tableau de comparaison des serveurs communautaires MCP. Mise à jour de Smart Connections vers v4.
2026-03-02 Ajout de potion-base-32M et potion-retrieval-32M à la comparaison des modèles. Ajout d’une section sur la quantification/réduction de dimensionnalité. Ajout d’une note sur l’évolution de la spécification MCP.
2026-03-01 Première version

Références


  1. Internet Vin, « 22 commands I use with Obsidian and Claude Code, » mars 2026, x.com/internetvin/status/2026461256677245131

  2. Nicopreme, skill d’agent « Visual Explainer » avec commandes slash, x.com/nicopreme/status/2023495040258261460

  3. Cormack, G.V., Clarke, C.L.A. et Buettcher, S. Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods. SIGIR, 2009. Introduit RRF avec k=60 comme méthode sans paramètre pour combiner des listes classées. 

  4. OpenAI Embeddings Pricing. text-embedding-3-small : 0,02 $ par million de tokens. Coût estimé du vault pour une réindexation complète : ~0,30 $. 

  5. van Dongen, T. et al. Model2Vec: Turn any Sentence Transformer into a Small Fast Model. arXiv, 2025. Décrit l’approche de distillation qui produit des embeddings statiques à partir de sentence transformers. 

  6. potion-base-8M Model Card et Model2Vec results. Les tableaux publiés actuels donnent potion-base-8M à 51.32 Avg (All) / 51.08 Avg (MTEB), contre all-MiniLM-L6-v2 à 55.80 Avg (All) / 55.93 Avg (MTEB), soit environ 92 % de conservation sur le score toutes tâches confondues. 

  7. Model Context Protocol Specification. La norme MCP pour connecter les outils d’IA aux sources de données. 

  8. Model2Vec Potion Models, potion-base-32M et potion-retrieval-32M. Les fiches de modèle actuelles indiquent potion-base-32M à 52.83 Avg (All) et potion-retrieval-32M à 35.06 dans le tableau de récupération. 

  9. Update on the Next MCP Protocol Release. Historique : la version de novembre 2025 a apporté le transport Streamable HTTP, la découverte d’URL .well-known, des annotations d’outils structurées et la standardisation des niveaux SDK. Le cycle de publication qu’elle annonçait s’est conclu avec la révision du 28 juillet 2026 — la spécification actuelle (voir 24). 

  10. Model2Vec Releases. v0.4.0 (févr. 2025) : prise en charge de l’entraînement/fine-tuning. v0.5.0 (avr. 2025) : réécriture du backend, quantification, réduction dimensionnelle. v0.7.0 (oct. 2025) : quantification du vocabulaire, prise en charge des tokenizers BPE/Unigram. v0.8.0/v0.8.1 (mars 2026) : refontes du tokenizer et de la persistance, abandon de Python 3.9, mises à jour des résultats MTEB V2 et compatibilité des chemins Windows. v0.8.2 (29 mai 2026) : version de maintenance ajoutant une option de poids gelés pour l’entraînement, ainsi que des correctifs pour les tokens composés de plusieurs mots, une refonte de l’entraînement et la gestion des poids non quantifiés. 

  11. Smart Connections for Obsidian. Smart Connections v4 : embeddings d’IA local-first, la recherche sémantique fonctionne hors ligne après l’indexation initiale. 

  12. potion-multilingual-128M. Minish Lab, mai 2025. Modèle d’embeddings statiques couvrant 101 langues, les embeddings statiques multilingues les plus performants. Même dépendance uniquement à numpy que les autres modèles potion. 

  13. MCPVault — bitbonsai/mcpvault. npm @bitbonsai/mcpvault, dernière version v0.15.0 (publiée le 2026-08-09) ; les versions 0.12.2 à 0.12.4 sont toutes parues le 2026-07-23 (0.12.2 à 09:51, 0.12.4 à 10:10 — 0.12.3 apparaît dans le changelog du dépôt entre les deux, mais n’a jamais été publiée sur npm) ; projet distinct de MarkusPfundstein/mcp-obsidian, et non un renommage de celui-ci. v0.11.0 (mars 2026) a ajouté l’outil list_all_tags pour parcourir le frontmatter et les hashtags avec leurs décomptes, amélioré la gestion des dossiers avec points et ajouté la prise en charge des fichiers .base/.canvas. Le contenu des versions 0.12.2 à 0.12.4 provient du dépôt CHANGELOG.md, qui constitue le seul historique des versions — le point de terminaison des versions GitHub de ce dépôt renvoie une liste vide, les heures de publication npm et le changelog sont donc les sources principales. 0.12.2 : patch_note insère newString littéralement au lieu de développer $', $&, $`, $$ (issue #149 / PR #153) ; les chemins absolus préfixés par le vault ou de type ~/ sont normalisés en chemins relatifs au vault (issue #122 / PR #151) ; les résultats de gravité élevée de npm audit sont éliminés par des mises à jour du lockfile uniquement (PR #154). 0.12.3 : nouvel outil wiki_link (PR #101) et exclusion de .trash/ de tous les outils via le filtre de chemin par défaut. 0.12.4 : wiki_link résout les liens qualifiés par chemin tels que [[folder/Note]] selon leur chemin complet relatif au vault plutôt que leur nom de base. Deux avis de sécurité GitHub de gravité moyenne affectent son filtre de chemin : GHSA-9c83-rr99-vfwj (les dossiers restreints ne sont refusés qu’à la racine du vault, pas dans les sous-dossiers) et GHSA-j99q-93c9-h869 (contournement de la liste de refus par équivalence de casse et de point/espace final). Selon la API des avis GitHub, leurs plages vulnérables sont < 0.11.5 et < 0.11.4, avec comme premières versions corrigées 0.11.5 et 0.11.4 respectivement — elles sont toutes deux antérieures à 0.12.0, donc chaque version 0.12.x, y compris 0.12.1, est déjà corrigée. Plages des avis et horodatages npm revérifiés le 2026-08-14. 

  14. sqlite-vec v0.1.7 Release. 17 mars 2026. Version stable : prise en charge de DELETE pour les tables virtuelles vec0, contraintes de distance KNN pour la pagination, améliorations des tests de fuzzing. L’indexation approximative des plus proches voisins DiskANN est annoncée pour une version future. 

  15. Introduction to Bases. Plugin de base d’Obsidian introduit dans la v1.9.10. Vues de type base de données (tableaux, galeries, calendriers, tableaux kanban) sur les fichiers du vault en utilisant les propriétés du frontmatter comme champs. Les fichiers sont enregistrés au format .base

  16. Obsidian Desktop v1.12.0 Changelog et Obsidian Desktop v1.12.7 Changelog. v1.12.0 a introduit le CLI pour l’automatisation du vault depuis le terminal ; v1.12.7 a amélioré l’empaquetage de l’installation/de l’exécution avec un binaire autonome, une TUI et le comportement des fichiers socket. Consultez également la documentation du CLI

  17. Claudian. Plugin Obsidian qui intègre Claude Code comme collaborateur IA dans le vault. Fournit un chat dans la barre latérale, des prompts tenant compte du contexte, la prise en charge de la vision, des commandes slash et des modes d’autorisation. 

  18. Agent Client. Plugin Obsidian fournissant une interface unifiée pour Claude Code, Codex CLI et Gemini CLI via Agent Client Protocol (ACP). Prend en charge les mentions de notes, l’exécution du shell et l’approbation des actions. 

  19. Obsidian iOS Changelog. Les mises à jour du début 2026 incluent une extension de partage pour enregistrer directement dans le vault le contenu d’autres applications, des correctifs pour les widgets Daily Note et Bookmark, ainsi que des améliorations du rafraîchissement du widget View Note. 

  20. MarkusPfundstein/mcp-obsidian. Activement maintenu — commits jusqu’au 15 mai 2026, avec des travaux récents ajoutant notamment les outils search_by_tag et get_frontmatter, ainsi qu’une couverture de tests étendue (vérifiée à partir de l’historique des commits du dépôt et de tools.py). Toujours sans versions taguées ; installez donc à partir d’un commit épinglé. Basé sur Local-REST-API ; des discussions sur le forum (avril 2026) signalent une migration de la communauté vers le pont CLI Obsidian de première classe (1.12.x) pour les nouvelles configurations, mais mcp-obsidian reste une option opérationnelle et à jour pour les déploiements REST-API existants. 

  21. Smart Connections v4.5.0 Release. 5 mai 2026. Les connexions en pied de page sont devenues une fonctionnalité Core ; les versions récentes de v4 incluent également des vues graphiques pour les listes de connexions, des emplacements configurables pour le panneau de connexions, une meilleure récupération des block embeddings, l’état inter-plugin Substrate, des correctifs de repli des transformers et une réduction des calculs de connexions en double. 

  22. obsidianmd/obsidian-clipper releases — source principale de la correspondance entre versions et fonctionnalités de Web Clipper. Cycle d’avril 2026 : 1.4.0 (9 avr., interface de transcription YouTube + Open in Reader par défaut), 1.5.0 (15 avr., visionneuse Highlights + apparition progressive de Reader), 1.5.1 (15 avr., correctif de compilation webpack), 1.6.0 (21 avr., UX Highlighter + Defuddle 0.18 avec extracteurs LinkedIn/Threads/Bluesky/Discourse/Medium), 1.6.1 (22 avr., correctifs du plan Reader + recherche dans les highlights), 1.6.2 (23 avr., correctif du presse-papiers en mode intégré Safari). Également référencé dans le Mozilla Add-ons store et le Chrome Web Store

  23. sqlite-vec v0.1.8, sqlite-vec v0.1.9, sqlite-vec v0.1.10-alpha.3 et sqlite-vec v0.1.10-alpha.4. v0.1.8 a corrigé l’empaquetage npm ; v0.1.9 a corrigé un bug DELETE pour les colonnes de texte de métadonnées de plus de 12 caractères ; v0.1.10-alpha.3 ajoute une prise en charge correcte de INSERT OR REPLACE INTO ; v0.1.10-alpha.4 (18 mai 2026) corrige l’échec de ALTER TABLE RENAME sur les tables vec0 utilisant les nouvelles fonctionnalités ivf/diskann, ainsi qu’un bug de nettoyage d’instructions mises en cache dans DiskANN. La branche 0.1.10 reste en préversion. 

  24. MCP 2026-07-28 Specification Release Candidate. Annoncée le 21 mai 2026 ; spécification finale publiée le 28 juillet 2026. Plus grande révision de MCP depuis son lancement : cœur de protocole sans état (supprime le handshake initialize et l’en-tête Mcp-Session-Id), Apps MCP (HTML rendu côté serveur dans des iframes client sandboxées), Tasks passant d’un cœur expérimental à une extension officielle (tasks/get, tasks/update, tasks/cancel), renforcement de l’autorisation OAuth 2.0 / OIDC et politique de cycle de vie de dépréciation des fonctionnalités sur 12 mois. 

  25. Obsidian Desktop v1.13.0 Changelog. Accès anticipé, 28 mai 2026. Version axée UX/sécurité/outils de développement : panneau Settings repensé, qui s’ouvre dans sa propre fenêtre avec recherche et navigation au clavier, boîtes de dialogue de confirmation avant le déclenchement des URI Obsidian, nouvelle API Settings pour les développeurs de plugins et correctif CLI pour les installations flatpak. Aucune capacité majeure nouvelle d’IA/d’automatisation au-delà de la surface CLI de la version 1.12.x. 

  26. Obsidian Changelog. Obsidian 1.13.1 desktop a été publiée le 9 juin 2026 comme version Catalyst en accès anticipé — un raffinement de l’UX des paramètres et une mise à niveau de CodeMirror par rapport à 1.13.0, sans nouvelle capacité d’IA/d’automatisation. La page de changelog de 1.13.1 porte elle-même le badge « Early access », et le manifeste officiel de mise à jour automatique (obsidianmd/obsidian-releases, desktop-releases.json) indique la latestVersion publique 1.12.7, avec 1.13.2 sur le canal bêta ; vérifié le 2026-07-21. Revérifié le 2026-07-27 : le manifeste indique toujours latestVersion 1.12.7, avec désormais beta.latestVersion 1.13.4. Le flux Atom sur obsidian.md/changelog.xml attribue à chaque entrée 1.13.x — de 1.13.1 à 1.13.4 — le badge « (Early access) » ; l’entrée la plus récente intitulée « (Public) » reste 1.12.7, datée du 2026-03-23, ce qui correspond à la liste des versions GitHub de obsidian-releases. Revérifié le 2026-08-07 : le manifeste indique désormais latestVersion 1.13.4 (promotion publique le 30 juillet 2026) avec beta.latestVersion 1.13.6 — la branche 1.13 est généralement disponible et les lignes historiques ci-dessus décrivent correctement la période réservée à Catalyst à leurs dates respectives. Revérifié le 2026-08-14 : le manifeste indique latestVersion 1.13.7 avec beta.latestVersion 1.13.7 — les canaux stable et bêta ont convergé. 

VAULT obsidian.md INDEXED