For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navegación principal
Theme

Hooks

Ejecuta scripts o herramientas MCP durante el ciclo de vida de Codex

Los hooks permiten extender las funciones de Codex. Con ellos puedes ejecutar scripts o herramientas MCP durante el ciclo de ejecución del agente para hacer tareas como estas:

  • Enviar el chat a un motor personalizado de registro y análisis
  • Revisar los prompts de tu equipo para impedir que se envíen claves de API pegadas por accidente
  • Resumir chats para crear memorias persistentes de forma automática
  • Ejecutar una validación personalizada cuando termina un turno del chat para exigir el cumplimiento de estándares
  • Personalizar los prompts cuando trabajas en un directorio específico

Cómo se ejecutan los hooks:

  • Se ejecutan todos los hooks que coincidan, aunque provengan de archivos distintos.
  • Si varios hooks de comando coinciden con el mismo evento, se inician de forma concurrente. Ninguno puede impedir que se inicie otro hook que también coincida.
  • Antes de ejecutar un hook no administrado, debes revisarlo y marcarlo como confiable.

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
En cada intento de enviar una solicitud al modelo PreModelRequest, PostModelRequest
Cuando interrumpes un turno activo Interrupt (no se ejecuta para subagentes)
Cuando se inicia una sesión o un subagente SessionStart, SubagentStart
Cuando termina el hilo principal SessionEnd (no se ejecuta para subagentes)

Dónde busca hooks Codex

Codex busca hooks en las ubicaciones de las capas de configuración activas. Pueden tener cualquiera de estas formas:

  • hooks.json
  • Tablas [hooks] integradas en config.toml

Los complementos instalados también pueden incluir la configuración del ciclo de vida en su archivo de manifiesto o en el archivo predeterminado hooks/hooks.json. Consulta las reglas de empaquetado en Crear complementos.

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 hay más de una fuente de hooks, Codex carga todos los hooks que coincidan. Las capas de configuración de mayor prioridad no reemplazan los hooks de las capas de menor prioridad. Si una capa contiene tanto hooks.json como tablas [hooks] integradas, Codex los combina y muestra una advertencia al iniciarse. Procura usar una sola representación por capa.

Codex también puede detectar hooks incluidos en complementos habilitados. Estos hooks se cargan junto con los de otras fuentes y pasan por el mismo proceso de revisión de confianza que los demás hooks no administrados.

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

Revisar hooks y marcarlos como confiables

Codex enumera los hooks configurados antes de determinar cuáles pueden ejecutarse. Para que un hook no administrado pueda ejecutarse, Codex requiere que revises su definición exacta y la marques como confiable. Codex asocia esa decisión con el hash actual del hook. Por eso, marca los hooks nuevos o modificados como pendientes de revisión y los omite hasta que los marques como confiables.

Usa /hooks en la CLI para inspeccionar las fuentes de los hooks, revisar hooks nuevos o modificados, marcarlos como confiables o deshabilitar hooks no administrados de forma individual. Si hay hooks pendientes de revisión al iniciar Codex, verás una advertencia que te indica que abras /hooks.

Los hooks administrados que provienen del sistema, de MDM, de la nube o de requirements.toml aparecen como administrados. La política los considera confiables y no puedes deshabilitarlos desde el explorador de hooks del usuario.

Para una automatización puntual que ya verifica las fuentes de los hooks fuera de Codex, pasa --dangerously-bypass-hook-trust. Así puedes ejecutar los hooks habilitados sin que esa invocación requiera una decisión de confianza guardada.

