26.1 KB · updated 2026-07-06 · md

v0.2.0.fr.md

docs/i18n/release-notes/v0.2.0.fr.md

Tesserae v0.2.0 — Recherche typée, graphe de code, évolution de l'ontologie

<!-- translations:start -->

English · 한국어 · 中文 · 日本語 · Русский · Español · Deutsch

<!-- translations:end -->

Publié le 2026-05-21 · PyPI · Release GitHub · pip install --upgrade tesserae

Tesserae 0.2.0 est la première version fonctionnelle de la lignée v0.1.0 et propose six fonctionnalités additives sans aucune rupture de compatibilité. Cette release fait passer la surface de recherche de Tesserae de « BM25 sur un graphe typé » à un récupérateur hybride de type HippoRAG-2 avec expansion de germes par Personalized PageRank (PageRank personnalisé), pose les fondations d'un code-en-tant-que-graphe qui relie les insights rédigés aux symboles du code source, et ajoute deux passes d'évolution d'ontologie (résumés de communautés et décroissance mémorielle) ainsi qu'un rapport de dérive de schéma. Ces fonctionnalités s'inscrivent à trois points du flux de travail utilisateur : meilleur rappel au moment de la requête (graph_ppr, hybrid search_nodes), nœuds plus riches au moment de la compilation (ingest-code, résumés de communautés, decay/supersedes), et une boucle d'itération plus rapide sur l'ontologie elle-même (schema-drift).

Table des matières :

  1. MD0 — Personalized PageRank sur le graphe typé
  2. MD0 hybride — BM25 + lexical + embedding via RRF
  3. MD0 — AST Python → graphe de code typé
  4. Résumés de communautés — Louvain + LLM (opt-in)
  5. Scoring de décroissance + MD0 + MD1
  6. MD0 — propositions d'enum EDC
  7. Mise à niveau depuis la v0.1.0
  8. Contexte stratégique

1. graph_ppr — Personalized PageRank sur le graphe typé

Description

Un nouvel outil MCP qui exécute Personalized PageRank (PPR) initialisé à partir d'un ou plusieurs identifiants de nœuds et renvoie les top-k nœuds les plus pertinents par masse de distribution stationnaire. La marche est sensible au type : les arêtes sont pondérées selon leur type de relation, le profil par défaut renforçant les quatre types d'arêtes qui portent le plus de signal « réel » dans un graphe Tesserae — derived_from_session, discussed_in, references et supersedes. Il s'agit de la même primitive d'expansion multi-sauts utilisée par HippoRAG 2, mais adaptée aux arêtes typées de Tesserae plutôt qu'à un graphe de co-occurrence au niveau des passages.

Concrètement, graph_ppr répond à la question « quel est le voisinage de ce nœud, pondéré par les relations qui m'importent vraiment ? » d'une manière inaccessible à un simple BFS ou à BM25. Un germe Decision rapportera les sessions qui l'ont produit, les questions auxquelles il a répondu, les documents qu'il a supplantés, et les concepts dont parlaient ces documents — même si aucun de ces nœuds ne mentionne les mêmes mots-clés.

Utilisation

L'outil est enregistré automatiquement au démarrage du serveur MCP de Tesserae. Depuis n'importe quel client MCP :

// Germe à un seul nœud, α=0.15 par défaut, top-10 résultats
{
  "tool": "graph_ppr",
  "arguments": {
    "seed_node_id": "decision-2026-05-12-switch-to-hybrid-retrieval",
    "top_k": 10
  }
}

// Germe à plusieurs nœuds (un « cluster de concepts »), α et poids d'arêtes personnalisés
{
  "tool": "graph_ppr",
  "arguments": {
    "seed_node_ids": ["concept-rrf", "concept-bm25", "concept-embedding-fusion"],
    "top_k": 25,
    "alpha": 0.2,
    "edge_type_weights": {
      "derived_from_session": 3.0,
      "discussed_in": 2.0,
      "references": 1.5,
      "supersedes": 1.5
    }
  }
}

