Accueil

Nos publications

Blog

Hooks Claude Code vs GitHub Copilot

néosoft hook IA

Acheter du déterminisme dans un monde probabiliste


Chaque instruction que vous donnez à un agent de code IA, que ce soit dans un CLAUDE.md, des Cursor rules, ou un copilot-instructions.md, n’est qu’une suggestion. Le LLM va probablement la suivre. Probablement. Mais probablement cela ne suffit pas quand on parle de sécurité, de qualité de code, ou de compliance.

Soyons francs. Votre LLM préféré peut oublier d’appeler un tool qu’il aurait dû appeler. Il peut ignorer une skill qu’il aurait dû déclencher. Il peut passer à côté d’une règle de sécurité parce qu’elle a été poussée hors de sa fenêtre de contexte par 200 lignes d’instructions. Et si quelqu’un vous dit qu’on peut sécuriser la génération de code uniquement via des règles textuelles ou un serveur MCP, ne l’ignorez pas, fuyez sans vous retourner ! C’est le créateur de la Ralph loop qui le dit (Geoffrey Huntley), et après neuf mois sans écrire une seule ligne de code à la main, il sait de quoi il parle.

Les hooks sont le mécanisme qui permet d’injecter des garanties déterministes dans un système fondamentalement probabiliste. Ce sont des commandes qui vont s’exécuter quand l’événement se produit, que le LLM le veuille ou non. Du code, pas de la prose. Et vu que les repos utilisant Copilot fuient 40 % plus de secrets que le développement traditionnel (GitGuardian), ce n’est pas un luxe. On ne parle pas d’un risque théorique. On parle de secrets en clair dans vos PRs.

C’est quoi un hook ? Du git hook au hook d’agent IA

Le cœur de toute bonne veille technologique réside dans l’utilisation d’agrégateurs de contenu. Camille a souligné l’importance d’outils comme Feedly et Inoreader, qui si vous avez déjà utilisé des git hooks (pre-commit, pre-push) vous connaissez le principe. Un script qui s’exécute automatiquement à un moment clé du workflow. Vous ne pouvez pas l’oublier. Vous ne pouvez pas le contourner (sauf --no-verify, mais c’est un acte conscient).

Les hooks d’agents IA sont exactement le même concept, transposé au cycle de vie d’un agent de code autonome. La différence, c’est que cette fois, l’acteur que vous cherchez à contraindre n’est pas un développeur humain — c’est un LLM.

Et c’est là que la distinction devient cruciale :

  • Une instruction dans CLAUDE.md ou copilot-instructions.md → c’est une suggestion. Le LLM décide s’il la suit. La plupart du temps il la suit. Mais « la plupart du temps », dans un système de production, ça veut dire « parfois il ne la suit pas ».
  • Un hook → c’est une garantie mécanique. Le système l’exécute. Le LLM n’a aucun contrôle dessus. Il ne peut pas décider de ne pas le déclencher.

C’est la même logique qu’ajouter un script de sécurité comme target obligatoire dans votre build. Que le développeur (humain ou IA) y pense ou non, le scan de sécurité sera exécuté avant que le code ne soit livré. Vous rendez l’action déterministe. Vous achetez de la certitude.

Le principe est simple et identique chez Claude Code et GitHub Copilot :

  • Le hook décide : approuver, refuser, modifier, ou simplement logger
  • L’agent déclenche un événement (il s’apprête à exécuter une commande bash, éditer un fichier, etc.)
  • Le hook reçoit le contexte en JSON via stdin (quel outil, quels arguments, quel répertoire)

L’agent peut halluciner, oublier des règles, ou mal interpréter votre prompt. Mais il ne peut pas contourner un hook qui refuse l’exécution d’une commande. La différence entre espérer que votre IA se comporte bien et garantir qu’elle ne puisse pas mal se comporter, c’est ça un hook.

Comparatif : Claude Code vs GitHub Copilot

Les deux plateformes proposent des hooks, mais leurs approches divergent significativement.

Les types de hooks disponibles

