Ajouter une mémoire de session comme dans OpenClaw


Lundi matin. Vous ouvrez Claude Code sur un bug complexe que vous aviez laissé en suspens vendredi. Claude ne se souvient de rien. Vous ré-expliquez le contexte, re-décrivez l'architecture, re-listez ce qui a été essayé. Quinze minutes perdues avant de pouvoir reprendre où vous en étiez.

C'est exactement le problème que résout la mémoire de session — et c'est ce qu'OpenClaw a résolu en premier.


Qu'est-ce qu'OpenClaw ?

OpenClaw est un framework open source conçu pour Claude Code. Son objectif : transformer Claude d'un assistant sans mémoire en un agent autonome persistant, capable de se souvenir de ce qu'il a fait, de ce qui a été décidé, et de ce qui reste à faire.

OpenClaw fonctionne entièrement en Markdown et Python, sans base de données, sans dépendance externe. Sa philosophie : les fichiers plats, versionnables et lisibles par un humain, sont la meilleure mémoire à long terme.

Son architecture mémoire repose sur trois niveaux : - Mémoire immédiate — le contexte chargé dans la session courante - Logs quotidiens — ce qui s'est passé aujourd'hui (et hier) - Mémoire long terme — les faits durables, condensés et maintenus à jour

J'ai adapté cette architecture pour mes projets Claude Code : un Stop hook qui tourne automatiquement après chaque échange, deux fichiers Markdown par projet (long_memory.md + un log par jour), et deux skills pour charger et consolider la mémoire. Voici comment ça fonctionne et comment le mettre en place.


Pourquoi c'est un vrai plus par rapport à Claude par défaut

Claude Code dispose bien d'une mémoire automatique native — mais elle a deux limites importantes :

Mémoire auto Claude Code Système OpenClaw-style
Emplacement ~/.claude/projects/... (machine locale) Dans le repo git du projet
Portabilité Non — liée à la machine Oui — suit le repo partout
Versionnement Non Oui — git log sur la mémoire
Granularité Globale Par projet / sous-projet
Inspectable Difficilement Markdown lisible directement

Le CLAUDE.md est une autre solution, mais c'est un fichier de règles statiques — pas un journal d'activité. Il ne trace pas ce qui a été fait, les problèmes rencontrés, ni les décisions prises en cours de session.

La mémoire de session comble ce vide : elle capture automatiquement, à chaque échange, ce qui s'est passé. Sans que vous ayez à y penser.


Architecture

Le système repose sur deux types de fichiers Markdown, un hook Stop, et un modèle Haiku qui fait l'extraction.

Structure des fichiers

projet/
  memory_sessions/
    long_memory.md          ← mémoire long terme (condensé permanent)
    logs/
      2026-03-22.md         ← log quotidien structuré par sections
      2026-03-21.md
      archives/             ← logs > 30 jours
      .debug/               ← JSON brut Haiku (gitignored)

Pour un workspace multi-projets, chaque sous-projet a son propre répertoire memory_sessions/ — la mémoire de cmms_doc ne se mélange pas avec celle de competitors.


Template 1 — Le log quotidien (logs/2026-03-22.md)

Un fichier par jour, structuré en sections fixes. Haiku y ajoute des bullets à chaque échange — sans jamais dupliquer ce qui existe déjà.

# Log session — 2026-03-22

## Contexte
- Refonte du système de mémoire de session pour le workspace PRODUCT_AGENTS.

## Objectif
- Tester le nouveau format JSON structuré retourné par Haiku.

## Problèmes rencontrés
- Extraction du transcript échouait : messages tool_result filtrés incorrectement.

## Connaissances acquises
- Le transcript JSONL contient beaucoup de messages à contenu vide (tool_use, thinking) — filtrer sur `content[].type == "text"`.

## Travail produit
- Réécriture du parser de transcript dans memory-session.sh.
- Ajout du répertoire .debug/ pour inspecter le JSON brut Haiku.

## Décisions prises
- Appeler `claude` depuis `/tmp` pour éviter que le CLAUDE.md du projet interfère.

## À suivre
- Valider que la découverte des skills fonctionne après le patch.

## Finalisé
- ✅ Valider que la découverte des skills fonctionne après le patch.

Chaque section a un rôle précis. La section Finalisé reçoit les points résolus de « À suivre » — déclenchés quand vous envoyez OK-done à Claude.


Template 2 — La mémoire long terme (long_memory.md)

Un condensé permanent, limité à 300 lignes. Ce n'est pas un log — c'est ce que Haiku juge durable : faits techniques, règles métier, décisions structurantes.

# Mémoire long terme — cmms_doc

## 2026-03-09
- Le hook memory-session.sh doit appeler `claude` depuis /tmp (pas depuis le projet) pour éviter l'injection du CLAUDE.md hôte dans la réponse Haiku.
- Format intermédiaire retenu : JSON structuré par sections → Python formate le Markdown.
- Déduplication gérée par Haiku qui relit le log existant avant d'écrire.