L'outil renvoie un tableau d'enregistrements {node_id, score, kind, title} triés par masse stationnaire. Depuis une session Claude Code, il suffit de demander à l'agent « utilise graph_ppr en partant de <node> avec top-k 15 » et la skill using-tesserae routera l'appel.

Quand l'utiliser

Tournez-vous vers graph_ppr lorsque :

  • Vous disposez d'un nœud bien identifié (une décision, un article, une trouvaille de session) et avez besoin de son voisinage en termes de distance dans le graphe, et non de ses voisins par correspondance de mots-clés.
  • Vous voulez du rappel multi-sauts — par exemple « tout ce qui se trouve à deux ou trois relations de ce concept, biaisé par les trouvailles issues des sessions ».
  • Le simple search_nodes renvoie le bon nœud mais son contexte lié par references est trop étroit.

Pour une requête en texte libre démarrant d'une phrase, préférez le search_nodes hybride (fonctionnalité 2) ; pour récupérer le contexte textuel d'un nœud connu, préférez node_context.

Emplacement

Implémentation principale : MD0. Enregistrement de l'outil : tesserae/mcp_server.py.

Limitations

  • Les valeurs par défaut α=0.15 (probabilité de redémarrage) et un plafond de 50 itérations sont ajustées pour des graphes de 5k à 50k nœuds, taille typique d'une mémoire de projet. Les très grands graphes (>250k nœuds) peuvent nécessiter un α plus bas et une initialisation sensible au degré des nœuds ; c'est un chantier ultérieur.
  • Les poids d'arêtes sont appliqués symétriquement ; un profil asymétrique (par exemple pondérer references différemment de son inverse) n'est pas encore exposé.
  • L'implémentation est en Python pur et n'embarque aucune nouvelle dépendance d'exécution ; si vous avez une boucle critique appelant graph_ppr des milliers de fois au cours d'une même session, envisagez de mettre en cache la matrice stochastique en colonnes entre les appels.

2. search_nodes hybride — BM25 + lexical + embedding via RRF

Description

L'outil MCP search_nodes existant s'est doté d'un paramètre mode et d'un récupérateur fusionné en dessous. Le nouveau défaut, mode="hybrid", exécute trois récupérateurs en parallèle — BM25 (la base v0.1.0), lexical (chevauchement de tokens / sous-chaîne) et embedding (similarité sémantique) — et les fusionne via Reciprocal Rank Fusion (RRF(d) = Σ 1/(k + rank_i(d)), k=60, la constante de Cormack et al. 2009). C'est la même recette de fusion qu'utilisent la recherche locale de Microsoft GraphRAG et le mode hybride de LightRAG.

Le paramètre mode accepte :

ModeRécupérateurs utilisés
hybrid (par défaut)BM25 + lexical + embedding, fusionnés via RRF
lexicalLexical uniquement
bm25BM25 uniquement
embeddingEmbedding uniquement
legacyLe classement exact de v0.1.0 — préservé bit à bit

Le backend d'embedding s'autodétecte dans cet ordre : si sentence-transformers est importable, il charge sentence-transformers/all-MiniLM-L6-v2 (384 dimensions, ~80 Mo, licence MIT, aucun appel réseau après le premier téléchargement). Sinon, il bascule sur une projection déterministe à buckets de hachage — utilisable, sans dépendance et reproductible, mais avec un rappel sémantique plus faible.

Un nouvel outil MCP compagnon, embedding_status, signale quel backend est actif afin de pouvoir vérifier si vos scores hybrides bénéficient de vrais embeddings ou s'exécutent sur le repli par buckets de hachage.

Utilisation

// Nouveau défaut — fusionné, renvoie le top 10
{
  "tool": "search_nodes",
  "arguments": { "query": "RRF fusion constant choice", "top_k": 10 }
}

// Forcer un seul récupérateur pour une ablation
{ "tool": "search_nodes", "arguments": { "query": "RRF fusion", "mode": "bm25" } }

// Revenir au comportement v0.1.0 bit à bit
{ "tool": "search_nodes", "arguments": { "query": "RRF fusion", "mode": "legacy" } }

