Español

Hooks

Hooks

Ejecuta scripts deterministas durante el ciclo de vida de Codex

Los hooks son un marco de extensibilidad para Codex. Permiten ejecutar scripts o herramientas MCP durante el bucle del agente, lo que habilita funciones como:

  • Enviar el chat a un motor personalizado de registro o análisis
  • Analizar los prompts de tu equipo para impedir que se peguen accidentalmente API keys
  • Resumir chats para crear automáticamente memorias persistentes
  • Ejecutar una comprobación de validación personalizada cuando se detiene un turno del chat para aplicar estándares
  • Personalizar los prompts cuando se trabaja en un directorio determinado

Comportamiento del entorno de ejecución que debes tener en cuenta:

  • Se ejecutan todos los hooks coincidentes de varios archivos.
  • Los distintos hooks de comandos que coinciden con el mismo evento se inician simultáneamente, por lo que un hook no puede impedir que se inicie otro hook coincidente.
  • Los hooks no administrados deben revisarse y considerarse de confianza antes de ejecutarse.

Los hooks se ejecutan en distintos momentos de una conversación:

Cuándo Hooks
Durante un turno PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop
Al interrumpir un turno activo Interrupt (no se ejecuta para subagentes)
Al iniciar una sesión o subagente SessionStart, SubagentStart
Cuando termina el hilo principal SessionEnd (no se ejecuta para subagentes)

Dónde busca Codex los hooks

Codex detecta hooks junto a las capas de configuración activas en cualquiera de estas formas:

  • hooks.json
  • tablas [hooks] insertadas dentro de config.toml

Los plugins instalados también pueden incluir una configuración del ciclo de vida mediante su manifiesto o un archivo hooks/hooks.json predeterminado. Consulta Crear plugins para conocer las reglas de empaquetado de plugins.

En la práctica, las cuatro ubicaciones más útiles son:

  • ~/.codex/hooks.json
  • ~/.codex/config.toml
  • <repo>/.codex/hooks.json
  • <repo>/.codex/config.toml

Si existe más de un origen de hooks, Codex carga todos los hooks coincidentes. Las capas de configuración con mayor precedencia no sustituyen los hooks de las capas con menor precedencia. Si una misma capa contiene tanto hooks.json como [hooks] insertados, Codex los combina y muestra una advertencia al iniciarse. Usa preferentemente una sola representación por capa.

Codex también puede detectar hooks incluidos en los plugins habilitados. Los hooks incluidos en plugins se cargan junto con otros orígenes de hooks y siguen el mismo flujo de revisión de confianza que los demás hooks no administrados.

Los hooks locales del proyecto solo se cargan cuando la capa .codex/ del proyecto es de confianza. En proyectos que no son de confianza, Codex sigue cargando los hooks del usuario y del sistema desde sus propias capas de configuración activas.

Revisar los hooks y confiar en ellos

Codex enumera los hooks configurados antes de decidir cuáles pueden ejecutarse. Antes de que pueda ejecutarse un hook no administrado, Codex exige que revises y marques como confiable su definición exacta. Codex registra la confianza con respecto al hash actual del hook, por lo que los hooks nuevos o modificados se marcan para revisión y se omiten hasta que se confíe en ellos.

Usa /hooks en la CLI para inspeccionar los orígenes de los hooks, revisar hooks nuevos o modificados, marcarlos como confiables o deshabilitar hooks no administrados concretos. Si hay hooks pendientes de revisión al iniciarse, Codex muestra una advertencia que te indica que abras /hooks.

Los hooks administrados procedentes del sistema, MDM, la nube o fuentes requirements.toml se marcan como administrados, son de confianza por directiva y no pueden deshabilitarse desde el explorador de hooks del usuario.

Para automatizaciones puntuales que ya verifican los orígenes de los hooks fuera de Codex, proporciona --dangerously-bypass-hook-trust para ejecutar los hooks habilitados sin exigir que se conserve la confianza en ellos durante esa invocación.

Estructura de configuración

Los hooks se organizan en tres niveles:

  • Un evento de hook, como PreToolUse, PostToolUse, PreCompact, SubagentStart o Stop
  • Un grupo de coincidencia que decide cuándo coincide ese evento
  • Uno o varios controladores de hooks que se ejecutan cuando coincide el grupo
{
  "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
          }
        ]
      }
    ]
  }
}