Estructura de la 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 define los criterios que debe cumplir el evento
  • Uno o más manejadores de hooks que se ejecutan cuando el evento cumple los criterios del 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 es un campo opcional de metadatos en el nivel superior de un archivo hooks.json. No cambia qué hooks se ejecutan.
  • timeout se expresa en segundos.
  • Si omites timeout, Codex usa 600 segundos para la mayoría de los hooks.
    • SessionEnd e Interrupt usan 1 segundo de forma predeterminada y admiten hasta 3 segundos.
  • statusMessage es opcional.
  • additionalContextLimit establece cuánto contenido de additionalContext puede enviar un hook de comando al modelo antes de que Codex guarde el texto completo en disco y envíe una vista previa más corta. Consulta Salidas extensas de los hooks.
  • commandWindows permite especificar un comando alternativo que se usa solo en Windows. En TOML, usa command_windows o commandWindows.
  • Establece async en true para ejecutar un hook de comando en segundo plano.
  • Se admiten los manejadores command y mcp_tool. Los manejadores prompt y agent se interpretan, pero se omiten.
  • Los comandos usan el cwd de la sesión como directorio de trabajo.
  • Para los hooks locales del repositorio, conviene resolver la ruta desde la raíz del repositorio de Git en lugar de usar una ruta relativa como .codex/hooks/.... Codex puede iniciarse desde un subdirectorio. Una ruta basada en la raíz del repositorio permite localizar el hook independientemente del directorio de inicio.

Configuración TOML equivalente integrada 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 usa el mismo proceso de revisión de confianza y el mismo contrato de salida que un hook de comando.

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 que ofrece ese servidor.
input Objeto JSON opcional con plantillas de argumentos. El valor predeterminado es {}.
timeout Tiempo límite opcional de 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 del evento mediante la notación de puntos. Si un marcador de posición ocupa todo el valor, conserva su tipo JSON. Si forma parte de una cadena más larga, se convierte en texto. Codex expande los objetos y los arreglos de forma recursiva.