ÉvénementClaude CodeGitHub Copilot
Début de sessionSessionStartsessionStart
Fin de sessionSessionEndsessionEnd
Soumission de promptUserPromptSubmituserPromptSubmitted
Avant exécution outilPreToolUsepreToolUse
Après exécution outilPostToolUsepostToolUse
ErreurerrorOccurred
Demande de permissionPermissionRequest
NotificationNotification
Fin de réponseStopagentStop
Sous-agentsSubagentStop/StartsubagentStop
Modification d’inputupdatedInput
Setup/MaintenanceSetup

Le constat est net : Claude Code propose bien plus de types d’événements de Copilot. Chaque événement supplémentaire, c’est un point d’interception déterministe en plus. Copilot couvre l’essentiel, le preToolUse est bien là, et c’est le plus critique. Mais Claude Code va plus loin avec les hooks de sous-agents, la modification d’input avant exécution et les notifications.

Configuration : où et comment

Claude Code offre trois niveaux de configuration, du global au local :

  • ~/.claude/settings.json       → tous vos projets (global)
  • .claude/settings.json         → par projet (versionnable)
  • .claude/settings.local.json   → local uniquement (pas committé)

Il propose aussi une interface interactive via la commande /hooks et des matchers regex pour filtrer finement les outils (Edit|Write, Bash, mcp__github__.*). Ce dernier point est important : les matchers permettent aussi de surveiller les outils MCP (Model Context Protocol). Si votre agent interagit avec un serveur MCP GitHub, un serveur de base de données ou un service externe, vous pouvez intercepter ces appels exactement comme les commandes bash. Un matcher comme mcp__.*__write.* couvre tous les outils d’écriture de tous vos serveurs MCP. Le déterminisme ne s’arrête pas aux outils natifs mais s’étend à tout l’écosystème MCP.

GitHub Copilot adopte une approche plus simple mais plus contrainte : un fichier JSON dans .github/hooks/ du repository, qui doit être sur la branche par défaut.

Pas de configuration globale chez Copilot. Chaque repository doit être configuré séparément. Si vous avez 50 repos, vous avez 50 configurations à maintenir. Votre déterminisme s’arrête aux frontières du repo. C’est la limitation la plus remontée par la communauté. L’issue #1157 sur copilot-cli demande explicitement une configuration globale, citant Claude Code et Cursor comme exemples à suivre.

En revanche, Copilot marque un point sur le cross-platform : chaque hook peut déclarer un script bash et un script powershell dans la même définition. Claude Code ne propose pas d’équivalent natif. Si vous développez sur Windows, il faut gérer ça vous-même.

Communication hook ↔ agent

Les deux systèmes utilisent stdin (JSON) pour envoyer le contexte et stdout (JSON) pour recevoir la décision.

  • Claude Code utilise les exit codes : 0 = succès, 2 = blocage (stderr envoyé comme feedback), autre = erreur non bloquante.
  • GitHub Copilot attend un JSON en sortie avec permissionDecision: "deny". Pas de sortie = approuvé implicitement.

Claude Code étend le mécanisme avec la possibilité de modifier les inputs directement (updatedInput) — un vrai transparent sandboxing où le hook corrige silencieusement les paramètres.

En pratique : ce qu’on peut faire concrètement

Cinq cas d’usage concrets, côte à côte.

1. Bloquer les commandes dangereuses

Empêcher l’agent d’exécuter des commandes destructrices. Un rm -rf / échappé ne devrait jamais atteindre votre terminal. Les deux plateformes utilisent un hook preToolUse avec un script qui vérifie la commande contre des patterns dangereux (rm -rf, sudo, mkfs).

Différence clé : chez Claude Code, le matcher: "Bash" filtre en amont — le script ne s’exécute que pour les appels bash. Chez Copilot, le script doit vérifier toolName lui-même.

2. Forcer le linting après chaque édition

Claude Code utilise un PostToolUse avec matcher Edit|Write pour formater automatiquement les fichiers TypeScript après édition. Copilot utilise un preToolUse qui lint avant d’autoriser l’édition.

