Revisada el 2026-10-09 · vigente hasta 2027-01-07

Haz que Claude Code ejecute un script tuyo en un momento fijo de la sesión, siempre y sin depender de que el modelo se acuerde.

El método: en un settings.json declaras qué evento dispara el hook y qué comando corre; el script recibe un JSON por la entrada estándar y responde con su código de salida o con otro JSON.1 A diferencia de una instrucción en CLAUDE.md, que es una petición, un hook es una garantía: salta siempre en su evento.2

Requisitos

  • Claude Code instalado.
  • Un script ejecutable (bash, Python) y jq o Python para leer el JSON de entrada.
  • Tener presente que el hook corre con todos tus permisos de usuario: puede leer, cambiar o borrar lo mismo que tú. Revísalo y pruébalo antes de activarlo.1

Pasos

  1. Elige el evento. Los más útiles:1

    • SessionStart: al empezar o reanudar sesión, y también tras /clear o una compactación. Para cargar contexto que cambia.
    • UserPromptSubmit: al enviar un prompt, antes de que Claude lo procese. Para añadir contexto, validar o bloquear.
    • PreToolUse: antes de usar una herramienta. Puede bloquearla.
    • PostToolUse: después de una herramienta que ha ido bien. Por ejemplo, formatear o pasar el linter.
    • Stop: cuando Claude termina de responder.
    • Notification: cuando Claude Code envía un aviso, por ejemplo porque espera tu permiso.
  2. Elige dónde guardarlo. ~/.claude/settings.json vale para todos tus proyectos; .claude/settings.json, para uno y se puede subir a git; .claude/settings.local.json, para uno y solo para ti. Los hooks de todos los niveles se suman.1

  3. Escribe la entrada con tres niveles: evento, grupo con matcher (qué herramienta; vacío equivale a todas) y lista de hooks con type, command y, si quieres, timeout en segundos.1 Este ejemplo oficial avisa en macOS cuando Claude te necesita:3

    {
      "hooks": {
        "Notification": [
          {
            "matcher": "",
            "hooks": [
              {
                "type": "command",
                "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
              }
            ]
          }
        ]
      }
    }

    Si ya hay una clave hooks, añade el evento nuevo a su lado; no sustituyas el objeto entero.3

  4. Escribe el script. Recibe por stdin un JSON con, entre otros, session_id, transcript_path, cwd y hook_event_name; en los eventos de herramientas, además, tool_name y tool_input.1

  5. Decide cómo responde:1

    • Código 0: todo bien. En SessionStart y UserPromptSubmit, el texto que imprimas se añade al contexto de Claude.
    • Código 2: error que bloquea; lo que escribas en stderr le llega a Claude como motivo.
    • Otro código: error que no bloquea; la acción sigue.
    • JSON por stdout: systemMessage es un aviso que ves tú y hookSpecificOutput.additionalContext, texto que lee Claude.
  6. Compruébalo con /hooks, que lista los hooks configurados y su origen. Los cambios en los ajustes se suelen detectar solos; si no aparecen, reinicia la sesión.3

  7. Pruébalo a mano: pásale un JSON de ejemplo por tubería (echo '{...}' | ./mi-hook.sh) y mira el código de salida con echo $?.3

Errores frecuentes

  • Un echo sin condición en el perfil de la shell se cuela delante del JSON y Claude Code deja de interpretarlo.3
  • Poner additionalContext fuera de hookSpecificOutput: se ignora sin avisar.3
  • Hooks lentos en UserPromptSubmit: frenan cada prompt. Su tiempo máximo por defecto es de 30 segundos; si se agota, la salida se descarta.1
  • Usar claude -p sobre un repositorio ajeno: en ese modo no hay diálogo de confianza y sus hooks se ejecutan sin preguntar.1
  • Variables sin comillas y rutas relativas: usa "$VAR" y rutas absolutas.1

Cómo lo uso

Tengo dos hooks globales en ~/.claude/settings.json, ambos con un tiempo máximo de 10 segundos:

  • recordatorio-superficie.sh, en SessionStart. Lee el cwd del JSON de entrada, saca el nombre del proyecto y, según una tabla, recuerda qué conviene hacer en local y qué en la web o el móvil. Responde con systemMessage (lo leo yo) y additionalContext (lo lee Claude).
  • aviso-tokens.sh, en UserPromptSubmit. Lee transcript_path, busca el último registro de uso de tokens y calcula qué parte de la ventana está ocupada. Avisa una sola vez por sesión al 60 % y al 80 %, con un archivo marcador en /tmp. Al 80 % pide a Claude que escriba un handoff.md. El comando acaba en || true, así que un fallo nunca bloquea el prompt.
  • A mi entender, el patrón de responder a la vez con systemMessage y additionalContext es el más útil: un mensaje para mí y otro para Claude.
  • Pendiente: aviso-tokens.sh asume una ventana de 200.000 tokens salvo que se fije la variable CLAUDE_CONTEXT_WINDOW. Con modelos de un millón de tokens (ver ventana de contexto) el porcentaje no es el de la ventana real. A mi entender, hay que decidir si se mide contra la ventana real o se mantiene 200.000 como umbral prudente, y dejarlo escrito en el script.

Véase también

Referencias

Footnotes

  1. Hooks reference. Anthropic, documentación de Claude Code. Consultado el 2026-10-09. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10

  2. Extend Claude Code. Anthropic, documentación de Claude Code. Consultado el 2026-10-09. ↩

  3. Automate actions with hooks. Anthropic, documentación de Claude Code. Consultado el 2026-10-09. ↩ ↩2 ↩3 ↩4 ↩5 ↩6