// Vérifier quel backend d'embedding est actif
{ "tool": "embedding_status", "arguments": {} }

Pour obtenir le véritable backend sentence-transformers au lieu du repli par buckets de hachage :

pip install 'sentence-transformers>=2.7'
# Le premier appel télécharge les poids MiniLM (~80 Mo) dans le cache HF ; les appels suivants sont hors ligne.

Quel mode utiliser et quand

  • hybrid pour tout, par défaut. RRF est robuste au cas où un récupérateur renvoie du bruit, car l'amortissement par rang réciproque borne la contribution de tout récupérateur unique.
  • bm25 lorsque la requête est essentiellement un tag ou un slug structurel (concept-rrf, decision-2026-05-12-…) — la correspondance exacte domine et les embeddings ajoutent du bruit.
  • embedding lorsque la requête est une paraphrase ou une question, et que les nœuds correspondants emploient un vocabulaire très différent.
  • legacy pour des ablations contre une base v0.1.0, ou comme issue de secours si une régression isolée apparaît.

Emplacement

Implémentation principale : MD0.

Limitations

  • Le repli par buckets de hachage est reproductible mais offre un rappel sémantique limité sur les paraphrases — embedding_status rend ce choix visible.
  • La constante RRF actuelle est fixée à 60 ; la rendre configurable par appel est une petite évolution si vous souhaitez tester d'autres valeurs.
  • La mise en cache des embeddings est par-processus ; un magasin d'embeddings persistant (Lance/SQLite-vec) est un candidat pour une future v0.3.

3. tesserae project ingest-code — AST Python → graphe de code typé

Description

Une nouvelle sous-commande CLI qui parcourt un dépôt Python en utilisant le module ast de la bibliothèque standard et émet cinq types de nœuds typés et cinq types d'arêtes :

NœudsArêtes
CODE_FILE, CODE_MODULE, CODE_CLASS, CODE_FUNCTION, CODE_METHODcontains, calls, imports, inherits_from, declared_in

Le résultat est persisté dans .tesserae/code-graph.json et ingéré par le prochain tesserae project compile, de sorte que les symboles du code deviennent des nœuds de graphe de premier ordre auxquels vous pouvez vous référer depuis votre prose, rechercher via search_nodes, étendre via graph_ppr et visualiser aux côtés des concepts et des articles. Cela pose les fondations pour relier les décisions aux symboles qui les ont mises en œuvre — un créneau qu'aucun autre outil PKM-AI ne comble actuellement.

Utilisation

# Depuis un projet Tesserae activé
tesserae project ingest-code

# Ou contre une racine arbitraire
tesserae project ingest-code --root ./my-package

# Ensuite, un compile normal récupère le nouveau code-graph.json
tesserae project compile

Après le prochain compile, les nœuds de code deviennent interrogeables :

tesserae ask "Where is the RRF fusion implemented?"

…et l'agent peut cheminer depuis un nœud Decision rédigé vers la CODE_FUNCTION qui l'implémente via les arêtes references / declared_in.

Quand l'utiliser

  • Vous voulez que les décisions et trouvailles renvoient aux symboles réels qu'elles évoquent, et pas seulement au README qui les mentionne.
  • Vous voulez une recherche sensible au code sans configurer un index de recherche de code séparé — les mêmes outils search_nodes + graph_ppr couvrent désormais à la fois la prose et le code.
  • Vous utilisez l'intégration Understand-Anything mais souhaitez un graphe de code plus léger et sans dépendance qui vit dans le graphe Tesserae principal plutôt que dans un JSON annexe.

Emplacement

Implémentation principale : MD0.

Limitations

  • Python uniquement en v0.2.0. L'extracteur est structuré pour ajouter des analyseurs par langage ultérieurement ; TypeScript / Rust / Go sont sur la feuille de route v0.3.
  • Les arêtes calls se résolvent par recherche de nom dans la portée du même module ; la résolution d'appels inter-modules utilise les alias d'import mais ne fait pas d'inférence de type complète. Attendez-vous à un taux modéré de faux positifs sur les noms très surchargés — convenable pour la recherche, pas pour le refactoring.
  • Les décorateurs sont enregistrés dans les attributs du nœud décoré mais ne génèrent pas (encore) leur propre type d'arête.

