Hooks Claude Code¶
Référence des trois hooks shell utilisés par Kirexo pour encadrer les actions de Claude Code et de ses sous-agents. Cette page documente uniquement le quoi — événement, entrée, sortie, effets de bord. Pour le pourquoi (raison d'être de la délégation, biais d'auto-confirmation, mécanique du quota de 5 fichiers), voir la page d'explication Workflow des agents Claude.
Les trois hooks sont enregistrés dans .claude/settings.json et écrits en Bash. Tous dépendent de jq pour lire le JSON reçu sur stdin — jq est un prérequis du projet.
guard-delegation.sh¶
| Champ | Valeur |
|---|---|
| Fichier source | .claude/hooks/guard-delegation.sh |
| Événement Claude Code | PreToolUse |
| Matcher | Write\|Edit |
| Bloquant | Oui (exit 2) |
Rôle¶
Contrôle qui peut écrire où, avant que l'écriture n'ait lieu. Empêche le main Claude de créer des fichiers dans tests/ ou docs/, et limite chaque sous-agent à son périmètre.
Entrée¶
Le hook lit sur stdin un JSON dont les champs suivants sont consommés :
| Champ JSON | Usage |
|---|---|
tool_input.file_path |
Chemin absolu du fichier ciblé. Si vide ou hors de $PWD, le hook laisse passer. |
agent_type (ou subagent_type en repli) |
Identifie l'appelant : vide pour le main Claude, sinon reviewer, test-writer, doc-writer. |
tool_name |
Nom de l'outil (Write ou Edit). Utilisé pour le main Claude : Edit est autorisé dans tests/ et docs/ (pour les renommages et corrections de références), Write est refusé. |
Règles appliquées¶
agent_type |
Périmètre autorisé |
|---|---|
reviewer |
Uniquement var/claude/reviewer-verdict.txt. Tout autre chemin est refusé. |
test-writer |
Uniquement les chemins contenant /tests/ ou /src/DataFixtures/. |
doc-writer |
Uniquement les chemins contenant /docs/, plus le fichier mkdocs.yml à la racine. |
| (vide — main Claude) | Refus de Write dans tests/ ou docs/. Edit reste autorisé partout. |
| Autre sous-agent non répertorié | Fail-closed sur tests/ et docs/ ; tout le reste passe. |
Sortie¶
exit 0— l'écriture est autorisée.exit 2— l'écriture est refusée. Un message explicatif est écrit surstderr(chemin refusé, raison du refus, action attendue).exit 2également sijqn'est pas installé.
Un avertissement est aussi écrit sur stderr si Claude Code n'est pas lancé depuis la racine du projet (absence de CLAUDE.md ou projet.md dans le CWD), sans pour autant bloquer.
Effets de bord¶
Aucun. Le hook lit, classe et tranche — il n'écrit rien sur disque.
count-prod-php.sh¶
| Champ | Valeur |
|---|---|
| Fichier source | .claude/hooks/count-prod-php.sh |
| Événement Claude Code | PostToolUse |
| Matcher | Write\|Edit |
| Bloquant | Non (informatif via systemMessage) |
Rôle¶
Comptabilise les fichiers PHP de production écrits par le main Claude pour faire respecter le plafond de 5 fichiers entre deux délégations au test-writer. Émet un avertissement préventif à 3/5 et un message bloquant à 5/5.
Définition d'un « fichier PHP de production »¶
Le hook ne comptabilise un chemin que si tous les critères suivants sont réunis :
- l'extension est
.php(ou le nom estbin/console) ; - le chemin est dans
src/,public/oubin/; - le chemin n'est pas dans
tests/nisrc/DataFixtures/; - le fichier n'est pas un fichier de tooling :
castor.php,.php-cs-fixer.dist.php,.php-cs-fixer.php,config/*,importmap.php.
Entrée¶
| Champ JSON | Usage |
|---|---|
tool_name |
Doit être Write ou Edit ; sinon le hook sort sans rien faire. |
agent_type (ou subagent_type) |
Discrimine main Claude (vide) et sous-agents (test-writer, reviewer). |
tool_input.file_path |
Chemin du fichier écrit. Filtré selon les critères ci-dessus. |
tool_input.content |
Lu uniquement quand agent_type=reviewer et que le chemin est var/claude/reviewer-verdict.txt : la première ligne, débarrassée des espaces, est comparée à APPROVED. |
Règles de reset¶
Le compteur est remis à zéro dans deux cas :
agent_type=test-writeret chemin danstests/ousrc/DataFixtures/. Toute écriture (WriteouEdit) du test-writer dans cette zone reset le compteur, parce qu'elle marque une vague de tests produits — qu'il s'agisse d'un nouveau fichier ou de l'ajout d'assertions sur un test existant.agent_type=revieweret cheminvar/claude/reviewer-verdict.txtet contenu valantAPPROVED. Un verdictBLOCKEDne reset pas.
Les écritures effectuées par un sous-agent sont ignorées pour le comptage (seul le main Claude alimente le compteur).
Sortie¶
exit 0dans tous les cas — le hook n'est jamais bloquant.- À 3/5 ou plus : un objet JSON est écrit sur
stdoutavec un champsystemMessageinformatif (« 3/5 fichiers modifiés, pense à déléguer »). - À 5/5 ou plus : objet JSON avec
systemMessagecontenant la liste des fichiers suivis et un rappel de la checklist, plushookSpecificOutput.additionalContextinjecté dans le contexte de la session. - Lors d'un reset après verdict
APPROVED:systemMessageconfirme la réinitialisation du quota.
Effets de bord¶
| Fichier | Comportement |
|---|---|
var/claude/prod-php-files.txt |
Liste dédupliquée des chemins PHP de production. Ajout en append (grep -Fxq empêche les doublons). Supprimé lors d'un reset. |
var/claude/ |
Créé en mkdir -p au premier appel. Si la création ou l'écriture échoue (CWD hors racine, FS read-only, droits cassés), le hook fail-close proprement : avertissement sur stderr, exit 0, sans tracer. |
stop-checklist.sh¶
| Champ | Valeur |
|---|---|
| Fichier source | .claude/hooks/stop-checklist.sh |
| Événement Claude Code | Stop |
| Matcher | (aucun — Stop n'a pas de matcher) |
| Bloquant | Non (continue: true) |
Rôle¶
Rappelle la checklist de clôture (commandes Castor + délégations obligatoires) à chaque fin de tour, uniquement quand au moins un fichier PHP de production a été modifié dans la session. Sortie silencieuse sur les tours purement conversationnels.
Entrée¶
Le hook lit stdin puis le jette (cat >/dev/null) — aucun champ du JSON n'est consommé. La détection se fait à partir de l'état du dépôt et du tracker laissé par count-prod-php.sh :
| Source | Usage |
|---|---|
var/claude/prod-php-files.txt |
Si présent et non vide, considéré comme indicateur que des fichiers PHP de production ont été touchés ce tour ; le compte et la liste sont injectés dans le message. |
git diff --name-only HEAD |
Filtré sur ^src/.*\.php$ hors DataFixtures — détecte les modifications non commitées. |
git ls-files --others --exclude-standard |
Filtré de la même manière — détecte les nouveaux fichiers non commités. |
Sortie¶
exit 0silencieux si rien à signaler (ni tracker non vide, ni fichier PHP production sale dans Git).- Sinon, objet JSON sur
stdoutavec :systemMessage— checklist de clôture (cs:fix→phpstan→lint→doctrine:schema:validate→test:unit→test:e2e) suivie du rappel des délégations obligatoires (reviewer,test-writer,doc-writer) ; en cas de fichiers sales détectés via Git, ajout d'un avertissement « reviewer OBLIGATOIRE avant clôture » ; en cas de tracker non vide, liste des fichiers suivis.continue: true— le hook informe, il ne refuse jamais l'arrêt.
Effets de bord¶
Aucun. Le hook lit le tracker et l'état Git, puis émet un message — il n'écrit rien sur disque.