Skip to content

Reglas y ganchos (Rules & Hooks): configurando puntos de control y disparadores en Codex

📚 Navegación de la serie: El artículo anterior [23 · Plugins (Plugins)] explicó cómo instalar paquetes de capacidades integradas en Codex de un solo golpe. En este capítulo analizaremos dos funcionalidades fundamentales: las Reglas (Rules) que definen qué comandos se permiten ejecutar fuera del sandbox, y los Ganchos (Hooks) que ejecutan scripts automáticamente en momentos específicos de la sesión. Las primeras actúan como filtros y los segundos como disparadores; una vez configurados, automatizarán las comprobaciones recurrentes y tediosas. En el próximo artículo [25 · Aislamiento en paralelo con Worktrees] explicaremos cómo ejecutar múltiples sesiones de Codex en paralelo de forma aislada.

Recreemos una conversación real del mes pasado mientras mi compañero y yo depurábamos un fallo en la CI:

Yo: "Esta semana habré ejecutado ruff format manualmente más de diez veces después de que Codex modificara el código". Compañero: "¿No especificaste 'recuerda formatear tras editar' en tu AGENTS.md?" Yo: "Sí, pero una de cada tres veces se le olvida. Es una petición, no una garantía. Si se le pasa, la validación de formato en la CI me tira el commit y tengo que repetir el proceso". Compañero: "Pues configura un Hook. Al dispararse el evento, el script se ejecutará sí o sí, independientemente de que el modelo se acuerde o no".

Esa simple sugerencia me dio la clave. Diseñé un Hook para el evento PostToolUse y, desde entonces, cada vez que Codex edita un archivo, el formateador se ejecuta automáticamente. No he vuelto a escribir el comando a mano ni me ha fallado ningún pipeline por formato. En este capítulo explicaremos cómo estructurar y depurar reglas y Hooks.

Al terminar este artículo, obtendrás:

  • Qué regulan las reglas y los Hooks, y cómo garantizan la automatización a diferencia de AGENTS.md.
  • Cómo definir reglas (archivos .rules y prefix_rule) para permitir o denegar comandos, y validarlas con codex execpolicy check.
  • Archivos de destino y eventos de ciclo de vida de los Hooks (PreToolUse, PostToolUse, Stop, SessionStart, etc.).
  • La directiva de confianza de Hooks de Codex: por qué los Hooks nuevos no se cargan por defecto y exigen tu validación manual con /hooks.
  • Flujo de comunicación de Hooks (JSON en stdin, códigos de salida y JSON en stdout) y diferencias críticas con Claude Code.
  • Dos plantillas listas para usar: formateo automático tras guardar e interceptor de comandos de riesgo, junto con pautas de depuración.

01 Comprender la diferencia: las reglas son filtros y los Hooks son disparadores

Definamos el propósito de cada uno, ya que sus conceptos abstractos suelen confundirse de entrada.

  • Reglas (Rules): definen si un comando tiene autorización para ejecutarse fuera del sandbox. Actúan como un filtro que evalúa las peticiones y decide si autorizar, preguntar al usuario o denegar directamente.
  • Ganchos (Hooks): ejecutan scripts automáticamente al llegar a un punto del ciclo de vida. Actúan como un disparador vinculado a un evento; cuando este ocurre, el script se ejecuta de forma independiente al criterio del modelo.

Analogía: El control de acceso y el sensor de luz de una urbanización. El sistema de acceso almacena la base de datos de "quién puede entrar, quién debe registrarse y a quién bloquear"; esto son las reglas: cada vez que se desliza una tarjeta, el software toma la decisión en base a la lista. Por otro lado, la lámpara del pasillo que se enciende cuando pasa un peatón es el Hook: no evalúa quién eres ni tu destino; si se detecta movimiento (evento), la luz se enciende. Uno filtra el acceso y el otro responde automáticamente; no los confundas.

¿En qué se diferencian de AGENTS.md (el manual del proyecto explicado en el artículo 11)? La diferencia es de concepto:

Las directrices en AGENTS.md son peticiones; las configuradas en reglas o Hooks son garantías.

En resumen:

  • Directrices en AGENTS.md: como pedir "ejecuta el formateador" o "no alteres la base de datos". Son sugerencias que el modelo evaluará en cada paso, pero que puede omitir u olvidar.
  • Reglas y Hooks formales: el formateo o bloqueo configurados en el sistema se ejecutarán siempre al cumplirse la condición, sin importar el criterio del modelo.

Esta es la clave: pedir formatear el código en AGENTS.md fallará ocasionalmente; configurarlo como Hook garantiza su ejecución en el 100% de los casos.

