Relier ses notes de mission : ce qui a marché, ce qui est passé à la trappe
Mon vault Obsidian sert de mémoire à Claude Code. Restait à le relier aux tickets Jira et aux pages Confluence de la mission. Ce que j'ai mis en place, ce que j'ai jeté, et les chiffres des deux.
Le besoin#
Je travaille en mission avec Claude Code. Une session est excellente sur la tâche du jour et parfaitement amnésique sur le reste : elle rouvre le projet sans savoir ce qu'on a tranché la semaine précédente, ni pourquoi. Le contexte, lui, est éclaté sur quatre outils (messagerie d'équipe, Jira, Confluence, la forge), dont chacun ne connaît qu'un bout de l'histoire.
D'où le montage. Un vault Obsidian sert de mémoire : j'y écris mes notes de décision et mes fiches de contexte, et une note de session s'y ajoute à la fin de chaque session de travail. À côté, un index local ingère les quatre sources dans du SQLite avec des embeddings, pour pouvoir les interroger en langage naturel.
L'intérêt n'est pas le confort de relecture. C'est qu'une session qui démarre puisse retrouver la décision d'il y a trois semaines et le ticket qui l'a motivée, au lieu de la redécouvrir ou, pire, de la contredire. J'ai détaillé ce montage et ses garde-fous dans donner une mémoire à Claude Code ; le présent article est le carnet de bord de ce qui s'est passé quand j'ai voulu relier tout ça.
Ce que je voulais mettre en place, c'est le lien entre les deux. Concrètement : partir d'une note de décision et retomber en un clic sur le ticket qui l'a déclenchée, sur la page de spec qui la documente, sur la session de travail où je l'ai appliquée. C'est exactement ce que promet la vue graphe d'Obsidian, où chaque note est un nœud, chaque lien une arête, et où l'on navigue par rebond.
Sauf que mon graphe était vide de sens. 171 notes, dont 81 sans le moindre lien, ni entrant ni sortant. Presque la moitié du vault était un tas de fichiers avec une jolie visualisation par-dessus.
L'idée de départ était simple : j'avais 1120 pages Confluence déjà indexées d'un côté, un vault famélique de l'autre. Il suffisait d'importer les unes dans l'autre.
C'est cette idée-là qui était fausse, et c'est le plus utile de ce que j'ai appris ce jour-là.
Pourquoi l'import brut était une mauvaise idée#
Deux raisons, chiffrées avant d'écrire la moindre ligne.
Le ratio. 1120 pages importées contre 29 notes de matière réellement pensée, c'est 39 nœuds venus d'ailleurs pour 1 nœud à moi. Le graphe cesserait de cartographier ma réflexion pour devenir un miroir dégradé du Confluence du client. Et ce coût-là n'apparaît dans aucune métrique : un graphe noyé affiche d'excellents chiffres de couverture, simplement on ne s'en sert plus.
Les liens morts. Dans Obsidian, un lien vers une note inexistante n'est pas inerte : quand on clique dessus, il crée une note vide. Importer 1828 références dont la cible n'existe pas ne construit pas un graphe, ça pose des mines. J'ai découvert le mécanisme en trouvant une note vide inexplicable dans ma boîte d'entrée.
D'où la règle qui a piloté tout le reste :
Un nœud ne mérite d'exister que s'il porte au moins une arête. Et on n'écrit jamais un lien dont la cible n'existe pas.
Ce que j'ai mis en place#
Des renvois, pas des copies#
Le vault reçoit une note légère par source : titre, lien, clés de tickets citées. Aucun contenu recopié. Une note de renvoi ressemble à ça :
---
type: renvoi-page
page_id: 12345678
url: https://…/pages/12345678
---
# Migration du parcours de paiement
Page Confluence. Cite : [[PROJ-1841]], [[PROJ-1902]]C'est tout, et c'est volontaire. Une page Confluence ou un ticket Jira est mutable et fait autorité. Si je recopie son contenu, ma copie devient fausse en silence : mon vault affirme « en cours » quand le ticket dit « livré depuis trois semaines », et rien ne signale l'écart. Un renvoi ne peut pas périmer, il ne contient que ce qui ne change pas.
Ce que le vault gagne, ce n'est donc pas du contenu. Ce sont des arêtes.
Une seule passe, pas deux#
Premier essai : un job qui crée les renvois de pages, un autre qui crée les renvois de tickets. Chacun fabrique des orphelins pour l'autre. Une page dont aucune clé citée n'a de cible, un ticket que personne ne pointe. Résultat mesuré : 239 nœuds isolés sur 588 créés.
La correction n'a pas été un job de nettoyage, mais une résolution en un seul passage : on calcule l'ensemble des candidats, puis l'ensemble des cibles, et on n'écrit que l'intersection. Zéro orphelin par construction, et un job supprimé au passage.
Les renvois vivent dans un dossier caché#
Ils sont rangés dans des dossiers _renvois/ que le code de listing ignorait déjà. Conséquence : invisibles dans la liste des fiches et dans la recherche, visibles dans le graphe. C'est ce qui rend l'opération supportable. Les 1160 renvois n'écrasent ni l'interface ni la pertinence de la recherche, ils n'existent que comme structure.
Une convention de nommage de dossier a remplacé ce qui aurait été un champ en base et une migration.
La chronologie pour les notes que rien ne pouvait sauver#
Restaient 76 notes de session qui ne citaient aucun ticket. Aucun enrichissement ne pouvait les relier, sauf la seule relation déjà présente dans la donnée : le temps. Chaque note pointe la précédente du même projet. Une chaîne par projet.
Les chiffres#
| Avant | Après | |
|---|---|---|
| Arêtes dans le graphe | 276 | 1074 |
| Clés de tickets restées en texte brut | 413 | 13 |
| Notes orphelines (hors renvois) | 81 | 6 |
| Renvois isolés | 239 | 0 |
Les 6 orphelines restantes sont explicables une par une : gabarits, note racine, projet à session unique.
Ce qui est passé à la trappe#
L'import complet de la documentation#
Refusé sur le ratio 39:1 décrit plus haut. C'est le KO le plus structurant : il a transformé un projet d'import en projet de filtrage.
Les étiquettes Jira transformées en tags#
L'idée semblait évidente : les tickets portent des labels, faisons-en des tags Obsidian, ils relieront les notes. Mesure du vocabulaire réel avant de coder : 225 valeurs distinctes, dont les plus fréquentes sont des noms d'équipe (596 occurrences) et des statuts de recette (qa-regression, 327 occurrences).
Ce ne sont pas des tags thématiques, c'est du vocabulaire de process. En tag, qa-regression deviendrait un hub reliant 327 tickets sans aucun rapport entre eux. Elles sont donc restées en propriété de frontmatter : visibles et cherchables, mais hors du graphe.
La hiérarchie des pages Confluence#
Confluence est un arbre, chaque page a un parent. Arête gratuite, venue de la source, aucune inférence. Séduisant.
Échantillon de 30 pages pour vérifier : les 30 ont bien un parent, mais un seul de ces parents fait partie des pages retenues. Les autres sont des pages de sommaire, qui ne citent aucun ticket et sont donc écartées. Rendement projeté : environ 4 arêtes pour 117 appels d'API. Abandonné.
L'échantillon a coûté deux minutes et évité une fonctionnalité entière.
Les pages qui citent trop de tickets#
Une page de revue de backlog citait 182 tickets. Sur le corpus : médiane à 3 clés, 90e centile à 11, maximum à 182. Un nœud à 182 arêtes ne relie pas, il relie tout à tout. Plafond posé à 12, ce qui écarte 30 pages sur 313.
Et ce qui reste KO aujourd'hui#
Deux choses, autant les dire.
Le vault est passé à 1275 notes dont 1160 renvois, soit 91 %. Ma matière écrite reste à 96 notes, soit un rapport de douze pour un. Ça tient parce que les renvois sont tous connectés, tous hors de l'interface et de la recherche, et qu'aucun ne recopie une source. Ça reste une tension, pas une victoire.
Et le plafond à 12 ne s'applique qu'aux pages. Un nœud d'épic regroupe déjà 281 tickets. La différence est que ce regroupement est légitime : ces 281 tickets appartiennent réellement au même chantier. Ce plafond-là reste à écrire.
Les pièges qui m'ont coûté du temps#
Neuf, tous rencontrés dans la même journée.
set -euo pipefailplus un chemin inexistant.find "$A" "$B" | grep -q .où$Bn'existe pas :findsort en erreur,pipefailpropage, la condition ne se déclenche jamais. Ma déduplication ne s'est jamais exécutée, silencieusement.- Un lien mort crée un fichier. Déjà dit, mais c'est le piège qui justifie toute l'architecture.
- Une clé de ticket dans une URL se fait réécrire. Obsidian transforme
PROJ-19422en lien, y compris dans une URL Confluence dont le titre contient la clé. Ma détection de doublon comparait les URL. Elle échouait donc exactement sur les fiches créées par la fonctionnalité elle-même. Corrigé en comparant l'ID numérique de la page. - Un index qui saute l'écriture des métadonnées. L'indexation sort tôt quand l'empreinte du texte est inchangée. Ajouter un champ et réingérer ne le fait donc pas apparaître. Contournement gratuit : les métadonnées voulues étaient déjà dans le texte indexé, il suffisait de les y relire.
- Un code hexadécimal est une syntaxe de tag.
#0B1822est une couleur CSS ; dans Obsidian,#motest un tag. Dix-sept couleurs citées dans des notes étaient devenues dix-sept nœuds. - Un curseur incrémental transforme un ajout en no-op. L'ingestion filtre sur
modifié_depuis >= curseur. Brancher une nouvelle source sans remettre le curseur à zéro ramène zéro document, et le job se déclare réussi. - Une ingestion ciblée ne doit pas avancer le curseur. Le piège inverse : rattraper 657 vieux documents par identifiants explicites et avancer le curseur au passage ferait sauter des mises à jour récentes.
- Restreindre les outils d'un process automatisé n'en restreint qu'une partie. Vérifié par sonde : le drapeau censé tout désactiver ne coupe que les outils intégrés, pas les serveurs d'outils externes déclarés en configuration. Un process censé résumer un texte avait encore de quoi envoyer un e-mail. Une restriction de privilèges se vérifie par test, jamais par la doc du drapeau.
- Un binaire compilé obsolète qui écoute le port. Une heure à ne pas comprendre un 404 sur une route neuve : le serveur en écoute était un build de trois jours.
lsof -i :portpuispssur le PID auraient économisé l'heure.
Ce que je retiens#
- Ne jamais copier une source mutable dans sa base de connaissance. Stocker un renvoi.
- Créer un nœud seulement là où une arête va atterrir, et une arête seulement si sa cible existe.
- Séparer l'index de recherche de la couche écrite à la main. Le premier peut être énorme et jetable, la seconde est petite et précieuse. Les mélanger détruit la seconde.
- Mesurer le rendement d'une idée avant de l'implémenter. Trois pistes évaluées en quelques minutes, deux abandonnées sur les chiffres.
- Le nettoyage après coup est un aveu de conception. Passer de « je génère puis je purge les orphelins » à « je ne peux pas générer d'orphelin » a supprimé un job entier.
Rien de tout ça n'est propre à Obsidian. C'est le même arbitrage sur n'importe quel système qui agrège des sources : la question n'est jamais « qu'est-ce que je peux importer ? », mais « qu'est-ce qui va rester relié ». Quand on branche un agent sur des outils internes, construire un serveur MCP pose les mêmes questions de périmètre, une couche plus bas.
Vous avez un système qui agrège plus de données qu'il n'en rend exploitables ? C'est le genre d'arbitrage que je pose en mission de CTO à temps partagé. Prenons 30 minutes pour en discuter.
Articles similaires
Donner une mémoire à Claude Code : l'architecture que j'utilise en mission
Une session Claude Code est excellente sur la tâche du jour et amnésique sur tout le reste. Voici le montage qui lui donne une mémoire : un vault Obsidian, des notes de session, et trois étages qu'il ne faut jamais confondre.
Claude Code vs Cursor : quel outil IA choisir pour coder en 2025 ?
Comparaison détaillée entre Claude Code (CLI agentique) et Cursor (IDE augmenté) : philosophie, workflow, prix et cas d'usage pour faire le bon choix.
BAD-BMAD : quand l'IA gère tout votre sprint sans vous
BAD (BMad Autonomous Development) orchestre un sprint complet de façon entièrement autonome - spec, code, tests, PR, review - sans intervention humaine. Voici pourquoi c'est bluffant.