Español

Hooks

Ejecuta scripts deterministas durante el ciclo de vida de Codex

Los hooks son un marco de extensibilidad para Codex. Permiten inyectar tus propios scripts en el bucle de agentes, 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 memorias persistentes automáticamente
  • Ejecutar una comprobación de validación personalizada cuando se detiene un turno del chat, para hacer cumplir los estándares
  • Personalizar los prompts cuando se trabaja en un directorio determinado

Comportamiento en tiempo de ejecución que debes tener en cuenta:

  • Se ejecutan todos los hooks coincidentes de varios archivos.
  • Varios hooks de comando coincidentes para el mismo evento se inician simultáneamente, por lo que un hook no puede impedir que se inicie otro hook coincidente.
  • Los hooks de comando 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
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 Codex los hooks

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

  • hooks.json
  • tablas [hooks] en línea dentro de config.toml

Los plugins instalados también pueden incluir la configuración del ciclo de vida mediante su manifiesto de plugin 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 reemplazan los hooks de menor precedencia. Si una sola capa contiene tanto hooks.json como [hooks] en línea, 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 plugins habilitados. Los hooks incluidos en plugins se cargan junto con otros orígenes de hooks y utilizan 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 de 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 de comando no administrado, Codex exige que revises y marques como de confianza la definición exacta del hook. Codex registra la confianza en función del hash actual del hook, por lo que los hooks nuevos o modificados se marcan para su revisión y se omiten hasta que se consideren de confianza.

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

Los hooks administrados procedentes de orígenes del sistema, MDM, la nube o requirements.toml se marcan como administrados, se consideran de confianza por política y no pueden deshabilitarse desde el explorador de hooks del usuario.