Différence clé : les matchers de Claude Code filtrent en amont. Copilot reçoit tous les événements et doit filtrer manuellement dans le script. Plus verbeux, plus fragile.

3. Audit et traçabilité

Chaque action de l’agent doit être traçable. Les deux plateformes permettent de logger chaque appel d’outil dans un CSV ou un fichier texte. Ce sont des hooks « passifs » : ils observent sans intervenir, mais leur exécution est garantie à chaque appel.

4. Protéger les fichiers sensibles

Empêcher l’agent de toucher aux .env, secrets/, ou package-lock.json. C’est d’autant plus critique face à l’attaque « Rules File Backdoor », découverte par Pillar Security en mars 2025, qui a montré que des instructions malveillantes cachées via des caractères Unicode dans des fichiers de configuration peuvent manipuler l’IA pour insérer du code malicieux. Les instructions textuelles ne sont pas un mécanisme de sécurité. Seul le code déterministe peut garantir que ces fichiers restent intouchés.

5. Notifications quand l’agent attend (Claude Code exclusif)

Le hook Notification permet de recevoir une alerte système quand l’agent a besoin de votre input. Copilot ne propose pas d’équivalent à ce jour

Les limites : à ce jour, pas demain

Les hooks ne sont pas une baguette magique. Ils ont leurs angles morts, et il est important de les connaître avant de construire une stratégie de sécurité dessus.

Partager ses favoris : apprendre des autres