4. Résumés de communautés — Louvain + LLM (opt-in)

Description

Une passe post-compile optionnelle qui exécute la détection de communautés Louvain sur le graphe typé, puis demande au LLM de produire un résumé d'un paragraphe par communauté de taille ≥ 4. Chaque résumé est matérialisé en nœud COMMUNITY_SUMMARY, relié à ses membres par des arêtes summarizes, et mis en cache via le SHA de la liste des identifiants membres, de sorte qu'un re-compile ne ré-résume que les communautés dont l'appartenance a réellement changé. C'est le même schéma utilisé par Microsoft GraphRAG pour faire émerger « de quoi parle ce cluster ? » au moment de la requête.

Un nouvel outil MCP, list_communities(min_size, limit), renvoie les nœuds de résumés de communautés classés par nombre de membres afin que vous puissiez parcourir la macro-structure du graphe sans le charger.

Utilisation

Activez-le via une variable d'environnement, puis compilez :

export TESSERAE_COMMUNITY_SUMMARIES=true
tesserae project compile

Puis interrogez les résumés obtenus :

{ "tool": "list_communities", "arguments": { "min_size": 5, "limit": 20 } }

Ou suivez les arêtes summarizes d'un nœud de résumé de communauté vers ses membres via node_context.

Quand l'activer

  • Vous avez un graphe moyen à grand (>500 nœuds en règle générale) et souhaitez une table des matières au niveau du cluster.
  • Vous voulez des étiquettes de clusters écrites par le LLM associées aux groupes de couleur de la vue graphe dans le site statique.
  • Vous produisez des digests périodiques (hebdomadaires / mensuels) et voulez une section « macro-structure » qui ne se met à jour que lorsque l'appartenance a réellement évolué.

Si votre graphe est petit (un README de projet unique + une poignée de docs), les nœuds structurels Synthesis couvrent déjà ce besoin — les résumés de communautés ajoutent du bruit, pas du signal.

Emplacement

Implémentation principale : MD0.

Limitations

  • Désactivé par défaut — Louvain + la summarization LLM ajoutent du temps réel d'exécution, et le coût LLM n'est pas négligeable pour des graphes comportant beaucoup de communautés. Le cache amortit ce coût sur les re-compiles.
  • L'appartenance aux communautés est non déterministe entre les graines Louvain ; la passe fige la graine pour la reproductibilité au sein d'un projet, mais les comparaisons d'identifiants de communautés entre projets ne sont pas significatives.
  • Le prompt de résumé est générique ; des surcharges de prompt par domaine sont un suivi planifié.

5. Scoring de décroissance + supersedes + fresh_insights

Description

Deux primitives complémentaires, toutes deux inspirées du modèle de mémoire à décroissance d'Ebbinghaus d'A-MEM :

Le scoring de décroissance attribue à chaque nœud de trouvaille de session (Insight / Decision / Question / TODO / Hypothesis / Takeaway) un decay_score ∈ (0, 1] continu, en utilisant la courbe d'oubli classique :

decay_score = exp(-ln(2) · age_days / half_life)

La demi-vie par défaut est de 14 jours, et un incrément d'access_count (à chaque fois que le nœud est remonté par ask ou fresh_insights) ralentit encore la décroissance. Les horodatages des décisions structurelles sont dérivés de la session parente afin que les trouvailles rétro-importées obtiennent un âge sensé.

La passe supersedes est une étape post-compile optionnelle qui trouve les trouvailles de session quasi-dupliquées via une similarité de Jaccard sur les shingles titre + contenu, puis demande au LLM de juger si la plus récente supplante réellement la plus ancienne. Une paire confirmée reçoit une arête supersedes et le decay_score effectif du nœud le plus ancien est supprimé.

