Hooks do Claude Code não funcionam no Windows: causas e soluções

O mesmo hook que roda bem no Mac não faz nada no Windows ou, pior, bloqueia todos os comandos. Quase sempre o culpado é o shell. Veja como o Claude Code executa hooks no Windows e como deixar os seus confiáveis.

Por Aslan, equipe Pet Island · Atualizado em 26 de out. de 2026 · 5 min de leitura

RESPOSTA CURTA

No Windows, o Claude Code executa o command de um hook com o Git Bash ou, quando o Git Bash não está instalado, com o PowerShell. Diga qual você quer com "shell": "powershell" ou "shell": "bash", mantenha o stdout com um único objeto JSON (sem echos do perfil), use o código de saída 2 para bloquear e atualize o Claude Code (vários bugs de hooks no Windows foram corrigidos em versões até a 2.1.310). Depure com /hooks e claude --debug.

Qual shell executa seu hook

O Claude Code passa a string de command para um shell: sh -c no macOS e no Linux, Git Bash no Windows ou PowerShell quando o Git Bash não está instalado. Essa única frase da referência de hooks explica a maioria dos relatos de “no meu Mac funciona”. Um comando escrito para PowerShell falha no Git Bash, um script bash falha no PowerShell, e qual dos dois você recebe depende de o Git for Windows estar instalado ou não.

Acabe com a adivinhação usando o campo shell. Ele aceita "bash" ou "powershell":

%USERPROFILE%\.claude\settings.jsonCopiar
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "[Console]::Beep(880, 200)"
}
]
}
]
}
}

Se você quer o Git Bash e o Claude Code não o encontra, instale o Git for Windows ou defina CLAUDE_CODE_GIT_BASH_PATH com o local dele e inicie uma nova sessão.

Sintomas e suas causas

