Saltar al contenido
Lección 5 de 14

Hooks — Automatización Basada en Eventos

9 min read

Qué Son los Hooks

Los hooks son scripts o comandos que se ejecutan automáticamente en respuesta a eventos específicos durante una sesión de Claude Code. Cuando Claude lee un archivo, escribe código, ejecuta un comando o finaliza una tarea, los hooks te permiten interceptar esos eventos y ejecutar tu propia lógica -- validando entrada, formateando salida, bloqueando operaciones peligrosas o activando procesos posteriores.

Piensa en los hooks como oyentes de eventos para tu flujo de trabajo de desarrollo con IA. Igual que un pre-commit hook en git ejecuta tu linter antes de cada commit, un hook PreToolUse en Claude Code puede validar las entradas de herramientas antes de que Claude tome acción. La diferencia es que los hooks cubren un rango mucho más amplio de eventos y pueden hacer mucho más que simples verificaciones de pasa/falla.

Eventos de Hooks

Claude Code expone un conjunto rico de eventos a los que puedes conectarte. Los más comúnmente usados caen en cuatro categorías:

Eventos del ciclo de vida de herramientas:

  • PreToolUse -- se dispara antes de que Claude use cualquier herramienta (leer un archivo, escribir código, ejecutar un comando)
  • PostToolUse -- se dispara después de que una herramienta se completa, dándote acceso al resultado

Eventos de sesión:

  • SessionStart -- se dispara cuando comienza una nueva sesión de Claude Code
  • SessionEnd -- se dispara cuando se cierra una sesión
  • Stop -- se dispara cuando Claude termina de responder y está a punto de devolver el control
  • SubagentStop -- se dispara cuando un subagente completa su trabajo

Eventos de interacción del usuario:

  • UserPromptSubmit -- se dispara cuando el usuario envía un prompt, antes de que Claude lo procese
  • Notification -- se dispara cuando Claude envía una notificación

Eventos de contexto:

  • PreCompact -- se dispara antes de que Claude compacte la conversación, permitiéndote influir en lo que se preserva

Cada evento recibe datos de contexto relevantes: para eventos de herramientas, obtienes el nombre de la herramienta y sus entradas o salidas. Para eventos de sesión, obtienes metadatos de la sesión. Este contexto permite que tus hooks tomen decisiones informadas.

Tipos de Hooks

Hay cuatro tipos de hooks, cada uno adecuado para diferentes casos de uso:

command -- Ejecuta un comando de shell. El tipo más simple y común. Bueno para ejecutar linters, formateadores, validadores y scripts.

http -- Envía una solicitud HTTP a una URL de webhook. Usa esto para notificar servicios externos, activar pipelines de CI o registrar eventos en sistemas de monitoreo.

prompt -- Envía el contexto del evento a un modelo de IA para evaluación. El tipo más poderoso -- te permite crear reglas que son evaluadas por IA en lugar de simple coincidencia de patrones.

agent -- Lanza un subagente para manejar el evento. Usa esto para manejo complejo de eventos que requiere razonamiento de múltiples pasos.

Configuración

Los hooks se configuran en tu archivo de settings. Puedes establecerlos a nivel global (~/.claude/settings.json) o a nivel de proyecto (.claude/settings.json). Aquí está la estructura básica:

{
  "hooks": [
    {
      "event": "PreToolUse",
      "type": "command",
      "command": "node .claude/hooks/validate-tool.js",
      "matchers": ["Bash"]
    }
  ]
}

Cada definición de hook tiene:

  • event -- qué evento escuchar
  • type -- command, http, prompt o agent
  • command (o url, prompt, agent) -- qué ejecutar
  • matchers -- array opcional de nombres de herramientas para filtrar qué invocaciones de herramientas activan el hook

Matchers: Filtrando Qué Herramientas Activan Hooks

Los matchers te permiten apuntar a herramientas específicas para que tu hook no se dispare en cada llamada a herramienta. Sin matchers, un hook PreToolUse se dispara cada vez que Claude usa cualquier herramienta -- lo cual podría ser docenas de veces por sesión.