Casos prácticos recomendados:

  • Autorización directa: para comandos de uso continuo (p. ej. gh pr view), configura una regla para omitir el cuadro de confirmación.
  • Bloqueos de seguridad: impide la ejecución de comandos de riesgo como rm -rf o git push --force mediante reglas estrictas.
  • Automatización tras guardar: vincula un Hook para ejecutar el formateador tras modificar archivos, sin tener que teclearlo tú.

💡 Resumen en una frase: Las reglas filtran la ejecución de comandos y los Hooks disparan scripts al llegar a eventos específicos; su valor consiste en transformar las peticiones de AGENTS.md en garantías de automatización.


02 Reglas (Rules): regular la ejecución de comandos

⚠️ Función experimental: el sistema de reglas está etiquetado como experimental en la documentación oficial; las claves y comportamientos están sujetos a cambios.

¿Qué problemas resuelven las reglas? El sandbox del artículo 15 establece límites generales: permite actividades internas y solicita confirmación al salir de su marco. Sin embargo, a veces requieres controles específicos por comando: "permite gh pr view directamente" o "deniega el uso de grep para obligar a usar rg". Modificar los límites del sandbox global para esto sería imprudente; definir una regla es la solución idónea.

Analogía: La lista de excepciones del conserje. Las directivas del sandbox son las normas básicas de seguridad (p. ej. "solicitar identificación a toda persona ajena al edificio"). Las reglas son anotaciones específicas: una lista de "invitados habituales que pueden pasar sin identificarse" y otra de "personas con prohibición de entrada". Seguir estas listas ahorra tiempo y mantiene la seguridad del edificio.

It realmente se usa para:

  • Permitir comandos de lectura frecuentes como gh o make test para evitar clics repetitivos de aprobación.
  • Denegar utilidades obsoletas como grep o find para fomentar el uso de alternativas eficientes como rg o fd.
  • Bloquear de forma absoluta comandos peligrosos (p. ej. rm -rf / o cambios en ~/.ssh) a nivel corporativo.

Estructura y ubicación de los archivos de reglas

Las reglas se guardan en archivos con extensión .rules dentro de una carpeta rules/ contigua a los directorios de configuración de Codex. La ubicación habitual es ~/.codex/rules/default.rules. La sintaxis es similar a Python pero utiliza Starlark (un dialecto seguro e independiente del sistema de archivos).

Ejemplo básico para solicitar confirmación en gh pr view:

python
# Solicitar confirmación antes de ejecutar comandos con el prefijo `gh pr view`.
prefix_rule(
    # Prefijo de comando a analizar (desglosado por parámetros).
    pattern = ["gh", "pr", "view"],

    # Acción al coincidir: allow (permitir) / prompt (preguntar) / forbidden (bloquear).
    decision = "prompt",

    # Opcional: justificación mostrada en las alertas de confirmación.
    justification = "Permitir visualizar PRs pero solicitando autorización previa",

    # Opcional: pruebas unitarias para validar las coincidencias en la carga del archivo.
    match = [
        "gh pr view 7888",
        "gh pr view --repo openai/codex",
    ],
    not_match = [
        # No coincide: el parámetro pattern evalúa prefijos exactos.
        "gh pr --repo openai/codex view 7888",
    ],
)

Variables del bloque prefix_rule:

VariableFunciónNota
pattern (obligatorio)Prefijo de comando a buscar, desglosado por parámetrosPermite literales ("pr") o matrices lógicas (["view", "list"])
decision (por defecto allow)Acción al coincidir con el prefijoOpciones: allow / prompt / forbidden (aplica el criterio restrictivo)
justification (opcional)Motivo o justificación de la reglaSe visualiza al solicitar confirmación o denegar accesos
match / not_match (opcional)Comprobaciones del comportamiento de la reglaValidadas de forma automática por Codex al cargar el archivo

Prioridades de la variable decision (se aplica el criterio más restrictivo):

Valor de decisionEfecto
allowEjecuta el comando fuera del sandbox directamente sin preguntar
promptSolicita confirmación en pantalla en cada coincidencia
forbiddenDeniega la ejecución bloqueando el proceso sin preguntar

Reinicia Codex para aplicar cambios tras editar archivos .rules. Ten en cuenta que si autorizas de forma manual un comando en la interfaz interactiva de Codex (TUI), se guardará automáticamente en ~/.codex/rules/default.rules; el archivo suele crecer de forma desatendida por el uso.

Análisis seguro: los comandos compuestos se desglosan antes de evaluarse

Esta protección detallada en el artículo 15 es clave. Ante cadenas unificadas en una sola línea como git add . && rm -rf /, Codex las analizará con tree-sitter para desglosarlas en instrucciones individuales y aplicar el criterio restrictivo:

text
["bash", "-lc", "git add . && rm -rf /"]

Se analizan por separado:

text
["git", "add", "."]
["rm", "-rf", "/"]

Aquí radica la protección: aunque autorices git add, la instrucción rm -rf / será interceptada de forma aislada, cancelando la secuencia. Evita el riesgo de camuflar comandos peligrosos en líneas combinadas.

Ten en cuenta que esta segmentación se limita a secuencias de comandos lineales y limpias. El uso de redirecciones (>), expansiones de variables ($(...)), asignaciones locales (FOO=bar) o caracteres comodín (*) impedirá la segmentación de Codex, evaluando la línea de forma global como una llamada simple bash -lc. Adopta políticas prudentes ante secuencias complejas.

Comprobar las reglas con execpolicy check

Evita fallos de sintaxis en producción: valida el comportamiento del archivo de reglas ejecutando codex execpolicy check:

bash
codex execpolicy check --pretty \
  --rules ~/.codex/rules/default.rules \
  -- gh pr view 7888 --json title,body,comments

Devuelve un reporte en formato JSON con la decisión final y las reglas coincidentes (incluyendo el parámetro justification). Se recomienda comprobar los comandos permitidos y prohibidos antes de reiniciar Codex para evitar falsos positivos que bloqueen tareas habituales (como invalidar accesos a git log por un patrón mal diseñado).

💡 Resumen en una frase: Declara reglas mediante prefix_rule en archivos .rules para regular accesos de comandos; las secuencias compuestas se desglosan por seguridad, y puedes depurar los filtros ejecutando codex execpolicy check antes de reiniciar.


03 Eventos de ciclo de vida para los Hooks

Los Hooks se vinculan a momentos específicos del ciclo de vida de Codex, definidos en la documentación como eventos (events). Identificar el momento de ejecución es el paso inicial para su configuración.

El ciclo de desarrollo de Codex (analizado en el artículo 02) sigue la secuencia "pensar → actuar → observar". Los eventos se distribuyen a lo largo de este bucle. Visualiza la posición de los eventos en este esquema:

Ciclo de vida de los eventos de Hooks en Codex

Esquema: El inicio de la conversación activa SessionStart, tu consulta envía UserPromptSubmit, y arranca el bucle de herramientas: cada llamada se rodea de PreToolUse y PostToolUse, finalizando la respuesta en Stop. Vincula tus scripts al evento de la fase que deseas automatizar.

Además de los eventos secundarios (como compactación de contexto PreCompact/PostCompact o permisos PermissionRequest), los siguientes cuatro eventos cubren la mayoría de las necesidades prácticas:

EventoActivaciónCasos de uso típicos
PreToolUseAntes de invocar una herramientaInterceptar comandos de riesgo o reescribir llamadas (admite bloqueo)
PostToolUseDespués de que la herramienta devuelva datosFormateo automático de archivos o ejecución de linter
StopAl finalizar el turno de respuestaForzar una revisión adicional (p. ej. corregir pruebas que sigan fallando)
SessionStartAl inicializar o restaurar la sesiónAñadir contexto del proyecto (p. ej. últimos commits)

Nota sobre los prefijos Pre y Post: Pre evalúa el estado previo, permitiendo bloquear la ejecución; Post se dispara posteriormente, cuando la herramienta ya ha terminado, permitiendo únicamente acciones de auditoría o formateo posterior.

Puntos de anclaje de Hooks

Esquema: Los eventos se anclan en hitos fijos de la sesión: inicio, llamadas a herramientas (antes/después) y cierre. El script asignado se disparará automáticamente al pasar por ese punto.

Diferencia de comportamiento con Claude Code: declarar decision: "block" en el evento Stop en Codex no cancela la respuesta; al contrario, indica al modelo "continúa con otro turno", insertando el parámetro reason como una consulta de usuario adicional. En PostToolUse, block no revoca la ejecución terminada, sino que devuelve la traza como feedback para forzar otra iteración. El bloqueo en estos eventos actúa como reintento o reenvío, no como denegación.

💡 Resumen en una frase: Vincula los Hooks a eventos del ciclo de vida; prioriza PreToolUse (antes, bloquea), PostToolUse (después, audita), Stop (fin del turno, fuerza reintento) y SessionStart (inicio); ten en cuenta el comportamiento específico de block en Codex.


04 Directorios de configuración and el parámetro matcher

Archivos de configuración de Hooks

Puedes configurar Hooks mediante archivos individuales hooks.json o declarándolos bajo la sección [hooks] en config.toml. La especificación detalla las cuatro ubicaciones estándar:

ArchivoÁmbito de aplicaciónCompartido en Git
~/.codex/hooks.jsonGlobal (todos tus proyectos)No (exclusivo de tu máquina local)
~/.codex/config.tomlGlobal (todos tus proyectos)No
<repo>/.codex/hooks.jsonLocal (repositorio activo) (incluido en Git)
<repo>/.codex/config.tomlLocal (repositorio activo)

