Comment savoir quand Claude Code, Codex ou OpenCode vous attend
Claude Code vous signale qu’il attend par trois hooks : PreToolUse sur AskUserQuestion, une Notification permission_prompt, et un Stop dont le dernier message se termine par une question. Ignorez idle_prompt, qui arrive après toute réponse restée sans suite. Voici la correspondance qu’utilise Foxl Code pour les terminaux distants Claude Code, Codex, OpenCode et Hermes, ce que chaque CLI ne sait pas signaler, et comment écrire un hook qui coûte peu à l’agent et ne parle jamais au modèle par accident.

Sur cette page
Les hooks de Claude Code exécutent une commande de votre choix quand un événement donné se produit, et trois d’entre eux vous indiquent qu’il vous attend. Un hook PreToolUse sur l’outil AskUserQuestion se déclenche quand il ouvre sa boîte de dialogue de question. Un hook Notification de type permission_prompt se déclenche quand une boîte de dialogue d’autorisation est ouverte depuis quelques secondes. Un hook Stop se déclenche à la fin de chaque réponse et transporte le texte de la réponse dans last_assistant_message : vous pouvez donc vérifier s’il se termine par une question. Ignorez idle_prompt : il arrive environ une minute après toute réponse à laquelle personne n’a donné suite au clavier, pas seulement après une question.
Foxl Code, qui exécute des agents de code dans des terminaux distants, utilise exactement ces trois hooks pour signaler qu’un terminal Claude Code distant attend son utilisateur. Depuis v0.9.3-beta.5, la même commande de signalement lit aussi Codex, OpenCode et Hermes à travers leurs propres hooks et plugins. Voici la correspondance pour chaque CLI, les pièges de chacune, et la façon d’écrire le hook pour qu’il coûte le moins possible à l’agent et ne laisse jamais fuir de texte dans le contexte du modèle. Aucun terminal cloud en production n’a encore signalé de question ; la dernière section dit ce qui reste à vérifier.
Pourquoi ne voit-on pas qu’un agent dans un terminal attend ?
Quelqu’un qui fait tourner des agents dans des terminaux distants peut en avoir plusieurs ouverts à la fois sans en regarder aucun. Le 21 octobre 2026, un terminal Claude Code distant a posé une question appelant un oui ou un non et est resté en attente sur son invite, alors que l’API de Foxl elle-même indiquait qu’aucune tâche n’attendait personne. La barre latérale de Foxl Code, sa liste « Requiert votre attention » des tâches qui attendent une personne, et l’app mobile sont toutes restées muettes. Avant ce changement, rien dans Foxl Code n’était à l’écoute de ce moment.
Lire l’écran semble être la solution, mais c’est fragile. Pour un lecteur extérieur, les écrans « en réflexion », « terminé » et « en train de demander » ne diffèrent que de quelques caractères du dessin propre à la CLI, et n’importe quelle version peut les redessiner. Le jour où nous avons mis à jour les versions de CLI que nous livrons, les nouvelles builds dessinaient un premier écran différent de celui qu’attendait notre contrôle de saisie, et les terminaux Codex et OpenCode distants ont ignoré la frappe sans rien dire pendant dix jours. Un hook, c’est la CLI qui déclare elle-même ce qui vient de se passer, avec une charge utile documentée : c’est donc lui que nous écoutons.
Quels hooks de Claude Code veulent dire « je vous attends » ?
Nos images cloud figent Claude Code en version 2.1.296. Quand un détail ci-dessous est indiqué comme lu dans le paquet, il provient du paquet npm de cette version, et non d’un terminal en fonctionnement.
| hook | ce qu’il signifie | nous le traitons comme |
|---|---|---|
PreToolUse, matcher AskUserQuestion | la boîte de dialogue de question va s’ouvrir ; tool_input contient les questions et leurs options | une question, avec ses choix |
Notification, matcher permission_prompt | une boîte de dialogue d’autorisation est ouverte depuis environ six secondes sans aucune frappe (lu dans le paquet) | une demande d’autorisation |
Stop | la réponse est terminée ; last_assistant_message en est le texte | une question si le texte se termine par ?, sinon la fin d’un tour |
UserPromptSubmit, PostToolUse, PostToolUseFailure, SessionEnd | la personne a tapé quelque chose, l’outil approuvé s’est exécuté ou a échoué, la CLI s’est fermée | répondu |
Notification, type idle_prompt | « Claude a fini de répondre il y a environ 60 secondes et vous n’avez rien tapé depuis » | ignoré |
C’est sur la ligne idle_prompt que la plupart des configurations se trompent. Son message ressemble exactement à ce que l’on cherche, mais il suit toute réponse après laquelle personne n’a tapé : le traiter comme une question déclenche une alerte après presque chaque tour (dans le cas de Foxl, une entrée « Requiert votre attention » et une notification sur le téléphone). Nous enregistrons le hook Notification uniquement avec le matcher permission_prompt, et le script vérifie de nouveau le type. Pour le test sur Stop, nous retirons avant de regarder les espaces finaux, l’emphase Markdown, les backticks, les crochets et parenthèses fermants et les guillemets, et nous acceptons le ? pleine chasse que tapent les méthodes de saisie CJK.
La documentation actuelle de Claude Code mentionne aussi un événement dédié, PermissionRequest, et davantage de types de notification que ceux-ci. Nous n’avons pas vérifié si la 2.1.296 dispose de ce nouvel événement. permission_prompt figure toujours dans la liste actuelle, et son attente de six secondes écarte les boîtes de dialogue auxquelles quelqu’un répond devant l’écran. Ajoutez les hooks au fichier de réglages de Claude Code au niveau utilisateur, après les hooks déjà configurés pour le même événement, afin que les hooks existants continuent de s’exécuter :
{
"hooks": {
"PreToolUse": [{ "matcher": "AskUserQuestion",
"hooks": [{ "type": "command", "command": "report-prompt", "timeout": 10 }] }],
"Notification": [{ "matcher": "permission_prompt",
"hooks": [{ "type": "command", "command": "report-prompt", "timeout": 10 }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "report-prompt", "timeout": 10 }] }]
}
}Tous appellent un même petit script, la commande de signalement (report-prompt ci-dessus), qui lit l’identifiant de la tâche dans son environnement. Les événements qui signifient que la personne a répondu, UserPromptSubmit et les autres (les événements de fermeture), sont enregistrés de la même manière, derrière une garde décrite plus bas.
Comment écrire un hook qui coûte le moins possible à l’agent ?
Un hook de signalement s’exécute dans la boucle même de l’agent : chacune de ses erreurs devient donc le problème de l’agent. Nous sommes arrivés à cinq règles, chacune tirée de la documentation ou du paquet 2.1.296 :
- Ne rien écrire sur stdout. Pour la plupart des événements, Claude Code se contente de journaliser la sortie standard d’un hook, mais pour
UserPromptSubmitet quelques autres, « Claude Code ajoute la sortie standard en texte brut comme contexte que Claude peut voir et exploiter ». Une ligne d’état écrite par un script de signalement deviendrait une partie du prompt. - Toujours terminer avec le code 0. Le code 2 bloque l’action sur les événements qui peuvent bloquer, et tout autre code non nul affiche un avertissement d’erreur. Dans notre script, une panne réseau coûte une ligne sur stderr et rien de plus.
- S’exécuter de façon synchrone, avec un délai court. Les hooks peuvent s’exécuter avec
"async": true, mais la build figée affiche une ligne dans le terminal chaque fois qu’un hook asynchrone se termine, ce qui devient du bruit quand des hooks s’exécutent après chaque appel d’outil. Nos hooks sont synchrones avectimeout: 10, et le script accorde trois secondes à sa requête puis se termine de lui-même un instant plus tard. Sur Claude Code, le vrai coût est un démarrage de Node.js et une requête à la fin de chaque réponse, soit au plus environ trois secondes quand le serveur de Foxl est injoignable. - Filtrer les événements fréquents dans le shell.
PostToolUsese déclenche à chaque appel d’outil. La commande de signalement crée un fichier marqueur quand elle signale une question ouverte. Les hooks de fermeture ne démarrent Node.js que si ce fichier existe, et sinon vident stdin pour que la CLI ne voie jamais de tube cassé :
Tant que rien n’est ouvert, cela représente unif [ -e /tmp/foxl-agent-prompt/open ]; then exec report-prompt; else cat >/dev/null; fitest -epar appel d’outil. - Garder l’identifiant hors de la ligne de commande. Le hook hérite de l’environnement de la CLI : le jeton est donc lu dans une variable d’environnement et n’apparaît jamais dans
ps.
Comment Codex, OpenCode et Hermes le disent-ils ?
Chaque CLI a son propre point d’extension ; nous avons lu chacun dans la version que nos images figent. Codex a un moteur de hooks qui accepte le format de hooks de Claude Code. OpenCode et Hermes (la CLI d’agent de Nous Research) n’exécutent aucun hook shell dans leur interface en terminal ; ils chargent des plugins, et nos plugins transmettent un événement normalisé à la même commande de signalement. Kiro, la CLI de code d’AWS, n’a aucun événement à écouter.
| CLI (version figée) | demande | répondu | non signalé |
|---|---|---|---|
Codex 0.162.1, un hooks.json au niveau système | PermissionRequest ; Stop dont le last_assistant_message se termine par ? | UserPromptSubmit, PostToolUse, Interrupt, SessionEnd | la boîte de dialogue de question du mode Plan |
| OpenCode 1.19.0, un plugin serveur | question.asked, permission.asked ; session.status inactif avec une réponse qui se termine par ? | question.replied ou rejected, permission.replied, session.status occupé | - |
| Hermes 0.19.0, un plugin Python | pre_tool_call pour clarify, pre_approval_request, post_llm_call se terminant par ? | post_tool_call pour clarify, post_approval_response, pre_llm_call, un on_session_end interrompu | - |
| Kiro 2.29.1 | rien | - | tout : aucun événement de question ou d’approbation, et son Stop ne transporte aucun texte de réponse |
Codex. Codex examine les hooks de votre propre configuration avant de les exécuter : les hooks nouveaux ou modifiés « sont marqués pour examen et ignorés tant qu’ils ne sont pas approuvés ». Un hook géré, défini dans la configuration au niveau système, est approuvé par la politique : c’est donc ainsi que nous installons les nôtres. La commande de signalement elle-même n’est installée que dans les terminaux où Foxl Code a demandé des signalements de questions. Mesuré sur 0.162.1, le mode non interactif codex exec exécute lui aussi les hooks gérés et affiche deux lignes à leur sujet par appel d’outil dans sa sortie : nous désactivons donc les hooks pour les exécutions que Foxl Code lance avec codex exec. D’après le code source de la 0.162.1, l’interface en terminal de Codex affiche tout hook qui dure plus de 300 ms : la commande de signalement détermine donc s’il y a une question, écrit son fichier marqueur, et confie la requête réseau à une copie détachée d’elle-même.
La boîte de dialogue de question du mode Plan de Codex n’est volontairement pas signalée, car son hook PreToolUse se déclenche avant que Codex ne décide si la question est autorisée, et hors du mode Plan, Codex la refuse. Mesuré sur 0.162.1, le hook s’est déclenché avec la question, puis Codex a répondu « request_user_input is unavailable in Default mode ». Les terminaux de Foxl Code démarrent en mode Default : signaler ce hook enverrait donc sur votre téléphone une question que personne n’a jamais posée. La contrepartie, c’est qu’un terminal Codex en mode Plan ne fait pas apparaître sa boîte de dialogue de question dans « Requiert votre attention ».
OpenCode. Notre plugin écoute le bus d’événements d’OpenCode. Les événements de question ne figurent pas dans la liste d’événements de la documentation des plugins d’OpenCode ; ils se trouvent dans le code source du schéma de la v1.19.0, et c’est lui que nous avons lu. Un état inactif termine un tour, et le tour compte comme une question quand sa dernière réponse se termine par ?. Tant qu’une boîte de dialogue de question ou d’autorisation est ouverte, les changements d’état sont ignorés : l’agent qui passe occupé ou inactif autour de la boîte de dialogue ne la ferme donc pas. Les événements de la session d’un sous-agent sont ignorés.
Hermes. Malgré son nom, le on_session_end de Hermes se déclenche à la fin de chaque tour sur la 0.19.0, juste après la réponse. Quand notre plugin le traitait comme une fermeture, il retirait la question que le tour venait de poser : 7 questions sur 12 ont été fermées aussitôt, et dans 1 cas sur 12, la question est arrivée au serveur après sa propre fermeture, si bien qu’elle est restée ouverte sans plus rien pour la fermer. Désormais, seule une fin de session interrompue compte comme une fermeture, et les signalements partent un par un, dans l’ordre où Hermes les a émis.
Kiro n’est pas couvert, car ses hooks n’ont aucun événement de question ou d’approbation, et la charge utile de son arrêt ne transporte aucun texte de réponse. Un hook ne pourrait ni ouvrir une question ni distinguer une question d’une réponse. Le seul signal est un fichier de session interne dans un format non publié, et nous avons choisi de ne pas l’analyser.
Que se passe-t-il une fois que Foxl le sait ?
Chaque signalement est envoyé à un seul endpoint du serveur de Foxl Code, authentifié avec l’identifiant propre à la tâche, et ouvre ou ferme une entrée dans la même liste « Requiert votre attention » que celle qui regroupe les autres questions des agents. La tâche est marquée comme en attente de votre réponse, comme sur la figure.

