OSS · CLI en Bash · Claude Code

hook-chain-lens

Los hooks de Claude Code disparan de forma aditiva en cuatro ámbitos. Mira qué corre de verdad.

Una CLI de solo lectura que carga todas las definiciones de hook que Claude Code va a fusionar para el cwd actual (user, project, local y cada plugin habilitado), resuelve ${CLAUDE_PLUGIN_ROOT} y muestra la cadena fusionada agrupada por evento con ámbito de origen, matcher, timeout y archivo de origen. Bash + jq, sin escrituras, sin hooks en runtime.

Ver en GitHub Qué detecta doctor →

Demo en terminal: hook-chain-lens list muestra la cadena fusionada del cwd actual, con PreCompact y dos handlers de matcher vacío, SessionStart, PostCompact y UserPromptSubmit, cada uno anotado con ámbito, matcher, timeout y archivo de origen; luego hook-chain-lens doctor marca [W1] "PreCompact" has 2 handlers with empty matcher.
list agrupa los hooks por evento con ámbito y archivo de origen. doctor convierte los mismos datos en pass / warn / error, con un exit code que sirve como gate de CI.

Qué detecta doctor

Ocho reglas sobre la cadena fusionada. Los errores retornan exit 1, así que doctor funciona como gate de CI o verificación de pre-commit para los archivos de settings de Claude Code en tu repositorio.

Código Severidad Qué detecta
W1 warn El mismo evento tiene dos o más handlers con matcher vacío: todos disparan en cada trigger, en el orden dado. A veces es intencional, a veces no.
W2 warn El mismo evento tiene el mismo matcher compartido por dos o más handlers: suele ser un copy-paste de un hook de plugin que ya existía.
W3 error Un command apunta a un archivo que no existe después de expandir ${CLAUDE_PLUGIN_ROOT}: el hook va a fallar cada vez que se dispare.
W4 warn El archivo del command existe pero no es legible ni ejecutable: probables permisos rotos por un paso de install.
W5 warn Un timeout está inusualmente bajo (menos de un segundo): casi siempre un typo del valor previsto.
I1 info Un timeout está inusualmente alto (más de 300 segundos): vale confirmar si el hook realmente necesita ese presupuesto.
W6 error Un nombre de evento no lo reconoce Claude Code: casi siempre un typo (PreToolUsage en vez de PreToolUse, etc.).
W7 warn El campo matcher aparece en un evento que no acepta matcher: el campo queda muerto, el handler dispara en cada trigger.

Instalación

Clona el repositorio y crea un symlink de la CLI dentro de tu PATH. Requiere bash 4+, jq y coreutils. Corre en Linux y macOS.

git clone https://github.com/kenimo49/hook-chain-lens.git
ln -s "$(pwd)/hook-chain-lens/bin/hook-chain-lens" ~/.local/bin/hook-chain-lens

# requires: bash 4+, jq, coreutils

Uso

Tres subcomandos. Todos aceptan --cwd para leer los ámbitos project y local desde otro directorio, y list acepta --json para pipelines guiados por jq.

hook-chain-lens list                       # merged chain, grouped by event
hook-chain-lens list --event PreToolUse    # filter to one event
hook-chain-lens list --cwd ~/other-repo    # read project/local scope from elsewhere
hook-chain-lens list --json | jq '.'       # machine-readable output

hook-chain-lens doctor                     # 8 rules; exit 1 on errors, 0 otherwise
hook-chain-lens events                     # every event Claude Code knows, grouped by matcher support

Cuatro decisiones de diseño

Las decisiones interesantes son todas sobre lo que la herramienta no hace.

  1. Solo lectura, siempre

    hook-chain-lens nunca edita settings.json, nunca instala un hook y nunca ejecuta uno. No puede desactivar en silencio algo que se rompió, y no puede alterar lo que la próxima corrida de Claude Code va a hacer. El análisis estático deja a la herramienta segura para correr en medio de una sesión y segura para dejar en CI.

  2. Aditivo, no sobrescrito

    Claude Code fusiona hooks de forma aditiva: un evento definido en los ámbitos user, project, local y plugin corre todos, en ese orden. list refleja esto tal cual: ningún ámbito eclipsa a otro. Es el modelo que sorprende a la gente cuando cuatro plugins están instalados y todos registran UserPromptSubmit.

  3. "Habilitado" significa instalado Y activado

    Un plugin solo aporta hooks si installed_plugins.json lo lista y settings.json marca enabledPlugins["<key>"] en true. Los plugins instalados pero desactivados quedan fuera, lo que coincide con el comportamiento en runtime del propio Claude Code, así la vista fusionada es confiable.

  4. doctor sale con código distinto de cero en errores

    Los warnings y las notas info se muestran pero no tumban la corrida. Los errores (W3 archivo faltante, W6 evento desconocido) retornan exit 1, así que hook-chain-lens doctor se vuelve un gate real de pre-commit o de CI para los archivos de settings de tu repositorio: una ruta de hook rota nunca aterriza en main.

Herramientas relacionadas para devs

Todos los productos →

← Volver a productos