Un nouvel outil MCP, fresh_insights(limit, kind), renvoie les meilleures trouvailles par decay_score courant, en excluant les nœuds supplantés. C'est la requête canonique « que doit prioriser l'agent parmi les sessions passées ? ».

Utilisation

Le scoring de décroissance s'exécute automatiquement à chaque compile. Pour activer la passe supersedes :

export TESSERAE_SUPERSEDE_PASS=true
tesserae project compile

Puis interrogez les trouvailles non supplantées les plus fraîches :

{
  "tool": "fresh_insights",
  "arguments": { "limit": 15, "kind": "Decision" }
}

Ou omettez kind pour obtenir un flux mixte sur tous les types de trouvailles de session.

Quand activer la passe supersedes

  • Vous accumulez des sessions chaque semaine et vos requêtes Decision / Hypothesis commencent à renvoyer des entrées périmées et contradictoires.
  • Vous voulez que le flux de rappel using-tesserae de l'agent privilégie « voici la pensée actuelle sur X » plutôt que « tout ce que nous avons jamais pensé sur X ».
  • Le coût est acceptable : chaque compile paie une passe Jaccard (peu coûteuse) plus N appels de juge LLM pour les paires candidates au-dessus du seuil Jaccard (mis en cache par hash de contenu).

Si vous n'avez que quelques semaines de sessions, la décroissance seule suffit généralement — l'arête supersedes est une optimisation pour les graphes plus anciens et plus denses.

Emplacement

  • Scoring de décroissance : MD0
  • Passe supersedes : MD0

Limitations

  • La demi-vie de 14 jours est un défaut raisonnable pour les projets de recherche actifs ; les graphes d'archivage à long horizon peuvent préférer 60-90 jours. Une table de demi-vies par type est une fonctionnalité planifiée pour v0.3.
  • La génération de candidats Jaccard utilise une taille de shingle fixée à 5 ; les trouvailles très courtes (Takeaways d'une phrase) peuvent sous-clusteriser.
  • Le juge LLM de supersedes est conservateur par conception — les faux négatifs (doublons manqués) priment sur les faux positifs (arêtes supersedes incorrectes).

6. tesserae project schema-drift — propositions d'enum EDC

Description

Une nouvelle sous-commande CLI qui aide l'ontologie à évoluer en même temps que le corpus. Elle implémente le pattern EDC (Extract-Define-Canonicalize, EMNLP'24) : pour chaque type de nœud à fort volume, elle clusterise par Jaccard les membres selon les shingles titre+contenu, puis demande au LLM de proposer des sous-types en PascalCase avec un court argumentaire et trois aperçus représentatifs de membres par cluster. La sortie est écrite dans .tesserae/schema-drift.md sous forme de checklist d'ajouts d'enum copiables-collables vers les fichiers d'ontologie de ontology/.

Les propositions du LLM sont mises en cache atomiquement (écriture dans un fichier temporaire puis renommage) et indexées par le SHA des identifiants des membres du cluster, de sorte que ré-exécuter la passe est peu coûteux et converge vers les mêmes propositions tant que le corpus est inchangé.

Utilisation

tesserae project schema-drift
# → écrit .tesserae/schema-drift.md

Ouvrez ensuite le rapport, examinez les enums proposés (chaque bloc est un littéral Python copiable-collable), et collez ceux que vous acceptez dans le fichier pertinent sous ontology/. Le prochain tesserae project compile validera contre le schéma mis à jour.

Quand l'utiliser

  • Après un grand lot de nouveaux docs / sessions, avant de promouvoir une nouvelle valeur de type de nœud en enum de premier ordre.
  • Périodiquement (mensuellement) sur les projets de longue durée, pour faire émerger la dérive d'ontologie — le rapport est rapide et en lecture seule.
  • Comme artefact de transmission : le markdown est autonome, vous pouvez donc le confier à un relecteur (ou à un autre agent) sans avoir à configurer toute la CLI Tesserae.

Emplacement

Implémentation principale : MD0.