Limites propres à Copilot

  • Pas de configuration globale. Chaque repo doit avoir sa propre config. 50 repos = 50 fichiers (issue #1157).
  • Conflit avec les git hooks existants. Le coding agent gère mal les hooks pre-commit/pre-push traditionnels (Discussion #167906). Quand ces hooks échouent, l’agent ne corrige pas, il abandonne avec un message d’erreur cryptique. Les garde-fous déterministes que vous aviez déjà mis en place sont sabotés par l’agent lui-même.
  • Pas de modification d’input. Quand un hook détecte un problème, il peut uniquement approuver ou refuser. Il ne peut pas corriger silencieusement les arguments avant l’exécution. Le déterminisme est binaire : oui ou non. Pas « oui, mais autrement ».

Limites propres à Claude Code

  • Bugs sur les hooks critiques. PreToolUse et PostToolUse ne se déclenchent parfois pas (issue #6305). Un hook qui ne s’exécute pas, ce n’est plus du déterminisme. C’est du silence.
  • Complexité de la configuration. Trois niveaux de settings (global, projet, local), des matchers regex, des policies enterprise… Plus c’est complexe, plus le risque de mauvaise configuration augmente.

Ce qui échappe au déterminisme, quel que soit l’outil

Au-delà des limitations propres à chaque plateforme (qui seront probablement résolues), il existe des limites plus fondamentales, inhérentes au concept même de hooks.

Le pattern matching a ses limites. Toutes les vérifications qu’on a vues reposent sur du grep, du regex, ou du string matching. Votre hook bloque rm -rf ? L’agent (ou un attaquant) pourrait utiliser find . -delete, ou python3 -c "import shutil; shutil.rmtree('/')", ou même un alias. Le déterminisme de l’exécution est garanti. La qualité de la détection, elle, dépend entièrement de votre script. Un hook mal écrit est un faux sentiment de sécurité, et un hook modifié à votre insu, via un repo cloné ou une PR malveillante, devient lui-même un vecteur d’attaque.

Le .cursorignore de Cursor illustre parfaitement ce décalage entre niveaux de protection. Ce fichier empêche les outils natifs de l’IDE d’accéder aux fichiers protégés, c’est du filtrage déterministe côté infrastructure, et ça fonctionne. Mais quand l’agent en mode agentique réalise qu’un fichier .env lui est inaccessible, il contourne la restriction via le terminal : ls pour lister, cat pour lire, echo >> pour écrire. La documentation de Cursor elle-même reconnaît que Chat et Composer ont accès à tous les fichiers dans leur contexte, indépendamment des paramètres .cursorignore. Le garde-fou existe à un niveau, mais l’agent opère à un autre. Un hook preToolUse sur les commandes bash, filtrant les noms de fichiers protégés, aurait bloqué cette manœuvre mécaniquement. C’est toute la différence entre une restriction au niveau de l’application et une garantie au niveau de l’exécution.

Et les menaces ne viennent pas que des commandes. L’attaque « Rules File Backdoor » a montré que l’IA peut obéir à des instructions sans que le développeur ne les voie. Les hooks pourraient-ils détecter le code malicieux résultant ? Peut-être, si vos scripts sont suffisamment sophistiqués. Mais du simple pattern matching ne suffira pas. C’est la preuve que les instructions ne sont pas un mécanisme de sécurité, et que même les hooks ne sont qu’une couche parmi d’autres.

Pas de conscience sémantique. Les hooks ne peuvent pas distinguer un rm -rf dist/ parfaitement légitime (nettoyage de build) d’un rm -rf / catastrophique. Aucune mise à jour de Copilot ou Claude Code ne le résoudra — c’est la nature même du mécanisme.

Où placer le curseur ?

Le spectre va du tout-probabiliste (tout repose sur le prompt et les instructions) au tout-déterministe (workflow rigide sans IA). Les hooks permettent de se positionner au milieu : l’agent garde sa flexibilité, mais des contraintes mécaniques garantissent un socle de sécurité.

C’est exactement l’analogie du build. Vous ajoutez des targets obligatoires (lint, test, security scan) que personne ne peut contourner. Le développeur peut écrire n’importe quoi ; le build ne passera pas si les contrôles échouent. Les hooks font la même chose pour l’agent IA. Ils ne garantissent pas que le code soit parfait. Ils garantissent un plancher de qualité en dessous duquel il ne peut pas descendre.

La vraie stratégie de défense en profondeur empile quatre couches :

  1. Instructions et prompts : probabilistes mais utiles. Le LLM les suit la plupart du temps. C’est votre première ligne, mais ne comptez pas dessus seule.
  2. Hooks : déterministes au niveau de l’agent. Ils s’exécutent quoi que le LLM décide. Votre plancher de garanties.
  3. CI/CD : déterministes au niveau du pipeline. Le filet de sécurité final avant la production. Lint, tests, SAST, dependency check.
  4. Review humaine : le jugement que ni les hooks ni la CI ne peuvent remplacer. Le regard qui comprend l’intention, pas juste le pattern.

Sauter une couche, c’est accepter un risque. Ne compter que sur la première, c’est de l’inconscience. Le code généré par l’IA n’est pas du code de confiance tant qu’il n’a pas franchi toutes les couches.

Conclusion

Dans un monde où le code est de plus en plus généré par des agents IA non-déterministes, les hooks sont le mécanisme qui vous permet d’acheter du déterminisme sans renoncer à la flexibilité de l’IA. Ils ne rendent pas l’IA parfaite. Ils garantissent un plancher de contrôle en dessous duquel elle ne peut pas descendre.

CritèresClaude CodeGitHub Copilot
Types d’événements12+8
Configuration globale
Cross-platform natif✅ (bash + PS)
Modification d’input
Matchers/filtres✅ (regex)❌ (manuel)
Intégration GitHub
Maturité⚠️ bugs⚠️ récent
Exécution parallèle❌ Séquentiel
Timeout10 min30 sec
Communauté⚠️ Petite mais technique✅ Massive (150M+ devs)
Market place hooks⚠️ En constructio
Protection contre hooks malveillants⚠️ Dialog d’avertissement + snapshot session

Claude Code est plus riche en fonctionnalités et plus flexible. Copilot est plus simple, mieux intégré à l’écosystème GitHub s’appuie sur une plus grande communauté. Mais le vrai choix n’est pas entre les deux, c’est entre avoir des hooks et ne pas en avoir.

La question n’est plus de savoir si les agents IA vont générer votre code. C’est déjà le cas. La question est de savoir si vous allez laisser ce code passer en production avec pour seule garantie un prompt bien tourné et une prière, ou si vous allez construire les garde-fous déterministes que la situation exige.

Vous souhaitez en savoir plus ? Contactez-nous !