Build This Now
Build This Now
Raccourcis clavierGuide de la Status Line
Guide des HooksHooks cross-platform pour Claude CodeHooks de configuration Claude CodeStop HooksAgents Claude Code Auto-ValidantsHooks de Cycle de Vie de Session Claude CodeHooks de sauvegarde de contexte pour Claude CodeHook d'activation des skillsHook de Permission Claude Code
speedy_devvkoen_salo
Blog/Toolkit/Hooks/Stop Hooks

Stop Hooks

Les stop hooks empêchent Claude Code de terminer un tour tant que les tests échouent, le build est cassé, ou le lint est rouge. Quatre patterns d'application plus des protections anti-boucle infinie.

Arrêtez de configurer. Commencez à construire.

Templates SaaS avec orchestration IA.

Published Feb 25, 2026Toolkit hubHooks index

Problème : Claude termine une réponse, mais le travail n'est pas vraiment fini. Les tests échouent encore. Des fichiers sont à moitié écrits. Tu demandes "tu as terminé ?" et tu obtiens un oui, pendant que le build est rouge.

Solution rapide : Ajoute ce Stop hook et Claude ne peut plus terminer le tour tant que les tests ne sont pas au vert :

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python .claude/hooks/test-gate.py"
          }
        ]
      }
    ]
  }
}
#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
# CRITICAL: Prevent infinite loops
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
# Run tests
result = subprocess.run(['npm', 'test'], capture_output=True, timeout=60)
 
if result.returncode != 0:
    output = {
        "decision": "block",
        "reason": "Tests are failing. Fix them before completing."
    }
    print(json.dumps(output))
    sys.exit(0)
 
sys.exit(0)

À partir de là, Claude ne peut littéralement plus clore un tour avec une suite en échec.

Comment fonctionne le Stop Hook

Chaque fois que Claude veut terminer une réponse, ce hook se déclenche. Trois choses peuvent se passer :

  1. Autoriser l'arrêt - Exit 0, et le tour se termine proprement.
  2. Bloquer l'arrêt - Retourne {"decision": "block", "reason": "..."}, et Claude continue.
  3. Lancer des validations - Exécute des tests, des vérifications, ou n'importe quel script.

Le payload

{
  "session_id": "uuid-string",
  "stop_hook_active": false,
  "transcript_path": "/path/to/transcript.jsonl"
}

Fais attention à stop_hook_active. Une valeur true signifie que Claude est déjà dans un état de continuation forcée suite à un blocage précédent. Manquer ce flag et tu te retrouves dans une boucle infinie.

Pattern 1 : Test Gate

Garde le tour ouvert jusqu'à ce que tous les tests passent :

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
result = subprocess.run(
    ['npm', 'test', '--passWithNoTests'],
    capture_output=True,
    timeout=120
)
 
if result.returncode != 0:
    # Extract last 10 lines of test output for context
    stderr = result.stderr.decode()[-500:] if result.stderr else ""
    print(json.dumps({
        "decision": "block",
        "reason": f"Tests failing. Output: {stderr}"
    }))
    sys.exit(0)
 
sys.exit(0)

Pattern 2 : Validation du build

Bloque tant que le projet ne compile pas :

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
result = subprocess.run(
    ['npm', 'run', 'build'],
    capture_output=True,
    timeout=180
)
 
if result.returncode != 0:
    print(json.dumps({
        "decision": "block",
        "reason": "Build failed. Fix compilation errors before completing."
    }))
    sys.exit(0)
 
sys.exit(0)

Pattern 3 : Vérification du lint

Pas question de quitter le tour avec des erreurs de lint :

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
result = subprocess.run(
    ['npx', 'eslint', 'src/', '--max-warnings=0'],
    capture_output=True,
    timeout=60
)
 
if result.returncode != 0:
    print(json.dumps({
        "decision": "block",
        "reason": "Lint errors detected. Run eslint --fix or resolve manually."
    }))
    sys.exit(0)
 
sys.exit(0)

Pattern 4 : Marqueur de complétion de tâche

Conditionne le tour à un flag de tâche spécifique :

#!/usr/bin/env python3
import json
import sys
from pathlib import Path
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
# Check for incomplete task marker
marker = Path('.claude/incomplete-task')
if marker.exists():
    task_info = marker.read_text().strip()
    print(json.dumps({
        "decision": "block",
        "reason": f"Task incomplete: {task_info}. Finish it before stopping."
    }))
    sys.exit(0)
 
sys.exit(0)

Dépose le marqueur au début du travail :

echo "Implement user authentication" > .claude/incomplete-task

Supprime-le quand c'est terminé :

rm .claude/incomplete-task

Éviter les boucles infinies

Voilà pourquoi le flag stop_hook_active est important. Sans lui, tu obtiens ça :

Claude responds → Stop hook fires → "block" → Claude continues
                                            ↓
Claude responds → Stop hook fires → INFINITE LOOP (without flag check)

Vérifie toujours le flag en premier :

if input_data.get('stop_hook_active', False):
    sys.exit(0)  # Allow stopping, break the loop

Combiner plusieurs vérifications

Un seul hook peut enchaîner plusieurs contrôles :

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
checks = [
    (['npm', 'run', 'lint'], "Lint errors"),
    (['npm', 'run', 'typecheck'], "Type errors"),
    (['npm', 'test'], "Test failures"),
]
 