Notas:

  • description son metadatos opcionales de nivel superior para un archivo hooks.json. No cambian qué hooks se ejecutan.
  • timeout se expresa en segundos.
  • Si se omite timeout, Codex usa 600 segundos para la mayoría de los hooks.
    • SessionEnd y Interrupt usan 1 segundo de forma predeterminada y admiten hasta 3 segundos.
  • statusMessage es opcional.
  • additionalContextLimit establece cuánto additionalContext puede enviar un hook de comando al modelo antes de que Codex guarde el texto completo en el disco y envíe en su lugar una vista previa más breve. Consulta Salida extensa de hooks.
  • commandWindows es una anulación opcional del comando solo para Windows. En TOML, usa command_windows o commandWindows.
  • Establece async en true para ejecutar un hook de comando en segundo plano.
  • Se admiten controladores command y mcp_tool. Los controladores prompt y agent se analizan, pero se omiten.
  • Los comandos se ejecutan con el cwd de la sesión como directorio de trabajo.
  • Para hooks locales del repositorio, es preferible resolver la ruta desde la raíz de git en lugar de usar una ruta relativa como .codex/hooks/.... Codex puede iniciarse desde un subdirectorio, y una ruta basada en la raíz de git mantiene estable la ubicación del hook.

TOML insertado equivalente en 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"

Hooks de herramientas MCP

Un hook de herramienta MCP permite que un evento del ciclo de vida llame a una herramienta de un servidor MCP ya conectado. Envía argumentos estructurados directamente a la herramienta y utiliza el mismo contrato de revisión de confianza y salida que un hook de comandos.

Configurar un hook de herramienta MCP

Este hook solicita al servidor MCP scanner que analice cada parche después de que Codex escriba o edite archivos:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "scanner",
            "tool": "scan_patch",
            "input": { "patch": "${tool_input.command}" },
            "timeout": 30,
            "statusMessage": "Scanning edited files"
          }
        ]
      }
    ]
  }
}
Campo Significado
type Debe ser mcp_tool.
server Nombre obligatorio de un servidor MCP ya conectado.
tool Nombre obligatorio de una herramienta expuesta por ese servidor.
input Objeto JSON opcional con plantillas de argumentos. El valor predeterminado es {}.
timeout Tiempo de espera opcional de la ejecución activa, en segundos. El valor predeterminado es 600.
statusMessage Mensaje opcional que se muestra mientras se ejecuta el hook.

Expandir argumentos a partir del evento del hook

Usa ${field.nested} para leer un campo con notación de puntos del evento del hook. Un marcador de posición que ocupe un valor completo conserva su tipo JSON. Un marcador de posición dentro de una cadena más larga se representa como texto. Codex expande recursivamente los objetos y arrays.

Para un evento que contenga {"tool_input":{"file_path":"src/main.rs","count":3}}, esta plantilla de argumentos:

{
  "path": "${tool_input.file_path}",
  "count": "${tool_input.count}",
  "message": "Scanning ${tool_input.file_path}"
}

se convierte en:

{
  "path": "src/main.rs",
  "count": 3,
  "message": "Scanning src/main.rs"
}

Ejecución y ciclo de vida

  • Los hooks utilizan una conexión MCP existente. No inician ni vuelven a conectar servidores.
  • Un hook puede bloquear una operación cuando la herramienta devuelve una decisión de bloqueo. Los errores, los servidores ausentes y las herramientas no disponibles no bloquean la operación.
  • Los hooks de herramientas MCP se ejecutan de forma síncrona. No solicitan aprobación para la herramienta ni activan otros hooks.
  • Se aplica el tiempo de espera más corto del hook o del servidor. El tiempo dedicado a esperar una respuesta de elicitación MCP no cuenta para el tiempo de espera.
  • Los hooks SessionStart pueden ejecutarse antes de que un servidor MCP esté listo. Si ocurre, no bloquean la sesión.
  • SessionEnd no admite hooks de herramientas MCP.

Desactivar los hooks

Los hooks están habilitados de forma predeterminada. Para desactivarlos en config.toml, establece:

[features]
hooks = false

Usa hooks como clave canónica de la función. codex_hooks sigue funcionando como alias obsoleto. Los administradores pueden forzar la desactivación de los hooks del mismo modo en requirements.toml con [features].hooks = false.

Hooks administrados desde requirements.toml

