Configura hooks de eventos para aplicar políticas, automatizar lint e inyectar contexto, sin tocar el código del agente.
Los hooks son scripts externos ejecutados por el harness en momentos específicos del ciclo de vida del agente. Reciben metadatos del evento vía stdin y pueden influir en el comportamiento del harness mediante el exit code y el output.
La gran ventaja: agregas comportamiento sin modificar el prompt ni el agente. Las políticas quedan en scripts versionados en el repositorio y se aplican automáticamente a todo el equipo.
Se activa al iniciar una nueva sesión. El stdout se inyecta como mensaje inicial en el contexto. Ideal para cargar el estado del proyecto, la rama actual y las tareas pendientes.
Se activa antes de cada herramienta. Exit 0 = permite. Un Exit distinto de cero = bloquea la herramienta. El mensaje de error en stderr se devuelve al agente.
Se activa después de que cada herramienta devuelve un resultado. El stdout se inyecta en el contexto. Ideal para ejecutar lint automático, auditorías y métricas de uso.
Se activa cuando el agente termina. Ideal para tareas de limpieza, notificaciones de finalización, informes de sesión y persistencia de memoria.
Los hooks se configuran en la clave hooks de settings.json. Cada entrada define: el evento, un matcher de herramienta (opcional) y el comando de shell que se ejecutará.
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/session-start.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/block-dangerous.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/lint.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/session-end.sh"
}
]
}
]
}
}
Se aplica a todos los proyectos. Útil para políticas personales: bloqueo de comandos destructivos, preferencias de lint.
Específico del proyecto. Se registra en el repositorio con un commit — todo el equipo hereda las políticas automáticamente.
PostToolUse en Write/Edit ejecuta eslint/prettier. El resultado se inyecta en el contexto: el agente ve los errores y los corrige automáticamente.
#!/bin/bash # .claude/hooks/lint.sh
FILE=$(cat /dev/stdin | jq -r '.tool_input.file_path // empty')
if [[ "$FILE" == *.ts || "$FILE" == *.tsx ]]; then
npx eslint --fix "$FILE" 2>&1
fi
PreToolUse en Bash inspecciona el comando. Si detecta patrones prohibidos, devuelve exit 1 con un mensaje que explica el bloqueo.
#!/bin/bash # .claude/hooks/block-dangerous.sh
CMD=$(cat /dev/stdin | jq -r '.tool_input.command // empty')
DANGEROUS="rm -rf|git push --force|DROP TABLE|truncate"
if echo "$CMD" | grep -qE "$DANGEROUS"; then
echo "❌ Comando bloqueado por política de segurança" >&2
exit 1
fi
Al iniciar cada sesión, inyecta automáticamente el estado actual: branch, commits recientes, issues abiertas. El agente empieza con el contexto necesario.
#!/bin/bash # .claude/hooks/session-start.sh
echo "=== CONTEXTO DO PROJETO ==="
echo "Branch: $(git branch --show-current)"
echo "Último commit: $(git log -1 --oneline)"
echo "Arquivos modificados:"
git status --short | head -10
Fail-open es el comportamiento predeterminado: si un hook falla (timeout, error del script, crash), el harness continúa la ejecución normalmente. La herramienta que el hook debería interceptar no queda bloqueada.
Esto es intencional para los hooks de enriquecimiento (lint, contexto): no quieres que un lint con errores interrumpa todo el trabajo. Pero, en los hooks de seguridad, fail-open es peligroso.
#!/bin/bash # Sempre: timeout explícito para não travar o agente # Leitura do stdin com timeout INPUT=$(timeout 2 cat /dev/stdin 2>/dev/null || echo '{}') # Parse seguro com fallback CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null) # Se nada para verificar, sair com sucesso (fail-open explícito) [ -z "$CMD" ] && exit 0 # Verificação principal if echo "$CMD" | grep -qE "rm -rf /|DROP DATABASE"; then echo "Comando bloqueado: risco de perda de dados irreversível" >&2 exit 1 fi exit 0
| Evento | Datos en stdin | Impacto del output |
|---|---|---|
| Inicio de sesión | Metadatos de la sesión | Stdout inyectado como mensaje inicial |
| PreToolUse | Nombre de la tool + tool_input (JSON) | Exit 0=permite, 1=bloquea; stderr→agente |
| PostToolUse | tool_input + tool_response (JSON) | Stdout inyectado en el contexto actual |
| Stop | Motivo del cierre | Solo efectos secundarios (log, notificación) |
La skill /update-config de Claude Code facilita agregar hooks a settings.json mediante un prompt en lenguaje natural: "agrega un hook de lint para TypeScript".
4.3 — ⌨️ Slash commands y workflows deterministas