O que você vêCausa provávelSolução
O hook parece nunca rodarVersão antiga do Claude Code, evento ou matcher errado, JSON inválido nas configuraçõesAtualize; confira /hooks; remova comentários e vírgulas sobrando no final
ParserError ou “unexpected token”Sintaxe de PowerShell chegando ao Git Bash, ou o contrárioDefina shell explicitamente
A saída do hook “does not start with {” (não começa com {)Algo foi impresso antes do JSON, muitas vezes um perfil de shellSilencie a saída do perfil; envie logs para o stderr
Um caminho com \ e / misturados não é encontradoVariável de caminho do Windows concatenada com um sufixo no estilo UnixUse a forma exec: o programa em command e cada argumento em args
powershell: Permission denied vindo do Git BashRelatado de forma intermitente na 2.1.283 e nas 2.1.304–2.1.305 (#103910, em aberto)Use "shell": "powershell" para que o Git Bash não fique no meio
Um hook de proteção deixa tudo passarCódigo de saída 1 em vez de 2, ou um bug de fail-open em versões antigasSaia com 2 para bloquear; atualize para a 2.1.310 ou posterior
O hook retorna na hora, sem saídaUm programa do subsistema GUI pelo qual o shell não esperaUse um programa de console ou espere pelo processo

Apenas JSON no stdout

O Claude Code lê a saída padrão do seu hook como resposta. A regra na documentação é curta: não imprima nada além do objeto JSON no stdout. No Windows isso quebra de um jeito traiçoeiro: o Git Bash e algumas configurações ainda carregam seu perfil de shell, e um echo incondicional nesse perfil é colocado antes do seu JSON. Aí o hook “funciona” no terminal e falha dentro do Claude Code.

Em vez disso, registre os logs em um arquivo ou no stderr e faça a saída do seu perfil depender de um shell interativo.

Códigos de saída: 2 bloqueia, 1 não

Sair com 0 é sucesso. Sair com 2 é um erro bloqueante: em eventos que podem ser bloqueados, o Claude Code interrompe a ação e mostra seu stderr. Sair com 1 sem JSON válido é um erro não bloqueante, e a ação segue em frente. Se o seu hook impõe uma política, use a saída 2.

Nem todo evento pode ser bloqueado assim. O código de saída de um hook Notification é ignorado. Um hook Stop que sai com 2 mantém o Claude trabalhando. Um hook PermissionRequest ignora completamente a saída 2. Ele decide por meio de um objeto decision no seu JSON.

O Claude Code 2.1.309 corrigiu hooks de PowerShell que não bloqueavam quando o programa do hook saía com o código 2. Se a sua proteção em PowerShell parece ignorada, confira primeiro a sua versão.

Correções para Windows que valem a atualização

O changelog da Anthropic tem uma longa lista de correções de hooks no Windows. As que explicam tópicos antigos de fórum:

VersãoCorreção
2.1.47Hooks PreToolUse e PostToolUse falhavam silenciosamente no Windows; agora rodam com o Git Bash em vez do cmd.exe
2.1.161Hooks que chamam o bash explicitamente (/usr/bin/bash script.sh) falhavam com “command not found”
2.1.299Hooks PreToolUse e PermissionRequest sem shell definido deixavam tudo passar ao falhar (fail-open) sem o Git for Windows; uma proteção com falha agora bloqueia
2.1.309Hooks de PowerShell não bloqueavam com o código de saída 2; proteções com "shell": "powershell" deixavam tudo passar ao falhar (fail-open) sem o Git for Windows
2.1.310Proteções cujo comando era só strings entre aspas (como um caminho entre aspas) deixavam tudo passar ao falhar (fail-open) sem o Git Bash

A issue mais antiga, intitulada “No hook is working on Windows” (#10450), foi relatada na 2.0.27; um comentarista descobriu que o stdin não chegava aos comandos dos hooks. Se você está em uma versão tão antiga, atualize antes de depurar qualquer outra coisa.

Chamando um programa diretamente

Se o seu hook é um programa compilado, você pode pular o shell com a forma exec (o campo args; shell é ignorado quando args está definido). No Windows, a forma exec exige que command aponte para um executável de verdade, como um .exe; shims .cmd e .bat (incluindo a maioria das coisas que o npm instala) não podem ser iniciados sem um shell. Aponte para o .exe ou use a forma shell.

Uma lição de quando criamos nosso próprio helper de hooks: no Windows, quando um shell inicia um programa compilado para o subsistema GUI, ele não espera pelo programa. O shell retorna na hora, o agente lê uma saída vazia e o hook parece morto. Programas de hook precisam ser programas de console.

Hooks de plugin e caminhos

Hooks de plugin que montam caminhos como ${CLAUDE_PLUGIN_ROOT}/hooks/run.sh quebraram no Windows entre a v2.1.2 e a v2.1.12 (#18610): a variável se expande para um caminho com barras invertidas, e adicionar um sufixo com barra normal gera um caminho misto que o bash não consegue resolver. A documentação atual traz a solução limpa: use a forma exec sempre que um hook fizer referência a um placeholder de caminho. Coloque o programa em command e cada argumento em args, por exemplo "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/format.js"]. Cada elemento é passado como um único argumento, sem shell para estragá-lo.

Checklist de depuração

  1. /hooks abre uma lista somente leitura de todos os hooks configurados e de onde cada um vem.
  2. claude --debug (ou /debug no meio da sessão) mostra cada execução de hook, sua saída e seu código de saída. claude --debug-file <path> grava isso em um arquivo.
  3. Valide o JSON. Os arquivos de configuração são JSON estrito; uma única vírgula sobrando no final desativa o arquivo inteiro.
  4. Confira o matcher. Matchers diferenciam maiúsculas de minúsculas; "*", "" ou nenhum matcher correspondem a tudo.
  5. Execute o comando você mesmo no mesmo shell que o Claude Code vai usar, passando um JSON de exemplo pelo pipe.
  6. Olhe o timeout. Hooks de comando têm timeout padrão de 600 segundos; um hook que espera por uma pessoa precisa dessa folga.

Para desligar todos os hooks enquanto investiga, defina "disableAllHooks": true.

Se você só queria notificações e aprovações

Muitas configurações de hooks no Windows existem por um único motivo: saber quando o Claude Code precisa de você e responder. O Pet Island faz isso sem nenhum script. Ele se conecta ao Claude Code com um clique, cuida dos detalhes do Windows para você e coloca cada pedido de permissão, pergunta e plano em uma pequena ilha no topo da tela, com o comando ou o diff, onde você permite ou nega. Também funciona quando o Claude Code roda dentro do WSL.

PERGUNTAS FREQUENTES

Qual shell executa os hooks do Claude Code no Windows?

O Git Bash ou, quando o Git Bash não está instalado, o PowerShell. Defina "shell": "powershell" ou "shell": "bash" no hook para escolher explicitamente.

Por que meu hook do Claude Code funciona no terminal, mas não no Claude Code?

Normalmente é saída extra: um perfil de shell que imprime texto com echo faz esse texto aparecer antes do JSON do hook. Imprima apenas o objeto JSON no stdout.

Como faço um hook bloquear uma chamada de ferramenta?

Saia com o código 2 (ou retorne uma decisão deny em JSON). O código de saída 1 é um erro não bloqueante, e a ação segue em frente. Hooks PermissionRequest ignoram a saída 2 e usam um objeto decision no lugar.

O comando de um hook pode ser um arquivo .cmd ou .bat?

Não na forma exec. No Windows, ele precisa apontar para um executável de verdade, como um .exe. Use a forma shell para executar arquivos .cmd ou .bat.

Como vejo por que um hook falhou?

Execute claude --debug ou digite /debug e use /hooks para ver quais hooks estão carregados.

Fontes

Todas as configurações e comportamentos desta página foram conferidos com estas páginas em 26 de outubro de 2026. Os agentes mudam rápido; se algo não bater mais, vale o que diz a página oficial.

CONTINUE LENDO

Responda a todos os agentes direto do topo da sua tela.

Windows e Mac · 7 dias grátis, depois US$ 8,99 uma única vez · US$ 1 de cada venda alimenta animais de rua

Experimente o Pet Island grátis