Los requisitos administrados por la empresa también pueden definir hooks insertados bajo [hooks]. Esto resulta útil cuando los administradores quieren imponer la configuración de los hooks y, al mismo tiempo, distribuir los scripts reales mediante MDM u otro sistema de administración de dispositivos. Para imponer hooks administrados incluso a los usuarios que los hayan deshabilitado localmente, fija [features].hooks = true en requirements.toml junto con [hooks]. Para ignorar los hooks del usuario, proyecto, sesión y plugin sin dejar de permitir los hooks administrados por el administrador, establece 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"

Notas sobre los hooks administrados:

  • managed_dir se usa en macOS y Linux.
  • windows_managed_dir se usa en Windows.
  • Codex no distribuye los scripts de managed_dir; las herramientas de tu empresa deben instalarlos y actualizarlos por separado.
  • Los comandos de hooks administrados deben usar rutas absolutas de scripts dentro del directorio administrado configurado.
  • allow_managed_hooks_only = true omite los hooks procedentes del usuario, proyecto, sesión y plugins, pero sigue cargando los hooks administrados desde requirements.toml y otras capas de configuración administradas.

Hooks incluidos en plugins

Cuando un plugin está habilitado, Codex puede cargar desde él hooks del ciclo de vida junto con los hooks del usuario, proyecto y administrados.

De forma predeterminada, Codex busca hooks/hooks.json dentro de la raíz del plugin. El manifiesto de un plugin puede sustituir ese valor predeterminado mediante una entrada hooks en .codex-plugin/plugin.json. La entrada del manifiesto puede ser una ruta con el prefijo ./, un array de rutas con el prefijo ./, un objeto de hooks insertado o un array de objetos de hooks insertados.

{
  "name": "repo-policy",
  "hooks": "./hooks/hooks.json"
}

Las rutas de hooks del manifiesto se resuelven con respecto a la raíz del plugin y deben permanecer dentro de ella. Si un manifiesto define hooks, Codex utiliza esas entradas del manifiesto en lugar del valor predeterminado hooks/hooks.json.

Los comandos de hooks de plugins reciben estas variables de entorno:

  • PLUGIN_ROOT es una extensión específica de Codex que apunta a la raíz del plugin instalado.
  • PLUGIN_DATA es una extensión específica de Codex que apunta al directorio de datos escribible del plugin.
  • Codex también establece CLAUDE_PLUGIN_ROOT y CLAUDE_PLUGIN_DATA por compatibilidad con los hooks de plugins existentes.

Los hooks de plugins usan el mismo esquema de eventos que los demás hooks. Instalar o habilitar un plugin no hace que se confíe automáticamente en sus hooks; Codex omite los hooks incluidos en el plugin hasta que revises y marques como confiable la definición actual del hook.

Patrones de coincidencia

El campo matcher es una cadena de expresión regular que filtra cuándo se activan los hooks. Usa "*", "" u omite matcher por completo para hacer coincidir todas las apariciones de un evento admitido.

Solo algunos eventos actuales de Codex respetan matcher:

Evento Qué filtra matcher Notas
PermissionRequest nombre de la herramienta Se admiten Bash, apply_patch* y nombres de herramientas MCP
PostToolUse nombre de la herramienta Consulta Cobertura de herramientas
PostCompact desencadenante de compactación Los valores son manual o auto
PreCompact desencadenante de compactación Los valores son manual o auto
PreToolUse nombre de la herramienta Consulta Cobertura de herramientas
SessionEnd motivo de finalización Actualmente, solo other
SessionStart origen del inicio Los valores son startup, resume, clear y compact
SubagentStart tipo de subagente Los valores dependen del subagente que se inicia
SubagentStop tipo de subagente Los valores dependen del subagente que se detiene
UserPromptSubmit no se admite Cualquier matcher configurado se ignora para este evento
Stop no se admite Cualquier matcher configurado se ignora para este evento
Interrupt no se admite Cualquier matcher configurado se ignora para este evento

*Para apply_patch, los valores matcher también pueden usar Edit o Write.

Ejemplos:

  • Bash
  • ^apply_patch$
  • Edit|Write
  • mcp__filesystem__read_file
  • mcp__filesystem__.*
  • startup|resume|clear|compact
  • manual|auto

Cobertura de herramientas