La lógica coincide con el artículo 15: las automatizaciones del proyecto (como formatear al editar) se definen en la carpeta .codex/ local para Git; las preferencias personales se configuran en el directorio de usuario ~/.codex/. Detalles a considerar:

  • Los Hooks de diferentes niveles se acumulan: los perfiles de configuración no se sobrescriben, sino que ejecutan todos los scripts coincidentes de forma agregada.
  • Evita duplicar formatos: no declares hooks.json e inline [hooks] en el mismo nivel; aunque Codex los unifique, mostrará una advertencia al iniciar.
  • Los Hooks locales exigen autorización: solo se cargarán si confirmas confiar en la carpeta del repositorio .codex/ (sección 05); de lo contrario, solo se ejecutarán los globales de usuario.

Sintaxis de configuración

Ejemplo mínimo para ejecutar un script tras cada llamada del comando Bash (PostToolUse) en .codex/hooks.json:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use.py\"",
            "timeout": 30,
            "statusMessage": "Reviewing Bash output"
          }
        ]
      }
    ]
  }
}

Desglose del bloque JSON:

  1. PostToolUse: el evento de ciclo de vida asociado (después de ejecutar herramientas).
  2. matcher: "Bash": limita la ejecución a una herramienta específica (solo el intérprete Bash).
  3. hooks interno: define el comando a ejecutar (type: "command" y la ruta de llamada).

Pautas críticas de configuración:

  • timeout se define en segundos, no en milisegundos; el valor por defecto es 600 segundos si se omite.
  • Solo se admite type: "command" actualmente; los tipos prompt, agent o llamadas con async: true se ignoran en esta versión.
  • Los Hooks coincidentes se ejecutan en paralelo: declarar un interceptor en PreToolUse no impedirá que otros scripts asociados al mismo evento se inicien simultáneamente. A diferencia de Claude Code, no asumas secuencialidad.
  • El directorio activo es el cwd de la sesión. Evita declarar rutas relativas (.codex/hooks/...), ya que Codex puede iniciarse desde subcarpetas. Utiliza el comando de Git $(git rev-parse --show-toplevel) para resolver rutas absolutas.
  • Compatibilidad con Windows: añade la clave command_windows (o commandWindows en TOML) para declarar la llamada del sistema alternativa.

⚠️ Diferencias con Claude Code: timeout usa segundos (no milisegundos), no se admite la variable $CLAUDE_PROJECT_DIR (sustitúyela por la raíz de Git) y no existe la variable de apagado rápido disableAllHooks (usa [features] hooks = false en config.toml para desactivarlos).

Equivalente en formato TOML en config.toml:

toml
[[hooks.PostToolUse]]
matcher = "^Bash$"

