Aller au contenu

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 stdinjq 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 sur stderr (chemin refusé, raison du refus, action attendue).
  • exit 2 également si jq n'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 est bin/console) ;
  • le chemin est dans src/, public/ ou bin/ ;
  • le chemin n'est pas dans tests/ ni src/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-writer et chemin dans tests/ ou src/DataFixtures/. Toute écriture (Write ou Edit) 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=reviewer et chemin var/claude/reviewer-verdict.txt et contenu valant APPROVED. Un verdict BLOCKED ne 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 0 dans tous les cas — le hook n'est jamais bloquant.
  • À 3/5 ou plus : un objet JSON est écrit sur stdout avec un champ systemMessage informatif (« 3/5 fichiers modifiés, pense à déléguer »).
  • À 5/5 ou plus : objet JSON avec systemMessage contenant la liste des fichiers suivis et un rappel de la checklist, plus hookSpecificOutput.additionalContext injecté dans le contexte de la session.
  • Lors d'un reset après verdict APPROVED : systemMessage confirme 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 0 silencieux si rien à signaler (ni tracker non vide, ni fichier PHP production sale dans Git).
  • Sinon, objet JSON sur stdout avec :
    • systemMessage — checklist de clôture (cs:fixphpstanlintdoctrine:schema:validatetest:unittest: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.