{
  "hooks": [
    {
      "event": "PreToolUse",
      "type": "command",
      "command": "node .claude/hooks/block-dangerous.js",
      "matchers": ["Bash"]
    },
    {
      "event": "PostToolUse",
      "type": "command",
      "command": "npx prettier --write",
      "matchers": ["Write"]
    }
  ]
}

En este ejemplo, el primer hook solo se dispara cuando Claude está a punto de ejecutar un comando de shell (herramienta Bash), y el segundo hook solo se dispara después de que Claude escribe un archivo (herramienta Write).

PreToolUse: Bloqueando Comandos Peligrosos

El caso de uso más popular para hooks es prevenir que Claude ejecute comandos que consideras peligrosos. Aquí hay un script que bloquea operaciones destructivas:

// Archivo: .claude/hooks/block-dangerous.js
// Lee la entrada de la herramienta desde stdin y bloquea comandos peligrosos

import { readFileSync } from "fs";

const input = JSON.parse(readFileSync("/dev/stdin", "utf-8"));
const command = input.tool_input?.command || "";

const blocked = [
  /rm\s+-rf\s+\//,           // Borrado recursivo desde la raiz
  /git\s+push\s+--force/,    // Force push
  /git\s+reset\s+--hard/,    // Hard reset
  /DROP\s+TABLE/i,           // SQL drop table
  /DROP\s+DATABASE/i,        // SQL drop database
  /:\(\)\{.*\|.*\}/,         // Fork bomb
];

for (const pattern of blocked) {
  if (pattern.test(command)) {
    // Salida JSON para bloquear la accion
    console.log(JSON.stringify({
      action: "block",
      message: `Comando peligroso bloqueado: ${command}`
    }));
    process.exit(0);
  }
}

// Permitir que el comando proceda
console.log(JSON.stringify({ action: "allow" }));

Cuando este hook bloquea un comando, Claude recibe el mensaje de bloqueo y puede informar al usuario o tomar un enfoque alternativo.

PostToolUse: Auto-Formateo Después de Escrituras

Después de que Claude escribe un archivo, podrías querer ejecutar automáticamente tu formateador para asegurar que el código coincida con el estilo de tu proyecto:

{
  "hooks": [
    {
      "event": "PostToolUse",
      "type": "command",
      "command": "node .claude/hooks/auto-format.js",
      "matchers": ["Write"]
    }
  ]
}
// Archivo: .claude/hooks/auto-format.js
import { readFileSync } from "fs";

const input = JSON.parse(readFileSync("/dev/stdin", "utf-8"));
const filePath = input.tool_input?.file_path || "";

// Solo formatear archivos de codigo fuente
const formattable = /\.(ts|tsx|js|jsx|css|json|md)$/;

if (formattable.test(filePath)) {
  // La salida le dice a Claude Code que ejecute el formateador
  console.log(JSON.stringify({
    action: "allow",
    commands: [`npx prettier --write "${filePath}"`]
  }));
} else {
  console.log(JSON.stringify({ action: "allow" }));
}

Esto asegura que cada archivo que Claude escribe sea automáticamente formateado, eliminando inconsistencias de estilo sin ninguna intervención manual.

Hook Stop: Ejecutando Verificaciones Cuando Claude Finaliza

El hook Stop se dispara cuando Claude completa una respuesta. Este es el lugar perfecto para ejecutar linting, verificación de tipos o suites de tests para validar el trabajo de Claude:

{
  "hooks": [
    {
      "event": "Stop",
      "type": "command",
      "command": "node .claude/hooks/post-check.js"
    }
  ]
}
// Archivo: .claude/hooks/post-check.js
// Ejecutar linter despues de que Claude termina de hacer cambios

import { readFileSync } from "fs";

const input = JSON.parse(readFileSync("/dev/stdin", "utf-8"));

// Verificar si algun archivo fue modificado en este turno
const filesModified = input.tool_results?.some(
  (r) => r.tool_name === "Write"
);

if (filesModified) {
  console.log(JSON.stringify({
    action: "allow",
    commands: ["npm run lint -- --quiet"]
  }));
} else {
  console.log(JSON.stringify({ action: "allow" }));
}

UserPromptSubmit: Validando Entrada