PreToolUse y PostToolUse pueden observar más que llamadas de shell y MCP. La mayoría de las herramientas de funciones locales utilizan la misma ruta de hooks, por lo que puedes hacer coincidir el nombre de la herramienta, inspeccionar sus argumentos JSON y, para PreToolUse, bloquear o reescribir la llamada.

Ruta de la herramienta PreToolUse PostToolUse Notas
Comandos de shell Coinciden como Bash.
Ejecución unificada (exec_command) Coincide como Bash. Un sondeo write_stdin posterior puede entregar el PostToolUse del comando original cuando finalice.
apply_patch Coincide como apply_patch, Edit o Write.
Herramientas MCP Haz coincidir el nombre de la herramienta MCP, como mcp__filesystem__read_file.
Otras herramientas de funciones locales Haz coincidir el nombre de la herramienta de función, como update_plan. spawn_agent también coincide con Agent.
Herramientas alojadas, como WebSearch No No No utilizan la ruta de hooks de herramientas de funciones locales.

write_stdin es el transporte de una sesión de ejecución unificada existente. No vuelve a ejecutar PreToolUse cuando envía entradas o sondea un comando que ya ha pasado PreToolUse.

Algunas rutas de herramientas especializadas pueden excluirse de la ruta de hooks predeterminada. Considera los hooks de herramientas como una medida de protección útil, no como un límite de aplicación completo.

Campos de entrada comunes

Cada hook de comandos recibe un objeto JSON en stdin.

Estos son los campos compartidos que usarás habitualmente:

Campo Tipo Significado
session_id string Id. de la sesión actual de Codex. Los hooks de subagentes usan el id. de la sesión principal.
transcript_path string | null Ruta al archivo de transcripción de la sesión, si existe
cwd string Directorio de trabajo de la sesión
hook_event_name string Nombre del evento de hook actual
model string Extensión específica de Codex. Slug del modelo activo

Los hooks con ámbito de turno incluyen turn_id como extensión específica de Codex en sus tablas propias del evento.

SessionStart, PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, SubagentStart, SubagentStop, Stop y Interrupt también incluyen permission_mode, que describe el modo de permisos actual como default, acceptEdits, plan, dontAsk o bypassPermissions.

transcript_path apunta a una transcripción del chat por comodidad, pero el formato de la transcripción no es una interfaz estable para los hooks y puede cambiar con el tiempo.

Si necesitas el formato de transmisión completo, consulta Esquemas.

Campos de salida comunes

SessionStart, PreCompact, PostCompact, UserPromptSubmit, SubagentStop y Stop admiten estos campos JSON compartidos. SubagentStart acepta la misma estructura para systemMessage y el contexto específico del hook, pero continue: false no detiene al subagente:

{
  "continue": true,
  "stopReason": "optional",
  "systemMessage": "optional",
  "suppressOutput": false
}
Campo Efecto
continue Si es false, marca esa ejecución del hook como detenida
stopReason Se registra como motivo de la detención
systemMessage Se muestra como advertencia en la interfaz de usuario o el flujo de eventos
suppressOutput Se analiza actualmente, pero aún no está implementado

El código de salida 0 sin salida se considera correcto y Codex continúa.

PreToolUse y PermissionRequest admiten systemMessage, pero continue, stopReason y suppressOutput no son compatibles actualmente con esos eventos. Si un hook PreToolUse devuelve uno de esos campos no compatibles, Codex marca la ejecución del hook como fallida, informa del error y continúa con la llamada a la herramienta.

PostToolUse admite systemMessage, continue: false y stopReason. suppressOutput se analiza, pero actualmente no es compatible con ese evento.

Salida extensa de hooks

De forma predeterminada, Codex limita cada mensaje de salida de hook visible para el modelo a unos 2.500 tokens. Si un hook devuelve más, Codex guarda el texto completo en <temp_dir>/hook_outputs/<session_id>/<uuid>.txt y proporciona al modelo una vista previa del principio y el final junto con la ruta del archivo guardado. Este comportamiento se denomina volcado: Codex almacena en el disco la salida sobredimensionada y la sustituye por una vista previa más breve y visible para el modelo. Si no se puede escribir el archivo, el modelo sigue recibiendo una vista previa truncada.

Para cualquier hook de comandos que devuelva additionalContext, establece additionalContextLimit en el controlador para personalizar el umbral aproximado de tokens:

{
  "type": "command",
  "command": "python3 ~/.codex/hooks/session_start.py",
  "additionalContextLimit": 5000
}

