Perché gli agenti di coding ignorano le istruzioni
L'agente ignora una regola che impone di fermarsi? Scopri se non è nel contesto, è vaga, contraddetta dal codice o ormai troppo lontana.
Perché gli agenti di coding ignorano le istruzioni
Gli agenti di coding ignorano le istruzioni per quattro motivi, e nessuno di questi dipende dal fatto che tu sia stato troppo cortese. La regola non era mai entrata nella finestra di contesto. La regola era troppo vaga per consentire di verificare un'azione rispetto a essa. Qualcos'altro nel contesto la contraddiceva, di solito il codice appena letto dall'agente. Oppure la regola è ancora caricata, ma si trova molto indietro rispetto al turno corrente e l'agente lavora principalmente su ciò che è più vicino.
Ogni causa richiede una correzione diversa, quindi il primo compito consiste nel distinguerle. Le maiuscole e la parola IMPORTANT non sono una diagnosi. Gli aspetti tecnici descritti di seguito usano Claude Code come esempio pratico, perché il suo comportamento di caricamento e compattazione è documentato in dettaglio ad agosto 2026. Gli altri strumenti differiscono nei dettagli, ma in linea generale si comportano allo stesso modo.
Prima di tutto, due termini. La finestra di contesto è il blocco di testo che il modello vede in un determinato turno: il prompt di sistema, i file di istruzioni, la conversazione e ogni file letto dall'agente. L'harness è il programma che circonda il modello, cioè quello che legge i file dal disco e assembla quel blocco. Quasi ogni lamentela espressa in questo articolo riguarda in realtà l'harness, non il modello.
Il file di istruzioni è un messaggio, non un'impostazione
Un file di istruzioni non è una configurazione. Nulla nel runtime legge CLAUDE.md e la applica. L'harness legge il file dal disco e incolla il testo nella conversazione. In Claude Code, quel contenuto viene inviato come messaggio dell'utente dopo il prompt di sistema. Il modello vede quindi le tue regole nello stesso modo in cui vede qualsiasi altro testo digitato.
Questa situazione ha una conseguenza scomoda. Le tue regole competono con ogni altro contenuto presente nella finestra, sullo stesso piano. Una regola è un'affermazione. Il file appena aperto dall'agente è un'evidenza. Quando i due elementi sono in contrasto, spesso prevale l'evidenza e non viene generato alcun errore, perché dal punto di vista del modello non è successo nulla di anomalo.
La documentazione ufficiale lo afferma chiaramente: i file di istruzioni vengono trattati come contesto, non come configurazione applicata. Per bloccare un'azione indipendentemente dalla decisione del modello, serve un hook, non una frase. Tieni a mente questa distinzione. La maggior parte delle correzioni alla fine di questo articolo consiste nell'applicarla a un caso specifico.
Quali file di istruzioni vengono caricati e quando
Claude Code risale l'albero delle directory a partire dalla directory da cui è stato avviato. Tutti i file CLAUDE.md e CLAUDE.local.md presenti dal filesystem root fino alla directory di lavoro vengono caricati integralmente all'avvio. I file vengono concatenati in quest'ordine: quello più vicino alla directory da cui è stato avviato viene letto per ultimo e, all'interno della stessa directory, il file .local viene aggiunto dopo quello principale.
I file nelle sottodirectory al di sotto della directory di lavoro si comportano in modo diverso. Non vengono caricati all'avvio. Vengono caricati quando l'agente legge un file in quella directory. Lo stesso vale per le regole con ambito basato sul percorso in .claude/rules/ che contengono un campo frontmatter paths:: entrano nel contesto quando viene letto un file corrispondente, non a ogni turno.
Questa differenza spiega gran parte dei problemi segnalati. Inserisci una regola in packages/api/CLAUDE.md, poni una domanda sull'API e l'agente risponde senza aprire alcun file in packages/api/. La regola non è stata ignorata. Non era mai presente nel contesto. Se il repository distribuisce le istruzioni tra file di istruzioni per pacchetto in un monorepo, questo è il primo controllo da eseguire, ogni volta.
Esiste un'altra trappola nel caricamento, ed è la causa più comune del messaggio "l'agente ha ignorato le mie istruzioni": Claude Code legge CLAUDE.md, non AGENTS.md. Un repository standardizzato su AGENTS.md e privo di CLAUDE.md non fornisce a Claude Code alcun file da caricare. Il meccanismo supportato è un file CLAUDE.md la cui prima riga è @AGENTS.md e che importa il file all'avvio, con eventuali note specifiche per Claude sotto questa riga. Anche un symlink funziona se non devi aggiungere altro. Stabilire cosa inserire in quel file è una questione distinta, trattata in separare le istruzioni per l'agente dalla documentazione per le persone.
Conferma il caricamento del file prima di riscriverlo
Non modificare il testo finché non hai la certezza che l'agente possa vedere il file. Sono disponibili due controlli; esegui prima quello più semplice.
Esegui /context nella sessione. Il comando stampa la finestra corrente suddivisa per categoria e, nell'elenco Memory files, indica ogni file di istruzioni effettivamente caricato. Se un file non compare nell'elenco, non fa parte della conversazione; di conseguenza, nessun contenuto che inserisci al suo interno può avere effetto. /memory elenca i percorsi dei file e li apre per la modifica, inclusi quelli che non esistono ancora.
Per ottenere una verifica più approfondita, registra i caricamenti. L'evento hook InstructionsLoaded viene attivato ogni volta che un CLAUDE.md o un file di regole entra nel contesto; il relativo matcher indica il motivo del caricamento: session_start, nested_traversal, path_glob_match, include o compact. Inserisci questo contenuto in .claude/settings.json:
{
"hooks": {
"InstructionsLoaded": [
{
"matcher": "nested_traversal",
"hooks": [
{
"type": "command",
"command": "cat >> /tmp/instructions-loaded.log"
}
]
}
]
}
}L'hook riceve il payload in formato JSON tramite lo standard input, quindi cat aggiunge il record completo. Monitoralo con tail -f /tmp/instructions-loaded.log mentre lavori. Lo stato di uscita di questo evento viene ignorato, quindi l'hook può soltanto osservare e non bloccare l'esecuzione. Se il file annidato non compare mai in quel log durante una sessione in cui ti aspettavi che venisse caricato, interrompi la riscrittura. Il problema è il posizionamento.
Cosa comporta una sessione lunga per le tue regole
Qui si applicano due effetti distinti, che richiedono risposte diverse.
Distanza. Una regola dichiarata al turno 1 è ancora nella finestra al turno 90, ma ora compete con 90 turni di testo più recente e più specifico rispetto all'attività in corso. Non puoi eliminare questo effetto con la configurazione, ma puoi misurarlo. Esegui la stessa attività in una sessione nuova. Se la regola viene rispettata nella sessione nuova e non più nelle fasi avanzate di una sessione lunga, hai identificato l'effetto della distanza.
Compattazione. Quando la finestra si riempie, l'ambiente di esecuzione riassume la conversazione fino a quel momento e continua a partire dal riepilogo. Sopravvive ciò che il sistema di riepilogo ha considerato importante, che non coincide necessariamente con ciò che consideri importante tu. Claude Code documenta il comportamento per ciascun meccanismo e le differenze sono rilevanti. La directory principale del progetto CLAUDE.md e le regole senza ambito vengono reinserite dal disco dopo una compattazione. La memoria automatica viene reinserita dal disco. Le regole con frontmatter paths: vengono perse finché non viene letto di nuovo un file corrispondente. I file CLAUDE.md annidati nelle sottodirectory vengono persi finché non viene letto di nuovo un file in quella sottodirectory.
Classifica le istruzioni in base a questa tabella e l'ordine di fragilità risulta evidente. Una regola inserita soltanto nella chat è l'elemento più fragile della sessione: persiste solo se il riepilogo la conserva. Una regola in packages/api/CLAUDE.md viene dopo, perché è stata caricata una volta, rimossa dal riepilogo e torna disponibile soltanto alla lettura successiva in quella directory. Una regola nel file della directory principale del progetto è la più persistente, perché viene riletta dal disco ogni volta.
Se quindi un'istruzione deve essere rispettata per l'intera sessione, inseriscila nel file della directory principale del progetto senza frontmatter paths:. Tutto il resto è un compromesso da scegliere consapevolmente. Gestire ciò che rimane nella finestra di contesto tratta /compact con un argomento focus e /clear tra attività non correlate; entrambi modificano la frequenza con cui il sistema di riepilogo può decidere quali fossero le tue regole.
Perché il codice circostante prevale sulla regola
Questo è il problema che viene descritto più spesso e diagnosticato meno spesso. Il file stabilisce che l'accesso al database passa dal livello repository. L'agente scrive un handler che chiama direttamente l'ORM (object relational mapper). Non ha ignorato la regola per motivi di stile. Ha seguito le evidenze disponibili.
Una regola descrive una preferenza. Il codice ne dimostra una. Quando l'agente apre tre file del modulo che sta per modificare e tutti e tre chiamano direttamente l'ORM, il contesto contiene una frase astratta da una parte e tre esempi concreti, recenti e pertinenti all'attività dall'altra. Copiare il pattern locale è di solito il comportamento corretto. In questo caso è sbagliato solo perché tu sai qualcosa che il contesto non sa: quei file sono codice legacy.
Quindi, scrivilo nella regola. Le regole che indicano le proprie controevidenze resistono al confronto con un repository reale. Le regole che esprimono soltanto una preferenza non lo fanno.
Il nuovo accesso al database passa daapp/repositories/. I file inapp/legacy/chiamano ancora direttamente l'ORM. È codice obsoleto, non il pattern da seguire. Non copiarlo.
È la seconda frase a svolgere il lavoro. Indica all'agente cosa troverà e come deve interpretarlo, prima che lo trovi. La stessa correzione si applica a qualsiasi regola che il repository contraddice visibilmente: uno stile dei commit che la cronologia non segue, una struttura dei test ignorata da metà della suite, una convenzione per gli import applicata solo al nuovo codice. Ogni volta che il codice non concorda con il file, descrivi il disaccordo nel file.
Una regola vaga non può essere verificata, quindi non può essere applicata
"Scrivi codice pulito." "Non progettare più del necessario." "Mantieni la semplicità." "Presta attenzione alle migrazioni." Nessuna di queste regole può essere verificata rispetto a un'azione specifica, né dall'agente né da te. Se riceve una regola che non può verificare sul proprio output, l'agente procede per tentativi, e tu valuti il risultato in base a un'impressione.
Applica questo test a ogni riga del tuo file. Scrivi il comando shell che restituisce un codice diverso da zero quando la regola viene violata. Se non puoi scrivere quel comando, la regola non è verificabile. Confronta queste coppie:
- Non verificabile: "Mantieni brevi le funzioni." Verificabile: "Una funzione più lunga di 60 righe deve avere sopra di sé un commento che spieghi il motivo."
- Non verificabile: "Esegui i test sulle modifiche." Verificabile: "Esegui
npm teste incolla il numero di errori prima di considerare completata un'attività." - Non verificabile: "Mantieni i file organizzati." Verificabile: "I gestori HTTP si trovano in
src/api/handlers/. In quella directory non deve esserci altro." - Non verificabile: "Formatta correttamente il codice." Verificabile: "Usa un'indentazione di 2 spazi nei file
.ts."
"Non progettare più del necessario" è la regola a cui le persone rinunciano per prima, perché la correzione non consiste in una frase più breve, ma in una frase più lunga: specificare che cosa significa esattamente la modifica minima funzionante fornisce all'agente criteri rispetto ai quali può verificare il proprio diff.
La dimensione presenta lo stesso problema sotto un altro aspetto. Le linee guida di Claude Code raccomandano meno di 200 righe per file di istruzioni e affermano esplicitamente che i file più lunghi riducono il rispetto delle istruzioni. Un file di 700 righe non contiene istruzioni più vincolanti. Contiene 700 affermazioni con più possibilità di contraddirsi a vicenda, e viene conteggiato nella finestra a ogni singolo turno, il che si riflette direttamente nell'utilizzo dei token. Organizzare il file in modo che ogni regola si trovi sotto un'intestazione facilmente consultabile è descritto in scrivere un file di istruzioni che l'agente possa applicare.
Come diagnosticare il problema in dieci minuti
Esegui questi controlli nell’ordine indicato. Passare direttamente all’ultimo controllo porta a creare un lungo file di regole formulate in modo perentorio che continua a non funzionare.
- Verifica che sia stato caricato. Esegui
/contexte leggi l’elenco dei file di memoria. Se il file non è presente, correggi il percorso e fermati. Nessun altro controllo di questo elenco è ancora applicabile. - Riproduci il problema in una sessione nuova. Avvia una nuova sessione e assegna l’attività minima che dovrebbe attivare la regola. Se il problema si verifica solo in una sessione lunga, la causa è probabilmente la distanza dal contesto o la sua compattazione. Se si verifica anche nella sessione nuova, il problema è nella regola stessa.
- Rimuovi la concorrenza. Richiedi la stessa modifica in una directory il cui codice esistente segue già la regola. Se la conformità viene ripristinata, il codice circostante stava prevalendo sulla tua istruzione.
- Cerca un conflitto. Due file che forniscono indicazioni diverse per lo stesso comportamento costituiscono un errore documentato: il modello può sceglierne uno arbitrariamente e non ti dirà di averlo fatto.
- Rendi la regola verificabile e ripeti il test. Riscrivi la regola specificando un percorso concreto e una condizione. Un aumento significativo della conformità indica che la causa era la formulazione.
Il passaggio 4 richiede un solo comando. Cerca l’argomento in tutte le fonti delle istruzioni, non soltanto nel file che stavi modificando:
grep -rni "migration" --include="CLAUDE.md" --include="CLAUDE.local.md" .
grep -rni "migration" .claude/rules/ ~/.claude/CLAUDE.md ~/.claude/rules/ 2>/dev/nullSe lo stesso argomento compare in due file che forniscono indicazioni diverse, hai trovato il problema. Elimina una delle due indicazioni. Non cercare di stabilire una priorità usando una formulazione più forte: non esiste alcun motore di assegnazione delle priorità a cui appellarsi.
Le correzioni, in ordine di efficacia
Ogni passaggio seguente ha un'efficacia maggiore di quello precedente e richiede più lavoro di configurazione. Partite dall'alto quando è sufficiente riformulare una regola a basso costo. Scendete di livello non appena una regola diventa abbastanza importante da rendere inaccettabili le violazioni occasionali.
- Rendete concreta la regola. Indicate un percorso, un comando o una condizione. Aggiungete gli elementi contrari che l'agent troverà nel repository, come mostrato in precedenza. Questo non costa nulla e risolve una quota sorprendentemente ampia dei casi.
- Avvicinatela all'oggetto a cui si applica. Usate un
CLAUDE.mdannidato, una regola con ambito limitato al percorso in.claude/rules/oppure un commento all'inizio del file stesso. In questo modo la regola viene letta insieme al codice a cui si applica. Accettate il compromesso: tutto ciò che viene caricato in questo modo viene escluso alla successiva compattazione e torna disponibile alla lettura successiva che corrisponde all'ambito della regola. - Spostate l'applicazione della regola in un hook. La prosa chiede. Un hook decide. Gli hook vengono eseguiti come codice in corrispondenza di eventi fissi del ciclo di vita e si applicano indipendentemente dalla conclusione a cui arriva il modello.
- Affidate la regola a uno strumento deterministico ed eliminate la prosa. Formattazione, ordine degli import, lunghezza delle righe, import vietati, formato dei messaggi di commit.
ruff format,prettier --write,eslint, un hookpre-commit. Il formatter è corretto ogni volta e non consuma token. La frase è corretta nella maggior parte dei casi e consuma token a ogni turno.
Il passaggio 3 in dettaglio. Supponiamo che l'agent non debba mai modificare i file di migrazione. Inserite questo in .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-migrations.sh"
}
]
}
]
}
}E questo in .claude/hooks/guard-migrations.sh:
#!/usr/bin/env bash
set -euo pipefail
path=$(jq -r '.tool_input.file_path // empty')
case "$path" in
*/migrations/*)
echo "Files under migrations/ are written by hand. Stop and ask first." >&2
exit 2
;;
esac
exit 0Eseguite chmod +x .claude/hooks/guard-migrations.sh, quindi avviate una nuova sessione e chiedete all'agent di modificare un file sotto migrations/. La modifica viene rifiutata e il vostro messaggio torna indietro come motivazione. Un codice di uscita 2 in PreToolUse blocca la chiamata allo strumento prima dell'esecuzione, mentre il testo su stderr viene passato al modello come messaggio di blocco. ${CLAUDE_PROJECT_DIR} restituisce la directory radice del progetto, quindi l'hook funziona indipendentemente dalla directory in cui si trova l'agent. L'agent non deve accettare la regola, ricordarla o averla ancora nel contesto. La modifica non viene eseguita.
Per un divieto semplice che non richiede logica, permissions.deny nelle impostazioni svolge lo stesso compito senza uno script da mantenere, mentre le modalità di autorizzazione determinano quali operazioni vengono eseguite senza chiedere prima conferma. Se un'istruzione deve necessariamente trovarsi al livello del prompt di sistema anziché in un messaggio dell'utente, --append-system-prompt la inserisce in quel livello. Tuttavia, deve essere passata a ogni invocazione, quindi è più adatta agli script che al lavoro interattivo.
Ciò che non puoi imporre con le istruzioni
Sii chiaro su quale parte dipende da te. Posizione, formulazione, conflitti tra file e dimensioni del file sono problemi dell’autore, che deve anche risolverli. Il resto riguarda il comportamento del modello e una formulazione migliore non lo eliminerà.
Accettare non significa rispettare. Un agent può riconoscere una regola, riformularla correttamente e violarla due chiamate agli strumenti più tardi. Il riconoscimento non ha alcun costo e non consente di prevedere il comportamento. Non considerarlo una correzione e non usarlo come test.
Alcune abitudini persistono. Aggiungere commenti, introdurre una gestione difensiva degli errori, scrivere un riepilogo conclusivo, eseguire il comando successivo ovvio. Questi comportamenti ricompaiono quando una regola li vieta, anche se con una frequenza ridotta e non pari a zero. Puoi misurare la tua frequenza: esegui la stessa attività dieci volte in sessioni nuove e conta le violazioni. Quando quel numero deve essere zero, la regola deve uscire dal prompt.
La sessione corrente diventa un esempio. Se l'agent viola la regola al turno 12 e lasci correre, quella violazione entra nel contesto come dimostrazione ed è molto più recente della regola. Correggi la violazione appena la noti. Una violazione non corretta insegna il comportamento al resto della sessione.
Un file di istruzioni non è un confine di sicurezza. Orienta il comportamento, ma non lo impone. Tutto ciò per cui un errore ha conseguenze elevate, come le credenziali o i comandi distruttivi, deve essere gestito tramite autorizzazioni o un hook. Tenere i segreti fuori dalla portata di un agent applica lo stesso principio ai dati: non chiedere a un agent di non leggere un file; fai in modo che il file non sia leggibile.
In breve: verifica che il file sia stato caricato, rendi la regola verificabile, spostala accanto all'elemento che disciplina e, quando la frequenza degli errori continua a essere rilevante, rimuovila dal testo descrittivo. Una regola che un agent non può ignorare è una regola che non è mai stata affidata all'agent.
FAQ
Perché Claude Code ignora il mio CLAUDE.md?
Verificate che il file sia stato caricato prima di concludere che sia stato ignorato. Eseguite /context e controllate l’elenco Memory files; un file che non compare nell’elenco non fa parte della conversazione. I file di istruzioni vengono forniti come messaggio dell’utente dopo il prompt di sistema e vengono trattati come contesto, non come configurazione applicata in modo vincolante. Non esiste quindi alcuna garanzia di conformità rigorosa. Nella maggior parte dei casi reali, il problema rientra in una di quattro categorie: il file si trova in una sottodirectory da cui l’agente non ha mai letto, due file contengono istruzioni in conflitto e il modello ne sceglie una arbitrariamente, la regola è troppo vaga per verificare un’azione rispetto a essa oppure il codice circostante dimostra il contrario di quanto stabilito dalla regola.
La modifica del file di istruzioni durante la sessione produce qualche effetto?
Non sulla copia già presente nella conversazione. I file situati sopra la directory di lavoro vengono caricati integralmente all’avvio, quindi il testo disponibile al modello è quello presente al momento dell’avvio. Per acquisire una modifica, avviate una nuova sessione oppure chiedete all’agente di leggere il file con i normali strumenti per i file. In questo modo la versione corrente viene inserita nella conversazione come nuovo messaggio. Dopo una compattazione, il file nella radice del progetto viene riletto dal disco, quindi anche la nuova versione viene acquisita in quel momento.
Quale file prevale quando un CLAUDE.md nella radice e uno annidato contengono istruzioni in conflitto?
Nessuno dei due in modo affidabile. I file individuati vengono concatenati nel contesto invece di sovrascriversi a vicenda. L’ordine va dalla radice del filesystem fino alla directory di lavoro, quindi il file più vicino viene semplicemente letto per ultimo. Non esiste un motore di precedenza che risolva le contraddizioni e la documentazione di Claude Code specifica che le regole contraddittorie possono essere risolte arbitrariamente. Scrivete i file annidati come aggiunte e indicate il percorso a cui si applicano. Eliminate la contraddizione invece di tentare di assegnare a una regola una precedenza maggiore.
Le mie istruzioni sopravvivono a /compact?
Dipende da come sono state caricate. Il file CLAUDE.md nella radice del progetto, le regole senza ambito e la memoria automatica vengono reinseriti dal disco dopo una compattazione. Le regole con frontmatter paths: e i file CLAUDE.md annidati nelle sottodirectory vengono persi finché non viene nuovamente letto un file corrispondente. Tutto ciò che avete digitato soltanto nella chat sopravvive solo se il riepilogatore ha deciso di conservarlo. Se una regola deve restare valida per l’intera sessione, inseritela nel file nella radice del progetto, senza frontmatter paths:.
Quando una regola deve diventare un hook invece di restare una descrizione testuale?
Quando il controllo è deterministico e il costo di un mancato controllo è maggiore del costo di scrivere un piccolo script. Le restrizioni sui percorsi dei file, i comandi obbligatori prima di un commit e le chiamate agli strumenti vietate rientrano in questa categoria. Un hook PreToolUse che termina con lo stato 2 blocca direttamente la chiamata allo strumento e restituisce al modello il testo su stderr come motivazione. In questo modo la regola resta applicata anche se non è più presente nel contesto. Tutto ciò che può essere deciso da un formatter o da un linter deve essere gestito da quello strumento e rimosso completamente dal file di istruzioni.