Para una automatización puntual que ya comprueba los orígenes de los hooks fuera de Codex, pasa --dangerously-bypass-hook-trust para ejecutar los hooks habilitados sin requerir que la confianza en los hooks se conserve para 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 determina cuándo coincide ese evento
  • Uno o más controladores de hooks que se ejecutan cuando coincide el grupo de coincidencia
{
  "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 usa 1 segundo de forma predeterminada y admite 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 corta. Consulta Salida extensa de hooks.
  • commandWindows es una sustitución opcional del comando exclusiva de Windows. En TOML, usa command_windows o commandWindows.
  • La opción async se analiza, pero los hooks de comando asíncronos todavía no son compatibles.
  • Actualmente, solo se ejecutan los controladores type: "command". 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 los 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 en línea 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"

Desactivar los hooks

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

[features]
hooks = false

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

Hooks administrados desde requirements.toml

Los requisitos administrados por la empresa también pueden definir hooks en línea bajo [hooks]. Esto resulta útil cuando los administradores quieren imponer la configuración de hooks mientras distribuyen los scripts reales mediante MDM u otro sistema de administración de dispositivos. Para imponer hooks administrados incluso a los usuarios que hayan deshabilitado los hooks localmente, fija [features].hooks = true en requirements.toml junto con [hooks]. Para ignorar los hooks de 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 de orígenes de usuario, proyecto, sesión y plugin, pero sigue cargando los hooks administrados de requirements.toml y otras capas de configuración administradas.

Hooks incluidos en plugins

Cuando se habilita un plugin, Codex puede cargar hooks del ciclo de vida desde ese plugin junto con los hooks de usuario, proyecto y administrados.

De forma predeterminada, Codex busca hooks/hooks.json dentro de la raíz del plugin. Un manifiesto de 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 en línea o un array de objetos de hooks en línea.

{
  "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 usa esas entradas del manifiesto en lugar del hooks/hooks.json predeterminado.

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 del plugin con permisos de escritura.
  • Codex también establece CLAUDE_PLUGIN_ROOT y CLAUDE_PLUGIN_DATA para mantener la 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 sus hooks se consideren de confianza automáticamente; Codex omite los hooks incluidos en plugins hasta que revises y marques como de confianza 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 por completo matcher para hacer coincidir cada aparición de un evento compatible.

Solo algunos eventos actuales de Codex respetan matcher:

Evento Qué filtra matcher Notas
PermissionRequest nombre de la herramienta La compatibilidad incluye Bash, apply_patch* y nombres de herramientas MCP
PostToolUse nombre de la herramienta Consulte Cobertura de herramientas
PostCompact desencadenador de compactación Los valores son manual o auto
PreCompact desencadenador de compactación Los valores son manual o auto
PreToolUse nombre de la herramienta Consulte Cobertura de herramientas
SessionEnd motivo de finalización Actualmente, solo other
SessionStart origen de 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 compatible Cualquier matcher configurado se ignora para este evento
Stop no compatible Cualquier matcher configurado se ignora para este evento

*Para apply_patch, los valores de 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 usan la misma ruta de hooks, por lo que puede buscar coincidencias con 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 Busque coincidencias como Bash.
Ejecución unificada (exec_command) Busque coincidencias como Bash. Una consulta posterior de write_stdin puede entregar el PostToolUse del comando original cuando este finalice.
apply_patch Busque coincidencias como apply_patch, Edit o Write.
Herramientas MCP Busque coincidencias con el nombre de la herramienta MCP, como mcp__filesystem__read_file.
Otras herramientas de funciones locales Busque coincidencias con 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 no usan la ruta de hooks de herramientas de funciones locales.

write_stdin es el transporte de una sesión de ejecución unificada existente. No ejecuta PreToolUse de nuevo cuando envía entradas o consulta un comando que ya pasó por PreToolUse.

Algunas rutas de herramientas especializadas pueden excluirse de la ruta de hooks predeterminada. Considere 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 comando recibe un objeto JSON en stdin.

Estos son los campos compartidos que usará 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 cuyo ámbito es el turno incluyen turn_id como una extensión específica de Codex en sus tablas específicas del evento.

SessionStart, PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, SubagentStart, SubagentStop y Stop 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 para facilitar el acceso, pero el formato de la transcripción no es una interfaz estable para los hooks y puede cambiar con el tiempo.

Si necesita el formato de transmisión completo, consulte 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 Actualmente se analiza, pero aún no está implementado

Salir con 0 sin generar salida se considera un éxito 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 esa 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 de hook grande

De forma predeterminada, Codex limita cada mensaje de salida de hook visible para el modelo a aproximadamente 2500 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 con la ruta del archivo guardado. Este comportamiento se denomina desbordamiento: Codex almacena en disco la salida que supera el tamaño permitido y la sustituye por una vista previa más breve visible para el modelo. Si no se puede escribir el archivo, el modelo sigue recibiendo una vista previa truncada.

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

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

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

La configuración se aplica únicamente a additionalContext. Los comentarios de las herramientas y las solicitudes de continuación mantienen el límite predeterminado.

Dado que la salida que supera el tamaño permitido puede escribirse en el disco, evite devolver secretos u otros datos confidenciales en la salida de los hooks.

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 de 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 la compactación automática ocurre 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 finaliza una sesión, por ejemplo, para guardar las notas finales o limpiar archivos. Se ejecuta para el hilo principal cuando archiva o elimina una conversación que sigue abierta, cuando Codex se cierra normalmente o después de que una conversación permanezca inactiva y no esté abierta en ningún cliente conectado durante 30 minutos. No se ejecuta para los subagentes.

Cambiar de conversación o llamar a thread/unsubscribe no finaliza la sesión inmediatamente, por lo que SessionEnd no se ejecutará de inmediato. Su hook aún puede leer la transcripción de la sesión mientras se ejecuta.

matcher filtra reason para este evento. Por ahora, reason siempre es other. Puede 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é finalizó 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 son informativos. Su salida no orientará a Codex ni mantendrá el hilo abierto. Si un comando agota el tiempo de espera o finaliza con un error, Codex lo informa 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 motivos de 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 la cobertura de herramientas para conocer las rutas compatibles 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 de 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 de 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 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 bloque 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 a una herramienta compatible 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 reemplazo. Devuelve updatedInput únicamente con permissionDecision: "allow"; las demás estructuras de updatedInput se notifican como errores.

permissionDecision: "ask", el formato heredado decision: "approve", 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 aprobación, por ejemplo para una escalación del shell o una aprobación de red administrada. Puede permitir la solicitud, denegar la solicitud o abstenerse de decidir y dejar que continúe la solicitud de aprobación normal. No se ejecuta para 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 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 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 dependas de un campo tool_input.description para todas las herramientas.

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 coincidentes devuelven decisiones, prevalece cualquier deny. De lo contrario, un allow permite que la solicitud continúe sin mostrar la solicitud de aprobación. Si ningún hook coincidente toma una decisión, Codex usa el flujo de aprobación normal.

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

PostToolUse

PostToolUse se ejecuta después de que las herramientas compatibles generen una salida, incluidas Bash, apply_patch, las llamadas a herramientas MCP y otras herramientas de funciones locales. En el caso de Bash, también se ejecuta después de comandos que finalizan con un estado distinto de cero. No puede deshacer los efectos secundarios de una herramienta que ya se ha ejecutado. Consulta la cobertura de herramientas para conocer las rutas compatibles 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 de 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 de 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. Otras 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, reemplaza el resultado de la herramienta por esos comentarios y continúa el modelo 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 reemplazará 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 del hook 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 puede impedir que el resultado original llegue al script en ejecución.

Resultado del hook Lo que 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 finaliza 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 de la herramienta anidada.

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 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 para el 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 Último mensaje 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 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 prioridad sobre las decisiones de continuación de otros hooks SubagentStop coincidentes.

Stop

matcher no se utiliza 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 Stop ya continuó este turno
last_assistant_message string | null Texto del último mensaje 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 Campos de salida comunes. Para que Codex siga ejecutándose, 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, usando tu reason como texto del prompt.

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

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