Omite additionalContextLimit para usar el umbral predeterminado de 2500 tokens. Usa un entero positivo para seleccionar otro umbral, o 0 para transmitir directamente al modelo el contexto adicional completo del controlador. Codex evalúa de forma independiente cada controlador coincidente. Para los eventos que no pueden generar contexto adicional, Codex ignora additionalContextLimit e informa de una advertencia de configuración.

El ajuste solo se aplica a additionalContext. Los comentarios de herramientas y los prompts de continuación conservan el límite predeterminado.

Como la salida sobredimensionada puede escribirse en el disco, evita devolver secretos u otros datos confidenciales en la salida del hook.

Ejecutar hooks en segundo plano

De forma predeterminada, Codex espera a que termine un hook de comandos antes de continuar con la operación que lo activó. Establece async en true para ejecutar un hook de comandos en segundo plano mientras Codex continúa.

Configurar un hook en segundo plano

Añade "async": true a un controlador de comandos en hooks.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.codex/hooks/post_tool_use.py",
            "async": true,
            "timeout": 120
          }
        ]
      }
    ]
  }
}

Para un hook insertado en config.toml, establece async = true:

[[hooks.PostToolUse]]
matcher = "Bash"

[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/post_tool_use.py"
async = true
timeout = 120

Los hooks en segundo plano usan la misma entrada, matcher, revisión de confianza, tiempo de espera y gestión de salidas extensas que los hooks de comando síncronos. Al igual que con otros hooks de comando, timeout se mide en segundos y su valor predeterminado es 600. Los hooks Interrupt usan un valor predeterminado de un segundo y un máximo de tres segundos, incluso cuando se ejecutan en segundo plano.

Cómo se ejecutan los hooks en segundo plano

Cuando termina un hook en segundo plano, Codex entrega la salida informativa admitida en el siguiente punto seguro de la conversación:

  • Si hay un turno activo, Codex espera a que finalicen la solicitud actual al modelo y las llamadas a herramientas, y después pone la salida a disposición de la siguiente solicitud al modelo de ese turno.
  • Si no hay ningún turno activo, Codex espera hasta el siguiente turno del usuario. La finalización de un hook en segundo plano no inicia un turno nuevo.

Usa la misma salida JSON específica del evento que en un hook síncrono. Codex añade additionalContext al contexto del modelo y muestra systemMessage como advertencia.

Limitaciones

  • Codex ejecuta hasta ocho hooks en segundo plano simultáneamente por sesión. Los hooks adicionales esperan hasta que termine uno en ejecución.
  • Cada invocación coincidente se ejecuta de forma independiente, y los hooks en segundo plano pueden terminar en un orden distinto del de inicio.
  • Cuando termina la sesión, Codex cancela los hooks en segundo plano sin finalizar y descarta la salida que no se haya entregado.
  • Los hooks SessionEnd siempre se ejecutan de forma síncrona.

Hooks

SessionStart

matcher se aplica a source para este evento.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
source string Cómo se inició la sesión: startup, resume, clear o compact

El texto sin formato en stdout se añade como contexto adicional del desarrollador.

El JSON en stdout admite los campos de salida comunes y esta estructura específica del hook:

{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Load the workspace conventions before editing."
  }
}

Ese texto additionalContext se añade como contexto adicional del desarrollador.

Después de que Codex compacte una sesión raíz, los hooks SessionStart que coincidan con source: "compact" se ejecutan antes de la siguiente solicitud al modelo. Esto también se aplica cuando se produce una compactación automática en medio de un turno: Codex entrega el contexto adicional del hook a la continuación inmediata en lugar de esperar a un turno posterior del usuario. Si el hook devuelve continue: false, Codex finaliza el turno sin enviar otra solicitud al modelo.

SessionEnd

SessionEnd permite ejecutar un comando cuando termina una sesión, por ejemplo para guardar las notas finales o limpiar archivos. Se ejecuta para el hilo principal cuando archivas o eliminas una conversación que sigue abierta, cuando Codex se cierra con normalidad o después de que una conversación haya permanecido inactiva y no esté abierta en ningún cliente conectado durante 30 minutos. No se ejecuta para subagentes.

Cambiar de conversación o llamar a thread/unsubscribe no termina la sesión de inmediato, por lo que no ejecutará inmediatamente SessionEnd. El hook puede seguir leyendo la transcripción de la sesión mientras se ejecuta.