for cmd, error_msg in checks:
    result = subprocess.run(cmd, capture_output=True, timeout=120)
    if result.returncode != 0:
        print(json.dumps({
            "decision": "block",
            "reason": f"{error_msg} detected. Fix before completing."
        }))
        sys.exit(0)
 
sys.exit(0)

Quand utiliser les Stop Hooks

Bons cas d'usage :

  • Conditionner à une suite de tests verte avant "tâche terminée"
  • S'assurer que le build compile toujours
  • Attraper les erreurs de lint et de types
  • Toute règle personnalisée sur ce que "terminé" signifie pour toi

Mauvais cas d'usage :

  • Tout ce qui dépasse le timeout de 60 secondes
  • Les vérifications réseau qui flanchent parfois
  • Les prompts qui attendent une réponse humaine (pas d'interaction ici)

Configuration

Branche-le dans .claude/settings.json :

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python .claude/hooks/stop-validation.py"
          }
        ]
      }
    ]
  }
}

Plusieurs hooks peuvent tourner en même temps, en parallèle. Un block de l'un d'eux suffit à maintenir Claude en activité.

Débogage

Bloqué dans une boucle ?

  • Vérifie bien que tu lis stop_hook_active au début du script
  • Logge-le : echo "stop_hook_active: $stop_hook_active" >> ~/.claude/stop-debug.log

Le block ne fonctionne pas ?

  • Le JSON doit ressembler à {"decision": "block", "reason": "..."}
  • Utilise le code de sortie 0, pas 2. Le code 2 correspond à un autre chemin de blocage.

Les tests tournent trop longtemps ?

  • Le timeout du hook est de 60 secondes
  • Lance un sous-ensemble plus petit, ou accélère la suite

Le pattern "Ralph Wilgum"

Ça vient d'une technique communautaire qui utilise les Stop hooks pour forcer une boucle de tâche persistante :

  1. Dépose un marqueur de tâche au début de la session
  2. Le Stop hook bloque tant que le marqueur est là
  3. Tu exiges que Claude supprime le marqueur comme preuve de complétion
  4. Plus de "j'ai terminé" accidentel avec du travail encore ouvert

Le résultat : Claude passe du mode best-effort au mode garantie de finir.

Prochaines étapes

  • Lis le guide Hooks principal pour voir tous les types de hooks
  • Configure le Context Recovery pour que les sessions survivent à la compaction
  • Configure le Skill Activation pour le chargement automatique des skills
  • Consulte les Permission Hooks pour les flux d'auto-approbation

Continue in Hooks

  • Hooks de configuration Claude Code
    Assemble scripts, agents et docs dans des hooks de configuration Claude Code. Une commande lance un script déterministe, passe la sortie à un agent de diagnostic, et journalise une doc vivante.
  • Hooks de sauvegarde de contexte pour Claude Code
    Un hook de sauvegarde de contexte Claude Code piloté par StatusLine. Écrit des snapshots structurés toutes les 10K tokens pour que la compaction automatique ne mange jamais les erreurs, signatures et décisions.
  • Hooks cross-platform pour Claude Code
    Hooks Claude Code cross-platform : supprime les wrappers .cmd, .sh et .ps1 et invoque node directement pour qu'un seul fichier .mjs tourne sur macOS, Linux et Windows dans toute l'équipe.
  • Guide des Hooks
    Les hooks Claude Code depuis les bases : codes de sortie, sortie JSON, commandes asynchrones, endpoints HTTP, matchers PreToolUse et PostToolUse, patterns de production.
  • Hook de Permission Claude Code
    Installe un hook de permission Claude Code à trois niveaux : approbation instantanée pour les appels sûrs, refus instantané pour les dangereux, vérification LLM pour la zone grise. Sans flag skip.
  • Agents Claude Code Auto-Validants
    Agents Claude Code auto-validants : câble des hooks lint PostToolUse, des hooks Stop, et des sous-agents réviseurs en lecture seule dans les définitions d'agents pour que le mauvais code ne soit jamais livré.

More from Toolkit

  • Raccourcis clavier
    Configurer keybindings.json dans Claude Code : 17 contextes, syntaxe des touches, séquences d'accords, combinaisons de modificateurs, et comment désactiver n'importe quel raccourci par défaut instantanément.
  • Guide de la Status Line
    Configure une status line Claude Code affichant le nom du modèle, la branche git, le coût de session et l'utilisation du contexte. Config settings.json, JSON d'entrée, scripts bash, Python, Node.js.
  • SEO IA et optimisation GEO
    Un tour d'horizon de la Generative Engine Optimization : comment faire citer ton contenu dans les réponses de ChatGPT, Claude et Perplexity plutôt que simplement classé sur Google.
  • Claude Code vs Cursor en 2026
    Une comparaison côte à côte de Claude Code et Cursor en 2026 : modèles d'agents, fenêtres de contexte, niveaux de prix, et comment chaque outil s'adapte aux différents workflows des développeurs.

Arrêtez de configurer. Commencez à construire.

Templates SaaS avec orchestration IA.

On this page

Comment fonctionne le Stop Hook
Le payload
Pattern 1 : Test Gate
Pattern 2 : Validation du build
Pattern 3 : Vérification du lint
Pattern 4 : Marqueur de complétion de tâche
Éviter les boucles infinies
Combiner plusieurs vérifications
Quand utiliser les Stop Hooks
Configuration
Débogage
Le pattern "Ralph Wilgum"
Prochaines étapes

Arrêtez de configurer. Commencez à construire.

Templates SaaS avec orchestration IA.