← SCRAM AI Lab

Claude Code

Hooks: el patrón que sustituye 80% de validaciones manuales

PreToolUse y PostToolUse son el lugar correcto para bloquear commits a main, formatear código, ejecutar tests y validar comandos peligrosos. Sin pedirle permiso al modelo.

May 21, 2026

10 lecturas

La diferencia entre pedirle al modelo y forzar al harness

Llevas tres semanas escribiendo "no hagas commits directos a main" en CLAUDE.md y el modelo lo respeta el 95% del tiempo. El otro 5% es el que rompe producción. La solución no es escribirlo más fuerte; es mover la validación fuera del modelo. Los hooks de Claude Code se ejecutan en el harness, no en el LLM: no se "olvidan", no se distraen, no negocian. Si el matcher dispara, el hook corre. Punto.

PreToolUse y PostToolUse: dónde vive la lógica

  • PreToolUse: corre antes de que la herramienta se ejecute. Si retornas exit code distinto de cero, la llamada se cancela. Aquí van validaciones bloqueantes: comandos peligrosos, edits a archivos protegidos, commits a ramas críticas.
  • PostToolUse: corre después de éxito. Aquí van efectos secundarios: formatear código tras un Edit, regenerar tipos tras tocar el schema, correr tests, notificar a Slack.
  • Stop, SessionStart, UserPromptSubmit: más nichos, pero útiles para auditoría e inicialización.

Configuración real

Esto vive en .claude/settings.json (proyecto) o ~/.claude/settings.json (global). El matcher filtra por nombre de herramienta:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": "node ~/.claude/hooks/block-dangerous-bash.js"
        }]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "node ~/.claude/hooks/block-protected-files.js"
        }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "node ~/.claude/hooks/prettier-format.js"
        }]
      }
    ]
  }
}

El hook que bloquea commits a main

// ~/.claude/hooks/block-dangerous-bash.js
const input = JSON.parse(require("fs").readFileSync(0, "utf-8"));
const cmd = input.tool_input?.command ?? "";

const dangerous = [
  /git\s+push\s+.*\s(main|master)\b/,
  /git\s+reset\s+--hard/,
  /rm\s+-rf\s+\//,
  /DROP\s+TABLE/i,
];

for (const re of dangerous) {
  if (re.test(cmd)) {
    console.error(`Blocked: command matches ${re}. If intentional, run in shell directly.`);
    process.exit(2); // exit code 2 = block + show stderr to model
  }
}
process.exit(0);

El exit code 2 es la convención: bloquea la herramienta y pasa el stderr al modelo para que entienda por qué falló. El modelo entonces busca otra forma de cumplir la tarea, no se queda peleando con el harness.

Hook vs skill vs slash command

  • Hook: validación o efecto automático que debe correr SIEMPRE. No negociable. No requiere contexto del usuario.
  • Skill: procedimiento con lógica condicional que el modelo invoca cuando el contexto lo activa. Negociable, contextual.
  • Slash command: shortcut explícito que el usuario invoca a mano. Cero ambigüedad, cero contexto.

Si te encuentras escribiendo "siempre debes hacer X antes de Y" en un skill, eso es un hook disfrazado. Muévelo.

Casos donde el ROI es brutal

  • Formateo automático: prettier/eslint en PostToolUse tras cada Edit. Ahorra revisiones de diffs ruidosos.
  • Bloqueo de secrets: PreToolUse en Write/Edit que rechaza si detecta patrones tipo sk-, AKIA, ghp_.
  • Tests incrementales: PostToolUse que corre vitest related solo sobre archivos tocados.
  • Auditoría: log de toda llamada Bash a Loki para forense post-incident.

El anti-patrón: hooks lentos

Si tu hook tarda 4 segundos, lo pagas en cada Edit. Multiplica por 80 edits en una sesión y son 5 minutos perdidos. Los hooks deben ser sub-segundo: validación pura, sin red, sin builds. Si necesitas algo pesado, dispáralo en background y deja que falle async (Slack, métricas), no bloquees la conversación.

Cuenta tus hooks. Si tienes menos de tres, probablemente le estás pidiendo al modelo cosas que el harness debería hacer solo. ¿Cuál validación repites en cada CLAUDE.md y nunca codificaste?

hooks
claude-code
automatizacion
← Volver a SCRAM AI Lab