Para un evento que contiene {"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 usan una conexión MCP existente. No inician servidores ni vuelven a conectarlos.
  • Un hook puede bloquear una operación si la herramienta devuelve una decisión de bloqueo. Los errores, la ausencia de un servidor y la falta de disponibilidad de una herramienta no bloquean la operación.
  • Los hooks de herramientas MCP se ejecutan de forma síncrona. No solicitan aprobación para usar herramientas ni activan otros hooks.
  • Se aplica el menor de los tiempos límite del hook y del servidor. El tiempo de espera de una respuesta a una solicitud de exploración de MCP no cuenta para ese límite.
  • Los hooks SessionStart pueden ejecutarse antes de que un servidor MCP esté listo. Si eso 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, usa esta configuración:

[features]
hooks = false

Usa hooks como clave de la función. codex_hooks aún funciona como alias obsoleto. Los administradores pueden desactivar los hooks de forma obligatoria en requirements.toml con [features].hooks = false.

Hooks administrados desde requirements.toml

Elige los hooks según el entorno que coordina la tarea.

Hooks con orquestación en la nube

En los espacios de trabajo que tienen habilitados tanto la política administrada como los hooks remotos, el modo Work en la nube con acceso a la computadora local y los dots pueden llamar a un servicio MCP cuando se producen determinados eventos de tareas o herramientas. Estas llamadas usan los manejadores mcp_tool que el administrador de tu espacio de trabajo configura en Seguridad de agentes. Ni el modo Work en la nube sin acceso a la computadora local ni las cuentas personales usan estos hooks empresariales.

La orquestación en la nube solo admite hooks MCP de alcance global, incluso cuando una herramienta se ejecuta en una computadora conectada. No admite manejadores de comandos, de prompts ni de agentes. Tampoco admite hooks de la configuración local, de complementos o de directorios locales, hooks específicos de un entorno ni hooks MCP de SessionEnd. Cuando tanto la orquestación como la ejecución son locales, los hilos exclusivamente locales del modo Work y de Codex siguen admitiendo los hooks que ya usaban.

Un hook compatible puede bloquear una acción si la deniega de forma explícita. Si se produce un error en PreToolUse, se agota el tiempo de espera o la respuesta tiene un formato incorrecto, es posible que la herramienta se ejecute. Los hooks MCP solo proporcionan una parte del registro de auditoría. Para saber qué comprobar durante la implementación y qué cubre la auditoría, consulta Comprobar la compatibilidad de los hooks y la red.

Hooks administrados en Codex local

Define los hooks locales de Codex en la sección [hooks] de requirements.toml. Para exigir la ejecución de los hooks administrados incluso si un usuario deshabilitó los hooks de forma local, fija [features].hooks = true en requirements.toml junto con [hooks]. Para omitir los hooks de usuario, proyecto, sesión y complementos y seguir permitiendo los que gestiona 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 los hooks administrados deben usar rutas absolutas a scripts dentro del directorio administrado que hayas configurado.
  • allow_managed_hooks_only = true omite los hooks de usuario, proyecto, sesión y complementos, pero sigue cargando los hooks administrados de requirements.toml y de otras capas de configuración administradas.

Hooks incluidos en complementos

Cuando un complemento está habilitado, Codex puede cargar sus hooks de ciclo de vida junto con los hooks de usuario, de proyecto y administrados.

De forma predeterminada, Codex busca hooks/hooks.json dentro de la raíz del complemento. El archivo de manifiesto del complemento puede cambiar este comportamiento con una entrada hooks en .codex-plugin/plugin.json. La entrada del archivo de manifiesto puede ser una ruta que comience con ./, un arreglo de rutas que comiencen con ./, un objeto de hooks definido directamente en el archivo o un arreglo de esos objetos.

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

Las rutas de los hooks del archivo de manifiesto se resuelven con respecto a la raíz del complemento y deben quedar dentro de ella. Si el archivo de manifiesto define hooks, Codex usa esas entradas en lugar del archivo predeterminado hooks/hooks.json.

Los comandos de los hooks de complementos reciben estas variables de entorno:

  • PLUGIN_ROOT es una extensión específica de Codex que apunta a la raíz del complemento instalado.
  • PLUGIN_DATA es una extensión específica de Codex que apunta al directorio de datos del complemento con permisos de escritura.
  • Codex también establece CLAUDE_PLUGIN_ROOT y CLAUDE_PLUGIN_DATA para mantener la compatibilidad con los hooks de complementos existentes.

Los hooks de complementos usan el mismo esquema de eventos que los demás hooks. Revísalos y márcalos como confiables antes de que se ejecuten. En la CLI, abre /hooks. En la aplicación de escritorio, selecciona Revisar hooks en el editor o abre Configuración > Hooks. Si una actualización del complemento modifica uno de los scripts incluidos, Codex exige una nueva revisión, aunque la definición del hook siga siendo la misma.

Patrones de coincidencia

El campo matcher contiene una expresión regular que determina cuándo se activa un hook. Usa "*" o "", u omite matcher por completo, para que coincida cada vez que ocurra un evento compatible.

Solo algunos eventos actuales de Codex tienen en cuenta matcher:

Evento Qué filtra matcher Notas
PermissionRequest Nombre de la herramienta Admite Bash, apply_patch* y nombres de herramientas MCP
PostToolUse Nombre de la herramienta Consulta Herramientas compatibles
PostCompact Desencadenante de la compactación Los valores son manual o auto
PreModelRequest, PostModelRequest No se admite Ambos eventos se ejecutan en cada intento de enviar una solicitud al modelo
PreCompact Desencadenante de la compactación Los valores son manual o auto
PreToolUse Nombre de la herramienta Consulta Herramientas compatibles
SessionEnd Motivo de finalización Por ahora, solo other
SessionStart Origen del inicio Los valores son startup, resume, clear, compact y fork
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 Se ignora cualquier matcher configurado para este evento
Stop No se admite Se ignora cualquier matcher configurado para este evento
Interrupt No se admite Se ignora cualquier matcher configurado para este evento

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

Ejemplos:

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

Herramientas compatibles

PreToolUse y PostToolUse pueden observar llamadas a herramientas además de las llamadas al shell y a MCP. La mayoría de las herramientas de función locales usan el mismo mecanismo de hooks. Puedes filtrar por nombre de herramienta, inspeccionar sus argumentos JSON y, en el caso de PreToolUse, bloquear o reescribir la llamada.

Vía de ejecución de la herramienta PreToolUse PostToolUse Notas
Comandos de shell Sí Sí Coinciden con Bash.
Ejecución unificada (exec_command) Sí Sí Coincide con Bash. Una consulta posterior con write_stdin puede entregar el evento PostToolUse del comando original cuando este termine.
apply_patch Sí Sí Coincide con apply_patch, Edit o Write.
Herramientas MCP Sí Sí Usa el nombre de la herramienta MCP, como mcp__filesystem__read_file.
Otras herramientas de función locales Sí Sí Usa el nombre de la herramienta de función, como update_plan. spawn_agent también coincide con Agent.
Herramientas alojadas, como WebSearch No No Estas herramientas no usan el mecanismo de hooks de las herramientas de función locales.

write_stdin sirve de transporte para una sesión de ejecución unificada existente. No vuelve a ejecutar PreToolUse cuando envía datos de entrada o consulta el estado de un comando que ya pasó por PreToolUse.

Algunas vías de ejecución especializadas pueden omitir el mecanismo de hooks predeterminado. Los hooks de herramientas ofrecen una protección útil, pero por sí solos no garantizan que se apliquen todas las restricciones.

Campos de entrada comunes

Cada hook de comando recibe un objeto JSON en stdin.

Estos son los campos compartidos que usarás habitualmente:

Campo Tipo Significado
session_id string Identificador de la sesión actual de Codex. Los hooks de subagentes usan el identificador 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

En los hooks cuyo alcance se limita a un turno, turn_id aparece como extensión específica de Codex en la tabla del evento correspondiente.

SessionStart, PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, SubagentStart, SubagentStop, Stop e Interrupt también incluyen permission_mode, que indica el modo de permisos actual mediante uno de estos valores: default, acceptEdits, plan, dontAsk o bypassPermissions.

transcript_path apunta a la transcripción del chat para facilitar su consulta, 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 completo de los datos transmitidos, 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 Aparece como advertencia en la interfaz de usuario o en el flujo de eventos
suppressOutput El campo se interpreta, pero su efecto aún no está implementado

El código de salida 0 sin datos de salida indica que la ejecución tuvo éxito y Codex continúa.

PreToolUse y PermissionRequest admiten systemMessage, pero estos eventos aún no admiten continue, stopReason ni suppressOutput. Si un hook PreToolUse devuelve uno de esos campos no admitidos, 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. El campo suppressOutput se interpreta, pero este evento aún no admite su uso.

Salidas extensas de los hooks

De forma predeterminada, Codex limita cada mensaje de salida de un hook visible para el modelo a unos 2500 tokens. Si un hook devuelve más, Codex guarda el texto completo en <temp_dir>/hook_outputs/<session_id>/<uuid>.txt y entrega al modelo una vista previa del principio y del final junto con la ruta del archivo guardado. Este comportamiento se denomina volcado a disco: Codex guarda en disco la salida que excede el límite y la sustituye por una vista previa más breve que el modelo puede ver. Si no se puede escribir el archivo, el modelo recibe de todos modos una vista previa truncada.

Mantén breve el contexto de los hooks y los complementos. El contexto de varios hooks y complementos se acumula y puede reducir el rendimiento del modelo. Aumentar additionalContextLimit incrementa ese riesgo. Evita establecer el límite en 0 a menos que el hook imponga un límite estricto a su salida. De lo contrario, un solo hook puede ocupar toda la ventana de contexto.

Para personalizar el umbral aproximado de tokens de un hook de comando que devuelve additionalContext, establece additionalContextLimit en su manejador:

{
  "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 elegir otro umbral, o 0 para pasar todo el contexto adicional del manejador directamente al modelo. Codex evalúa por separado cada manejador que coincida. En los eventos que no pueden generar contexto adicional, Codex ignora additionalContextLimit y muestra una advertencia de configuración.

Esta configuración solo se aplica a additionalContext. Los comentarios sobre las herramientas y los prompts de continuación conservan el límite predeterminado.

Como las salidas extensas pueden guardarse en disco, evita devolver secretos u otros datos confidenciales en la salida de los hooks.

Ejecutar hooks en segundo plano

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

Configurar un hook en segundo plano

Agrega "async": true a un manejador 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 definido directamente 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 los mismos datos de entrada, criterios de coincidencia, proceso de revisión de confianza, tiempo límite y tratamiento de salidas extensas que los hooks de comando síncronos. Como en los demás hooks de comando, timeout se mide en segundos y su valor predeterminado es 600. Los hooks Interrupt tienen un tiempo límite predeterminado de un segundo y admiten 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 momento seguro de la conversación:

  • Si hay un turno activo, Codex espera a que terminen la solicitud actual al modelo y las llamadas a herramientas. Luego pone la salida a disposición de la siguiente solicitud al modelo dentro de ese turno.
  • Si no hay un 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 usarías con un hook síncrono. Codex agrega additionalContext al contexto del modelo y muestra systemMessage como advertencia.

Los hooks en segundo plano no pueden bloquear, aprobar, reescribir ni controlar de otro modo la operación que los activó. Usa hooks síncronos para aplicar políticas de herramientas, tomar decisiones sobre permisos, rechazar prompts o continuar un turno.

Limitaciones

  • Codex ejecuta hasta ocho hooks en segundo plano de forma concurrente por sesión. Los demás esperan a que termine uno de los que están en ejecución.
  • Cada invocación que coincide se ejecuta de forma independiente. Los hooks en segundo plano pueden terminar en un orden distinto al de inicio.
  • Al terminar la sesión, Codex cancela los hooks en segundo plano que aún se estén ejecutando y descarta la salida que todavía no haya entregado.
  • Los hooks SessionEnd siempre se ejecutan de forma síncrona.

Hooks

SessionStart

En este evento, matcher se aplica a source.

Campos adicionales a los campos de entrada comunes:

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

Un hilo creado mediante un fork usa source: "fork". Al reanudar un hilo con un historial proporcionado, se sigue usando source: "resume".

El texto plano de stdout se agrega como contexto adicional del desarrollador.

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

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

El texto de additionalContext se agrega como contexto adicional del desarrollador.

Después de que Codex compacta una sesión raíz, los hooks SessionStart que coinciden con source: "compact" se ejecutan antes de la siguiente solicitud al modelo. Esto también ocurre si la compactación automática tiene lugar en medio de un turno. Codex entrega el contexto adicional del hook en cuanto continúa el turno, sin esperar a un turno posterior del usuario. Si el hook devuelve continue: false, Codex termina el turno sin enviar otra solicitud al modelo.

SessionEnd

SessionEnd te permite ejecutar un comando cuando termina una sesión, por ejemplo, para guardar notas finales o limpiar archivos. Se ejecuta en el hilo principal cuando archivas o eliminas una conversación que sigue abierta, cuando Codex se cierra normalmente o cuando una conversación lleva 30 minutos inactiva sin estar abierta en ningún cliente conectado. No se ejecuta para subagentes.

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

En este evento, matcher filtra por reason. Por ahora, reason siempre es other. Puedes omitir matcher o usar other para que el hook se ejecute en cada evento SessionEnd.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
reason string Motivo por el que terminó la sesión: other

Por ejemplo, un comando de 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 si async es true. Su salida es informativa, por lo que no modifica el comportamiento de Codex ni mantiene abierto el hilo. Si un comando excede el tiempo límite o termina con un error, Codex lo informa como una falla del hook.

SubagentStart

En este evento, matcher se aplica a agent_type.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Identificador 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 plano de stdout se agrega como contexto adicional del desarrollador para el subagente.

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

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

El texto de additionalContext se agrega como contexto adicional del desarrollador para el subagente. El valor continue: false se interpreta por compatibilidad, pero no impide que se inicie el subagente.

PreToolUse

PreToolUse puede interceptar comandos de Bash, ediciones de archivos realizadas mediante apply_patch, llamadas a herramientas MCP y llamadas a otras herramientas de función locales. Consulta las vías de ejecución compatibles y sus excepciones en Herramientas compatibles.

matcher se aplica a tool_name y a los alias de coincidencia. Para las ediciones de archivos mediante apply_patch, los valores de matcher pueden ser 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. Identificador del turno activo de Codex
tool_name string Nombre canónico de la herramienta para el hook, como Bash, apply_patch o un nombre de MCP como mcp__fs__read
tool_use_id string Identificador de la llamada a la herramienta en esta invocación
tool_input JSON value Entrada específica de la herramienta. Bash y apply_patch usan tool_input.command. Las herramientas MCP y otras herramientas de función locales envían sus argumentos.

El texto plano de stdout se ignora.

El JSON de stdout puede usar systemMessage. Para denegar una llamada a una herramienta compatible, 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 agregar contexto visible para el modelo sin bloquear la llamada, devuelve hookSpecificOutput.additionalContext:

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

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

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

Para comandos de Bash y apply_patch, updatedInput debe incluir un campo command de tipo cadena. Para MCP y otras herramientas de función locales, updatedInput es el objeto de argumentos que reemplaza al original. Devuelve updatedInput solo junto con permissionDecision: "allow". Codex informa de un error si updatedInput tiene otra estructura.

Los valores permissionDecision: "ask", decision: "approve" de versiones anteriores, continue: false, stopReason y suppressOutput se interpretan, pero aún no se admiten. 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á por solicitar aprobación, por ejemplo, para elevar los permisos de un comando de shell o autorizar el acceso a una red administrada. Puede permitir la solicitud, denegarla o abstenerse de decidir para que se muestre la solicitud de aprobación habitual. No se ejecuta para comandos que no requieren 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. La herramienta 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. Identificador del turno activo de Codex
tool_name string Nombre canónico de la herramienta para el hook, como Bash, apply_patch o un nombre de 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 sus argumentos.
tool_input.description string | null Motivo de la solicitud de aprobación en lenguaje natural, si Codex dispone de él

El texto plano de stdout se ignora.

La entrada de algunas herramientas puede incluir una descripción en lenguaje natural, pero no cuentes con que todas tengan el campo tool_input.description.

Para aprobar la solicitud, devuelve:

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

Para denegar la solicitud, devuelve:

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

Si varios hooks coinciden y devuelven decisiones, cualquier deny tiene prioridad. En los demás casos, un allow permite que la solicitud continúe sin mostrar el mensaje de aprobación. Si ningún hook coincidente toma una decisión, Codex usa el flujo de aprobación habitual.

No devuelvas updatedInput, updatedPermissions ni interrupt para PermissionRequest. Estos campos están reservados para funciones futuras y, por ahora, su uso impide que se autorice la solicitud.

PostToolUse

PostToolUse se ejecuta después de que las herramientas compatibles generan una salida. Esto incluye Bash, apply_patch, las llamadas a herramientas MCP y otras herramientas de función locales. En Bash, también se ejecuta después de comandos que terminan con un código de salida distinto de cero. No puede revertir los efectos de una herramienta que ya se ejecutó. Consulta las vías de ejecución compatibles y sus excepciones en Herramientas compatibles.

matcher se aplica a tool_name y a los alias de coincidencia. Para las ediciones de archivos mediante apply_patch, los valores de matcher pueden ser 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. Identificador del turno activo de Codex
tool_name string Nombre canónico de la herramienta para el hook, como Bash, apply_patch o un nombre de MCP como mcp__fs__read
tool_use_id string Identificador de la llamada a la herramienta en esta invocación
tool_input JSON value Entrada específica de la herramienta. Bash y apply_patch usan tool_input.command. Las herramientas MCP y otras herramientas de función 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 función locales normalmente envían la salida que recibe el modelo.

El texto plano de stdout se ignora.

El JSON de 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."
  }
}

