CLAUDE.md imbriqués : un monorepo, plusieurs sous-projets, zéro répétition
À la fin de cet article, ton dépôt (un dossier de projet, un peu comme un classeur qui regroupe plusieurs dossiers de clients) pourra contenir plusieurs sous-dossiers, comme un frontend, un backend et une CLI, chacun avec ses propres règles. Tu n’auras pas besoin d’écrire deux fois la même règle si elle vaut pour tous.
Le CLAUDE.md de projet de l’article précédent vit à la racine et s’applique à tout le dépôt, comme un règlement affiché à l’entrée d’un bureau qui vaut pour tous les services. Ce troisième niveau descend plus bas : un sous-dossier peut avoir ses propres règles, différentes du reste du bureau.
Ce qu’il te faut
Un projet avec au moins deux sous-dossiers qui pourraient raisonnablement avoir des règles différentes, par exemple des technologies différentes d’un dossier à l’autre. Si ton projet est simple et homogène, ce niveau ne te sert probablement à rien : ne l’ajoute pas juste parce qu’il existe.
Comment ça se charge, concrètement
Un point technique avant de commencer, parce qu’il change la façon dont tu dois écrire ces fichiers. Le CLAUDE.md de la racine se charge en entier dès que tu démarres une session, comme une note que tu lirais au réveil. Un CLAUDE.md posé dans un sous-dossier fonctionne autrement : il ne se charge que le jour où Claude Code ouvre un fichier de ce sous-dossier. C’est ce qu’on appelle le chargement à la demande (lazy loading) : la règle reste rangée tant que personne n’en a besoin. Tant que tu travailles dans frontend/, celui de backend/ reste invisible, et inversement.
Ce n’est pas une limitation à contourner, c’est le comportement voulu. Un sous-projet n’a pas besoin des règles d’un autre sous-projet auquel tu ne touches pas dans la session en cours, exactement comme tu n’as pas besoin de sortir le dossier d’un client que tu ne traites pas aujourd’hui.
D’où tu lances claude change ce qui se charge
Ce même mécanisme de lazy loading a une conséquence à laquelle on ne pense pas assez : ce qui compte, c’est le dossier depuis lequel la commande claude démarre, pas un dossier dans lequel tu te déplaces ensuite.
Compare ces deux façons de faire, en apparence équivalentes :
# Façon A : se placer dans le projet AVANT de lancer claude
cd ~/chemin/vers/projet
claude
# Façon B : lancer claude depuis le dossier utilisateur (~), puis se déplacer
claude
# et seulement ensuite, dans la session, un cd vers le projet
# Équivalent PowerShell de la façon A
cd ~cheminversprojet
claude
Elles ne sont pas équivalentes. Dans la façon A, claude démarre avec le projet comme point de départ : son CLAUDE.md racine se charge en entier dès le lancement, exactement comme décrit dans l’article précédent. Dans la façon B, claude démarre depuis ~ : le dossier du projet est alors traité comme n’importe quel sous-dossier, exactement comme frontend/ ou backend/ plus haut. Son CLAUDE.md ne se charge qu’au moment où Claude lit un premier fichier à l’intérieur, pas avant. Se déplacer soi-même vers ce dossier après coup, ou demander à Claude de le faire, ne change rien : c’est le point de départ du processus qui compte, pas l’endroit où tu te trouves plus tard dans la session.
Retiens la règle pratique : place-toi toujours dans la racine du projet (cd) avant de taper claude, jamais après. C’est d’ailleurs ce que les articles précédents de cette série t’ont fait faire sans le nommer explicitement.
Étape 1 — Un CLAUDE.md par sous-projet (5 minutes)
Prends un dépôt avec cette forme :
mon-projet/
├── CLAUDE.md # racine, déjà en place (article précédent)
├── frontend/
│ ├── CLAUDE.md # nouveau
│ └── ...
└── backend/
├── CLAUDE.md # nouveau
└── ...
Le CLAUDE.md de frontend/ ne parle que du frontend :
# Sous-projet — Frontend
## Stack
- React 19, TypeScript, Vite
- Tests avec Vitest, pas Jest (migration terminée en 2025)
## Conventions
- Composants en fichiers `.tsx`, un composant par fichier
- Pas de `any` : si le typage est incertain, `unknown` et un garde de type
Celui de backend/ ne parle que du backend, avec ses propres outils et ses propres conventions, sans se soucier de React ni de Vite.
Étape 2 — Vérifier le chargement à la demande (3 minutes)
Un piège : ni /memory ni /context ne listent un CLAUDE.md de sous-dossier qui se charge en cours de route. Ils ne montrent que les fichiers lus au démarrage (testé avec la version 2.1.289). Pour vérifier le chargement à la demande, on pose donc un repère.
Ouvre frontend/CLAUDE.md et ajoute temporairement une règle facile à repérer :
- Commence chaque réponse par [frontend].
Ouvre une session à la racine du dépôt et pose une question qui ne touche aucun fichier du frontend :
Que contient le fichier README.md à la racine ?
La réponse n’a pas le repère : aucun fichier de frontend/ n’a encore été lu. Demande maintenant quelque chose qui touche un fichier du frontend :
Explique-moi la structure du composant dans frontend/src/App.tsx
Cette fois, la réponse commence par [frontend] : Claude Code vient de lire un fichier de ce dossier, et son CLAUDE.md s’est chargé à ce moment-là. C’est la preuve que le lazy loading fonctionne. Retire ensuite la règle repère, et garde le réflexe : si une règle de sous-projet semble ignorée, vérifie d’abord que Claude Code a effectivement lu un fichier de ce sous-dossier dans la session en cours.
Étape 3 — Partager une règle commune avec @import (3 minutes)
Une règle de sécurité ou une convention de commit s’applique aux deux sous-projets ? Ne la recopie pas dans les deux fichiers. Écris-la une fois, dans un fichier à part, puis fais-y référence partout où elle s’applique. C’est ce qu’on appelle un import : au lieu de coller le texte, tu pointes vers lui.
mon-projet/
├── docs/
│ └── git-conventions.md # règle partagée
├── frontend/CLAUDE.md # contient : @../docs/git-conventions.md
└── backend/CLAUDE.md # contient : @../docs/git-conventions.md
La syntaxe est simple : @chemin/vers/le/fichier, en relatif (résolu par rapport au fichier qui importe, pas par rapport à ton dossier de travail) ou en absolu. Un fichier importé peut lui-même en importer un autre, jusqu’à quatre niveaux de profondeur.
Un détail qui piège parfois : si tu veux juste mentionner un chemin dans le texte sans qu’il soit importé, mets-le entre apostrophes inversées. ` @docs/git-conventions.md reste du texte ; @docs/git-conventions.md` sans les apostrophes déclenche l’import.
Import en dehors du projet. Si tu importes un fichier situé hors de ton dossier de travail, par exemple des préférences personnelles rangées dans ton dossier utilisateur, Claude Code affiche une fenêtre de confirmation la première fois, un peu comme un coffre qui te demande de valider avant d’ouvrir un tiroir qui n’est pas le tien. C’est une protection contre un import externe qu’un collègue aurait ajouté sans que tu le voies passer. Si tu refuses, l’import reste désactivé et la fenêtre ne réapparaît pas.
Le piège à éviter : trop de granularité, trop tôt
Un CLAUDE.md par sous-dossier est tentant à multiplier. Résiste : ce niveau ne vaut la peine que si les sous-projets ont réellement des règles différentes. Un dossier frontend/components/ avec son propre CLAUDE.md en plus de celui de frontend/ ajoute une couche de lazy loading pour un gain qui, la plupart du temps, n’existe pas. Commence à deux niveaux (racine plus un ou deux sous-projets clairement distincts), et ajoute plus de granularité seulement quand une vraie contradiction te force la main.
Ce qui vient de se passer
Trois niveaux de CLAUDE.md sont maintenant en place : général (ta machine), projet (ton dépôt), sous-projet (un dossier précis, chargé à la demande). Une règle commune aux sous-projets vit à un seul endroit et s’importe partout où elle s’applique, plutôt que d’être copiée-collée.
En résumé
- Un
CLAUDE.mddans un sous-dossier se charge seulement quand Claude Code lit un fichier de ce sous-dossier, pas au démarrage de la session. /memoryet/contextne montrent que les fichiers chargés au démarrage : pour vérifier unCLAUDE.mdde sous-dossier, glisse-y une règle repère et regarde si Claude l’applique après avoir lu un fichier de ce dossier.@chemin/vers/fichierimporte un fichier partagé dans plusieursCLAUDE.md, jusqu’à quatre niveaux de profondeur ; entre apostrophes inversées, le chemin reste du texte.- Un import hors du dossier de travail déclenche une confirmation la première fois : c’est voulu.
- N’ajoute ce niveau que si des sous-projets ont vraiment des règles différentes ; sinon, le
CLAUDE.mdde projet suffit.
Prochaine étape : deux commandes pour voir exactement ce que Claude a en tête à tout moment, plus la statusline pour l’avoir sous les yeux en continu.
Cette mise en pratique poursuit la série sur l’installation et la configuration de Claude Code, de zéro jusqu’à un premier programme fonctionnel. La vidéo est ici.
Abonne-toi au blog pour suivre la suite de la série.