OSS · CLI em Bash · Claude Code

hook-chain-lens

Os hooks do Claude Code disparam de forma aditiva em quatro escopos. Veja o que roda de fato.

Uma CLI de leitura pura que carrega todas as definições de hook que o Claude Code vai mesclar para o cwd atual (user, project, local e cada plugin habilitado), resolve ${CLAUDE_PLUGIN_ROOT} e imprime a cadeia mesclada agrupada por evento com escopo de origem, matcher, timeout e arquivo de origem. Bash + jq, sem escritas, sem hooks em runtime.

Ver no GitHub O que o doctor pega →

Demo no terminal: hook-chain-lens list imprime a cadeia mesclada do cwd atual, mostrando PreCompact com dois handlers de matcher vazio, SessionStart, PostCompact e UserPromptSubmit, cada um anotado com escopo, matcher, timeout e arquivo de origem; em seguida hook-chain-lens doctor sinaliza [W1] "PreCompact" has 2 handlers with empty matcher.
list agrupa os hooks por evento com escopo e arquivo de origem. doctor transforma os mesmos dados em pass / warn / error, com um exit code que dá para usar como gate de CI.

O que o doctor pega

Oito regras sobre a cadeia mesclada. Erros retornam exit 1, então o doctor funciona como gate de CI ou verificação de pre-commit para os arquivos de settings do Claude Code no seu repositório.

Código Severidade O que detecta
W1 warn O mesmo evento tem dois ou mais handlers com matcher vazio: todos disparam a cada trigger, mantendo a ordem. Muitas vezes é proposital, muitas vezes não.
W2 warn O mesmo evento tem o mesmo matcher compartilhado por dois ou mais handlers: costuma ser um copy-paste de um hook de plugin que já existia.
W3 error Um command aponta para um arquivo que não existe depois da expansão de ${CLAUDE_PLUGIN_ROOT}: o hook vai falhar sempre que for disparado.
W4 warn O arquivo de command existe mas não está legível nem executável: permissões provavelmente derrubadas por um passo de install.
W5 warn Um timeout está anormalmente baixo (menos de um segundo): quase sempre um typo do valor pretendido.
I1 info Um timeout está anormalmente alto (mais de 300 segundos): vale confirmar se o hook realmente precisa desse orçamento.
W6 error Um nome de evento não é reconhecido pelo Claude Code: quase sempre um typo (PreToolUsage no lugar de PreToolUse, etc.).
W7 warn O campo matcher aparece em um evento que não aceita matcher: o campo é morto, o handler dispara a cada trigger.

Instalação

Clone o repositório e crie um symlink da CLI dentro do seu PATH. Requer bash 4+, jq e coreutils. Roda em Linux e 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

Três subcomandos. Todos aceitam --cwd para ler os escopos project e local a partir de outro diretório, e list aceita --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

Quatro decisões de design

As decisões interessantes são todas sobre o que a ferramenta não faz.

  1. Somente leitura, sempre

    O hook-chain-lens nunca edita settings.json, nunca instala um hook e nunca executa um. Ele não pode desativar em silêncio algo que quebrou, e não pode alterar o que a próxima execução do Claude Code vai fazer. A análise estática deixa a ferramenta segura para rodar no meio da sessão e segura para manter no CI.

  2. Aditivo, não sobrescrito

    O Claude Code mescla hooks de forma aditiva: um evento definido nos escopos user, project, local e plugin roda todos eles, nessa ordem. O list espelha isso literalmente: nenhum escopo esconde outro. É o modelo que surpreende as pessoas quando quatro plugins estão instalados e todos registram UserPromptSubmit.

  3. "Habilitado" quer dizer instalado E ativado

    Um plugin só contribui com hooks se o installed_plugins.json listar ele e o settings.json marcar enabledPlugins["<key>"] como true. Plugins instalados mas desativados ficam fora, o que casa com o comportamento em runtime do próprio Claude Code, então a visão mesclada é confiável.

  4. O doctor sai com código diferente de zero em erros

    Warnings e notas info aparecem mas não derrubam a execução. Erros (W3 arquivo ausente, W6 evento desconhecido) retornam exit 1, então hook-chain-lens doctor vira um gate de pre-commit ou de CI de verdade para os arquivos de settings no seu repositório: um caminho de hook quebrado nunca chega na main.

Ferramentas relacionadas para devs

Todos os produtos →

← Voltar para produtos