matcher filtra reason para este evento. Por ahora, reason siempre es other. Puedes omitir matcher o usar other para ejecutarlo en cada evento SessionEnd.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
reason string Por qué terminó la sesión: other

Por ejemplo, un comando SessionEnd recibe:

{
  "session_id": "thr_123",
  "transcript_path": "/workspace/.codex/rollout.jsonl",
  "cwd": "/workspace",
  "hook_event_name": "SessionEnd",
  "reason": "other"
}

Los hooks SessionEnd siempre se ejecutan de forma síncrona, incluso cuando async es true. Son informativos, por lo que su salida no dirigirá Codex ni mantendrá abierto el hilo. Si un comando supera el tiempo de espera o termina con un error, Codex lo registra como un fallo del hook.

SubagentStart

matcher se aplica a agent_type para este evento.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
agent_id string Identificador del subagente
agent_type string Tipo o perfil del subagente
permission_mode string Modo de permisos actual

El texto sin formato en stdout se añade como contexto adicional del desarrollador para el subagente.

El JSON en stdout admite systemMessage y esta estructura específica del hook:

{
  "hookSpecificOutput": {
    "hookEventName": "SubagentStart",
    "additionalContext": "Review the repository test conventions first."
  }
}

Ese texto additionalContext se añade como contexto adicional del desarrollador para el subagente. continue: false se analiza por compatibilidad, pero no impide que el subagente se inicie.

PreToolUse

PreToolUse puede interceptar Bash, las ediciones de archivos realizadas mediante apply_patch, las llamadas a herramientas MCP y otras herramientas de funciones locales. Consulta Cobertura de herramientas para conocer las rutas admitidas y las excepciones.

matcher se aplica a tool_name y a los alias de coincidencia. Para las ediciones de archivos mediante apply_patch, los valores matcher pueden usar apply_patch, Edit o Write; la entrada del hook sigue indicando tool_name: "apply_patch".

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
tool_name string Nombre canónico de la herramienta del hook, como Bash, apply_patch o un nombre MCP como mcp__fs__read
tool_use_id string Id. de la llamada a la herramienta para esta invocación
tool_input JSON value Entrada específica de la herramienta. Bash y apply_patch usan tool_input.command. MCP y otras herramientas de funciones locales envían sus argumentos.

El texto sin formato en stdout se ignora.

El JSON en stdout puede usar systemMessage. Para rechazar una llamada admitida a una herramienta, devuelve esta estructura específica del hook:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Destructive command blocked by hook."
  }
}

Codex también acepta esta estructura de bloqueo anterior:

{
  "decision": "block",
  "reason": "Destructive command blocked by hook."
}

También puedes usar el código de salida 2 y escribir el motivo del bloqueo en stderr.

Para añadir contexto visible para el modelo sin bloquear, devuelve hookSpecificOutput.additionalContext:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "additionalContext": "The pending command touches generated files."
  }
}

Para reescribir una llamada admitida a una herramienta sin bloquearla, devuelve permissionDecision: "allow" con updatedInput:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "updatedInput": {
      "command": "echo rewritten"
    }
  }
}

Para los comandos de Bash y apply_patch, updatedInput debe incluir un campo de cadena command. Para MCP y otras herramientas de funciones locales, updatedInput es el objeto de argumentos de sustitución. Devuelve updatedInput solo con permissionDecision: "allow"; otras estructuras updatedInput se registran como errores.

permissionDecision: "ask", el decision: "approve" heredado, continue: false, stopReason y suppressOutput se analizan, pero aún no son compatibles. Codex marca la ejecución del hook como fallida, informa del error y continúa con la llamada a la herramienta.

PermissionRequest

PermissionRequest se ejecuta cuando Codex está a punto de solicitar una aprobación, como una escalación del shell o una aprobación de la red administrada. Puede permitir la solicitud, rechazarla o abstenerse de decidir y dejar que continúe la solicitud normal de aprobación. No se ejecuta para los comandos que no necesitan aprobación.

matcher se aplica a tool_name y a los alias de coincidencia. Los valores canónicos actuales incluyen Bash, apply_patch y nombres de herramientas MCP como mcp__server__tool; apply_patch también coincide con Edit y Write.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
tool_name string Nombre canónico de la herramienta del hook, como Bash, apply_patch o un nombre MCP como mcp__fs__read
tool_input JSON value Entrada específica de la herramienta. Bash y apply_patch usan tool_input.command, mientras que las herramientas MCP envían todos los argumentos.
tool_input.description string | null Motivo de aprobación legible para las personas, cuando Codex dispone de uno

