CLAUDE.md: dare a Claude Code una memoria di progetto persistente
La parte più noiosa di lavorare con un assistente da terminale è ripetersi: ogni sessione riparte da un contesto vuoto e, se non glielo dico, Claude Code non sa che uso yarn e non npm, dove stanno gli handler o quale comando lancia i test. La soluzione è un file di testo semplice, CLAUDE.md, che l'assistente legge all'avvio di ogni sessione e tiene come contesto per tutto il lavoro. È il posto dove metto una volta ciò che altrimenti riscriverei ogni giorno. La regola che mi ripeto è una sola: ci va quello che rispiegherei a un collega appena arrivato. In questo articolo guardo cos'è di preciso, dove metto i file nella gerarchia, come scrivo istruzioni che vengono seguite e perché, alla fine, resta contesto e non un vincolo assoluto.
🧠 Cos'è CLAUDE.md e perché lo scrivo
Un CLAUDE.md è un file markdown con istruzioni persistenti per un progetto. Lo scrivo io in testo semplice e Claude Code lo legge all'inizio di ogni sessione, prima ancora che io digiti il primo prompt. Il contesto non lo ricostruisco a mano ogni volta: comandi di build, convenzioni, struttura delle cartelle e regole del tipo «fai sempre così» stanno lì e valgono da subito.
La domanda che uso per decidere cosa scriverci è sempre la stessa: lo rispiegherei a un collega appena arrivato? Se sì, va nel file. Ci finisce quando Claude ripete lo stesso errore una seconda volta, quando una code review scopre qualcosa che avrebbe dovuto sapere su questo repo, o quando mi accorgo di digitare la stessa correzione della sessione prima.
Quello che invece non ci metto sono le procedure lunghe o le regole che valgono solo per un angolo del codice: per quelle uso una skill o una regola scoped, che si carica solo quando serve. Il CLAUDE.md resta il posto dei fatti che voglio in ogni sessione, non il manuale del progetto.
# Progetto — regole per Claude Code
## Comandi
- Build: `yarn build` # mai npm
- Test: `yarn test`
## Convenzioni
- Indentazione a 2 spazi
- Gli handler API stanno in `src/api/handlers/`
- Early return, niente else dopo un returnDoc ufficiale · Claude Code memory ↗
🗂️ Dove vivono i file: la gerarchia della memoria
I CLAUDE.md possono stare in più posti, ognuno con un raggio d'azione diverso. Claude Code li carica dal più ampio al più specifico, così un'istruzione di progetto arriva in coda a una personale e, a parità di tema, vince quella più vicina al punto in cui lancio il comando.
I quattro livelli, dal più ampio al più stretto: la policy gestita dall'organizzazione, le mie preferenze utente in ~/.claude/CLAUDE.md, il progetto in ./CLAUDE.md (o ./.claude/CLAUDE.md) condiviso col team via Git, e il locale in ./CLAUDE.local.md, che tengo nel .gitignore per le cose mie di questo repo.
Un dettaglio che sfrutto nei monorepo: Claude risale l'albero delle cartelle dalla directory in cui sono e concatena tutti i CLAUDE.md che trova, mentre quelli nelle sottocartelle si caricano su richiesta, solo quando tocca file lì dentro. Le istruzioni non si sovrascrivono: si sommano.
- 01Policy gestitaIstruzioni a livello di organizzazione, una per macchina, non escludibili dal singolo.
- 02Utente~/.claude/CLAUDE.md: le mie preferenze, valide su tutti i progetti.
- 03Progetto./CLAUDE.md o ./.claude/CLAUDE.md: condiviso col team via version control.
- 04Locale./CLAUDE.local.md: preferenze private di questo repo, tenute nel .gitignore.
Dal raggio più ampio al più specifico: l'ultimo letto pesa di più.
✍️ Scrivere istruzioni che Claude segue davvero
Siccome il CLAUDE.md entra nel contesto a ogni avvio, come scrivo le istruzioni conta quanto cosa scrivo. Tre cose fanno la differenza. La prima è la misura: punto a stare sotto le 200 righe, perché un file lungo consuma contesto e, paradossalmente, viene seguito peggio.
La seconda è la concretezza. «Formatta bene il codice» non è verificabile; «Usa l'indentazione a 2 spazi» sì. Preferisco sempre l'istruzione che un revisore potrebbe spuntare: «Lancia yarn test prima di committare» invece di «testa le modifiche». La terza è la coerenza: se due regole si contraddicono, Claude ne sceglie una a caso, quindi ogni tanto rileggo e poto quelle vecchie o in conflitto.
Quando il file cresce troppo, invece di gonfiarlo sposto le istruzioni per area in .claude/rules/, un file per tema agganciato a percorsi precisi via glob nel frontmatter. Così le regole sui componenti si caricano solo quando tocco i componenti, e il resto non occupa contesto in ogni sessione.
Vago — Claude tira a indovinare
- Formatta bene il codice
- Tieni i file in ordine
- Testa le modifiche
- Gestisci gli errori come si deve
Concreto — Claude può spuntarlo
- Usa l'indentazione a 2 spazi
- Gli handler API stanno in src/api/handlers/
- Lancia yarn test prima di committare
- Usa il formato di errore standard del progetto
La stessa regola, scritta in due modi: a destra Claude può controllarsi da solo.
🔗 Import con @path e il ponte verso AGENTS.md
Un CLAUDE.md può tirare dentro altri file con la sintassi @path/to/file: all'avvio vengono espansi nel contesto insieme al file che li richiama. Li uso per non duplicare quello che vive già altrove — un @README per il quadro, un @package.json per gli script — con percorsi relativi o assoluti e una profondità massima di quattro salti.
Due accortezze che mi sono segnato. Se voglio nominare un percorso senza importarlo, lo avvolgo tra backtick: fuori dai backtick @README importa il file, dentro resta testo. E la prima volta che un file di progetto importa qualcosa fuori dalla cartella di lavoro — per esempio dalla mia home — Claude Code mi chiede conferma con una finestra: è la protezione dagli import che qualcun altro potrebbe committare in un repo condiviso.
Comodo anche il ponte con AGENTS.md: Claude Code legge CLAUDE.md, non AGENTS.md, quindi se un repo usa già il secondo creo un CLAUDE.md che lo importa con @AGENTS.md e aggiungo sotto le istruzioni per Claude. Un solo file di verità, letto da tutti gli strumenti.
Vedi @README per il quadro e @package.json per gli script.
# Regole comuni (condivise con altri agenti)
@AGENTS.md
## Solo per Claude Code
- Usa la plan mode per le modifiche sotto `src/billing/`
- Cita `@docs/api.md` tra backtick: resta testo, non lo importa🩺 /init, /memory e /context: generare e verificare
Non parto mai dal foglio bianco: /init analizza il codebase e mi genera un CLAUDE.md di partenza con comandi di build, istruzioni di test e convenzioni che scopre da solo. Se il file esiste già, invece di sovrascriverlo mi propone dei miglioramenti. Da lì rifinisco a mano con le cose che Claude non poteva indovinare guardando il codice.
Per capire cosa è davvero attivo uso due comandi distinti. /memory elenca i file di memoria — CLAUDE.md, CLAUDE.local.md e gli altri — nei vari livelli e me li apre nell'editor. /context invece mi mostra cosa è stato effettivamente caricato in questa sessione, sotto la voce Memory files: se un file non compare lì, Claude non lo sta vedendo, ed è la prima cosa che controllo quando una regola sembra ignorata.
C'è poi la auto memory, complementare: attiva di default, è Claude che si prende appunti da solo — comandi, insight di debug, preferenze — sotto ~/.claude/projects/, mentre il CLAUDE.md resta la parte che scrivo io. La ispeziono e la poto dallo stesso /memory.
# genera un CLAUDE.md di partenza dal codebase
/init
# elenca e apre i file di memoria (tutti i livelli)
/memory
# mostra cosa e' DAVVERO caricato in questa sessione
/context # -> voce "Memory files"⚠️ È contesto, non un vincolo: il limite da conoscere
Il malinteso più costoso è trattare il CLAUDE.md come una configurazione che impone comportamenti. Non lo è: le sue istruzioni arrivano come un messaggio dopo il system prompt, Claude le legge e cerca di seguirle, ma non c'è garanzia di conformità stretta, soprattutto se sono vaghe o in conflitto. Più sono specifiche e concise, più vengono rispettate.
Quando una regola deve scattare a un punto preciso — prima di ogni commit, dopo ogni modifica — non la lascio al CLAUDE.md: la scrivo come hook, che esegue un comando di shell a un evento del ciclo di vita e vale a prescindere da cosa decide Claude. Il CLAUDE.md guida, l'hook impone: due strumenti diversi, tenuti separati.
Un'ultima cosa: il CLAUDE.md della radice del progetto sopravvive al */compact* — dopo la compattazione Claude lo rilegge da disco e lo re-inietta. Quelli nelle sottocartelle no: si ricaricano quando tocco di nuovo un file lì dentro. Per questo le regole sempre-attive stanno nel file di radice.
CLAUDE.md — guida
- Contesto letto a inizio sessione
- Convenzioni, struttura, preferenze
- Seguito, ma senza garanzia stretta
- Lo aggiorno quando ripeto una correzione
Hook — impone
- Comando di shell a un evento preciso
- Scatta prima del commit o dopo un edit
- Vale a prescindere da cosa decide Claude
- Per i vincoli che non possono saltare
Due strumenti diversi: uno orienta il comportamento, l'altro lo forza.
✅ Il flusso che seguo per una memoria che resta utile
Messo tutto insieme, il CLAUDE.md non è un documento che scrivo una volta e dimentico, ma un file vivo che poto man mano che il progetto cambia. Il mini-flusso che seguo, in ordine:
- Parto da */init* per avere una base, poi taglio tutto ciò che Claude può dedurre da solo dal codice.
- Scrivo istruzioni verificabili, sotto le 200 righe, e sposto in .claude/rules/ ciò che vale solo per un'area del codice.
- Importo invece di copiare: un @AGENTS.md o un @docs/… tiene un solo file di verità, senza duplicati che invecchiano.
- Verifico con */context* quando una regola sembra ignorata: se non è tra i Memory files, il problema è dove l'ho messa.
- Promuovo a hook ciò che non può saltare, e lascio al CLAUDE.md ciò che deve solo guidare.
Domande frequenti su CLAUDE.md Claude Code
Dove metto il CLAUDE.md, a livello di progetto o utente?
Nel progetto (./CLAUDE.md o ./.claude/CLAUDE.md) ci va quello che serve a chiunque lavori sul repo — comandi, convenzioni, architettura — ed è condiviso col team via Git. Nell'utente (~/.claude/CLAUDE.md) le preferenze mie, valide su tutti i progetti. Le cose private di un singolo repo stanno invece in ./CLAUDE.local.md, che tengo nel .gitignore.
Perché Claude non segue una regola del mio CLAUDE.md?
Prima cosa: lancio /context e controllo che il file sia sotto Memory files; se non c'è, Claude non lo sta caricando ed è un problema di posizione. Se c'è, di solito la regola è troppo vaga o in conflitto con un'altra, e la rendo più concreta. Se deve scattare per forza, la trasformo in un hook.
Che differenza c'è tra CLAUDE.md e la auto memory?
Il CLAUDE.md lo scrivo io: sono istruzioni e regole. La auto memory la scrive Claude, che salva da solo learning e pattern utili tra una sessione e l'altra sotto ~/.claude/projects/. Sono complementari e si caricano entrambe all'avvio; io governo la prima, la seconda la ispeziono e poto da /memory.
Il CLAUDE.md sopravvive a /compact?
Quello della radice del progetto sì: dopo un /compact Claude lo rilegge da disco e lo re-inietta nella sessione. I CLAUDE.md nelle sottocartelle invece non vengono re-iniettati in automatico, si ricaricano la volta dopo che Claude apre un file in quella cartella. Per questo le regole sempre-attive le tengo nel file di radice.
Parliamone
Se questo tema ti riguarda, scrivimi: confrontarsi su codice e AI è sempre tempo speso bene.