Pourquoi les coding agents ignorent vos instructions
Votre fichier dit « arrêtez », mais l’agent continue. Identifiez si la règle manque du contexte, reste vague, est contredite ou trop ancienne avant de la réécrire.
Pourquoi les coding agents ignorent vos instructions
Les coding agents ignorent vos instructions pour quatre raisons, et aucune ne tient à un manque de politesse. La règle n’a jamais été présente dans la context window. Elle était trop vague pour permettre de vérifier une action par rapport à celle-ci. Un autre élément du contexte la contredisait, généralement le code que l’agent venait de lire. Ou bien la règle est toujours chargée, mais se trouve très loin avant le tour actuel, et l’agent s’appuie sur les éléments qui sont proches.
Chaque cause a son propre correctif. La première étape consiste donc à les distinguer. Les majuscules et le mot IMPORTANT ne permettent pas d’établir un diagnostic. Les mécanismes décrits ci-dessous prennent Claude Code comme exemple, car son comportement de chargement et de compaction est documenté en détail en août 2026. Les autres outils présentent des différences de détail, mais fonctionnent globalement de la même manière.
Commençons par deux termes. La context window est le bloc de texte que le modèle voit pendant un tour donné : le system prompt, vos fichiers d’instructions, la conversation et chaque fichier lu par l’agent. Le harness est le programme qui entoure le modèle, celui qui lit les fichiers sur le disque et assemble ce bloc. Presque toutes les plaintes formulées dans cet article concernent en réalité le harness, et non le modèle.
Votre fichier d’instructions est un message, pas un paramètre
Un fichier d’instructions n’est pas une configuration. Rien dans le runtime ne lit CLAUDE.md et ne l’applique. Le harness lit le fichier sur le disque, puis colle son contenu dans la conversation. Dans Claude Code, ce contenu est transmis sous la forme d’un message utilisateur placé après le system prompt. Le modèle voit donc vos règles de la même manière que tout autre texte que vous avez saisi.
Cette situation a une conséquence importante. Vos règles sont en concurrence avec tous les autres éléments affichés dans la fenêtre, sur un pied d’égalité. Une règle est une affirmation. Le fichier que l’agent vient d’ouvrir constitue un élément probant. Lorsque les deux éléments se contredisent, les éléments probants l’emportent souvent. Aucune erreur ne s’affiche, car du point de vue du modèle, rien ne s’est mal passé.
La documentation officielle l’indique clairement : les fichiers d’instructions sont traités comme du contexte, et non comme une configuration appliquée. Pour bloquer une action quelle que soit la décision du modèle, vous avez besoin d’un hook, pas d’une phrase. Retenez ce principe. La plupart des correctifs présentés à la fin de cet article appliquent ce principe à un cas précis.
Quels fichiers d’instructions sont chargés, et à quel moment
Claude Code remonte l’arborescence depuis le répertoire dans lequel vous l’avez démarré. Chaque fichier CLAUDE.md et CLAUDE.local.md situé entre la racine du système de fichiers et votre répertoire de travail est entièrement chargé au lancement. Ces fichiers sont concaténés dans cet ordre. Le fichier le plus proche du répertoire depuis lequel vous avez lancé Claude Code est donc lu en dernier. Dans un même répertoire, le fichier .local est ajouté après le fichier principal.
Les fichiers situés dans les sous-répertoires sous votre répertoire de travail se comportent différemment. Ils ne sont pas chargés au lancement. Ils le sont lorsque l’agent lit un fichier situé dans le répertoire concerné. Il en va de même pour les règles limitées à certains chemins dans .claude/rules/ qui contiennent un champ frontmatter paths: : elles sont ajoutées au contexte lorsqu’un fichier correspondant est lu, et non à chaque tour.
Cette différence explique une grande partie des échecs signalés. Vous placez une règle dans packages/api/CLAUDE.md, vous posez une question sur l’API, et l’agent répond sans jamais ouvrir de fichier sous packages/api/. La règle n’a pas été ignorée. Elle n’était tout simplement pas présente. Si votre dépôt répartit les consignes entre des fichiers d’instructions par package dans un monorepo, c’est la première chose à vérifier, à chaque fois.
Il existe un autre piège de chargement. C’est la cause la plus fréquente du message « l’agent a ignoré mes instructions ». Claude Code lit CLAUDE.md, et non AGENTS.md. Un dépôt standardisé sur AGENTS.md et dépourvu de CLAUDE.md ne fournit donc aucun fichier que Claude Code puisse charger. La méthode prise en charge consiste à utiliser un fichier CLAUDE.md dont la première ligne est @AGENTS.md. Cette ligne importe le fichier au lancement. Vous pouvez ajouter dessous des notes spécifiques à Claude. Un lien symbolique convient également si vous n’avez rien d’autre à ajouter. Déterminer ce qui doit figurer dans ce fichier est une question distincte, traitée dans la séparation des instructions destinées à l’agent et de la documentation destinée aux utilisateurs.
Vérifiez que le fichier est chargé avant de le réécrire
Ne modifiez pas le texte avant d’avoir la preuve que l’agent peut voir le fichier. Il existe deux vérifications, et la moins coûteuse vient en premier.
Exécutez /context dans la session. Cette commande affiche la fenêtre actuelle, classée par catégorie. La liste Memory files indique tous les fichiers d’instructions effectivement chargés. Si un fichier n’apparaît pas dans cette liste, il ne fait pas partie de la conversation. Rien de ce que vous écrivez à l’intérieur ne peut donc être pris en compte. /memory répertorie les emplacements des fichiers et les ouvre pour modification, y compris ceux qui n’existent pas encore.
Pour obtenir une réponse plus précise, journalisez les chargements. L’événement hook InstructionsLoaded se déclenche chaque fois qu’un CLAUDE.md ou qu’un fichier de règles entre dans le contexte. Son matcher indique pourquoi le chargement a eu lieu : session_start, nested_traversal, path_glob_match, include ou compact. Placez ceci dans .claude/settings.json :
{
"hooks": {
"InstructionsLoaded": [
{
"matcher": "nested_traversal",
"hooks": [
{
"type": "command",
"command": "cat >> /tmp/instructions-loaded.log"
}
]
}
]
}
}Le hook reçoit sa charge utile au format JSON sur l’entrée standard. cat ajoute donc l’enregistrement complet au fichier. Surveillez-le avec tail -f /tmp/instructions-loaded.log pendant votre travail. Le code de sortie de cet événement est ignoré. Le hook peut donc uniquement observer, et jamais bloquer. Si votre fichier imbriqué n’apparaît jamais dans ce journal pendant une session où vous vous attendiez à ce qu’il soit chargé, arrêtez de reformuler le texte. Le problème vient de son emplacement.
L’effet des longues sessions sur vos règles
Deux effets distincts s’appliquent ici et nécessitent des réponses différentes.
Distance. Une règle énoncée au tour 1 se trouve encore dans la fenêtre au tour 90, mais elle doit alors s’imposer face à 90 tours de texte plus récent et plus spécifique à ce que vous faites actuellement. Vous ne pouvez pas désactiver cet effet par la configuration, mais vous pouvez le mesurer. Exécutez la même tâche dans une nouvelle session. Si la règle est respectée dans cette session et cesse de l’être après un long échange, la distance est en cause.
Compactage. Lorsque la fenêtre est pleine, le harness résume la conversation à ce stade, puis reprend à partir de ce résumé. Les éléments conservés sont ceux que le summariser a jugés importants, ce qui ne correspond pas forcément à ce que vous considérez comme important. Claude Code documente le résultat pour chaque mécanisme, et les différences sont importantes. La racine du projet CLAUDE.md et les règles sans portée sont réinjectées depuis le disque après un compactage. L’auto memory est réinjectée depuis le disque. Les règles dont le frontmatter contient paths: sont perdues jusqu’à la lecture suivante d’un fichier correspondant. Les fichiers CLAUDE.md imbriqués dans des sous-répertoires sont perdus jusqu’à la lecture d’un fichier situé dans ce sous-répertoire.
Classez vos instructions selon ce tableau : l’ordre de fragilité apparaît immédiatement. Une règle saisie uniquement dans le chat est l’élément le plus fragile de la session : elle ne persiste que si le résumé l’a conservée. Une règle dans packages/api/CLAUDE.md vient ensuite, car elle a été chargée une fois, supprimée par le résumé, puis ne revient qu’à la prochaine lecture dans ce répertoire. Une règle dans le fichier à la racine du projet est la plus durable, car elle est relue depuis le disque à chaque fois.
Si une instruction doit rester valable pendant toute une session, placez-la dans le fichier à la racine du projet, sans frontmatter paths:. Pour le reste, choisissez volontairement le compromis adapté. Gérer ce qui reste dans la fenêtre de contexte couvre /compact avec un argument de focus et /clear entre des tâches sans rapport, deux éléments qui modifient la fréquence à laquelle le summariser peut décider quelles règles vous aviez définies.
Pourquoi le code environnant l’emporte sur la règle
C’est l’échec le plus souvent décrit et le moins souvent diagnostiqué. Votre fichier indique que l’accès à la base de données doit passer par la couche repository. L’agent écrit un handler qui appelle directement l’ORM (object relational mapper). Ce n’est pas une question de style ignorée. Les éléments concrets ont contredit votre règle.
Une règle décrit une préférence. Le code en démontre une. Lorsque l’agent ouvre trois fichiers du module qu’il s’apprête à modifier et que les trois appellent directement l’ORM, le contexte contient d’un côté une phrase abstraite et, de l’autre, trois exemples concrets, récents et adaptés à la tâche. Reproduire le pattern local est généralement le bon comportement. C’est incorrect ici pour une seule raison : vous savez quelque chose que le contexte ignore. Ces fichiers sont du code legacy.
Écrivez donc cette information dans la règle. Les règles qui mentionnent leurs propres éléments contradictoires résistent mieux à l’utilisation dans un vrai repository. Les règles qui énoncent seulement une préférence ne résistent pas.
Tout nouvel accès à la base de données passe parapp/repositories/. Les fichiers sousapp/legacy/appellent encore directement l’ORM. C’est du code ancien, pas le pattern à suivre. Ne le reproduisez pas.
La deuxième phrase fait le travail. Elle indique à l’agent ce qu’il va trouver et comment l’interpréter, avant même qu’il ne le trouve. La même correction s’applique à toute règle visiblement contredite par votre repository : un style de commit que votre historique ne suit pas, une organisation des tests ignorée par une partie de votre suite, une convention d’imports respectée uniquement dans le nouveau code. Lorsque le code contredit le fichier, mentionnez cette contradiction dans le fichier.
Une règle vague ne peut pas être vérifiée et ne peut donc pas être appliquée
« Écrivez du code propre. » « N’ajoutez pas de complexité inutile. » « Faites simple. » « Soyez prudent avec les migrations. » Aucune de ces règles ne peut être testée sur une action précise, ni par l’agent ni par vous. Un agent qui reçoit une règle qu’il ne peut pas vérifier sur sa propre sortie devine, et vous évaluez cette conjecture au ressenti.
Appliquez le test suivant à chaque ligne de votre fichier. Écrivez la commande shell qui se terminerait avec un code différent de zéro lorsque la règle est enfreinte. Si vous ne pouvez pas écrire cette commande, la règle n’est pas vérifiable. Comparez ces paires :
- Non vérifiable : « Gardez les fonctions courtes. » Vérifiable : « Une fonction de plus de 60 lignes doit être précédée d’un commentaire expliquant pourquoi. »
- Non vérifiable : « Testez vos modifications. » Vérifiable : « Exécutez
npm testet indiquez le nombre d’échecs avant de considérer la tâche terminée. » - Non vérifiable : « Gardez les fichiers organisés. » Vérifiable : « Les handlers HTTP se trouvent dans
src/api/handlers/. Aucun autre élément ne doit être placé dans ce répertoire. » - Non vérifiable : « Formatez correctement le code. » Vérifiable : « Utilisez une indentation de 2 espaces dans les fichiers
.ts. »
« N’ajoutez pas de complexité inutile » est la règle à laquelle les gens renoncent en premier, car sa correction ne consiste pas à raccourcir la phrase, mais à l’allonger : décrire précisément ce que signifie la plus petite modification fonctionnelle donne à l’agent des critères qu’il peut confronter à son propre diff.
La taille pose le même problème sous une autre forme. Les recommandations de Claude Code visent moins de 200 lignes par fichier d’instructions et indiquent directement que les fichiers plus longs réduisent le respect des consignes. Un fichier de 700 lignes ne contient pas des instructions plus fermes. Il contient 700 affirmations qui risquent davantage de se contredire, et ces lignes sont imputées à votre fenêtre à chaque tour, ce qui se reflète directement dans votre consommation de tokens. Structurer le fichier afin que chaque règle figure sous un heading qu’un lecteur peut parcourir est abordé dans rédiger un fichier d’instructions que l’agent peut appliquer.
Comment le diagnostiquer en dix minutes
Exécutez ces commandes dans l’ordre. Passer directement à la dernière étape produit souvent un long fichier de règles formulées en majuscules, qui ne fonctionne toujours pas.
- Vérifiez que le fichier a été chargé. Exécutez
/contextet consultez la liste Memory files. Si le fichier n’y figure pas, corrigez son emplacement et arrêtez-vous. Rien d’autre dans cette liste ne s’applique encore. - Reproduisez le problème dans une nouvelle session. Démarrez une nouvelle session et donnez la tâche la plus simple qui devrait déclencher la règle. Si la règle fonctionne ici, mais échoue dans une session longue, le problème vient de la distance ou de la compaction. Si elle échoue aussi ici, le problème vient de la règle elle-même.
- Supprimez la concurrence. Demandez la même modification dans un répertoire dont le code existant respecte déjà la règle. Si la conformité revient, le code environnant prenait le dessus sur votre phrase.
- Recherchez un conflit. Deux fichiers qui donnent des consignes différentes pour le même comportement constituent un échec documenté : le modèle peut choisir l’un ou l’autre de manière arbitraire, sans vous indiquer qu’il l’a fait.
- Rendez la règle vérifiable, puis retestez. Réécrivez la règle avec un chemin concret et une condition. Une forte amélioration de la conformité signifie que la formulation était à l’origine du problème.
L’étape 4 tient en une commande. Recherchez le sujet dans toutes les sources d’instructions, et pas uniquement dans le fichier que vous étiez en train de modifier :
grep -rni "migration" --include="CLAUDE.md" --include="CLAUDE.local.md" .
grep -rni "migration" .claude/rules/ ~/.claude/CLAUDE.md ~/.claude/rules/ 2>/dev/nullUne occurrence dans deux fichiers qui donnent des consignes différentes est la cause de votre problème. Supprimez-en une. N’essayez pas de les départager avec une formulation plus forte : aucun moteur de classement ne permet de trancher.
Les correctifs, par ordre d’efficacité
Chaque étape ci-dessous a plus d’effet que la précédente, mais demande davantage de configuration. Commencez par le haut lorsqu’une règle peut être reformulée à faible coût. Descendez dès qu’une règle devient assez importante pour que des oublis occasionnels ne soient plus acceptables.
- Rendez la règle concrète. Nommez un chemin, une commande ou une condition. Ajoutez les éléments qui la contredisent et que l’agent trouvera dans le dépôt, comme indiqué précédemment. Cette mesure ne coûte rien et corrige un nombre étonnamment élevé de cas.
- Rapprochez-la de ce qu’elle régit. Utilisez un
CLAUDE.mdimbriqué, une règle limitée à un chemin dans.claude/rules/ou un commentaire au début du fichier lui-même. La règle est alors lue en même temps que le code auquel elle s’applique. Acceptez le compromis : tout ce qui est chargé de cette manière disparaît lors de la prochaine compaction et revient à la prochaine lecture correspondante. - Déplacez l’application de la règle dans un hook. La prose formule une demande. Un hook prend une décision. Les hooks s’exécutent sous forme de code à des événements fixes du cycle de vie et s’appliquent quel que soit le résultat auquel le modèle aboutit.
- Confiez la règle à un outil déterministe et supprimez la prose. Formatage, ordre des imports, longueur des lignes, imports interdits, format des messages de commit.
ruff format,prettier --write,eslint, un hookpre-commit. Le formatter donne toujours le bon résultat et ne consomme aucun token. La phrase est correcte la plupart du temps et consomme des tokens à chaque tour.
L’étape 3 en détail. Supposons que les fichiers de migration ne doivent jamais être modifiés par l’agent. Ajoutez ceci dans .claude/settings.json :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-migrations.sh"
}
]
}
]
}
}Et ceci dans .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 0Exécutez chmod +x .claude/hooks/guard-migrations.sh, puis démarrez une nouvelle session et demandez à l’agent de modifier un fichier sous migrations/. La modification est refusée et votre message revient comme motif. Le code de sortie 2 sur PreToolUse bloque l’appel de l’outil avant son exécution, et votre texte stderr est transmis au modèle comme message de blocage. ${CLAUDE_PROJECT_DIR} correspond à la racine du projet, de sorte que le hook fonctionne quel que soit le répertoire courant de l’agent. L’agent n’a pas besoin d’être d’accord avec la règle, de s’en souvenir ni de l’avoir encore dans son contexte. La modification n’a pas lieu.
Pour une interdiction simple qui ne contient aucune logique, permissions.deny dans vos paramètres remplit la même fonction sans script à maintenir, et les modes d’autorisation déterminent ce qui s’exécute sans vous le demander. Si une instruction doit réellement se trouver au niveau du system prompt plutôt que dans un message utilisateur, --append-system-prompt l’y place, mais elle doit être transmise à chaque invocation, ce qui convient mieux aux scripts qu’au travail interactif.
Ce que vous ne pouvez pas imposer par des instructions
Soyez clair sur la part qui vous incombe. Le placement, la formulation, les conflits entre fichiers et la taille du fichier relèvent de l’auteur, qui doit les corriger. Le reste relève du comportement du modèle, et une meilleure formulation ne le supprimera pas.
L’accord ne vaut pas conformité. Un agent peut reconnaître une règle, vous la reformuler correctement, puis l’enfreindre deux appels d’outil plus tard. Cette reconnaissance ne coûte rien et ne permet aucune prédiction. Ne la considérez pas comme une correction et ne la comptez pas comme un test.
Certaines habitudes persistent. Ajouter des commentaires, ajouter une gestion défensive des erreurs, rédiger un récapitulatif final, exécuter la commande évidente suivante. Ces comportements réapparaissent lorsqu’une règle les interdit, à une fréquence réduite plutôt qu’à fréquence nulle. Vous pouvez mesurer votre propre taux : exécutez la même tâche dix fois dans des sessions vierges et comptez les infractions. Lorsque ce nombre doit être nul, la règle doit sortir du prompt.
Votre propre session devient un exemple. Si l’agent enfreint la règle au tour 12 et que vous laissez passer cette infraction, celle-ci reste dans le contexte comme démonstration et elle est beaucoup plus récente que la règle. Corrigez une infraction dès que vous la constatez. Une infraction non corrigée sert d’exemple pour le reste de la session.
Un fichier d’instructions n’est pas une frontière de sécurité. Il oriente le comportement, mais ne l’impose pas. Tout ce dont l’échec coûte cher, comme les identifiants ou les commandes destructrices, doit relever des permissions ou d’un hook. Garder les secrets hors de portée d’un agent applique le même principe aux données : ne demandez pas à un agent de ne pas lire un fichier, faites en sorte que le fichier ne soit pas lisible.
En bref : vérifiez que le fichier a été chargé, rendez la règle vérifiable, placez-la à côté de l’élément qu’elle régit et, lorsque le taux d’infraction reste important, retirez-la de la prose. Une règle qu’un agent ne peut pas ignorer est une règle qui ne lui a jamais été demandée.
FAQ
Pourquoi Claude Code ignore-t-il mon fichier CLAUDE.md ?
Vérifiez d’abord qu’il a bien été chargé avant de conclure qu’il a été ignoré. Exécutez /context et consultez la liste Memory files ; un fichier qui n’y figure pas ne fait pas partie de la conversation. Les fichiers d’instructions sont transmis dans un message utilisateur après le prompt système. Ils sont donc traités comme du contexte et non comme une configuration appliquée de manière stricte. Il n’existe aucune garantie de conformité stricte. Dans la plupart des cas, l’une de ces quatre situations se présente : le fichier se trouve dans un sous-répertoire que l’agent n’a jamais lu, deux fichiers se contredisent et le modèle en a choisi un arbitrairement, la règle est trop vague pour permettre de vérifier une action, ou le code environnant montre l’inverse de ce qu’indique la règle.
Modifier le fichier d’instructions pendant la session change-t-il quelque chose ?
Pas pour la copie déjà présente dans la conversation. Les fichiers situés au-dessus de votre répertoire de travail sont chargés intégralement au démarrage. Le modèle conserve donc le texte présent au moment du lancement. Pour prendre en compte une modification, démarrez une nouvelle session ou demandez à l’agent de lire le fichier avec ses outils de gestion de fichiers habituels. La version actuelle est alors ajoutée à la conversation dans un nouveau message. Après une compaction, le fichier situé à la racine du projet est relu depuis le disque. La nouvelle version est donc également chargée à ce moment-là.
Quel fichier est prioritaire lorsqu’un CLAUDE.md racine et un fichier imbriqué se contredisent ?
Aucun, de manière fiable. Les fichiers détectés sont concaténés dans le contexte au lieu de se remplacer. Ils sont ordonnés depuis la racine du système de fichiers jusqu’à votre répertoire de travail. Le fichier le plus proche est donc simplement lu en dernier. Aucun moteur de priorité ne résout les contradictions, et la documentation de Claude Code indique que les règles contradictoires peuvent être résolues arbitrairement. Rédigez les fichiers imbriqués comme des compléments qui indiquent le chemin qu’ils régissent, et supprimez la contradiction au lieu d’essayer de lui donner la priorité.
Mes instructions sont-elles conservées après /compact ?
Cela dépend de la manière dont elles ont été chargées. Le fichier racine du projet CLAUDE.md, les règles sans périmètre et la mémoire automatique sont réinjectés depuis le disque après une compaction. Les règles utilisant le frontmatter paths: et les fichiers CLAUDE.md imbriqués dans des sous-répertoires sont perdus jusqu’à la relecture d’un fichier correspondant. Tout ce que vous avez uniquement saisi dans le chat est conservé seulement si le résumeur l’a gardé. Si une règle doit s’appliquer pendant toute la session, placez-la dans le fichier racine du projet, sans frontmatter paths:.
Quand une règle doit-elle devenir un hook plutôt que rester dans le texte des instructions ?
Lorsqu’un contrôle est déterministe et que le coût d’un oubli est supérieur à celui de l’écriture d’un petit script. Les restrictions sur les chemins de fichiers, les commandes obligatoires avant un commit et les appels d’outils interdits sont des cas appropriés. Un hook PreToolUse qui se termine avec le code d’état 2 bloque directement l’appel de l’outil et transmet son texte stderr au modèle comme motif du blocage. La règle reste donc appliquée, même si elle ne figure plus dans le contexte. Tout ce qu’un formatter ou un linter peut décider doit être pris en charge par cet outil, puis supprimé entièrement du fichier d’instructions.