[[hooks.PostToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use.py"'
timeout = 30
statusMessage = "Reviewing Bash output"

matcher: limitar el ámbito de ejecución

El parámetro matcher define la precisión de la llamada: si se omite, el Hook se ejecutará en cada disparo del evento; si se declara, limita la llamada a coincidencias específicas.

Analogía: El ajuste de sensibilidad del sensor de movimiento. Si el sensor de movimiento detecta actividad en todo el rellano, se encenderá cuando los vecinos pasen por sus puertas, malgastando energía. Debes ajustar el área de detección para cubrir exclusivamente tu puerta. matcher delimita esta área.

En Codex, matcher es una expresión regular (regex) que evalúa el nombre de la herramienta en eventos de ejecución (PreToolUse/PostToolUse). Formatos admitidos:

Valor de matcherCoincidenciaEjemplo
"Bash"Herramienta BashSe activa únicamente al ejecutar comandos en terminal
"^apply_patch$"Coincidencia exacta por regexSe activa únicamente al modificar archivos locales
"Edit|Write"Alias para edición de archivos (| indica operador lógico OR)Se dispara tras operaciones de guardado o edición
"mcp__filesystem__.*"Coincidencia por patrón de servidores MCPFiltra herramientas de un servidor MCP específico
* / "" / OmitidoCualquier herramientaSe dispara en cada ejecución del evento

Errores comunes a evitar:

  • La herramienta de edición es apply_patch, no Edit o Write. Aunque matcher acepta Edit y Write como alias simplificados, los datos JSON de stdin reportarán siempre tool_name: "apply_patch". Valida esa cadena en tus scripts.
  • No todos los eventos admiten matcher. Los eventos UserPromptSubmit y Stop ignoran este parámetro al carecer de herramientas asociadas; se ejecutarán siempre. Sin embargo, SubagentStop sí lo admite (evalúa agent_type). En SessionStart, matcher evalúa el tipo de inicialización de la sesión (startup/resume/clear/compact).
  • PreToolUse tiene límites de intercepción. La documentación detalla que actúa como control preventivo, no como restricción infalible: intercepta llamadas de terminal sencillas, apply_patch y herramientas MCP, pero no scripts complejos en unified_exec o búsquedas WebSearch. No confíes la seguridad del sistema únicamente a los ganchos PreToolUse.

💡 Resumen en una frase: Configura los Hooks en hooks.json o config.toml definiendo el evento, el matcher y la acción; recuerda las especificaciones de Codex: timeout en segundos, la edición se identifica como apply_patch, matcher usa regex y las rutas locales se resuelven con la raíz de Git.


05 Directiva de confianza: por qué los Hooks nuevos no se ejecutan

Esta es la diferencia principal con Claude Code: si un Hook configurado correctamente no se dispara, se debe a la directiva de seguridad de Codex, que no lo autoriza por defecto.

Los Hooks ejecutan scripts locales con tus permisos de usuario, pudiendo alterar archivos o transmitir datos. Si Codex ejecutase de forma desatendida los Hooks incluidos en un repositorio clonado, estarías expuesto a la ejecución de código arbitrario. Por ello, exige una auditoría y confirmación manual.

Analogía: La alerta de permisos de una aplicación móvil. Al instalar una app nueva, si esta solicita acceso a la cámara o notificaciones, el sistema operativo no las concede por defecto; te muestra una alerta interactiva. Si la rechazas, la función se bloquea. La seguridad de Codex sigue el mismo principio: los Hooks locales no administrados se ignoran hasta que confirmes explícitamente confiar en ellos.

Pautas del sistema de confianza:

  • Codex registra la autorización en base al hash del archivo de definición. Los Hooks nuevos o modificados se marcan como pendientes de revisión y se omiten hasta ser autorizados. Cambiar un solo carácter altera el hash e invalida la confianza.
  • Ejecuta /hooks en el chat para auditar orígenes, aprobar cambios o desactivar automatizaciones locales.
  • Si existen perfiles pendientes de revisión al arrancar la sesión, Codex mostrará una advertencia sugiriendo ejecutar /hooks.

Flujo tras configurar un Hook: edita el archivo → inicia Codex → ejecuta /hooks → confirma las líneas del script → autoriza su ejecución. Ignorar este paso impedirá el disparo de la automatización aunque la sintaxis sea correcta.

text
/hooks

Resultado esperado: se despliega el menú de auditoría detallando los estados: pendiente (review), de confianza (trusted) o administrado (managed). Los Hooks administrados (empresa o directivas del sistema) se autorizan por políticas corporativas y no pueden desactivarse localmente.

Para entornos automatizados de CI/CD donde la auditoría se resuelve de forma externa, inicia la sesión con el parámetro --dangerously-bypass-hook-trust para omitir la confirmación manual. Como indica el prefijo dangerously, evita su uso en tu máquina local de desarrollo.

⚠️ Pauta de seguridad del artículo 16: inspecciona siempre las líneas del comando en /hooks antes de autorizarlo; evita incorporar scripts desconocidos a ciegas. La plataforma expone la advertencia, pero la decisión de conceder permisos depende de ti.

💡 Resumen en una frase: Codex exige confirmación manual para los Hooks locales; cualquier cambio invalida su hash requiriendo volver a ejecutar /hooks para autorizarlo. Es la causa habitual de fallos de ejecución en configuraciones iniciales.


06 Canal de comunicación del Hook: stdin, códigos de salida y stdout

Esta sección describe los principios de comunicación de datos de los Hooks (relacionados con el control de entradas y salidas del artículo 16).

El flujo de datos consta de tres vías: Codex transmite el contexto del evento por stdin al script → el script procesa la información → el script indica a Codex la respuesta mediante códigos de salida y stdout.

1. Entrada: datos JSON a través de stdin

Al dispararse el evento, Codex envía las variables del contexto en formato JSON por stdin. Campos comunes disponible en cualquier Hook:

CampoDefinición
session_idIdentificador de la sesión activa
cwdDirectorio de trabajo de la conversación
hook_event_nameNombre del evento disparado
transcript_pathRuta del archivo de registros de la sesión (puede ser null)
modelSlug del modelo activo (útil para condicionales por modelo)
permission_modeModo de permisos de la sesión activa

Los eventos de herramientas incorporan además tool_name ("Bash", "apply_patch") y tool_input (parámetros de entrada, conteniendo el comando en tool_input.command para Bash). Ejemplo de datos recibidos por PreToolUse antes de ejecutar una terminal:

json
{
  "session_id": "abc123",
  "cwd": "/Users/sarah/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "rm -rf /tmp/x"
  }
}

Toda la información del proceso se expone en la estructura. Tu script puede analizar tool_input.command para denegar o modificar la llamada según tus reglas.

2. Códigos de salida: instrucciones básicas

El script reporta el resultado de su análisis a través del código de salida (exit code):

Código de salidaSignificadoEfecto
0CorrectoContinúa el flujo de la sesión; la ausencia de salida equivale a éxito
2Señal especialBloqueo o reintento de turno según el evento (detallado abajo)
OtrosNo definido formalmenteVaría según el contexto

El código exit 2 es crítico, variando su lógica según el evento a diferencia de Claude Code:

  • En PreToolUse / UserPromptSubmit: retornar exit 2 volcando el motivo en stderr bloquea la llamada o consulta.
  • En PostToolUse / Stop / SubagentStop: retornar exit 2 no cancela el proceso (ya ha finalizado), sino que reenvía el texto de stderr como feedback al modelo para forzar una corrección o reintento (sección 03).

En definitiva: solo los eventos Pre permiten cancelar operaciones; en eventos Post o Stop, exit 2 actúa como feedback corrector sin deshacer los cambios ya realizados.

3. Salida de datos: control preciso mediante stdout JSON

La salida estándar (stdout) permite definir comportamientos avanzados cuando el código de salida es 0. Formatos principales:

Denegación en PreToolUse: retorna permissionDecision: "deny":

json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "El comando interactúa con la base de datos de producción, bloqueado por seguridad"
  }
}

