Guías

Hooks en todos los agentes de programación con IA: Claude Code, Cursor, Gemini CLI, GitHub Copilot, Kiro y Factory Droid (2026)

¿Dónde van los hooks en cada agente de programación con IA, y cómo bloquea un hook un comando?

Claude Code lee un bloque hooks en .claude/settings.json, Gemini CLI un bloque hooks en .gemini/settings.json, Cursor lee .cursor/hooks.json, Factory Droid .factory/hooks.json, GitHub Copilot .github/hooks/*.json y Kiro cualquier archivo JSON en .kiro/hooks/. Todos envían el evento a tu script como JSON por stdin. Para bloquear una llamada a herramienta, sal con código 2 en Claude Code, Cursor, Gemini CLI, Factory Droid y la Kiro CLI, o imprime una decisión deny como JSON (Copilot usa permissionDecision, Cursor usa permission).

Esta página es una traducción de la guía en inglés. Los comandos, claves de configuración y el código no se modifican; si hay diferencias, prevalece la versión en inglés. Leer en inglés → · Otros idiomas: 简体中文 · 日本語 · 한국어 · Português (Brasil)

Entérate cuando cambie la configuración

Cuando cambie un ajuste, flag o regla de permisos de estas herramientas, te avisamos en un correo semanal (en inglés), verificado con la documentación oficial.

Respuesta rápida: ubicación de los archivos de hooks

  • Claude Code: una clave hooks en .claude/settings.json (proyecto) o ~/.claude/settings.json (usuario). /hooks muestra lo que está configurado.
  • Cursor: .cursor/hooks.json (proyecto) o ~/.cursor/hooks.json (usuario), con "version": 1. Los hooks de enterprise y de equipo están por encima de ambos.
  • Gemini CLI: una clave hooks en .gemini/settings.json (proyecto), ~/.gemini/settings.json (usuario) o /etc/gemini-cli/settings.json (sistema).
  • GitHub Copilot: .github/hooks/*.json para el cloud agent y Copilot CLI, además de ~/.copilot/hooks/ para la CLI. "version": 1.
  • Kiro: cualquier archivo .json en .kiro/hooks/ (workspace) o ~/.kiro/hooks/ (global, CLI V3), con "version": "v1".
  • Factory Droid: .factory/hooks.json (proyecto) o ~/.factory/hooks.json (usuario). /hooks abre el gestor de hooks.

Cómo bloquea un hook una llamada a herramienta

  • Claude Code: un hook PreToolUse que sale con 2 bloquea la acción y devuelve su stderr como motivo.
  • Cursor: sal con 2 o imprime {"permission": "deny"}. Cualquier otro código distinto de cero falla en abierto, salvo que el hook defina failClosed: true.
  • Gemini CLI: sal con 0 e imprime {"decision": "deny", "reason": "..."} (la forma preferida), o sal con 2 con el motivo en stderr. Los demás códigos solo generan una advertencia.
  • GitHub Copilot: un hook preToolUse imprime {"permissionDecision": "deny", "permissionDecisionReason": "..."}. No hacer nada permite la llamada.
  • Kiro: en la CLI, salir con 2 bloquea PreToolUse. En el IDE, cualquier salida distinta de cero bloquea un hook Pre Tool Use.
  • Factory Droid: salir con 2 en PreToolUse bloquea la llamada a herramienta. Los demás códigos distintos de cero se registran y Droid continúa.

La misma idea, distintos nombres de eventos

  • Antes de que se ejecute una herramienta: PreToolUse (Claude Code, Kiro, Factory Droid), preToolUse y beforeShellExecution (Cursor), BeforeTool (Gemini CLI), preToolUse (Copilot).
  • Después de que se ejecute una herramienta: PostToolUse (Claude Code, Kiro, Factory Droid), postToolUse y afterFileEdit (Cursor), AfterTool (Gemini CLI), postToolUse (Copilot).
  • Inicio de sesión: SessionStart (Claude Code, Kiro, Factory Droid, Gemini CLI), sessionStart (Cursor, Copilot).
  • El agente terminó: Stop (Kiro, Factory Droid), stop (Cursor), agentStop (Copilot).
  • Prompt enviado: UserPromptSubmit (Kiro, Factory Droid), beforeSubmitPrompt (Cursor), userPromptSubmitted (Copilot).

El mismo hook, cuatro sintaxis

Claude Code: .claude/settings.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

Cursor: .cursor/hooks.json

{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      {
        "command": ".cursor/hooks/block-risky.sh",
        "matcher": "rm -rf|curl|wget"
      }
    ]
  }
}

Gemini CLI: .gemini/settings.json

{
  "hooks": {
    "BeforeTool": [
      {
        "matcher": "write_file|replace",
        "hooks": [
          {
            "name": "security-check",
            "type": "command",
            "command": "$GEMINI_PROJECT_DIR/.gemini/hooks/security.sh",
            "timeout": 5000
          }
        ]
      }
    ]
  }
}

Kiro: .kiro/hooks/guard-shell.json

{
  "version": "v1",
  "hooks": [
    {
      "name": "Guard shell commands",
      "trigger": "PreToolUse",
      "matcher": "shell",
      "action": {
        "type": "command",
        "command": "./scripts/guard.sh"
      }
    }
  ]
}

Errores comunes

  • En Gemini CLI, stdout debe contener solo el JSON final. Un JSON no válido se trata como allow.
  • Gemini CLI avisa antes de ejecutar un hook de proyecto cuyo nombre o comando cambió, por ejemplo después de un git pull.
  • Copilot pasa toolArgs como una cadena JSON, así que hay que parsearlo dos veces. El cloud agent trata una decisión "ask" como "deny" y solo carga hooks desde la rama predeterminada.
  • Los hooks de proyecto de Cursor se ejecutan desde la raíz del proyecto y los de usuario desde ~/.cursor/, así que las rutas relativas de los scripts difieren.
  • Las acciones de prompt de agente de Kiro inician un nuevo bucle del agente y consumen créditos. Las acciones de comando de shell no.
  • Los matchers de Factory Droid son regex que distinguen mayúsculas y minúsculas. Usa commandRegex para filtrar las llamadas Execute por el texto del comando.

Guía completa de hooks para cada agente

Fuentes

Documentación oficial (en inglés) con la que se verificó esta guía. Versión en inglés revisada el: 2026-10-18

Más guías en español