El texto sin formato en stdout se ignora.

Algunas entradas de herramientas pueden incluir una descripción legible para las personas, pero no debes depender de un campo tool_input.description para todas las herramientas.

Para aprobar la solicitud, devuelve:

{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow"
    }
  }
}

Para rechazar la solicitud, devuelve:

{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "deny",
      "message": "Blocked by repository policy."
    }
  }
}

Si varios hooks coincidentes devuelven decisiones, cualquier deny prevalece. De lo contrario, un allow permite que la solicitud continúe sin mostrar el prompt de aprobación. Si ningún hook coincidente toma una decisión, Codex utiliza el flujo normal de aprobación.

No devuelvas updatedInput, updatedPermissions ni interrupt para PermissionRequest; esos campos están reservados para funciones futuras y actualmente provocan un rechazo seguro.

PostToolUse

PostToolUse se ejecuta después de que las herramientas admitidas generen una salida, incluidas Bash, apply_patch, las llamadas a herramientas MCP y otras herramientas de funciones locales. Para Bash, también se ejecuta después de comandos que terminan con un estado distinto de cero. No puede deshacer los efectos secundarios de una herramienta que ya se haya ejecutado. Consulta Cobertura de herramientas para conocer las rutas admitidas y las excepciones.

matcher se aplica a tool_name y a los alias de coincidencia. Para las ediciones de archivos mediante apply_patch, los valores matcher pueden usar apply_patch, Edit o Write; la entrada del hook sigue indicando tool_name: "apply_patch".

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
tool_name string Nombre canónico de la herramienta del hook, como Bash, apply_patch o un nombre MCP como mcp__fs__read
tool_use_id string Id. de la llamada a la herramienta para esta invocación
tool_input JSON value Entrada específica de la herramienta. Bash y apply_patch usan tool_input.command. MCP y otras herramientas de funciones locales envían sus argumentos.
tool_response JSON value Salida específica de la herramienta. Las herramientas MCP envían el resultado de la llamada MCP. Las demás herramientas de funciones locales suelen enviar su salida destinada al modelo.

El texto sin formato en stdout se ignora.

El JSON en stdout puede usar systemMessage y esta estructura específica del hook:

{
  "decision": "block",
  "reason": "The Bash output needs review before continuing.",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "The command updated generated files."
  }
}

Ese texto additionalContext se añade como contexto adicional del desarrollador.

Para este evento, decision: "block" no deshace el comando de Bash completado. En su lugar, Codex registra los comentarios, sustituye el resultado de la herramienta por esos comentarios y permite que el modelo continúe desde el mensaje proporcionado por el hook.

También puedes usar el código de salida 2 y escribir el motivo de los comentarios en stderr.

Para detener el procesamiento normal del resultado original de la herramienta después de que el comando ya se haya ejecutado, devuelve continue: false. Codex sustituirá el resultado de la herramienta por tus comentarios o texto de detención y continuará desde allí.

updatedMCPToolOutput y suppressOutput se analizan, pero aún no son compatibles. Codex marca la ejecución del hook como fallida, informa del error y continúa con el procesamiento normal del resultado de la herramienta.

Llamadas a herramientas desde el modo de código

Cuando un modelo usa el modo de código para llamar a una herramienta desde JavaScript, las decisiones de los hooks se aplican a esa llamada anidada. PreToolUse puede detener la herramienta antes de que se ejecute o reescribir su entrada. Un PostToolUse de bloqueo no puede deshacer los efectos secundarios de la herramienta, pero sí puede impedir que el resultado original llegue al script en ejecución.

Resultado del hook Qué ve el modo de código
PreToolUse bloquea La promesa de la herramienta se rechaza antes de que esta se ejecute.
PreToolUse devuelve updatedInput La herramienta se ejecuta con la entrada reescrita y la promesa se resuelve con ese resultado.
PostToolUse devuelve decision: "block" o termina con el código 2 La herramienta se ejecuta y, después, la promesa se rechaza con el motivo del hook.
PostToolUse devuelve continue: false Codex usa los comentarios del hook como resultado visible para el modelo, pero no rechaza la promesa anidada de la herramienta.

