Pourquoi ce module
Anthropic propose le memory tool (memory_20250818, bêta) : une primitive qui laisse Claude lire et écrire des fichiers de mémoire entre les sessions, sans rebrancher le contexte à chaque fois.
⚠️ Point clé souvent mal compris. Le memory tool est client-side : Claude émet des commandes (
view,create,str_replace,insert,delete,rename) sur un répertoire/memories, et c'est vous qui implémentez le backend de stockage (fichiers, base de données, chiffrement, scoping par utilisateur). Anthropic n'héberge pas cette mémoire — il n'existe pas de « Memory API » clé-valeur hébergée et chiffrée côté Anthropic. Pour une mémoire hébergée côté serveur, c'est une autre primitive : les memory stores des Managed Agents (montés en FUSE dans le conteneur de session, documents versionnés avec audit/redact — voir M13). Et ce n'est pas non plus leMEMORY.mdde Claude Code (fichier local, scope projet).

/memory gère la mémoire fichier (client) : ~/.claude/CLAUDE.md (user), ./CLAUDE.md (projet, versionné), AGENTS.md importé. À distinguer du memory tool serveur étudié ici.Dans ce module, les exemples utilisent un backend clé-valeur que vous hébergez vous-même, exposé soit via le memory tool natif, soit via vos propres tools custom — les deux approches sont valides. C'est votre responsabilité RGPD (chiffrement, droit à l'oubli, audit).
🧠 Le défaut, c'est l'oubli. Hors mémoire explicitement activée, Claude ne se souvient de rien d'une session à l'autre : chaque conversation repart de zéro. La fonctionnalité de mémoire de claude.ai est opt-in (à activer dans les réglages), et côté Claude Code l'auto memory dépend de
autoMemoryEnabled(désactivable viaCLAUDE_CODE_DISABLE_AUTO_MEMORY). Autrement dit, « Claude se rappelle de la semaine dernière » n'est vrai que si vous avez branché une des couches de persistance ci-dessous — sinon, c'est à vous de réinjecter le contexte.
Pour les équipes construisant des assistants long terme (chatbots SaaS, support client AI, CRM IA), la mémoire transforme l'UX : votre assistant se souvient de vos 3 derniers tickets, vos préférences produit, votre contexte de compte. Mais sans garde-fous, c'est RGPD-catastrophe. Vous allez apprendre à stocker, lire, mettre à jour et supprimer de la mémoire de manière compliant.
Prérequis : maîtriser les tool calls Claude (voir M1), avoir une clé API Anthropic, et connaître les basics de RGPD art. 17 (droit à l'oubli).
Objectifs pédagogiques
À l'issue de ce module, vous serez capable de :
- Distinguer les couches de mémoire : MEMORY.md (projet, Claude Code), memory tool client-side (backend à vous), memory stores Managed Agents (serveur), context window (session courante)
- Implémenter un cycle write/read/update/delete via tool calls TypeScript (memory tool natif ou tools custom)
- Concevoir un schéma de mémoire : quoi stocker (faits courts), quoi pas (transcripts entiers), comment versioner
- Exposer un opt-out RGPD complet : suppression du droit à l'oubli en 1 clic, audit trail, consentement préalable
- Debugger des mémoires divergentes (stale reads, concurrence, conflits d'updates)
- Évaluer ROI : quand la mémoire persistante vaut vraiment le coup vs context window ou logs externes
Plan détaillé
- Les trois couches : MEMORY.md vs mémoire vs context
- Anatomie mémoire : schema, scope, TTL
- Cycle complet : write / read / update / delete
- Use cases : chatbot, support N1, CRM IA
- Schéma de mémoire recommandé
- Concurrence et consistency
- RGPD et droit à l'oubli
- Audit trail et compliance
- Atelier : assistant support avec mémoire de tickets
- Pièges courants
Les trois couches : MEMORY.md vs mémoire vs context
MEMORY.md (Claude Code client)
- Fichier
.claude/MEMORY.mddans votre projet - Scope : projet entier
- Persistance : fichier sur disque, versionné en Git
- Lifecycle : existe tant que le projet existe
- Format : Markdown libre
- Use case : "Ce projet utilise Next.js, React Query, Tailwind"
Memory tool (memory_20250818, client-side, bêta)
- Stockage : votre infrastructure — Claude appelle des commandes fichier (
view/create/str_replace/insert/delete/rename), vous implémentez le backend - Scope : ce que vous décidez (utilisateur, tenant SaaS…) via vos chemins
/memories/... - Persistance : selon votre backend ; survit aux sessions
- Format : libre (le KV
{key, value, ttl}montré plus bas est votre choix d'implémentation, pas un format imposé par Anthropic) - Chiffrement / RGPD : votre responsabilité (Anthropic ne stocke rien ici)
- Use case : "Cet utilisateur a vu mes 3 derniers tickets" ou "Ses préférences de notification sont weekly"
Memory stores (Managed Agents, serveur Anthropic — voir M13)
- Stockage : côté Anthropic, monté en FUSE dans le conteneur de session
- Format : documents texte adressés par
path, versionnés (audit + redact) - Use case : agents serveur persistants partageant une mémoire entre sessions
Context window (session courante)
- Scope : conversation en cours
- Persistance : none (réinitialise à chaque requête)
- Use case : "Rappeler le contexte immédiat de la requête précédente"

/context rend visible la couche éphémère : ce qui occupe la fenêtre de la session courante (system prompt, outils, mémoire chargée, messages) et l'espace libre. Contrairement aux trois autres couches, elle se réinitialise à chaque requête — d'où l'intérêt d'une mémoire persistante (fichier ou backend) pour ce qui doit survivre.Matrice comparative :
| Propriété | MEMORY.md | memory tool (client) | memory stores (CMA) | Context |
|---|---|---|---|---|
| Persistance | ✅ Git | ✅ Votre backend | ✅ Serveur Anthropic | ❌ None |
| Cross-session | ✅ Oui | ✅ Oui | ✅ Oui | ❌ Non |
| Scope | Projet | Au choix (user…) | Workspace/session | Conversation |
| Format | Markdown | Libre (vous) | Documents versionnés | Text/tokens |
| Droits RGPD | Local (vous) | Vous (backend & chiffrement) | Anthropic (redact dispo) | N/A |
Voici une visualisation des trois couches et leurs interactions :
Chargement du schéma…
Anatomie : le memory tool natif + votre schéma backend
1. Déclarer le memory tool natif
Côté requête, vous déclarez simplement le tool natif — Claude émet alors des commandes fichier (view, create, str_replace, insert, delete, rename) sur un répertoire /memories, que votre handler exécute :
const response = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
tools: [{ type: "memory_20250818", name: "memory" }], // tool natif
messages: [{ role: "user", content: "Retiens que je préfère les notifs le vendredi." }],
});
// → Claude renvoie un tool_use `memory` avec command="create", path="/memories/prefs.md", ...
// → VOUS écrivez le fichier (ou la ligne KV) dans VOTRE backend, puis renvoyez le tool_result.
Le SDK fournit un helper
betaMemoryTool(handlers)(TS) / classe équivalente (Python) où vous branchezview/create/str_replace/insert/delete/renamesur le stockage de votre choix.
2. Le schéma de votre backend (exemple)
Le memory tool ne vous impose aucun format de données : à vous de modéliser ce que vous stockez. Un schéma clé-valeur courant pour un assistant multi-utilisateur :
{
"key": "support_ticket_last_3",
"value": {
"tickets": [
{ "id": "T-2048", "date": "2026-04-28", "status": "resolved" },
{ "id": "T-2047", "date": "2026-04-15", "status": "resolved" },
{ "id": "T-2046", "date": "2026-03-30", "status": "open" }
]
},
"scope": "user",
"ttl": 2592000
}
Champs (convention backend, pas imposés par Anthropic) :
key: identifiant unique par user (alphanumériques, tirets, underscores)value: objet JSON quelconque (objets, arrays, strings, numbers)scope:"user"(par utilisateur) ou"session"(par conversation — moins courant)ttl: time-to-live en secondes.null= jamais expire.2592000= 30 jours.
Tailles limites (à fixer côté backend — bonnes pratiques) :
- Clé : garder court (< 256 caractères)
- Valeur : éviter les transcripts entiers ; viser des faits courts (< 10 K tokens)
- Nettoyage : TTL + script d'archivage (sinon dérive infinie)
Cycle complet : write / read / update / delete
Le cycle CRUD de la mémoire suit cet ordre et ces dépendances :
Chargement du schéma…
En TypeScript avec Anthropic SDK :
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
async function memoryDemo(userId: string) {
// ========== WRITE ==========
// Créer une nouvelle entrée mémoire
const writeResponse = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
system: `You have access to user memory. Write facts you learn to memory.`,
tools: [
{
name: "memory_write",
description: "Write a fact to the user's memory.",
input_schema: {
type: "object",
properties: {
key: {
type: "string",
description: "Memory key (e.g., 'user_preferences')",
},
value: {
type: "object",
description: "JSON value to store",
},
ttl: {
type: "number",
description: "Time-to-live in seconds (e.g., 2592000 for 30 days)",
},
},
required: ["key", "value"],
},
},
],
messages: [
{
role: "user",
content: `Remember that I prefer email notifications on Fridays only,
and my company is Acme Corp with 50 employees.`,
},
],
});
console.log("Write response:", writeResponse.content);
// ========== READ ==========
// Lire une entrée mémoire
const readResponse = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
system: `You have access to user memory. Read and use stored facts to personalize responses.`,
tools: [
{
name: "memory_read",
description: "Read a fact from the user's memory.",
input_schema: {
type: "object",
properties: {
key: {
type: "string",
description: "Memory key to read",
},
},
required: ["key"],
},
},
],
messages: [
{
role: "user",
content: `What are my notification preferences?`,
},
],
});
console.log("Read response:", readResponse.content);
// ========== UPDATE ==========
// Mettre à jour une entrée (remplace complètement la valeur)
const updateResponse = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
tools: [
{
name: "memory_update",
description: "Update an existing memory entry.",
input_schema: {
type: "object",
properties: {
key: {
type: "string",
},
value: {
type: "object",
},
},
required: ["key", "value"],
},
},
],
messages: [
{
role: "user",
content: `Update my preferences: now I want daily notifications instead.`,
},
],
});
console.log("Update response:", updateResponse.content);
// ========== DELETE ==========
// Supprimer une entrée (droit à l'oubli RGPD)
const deleteResponse = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
tools: [
{
name: "memory_delete",
description: "Delete a memory entry (GDPR right to be forgotten).",
input_schema: {
type: "object",
properties: {
key: {
type: "string",
},
},
required: ["key"],
},
},
],
messages: [
{
role: "user",
content: `Delete all my personal preferences from memory (exercising my right to be forgotten).`,
},
],
});
console.log("Delete response:", deleteResponse.content);
}
memoryDemo("user-12345");
Use cases : chatbot, support N1, CRM IA
Cas 1 : Chatbot SaaS client
Chaque client accède à votre chatbot. Au-delà de "Bonjour", votre assistant devrait :
- Se souvenir du plan tarifaire du client (Enterprise vs Starter)
- Connaître son industrie (répondre différemment à un SaaS vs un e-commerce)
- Tracker les 3 dernières questions → éviter les répétitions
{
"key": "client_profile_acme",
"value": {
"company": "Acme Corp",
"plan": "Enterprise",
"industry": "SaaS",
"onboarding_step": 5,
"recent_questions": ["How to customize dashboards?", "SSO setup?"]
},
"ttl": 7776000
}
Cas 2 : Support N1 avec mémoire de tickets
Agent support qui traite 100 tickets/jour. Pour chaque client, tracker :
- Derniers 5 tickets ouverts et résolus
- Status courant (waiting for client feedback, etc.)
- Contexte persistant (c'est un client new, old, VIP, etc.)
{
"key": "support_context_user_4521",
"value": {
"customer_type": "vip",
"open_tickets": ["T-9821", "T-9820"],
"last_resolution": "2026-04-28",
"escalation_needed": false
},
"ttl": 2592000
}
Cas 3 : CRM IA
Agent accédant HubSpot qui enrichit les deals. Pour chaque prospect :
- Dernier interaction timestamp
- Angle de vente testé (n'essayer la même approche 2 fois)
- Notes contexte non-structurées
{
"key": "deal_context_12048",
"value": {
"prospect": "Acme Corp",
"last_call": "2026-04-25",
"tested_angles": ["cost savings", "time to value"],
"next_angle": "compliance risk",
"budget_range": "50K–100K USD"
},
"ttl": 5184000
}
Schéma de mémoire recommandé
Voici une structure scalable pour app multi-tenant :
memory_key_pattern: {namespace}_{resource_type}_{resource_id}
Exemples :
- app_user_profile_u12345
- support_ticket_context_t5678
- crm_deal_metadata_d9012
- feature_flag_cache_fflag_ab_test_v2
Anti-patterns :
- ❌ Stocker des transcripts complets (100 K+ tokens)
- ❌ Clés non-structurées (style
"data","stuff") - ❌ Valeurs gigantesques sans TTL (dérive infinie)
- ❌ Pas de versioning (impossible d'upgrades le schéma)
Best practices :
- ✅ Faits structurés, courts (< 10 K tokens)
- ✅ TTL explicite (jamais
nullsauf raison solide) - ✅ Naming cohérent
- ✅ Versioning clé :
app_user_profile_v2_{id}si schema change - ✅ Cleanup script : archiver/supprimer memories > 180 jours
Concurrence et consistency
Deux users accèdent simultanément à la mémoire. Scénario : User A et B requêtent une mise à jour du même key au même temps.
Chargement du schéma…
Comportement par défaut d'un backend KV naïf : last-write-wins — l'update le plus récent écrase les précédents, pas de merge intelligent. (Comme c'est votre backend, c'est à vous d'ajouter de l'optimistic locking si besoin ; les memory stores CMA, eux, offrent un precondition content-sha256.)
Mitigation :
// UNSAFE : deux requêtes concurrentes overwrite-ing
const r1 = client.messages.create({ tools: [memory_update] });
const r2 = client.messages.create({ tools: [memory_update] });
await Promise.all([r1, r2]); // Risque : une overwrite l'autre
// SAFE : lire avant écrire (optimistic locking)
const currentValue = await memory_read("key");
const newValue = { ...currentValue, updated_field: "new" };
await memory_update("key", newValue); // Écrire la version complète
Pour haute concurrence (100+ writes/sec sur le même key) : ne pas faire transiter chaque write par le LLM. Écrire directement dans votre DB et ne synchroniser vers la mémoire de l'agent qu'en batch.
RGPD et droit à l'oubli
Article 17 RGPD : l'utilisateur peut demander la suppression complète de ses données. Avec la mémoire, c'est simple mais impératif :
async function completeUserDeletion(userId: string) {
// 1. Lister tous les keys de cet user
const allMemories = await listUserMemories(userId);
// 2. Supprimer chaque key
for (const memory of allMemories) {
await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 100,
tools: [
{
name: "memory_delete",
input_schema: {
type: "object",
properties: { key: { type: "string" } },
required: ["key"],
},
},
],
messages: [
{
role: "user",
content: `Delete memory key: ${memory.key}`,
},
],
});
}
// 3. Log audit trail
console.log(`[AUDIT] User ${userId} GDPR deletion completed at ${new Date()}`);
}
Consentement préalable : Avant de stocker la première mémoire pour un utilisateur, demander explicitement :
<dialog>
<h2>Mémoire utilisateur</h2>
<p>Nous allons mémoriser vos préférences, contexte et historique pour améliorer votre expérience.</p>
<p>Vous pouvez demander la suppression complète à tout moment (droit à l'oubli RGPD).</p>
<input type="checkbox" id="consent" /> J'accepte
<button onclick="recordConsent()">Continuer</button>
</dialog>
Opt-out à tout moment :
// Dans l'UI utilisateur, exposer un bouton "Delete my memory"
async function userInitiatedDeletion() {
await completeUserDeletion(currentUserId);
showAlert("Votre mémoire a été supprimée. Données purgées en 24h.");
}
Audit trail et compliance
Chaque action mémoire doit être loggée pour compliance audit :
{
"timestamp": "2026-04-28T14:32:10Z",
"user_id": "u12345",
"action": "memory_write",
"key": "user_profile_v2_u12345",
"result": "success",
"value_size_tokens": 512,
"ip_address": "192.168.1.1"
}
Logs à conserver : minimum 1 an (compliance audit, investigation fraude). Après purge data RGPD, logs restent anonymisés :
{
"timestamp": "2026-04-28T14:32:10Z",
"user_id": "REDACTED",
"action": "memory_delete",
"result": "success",
"reason": "GDPR Article 17 - User request"
}
Atelier : assistant support avec mémoire de tickets (45 min)
Vous construisez un assistant support qui gère tickets clients et se souvient des contextes.
Livrable :
- Agent TypeScript qui utilise mémoire
- Schéma :
support_context_{user_id}stockant derniers 3 tickets - Quand utilisateur pose question :
- Read memory → charger les 3 derniers tickets
- Répondre en tenant compte du contexte passé
- Write memory → mettre à jour status si ticket fermé
- Bouton "Droit à l'oubli" qui supprime TOUT
- Audit logs pour chaque opération mémoire
Critères de succès :
- ✅ Read/write/delete working
- ✅ Contexte réutilisé dans réponse
- ✅ TTL défini (30 jours)
- ✅ RGPD consentement visible
- ✅ Audit logs sauvegardés
Pièges courants
| Piège | Symptôme | Cure |
|---|---|---|
| Mémoire stale | Agent cite contexte obsolète | Read avant chaque usage + TTL court |
| Explosion de taille | Memory key > 100 K tokens | Archiver vieux entries, truncate arrays |
| Pas de versioning | Schema change casse old memories | Clé avec version (_v2, _v3) |
| Oubli RGPD | User demande suppression ignorée | Exposer bouton delete UI, audit logs |
| Concurrence | Deux writes simultanés perdus | Lire avant écrire, pas Promise.all |
| Coût surprise | Memory reads incluent token costs | Cacher agressivement (context window) |