Hooks
Exécutez des scripts déterministes au cours du cycle de vie de Codex
Les hooks constituent un framework d’extensibilité pour Codex. Ils vous permettent d’injecter vos propres scripts dans la boucle agentique, afin d’activer des fonctionnalités telles que :
- Envoyer la conversation à un moteur personnalisé de journalisation ou d’analyse
- Analyser les prompts de votre équipe pour empêcher le collage accidentel de clés API
- Résumer automatiquement les conversations afin de créer des mémoires persistantes
- Exécuter un contrôle de validation personnalisé à l’arrêt d’un tour de conversation, afin de faire respecter les normes
- Personnaliser les prompts lorsque vous vous trouvez dans un répertoire donné
Comportements d’exécution à garder à l’esprit :
- Tous les hooks correspondants provenant de plusieurs fichiers sont exécutés.
- Plusieurs hooks de commande correspondant au même événement sont lancés simultanément ; un hook ne peut donc pas empêcher le démarrage d’un autre hook correspondant.
- Les hooks de commande non gérés doivent être examinés et approuvés avant leur exécution.
Les hooks s’exécutent à différents moments d’une conversation :
| Moment | Hooks |
|---|---|
| Pendant un tour | PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop |
| Au démarrage d’une session ou d’un sous-agent | SessionStart, SubagentStart |
| À la fin du fil principal | SessionEnd (ne s’exécute pas pour les sous-agents) |
Où Codex recherche les hooks
Codex détecte les hooks à côté des couches de configuration actives, sous l’une des formes suivantes :
hooks.json- des tables
[hooks]intégrées dansconfig.toml
Les plugins installés peuvent également inclure une configuration de cycle de vie dans leur
manifeste ou dans un fichier hooks/hooks.json par défaut. Consultez Créer des
plugins pour connaître les
règles d’empaquetage des plugins.
En pratique, les quatre emplacements les plus utiles sont :
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.codex/config.toml
S’il existe plusieurs sources de hooks, Codex charge tous les hooks correspondants.
Les couches de configuration de priorité supérieure ne remplacent pas les hooks des couches de priorité inférieure.
Si une même couche contient à la fois hooks.json et des éléments [hooks] intégrés, Codex
les fusionne et affiche un avertissement au démarrage. Privilégiez une seule représentation par couche.
Codex peut également détecter les hooks inclus dans les plugins activés. Les hooks inclus dans les plugins sont chargés avec les autres sources de hooks et suivent le même processus d’examen et d’approbation que les autres hooks non gérés.
Les hooks locaux au projet ne sont chargés que lorsque la couche .codex/ du projet est approuvée. Dans
les projets non approuvés, Codex continue de charger les hooks utilisateur et système à partir de leurs propres
couches de configuration actives.
Examiner et approuver les hooks
Codex répertorie les hooks configurés avant de déterminer ceux qui peuvent s’exécuter. Avant qu’un hook de commande non géré puisse s’exécuter, Codex vous demande d’examiner et d’approuver sa définition exacte. Codex associe l’approbation au hachage actuel du hook ; ainsi, les hooks nouveaux ou modifiés sont signalés comme nécessitant un examen et ignorés jusqu’à leur approbation.
Utilisez /hooks dans la CLI pour inspecter les sources des hooks, examiner les hooks nouveaux ou modifiés,
les approuver ou désactiver individuellement les hooks non gérés. Si des hooks doivent être examinés au
démarrage, Codex affiche un avertissement vous invitant à ouvrir /hooks.
Les hooks gérés provenant de sources système, MDM, cloud ou requirements.toml sont marqués
comme gérés, approuvés par la stratégie et ne peuvent pas être désactivés depuis le navigateur de hooks de l’utilisateur.
Pour une automatisation ponctuelle qui vérifie déjà les sources des hooks en dehors de Codex, transmettez
--dangerously-bypass-hook-trust afin d’exécuter les hooks activés sans exiger
une approbation persistante des hooks pour cette invocation.
Structure de la configuration
Les hooks sont organisés sur trois niveaux :
- Un événement de hook tel que
PreToolUse,PostToolUse,PreCompact,SubagentStartouStop - Un groupe de correspondance qui détermine quand cet événement correspond
- Un ou plusieurs gestionnaires de hooks qui s’exécutent lorsque le groupe de correspondance correspond
{
"description": "Optional lifecycle hooks for this workspace.",
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"statusMessage": "Loading session notes",
"additionalContextLimit": 5000
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_end.py",
"timeout": 3
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py\"",
"statusMessage": "Checking Bash command"
}
]
}
],
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/permission_request.py\"",
"statusMessage": "Checking approval request"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py\"",
"statusMessage": "Reviewing Bash output"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/user_prompt_submit_data_flywheel.py\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/stop_continue.py\"",
"timeout": 30
}
]
}
]
}
}Remarques :
descriptionest une métadonnée facultative de niveau supérieur pour un fichierhooks.json. Elle ne modifie pas les hooks exécutés.timeoutest exprimé en secondes.- Si
timeoutest omis, Codex utilise600secondes pour la plupart des hooks.SessionEndutilise1seconde par défaut et prend en charge jusqu’à3secondes.
statusMessageest facultatif.additionalContextLimitdéfinit la quantité deadditionalContextqu’un hook de commande peut envoyer au modèle avant que Codex n’enregistre le texte complet sur le disque et n’envoie à la place un aperçu plus court. Consultez Sortie volumineuse des hooks.commandWindowsest un remplacement de commande facultatif réservé à Windows. Dans TOML, utilisezcommand_windowsoucommandWindows.- L’option
asyncest analysée, mais les hooks de commande asynchrones ne sont pas encore pris en charge. - Seuls les gestionnaires
type: "command"s’exécutent actuellement. Les gestionnairespromptetagentsont analysés, mais ignorés. - Les commandes utilisent le
cwdde la session comme répertoire de travail. - Pour les hooks locaux au dépôt, privilégiez une résolution à partir de la racine Git plutôt que l’utilisation d’un
chemin relatif tel que
.codex/hooks/.... Codex peut être lancé depuis un sous-répertoire ; un chemin fondé sur la racine Git garantit la stabilité de l’emplacement du hook.
Équivalent TOML intégré dans config.toml :
[[hooks.SessionStart]]
matcher = "^compact$"
[[hooks.SessionStart.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/session_start.py"'
additionalContextLimit = 5000
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py"'
timeout = 30
statusMessage = "Checking Bash command"
[[hooks.PostToolUse]]
matcher = "^Bash$"
[[hooks.PostToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py"'
timeout = 30
statusMessage = "Reviewing Bash output"Désactiver les hooks
Les hooks sont activés par défaut. Pour les désactiver dans config.toml, définissez :
[features]
hooks = falseUtilisez hooks comme clé de fonctionnalité canonique. codex_hooks fonctionne encore comme
alias obsolète. Les administrateurs peuvent forcer la désactivation des hooks de la même manière dans
requirements.toml avec [features].hooks = false.
Hooks gérés provenant de requirements.toml
Les exigences gérées par l’entreprise peuvent également définir des hooks directement sous [hooks].
Cela s’avère utile lorsque les administrateurs souhaitent imposer la configuration des hooks tout en
déployant les scripts eux-mêmes par l’intermédiaire de MDM ou d’un autre système de gestion des appareils.
Pour imposer les hooks gérés même aux utilisateurs qui les ont désactivés localement, épinglez
[features].hooks = true dans requirements.toml avec [hooks]. Pour ignorer
les hooks utilisateur, de projet, de session et de plugin tout en autorisant les hooks gérés par les
administrateurs, définissez allow_managed_hooks_only = true.
allow_managed_hooks_only = true
[features]
hooks = true
[hooks]
managed_dir = "/enterprise/hooks"
windows_managed_dir = 'C:\enterprise\hooks'
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 /enterprise/hooks/pre_tool_use_policy.py"
command_windows = 'py -3 C:\enterprise\hooks\pre_tool_use_policy.py'
timeout = 30
statusMessage = "Checking managed Bash command"Remarques concernant les hooks gérés :
managed_direst utilisé sous macOS et Linux.windows_managed_direst utilisé sous Windows.- Codex ne distribue pas les scripts dans
managed_dir; les outils de votre entreprise doivent les installer et les mettre à jour séparément. - Les commandes des hooks gérés doivent utiliser des chemins de script absolus dans le répertoire géré configuré.
allow_managed_hooks_only = trueignore les hooks provenant des sources utilisateur, de projet, de session et de plugin, mais charge toujours les hooks gérés provenant derequirements.tomlet d’autres couches de configuration gérées.
Hooks inclus dans les plugins
Lorsqu’un plugin est activé, Codex peut charger les hooks de cycle de vie de ce plugin avec les hooks utilisateur, de projet et gérés.
Par défaut, Codex recherche hooks/hooks.json dans la racine du plugin. Le manifeste d’un plugin
peut remplacer cette valeur par défaut à l’aide d’une entrée hooks dans
.codex-plugin/plugin.json. L’entrée du manifeste peut être un chemin préfixé par ./, un
tableau de chemins préfixés par ./, un objet de hooks intégré ou un tableau d’objets de hooks
intégrés.
{
"name": "repo-policy",
"hooks": "./hooks/hooks.json"
}Les chemins de hooks du manifeste sont résolus par rapport à la racine du plugin et doivent rester
à l’intérieur de celle-ci. Si un manifeste définit hooks, Codex utilise ces entrées du manifeste
à la place de la valeur hooks/hooks.json par défaut.
Les commandes de hooks de plugin reçoivent les variables d’environnement suivantes :
PLUGIN_ROOTest une extension propre à Codex qui pointe vers la racine du plugin installé.PLUGIN_DATAest une extension propre à Codex qui pointe vers le répertoire de données accessible en écriture du plugin.- Codex définit également
CLAUDE_PLUGIN_ROOTetCLAUDE_PLUGIN_DATApour assurer la compatibilité avec les hooks de plugin existants.
Les hooks de plugin utilisent le même schéma d’événements que les autres hooks. L’installation ou l’activation d’un plugin n’approuve pas automatiquement ses hooks ; Codex ignore les hooks inclus dans le plugin jusqu’à ce que vous examiniez et approuviez leur définition actuelle.
Motifs de correspondance
Le champ matcher est une chaîne d’expression régulière qui filtre les déclenchements des hooks. Utilisez "*",
"", ou omettez entièrement matcher pour faire correspondre chaque occurrence d’un événement
pris en charge.
Seuls certains événements Codex actuels prennent en compte matcher :
| Événement | Ce que filtre matcher |
Remarques |
|---|---|---|
PermissionRequest |
nom de l’outil | La prise en charge inclut Bash, apply_patch* et les noms d’outils MCP |
PostToolUse |
nom de l’outil | Consultez Couverture des outils |
PostCompact |
déclencheur de compactage | Les valeurs sont manual ou auto |
PreCompact |
déclencheur de compactage | Les valeurs sont manual ou auto |
PreToolUse |
nom de l’outil | Consultez Couverture des outils |
SessionEnd |
motif de fin | Actuellement, uniquement other |
SessionStart |
source de démarrage | Les valeurs sont startup, resume, clear et compact |
SubagentStart |
type de sous-agent | Les valeurs dépendent du sous-agent qui démarre |
SubagentStop |
type de sous-agent | Les valeurs dépendent du sous-agent qui s’arrête |
UserPromptSubmit |
non pris en charge | Tout matcher configuré est ignoré pour cet événement |
Stop |
non pris en charge | Tout matcher configuré est ignoré pour cet événement |
*Pour apply_patch, les valeurs de matcher peuvent également utiliser Edit ou Write.
Exemples :
Bash^apply_patch$Edit|Writemcp__filesystem__read_filemcp__filesystem__.*startup|resume|clear|compactmanual|auto
Couverture des outils
PreToolUse et PostToolUse peuvent observer davantage que les appels shell et MCP. La plupart des
outils de fonction locaux utilisent le même chemin de hook ; vous pouvez donc faire correspondre leur nom,
inspecter leurs arguments JSON et, pour PreToolUse, bloquer ou réécrire l’appel.
| Chemin de l’outil | PreToolUse |
PostToolUse |
Remarques |
|---|---|---|---|
| Commandes shell | Oui | Oui | Correspond à Bash. |
Exécution unifiée (exec_command) |
Oui | Oui | Correspond à Bash. Une interrogation write_stdin ultérieure peut fournir le PostToolUse de la commande d’origine lorsque celle-ci se termine. |
apply_patch |
Oui | Oui | Correspond à apply_patch, Edit ou Write. |
| Outils MCP | Oui | Oui | Correspond au nom de l’outil MCP, tel que mcp__filesystem__read_file. |
| Autres outils de fonction locaux | Oui | Oui | Correspond au nom de l’outil de fonction, tel que update_plan. spawn_agent correspond également à Agent. |
Outils hébergés, tels que WebSearch |
Non | Non | Ils n’utilisent pas le chemin de hook des outils de fonction locaux. |
write_stdin sert de transport pour une session d’exécution unifiée existante. Il ne réexécute pas
PreToolUse lorsqu’il envoie une entrée ou interroge une commande qui a déjà passé
PreToolUse.
Certains chemins d’outils spécialisés peuvent ne pas utiliser le chemin de hook par défaut. Considérez les hooks d’outils comme un garde-fou utile, et non comme une frontière de contrôle absolue.
Champs d’entrée communs
Chaque hook de commande reçoit un objet JSON sur stdin.
Voici les champs partagés que vous utiliserez généralement :
| Champ | Type | Signification |
|---|---|---|
session_id |
string |
Identifiant de la session Codex actuelle. Les hooks de sous-agents utilisent l’identifiant de la session parente. |
transcript_path |
string | null |
Chemin vers le fichier de transcription de la session, le cas échéant |
cwd |
string |
Répertoire de travail de la session |
hook_event_name |
string |
Nom de l’événement de hook actuel |
model |
string |
Extension propre à Codex. Slug du modèle actif |
Les hooks limités à un tour indiquent turn_id comme extension propre à Codex dans leurs
tableaux spécifiques à l’événement.
SessionStart, PreToolUse, PermissionRequest, PostToolUse,
UserPromptSubmit, SubagentStart, SubagentStop et Stop incluent également
permission_mode, qui décrit le mode d’autorisation actuel comme default,
acceptEdits, plan, dontAsk ou bypassPermissions.
transcript_path pointe vers une transcription de conversation à titre pratique, mais le
format de transcription n’est pas une interface stable pour les hooks et peut évoluer.
Si vous avez besoin du format de transmission complet, consultez Schémas.
Champs de sortie communs
SessionStart, PreCompact, PostCompact, UserPromptSubmit,
SubagentStop et Stop prennent en charge ces champs JSON partagés. SubagentStart
accepte la même structure pour systemMessage et le contexte propre au hook, mais
continue: false n’arrête pas le sous-agent :
{
"continue": true,
"stopReason": "optional",
"systemMessage": "optional",
"suppressOutput": false
}| Champ | Effet |
|---|---|
continue |
Si false, indique que cette exécution du hook a été arrêtée |
stopReason |
Enregistré comme motif de l’arrêt |
systemMessage |
Affiché comme avertissement dans l’interface utilisateur ou le flux d’événements |
suppressOutput |
Analysé actuellement, mais pas encore implémenté |
Une sortie avec le code 0 sans contenu est considérée comme une réussite et Codex poursuit son exécution.
PreToolUse et PermissionRequest prennent en charge systemMessage, mais continue,
stopReason et suppressOutput ne sont actuellement pas pris en charge pour ces événements.
Si un hook PreToolUse renvoie l’un de ces champs non pris en charge, Codex marque
cette exécution du hook comme ayant échoué, signale l’erreur et poursuit l’appel de l’outil.
PostToolUse prend en charge systemMessage, continue: false et stopReason.
suppressOutput est analysé, mais n’est actuellement pas pris en charge pour cet événement.
Sortie volumineuse d’un hook
Par défaut, Codex limite chaque message de sortie de hook visible par le modèle à environ
2 500 tokens. Si un hook en renvoie davantage, Codex enregistre le texte intégral sous
<temp_dir>/hook_outputs/<session_id>/<uuid>.txt et fournit au modèle un aperçu du début et de la fin
avec le chemin du fichier enregistré. Ce comportement est appelé
déversement : Codex stocke la sortie surdimensionnée sur le disque et la remplace par un
aperçu plus court, visible par le modèle. Si le fichier ne peut pas être écrit, le modèle reçoit tout de même
un aperçu tronqué.
Pour tout hook de commande qui renvoie additionalContext, définissez
additionalContextLimit sur le gestionnaire afin de personnaliser le seuil approximatif de
tokens :
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"additionalContextLimit": 5000
}Omettez additionalContextLimit pour utiliser le seuil par défaut de 2500 tokens. Utilisez un
entier positif pour choisir un autre seuil, ou 0 pour transmettre directement au modèle
l’intégralité du contexte supplémentaire du gestionnaire. Codex évalue chaque
gestionnaire correspondant indépendamment. Pour les événements qui ne peuvent pas produire de contexte
supplémentaire, Codex ignore additionalContextLimit et signale un avertissement de
configuration.
Ce paramètre s’applique uniquement à additionalContext. Les retours des outils et les invites de
continuation conservent la limite par défaut.
Comme les sorties surdimensionnées peuvent être écrites sur le disque, évitez de renvoyer des secrets ou d’autres données sensibles dans la sortie des hooks.
Hooks
SessionStart
matcher est appliqué à source pour cet événement.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
source |
string |
Mode de démarrage de la session : startup, resume, clear ou compact |
Le texte brut sur stdout est ajouté comme contexte développeur supplémentaire.
Le JSON sur stdout prend en charge les champs de sortie communs et cette
structure propre au hook :
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Load the workspace conventions before editing."
}
}Ce texte additionalContext est ajouté comme contexte développeur supplémentaire.
Après que Codex a compacté une session racine, les hooks SessionStart correspondant à
source: "compact" s’exécutent avant la requête suivante au modèle. Cela s’applique également lorsque le
compactage automatique se produit au milieu d’un tour : Codex transmet le contexte
supplémentaire du hook à la continuation immédiate au lieu d’attendre un
tour utilisateur ultérieur. Si le hook renvoie continue: false, Codex met fin au tour
sans envoyer une autre requête au modèle.
SessionEnd
SessionEnd vous permet d’exécuter une commande lorsqu’une session se termine, par exemple pour enregistrer les
notes finales ou nettoyer des fichiers. Il s’exécute pour le fil principal lorsque vous archivez ou
supprimez une conversation encore ouverte, lorsque Codex se ferme normalement ou après qu’une
conversation est restée inactive et n’est ouverte dans aucun client connecté pendant 30
minutes. Il ne s’exécute pas pour les sous-agents.
Quitter une conversation ou appeler thread/unsubscribe ne met pas fin
immédiatement à la session ; SessionEnd ne s’exécute donc pas tout de suite. Votre hook peut
toujours lire la transcription de la session pendant son exécution.
matcher filtre reason pour cet événement. Pour l’instant, reason vaut toujours other.
Vous pouvez omettre matcher ou utiliser other pour une exécution à chaque événement SessionEnd.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
reason |
string |
Motif de fin de la session : other |
Par exemple, une commande SessionEnd reçoit :
{
"session_id": "thr_123",
"transcript_path": "/workspace/.codex/rollout.jsonl",
"cwd": "/workspace",
"hook_event_name": "SessionEnd",
"reason": "other"
}Les hooks SessionEnd sont consultatifs. Leur sortie n’orientera pas Codex et ne maintiendra pas le
fil ouvert. Si une commande expire ou se termine avec une erreur, Codex la signale comme
un échec du hook.
SubagentStart
matcher est appliqué à agent_type pour cet événement.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. Identifiant du tour Codex actif |
agent_id |
string |
Identifiant du sous-agent |
agent_type |
string |
Type ou profil du sous-agent |
permission_mode |
string |
Mode d’autorisation actuel |
Le texte brut sur stdout est ajouté comme contexte développeur supplémentaire pour le sous-agent.
Le JSON sur stdout prend en charge systemMessage et cette structure propre au hook :
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Review the repository test conventions first."
}
}Ce texte additionalContext est ajouté comme contexte développeur supplémentaire pour le
sous-agent. continue: false est analysé à des fins de compatibilité, mais n’empêche pas le
sous-agent de démarrer.
PreToolUse
PreToolUse peut intercepter Bash, les modifications de fichiers effectuées via apply_patch,
les appels d’outils MCP et d’autres outils de fonction locaux. Consultez la couverture des
outils pour connaître les chemins pris en charge et les exceptions.
matcher s’applique à tool_name et aux alias de correspondance. Pour les modifications de fichiers via
apply_patch, les valeurs matcher peuvent utiliser apply_patch, Edit ou Write ; l’entrée du hook
indique toujours tool_name: "apply_patch".
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
tool_name |
string |
Nom canonique de l’outil du hook, tel que Bash, apply_patch ou un nom MCP comme mcp__fs__read |
tool_use_id |
string |
ID de l’appel d’outil pour cette invocation |
tool_input |
JSON value |
Entrée propre à l’outil. Bash et apply_patch utilisent tool_input.command. MCP et les autres outils de fonction locaux envoient leurs arguments. |
Le texte brut sur stdout est ignoré.
Le JSON sur stdout peut utiliser systemMessage. Pour refuser un appel d’outil pris en charge, renvoyez
cette structure propre au hook :
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook."
}
}Codex accepte également cette ancienne structure de bloc :
{
"decision": "block",
"reason": "Destructive command blocked by hook."
}Vous pouvez aussi utiliser le code de sortie 2 et écrire le motif du blocage dans stderr.
Pour ajouter du contexte visible par le modèle sans bloquer, renvoyez
hookSpecificOutput.additionalContext :
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "The pending command touches generated files."
}
}Pour réécrire un appel d’outil pris en charge sans le bloquer, renvoyez
permissionDecision: "allow" avec updatedInput :
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": {
"command": "echo rewritten"
}
}
}Pour les commandes Bash et apply_patch, updatedInput doit inclure un champ de chaîne
command. Pour MCP et les autres outils de fonction locaux, updatedInput est l’objet
contenant les arguments de remplacement. Renvoyez updatedInput uniquement avec
permissionDecision: "allow" ; les autres structures updatedInput sont signalées comme des
erreurs.
permissionDecision: "ask", l’ancien decision: "approve", continue: false,
stopReason et suppressOutput sont analysés, mais ne sont pas encore pris en charge. Codex marque
l’exécution du hook comme ayant échoué, signale l’erreur et poursuit l’appel d’outil.
PermissionRequest
PermissionRequest s’exécute lorsque Codex est sur le point de demander une approbation, par exemple pour une
élévation de privilèges du shell ou une approbation du réseau géré. Il peut autoriser la demande, la refuser
ou ne pas prendre de décision et laisser l’invite d’approbation habituelle se poursuivre.
Il ne s’exécute pas pour les commandes qui ne nécessitent pas d’approbation.
matcher s’applique à tool_name et aux alias de correspondance. Les valeurs canoniques actuelles
incluent Bash, apply_patch et des noms d’outils MCP tels que
mcp__server__tool ; apply_patch correspond également à Edit et Write.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
tool_name |
string |
Nom canonique de l’outil du hook, tel que Bash, apply_patch ou un nom MCP comme mcp__fs__read |
tool_input |
JSON value |
Entrée propre à l’outil. Bash et apply_patch utilisent tool_input.command, tandis que les outils MCP envoient tous les arguments. |
tool_input.description |
string | null |
Motif d’approbation lisible, lorsque Codex en dispose |
Le texte brut sur stdout est ignoré.
Certaines entrées d’outil peuvent inclure une description lisible, mais ne comptez pas sur la présence d’un
champ tool_input.description pour chaque outil.
Pour approuver la demande, renvoyez :
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow"
}
}
}Pour refuser la demande, renvoyez :
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "deny",
"message": "Blocked by repository policy."
}
}
}Si plusieurs hooks correspondants renvoient des décisions, toute valeur deny l’emporte. Sinon, une valeur
allow permet à la demande de continuer sans afficher l’invite d’approbation. Si aucun
hook correspondant ne prend de décision, Codex utilise le flux d’approbation habituel.
Ne renvoyez pas updatedInput, updatedPermissions ou interrupt pour
PermissionRequest ; ces champs sont réservés à un comportement futur et provoquent actuellement
un refus par défaut.
PostToolUse
PostToolUse s’exécute après que les outils pris en charge ont produit une sortie, notamment Bash,
apply_patch, les appels d’outils MCP et d’autres outils de fonction locaux. Pour Bash, il
s’exécute également après les commandes qui se terminent avec un statut différent de zéro. Il ne peut pas annuler les effets
de bord d’un outil déjà exécuté. Consultez la couverture des outils pour
connaître les chemins pris en charge et les exceptions.
matcher s’applique à tool_name et aux alias de correspondance. Pour les modifications de fichiers via
apply_patch, les valeurs matcher peuvent utiliser apply_patch, Edit ou Write ; l’entrée du hook
indique toujours tool_name: "apply_patch".
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
tool_name |
string |
Nom canonique de l’outil du hook, tel que Bash, apply_patch ou un nom MCP comme mcp__fs__read |
tool_use_id |
string |
ID de l’appel d’outil pour cette invocation |
tool_input |
JSON value |
Entrée propre à l’outil. Bash et apply_patch utilisent tool_input.command. MCP et les autres outils de fonction locaux envoient leurs arguments. |
tool_response |
JSON value |
Sortie propre à l’outil. Les outils MCP envoient le résultat de l’appel MCP. Les autres outils de fonction locaux envoient normalement leur sortie destinée au modèle. |
Le texte brut sur stdout est ignoré.
Le JSON sur stdout peut utiliser systemMessage ainsi que cette structure propre au hook :
{
"decision": "block",
"reason": "The Bash output needs review before continuing.",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "The command updated generated files."
}
}Ce texte additionalContext est ajouté comme contexte développeur supplémentaire.
Pour cet événement, decision: "block" n’annule pas la commande Bash terminée.
À la place, Codex enregistre le retour, remplace le résultat de l’outil par ce
retour et poursuit le modèle à partir du message fourni par le hook.
Vous pouvez aussi utiliser le code de sortie 2 et écrire le motif du retour dans stderr.
Pour interrompre le traitement normal du résultat d’outil d’origine après que la commande a
déjà été exécutée, renvoyez continue: false. Codex remplacera le résultat de l’outil par
votre retour ou votre texte d’arrêt, puis poursuivra à partir de là.
updatedMCPToolOutput et suppressOutput sont analysés, mais ne sont pas encore pris en charge.
Codex marque l’exécution du hook comme ayant échoué, signale l’erreur et poursuit le
traitement normal du résultat de l’outil.
Appels d’outils depuis le mode code
Lorsqu’un modèle utilise le mode code pour appeler un outil depuis JavaScript, les décisions des hooks s’appliquent
à cet appel imbriqué. PreToolUse peut arrêter l’outil avant son exécution ou réécrire
son entrée. Un blocage par PostToolUse ne peut pas annuler les effets de bord de l’outil, mais il
peut empêcher le résultat d’origine d’atteindre le script en cours d’exécution.
| Résultat du hook | Ce que voit le mode code |
|---|---|
PreToolUse bloque |
La promesse de l’outil est rejetée avant son exécution. |
PreToolUse renvoie updatedInput |
L’outil s’exécute avec l’entrée réécrite et la promesse est résolue avec ce résultat. |
PostToolUse renvoie decision: "block" ou se termine avec le code 2 |
L’outil s’exécute, puis la promesse est rejetée avec le motif du hook. |
PostToolUse renvoie continue: false |
Codex utilise le retour du hook comme résultat visible par le modèle, mais ne rejette pas la promesse de l’outil imbriqué. |
PreCompact
PreCompact s’exécute avant que Codex compacte la discussion. matcher s’applique
à trigger, dont les valeurs sont manual et auto.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
trigger |
string |
Élément ayant déclenché la compaction : manual ou auto |
Le texte brut sur stdout est ignoré.
Le JSON sur stdout prend en charge les champs de sortie communs. Si un
hook PreCompact correspondant renvoie continue: false, Codex s’arrête avant
la compaction.
PostCompact
PostCompact s’exécute après que Codex a compacté la discussion. matcher s’applique
à trigger, dont les valeurs sont manual et auto.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
trigger |
string |
Élément ayant déclenché la compaction : manual ou auto |
Le texte brut sur stdout est ignoré.
Le JSON sur stdout prend en charge les champs de sortie communs. Si un
hook PostCompact correspondant renvoie continue: false, Codex s’arrête après
la compaction.
UserPromptSubmit
matcher n’est actuellement pas utilisé pour cet événement.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
prompt |
string |
Invite utilisateur sur le point d’être envoyée |
Le texte brut sur stdout est ajouté comme contexte développeur supplémentaire.
Le JSON sur stdout prend en charge les champs de sortie communs et
la structure propre à ce hook suivante :
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Ask for a clearer reproduction before editing files."
}
}Ce texte additionalContext est ajouté comme contexte développeur supplémentaire.
Pour bloquer le prompt, renvoyez :
{
"decision": "block",
"reason": "Ask for confirmation before doing that."
}Vous pouvez également utiliser le code de sortie 2 et écrire la raison du blocage dans stderr.
SubagentStop
matcher est appliqué à agent_type pour cet événement.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
agent_id |
string |
Identifiant du sous-agent |
agent_type |
string |
Type ou profil du sous-agent |
agent_transcript_path |
string | null |
Chemin du fichier de transcription du sous-agent, le cas échéant |
stop_hook_active |
boolean |
Indique si ce sous-agent a déjà été poursuivi |
last_assistant_message |
string | null |
Dernier message d’assistant du sous-agent, s’il est disponible |
SubagentStop attend du JSON sur stdout lorsqu’il se termine avec 0. Une sortie en texte brut est
invalide pour cet événement.
Le JSON sur stdout prend en charge les champs de sortie communs. Pour demander à
Codex de poursuivre le flux du sous-agent, renvoyez :
{
"decision": "block",
"reason": "Run one more focused pass inside the subagent."
}Vous pouvez également utiliser le code de sortie 2 et écrire la raison de la poursuite dans stderr.
Si un hook SubagentStop correspondant renvoie continue: false, cela prévaut
sur les décisions de poursuite des autres hooks SubagentStop
correspondants.
Stop
matcher n’est actuellement pas utilisé pour cet événement.
Champs qui s’ajoutent aux champs d’entrée communs :
| Champ | Type | Signification |
|---|---|---|
turn_id |
string |
Extension propre à Codex. ID du tour Codex actif |
stop_hook_active |
boolean |
Indique si ce tour a déjà été poursuivi par Stop |
last_assistant_message |
string | null |
Texte du dernier message de l’assistant, s’il est disponible |
Stop attend du JSON sur stdout lorsqu’il se termine avec 0. Une sortie en texte brut est invalide
pour cet événement.
Le JSON sur stdout prend en charge les champs de sortie communs. Pour permettre à
Codex de poursuivre, renvoyez :
{
"decision": "block",
"reason": "Run one more pass over the failing tests."
}Vous pouvez également utiliser le code de sortie 2 et écrire la raison de la poursuite dans stderr.
Pour cet événement, decision: "block" ne rejette pas le tour. À la place, il demande à
Codex de poursuivre et crée automatiquement un nouveau prompt de continuation qui agit
comme un nouveau prompt utilisateur, en utilisant votre reason comme texte de ce prompt.
Si un hook Stop correspondant renvoie continue: false, cela prévaut
sur les décisions de poursuite des autres hooks Stop correspondants.
Schémas
Si vous avez besoin du format d’échange actuel exact, consultez les schémas générés dans le dépôt GitHub de Codex.
Alias en texte brut
- string | null