On peut répondre à une question posée à la fin d’une réponse depuis « Requiert votre attention » ou depuis le téléphone. Foxl tape la réponse dans le terminal de cette tâche en une seule ligne, puis envoie la touche Entrée séparément une seconde plus tard, car un bloc unique qui inclut Entrée est traité comme un collage et n’est jamais envoyé. Pour une boîte de dialogue de question ou d’autorisation, Foxl ne devine jamais les frappes qu’attend l’interface du terminal. À la place, sa carte dans « Requiert votre attention » liste les choix, indique de répondre dans le terminal, et propose un bouton qui ouvre le terminal. Répondre dans le terminal ferme la carte par les mêmes hooks.
Le téléphone n’est notifié que pour les questions qui risquent de passer inaperçues. Une boîte de dialogue de question ou d’autorisation encore ouverte 15 secondes après que Foxl en a été informé déclenche une notification, puisqu’une personne qui regarde le terminal répond en quelques secondes. Une boîte de dialogue d’autorisation de Claude Code est signalée environ six secondes après son ouverture : sa notification arrive donc au bout d’environ 21 secondes. Une réponse qui se termine par une question apparaît dans « Requiert votre attention » mais n’est pas annoncée, car beaucoup de réponses se terminent ainsi. La question du 21 octobre 2026 était de ce type : elle apparaîtrait désormais dans « Requiert votre attention » et sur la tâche, et ne ferait toujours pas sonner le téléphone.