PreCompact

PreCompact se ejecuta antes de que Codex compacte el chat. matcher se aplica a trigger, cuyos valores son manual y auto.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
trigger string Qué activó la compactación: manual o auto

El texto sin formato en stdout se ignora.

El JSON en stdout admite los campos de salida comunes. Si un hook PreCompact coincidente devuelve continue: false, Codex se detiene antes de compactar.

PostCompact

PostCompact se ejecuta después de que Codex compacte el chat. matcher se aplica a trigger, cuyos valores son manual y auto.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
trigger string Qué activó la compactación: manual o auto

El texto sin formato en stdout se ignora.

El JSON en stdout admite los campos de salida comunes. Si un hook PostCompact coincidente devuelve continue: false, Codex se detiene después de compactar.

UserPromptSubmit

matcher no se usa actualmente para este evento.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
prompt string Prompt del usuario que está a punto de enviarse

El texto sin formato en stdout se añade como contexto adicional del desarrollador.

El JSON en stdout admite los campos de salida comunes y esta estructura específica del hook:

{
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "Ask for a clearer reproduction before editing files."
  }
}

Ese texto additionalContext se añade como contexto adicional del desarrollador.

Para bloquear el prompt, devuelve:

{
  "decision": "block",
  "reason": "Ask for confirmation before doing that."
}

También puedes usar el código de salida 2 y escribir el motivo del bloqueo en stderr.

SubagentStop

matcher se aplica a agent_type para este evento.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
agent_id string Identificador del subagente
agent_type string Tipo o perfil del subagente
agent_transcript_path string | null Ruta al archivo de transcripción del subagente, si existe
stop_hook_active boolean Indica si este subagente ya continuó
last_assistant_message string | null Mensaje más reciente del asistente del subagente, si está disponible

SubagentStop espera JSON en stdout cuando termina con 0. La salida de texto sin formato no es válida para este evento.

El JSON en stdout admite los campos de salida comunes. Para pedir a Codex que continúe el flujo del subagente, devuelve:

{
  "decision": "block",
  "reason": "Run one more focused pass inside the subagent."
}

También puedes usar el código de salida 2 y escribir el motivo de la continuación en stderr.

Si algún hook SubagentStop coincidente devuelve continue: false, esto tiene precedencia sobre las decisiones de continuación de otros hooks SubagentStop coincidentes.

Stop

matcher no se usa actualmente para este evento.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Id. del turno activo de Codex
stop_hook_active boolean Indica si este turno ya continuó mediante Stop
last_assistant_message string | null Texto del mensaje más reciente del asistente, si está disponible

Stop espera JSON en stdout cuando termina con 0. La salida de texto sin formato no es válida para este evento.

El JSON en stdout admite los campos de salida comunes. Para que Codex continúe, devuelve:

{
  "decision": "block",
  "reason": "Run one more pass over the failing tests."
}

También puedes usar el código de salida 2 y escribir el motivo de la continuación en stderr.

Para este evento, decision: "block" no rechaza el turno. En su lugar, indica a Codex que continúe y crea automáticamente un nuevo prompt de continuación que actúa como un nuevo prompt del usuario y usa tu reason como texto del prompt.

Si algún hook Stop coincidente devuelve continue: false, esto tiene precedencia sobre las decisiones de continuación de otros hooks Stop coincidentes.

Interrupción

Interrupt se ejecuta cuando interrumpes un turno activo en el hilo principal. Úsalo para registrar la interrupción o limpiar el trabajo iniciado por un hook. No se ejecuta para hilos inactivos ni subagentes, y cualquier matcher configurado se ignora.

Además de los campos de entrada comunes, el evento incluye turn_id, el id del turno interrumpido, y permission_mode.

El tiempo de espera predeterminado de los hooks de comando es de un segundo. Los tiempos de espera configurados están limitados a entre uno y tres segundos. La salida del hook no puede impedir la interrupción ni reiniciar el turno. Finaliza con 0 sin generar salida o devuelve JSON con un systemMessage opcional para mostrar una advertencia. La salida de texto sin formato no es válida para este evento.

{ "systemMessage": "Saved the interrupted turn to the local audit log." }

Esquemas

Si necesitas el formato de transmisión actual exacto, consulta los esquemas generados en el repositorio de Codex en GitHub.

Alias de texto sin formato

  • string | null