Usa PostToolUse Hooks para disparar lint automáticamente tras cada escritura de Claude. El código de salida 2 devuelve los errores a Claude para corrección automática.
Claude Code escribe código rápido, pero no siempre recuerda ejecutar el lint. Le pides que "revise mientras escribe" y a veces lo hace, a veces no. Los Hooks resuelven este problema: trasladan la responsabilidad de la comprobación de código de Claude al sistema.
Este artículo se centra en una sola cosa: usar PostToolUse Hooks para disparar automáticamente comprobaciones después de que Claude escriba código, asegurando que cada cambio de archivo cumpla tus estándares.
La lógica de un Hook de comprobación de código es sencilla:
Write o Edit para escribir un archivoEl código de salida 2 es la clave: hace que Claude reciba el error y lo corrija automáticamente, formando un ciclo "escribir→comprobar→corregir".
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.rb ]] && rubocop -A \"$file\" --no-color -q || true'"
}
]
}
]
}
}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" =~ \\.(js|ts|jsx|tsx)$ ]] && npx eslint --fix \"$file\" || true'"
}
]
}
]
}
}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.py ]] && ruff check --fix \"$file\" && ruff format \"$file\" || true'"
}
]
}
]
}
}
Los proyectos reales suelen mezclar lenguajes. Mover la lógica de comprobación a un script independiente es más fácil de mantener que acumular comandos en el JSON.
Crear .claude/hooks/lint.sh:
#!/bin/bash
set -e
input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path // empty')
[[ -z "$file" ]] && exit 0
[[ ! -f "$file" ]] && exit 0
ext="${file##*.}"
case "$ext" in
rb) rubocop -A "$file" --no-color -q ;;
js|ts|jsx|tsx) npx eslint --fix "$file" --quiet ;;
py) ruff check --fix "$file"; ruff format "$file" ;;
go) gofmt -w "$file"; golangci-lint run "$file" 2>&1 ;;
*) exit 0 ;;
esac
Referenciar el script en settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/lint.sh" }]
}
]
}
}
Código de salida 2 + stderr es lo que activa la autocorrección de Claude:
run_lint() {
local output exit_code
output=$(rubocop "$file" --no-color 2>&1)
exit_code=$?
if [[ $exit_code -ne 0 ]]; then
echo "$output" >&2
exit 2
fi
rubocop -A "$file" --no-color -q
}
skip_patterns=("vendor/" "node_modules/" "db/schema.rb" ".min.js" "_test.go")
for pattern in "${skip_patterns[@]}"; do
[[ "$file" == *"$pattern"* ]] && exit 0
done
Con esta configuración, el flujo de trabajo es:
Writerubocop -A automáticamente — detecta 3 problemasNo necesitas ejecutar ningún comando de comprobación manualmente.
Global (~/.claude/settings.json): Cuando usas las mismas reglas en todos los proyectos.
Nivel de proyecto (.claude/settings.json en git): Recomendado para equipos. Cualquiera que abra el repositorio obtiene la configuración correcta automáticamente.
Ambos coexisten; los hooks de proyecto se fusionan con los globales y ambos se ejecutan.
La comprobación automática de código con Hooks se reduce a tres pasos:
PostToolUse + matcher "Write|Edit" para interceptar escrituras de archivosEmpieza con un lenguaje. Cuando funcione, añade más. Haz commit de los scripts en .claude/hooks/ para compartirlos con el equipo.