El texto de additionalContext se agrega como contexto adicional del desarrollador.

En este evento, decision: "block" no revierte el comando de Bash que ya terminó. Codex registra los comentarios del hook, sustituye el resultado de la herramienta por esos comentarios y reanuda la ejecución del modelo a partir del mensaje del hook.

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

Para detener el procesamiento normal del resultado original después de que se haya ejecutado el comando, devuelve continue: false. Codex reemplazará el resultado de la herramienta por tus comentarios o por el texto que indica el motivo de la detención y continuará a partir de ahí.

Los campos updatedMCPToolOutput y suppressOutput se interpretan, pero aún no se admiten. 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 bloqueo de PostToolUse no puede revertir los efectos de la herramienta, pero sí puede impedir que el script en ejecución reciba el resultado original.

Resultado del hook Qué ocurre en el modo de código
PreToolUse bloquea la llamada La promesa de la herramienta se rechaza antes de que se ejecute la herramienta.
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 luego la promesa se rechaza con el motivo que indicó el hook.
PostToolUse devuelve continue: false Codex usa los comentarios del hook como resultado visible para el modelo, pero no rechaza la promesa de la llamada anidada a la herramienta.

PreModelRequest y PostModelRequest

Usa estos hooks para registrar las solicitudes al modelo, incluidos los reintentos dentro de un mismo turno. PreModelRequest se ejecuta antes de cada intento. PostModelRequest informa del resultado. Ambos reciben el modelo y turn_id, además de agent_id y agent_type cuando están disponibles. La salida de estos hooks solo sirve para fines de diagnóstico. No puede modificar el contexto del modelo ni bloquear una solicitud.

