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.
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.
-
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.
-
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.
-
"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.
-
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
- private-lint Git-hook gate that blocks personal and private names (family names, personal emails, client domains) before commit and push. Pure Bash; detection patterns stay machine-local, never in any repo, and a full-history audit covers the moment before you flip a repository public.
- quake-lens Earthquake statistics CLI + MCP server in pure-stdlib Python: Gutenberg-Richter b-value (Aki MLE) and Omori-Utsu aftershock decay (Ogata MLE) from public catalogs.
- rhythm-lens Measures the rhythm of Japanese, English and Portuguese Markdown (sentence-length burstiness, paragraph structure) against measured human/AI distributions from two published papers. A writing feedback instrument, not an AI detector.
- claude-shift Multi-account Claude Code manager. Switch the active login, sync the two-file auth Claude Code actually reads (~/.claude/.credentials.json + ~/.claude.json), and watch 5-hour and weekly usage across all accounts. CLI + local API + Chrome extension + browser Web UI + Tauri v2 desktop.