Limitations

  • Les propositions sont des suggestions — c'est l'humain (ou un agent en aval) qui décide quels clusters deviennent de véritables valeurs d'enum. La passe ne modifie délibérément pas ontology/ d'elle-même.
  • Le clustering Jaccard partage la même hypothèse de taille de shingle que la passe supersedes ; les membres très courts peuvent clusteriser moins nettement.
  • La passe se concentre sur les types à fort volume ; les types rares (≤ 3 membres) sont ignorés pour éviter les enums spéculatifs.

Mise à niveau depuis la v0.1.0

pip install --upgrade tesserae

C'est toute la mise à niveau — v0.2.0 est additive et sans rupture de compatibilité. Quelques options optionnelles méritent d'être connues :

Variables d'environnement pour les passes optionnelles :

# Active la passe post-compile de résumé de communautés (fonctionnalité 4)
export TESSERAE_COMMUNITY_SUMMARIES=true

# Active la passe supersedes pour les quasi-doublons (fonctionnalité 5)
export TESSERAE_SUPERSEDE_PASS=true

Le seul changement de surface MCP à connaître : search_nodes adopte désormais par défaut mode="hybrid". Si vous avez une automatisation qui dépendait du classement v0.1.0 exact, passez mode="legacy" — le chemin legacy est préservé bit à bit.

Nouvelle dépendance Python optionnelle pour le véritable backend d'embedding :

pip install 'sentence-transformers>=2.7'

Si vous l'omettez, search_nodes mode="hybrid" fonctionne toujours (repli par buckets de hachage) ; embedding_status signalera hash-bucket au lieu de minilm-l6-v2 afin que le choix soit observable.

Nouvelles sous-commandes CLI à intégrer à vos réflexes :

tesserae project ingest-code      # crée les nœuds de code (fonctionnalité 3)
tesserae project schema-drift     # propose des enums d'ontologie (fonctionnalité 6)

Nouveaux outils MCP désormais disponibles pour l'agent :

  • graph_ppr (fonctionnalité 1)
  • embedding_status (fonctionnalité 2)
  • list_communities (fonctionnalité 4)
  • fresh_insights (fonctionnalité 5)

Tout le reste — slash commands, hooks, ask, la projection wiki / Obsidian — est inchangé.


Contexte stratégique

v0.2.0 aligne structurellement Tesserae sur l'état de l'art 2026 en matière de GraphRAG / mémoire d'agent :

  • La recherche hybride (BM25 + lexical + embedding via RRF) est la même recette de fusion qu'utilisent la recherche locale de Microsoft GraphRAG et le mode hybride de LightRAG.
  • L'expansion de germes par Personalized PageRank est la primitive multi-sauts au cœur d'HippoRAG 2, adaptée ici à des arêtes typées plutôt qu'à la co-occurrence de passages.
  • Les résumés de communautés reflètent le niveau de résumé de cluster de Microsoft GraphRAG — la couche qui donne une réponse rapide et structurelle aux requêtes « de quoi parle globalement ce corpus ? ».
  • Le scoring de décroissance + supersedes est le modèle d'Ebbinghaus d'A-MEM appliqué à la mémoire de projet ; la passe supersedes est plus proche dans l'esprit des opérations mémoire « ADD / UPDATE / DELETE » de Mem0, mais exprimée comme une arête pure plutôt que comme une réécriture en place.
  • La dérive de schéma via EDC est la même idée Extract-Define-Canonicalize d'EMNLP'24, appliquée à l'évolution d'ontologie plutôt qu'à l'extraction de relations.

Ce qui reste spécifique à Tesserae et constitue un créneau défendable : des arêtes typées partout, les trouvailles de session en tant que nœuds de graphe de premier ordre, et (désormais) les symboles de code à l'intérieur de ce même graphe. La plupart des concurrents du paysage 2026 sont entièrement dépourvus d'arêtes typées ; parmi ceux qui en ont, aucun ne relie les décisions rédigées aux symboles de code — les fondations feat/code-graph posées en v0.2.0 sont l'endroit où ce créneau commence à se cumuler.

À voir également :