El hook UserPromptSubmit te permite inspeccionar y opcionalmente modificar los prompts del usuario antes de que Claude los procese. Esto es útil para hacer cumplir convenciones o agregar contexto automático:

{
  "hooks": [
    {
      "event": "UserPromptSubmit",
      "type": "command",
      "command": "node .claude/hooks/enrich-prompt.js"
    }
  ]
}

Podrías usar esto para agregar automáticamente contexto relevante, hacer cumplir convenciones de nombres en solicitudes o registrar prompts para fines de auditoría.

Prompt Hooks: Reglas Evaluadas por IA

Los prompt hooks son el tipo de hook más poderoso. En lugar de escribir lógica procedural, escribes una regla en lenguaje natural que es evaluada por un modelo de IA:

{
  "hooks": [
    {
      "event": "PreToolUse",
      "type": "prompt",
      "prompt": "Review this shell command for security risks. Block the command if it could delete data, modify system files, access the network in unexpected ways, or expose secrets. Allow the command if it is a standard development operation like running tests, building, or linting.",
      "matchers": ["Bash"]
    }
  ]
}

La IA evalúa la entrada de la herramienta contra tu regla y decide si permitir o bloquear. Esto es mucho más flexible que patrones regex -- puede entender contexto e intención, capturando casos límite que las reglas procedurales no detectarían.

Ejemplo Completo de Configuración de Hooks

Aquí hay un .claude/settings.json completo con múltiples hooks trabajando juntos:

{
  "hooks": [
    {
      "event": "PreToolUse",
      "type": "command",
      "command": "node .claude/hooks/block-dangerous.js",
      "matchers": ["Bash"]
    },
    {
      "event": "PostToolUse",
      "type": "command",
      "command": "node .claude/hooks/auto-format.js",
      "matchers": ["Write"]
    },
    {
      "event": "Stop",
      "type": "command",
      "command": "node .claude/hooks/run-lint.js"
    },
    {
      "event": "PreToolUse",
      "type": "prompt",
      "prompt": "Verify this file write does not overwrite test fixtures, migration files, or lock files without explicit user intent.",
      "matchers": ["Write"]
    }
  ]
}

Esta configuración bloquea comandos de shell peligrosos, auto-formatea archivos escritos, ejecuta el linter después de cada respuesta y usa IA para evaluar escrituras de archivos contra una política. Juntos, estos hooks crean una red de seguridad integral alrededor de las acciones de Claude.

Respuestas de Hooks

Los hooks se comunican de vuelta a Claude Code a través de salida JSON:

  • {"action": "allow"} -- permite que la operación proceda
  • {"action": "block", "message": "razon"} -- detiene la operación y muestra el mensaje
  • {"action": "allow", "commands": ["cmd1", "cmd2"]} -- permite y ejecuta comandos de seguimiento

Para hooks PreToolUse, también puedes modificar la entrada de la herramienta antes de que se ejecute, dándote la capacidad de sanitizar o transformar las operaciones previstas de Claude.

Mejores Prácticas

Mantén los hooks rápidos. Cada hook agrega latencia al flujo de trabajo de Claude. Los hooks de comandos de shell deben completarse en menos de un segundo. Si necesitas procesamiento complejo, considera ejecutarlo de forma asíncrona o moverlo a un hook PostToolUse o Stop donde la latencia es menos notable.

Usa matchers agresivamente. Un hook que se dispara en cada llamada a herramienta se acumula rápidamente. Apunta solo a las herramientas donde tu hook agrega valor.

Prueba los hooks exhaustivamente antes de desplegarlos a tu equipo. Un hook PreToolUse con bugs puede bloquear operaciones legítimas y frustrar a los usuarios. Comienza ejecutando tu script de hook manualmente con entrada de ejemplo para verificar que maneja todos los casos correctamente.

Prueba este ejercicio: agrega un hook PreToolUse que bloquee cualquier comando Bash que contenga sudo. Agrega un hook PostToolUse que registre cada escritura de archivo en un archivo local .claude/audit.log con una marca de tiempo. Ejecuta una sesión de Claude Code con estos hooks activos y verifica que funcionen como se espera. Luego comparte la configuración con tu equipo haciendo commit del .claude/settings.json y los scripts de hooks en el control de versiones.