Sophonix
Blog
Contact
Notes de terrain

BenBrain : mémoire persistante pour chaque session Claude

Publié 10 mai 2026#AIInfrastructure #ClaudeAI #VectorDatabase #KnowledgeGraph #BuildInPublic

Chaque session Claude que j'ouvre — téléphone, ordinateur portable, n'importe où — se réveille déjà en sachant ce qui a été livré hier et ce qui reste ouvert.

Ce n'était pas le cas il y a un mois.

Il y a un mois, chaque nouvelle conversation démarrait à froid. J'ouvrais un onglet, posais une question, et Claude me rencontrait comme un inconnu. Je brûlais les dix premières minutes à ré-expliquer le projet, la stack, les décisions de la semaine précédente, le bug qu'on avait traqué à 2h du matin. Le temps que le modèle ait assez de contexte pour être utile, mon énergie mentale pour le vrai travail était déjà à moitié dépensée.

C'est la taxe du démarrage à froid. C'est la friction qui fait que « l'IA comme partenaire de réflexion » ressemble à une promesse qui ne se concrétise jamais vraiment. Chaque session repart d'une page blanche : il faut replanter le décor.

Je l'ignorais parce que je supposais que c'était simplement la nature de l'outil. Les LLMs n'ont pas de mémoire entre les sessions ; c'est le deal. Alors on s'adapte — on épingle un long préambule dans son éditeur, on maintient un document « état du projet » à jour, on le colle au début de chaque chat. Et puis on oublie quelle version de ce document contient l'état vraiment actuel, et on perd encore dix minutes à réconcilier.

À un moment, il est devenu moins coûteux de corriger l'outil que de continuer à payer la taxe.

Ce que j'ai construit

BenBrain est une couche de mémoire persistante qui se trouve derrière chaque session Claude. Ce sont deux stores, tous deux hébergés sur mon serveur bare-metal en Europe, tous deux derrière mon mesh Tailscale, et aucun des deux ne parle à qui que ce soit d'autre.

Qdrant — le vector store. Des embeddings de tout ce qui a jamais été écrit. Décisions, tentatives, erreurs, apprentissages. Le rôle est le rappel flou : « qu'avons-nous décidé à propos de ce crash OOM il y a trois semaines ? » fonctionne même quand les mots que j'utilise aujourd'hui ne correspondent pas à ceux que j'utilisais alors. La similarité cosinus sur l'espace d'embedding est indulgente d'une manière que la recherche textuelle ne l'est pas.

Neo4j — le knowledge graph. Même contenu, découpe différente. Chaque décision, tentative, erreur, module, session et apprentissage est un nœud typé avec des relations typées vers d'autres nœuds. Une Decision a un Why, bloque une Error, remplace une autre Decision. Navigable comme un graphe : depuis n'importe quel point de départ, on peut demander « qu'est-ce qui a mené à ça ? » et suivre les arêtes en arrière.

Le vector store gère « trouve-moi des choses comme ça ». Le graphe gère « montre-moi comment ça s'articule ». Des questions différentes, des formes différentes, la même source de données.

Voici la forme approximative d'une entrée dans le graphe :

{
  "id": "sophonix:decision:notion-as-blog-cms",
  "type": "Decision",
  "title": "Sophonix blog content lives in Notion, not in-repo MDX",
  "body": "Article rich text + media live in Notion page blocks; the build pulls them at next build and mirrors assets to public/blog/ so deploys are self-contained.",
  "severity": "informational",
  "created_at": "2026-05-11T16:42:00Z",
  "relations": {
    "supports": ["sophonix:initiative:linkedin-pipeline"],
    "informed_by": ["sophonix:learning:notion-rich-text-limits"],
    "blocks": []
  }
}

C'est la donnée. La partie intéressante, c'est la boucle qui la remplit.

La boucle, en quatre étapes

  1. Je lance /compact quand le contexte d'une session commence à se remplir. C'est la seule étape manuelle, et j'expliquerai pourquoi elle reste manuelle.
  2. Un hook lit la transcription. Un hook SessionEnd dans Claude Code capture l'intégralité de la conversation et la fait passer par un prompt d'extraction structurée vers GPT-4o. Le prompt demande des entrées typées : quelles décisions ont été prises, quelles tentatives ont réussi ou échoué, ce qui a été appris et qui n'était pas évident depuis le code seul.
  3. Les entrées sont écrites dans les deux stores. Le JSON extrait est embarqué et indexé dans Qdrant. Les mêmes entrées deviennent des nœuds typés dans Neo4j avec des relations vers le contexte environnant. Une décision référence les tentatives qui ont conduit à elle. Une erreur référence les décisions qui l'ont empêchée de se reproduire.
  4. La session suivante se réveille avec cette mémoire en préambule. Un hook SessionStart interroge les deux stores — entrées récentes, plus une recherche par similarité basée sur le projet courant et les todos ouverts — et injecte les résultats comme contexte d'ouverture. Le temps que je tape le premier message, Claude sait déjà où on en était.