PostModelRequest incluye tres campos adicionales:

Campo Significado
status completed, failed o cancelled.
error Mensaje de error si está disponible. De lo contrario, null.
token_usage Recuentos de tokens del intento si están disponibles. De lo contrario, null.

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. Identificador del turno activo de Codex
trigger string Qué activó la compactación: manual o auto

El texto plano de stdout se ignora.

El JSON de stdout admite los campos de salida comunes. Si un hook PreCompact que coincide devuelve continue: false, Codex se detiene antes de la compactación.

PostCompact

PostCompact se ejecuta después de que Codex compacta 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. Identificador del turno activo de Codex
trigger string Qué activó la compactación: manual o auto

El texto plano de stdout se ignora.

El JSON de stdout admite los campos de salida comunes. Si un hook PostCompact que coincide devuelve continue: false, Codex se detiene después de la compactación.

UserPromptSubmit

Por ahora, matcher no se usa en este evento.

Campos adicionales a los campos de entrada comunes:

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

El texto plano de stdout se agrega como contexto adicional del desarrollador.

El JSON de 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."
  }
}

El texto de additionalContext se agrega 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

En este evento, matcher se aplica a agent_type.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Identificador 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 ya se hizo que este subagente continuara
last_assistant_message string | null Último mensaje del asistente del subagente, si está disponible

