Memoria dell'agente AI tra le sessioni: file di avanzamento, registro delle decisioni, git e script di init
L'agente AI non ha memoria tra le sessioni: tutto ciò che non è scritto nei file del repository non è noto alla nuova sessione. La memoria dell'agente si costruisce con degli artefatti: PROGRESS.md (a che punto siamo), DECISIONS.md (perché così e che cosa è stato scartato), commit git con la spiegazione dell'intento e un protocollo di passaggio in AGENTS.md che obbliga a leggerli all'inizio e ad aggiornarli alla fine; uno script di init verifica l'ambiente e stampa lo stato attuale.
Perché l'agente non ricorda nulla
Il modello non conserva lo stato tra un'esecuzione e l'altra. Tutto ciò che l'agente «sa» del vostro compito si trova nella finestra di contesto della sessione corrente: i file letti, l'output dei comandi, il dialogo con voi. Quando la sessione si chiude o il contesto si riempie, la nuova parte da zero e vede solo ciò che è stato scritto su disco.
Un modello utile: un ingegnere brillante che ogni mattina arriva al lavoro con la memoria completamente cancellata. Capisce rapidamente il codice, ma non ricorda quale architettura è stata scelta ieri, perché le altre sono state scartate e in quale stato sono i test. Senza appunti, impiegherà quindici-venti minuti di esplorazione e con buona probabilità rifarà qualcosa che avete già scartato di proposito.
Quindi la memoria dell'agente AI non è una proprietà del modello, ma una parte dell'harness: un insieme di file e regole che progettate voi. La buona notizia è che non servono database vettoriali né servizi speciali. Bastano pochi file Markdown, git e un po' di disciplina.
Perché una finestra di contesto più grande non risolve il problema
Si pensa che basti aspettare un modello con una finestra più ampia. Ma un compito complesso riempie qualsiasi finestra: l'agente legge la base di codice, accumula la storia delle decisioni, riceve output verbosi dei test e tiene l'intero dialogo. Le esigenze crescono insieme alla finestra. È un problema architetturale, non una questione di dimensioni.
C'è anche un secondo effetto. Vicino al limite della finestra molti modelli iniziano ad affrettarsi a concludere: saltano la verifica, scelgono la soluzione semplice invece di quella giusta. Anthropic descrive questa osservazione per i propri modelli, ma l'intensità dell'effetto varia da modello a modello. Una sessione lunga al limite del contesto non rischia solo di perdere informazioni, ma anche di peggiorare la qualità del lavoro.
Compattazione: che cosa si conserva e che cosa si perde
La compattazione è la riduzione della parte iniziale del dialogo in un riassunto breve, per liberare spazio nella stessa sessione. In Claude Code la fa il comando /compact, ma la compressione avviene anche automaticamente quando ci si avvicina al limite. Il comando /clear, al contrario, cancella la cronologia e ricomincia la conversazione da capo.
Il problema della compattazione è che il riassunto di solito conserva il «che cosa» e perde il «perché». Il codice finito resta nei file, ma i ragionamenti — perché è stata scelta la variante B, perché non si è usata una libreria, perché si è deliberatamente saltata un'ottimizzazione — si riducono a due parole o spariscono. Il passo successivo dell'agente «migliora» una decisione consapevole, perché non vede più le ragioni.
| Compattazione | Ripartenza (nuova sessione) | |
|---|---|---|
| Che cosa succede | La parte iniziale del dialogo viene sostituita da un riassunto | La sessione si chiude, la nuova legge i file di stato |
| Che cosa si conserva | Ciò che il modello ha ritenuto importante nella compressione | Esattamente ciò che avete scritto nei file |
| Fretta al limite della finestra | Può restare | Si azzera |
| Quando è opportuna | Il compito sta sicuramente nella sessione corrente | L'orizzonte del compito è lungo o poco chiaro |
Regola pratica senza metriche complesse: quando il compito ha occupato circa il 60% della finestra, smettete di scrivere codice e preparate il passaggio di consegne. Se invece il contesto è occupato per il 40% e la fine del compito è vicina, basta la compattazione.
Quattro artefatti che compongono la memoria dell'agente
Invece di sperare nella memoria del modello, create un giornale di bordo. È composto da quattro parti, ciascuna con un ruolo proprio.
- PROGRESS.md — a che punto siamo.
- DECISIONS.md — perché si è fatto così e non diversamente.
- Commit git — checkpoint gratuiti dello stato.
- Protocollo di passaggio in AGENTS.md — che cosa fare all'arrivo e alla partenza.
PROGRESS.md: il file di avanzamento
Risponde a una sola domanda: in che stato si trova il progetto in questo momento. L'agente lo legge per primo all'inizio della sessione e lo aggiorna per ultimo prima di andarsene. Il file è breve, si riscrive invece di aggiungere in fondo all'infinito: la storia vive in git.
# PROGRESS.md
## Obiettivo attuale
Ricerca nel catalogo prodotti (funzione search-01)
## Stato
- HEAD: 4f2a9c1
- make check: verde, 142/142 test
- Fatto: indice in PostgreSQL (tsvector), endpoint GET /search
- Verificato: test unitari + richiesta curl manuale su 3 query
## Blocchi
- Mancano dati di morfologia per la lingua kazaka — in attesa di una decisione
## Prossimo passo
Aggiungere la paginazione a GET /search, criterio: test sulla seconda pagina
Notate i quattro campi che bastano per un passaggio di consegne: hash del commit, quota di test che passano, blocchi e prossimo passo. Se una sessione nuova non riesce a riprendere il lavoro in modo univoco da questo file, nel modello manca un campo.
DECISIONS.md: il registro delle decisioni
Conserva proprio il «perché» che si perde con la compattazione. Il formato di una voce: decisione, motivazione, che cosa è stato scartato e perché, vincoli.
## 2026-03-14 — Cache delle impostazioni utente in Redis
- Decisione: Redis, TTL di 5 minuti, invalidazione attiva alla scrittura.
- Motivo: viene letta a ogni richiesta, il volume di dati è minimo.
- Scartato: materialized view in PostgreSQL — modifiche troppo frequenti,
la manutenzione non si ripaga.
- Vincolo: non mettere in cache le impostazioni di pagamento.
La riga più preziosa è «Scartato». È lei che impedisce alla sessione successiva di «ottimizzare» la decisione tornando alla variante già considerata e rifiutata. Il registro delle decisioni, a differenza del file di avanzamento, si limita ad crescere: le voci vecchie non si cancellano, ma si contrassegnano come sostituite da quelle nuove.
La storia di git come checkpoint
I commit sono snapshot versionati dello stato, già integrati nel lavoro. L'agente può leggere git log e git diff e ricostruire che cosa è cambiato. Perché la storia funzioni come memoria, il messaggio del commit deve spiegare l'intento, non riassumere il diff.
# male
git commit -m "update search.py"
# bene
git commit -m "search: indice tsvector al posto di LIKE
LIKE '%q%' non usa l'indice, su 200k prodotti la query impiega 1,8 s.
La paginazione non è ancora fatta, vedi PROGRESS.md."
Commit piccoli e frequenti dopo ogni esecuzione verde dei test offrono anche un punto di ritorno. Se la sessione è andata nella direzione sbagliata, è più semplice tornare all'ultimo stato verificato che districare modifiche a metà.
Protocollo di passaggio in AGENTS.md
I file di stato non servono a nulla se l'agente non li conosce. Per questo nel file di istruzioni di ingresso (AGENTS.md o CLAUDE.md) si scrive un protocollo breve: che cosa fare all'arrivo e alla partenza.
## Arrivo in turno
1. Leggere PROGRESS.md e DECISIONS.md.
2. Trovare la funzione attiva in .agent/feature_list.json.
3. Eseguire make check — verificare che il repository sia coerente.
4. Continuare dal «Prossimo passo», senza riaprire ciò che è già deciso.
## Partenza dal turno
1. Eseguire make check, fare il commit dello stato verde.
2. Aggiornare PROGRESS.md: HEAD, test, blocchi, prossimo passo.
3. Aggiungere le nuove decisioni in DECISIONS.md.
4. Non lasciare lavoro a metà nell'albero di lavoro.
Il protocollo conviene tenerlo breve: sono poche righe nel file di ingresso, non un papiro a parte.
Script di init: come accelerare l'avvio della sessione
Perché l'agente non ricostruisca il quadro a mano, datele uno script unico che verifica l'ambiente e stampa lo stato. Lo script deve essere idempotente — si può eseguire quante volte si vuole — e terminare con un messaggio esplicito di pronto.
#!/usr/bin/env bash
set -euo pipefail
echo "== 1. Ambiente =="
command -v uv >/dev/null || { echo "FAIL: uv non installato"; exit 1; }
uv sync --frozen
echo "== 2. Repository =="
if [ -n "$(git status --porcelain)" ]; then
echo "WARN: albero di lavoro sporco"
else
echo "OK: pulito"
fi
echo "HEAD: $(git log -1 --oneline)"
echo "== 3. Verifica =="
make check
echo "== 4. Stato =="
cat PROGRESS.md
echo "Pronto al lavoro"
Nel protocollo di arrivo basta allora una riga: «esegui scripts/init.sh». In Claude Code questo avvio si può automatizzare con un hook all'avvio della sessione (evento SessionStart), ma anche senza hook l'agente esegue lo script seguendo l'istruzione del file.
Che cosa mettere nella memoria dell'agente e che cosa no
L'errore principale è trasformare la memoria in una discarica. Ogni riga che l'agente legge all'avvio occupa spazio nel contesto, e il superfluo confonde l'importante.
| Mettere | Non mettere |
|---|---|
| Obiettivo attuale e prossimo passo | Riassunto del codice che l'agente leggerà da sé |
| Decisioni con motivazioni e alternative scartate | Log completo del dialogo e output dei comandi |
| Hash del commit e stato dei test | Elenco delle dipendenze — è già nel manifest dei pacchetti |
| Blocchi e domande aperte | «Ho fatto un lavoro ottimo, tutto funziona» senza dire come è stato verificato |
| Vicoli ciechi: che cosa si è provato e perché non ha funzionato | Segreti, token, password |
| Compiti con criteri di accettazione | Note obsolete su compiti chiusi |
Separate anche per durata di vita. Le regole del progetto cambiano di rado e riguardano tutti i compiti: il loro posto è il file di istruzioni di ingresso. Lo stato cambia a ogni sessione: il suo posto è il file di avanzamento. Se le mescolate, il file di ingresso cresce in fretta con note superate.
Prima sessione: l'inizializzazione come fase a sé
La memoria tra le sessioni non serve se la prima sessione è finita nel caos. Scenario tipico: sul repository appena creato scrivete «aggiungi la ricerca», e dopo mezz'ora si scopre che il framework di test è configurato male e il formato delle migrazioni non va bene. La ricerca c'è, ma le fondamenta sono storte.
Il motivo è che realizzazione e inizializzazione ottimizzano cose diverse: la prima il numero di funzioni pronte in questa sessione, la seconda la velocità e l'affidabilità di tutte le sessioni successive. L'agente tende verso il risultato visibile, cioè il codice. Per questo conviene separare l'inizializzazione in una sessione dedicata, con un criterio di completamento chiaro in quattro condizioni.
- Avviarsi:
make setupemake devfunzionano partendo da un clone pulito. - Verificarsi: esistono
make teste almeno un test reale che passa. - Vedere il progresso: il file di stato esiste e si legge.
- Riprendere il lavoro: c'è un elenco di compiti con criteri di accettazione.
Se avviate spesso progetti nuovi, preparate un template di repository: Makefile, framework di test, scheletro di AGENTS.md, la cartella .agent/, scripts/init.sh, linter e CI. Così l'inizializzazione si riduce alla sola specificità del progetto.
Come verificare che la memoria funzioni
La misura più onesta è il tempo che passa dall'inizio di una nuova sessione alla prima modifica significativa del codice. Senza artefatti sono di solito quindici-venti minuti di esplorazione, con un buon passaggio di consegne due-tre. Misuratelo una volta prima e una volta dopo, e si vedrà se la disciplina ripaga.
Il secondo metodo è il test di avvio a freddo. Aprite una sessione nuova, scrivete «continua» e fate cinque domande: qual è l'obiettivo attuale, in che stato sono i test, quale decisione è stata presa sul tema chiave e perché, che cosa blocca, qual è il prossimo passo. Se l'agente risponde a tutte e cinque basandosi sui file, senza supposizioni, la memoria è costruita bene. Ogni risposta incerta indica un campo mancante nel template.
Errori tipici
- Il file di avanzamento cresce soltanto. Dopo un mese contiene centinaia di righe di storia. Riscrivetelo in base allo stato attuale: la storia sta in git.
- Manca la riga «scartato». Un registro delle decisioni senza alternative scartate non protegge dalle discussioni ripetute.
- L'agente aggiorna lo stato «a occhio». Scrivete come è stato verificato: comando e risultato, non «tutto funziona».
- Passaggio di consegne al limite della finestra. Vicino al bordo del contesto l'agente ha già fretta; avviate l'handoff in anticipo, intorno al 60%.
- Albero di lavoro sporco alla fine. Modifiche a metà senza commit disorientano la sessione successiva.
In breve
La memoria dell'agente AI tra le sessioni non si costruisce sul modello, ma sui file: PROGRESS.md conserva lo stato attuale, DECISIONS.md le motivazioni e le alternative scartate, i commit git sono checkpoint con la spiegazione dell'intento, e il protocollo di passaggio in AGENTS.md obbliga a leggere e aggiornare tutto questo. Lo script di init riduce l'avvio a un solo comando, e il test di avvio a freddo mostra se le annotazioni bastano. Il giornale di bordo dell'agente e il contratto di bootstrap sono illustrati in pratica nel corso sull'harness engineering.
Domande frequenti
Posso semplicemente chiedere all'agente di ricordare qualcosa per il futuro?
L'agente lo ricorderà solo se lo scrive in un file che la sessione successiva leggerà. In Claude Code esistono i file di memoria e CLAUDE.md, ma per lo stato di un compito specifico è più affidabile un file di avanzamento esplicito nel repository.
In che cosa PROGRESS.md differisce dal CHANGELOG?
Il CHANGELOG descrive le modifiche per gli utenti, per versione. PROGRESS.md descrive lo stato di lavoro attuale per la sessione successiva dell'agente e viene riscritto ogni volta che lo stato cambia.
Serve un database vettoriale per la memoria di un agente programmatore?
Di solito no, quando si lavora in un solo repository: lo stato di un compito sta in pochi file brevi, e il codice l'agente lo legge direttamente. La ricerca vettoriale ha senso quando bisogna cercare in un grande volume di documenti esterni.
Conviene committare i file di stato in git?
Sì: così lo stato è disponibile a ogni sessione e a ogni membro del team, e la storia delle sue modifiche si conserva. Fanno eccezione le note personali e tutto ciò che contiene segreti.
Che cosa fare se l'agente dimentica di aggiornare PROGRESS.md alla fine?
Rendete l'aggiornamento parte del criterio di completamento nel protocollo di partenza e verificatelo in modo meccanico, per esempio con un hook o uno script che confronta l'HEAD scritto nel file con il commit attuale.
Questo argomento è trattato in modo approfondito, con pratica, nel corso «Harness Engineering: инженерия надёжности AI-агентов».
Vai al corso