Une commande de ma part. Tout le reste tourne tout seul.

Pourquoi du bare-metal

On me pose cette question constamment : pourquoi pas Pinecone, Weaviate, Neo4j Aura ? Pourquoi faire tourner tout ça sur une machine que je dois maintenir moi-même ?

La réponse économique est accessoire. Oui, c'est moins cher, mais ce n'est pas pour ça.

La réponse sur le contrôle, c'est l'essentiel. Cette couche contient chaque décision que je prends : positionnement client, choix d'architecture, compromis de sécurité, idées à demi-formées sur le prochain produit. Rien de tout ça ne devrait vivre sur un serveur que je ne contrôle pas. Pas celui de Pinecone. Pas celui de Neo4j. Pas n'importe qui. La raison pour laquelle je veux une mémoire persistante, c'est pour externaliser ma réflexion — et externaliser sa réflexion dans la base de données de quelqu'un d'autre est un échange strictement moins bon que de ne pas l'externaliser du tout.

Tailscale boucle la boucle. Le serveur n'est accessible qu'à l'intérieur de mon mesh. Il n'y a pas d'ingress public vers la couche de mémoire. Claude Code sur mon ordinateur atteint Qdrant et Neo4j via Tailscale ; rien d'autre n'y a accès. Zéro exposition internet sur le chemin des données.

C'est le même principe qui traverse le travail de conseil chez Sophonix : nous construisons pour nos clients de la même façon que nous construisons pour nous-mêmes. Si je ne ferais pas confiance à un tiers avec mon propre journal de décisions, je ne vais pas recommander à un client d'y faire confiance avec le sien.

Ce qui reste fait à la main

L'étape /compact est à moi de déclencher. C'est un choix délibéré.

L'alternative — capture continue, avec le hook qui se déclenche tous les quelques milliers de tokens de contexte — paraît élégante. Mais elle double les dépenses API sur l'extraction, et cela signifie que le modèle a moins de contrôle sur ce qui constitue une frontière mémorable. Une session qui s'égare sur trois sujets sans rapport est fragmentée en trois entrées incomplètes au lieu d'un fil cohérent. La compaction manuelle laisse à l'humain le soin de décider à quoi ressemble « une seule chose ».

L'oubli est aussi encore fait à la main, dans le sens où rien n'oublie encore. Chaque entrée vit indéfiniment, chaque embedding reste indexé. C'est correct pour l'instant, mais c'est une impasse connue. Une mémoire en append-only se dégrade à la récupération bien avant de se dégrader au stockage : à mesure que le corpus grandit, le signal dans n'importe quelle requête se noie sous le bruit historique. La bonne solution est la décroissance — une récupération pondérée par la récence, peut-être avec des tombstones explicites « ceci n'est plus d'actualité ». Pas encore construit. Journalisé.

La suite

La roadmap, dans l'ordre :

  • Capture continue avec des frontières plus intelligentes. Détecter les changements de sujet dans la transcription et compacter à ces transitions plutôt qu'attendre /compact. Je veux toujours une revue humaine sur les entrées, mais le repère « quoi compacter » peut être automatique.
  • Décroissance et tombstoning. Quand une décision est remplacée, l'ancienne ne devrait pas simplement coexister avec la nouvelle — elle devrait être marquée comme remplacée, et la récupération devrait peser contre son retour.
  • Primitives de partage. Pour l'instant BenBrain est mono-utilisateur. La même architecture pourrait servir une équipe : un petit groupe avec une couche de mémoire partagée, la session de chaque membre contribuant au même graphe. C'est là où le travail de conseil pointe : le même problème de durabilité que BenBrain résout pour moi, chaque équipe finit par le rencontrer.

L'essentiel

L'infrastructure était toujours allumée. Le serveur était là. Le graphe de données, le vector store, le réseau — tout ça existait déjà.

Ce qui a changé, ce n'est pas l'infrastructure. Ce qui a changé, c'est que la réflexion est maintenant allumée aussi. Les décisions ne s'évaporent plus à la fin d'une session. Les erreurs ne sont plus redéboguées six semaines plus tard. Le fil conducteur de « ce qu'on construit et pourquoi » survit aux jours, aux appareils, aux contextes.

C'est cette partie qui compte. Pas la stack. Pas le choix de Qdrant plutôt que Pinecone ou de Neo4j plutôt qu'Aura. Ce sont des notes de bas de page. L'essentiel, c'est qu'un partenaire de réflexion qui se souvient est un type de partenaire différent de celui qui ne se souvient pas — et y arriver s'est avéré tenir à un seul prompt d'extraction, deux stores, et un hook.

Quelle est votre couche de mémoire ?

Mentionnés
  • Qdrant
  • Neo4j
Lire sur LinkedIn
Préférences de cookies

Choisissez ce qui est activé. Nous ne partageons aucune donnée avec des tiers sauf consentement ci-dessous, et vous pouvez le retirer à tout moment.