Qu’est-ce qui reste à vérifier ?
Dans nos tests, la vraie commande de signalement a tourné sur les charges utiles de chaque CLI figée, les plugins ont tourné sous Node.js et Python sur les formats d’événements figés, et l’endpoint du serveur a tourné dans une copie locale du runtime de Cloudflare. Ce qui n’a pas encore eu lieu :
- Une vraie question venue d’un vrai terminal cloud. Au 23 octobre 2026, la table de production ne contient aucune question venant d’un tel terminal : la vérification de bout en bout sur un terminal en production reste donc à faire.
- Claude Code exécutant ces hooks. Les détails de Claude Code, dont le délai de six secondes et la ligne des hooks asynchrones, ont été lus dans le paquet 2.1.296, et non observés sur un terminal en fonctionnement. Nous avons un test qui exécute cette build avec ces hooks ; il n’a pas encore été lancé.
- Les terminaux des autres CLI. Plusieurs détails de Codex, OpenCode et Hermes ont été lus dans le code source, dont le fait qu’OpenCode émet les événements de question sous ces noms exacts ; seul
codex execa été exécuté.
Si vous faites tourner des agents dans vos propres terminaux, c’est le tableau des hooks de Claude Code qu’il faut reprendre. Branchez les trois hooks sur ce qui vous joint, ignorez idle_prompt, n’écrivez rien, terminez avec le code 0, et attendez quelques secondes avant d’envoyer une alerte. Pour le côté terminal de Foxl Code, notre article expliquant pourquoi, pendant un temps, chaque frappe partait sur la mauvaise machine explique comment la frappe parvient jusqu’à un agent distant.
Références et lectures complémentaires
- Claude Code : référence des hooksDocumentation
- Codex : hooksDocumentation
- OpenCode : pluginsDocumentation
- Hermes Agent (Nous Research)Référence
- Version Foxl v0.9.3-beta.5Version