Codex admite además el formato antiguo {"decision": "block", "reason": "..."}; ambos se procesan correctamente.

Inyección de datos en SessionStart: retorna additionalContext para añadir directrices en la ventana de contexto:

json
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Lee las directrices de código del repositorio antes de editar archivos."
  }
}

Consideraciones sobre la salida de datos en Codex:

  • Texto plano en PreToolUse por stdout se ignora: para añadir contexto usa la clave JSON additionalContext, y para bloquear usa permissionDecision o exit 2; usar echo simple no tendrá efecto.
  • En SessionStart y UserPromptSubmit, el texto plano en stdout se procesa como contexto directamente; sin embargo, Stop y SubagentStop exigen formato JSON, rechazando texto plano.
  • PreToolUse no admite claves como continue o stopReason: si las incluyes, Codex reportará un fallo de ejecución del Hook pero continuará con la llamada del comando; no confíes en continue: false para bloqueos en este evento.

💡 Resumen en una frase: La comunicación se realiza mediante JSON en stdin, códigos de salida y JSON en stdout; recuerda que exit 2 bloquea en eventos Pre e inicia reintentos de turno en Post/Stop, y que el texto plano por stdout en PreToolUse se descarta.


07 Ejemplos prácticos listos para usar

Presentamos dos configuraciones de Hooks habituales listas para integrar en tus proyectos.

Ejemplo 1: Formateador automático al editar (PostToolUse)

Es el script que soluciona los olvidos de formato del inicio del artículo; 强烈建议每个项目都配上

Primer paso: guarda las instrucciones de formateo en .codex/hooks/format.py (lee stdin, extrae la ruta del archivo y llama al formateador). Estructura básica:

python
#!/usr/bin/env python3
import json, subprocess, sys

data = json.load(sys.stdin)
# apply_patch 的 tool_input.command 里是补丁内容;实际项目里
# 通常直接对整个工作区跑格式化,简单稳妥:
subprocess.run(["ruff", "format", "."])

Segundo paso: registra el script en .codex/hooks.json vinculándolo al evento PostToolUse de apply_patch (usando el alias Edit|Write o apply_patch en el matcher):

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/format.py\"",
            "timeout": 30,
            "statusMessage": "Formateando archivos modificados"
          }
        ]
      }
    ]
  }
}

Tercer paso (obligatorio): inicia Codex y ejecuta /hooks para autorizar el script (sección 05). A partir de ese momento, el formateo se disparará tras cada guardado. Puedes sustituir ruff format por prettier --write ., gofmt -w . o black . según tu lenguaje.

Ejemplo 2: Interceptar comandos peligrosos (PreToolUse con script)

Usa la intercepción con exit 2. Es recomendable delegar la lógica en un script externo para mayor claridad:

Primer paso: guarda el script en .codex/hooks/block-dangerous.py:

python
#!/usr/bin/env python3
import json, sys

data = json.load(sys.stdin)
command = data.get("tool_input", {}).get("command", "")

if "rm -rf" in command:
    print("Bloqueado: se ha detectado y cancelado un comando rm -rf", file=sys.stderr)  # Envía el motivo por stderr
    sys.exit(2)                                                                        # exit 2 detiene el proceso

sys.exit(0)  # Permite continuar el flujo habitual para otros comandos

