Hooks de Cycle de Vie de Session Claude Code
Quatre hooks de cycle de vie de session Claude Code : lance init à la demande, injecte le contexte du projet au SessionStart, sauvegarde les transcripts, et journalise le nettoyage à la sortie SessionEnd.
Arrêtez de configurer. Commencez à construire.
Templates SaaS avec orchestration IA.
Problème : Chaque nouvelle session commence à l'aveugle. Tu ré-expliques la branche sur laquelle tu es, la file de tâches, et les variables d'env dont tes scripts ont besoin. Quand la session se termine, le nettoyage qui devrait se produire ne se produit jamais.
Victoire rapide : Colle ça dans settings.json. Le contexte Git arrive dans le chat à chaque démarrage :
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "echo '## Git' && git branch --show-current && git status --short | head -10"
}
]
}
]
}
}Chaque session s'ouvre maintenant avec du contexte. Zéro configuration manuelle.
Les Quatre Hooks du Cycle de Vie de Session
Le comportement de session est piloté par quatre types de hooks :
| Hook | Quand il se déclenche | Peut bloquer ? | Cas d'usage |
|---|---|---|---|
| Setup | Avec --init ou --maintenance | NON | Configuration initiale, migrations |
| SessionStart | Chaque démarrage/reprise de session | NON | Charger le contexte, définir les variables d'env |
| PreCompact | Avant la compaction du contexte | NON | Sauvegarder les transcripts |
| SessionEnd | La session se termine | NON | Nettoyage, journalisation |
SessionStart : Charge le Contexte à Chaque Fois
SessionStart s'exécute chaque fois qu'une session commence ou reprend. Utilise-le quand quelque chose devrait toujours être dans la tête de Claude.
Injection de Contexte Basique
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "echo '## Project State' && cat .claude/tasks/session-current.md 2>/dev/null || echo 'No active session'"
}
]
}
]
}
}Avec Sortie JSON
Pour une injection de contexte structurée :
#!/usr/bin/env python3
import json
import sys
import subprocess
def get_project_context():
try:
branch = subprocess.check_output(
['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
text=True, stderr=subprocess.DEVNULL
).strip()
status = subprocess.check_output(
['git', 'status', '--porcelain'],
text=True, stderr=subprocess.DEVNULL
).strip()
changes = len(status.split('\n')) if status else 0
except:
branch, changes = "unknown", 0
return f"""=== SESSION CONTEXT ===
Git Branch: {branch}
Uncommitted Changes: {changes}
=== END ===""".strip()
output = {
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": get_project_context()
}
}
print(json.dumps(output))
sys.exit(0)Matchers SessionStart
Cible des événements de session spécifiques :
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [{ "type": "command", "command": "echo 'Fresh session'" }]
},
{
"matcher": "resume",
"hooks": [{ "type": "command", "command": "echo 'Resumed session'" }]
},
{
"matcher": "compact",
"hooks": [{ "type": "command", "command": "echo 'Post-compaction'" }]
}
]
}
}startup- Nouvelle sessionresume- Depuis--resume,--continue, ou/resumeclear- Après/clearcompact- Après compaction
Persister les Variables d'Environnement
SessionStart a accès à CLAUDE_ENV_FILE pour définir des variables d'environnement valables pour toute la session :
#!/bin/bash
# Persist environment changes from nvm, pyenv, etc.
ENV_BEFORE=$(export -p | sort)
# Setup commands that modify environment
source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$CLAUDE_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0Tout ce qui est écrit dans CLAUDE_ENV_FILE apparaît dans chaque commande bash que Claude exécute après ça.
Setup : Opérations Ponctuelles
Les hooks Setup ne s'exécutent que quand tu invoques explicitement --init, --init-only, ou --maintenance. Bien pour le travail que tu ne veux pas déclencher à chaque nouvelle session.
Quand Utiliser Setup vs SessionStart
| Opération | Utilise Setup | Utilise SessionStart |
|---|---|---|
| Installer les dépendances | Oui | Non |
| Lancer les migrations de base de données | Oui | Non |
| Charger le statut git | Non | Oui |
| Définir les variables d'environnement | Oui | Oui |
| Injecter le contexte du projet | Non | Oui |
| Nettoyer les fichiers temporaires | Oui (maintenance) | Non |
Configuration Setup
{
"hooks": {
"Setup": [
{
"matcher": "init",
"hooks": [
{
"type": "command",
"command": "npm install && npm run db:migrate"
}
]
},
{
"matcher": "maintenance",
"hooks": [
{
"type": "command",
"command": "npm prune && npm dedupe && rm -rf .cache"
}
]
}
]
}
}Invoque avec :
claude --init # Runs 'init' matcher
claude --init-only # Runs 'init' matcher, then exits
claude --maintenance # Runs 'maintenance' matcherLes hooks Setup peuvent aussi écrire dans CLAUDE_ENV_FILE pour persister les variables d'environnement.
PreCompact : Avant la Perte de Contexte
PreCompact se déclenche juste avant la compaction, que l'utilisateur l'ait déclenchée avec /compact ou qu'elle se soit lancée automatiquement quand la fenêtre s'est remplie.
Sauvegarder les Transcripts
#!/usr/bin/env python3
import json
import sys
import shutil
from pathlib import Path
from datetime import datetime
input_data = json.load(sys.stdin)
transcript_path = input_data.get('transcript_path', '')
trigger = input_data.get('trigger', 'unknown')
if transcript_path and Path(transcript_path).exists():
backup_dir = Path('.claude/backups')
backup_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_name = f"transcript_{trigger}_{timestamp}.jsonl"
shutil.copy2(transcript_path, backup_dir / backup_name)
# Keep only last 10 backups
backups = sorted(backup_dir.glob('transcript_*.jsonl'))
for old_backup in backups[:-10]:
old_backup.unlink()
sys.exit(0)Matchers PreCompact
{
"hooks": {
"PreCompact": [
{
"matcher": "auto",
"hooks": [{ "type": "command", "command": "echo 'Auto-compacting...'" }]
},
{
"matcher": "manual",
"hooks": [{ "type": "command", "command": "echo 'Manual /compact'" }]
}
]
}
}auto- La fenêtre de contexte s'est remplie, compaction automatiquemanual- L'utilisateur a lancé/compact
Créer des Marqueurs de Récupération
Associe PreCompact avec SessionStart pour reconstruire le contexte après un événement de compaction. Un pattern qui marche : un module backup-core partagé, un moniteur statusline qui déclenche des triggers basés sur des seuils, et un gestionnaire PreCompact, tous coordonnés via un seul fichier d'état pour que rien ne soit perdu entre les sessions. Consulte le guide Context Recovery Hook pour le walkthrough complet.
SessionEnd : Nettoyage
SessionEnd s'exécute quand une session est sur le point de se terminer. Il ne peut pas bloquer l'arrêt, mais il peut faire du nettoyage.
Journaliser les Stats de Session
#!/usr/bin/env python3
import json
import sys
from pathlib import Path
from datetime import datetime
input_data = json.load(sys.stdin)
session_id = input_data.get('session_id', 'unknown')
reason = input_data.get('reason', 'unknown')
log_dir = Path('.claude/logs')
log_dir.mkdir(parents=True, exist_ok=True)
log_entry = {
"session_id": session_id,
"ended_at": datetime.now().isoformat(),
"reason": reason
}
with open(log_dir / 'session-history.jsonl', 'a') as f:
f.write(json.dumps(log_entry) + '\n')
sys.exit(0)Raisons de SessionEnd
Le champ reason te dit pourquoi la session s'est terminée :
clear- L'utilisateur a lancé/clearlogout- L'utilisateur s'est déconnectéprompt_input_exit- L'utilisateur a quitté pendant que le prompt était visibleother- Autres raisons de sortie
Exemple de Cycle de Vie Complet
Une configuration complète de cycle de vie câblée de bout en bout :
{
"hooks": {
"Setup": [
{
"matcher": "init",
"hooks": [
{
"type": "command",
"command": "npm install && echo 'Dependencies installed'"
}
]
}
],
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "echo '## Context' && git status --short && echo '## Tasks' && cat .claude/tasks/session-current.md 2>/dev/null | head -20"
}
]
}
],
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "cp \"$CLAUDE_TRANSCRIPT_PATH\" .claude/backups/last-transcript.jsonl 2>/dev/null || true"
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "echo \"Session ended: $(date)\" >> .claude/logs/sessions.log"
}
]
}
]
}
}Payloads d'Entrée
Entrée SessionStart
{
"session_id": "abc123",
"hook_event_name": "SessionStart",
"source": "startup",
"model": "claude-sonnet-4-20250514",
"cwd": "/path/to/project"
}Entrée Setup
{
"session_id": "abc123",
"hook_event_name": "Setup",
"trigger": "init",
"cwd": "/path/to/project"
}Entrée PreCompact
{
"session_id": "abc123",
"hook_event_name": "PreCompact",
"transcript_path": "~/.claude/projects/.../transcript.jsonl",
"trigger": "auto",
"custom_instructions": ""
}Entrée SessionEnd
{
"session_id": "abc123",
"hook_event_name": "SessionEnd",
"reason": "clear",
"cwd": "/path/to/project"
}Bonnes Pratiques
-
Garde SessionStart rapide : Il s'exécute à chaque session. Pousse le travail lourd dans Setup.
-
Utilise Setup pour le travail ponctuel : Installations de dépendances, migrations, bootstrap initial du projet.
-
Sauvegarde avant la compaction : PreCompact est ta dernière chance de récupérer le transcript.
-
Journalise les fins de session : SessionEnd est pratique pour l'analytique et le débogage.
-
Matche avec soin : Un comportement différent pour
startupvsresumevscompactévite les surprises.
Prochaines Étapes
- Configure le guide principal des Hooks pour les 12 hooks
- Configure Context Recovery pour survivre à la compaction
- Utilise les Stop Hooks pour l'application des tâches
- Explore Skill Activation pour le chargement automatique de skills
Arrêtez de configurer. Commencez à construire.
Templates SaaS avec orchestration IA.