Claude Code hooks: bloquea cambios accidentales en .env
Un hook PreToolUse probado con eventos JSON impide que Claude Code edite .env por accidente. Código copiable, prueba local y límites reales.

Başlıklar
Si le pides a Claude Code que arregle el login de tu app y guardas una clave en .env.local, una edición equivocada puede romper el entorno antes de que revises el diff. Una instrucción que dice «ten cuidado» depende del modelo; un hook decide antes de escribir. Aquí vamos a bloquear las herramientas de edición cuando apunten a un archivo de entorno.
Probé el script de esta guía con eventos JSON simulados: rechazó .env, .env.local y .env.production; permitió src/app.py y .env.example. Un JSON mal formado también se rechazó. No ejecuté una sesión real de Claude Code: la última comprobación en el producto debe hacerse en tu instalación. La documentación oficial de Anthropic confirma cómo funciona PreToolUse y el código de salida 2 para bloquear una operación.
La barrera, antes de que ocurra el cambio
Claude Code envía al hook un evento JSON por entrada estándar cuando está por llamar a una herramienta. Nuestro handler lee tool_input.file_path, toma el nombre del archivo y devuelve 2 si coincide con .env o una variante como .env.local. Para otros archivos devuelve 0. Registramos el handler en PreToolUse para que la decisión ocurra antes de editar. PostToolUse serviría para comprobar el resultado, pero no para evitar esa escritura.
Esta regla tiene una intención precisa. Una petición amplia, como «conecta Supabase», podría llevar a tocar una clave local sin que el usuario lo pidiera. La regla detiene esa ruta de edición y muestra el motivo. No inspecciona ni envía el contenido del archivo.

1. Crea el handler
Guarda el siguiente código en .claude/hooks/guard_sensitive.py dentro de tu proyecto. Requiere Python 3 en la máquina donde se ejecuta Claude Code. Puedes copiarlo completo:
#!/usr/bin/env python3
"""Claude Code PreToolUse guard for Edit and Write tool calls."""
import json
import pathlib
import sys
try:
event = json.load(sys.stdin)
raw = event["tool_input"]["file_path"]
if not isinstance(raw, str) or not raw.strip():
raise ValueError("missing file_path")
except (KeyError, TypeError, ValueError, json.JSONDecodeError):
print("Cannot verify edit target; edit blocked.", file=sys.stderr)
sys.exit(2)
name = pathlib.PurePosixPath(raw.replace("\\", "/")).name.lower()
if (name == ".env" or name.startswith(".env.")) and name != ".env.example":
print(f"Sensitive file blocked: {name}", file=sys.stderr)
sys.exit(2)
sys.exit(0)
El nombre .env.example queda permitido porque suele ser una plantilla sin secretos. Si tu equipo usa credentials.json u otro nombre sensible, añade una condición explícita. Evita copiar valores reales dentro del hook.
2. Regístralo en Claude Code
En .claude/settings.json, agrega esta entrada al objeto hooks. Si el archivo ya tiene otros hooks, conserva esas entradas y combina solo la nueva; reemplazar el archivo entero podría desactivar controles que ya existían.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/guard_sensitive.py\""
}
]
}
]
}
}
El matcher Edit|Write limita la ejecución a esas dos herramientas. La variable $CLAUDE_PROJECT_DIR apunta al proyecto activo. Anthropic distingue ajustes de proyecto compartibles y ajustes locales; si versionas este archivo, revísalo como código porque un hook ejecuta comandos en la computadora de cada desarrollador.
3. Haz una prueba que pueda fallar
Desde la raíz del proyecto, ejecuta primero el caso bloqueado. El comando debe mostrar un mensaje sobre .env.local; echo $? debe imprimir 2.
printf '%s' '{"tool_input":{"file_path":".env.local"}}' | python3 .claude/hooks/guard_sensitive.py
echo $?
Ahora prueba una edición permitida. Aquí echo $? debe imprimir 0.
printf '%s' '{"tool_input":{"file_path":"src/app.py"}}' | python3 .claude/hooks/guard_sensitive.py
echo $?
En mi prueba local ambos resultados coincidieron. También pasaron .env.example y una ruta normal en Windows; el JSON inválido se rechazó. Abre después /hooks en Claude Code para confirmar que aparece PreToolUse. En un proyecto descartable, sin claves reales, pídele que intente editar .env.local y comprueba que el archivo no cambió. Ese último paso es una prueba pendiente, no algo que yo haya ejecutado.
Límites: lo que este hook no promete
Un Bash que escriba el mismo archivo no pasa por el matcher Edit|Write. La guía de matchers de Anthropic lo advierte: una herramienta puede modificar archivos por otra vía. El script tampoco resuelve enlaces simbólicos ni impide que otra aplicación edite el archivo. Mantén las claves fuera de Git, configura .gitignore y revisa los permisos de herramientas. Si quieres una política obligatoria para toda escritura, necesitas controles más amplios.
El beneficio de este ejemplo es concreto: en un proyecto pequeño, bloquea una clase frecuente de edición accidental con una regla que puedes probar sin gastar tokens. Úsalo como primera barrera y amplíalo solo según las rutas y herramientas que tu agente realmente utiliza.
Recibe lo nuevo en tu correo
Workshops gratis, herramientas y novedades de IA aplicadas a negocio, sin humo.