Segundo paso: registra la llamada en .codex/hooks.json vinculándola al evento PreToolUse de Bash:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/block-dangerous.py\"",
            "statusMessage": "Analizando comando Bash"
          }
        ]
      }
    ]
  }
}

Tercer paso: autoriza el script en /hooks. Si Codex intenta ejecutar comandos de consola con rm -rf, la automatización forzará la salida exit 2, cancelando la acción y reportando el motivo.

⚠️ Nota de diseño: tanto las reglas como los Hooks permiten denegar comandos. Las reglas con forbidden son más ligeras al evitar scripts, mientras que los Hooks ofrecen mayor flexibilidad para analizar variables complejas antes de decidir. Usa reglas para prefijos directos, y Hooks para condicionales avanzados. Evita duplicar la misma restricción en ambos sistemas.

Comparativa de ambos flujos:

DimensiónEjemplo 1: Formateador automáticoEjemplo 2: Interceptor de seguridad
Evento de ciclo de vidaPostToolUse (posterior)PreToolUse (previo)
Parametro matcherEdit|Write (equivalente a apply_patch)Bash
Funcionamiento lógicoFormatea tras guardar, no cancela la sesiónRetorna exit 2 para bloquear la acción
Nivel de riesgoBajo (recomendado en cualquier repositorio)Medio (errores de código pueden bloquear tareas legítimas)
Alternativa con reglasNo (las reglas solo evalúan la autorización de comandos) (usa reglas forbidden para bloqueos de prefijos simples)

💡 Resumen en una frase: Configura Hooks de bajo riesgo (PostToolUse para formateo) o interceptores avanzados (PreToolUse con exit 2); utiliza la raíz de Git para resolver rutas absolutas y recuerda autorizar las tareas en /hooks tras editarlas.


08 Práctica: crear y ejecutar un Hook básico en 5 minutos

La teoría sin práctica no sirve. Configuraremos una automatización segura para verificar el flujo: guardar en un archivo de registros local cada comando Bash ejecutado por Codex.

Nota de plataforma: el script usa Python. En Windows PowerShell, sustituye python3 por py -3 o utiliza el parámetro command_windows en la configuración.

Primer paso: Crear el script y la configuración en una carpeta de pruebas

Crea una carpeta de pruebas y añade el script .codex/hooks/log-bash.py:

python
#!/usr/bin/env python3
import json, sys, os

data = json.load(sys.stdin)
command = data.get("tool_input", {}).get("command", "")
log = os.path.expanduser("~/codex-bash-log.txt")
with open(log, "a") as f:
    f.write(command + "\n")

Y crea el archivo .codex/hooks.json:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/log-bash.py\"",
            "statusMessage": "Registrando comando Bash"
          }
        ]
      }
    ]
  }
}

Nota: al usar la raíz de Git para resolver la ruta, inicializa el directorio con git init antes de probar el flujo, o sustitúyela por una ruta absoluta estática.

Segundo paso: Iniciar Codex y autorizar el Hook

bash
codex

Ejecuta en la consola de chat:

text
/hooks

Resultado esperado: el menú muestra el Hook PostToolUse bajo el estado pendiente (review). Selecciónalo para revisar el comando y márcalo como de confianza. Su cambio de estado confirma que la automatización está activa.

Tercer paso: Ejecutar un comando para disparar el Hook

Solicita una tarea sencilla en el chat:

text
muestra los archivos del directorio activo usando ls

Codex ejecutará ls mediante la terminal, disparando el Hook PostToolUse en segundo plano de forma silenciosa (sin mostrar alertas en la consola).

Cuarto paso: Validar la escritura en el archivo de registros

Abre una consola del sistema independiente y comprueba el fichero:

bash
cat ~/codex-bash-log.txt

Resultado esperado: el archivo contiene la línea del comando ls (y los comandos de terminal anteriores). Esto confirma que el script se dispara de forma automática tras cada llamada a la terminal.

Quinto paso: Limpieza (opcional)

Para desinstalarlo, elimina la carpeta de pruebas y el archivo de registros local ~/codex-bash-log.txt.

Probar esta secuencia practica el ciclo completo: "configuración → autorización interactiva → disparo del evento → validación". Cualquier Hook posterior se rige por las mismas directrices, variando únicamente el script y el matcher.

💡 Resumen en una frase: Prueba el flujo con tareas de bajo riesgo (como registrar comandos Bash en archivos de texto) para comprender el sistema de firmas y auditoría interactiva de /hooks en Codex.


09 Pautas de depuración ante fallos de ejecución

Si un Hook no responde, sigue este esquema de diagnóstico:

IncidenciaOrigen probable / Solución
El Hook no se ejecutaComprueba si está autorizado en /hooks (causa habitual en Codex, sección 05); ② Modificar el script altera el hash e invalida la confianza; ③ Revisa si has asignado mal el evento o el parámetro matcher
El Hook no figura en /hooks① Sintaxis JSON incorrecta (no se admiten comas al final ni comentarios); ② Ubicación o nombre de archivo erróneo (hooks.json o config.toml); ③ Conflicto por tener ambos formatos en la misma carpeta; ④ Reinicia Codex tras editar
Fallo command not found o script ausenteResolución de rutas incorrecta. El directorio activo es el cwd de la sesión, conviene usar la raíz de Git $(git rev-parse --show-toplevel) para definir rutas absolutas
El bloqueo no funciona① Asignación de evento errónea (los bloqueos exigen PreToolUse, PostToolUse ocurre tarde); ② PreToolUse no filtra scripts complejos en unified_exec o búsquedas WebSearch (sección 04); ③ El bloqueo exige exit 2 o la clave permissionDecision: "deny", descartando texto plano por stdout
Cancelación por límite de tiempoEl parámetro timeout usa segundos (por defecto 600), no milisegundos; incrementa el valor en tareas de larga duración

Herramientas recomendadas para depuración:

1. Pruebas unitarias en consola local: alimenta tu script con datos de prueba simulados para comprobar su código de salida:

bash
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /tmp/x"}}' | python3 .codex/hooks/block-dangerous.py
echo $?   # Código de salida: el script interceptor debe retornar 2

Es la mejor práctica para validar los scripts aisladamente antes de registrarlos en el manifiesto de Codex.

2. Validación con codex execpolicy check: audita los filtros de tus archivos de reglas para prever las coincidencias semánticas.

Para apagar todas las automatizaciones de la sesión, edita config.toml (Codex no cuenta con la variable disableAllHooks de Claude Code):

toml
[features]
hooks = false

💡 Resumen en una frase: Ante fallos, verifica primero si el Hook está autorizado en /hooks; comprueba después las rutas absolutas y la asignación del matcher; recuerda que interceptar llamadas exige PreToolUse con la salida exit 2, y depura reglas con execpolicy check.


10 Resumen

En este artículo hemos analizado las reglas y los Hooks: filtros y disparadores que aseguran el cumplimiento de las directrices del proyecto y transforman las peticiones sugeridas en AGENTS.md en automatizaciones garantizadas.

Repasemos las pautas consolidadas:

ObjetivoCanal / HerramientaNoción clave
Autorizar o bloquear un comandoReglas prefix_ruleCriterio restrictivo: allow/prompt/forbidden. Depura con execpolicy check
Vincular automatizaciones al ciclo de vidaEventos del sistemaPre bloquea antes; Post formatea después; Stop fuerza reintentos; SessionStart inicia la sesión
Registrar un HookFicheros hooks.json o config.tomlEstructura de tres niveles: evento, matcher (regex) y acción. timeout en segundos
Habilitar la automatizaciónMenú interactivo /hooksExclusivo de Codex: los Hooks no administrados exigen autorización manual tras cada edición
Comunicar el script con CodexTuberías stdin / stdout y salidaexit 2 bloquea en eventos Pre e inicia reintentos de turno en Post/Stop
Depuración de incidenciasSecuencia de diagnósticoComprueba primero el estado de confianza en /hooks; revisa después rutas absolutas, regex y eventos

Ahora deberías ser capaz de: elegir entre reglas y Hooks y entender por qué garantizan la automatización frente a AGENTS.md; definir reglas prefix_rule y validarlas con execpolicy check; identificar la posición de los eventos PreToolUse, PostToolUse, Stop y SessionStart en el ciclo de la sesión; estructurar un Hook con matcher en hooks.json y autorizarlo en /hooks; y gestionar la comunicación de datos considerando las particularidades de Codex. Ya puedes automatizar tareas repetitivas de formateo o controles de seguridad de forma predecible.

💡 Resumen en una frase: Las reglas actúan como filtros y los Hooks como disparadores para forzar el cumplimiento de las directrices del repositorio; ten en cuenta la directiva de confianza de /hooks, el paralelismo, el tiempo en segundos y la nomenclatura apply_patch de Codex.


El próximo artículo [25 · Aislamiento en paralelo con Worktrees]: hasta ahora hemos analizado el uso de Codex sobre tareas secuenciales unitarias. Al acelerar el desarrollo, querrás ejecutar múltiples tareas en paralelo (p. ej. corregir un fallo y desarrollar una funcionalidad simultáneamente) sin interferir en los mismos archivos. Abrir dos chats sobre la misma carpeta local provocará colisiones en el código. En el siguiente capítulo explicaremos cómo aprovechar Git worktree para asignar áreas de trabajo independientes por tarea y habilitar el paralelismo real de Codex.


Lecturas recomendadas