Quand long_memory.md dépasse 300 lignes, le skill /memory_promotion consolide et archive les entrées les plus anciennes.


Le mécanisme : le log quotidien nourrit la mémoire long terme

Échange Claude
    ↓
Haiku analyse : quoi retenir dans le log du jour ?
    ↓
Log quotidien mis à jour (sections append, déduplication)
    ↓
Si fait durable détecté → long_memory.md mis à jour
    ↓
/memory_promotion (hebdo/mensuel) → archive les logs anciens,
    consolide long_memory.md si > 300 lignes

Le flux du hook (version simplifiée)

Le déclencheur central est un Stop hook — un script Shell qu'exécute automatiquement Claude Code à la fin de chaque tour de conversation.

Claude répond
    ↓
Stop hook déclenché (settings.json)
    ↓
[Anti-boucle] stop_hook_active = true ? → exit 0
    ↓
Parser le transcript JSONL → extraire le dernier échange humain + assistant
    ↓
Lire les logs existants du jour (pour ne pas dupliquer)
    ↓
Appeler Haiku depuis /tmp avec le prompt structuré
    ↓
Haiku retourne un JSON par sections (objectif, problèmes, travail…)
    ↓
Python fusionne dans le log Markdown du jour
    ↓
exit 0

L'anti-boucle mérite une explication : quand le hook appelle claude, cette invocation se termine et re-déclenche le Stop hook. Claude Code injecte alors stop_hook_active: true dans le JSON stdin. Le hook détecte ce flag en premier et sort immédiatement, sans traitement.

Pourquoi appeler claude depuis /tmp ? Si le hook s'exécute depuis le répertoire du projet, le CLAUDE.md du projet est injecté dans le contexte de Haiku. Résultat : Haiku suit vos règles métier au lieu de retourner du JSON pur. Appeler depuis /tmp neutralise cet effet.


Comment mettre en place le système

1. Les skills de mémoire

Deux skills complètent le hook :

  • /memory_load [projet] — à appeler en début de session. Lit long_memory.md + les logs du jour et de la veille. Affiche un résumé consolidé. Ce chargement est manuel — la mémoire est enregistrée automatiquement, mais elle ne se recharge pas toute seule.
  • /memory_promotion [projet] — consolide les logs récents vers long_memory.md et archive les logs de plus de 30 jours. À lancer manuellement, une fois par semaine ou par mois selon votre activité.

Les skills sont des fichiers Markdown dans .claude/skills/{nom}/SKILL.md. Claude Code les reconnaît comme commandes /nom.

2. Brancher le hook Stop

Le hook Stop est déclaré dans .claude/settings.json :

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/memory-session.sh" }
        ]
      }
    ]
  }
}

Quand le Stop hook se déclenche-t-il ? Claude Code déclenche Stop à la fin de chaque tour — c'est-à-dire après chaque réponse complète de Claude, qu'elle soit simple (une phrase) ou complexe (avec des appels d'outils). C'est différent de la fin de session : le hook tourne après chaque échange, pas seulement quand vous fermez Claude Code.

3. Adapter la liste des projets

Dans le hook, une variable PROJECT_PATHS liste les répertoires mémoire de chaque sous-projet :

PROJECT_PATHS = {
    "root": "memory_sessions",
    "cmms_doc": "projects/cmms_doc/memory_sessions",
    "competitors": "projects/competitors/memory_sessions",
}

Haiku analyse l'échange et détermine aux projets concernés — puis écrit dans les bons fichiers.

4. Coût

Haiku 4.5 est délibérément choisi : rapide (~1-2 secondes) et économique. Avec une utilisation intensive de 20 échanges par jour, le coût reste sous 1 $/mois. C'est négligeable pour ce que ça apporte.


Ce que ça change concrètement

Avec ce système en place :

  • Reprise après week-end : /memory_load en début de session → Claude connaît l'état du bug, les décisions prises, ce qui restait à faire.
  • Multi-projets : chaque sous-projet a sa propre mémoire. Travailler sur cmms_doc puis competitors dans la même session → les logs sont séparés.
  • Traçabilité : l'historique des décisions techniques est dans le repo. git log memory_sessions/ raconte l'évolution du projet.
  • Portabilité : cloner le repo sur une autre machine, la mémoire est là.

Limitation principale

/memory_load est manuel. La mémoire est capturée automatiquement en fin de tour, mais elle ne se recharge pas toute seule au démarrage d'une nouvelle session. Il faut penser à lancer /memory_load en début de session pour en bénéficier.

C'est un choix délibéré — forcer le chargement automatique risquerait de polluer le contexte de sessions courtes ou sans rapport avec le projet.


Pièces jointes

La spécification technique complète (code complet du hook, format JSON, choix d'implémentation, bugs connus) est disponible en pièce jointe :

spec_session_memory.md

Exemple concret — log quotidien réel : le fichier ci-dessous est le log de session généré automatiquement le jour où cet article a été rédigé. Il illustre ce que le système capture réellement à chaque échange : contexte, travail produit, décisions prises, points à suivre.

session-log-exemple.md