Los prompts son sugerencias. Los hooks son paradas obligatorias.

Durante meses, traté a Claude Code como a un desarrollador junior que simplemente necesitaba reglas claras. Mis instrucciones para el proyecto eran explícitas: nunca hacer force-push, nunca borrar ramas, nunca ejecutar comandos destructivos. La mayoría de las noches, eso funcionaba. El agente escribía pruebas, refactorizaba funciones y mantenía sus manos lejos del historial de git. Entonces, un rebase salió mal.

La ventana de contexto se llenó con la salida de errores de git. Marcadores de conflicto, mensajes de HEAD desprendido (detached HEAD) y advertencias de divergencia de ramas se acumularon, token por token. Enterrada bajo ese ruido estaba mi instrucción educada de evitar el force-pushing. Para el modelo, el texto más reciente y relevante en el hilo era el flujo de errores. La atención estadística se impuso a la política. El agente ejecutó un comando que borró dos horas de cambios locales sin confirmar. No fue malintencionado; estaba distraído. Esa distinción es importante. Un LLM no rompe las reglas por despecho. Las rompe porque un patrón más ruidoso en la ventana de contexto anula temporalmente una instrucción anterior.

Ese incidente cambió mi forma de pensar sobre la seguridad de los agentes. Una barrera de seguridad que funciona el noventa y nueve por ciento de las veces es un riesgo. Si el modo de fallo te cuesta tiempo, dinero o datos de producción, no puedes dejarlo dentro del prompt. Necesitas una ejecución fuera del bucle de razonamiento del modelo.

Los hooks de Claude Code resuelven exactamente esto. Son pequeños scripts que interceptan las llamadas a herramientas en tres momentos específicos: antes de que una herramienta se ejecute (PreToolUse), después de que una herramienta termine (PostToolUse) y cuando el agente decide que ha terminado (Stop). Debido a que se ejecutan como código externo, no dependen de la memoria, el estado de ánimo o la presión del contexto del modelo. El modelo puede olvidar cada instrucción que le hayas dado; el hook seguirá diciendo que no.

Aquí está el armazón que construí después de aquella noche perdida.

El Guard Hook: Interceptar antes del daño

Mi hook PreToolUse inspecciona cada comando de Bash antes de que la shell lo toque. Mantengo una lista de denegación estricta de patrones destructivos. Si la cadena del comando coincide con algo peligroso, el hook aborta la ejecución y devuelve un error directamente al agente.

Los patrones que bloqueo son simples y sin ambigüedades:

  • git push --force o cualquier variante de force-with-lease en la que aún no confíe
  • git reset --hard
  • rm -rf

Esto no es investigación de seguridad sofisticada. Es un cinturón de seguridad. Pero el detalle crítico es lo que sucede después del bloqueo.

Nunca devuelvo un seco “Bloqueado”. Un rechazo rotundo confunde al agente y puede atraparlo en un bucle donde intenta variaciones del mismo comando destructivo. En su lugar, el mensaje de error incluye una ruta de escape. Cuando el hook detecta un reset forzado, le dice al agente: “Este comando está bloqueado para proteger el trabajo sin confirmar. Primero realiza un checkpoint y luego reevalúa”. Esa frase adicional cambia completamente el comportamiento del agente. Pasa de intentar controlar el daño a crear seguridad. El hook no es solo un muro; es control de tráfico.

También elegí una lista de denegación en lugar de una lista de permitidos para los comandos de shell. Al principio, consideré permitir solo un conjunto explícito de subcomandos de git seguros. Eso falló rápidamente. Los agentes son creativamente literales. Ejecutan comandos legítimos pero inesperados como git stash push -m "wip" o git branch --show-current para verificar el estado. Una lista de permitidos rompe el flujo de trabajo normal en el momento en que el modelo inventa un comando válido pero no listado. Una lista de denegación corta y curada de patrones genuinamente destructivos le da al agente espacio para moverse mientras protege los límites.

El Formatter Hook: Automatizar las tareas tediosas

Solía desperdiciar tokens de prompt diciéndole al agente que “siempre ejecute el formateador después de editar un archivo”. Lo olvidaba la mitad de las veces. La otra mitad, se detenía y preguntaba si debía formatear, gastando una llamada a una herramienta en una decisión que solo tenía una respuesta correcta.

Ahora manejo eso con un hook PostToolUse. Después de que el agente edita un archivo, el hook verifica la extensión del archivo. Si es Python, ejecuta Ruff. Si es JavaScript o TypeScript, ejecuta Prettier. Si es Go, ejecuta gofmt. El agente no sabe que el formateador existe. No necesita saberlo.

Mover esto fuera del prompt tuvo dos efectos. Primero, el código es consistentemente limpio sin añadir carga cognitiva al modelo. Segundo, mis instrucciones de proyecto se acortaron. Cada “siempre” y “nunca” que eliminas de un prompt es un token que el modelo puede gastar en la resolución de problemas reales. El hook se encarga de lo invariante; el prompt se encarga de la intención.

El Quality Gate: Redefiniendo el concepto de “Hecho”

El hook Stop se ejecuta cuando el agente decide que ha terminado la tarea e intenta terminar la sesión. Yo no lo permito. En su lugar, el hook ejecuta la suite de pruebas completa. Si alguna prueba falla, el hook bloquea el comando de parada y devuelve el resultado del fallo al agente.

Esto cambia la definición de finalización. “Hecho” ya no es una sensación que tiene el modelo. Es un umbral medible. El agente solo puede terminar cuando el harness confirma que el código funciona. En la práctica, esto crea un bucle de retroalimentación estrecho. El agente escribe código, cree que ha terminado, pulsa el botón de parada e inmediatamente ve un traceback de pytest. Luego se autocorrige, arregla el error de importación o la aserción rota, e intenta detenerse de nuevo. He visto agentes iterar tres o cuatro veces dentro de este bucle sin intervención humana. El harness impone la calidad; el modelo proporciona los parches.

Lo que esto enseña sobre la ingeniería de agentes

Construir sistemas autónomos fiables requiere un cambio de mentalidad. Pasas de escribir prompts más largos a construir harnesses más estrictos.

Usa hooks para la ejecución y prompts para la política. Si una regla debe cumplirse el cien por ciento de las veces, debe estar en el código, no en lenguaje natural. Los prompts destacan en la ambigüedad, el gusto y la arquitectura. Son pésimos con los invariantes. Si un error te costaría una tarde de tiempo de recuperación o, peor aún, el tiempo de actividad en producción, escribe un hook.

Los prompts más cortos producen mejores resultados. Cuando trasladas las reglas mecánicas a scripts, el modelo tiene menos que recordar y menos que contradecir. La ventana de contexto del agente es un recurso escaso. No la llenes con recordatorios de formato.

Finalmente, acepta que tu rol está cambiando. A medida que los agentes ganan autonomía, el trabajo del humano pasa de generar contenido a diseñar las salvaguardas. Estás construyendo el harness que decide qué puede tocar el modelo, cuándo puede terminar y cómo debe comportarse cuando las cosas salen mal. Eso es ingeniería, no prompting.

La fuente que inspiró este enfoque y los detalles adicionales de implementación se pueden encontrar aquí.

Si estás construyendo con agentes de IA y quieres intercambiar notas con otros profesionales, puedes encontrar la comunidad de aprendizaje de GyaanSetu aquí.