SubagentStop espera JSON en stdout cuando termina con el código 0. Este evento no admite texto plano como salida.

El JSON de stdout admite los campos de salida comunes. Para pedirle 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 alguno de los hooks SubagentStop que coinciden devuelve continue: false, ese valor tiene prioridad sobre las decisiones de continuar de otros hooks SubagentStop que también coincidan.

Stop

Por ahora, matcher no se usa en este evento.

Campos adicionales a los campos de entrada comunes:

Campo Tipo Significado
turn_id string Extensión específica de Codex. Identificador del turno activo de Codex
stop_hook_active boolean Indica si ya se prolongó este turno mediante Stop
last_assistant_message string | null Texto del último mensaje del asistente, si está disponible

Stop espera JSON en stdout cuando termina con el código 0. Este evento no admite texto plano como salida.

El JSON de 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.

En este evento, decision: "block" no rechaza el turno. Le indica a Codex que continúe y crea automáticamente un prompt de continuación que funciona como un nuevo prompt del usuario. El texto de ese prompt es el valor de reason que proporcionaste.

Si alguno de los hooks Stop que coinciden devuelve continue: false, ese valor tiene prioridad sobre las decisiones de continuar de otros hooks Stop que también coincidan.

Interrupt

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 en hilos inactivos ni para subagentes, y se ignora cualquier matcher configurado.

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

Los hooks de comando tienen un tiempo límite predeterminado de un segundo. Puedes configurar un tiempo límite de entre uno y tres segundos. La salida del hook no puede impedir la interrupción ni reiniciar el turno. Termina con el código 0 sin generar salida, o devuelve JSON con un campo opcional systemMessage para mostrar una advertencia. Este evento no admite texto plano como salida.

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

Esquemas

Los esquemas de la rama main que se enlazan a continuación pueden incluir campos de hooks que no están disponibles en la versión actual. Usa esta página como referencia para el comportamiento de la versión publicada.

Si necesitas el formato exacto que se usa actualmente para transmitir los datos, consulta los esquemas generados en el repositorio de Codex en GitHub.