Ciclo de vida do hook
Hooks disparam em pontos específicos durante uma sessão do Claude Code. Quando um evento dispara e um matcher corresponde, o Claude Code passa contexto JSON sobre o evento para seu manipulador de hook. Para hooks de comando, a entrada chega em stdin. Para hooks HTTP, chega como corpo da solicitação POST. Seu manipulador pode então inspecionar a entrada, tomar ação e opcionalmente retornar uma decisão. Os eventos caem em três cadências:- uma vez por sessão:
SessionStarteSessionEnd - uma vez por turno:
UserPromptSubmit,StopeStopFailure - em cada chamada de ferramenta dentro do loop agentic:
PreToolUseePostToolUse
Como um hook é resolvido
Para ver como essas peças se encaixam, considere este hookPreToolUse que bloqueia comandos shell destrutivos. O matcher se restringe a chamadas de ferramenta Bash e a condição if se restringe ainda mais a subcomandos Bash correspondendo a rm *, então block-rm.sh apenas é gerado quando ambos os filtros correspondem:
permissionDecision de "deny" se contiver rm -rf:
Bash "rm -rf /tmp/build". Aqui está o que acontece:
1
Evento dispara
O evento
PreToolUse dispara. O Claude Code envia a entrada da ferramenta como JSON em stdin para o hook:2
Matcher verifica
O matcher
"Bash" corresponde ao nome da ferramenta, então este grupo de hook é ativado. Se você omitir o matcher ou usar "*", o grupo é ativado em cada ocorrência do evento.3
Condição if verifica
A condição
if "Bash(rm *)" corresponde porque rm -rf /tmp/build é um subcomando correspondendo a rm *, então este manipulador é gerado. Se o comando tivesse sido npm test, a verificação if falharia e block-rm.sh nunca seria executado, evitando a sobrecarga de geração de processo. O campo if é opcional; sem ele, cada manipulador no grupo correspondido é executado.4
Manipulador de hook executa
O script inspeciona o comando completo e encontra Se o comando tivesse sido uma variante mais segura de
rm -rf, então imprime uma decisão em stdout:rm como rm file.txt, o script teria atingido exit 0 em vez disso. Código de saída 0 sem saída significa que o hook não tem decisão a relatar, então a chamada da ferramenta continua através do fluxo de permissão normal. O hook pode negar a chamada, mas ficar em silêncio não a aprova.5
Claude Code age sobre o resultado
O Claude Code lê a decisão JSON, bloqueia a chamada da ferramenta e mostra a razão ao Claude.
Configuração
Hooks são definidos em arquivos de configurações JSON. A configuração tem três níveis de aninhamento:- Escolha um evento de hook para responder, como
PreToolUseouStop - Adicione um grupo de matcher para filtrar quando dispara, como “apenas para a ferramenta Bash”
- Defina um ou mais manipuladores de hook para executar quando correspondido
Esta página usa termos específicos para cada nível: evento de hook para o ponto do ciclo de vida, grupo de matcher para o filtro e manipulador de hook para o comando shell, endpoint HTTP, ferramenta MCP, prompt ou agente que executa. “Hook” por si só refere-se ao recurso geral.
Locais de hooks
Onde você define um hook determina seu escopo:
Para detalhes sobre resolução de arquivo de configurações, consulte configurações. Administradores corporativos podem usar
allowManagedHooksOnly para bloquear hooks de usuário, projeto e plugin. Hooks de plugins forçadamente ativados em configurações gerenciadas enabledPlugins são isentos, para que administradores possam distribuir hooks verificados através de um marketplace de organização. Consulte Configuração de hook.
Padrões de matcher
O campomatcher filtra quando hooks disparam. Como um matcher é avaliado depende dos caracteres que contém:
Um matcher no caminho de expressão regular é testado com
RegExp.prototype.test do JavaScript, que sucede em uma correspondência em qualquer lugar no valor. Edit.* corresponde tanto a Edit quanto a NotebookEdit; envolva o padrão em ^ e $, como em ^Edit$, quando você precisa de uma correspondência de string inteira.
Separadores de vírgula e a tolerância de espaço em branco ao redor requerem Claude Code v2.1.191 ou posterior.
Hífens no conjunto de correspondência exata requerem Claude Code v2.1.195 ou posterior. Em versões anteriores, um nome com hífen como code-reviewer é avaliado como uma expressão regular não ancorada, então também dispara para senior-code-reviewer; ancorá-lo como ^code-reviewer$ nessas versões para corresponder apenas a esse nome.
FileChanged e StopFailure usam um conjunto de correspondência exata mais estreito de apenas letras, dígitos, _ e |. Um hífen, espaço ou vírgula em um matcher para esses dois eventos o mantém no caminho de expressão regular, e apenas | separa alternativas. Todos os outros eventos com suporte a matcher na tabela a seguir aceitam | ou ,.
O evento FileChanged não segue essas regras ao construir sua lista de monitoramento. Consulte FileChanged.
Cada tipo de evento corresponde em um campo diferente:
O matcher executa contra um campo da entrada JSON que o Claude Code envia para seu hook em stdin. Para eventos de ferramenta, esse campo é
tool_name. Cada seção evento de hook lista o conjunto completo de valores de matcher e o esquema de entrada para esse evento.
Este exemplo executa um script de linting apenas quando Claude escreve ou edita um arquivo:
UserPromptSubmit, PostToolBatch, Stop, TeammateIdle, TaskCreated, TaskCompleted, WorktreeCreate, WorktreeRemove, MessageDisplay e CwdChanged não suportam matchers e sempre disparam em cada ocorrência. Se você adicionar um campo matcher a esses eventos, ele é silenciosamente ignorado.
Para eventos de ferramenta, você pode filtrar mais estreitamente definindo o campo if em manipuladores de hook individuais. if usa sintaxe de regra de permissão para corresponder contra o nome da ferramenta e argumentos juntos, então "Bash(git *)" executa quando qualquer subcomando da entrada Bash corresponde a git * e "Edit(*.ts)" executa apenas para arquivos TypeScript.
Corresponder ferramentas MCP
Ferramentas de servidor MCP aparecem como ferramentas regulares em eventos de ferramenta (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied), então você pode corresponder a elas da mesma forma que corresponde a qualquer outro nome de ferramenta.
Ferramentas MCP seguem o padrão de nomenclatura mcp__<server>__<tool>, por exemplo:
mcp__memory__create_entities: ferramenta create entities do servidor Memorymcp__filesystem__read_file: ferramenta read file do servidor Filesystemmcp__github__search_repositories: ferramenta search do servidor GitHub
.* ao prefixo do servidor. O .* é obrigatório: um matcher como mcp__memory ou mcp__brave-search contém apenas caracteres de correspondência exata, então é comparado como uma string exata e não corresponde a nenhuma ferramenta.
mcp__memory__.*corresponde a todas as ferramentas do servidormemorymcp__brave-search__.*corresponde a todas as ferramentas de um servidor cujo nome contém um hífenmcp__.*__write.*corresponde a qualquer ferramenta cujo nome começa comwritede qualquer servidor
mcp__brave-search é avaliado como uma expressão regular não ancorada e corresponde a cada ferramenta daquele servidor. A forma mcp__brave-search__.* funciona em todas as versões.
Ferramentas de um servidor MCP fornecido por plugin usam um segmento de servidor com escopo que inclui o nome do plugin: mcp__plugin_<plugin-name>_<server-name>__<tool>. Um matcher escrito contra a chave do servidor simples nunca dispara para essas ferramentas. Para um plugin nomeado my-plugin que agrupa um servidor sob a chave db, uma ferramenta query aparece como mcp__plugin_my-plugin_db__query, então o matcher para cada ferramenta daquele servidor é mcp__plugin_my-plugin_db__.*. Use o mesmo nome de ferramenta com escopo no campo if de um manipulador. Consulte Servidores MCP fornecidos por plugin para saber como o nome com escopo é construído.
Este exemplo registra todas as operações do servidor memory e valida operações de escrita de qualquer servidor MCP:
Campos do manipulador de hook
Cada objeto no arrayhooks interno é um manipulador de hook: o comando shell, endpoint HTTP, ferramenta MCP, prompt LLM ou agente que executa quando o matcher corresponde. Existem cinco tipos:
- Hooks de comando (
type: "command"): executam um comando shell. Seu script recebe a entrada JSON do evento em stdin e comunica resultados através de códigos de saída e stdout. - Hooks HTTP (
type: "http"): enviam a entrada JSON do evento como uma solicitação HTTP POST para uma URL. O endpoint comunica resultados através do corpo da resposta usando o mesmo formato de saída JSON que hooks de comando. - Hooks de ferramenta MCP (
type: "mcp_tool"): chamam uma ferramenta em um servidor MCP já conectado. A saída de texto da ferramenta é tratada como stdout de hook de comando. - Hooks de prompt (
type: "prompt"): enviam um prompt para um modelo Claude para avaliação de turno único. O modelo retorna uma decisão sim/não como JSON. Consulte Hooks baseados em prompt. - Hooks de agente (
type: "agent"): geram um subagente que pode usar ferramentas como Read, Grep e Glob para verificar condições antes de retornar uma decisão. Hooks de agente são experimentais e podem mudar. Consulte Hooks baseados em agente.
args, e hooks HTTP são desduplicados por URL.
Manipuladores executam no diretório atual com o ambiente do Claude Code. A variável de ambiente $CLAUDE_CODE_REMOTE é definida como "true" em ambientes web remotos e não é definida na CLI local. A partir de v2.1.199, $CLAUDE_CODE_BRIDGE_SESSION_ID é definido para o ID de sessão Remote Control enquanto a sessão local tem uma conexão Remote Control ativa.
Campos comuns
Esses campos se aplicam a todos os tipos de hook:
O campo
if contém exatamente uma regra de permissão. Não há sintaxe &&, || ou lista para combinar regras; para aplicar múltiplas condições, defina um manipulador de hook separado para cada.
Para padrões Bash, se seu comando de hook executa depende da forma do padrão e do comando Bash que Claude está invocando. Atribuições VAR=value iniciais são removidas antes da correspondência.
O filtro também falha aberto, executando seu hook independentemente do padrão, quando o comando Bash não pode ser analisado. Como o filtro
if é melhor esforço, use o sistema de permissão em vez de um hook para impor um allow ou deny duro.
Campos de hook de comando
Além dos campos comuns, hooks de comando aceitam esses campos:
Um hook de comando executa como forma exec quando
args é definido, e forma shell quando args é omitido. Defina args sempre que o hook referenciar um placeholder de caminho, já que cada elemento é passado como um argumento sem aspas. Omita args quando você precisar de recursos de shell como pipes ou &&, ou quando nenhuma preocupação se aplica.
Forma exec executa quando args está presente. Claude Code resolve command como um executável em PATH e o gera diretamente com args como o vetor de argumentos. Não há shell, então cada elemento args é um argumento exatamente como escrito, e placeholders de caminho como ${CLAUDE_PLUGIN_ROOT} são substituídos em command e em cada elemento args como strings simples. Caracteres especiais como apóstrofos, $ e backticks passam verbatim porque não há shell para interpretá-los. Nenhuma tokenização de shell acontece em nenhuma plataforma.
Forma shell executa quando args está ausente. A string command é passada para um shell: sh -c em macOS e Linux, Git Bash no Windows, ou PowerShell quando Git Bash não está instalado. Defina o campo shell para escolher explicitamente. O shell tokeniza a string, expande variáveis e interpreta pipes, &&, redirecionamentos e globs.
No Windows, a forma exec requer que
command seja resolvido para um executável real como .exe. Os shims .cmd e .bat que npm, npx, eslint e outras ferramentas instalam em node_modules/.bin não são executáveis e não podem ser gerados sem um shell. Para executá-los em forma exec, invoque o script subjacente com node diretamente, por exemplo "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/node_modules/eslint/bin/eslint.js"]. O padrão node mais caminho-de-script funciona em todas as plataformas porque node.exe é um binário real. Para executar um shim .cmd ou .bat por nome, use forma shell.CLAUDE_PROJECT_DIR, CLAUDE_PLUGIN_ROOT e CLAUDE_PLUGIN_DATA no processo gerado, então um script pode ler process.env.CLAUDE_PLUGIN_ROOT independentemente de como foi lançado.
Um hook de plugin em forma shell cujo command referencia ${user_config.*} falha com um erro em vez de executar. Para usar um valor de opção de um hook em forma shell, leia a variável de ambiente $CLAUDE_PLUGIN_OPTION_<KEY>, como $CLAUDE_PLUGIN_OPTION_WEBHOOK_URL para uma opção webhook_url, ou defina args para mudar o hook para forma exec. Antes de v2.1.207, comandos de hook de plugin em forma shell também substituíam ${user_config.*}.
Em forma exec,
command é apenas o nome ou caminho do executável. Se command é um nome simples sem separador de caminho e contém espaço em branco junto com args, Claude Code registra um aviso porque o spawn falhará: não há executável nomeado node script.js. Mova os tokens extras para args. Caminhos absolutos com espaços, como C:\Program Files\nodejs\node.exe, são um executável válido único e não disparam o aviso.Campos de hook HTTP
Além dos campos comuns, hooks HTTP aceitam esses campos:
O Claude Code envia a entrada JSON do hook como corpo da solicitação POST com
Content-Type: application/json. O corpo da resposta usa o mesmo formato de saída JSON que hooks de comando.
O tratamento de erros difere dos hooks de comando: respostas não-2xx, falhas de conexão e timeouts todos produzem erros não-bloqueadores que permitem que a execução continue. Para bloquear uma chamada de ferramenta ou negar uma permissão, retorne uma resposta 2xx com um corpo JSON contendo decision: "block" ou um hookSpecificOutput com permissionDecision: "deny".
Este exemplo envia eventos PreToolUse para um serviço de validação local, autenticando com um token da variável de ambiente MY_TOKEN:
Campos de hook de ferramenta MCP
Além dos campos comuns, hooks de ferramenta MCP aceitam esses campos:
A saída de texto da ferramenta é tratada como stdout de hook de comando: se analisar como saída JSON válida, é processada como uma decisão, caso contrário, é mostrada como texto simples. Se o servidor nomeado não estiver conectado, ou a ferramenta retornar
isError: true, o hook produz um erro não-bloqueador e a execução continua.
Hooks de ferramenta MCP estão disponíveis em cada evento de hook uma vez que o Claude Code tenha se conectado aos seus servidores MCP. SessionStart e Setup normalmente disparam antes dos servidores terminarem de conectar, então hooks nesses eventos devem esperar o erro “não conectado” na primeira execução.
Este exemplo chama a ferramenta security_scan no servidor MCP my_server após cada Write ou Edit, passando o caminho do arquivo editado:
Campos de hook de prompt e agente
Além dos campos comuns, hooks de prompt e agente aceitam esses campos:Referenciar scripts por caminho
Use esses placeholders para referenciar scripts de hook relativos à raiz do projeto ou plugin, independentemente do diretório de trabalho quando o hook executa:${CLAUDE_PROJECT_DIR}: a raiz do projeto. Claude Code também define essa variável no ambiente de servidores MCP stdio e servidores LSP de plugin.${CLAUDE_PLUGIN_ROOT}: o diretório de instalação do plugin, para scripts agrupados com um plugin. Muda em cada atualização de plugin.${CLAUDE_PLUGIN_DATA}: o diretório de dados persistentes do plugin, para dependências e estado que devem sobreviver a atualizações de plugin.
args como um argumento sem tokenização de shell, então caminhos com espaços ou caracteres especiais não precisam de aspas. Em forma shell, envolva cada placeholder em aspas duplas.
- Scripts de projeto
- Scripts de plugin
Este exemplo usa
${CLAUDE_PROJECT_DIR} para executar um verificador de estilo do diretório .claude/hooks/ do projeto após qualquer chamada de ferramenta Write ou Edit:Hooks em skills e agentes
Além de arquivos de configurações e plugins, hooks podem ser definidos diretamente em skills e subagentes usando frontmatter. Esses hooks são escopo do ciclo de vida do componente e apenas executam quando esse componente está ativo. Todos os eventos de hook são suportados. Para subagentes, hooksStop são automaticamente convertidos para SubagentStop já que esse é o evento que dispara quando um subagente completa.
Hooks usam o mesmo formato de configuração que hooks baseados em configurações, mas são escopo da vida útil do componente e limpos quando termina.
Esta skill define um hook PreToolUse que executa um script de validação de segurança antes de cada comando Bash:
O menu /hooks
Digite /hooks no Claude Code para abrir um navegador somente leitura para seus hooks configurados. O menu mostra cada evento de hook com uma contagem de hooks configurados, permite que você detalhe em matchers e mostra os detalhes completos de cada manipulador de hook. Use-o para verificar configuração, verificar qual arquivo de configurações um hook veio, ou inspecionar comando, prompt ou URL de um hook.
O menu exibe todos os cinco tipos de hook: command, prompt, agent, http e mcp_tool. Cada hook é rotulado com um prefixo [type] e uma fonte indicando onde foi definido:
User: de~/.claude/settings.jsonProject: de.claude/settings.jsonLocal: de.claude/settings.local.jsonPlugin: dehooks/hooks.jsonde um pluginSession: registrado em memória para a sessão atualBuilt-in: registrado internamente pelo Claude Code
Desabilitar ou remover hooks
Para remover um hook, delete sua entrada do arquivo de configurações JSON. Para desabilitar temporariamente todos os hooks sem removê-los, defina"disableAllHooks": true em seu arquivo de configurações. Não há forma de desabilitar um hook individual mantendo-o na configuração.
A configuração disableAllHooks respeita a hierarquia de configurações gerenciadas. Se um administrador configurou hooks através de configurações de política gerenciada, disableAllHooks definido em configurações de usuário, projeto ou local não pode desabilitar esses hooks gerenciados. Apenas disableAllHooks definido no nível de configurações gerenciadas pode desabilitar hooks gerenciados.
Edições diretas a hooks em arquivos de configurações são normalmente capturadas automaticamente pelo observador de arquivo.
Entrada e saída de hook
Hooks de comando recebem dados JSON via stdin e comunicam resultados através de códigos de saída, stdout e stderr. Hooks HTTP recebem o mesmo JSON como corpo da solicitação POST e comunicam resultados através do corpo da resposta HTTP. Esta seção cobre campos e comportamento comuns a todos os eventos. Cada seção de evento sob Eventos de hook inclui seu esquema de entrada específico e opções de controle de decisão. No macOS e Linux, hooks de comando executam em sua própria sessão sem um terminal controlador a partir de v2.1.139. O processo de hook e qualquer processo filho não podem abrir/dev/tty ou enviar sequências de escape diretamente para a interface do Claude Code. Windows não tem /dev/tty. Para exibir uma mensagem ao usuário em qualquer plataforma, retorne systemMessage na saída JSON. Para disparar uma notificação de desktop, definir um título de janela ou tocar o sino, retorne terminalSequence em vez disso.
Campos de entrada comuns
Eventos de hook recebem esses campos como JSON, além de campos específicos do evento documentados em cada seção evento de hook. Para hooks de comando, este JSON chega via stdin. Para hooks HTTP, chega como corpo da solicitação POST.
Ao executar com
--agent ou dentro de um subagente, dois campos adicionais são incluídos:
Apenas hooks
SessionStart podem receber um campo model, e não é garantido que esteja presente. Não há variável de ambiente $CLAUDE_MODEL. Um processo de hook herda o ambiente pai, então pode ler $ANTHROPIC_MODEL se você defini-lo em seu shell, mas esse valor não muda quando você alterna modelos com /model durante uma sessão. Um conjunto de variáveis não é herdado: Claude Code remove variáveis exportadoras OTEL_* de cada subprocesso que spawna, incluindo hooks.
Por exemplo, um hook PreToolUse para um comando Bash recebe isso em stdin:
tool_name e tool_input são específicos do evento. Cada seção evento de hook documenta os campos adicionais para esse evento.
Saída de código de saída
O código de saída do seu comando de hook diz ao Claude Code se a ação deve prosseguir, ser bloqueada ou ser ignorada. Saída 0 significa sucesso. O Claude Code analisa stdout para campos de saída JSON. A saída JSON é apenas processada na saída 0. Para a maioria dos eventos, stdout é escrito no log de debug, mas não mostrado na transcrição. As exceções sãoUserPromptSubmit, UserPromptExpansion e SessionStart, onde stdout é adicionado como contexto que Claude pode ver e agir.
Saída 2 significa um erro bloqueador. O Claude Code ignora stdout e qualquer JSON nele. Em vez disso, texto de stderr é alimentado de volta ao Claude como uma mensagem de erro. O efeito depende do evento: PreToolUse bloqueia a chamada da ferramenta, UserPromptSubmit rejeita o prompt e assim por diante. Consulte comportamento de código de saída 2 para a lista completa.
Qualquer outro código de saída é um erro não-bloqueador para a maioria dos eventos de hook. A transcrição mostra um aviso <hook name> hook error seguido pela primeira linha de stderr, para que você possa identificar a causa sem --debug. A execução continua e o stderr completo é escrito no log de debug.
Por exemplo, um script de comando de hook que bloqueia comandos Bash perigosos:
Comportamento de código de saída 2 por evento
Código de saída 2 é a forma de um hook sinalizar “pare, não faça isso”. O efeito depende do evento, porque alguns eventos representam ações que podem ser bloqueadas (como uma chamada de ferramenta que ainda não aconteceu) e outros representam coisas que já aconteceram ou não podem ser prevenidas.
Para
SessionStart, Setup e SubagentStart, o stderr de código de saída 2 é renderizado na transcrição como um aviso <hook name> hook error, da mesma forma que um erro não-bloqueador faz. Claude não vê isso, e a sessão ou subagente prossegue. Para SubagentStart, o aviso aparece na própria transcrição do subagente, não na conversa pai.
A partir do Claude Code v2.1.199, SessionStart, Setup e SubagentStart mostram stderr de código de saída 2 na transcrição. Versões anteriores o escreviam apenas no log de debug.
Tratamento de resposta HTTP
Hooks HTTP usam códigos de status HTTP e corpos de resposta em vez de códigos de saída e stdout:- 2xx com corpo vazio: sucesso, equivalente a código de saída 0 sem saída
- 2xx com corpo de texto simples: sucesso, o texto é adicionado como contexto
- 2xx com corpo JSON: sucesso, analisado usando o mesmo esquema saída JSON que hooks de comando
- Status não-2xx: erro não-bloqueador, execução continua
- Falha de conexão ou timeout: erro não-bloqueador, execução continua
Saída JSON
Códigos de saída permitem você bloquear ou ficar em silêncio, mas saída JSON oferece controle mais granular. Em vez de sair com código 2 para bloquear, saia 0 e imprima um objeto JSON em stdout. O Claude Code lê campos específicos desse JSON para controlar comportamento, incluindo controle de decisão para bloquear, permitir ou escalar para o usuário.Você deve escolher uma abordagem por hook, não ambas: ou use códigos de saída sozinhos para sinalizar, ou saia 0 e imprima JSON para controle estruturado. O Claude Code apenas processa JSON na saída 0. Se você sair 2, qualquer JSON é ignorado.
additionalContext, systemMessage e stdout simples, são limitadas a 10.000 caracteres. Saída que excede este limite é salva em um arquivo e substituída por uma visualização e caminho de arquivo, da mesma forma que resultados de ferramenta grandes são tratados.
O objeto JSON suporta três tipos de campos:
- Campos universais como
continuefuncionam em todos os eventos. Esses são listados na tabela abaixo. decisionereasonde nível superior são usados por alguns eventos para bloquear ou fornecer feedback.hookSpecificOutputé um objeto aninhado para eventos que precisam de controle mais rico. Requer um campohookEventNamedefinido para o nome do evento.
Para parar Claude inteiramente independentemente do tipo de evento:
Emitir notificações de terminal
O campoterminalSequence requer Claude Code v2.1.141 ou posterior.
Hooks executam sem um terminal controlador, então escrever sequências de escape diretamente para /dev/tty falha. Em vez disso, retorne a sequência de escape no campo terminalSequence e Claude Code a emite para você através de seu próprio caminho de escrita de terminal. Isso é livre de corrida, funciona dentro de tmux e GNU screen, e funciona no Windows onde não há /dev/tty.
O campo aceita uma string de uma ou mais sequências de escape na lista de permissões:
- OSC
0,1,2: títulos de janela e ícone - OSC
9: notificações iTerm2, ConEmu, Windows Terminal e WezTerm, incluindo progresso de barra de tarefas9;4 - OSC
99: notificações Kitty - OSC
777: notificações urxvt, Ghostty e Warp - BEL simples
Notification. A sequência de escape é construída com printf escapes octais para que os bytes de controle nunca apareçam na linha de comando do shell, e jq -n --arg constrói a saída JSON para que aspas, barras invertidas e quebras de linha na mensagem de notificação sejam escapadas corretamente:
{ "terminalSequence": "..." } é a mesma de qualquer shell ou linguagem. No Windows, construa a string de escape em PowerShell ou um script e emita o mesmo objeto JSON.
terminalSequence é a substituição suportada para hooks que anteriormente escreviam sequências de escape diretamente para /dev/tty. A lista de permissões é restrita a sequências que não podem mover o cursor ou alterar cores, para que um hook nunca possa corromper um prompt na tela.Adicionar contexto para Claude
O campoadditionalContext passa uma string do seu hook para a janela de contexto do Claude. O Claude Code envolve a string em um lembrete do sistema e a insere na conversa no ponto onde o hook disparou. Claude lê o lembrete na próxima solicitação de modelo, mas não aparece como uma mensagem de chat na interface.
Retorne additionalContext dentro de hookSpecificOutput ao lado do nome do evento:
- SessionStart, Setup e SubagentStart: no início da conversa, antes do primeiro prompt
- UserPromptSubmit e UserPromptExpansion: ao lado do prompt enviado
- PreToolUse, PostToolUse, PostToolUseFailure e PostToolBatch: ao lado do resultado da ferramenta
- Stop e SubagentStop: no final da rodada. A conversa continua para que Claude possa agir sobre o feedback. Consulte Controle de decisão Stop
additionalContext para o mesmo evento, Claude recebe todos os valores. Se um valor exceder 10.000 caracteres, o Claude Code escreve o texto completo em um arquivo no diretório de sessão e passa ao Claude o caminho do arquivo com uma visualização curta em vez disso.
Use additionalContext para informações que Claude deve saber sobre o estado atual do seu ambiente ou a operação que acabou de executar:
- Estado do ambiente: o branch atual, alvo de implantação ou sinalizadores de recurso ativos
- Regras de projeto condicional: qual comando de teste se aplica ao arquivo que acabou de ser editado, quais diretórios são somente leitura nesta worktree
- Dados externos: problemas abertos atribuídos a você, resultados recentes de CI, conteúdo obtido de um serviço interno
bun test” lê como informação de projeto. Texto enquadrado como comandos de sistema fora de banda pode disparar as defesas de injeção de prompt do Claude, o que faz com que Claude superficialize o texto para você em vez de tratá-lo como contexto.
Uma vez injetado, o texto é salvo na transcrição de sessão. Para eventos de mid-sessão como PostToolUse ou UserPromptSubmit, retomar com --continue ou --resume reproduz o texto salvo em vez de re-executar o hook para turnos anteriores, então valores como timestamps ou SHAs de commit ficam obsoletos na retomada. Hooks SessionStart executam novamente na retomada com source definido como "resume", para que possam atualizar seu contexto.
Controle de decisão
Nem todo evento suporta bloqueio ou controle de comportamento através de JSON. Os eventos que fazem cada um usam um conjunto diferente de campos para expressar essa decisão. Use esta tabela como referência rápida antes de escrever um hook:
Alguns eventos também podem reescrever conteúdo em vez de apenas permitir ou bloquear:
PreToolUse:updatedInputdiretamente sobhookSpecificOutputsubstitui os argumentos de uma ferramenta antes de executar. Consulte Controle de decisão PreToolUsePermissionRequest:updatedInputdentro do objetodecision. Consulte Controle de decisão PermissionRequestPostToolUse:updatedToolOutputsubstitui o resultado da ferramenta. Consulte Controle de decisão PostToolUseUserPromptSubmit: não pode substituir o prompt; apenas injetaadditionalContextao lado dele
PreToolUse para entradas de ferramenta de saída e PostToolUse para resultados de ferramenta de entrada.
Aqui estão exemplos de cada padrão em ação:
- Decisão de nível superior
- PreToolUse
- PermissionRequest
Usado por
UserPromptSubmit, UserPromptExpansion, PostToolUse, PostToolUseFailure, PostToolBatch, Stop, SubagentStop, ConfigChange e PreCompact. O único valor é "block". Para permitir que a ação prossiga, omita decision do seu JSON ou saia 0 sem qualquer JSON:Eventos de hook
Cada evento corresponde a um ponto no ciclo de vida do Claude Code onde hooks podem executar. As seções abaixo são ordenadas para corresponder ao ciclo de vida: da configuração de sessão através do loop agentic até o fim da sessão. Cada seção descreve quando o evento dispara, quais matchers suporta, a entrada JSON que recebe e como controlar comportamento através de saída.SessionStart
Executa quando Claude Code inicia uma nova sessão ou retoma uma sessão existente. Útil para carregar contexto de desenvolvimento como problemas existentes ou mudanças recentes em seu codebase, ou configurar variáveis de ambiente. Para contexto estático que não requer um script, use CLAUDE.md em vez disso. SessionStart executa em cada sessão, então mantenha esses hooks rápidos. Apenas hookstype: "command" e type: "mcp_tool" são suportados.
O valor do matcher corresponde a como a sessão foi iniciada:
Entrada de SessionStart
Além dos campos de entrada comuns, hooks SessionStart recebemsource e opcionalmente model, agent_type e session_title:
Controle de decisão de SessionStart
Qualquer texto que seu script de hook imprima em stdout é adicionado como contexto para Claude. Além dos campos de saída JSON disponíveis para todos os hooks, você pode retornar esses campos específicos do evento:suppressOutput ou sessionTitle.
Use reloadSkills quando um hook SessionStart instala ou atualiza skills. A descoberta de skill normalmente executa antes dos hooks SessionStart terminarem, então arquivos que o hook escreve em ~/.claude/skills/ ou .claude/skills/ caso contrário apenas apareceriam na próxima sessão. Este exemplo sincroniza um repositório de skills compartilhado e solicita a re-varredura:
Persistir variáveis de ambiente
Hooks SessionStart têm acesso à variável de ambienteCLAUDE_ENV_FILE, que fornece um caminho de arquivo onde você pode persistir variáveis de ambiente para comandos Bash subsequentes.
Para definir variáveis de ambiente individuais, escreva declarações export para CLAUDE_ENV_FILE. Use append (>>) para preservar variáveis definidas por outros hooks:
CLAUDE_ENV_FILE está disponível para SessionStart, Setup, CwdChanged e FileChanged hooks. Outros tipos de hook não têm acesso a esta variável.Setup
Dispara apenas quando você lança Claude Code com--init-only, ou com --init ou --maintenance em modo não-interativo com a flag -p. Não dispara na inicialização normal. Use-o para instalação de dependência única ou limpeza agendada que você aciona explicitamente de CI ou scripts, separado da inicialização de sessão normal. Para inicialização por sessão, use SessionStart em vez disso.
O valor do matcher corresponde à flag CLI que acionou o hook:
--init-only executa hooks Setup e hooks SessionStart com o matcher startup, depois sai sem iniciar uma conversa. --init e --maintenance disparam hooks Setup apenas quando combinados com -p; em uma sessão interativa essas duas flags atualmente não disparam hooks Setup.
Porque Setup não dispara em cada lançamento, um plugin que precisa de uma dependência instalada não pode confiar apenas em Setup. O padrão prático é verificar a dependência no primeiro uso e instalar se ausente, por exemplo um hook ou skill que testa ${CLAUDE_PLUGIN_DATA}/node_modules e executa npm install se ausente. Consulte o diretório de dados persistentes para onde armazenar dependências instaladas.
Entrada de Setup
Além dos campos de entrada comuns, hooks Setup recebem um campotrigger definido como "init" ou "maintenance":
Controle de decisão de Setup
Hooks Setup não podem bloquear. Qualquer código de saída não-zero, incluindo 2, superficializa stderr ao usuário como um aviso de<hook name> hook error, e a execução continua. Em modo não-interativo, a saída do hook aparece apenas quando você lança com --verbose.
Para passar informação para o contexto de Claude, retorne additionalContext em saída JSON; stdout simples é escrito apenas no log de debug. Além dos campos de saída JSON disponíveis para todos os hooks, você pode retornar esses campos específicos do evento:
CLAUDE_ENV_FILE. Variáveis escritas para esse arquivo persistem em comandos Bash subsequentes para a sessão, assim como em hooks SessionStart. Apenas hooks type: "command" e type: "mcp_tool" são suportados.
InstructionsLoaded
Dispara quando um arquivoCLAUDE.md ou .claude/rules/*.md é carregado em contexto. Este evento dispara na inicialização da sessão para arquivos carregados com entusiasmo e novamente mais tarde quando arquivos são carregados preguiçosamente, por exemplo quando Claude acessa um subdiretório que contém um CLAUDE.md aninhado ou quando regras condicionais com frontmatter paths: correspondem. O hook não suporta bloqueio ou controle de decisão. Executa assincronamente para fins de observabilidade.
O matcher executa contra load_reason. Por exemplo, use "matcher": "session_start" para disparar apenas para arquivos carregados na inicialização da sessão, ou "matcher": "path_glob_match|nested_traversal" para disparar apenas para carregamentos preguiçosos.
Entrada de InstructionsLoaded
Além dos campos de entrada comuns, hooks InstructionsLoaded recebem esses campos:Controle de decisão de InstructionsLoaded
Hooks InstructionsLoaded não têm controle de decisão. Eles não podem bloquear ou modificar carregamento de instrução. Use este evento para logging de auditoria, rastreamento de conformidade ou observabilidade.UserPromptSubmit
Executa quando o usuário submete um prompt, antes do Claude processá-lo. Isso permite que você adicione contexto adicional baseado no prompt/conversa, valide prompts ou bloqueie certos tipos de prompts. HooksUserPromptSubmit têm um timeout padrão de 30 segundos para tipos command, http e mcp_tool, mais curto que o padrão de 600 segundos para esses tipos em outros eventos. Porque este hook executa antes de cada prompt e bloqueia processamento do modelo até que seja concluído, um hook travado paralisa a sessão. Se seu hook precisa de mais tempo, defina o campo timeout na entrada do hook.
Um hook UserPromptSubmit que atinge seu timeout é cancelado e sua saída, incluindo qualquer additionalContext, é descartada. O prompt ainda chega ao Claude sem esse contexto. A partir de v2.1.196, a transcrição mostra um aviso nomeando o hook, o timeout que disparou e que a saída foi descartada. Versões anteriores cancelam o hook sem aviso.
Um hook de callback Agent SDK em UserPromptSubmit que atinge seu timeout bloqueia o prompt com uma mensagem nomeando o hook e o timeout, porque um callback lá pode estar atuando como um portão de política que não deve falhar aberto. A sessão continua. Antes de v2.1.208, um timeout de callback naquele evento terminava o turno com um erro de execução.
Entrada de UserPromptSubmit
Além dos campos de entrada comuns, hooks UserPromptSubmit recebem o campoprompt contendo o texto que o usuário submeteu.
Controle de decisão de UserPromptSubmit
HooksUserPromptSubmit podem controlar se um prompt de usuário é processado e adicionar contexto. Todos os campos de saída JSON estão disponíveis.
Existem duas formas de adicionar contexto à conversa na saída 0:
- Stdout de texto simples: qualquer texto não-JSON escrito em stdout é adicionado como contexto
- JSON com
additionalContext: use o formato JSON abaixo para mais controle. O campoadditionalContexté adicionado como contexto
additionalContext é injetado como um lembrete do sistema que Claude lê sem uma entrada de transcrição visível.
Para bloquear um prompt, retorne um objeto JSON com decision definido para "block":
UserPromptExpansion
Executa quando um comando de barra invertida digitado pelo usuário se expande em um prompt antes de chegar ao Claude. Use isso para bloquear comandos específicos de invocação direta, injetar contexto para uma skill particular ou registrar quais comandos os usuários invocam. Por exemplo, um hook correspondendo adeploy pode bloquear /deploy a menos que um arquivo de aprovação esteja presente, ou um hook correspondendo a uma skill de revisão pode anexar a lista de verificação de revisão da equipe como additionalContext.
Este evento cobre o caminho que PreToolUse não cobre: um hook PreToolUse correspondendo à ferramenta Skill dispara apenas quando Claude chama a ferramenta, mas digitar /skillname diretamente ignora PreToolUse. UserPromptExpansion dispara nesse caminho direto.
Corresponde em command_name. Deixe o matcher vazio para disparar em cada comando de barra invertida do tipo prompt.
Entrada de UserPromptExpansion
Além dos campos de entrada comuns, hooks UserPromptExpansion recebemexpansion_type, command_name, command_args, command_source e a string prompt original. O campo expansion_type é slash_command para skills e comandos personalizados, ou mcp_prompt para prompts de servidor MCP.
Controle de decisão de UserPromptExpansion
HooksUserPromptExpansion podem bloquear a expansão ou adicionar contexto. Todos os campos de saída JSON estão disponíveis.
MessageDisplay
Executa enquanto uma mensagem de assistente flui para a tela. Claude Code exibe a mensagem em incrementos: cada vez que um lote de linhas recém-concluídas está pronto para renderizar, o hook executa uma vez com essas linhas e Claude Code renderiza o texto de substituição do hook em seu lugar. Uma mensagem longa produz várias chamadas; uma mensagem curta pode produzir apenas uma. Use MessageDisplay para:- remover markdown para uma exibição mínima
- transformar o texto que um aplicativo Agent SDK mostra seus usuários
- redactar chaves de API ou nomes de host internos das respostas de Claude
timeout na entrada do hook.
MessageDisplay é apenas para exibição: o texto de substituição muda apenas o que é renderizado na tela. A transcrição e o que Claude vê mantêm o texto original, então Claude nunca vê a substituição, e modo verbose mostra o original. O hook recebe apenas texto de mensagem de assistente, então resultados de ferramenta e o texto que você digita renderizam inalterados.
MessageDisplay não suporta matchers e dispara para cada mensagem de assistente que flui texto; mensagens sem texto, como respostas apenas de chamada de ferramenta, não o acionam.
Em execuções não-interativas, incluindo consultas Agent SDK e claude -p, MessageDisplay executa uma vez por mensagem de assistente em vez de uma vez por lote de linhas. A chamada única chega após a mensagem ser concluída e carrega o texto completo da mensagem: index é 0, final é true e delta contém a mensagem inteira. Um hook que coleta o texto delta para cada mensagem recebe o mesmo texto total em ambos os modos.
Entrada de MessageDisplay
Além dos campos de entrada comuns, hooks MessageDisplay recebem identificadores para o turno e mensagem, a posição desta chamada dentro da mensagem e o novo texto emdelta. Os limites de lote dependem de como o texto flui, então use index e final para rastrear progresso através de uma mensagem em vez de esperar que linhas sejam agrupadas de uma forma particular.
Saída de MessageDisplay
Além dos campos de saída JSON disponíveis para todos os hooks, hooks MessageDisplay podem retornardisplayContent para substituir o delta na tela:
Hooks MessageDisplay não têm controle de decisão. Eles não podem bloquear a mensagem ou mudar o que é armazenado na transcrição ou enviado ao Claude.
Este exemplo remove formatação markdown das respostas de Claude para uma exibição em texto simples. O script lê cada lote de stdin, remove marcadores de negrito e backticks de código inline de
delta e retorna o resultado como displayContent.
- macOS/Linux
- Windows (PowerShell)
Registre um hook de comando para o evento em seu arquivo de configurações:Salve este script em O script precisa de
.claude/hooks/plain-display.sh em seu projeto e torne-o executável com chmod +x:jq em seu PATH.jq está faltando, Claude Code exibe o texto original e nota a falha apenas em saída de debug, não na sessão.
PreToolUse
Executa após Claude criar parâmetros de ferramenta e antes de processar a chamada da ferramenta. Corresponde no nome da ferramenta:Bash, Edit, Write, Read, Glob, Grep, Agent, WebFetch, WebSearch, AskUserQuestion, ExitPlanMode e qualquer nome de ferramenta MCP.
Use Controle de decisão PreToolUse para permitir, negar, pedir ou adiar a chamada da ferramenta.
Entrada de PreToolUse
Além dos campos de entrada comuns, hooks PreToolUse recebemtool_name, tool_input e tool_use_id. Os campos tool_input dependem da ferramenta:
Executa comandos shell.
Cria ou sobrescreve um arquivo.
Substitui uma string em um arquivo existente.
Lê conteúdo de arquivo.
Encontra arquivos correspondendo a um padrão glob.
Pesquisa conteúdo de arquivo com expressões regulares.
Busca e processa conteúdo web.
Pesquisa a web.
Gera um subagente.
Em
PostToolUse, tool_response para uma chamada Agent concluída carrega o texto final do subagente junto com telemetria de uso. Leia esses campos para registrar custo por subagente de um hook:
Para subagentes em background, a ferramenta retorna imediatamente após lançar, então
tool_response não carrega campos de uso. Tem status: "async_launched", agentId, description, prompt, outputFile e resolvedModel.
O campo resolvedModel nomeia o modelo que o subagente realmente executa, que pode diferir do valor model em tool_input, como quando availableModels ou outra sobrescrita se aplica. Requer Claude Code v2.1.174 ou posterior.
Faz ao usuário uma a quatro perguntas de múltipla escolha.
Apresenta um plano e pede ao usuário para aprová-lo antes do Claude sair do modo de plano. Claude escreve o plano em um arquivo no disco antes de chamar a ferramenta, então o
tool_input literal do modelo é tipicamente vazio. Claude Code injeta o conteúdo do plano e o caminho do arquivo antes de passar a entrada para hooks.
Em
PostToolUse, tool_response é um objeto com campos plan e filePath contendo o plano aprovado, mais flags de status interno. Leia tool_response.plan para o conteúdo do plano em vez de re-ler o arquivo do disco.
Controle de decisão de PreToolUse
HooksPreToolUse podem controlar se uma chamada de ferramenta prossegue. Diferentemente de outros hooks que usam um campo decision de nível superior, PreToolUse retorna sua decisão dentro de um objeto hookSpecificOutput. Isso oferece controle mais rico: quatro resultados (permitir, negar, pedir ou adiar) além da capacidade de modificar entrada de ferramenta antes da execução.
Quando múltiplos hooks PreToolUse retornam decisões diferentes, a precedência é
deny > defer > ask > allow.
Quando um hook retorna "ask", o diálogo de permissão exibido ao usuário inclui um rótulo identificando de onde o hook veio: por exemplo, [User], [Project], [Plugin] ou [Local]. Isso ajuda os usuários a entender qual fonte de configuração está solicitando confirmação.
AskUserQuestion e ExitPlanMode requerem interação do usuário e normalmente bloqueiam em modo não-interativo com a flag -p. Retornar permissionDecision: "allow" junto com updatedInput satisfaz esse requisito: o hook lê a entrada da ferramenta de stdin, coleta a resposta através de sua própria UI e a retorna em updatedInput para que a ferramenta execute sem solicitar. Retornar "allow" sozinho não é suficiente para essas ferramentas. Para AskUserQuestion, ecoar de volta o array questions original e adicionar um objeto answers mapeando o texto de cada pergunta para a resposta escolhida.
Ferramentas conectoras sua organização definiu para ask solicitam mesmo quando um hook retorna "allow".
A partir de v2.1.199, uma ferramenta MCP cujo servidor a marca com _meta["anthropic/requiresUserInteraction"] é mais rigorosa: um hook não pode pular seu prompt de aprovação com "allow", com ou sem updatedInput, porque Claude Code não pode confirmar que o hook coletou a interação que a ferramenta precisa.
PreToolUse anteriormente usava campos
decision e reason de nível superior, mas esses estão deprecados para este evento. Use hookSpecificOutput.permissionDecision e hookSpecificOutput.permissionDecisionReason em vez disso. Os valores deprecados "approve" e "block" mapeiam para "allow" e "deny" respectivamente. Outros eventos como PostToolUse e Stop continuam usando decision e reason de nível superior como seu formato atual.Adiar uma chamada de ferramenta para mais tarde
"defer" é para integrações que executam claude -p como um subprocesso e leem sua saída JSON, como um aplicativo Agent SDK ou uma UI personalizada construída em cima do Claude Code. Permite que esse processo chamador pause Claude em uma chamada de ferramenta, colete entrada através de sua própria interface e retome onde parou. Claude Code honra este valor apenas em modo não-interativo com a flag -p. Em sessões interativas ele registra um aviso e ignora o resultado do hook.
A ferramenta AskUserQuestion é o caso típico: Claude quer fazer uma pergunta ao usuário, mas não há terminal para responder. A viagem de ida e volta funciona assim:
- Claude chama
AskUserQuestion. O hookPreToolUsedispara. - O hook retorna
permissionDecision: "defer". A ferramenta não executa. O processo sai comstop_reason: "tool_deferred"e a chamada de ferramenta pendente preservada na transcrição. - O processo chamador lê
deferred_tool_usedo resultado SDK, superficializa a pergunta em sua própria UI e espera por uma resposta. - O processo chamador executa
claude -p --resume <session-id>. A mesma chamada de ferramenta disparaPreToolUsenovamente. - O hook retorna
permissionDecision: "allow"com a resposta emupdatedInput. A ferramenta executa e Claude continua.
deferred_tool_use carrega o id, name e input da ferramenta. O input são os parâmetros que Claude gerou para a chamada de ferramenta, capturados antes da execução:
cleanupPeriodDays que deleta arquivos de sessão após 30 dias por padrão. Se a resposta não estiver pronta quando você retomar, o hook pode retornar "defer" novamente e o processo sai da mesma forma. O processo chamador controla quando quebrar o loop eventualmente retornando "allow" ou "deny" do hook.
"defer" apenas funciona quando Claude faz uma única chamada de ferramenta no turno. Se Claude faz várias chamadas de ferramenta de uma vez, "defer" é ignorado com um aviso e a ferramenta prossegue através do fluxo de permissão normal. A restrição existe porque resume pode apenas re-executar uma ferramenta: não há forma de adiar uma chamada de um lote sem deixar as outras não resolvidas.
Se a ferramenta adiada não estiver mais disponível quando você retomar, o processo sai com stop_reason: "tool_deferred_unavailable" e is_error: true antes do hook disparar. Isso acontece quando um servidor MCP que forneceu a ferramenta não está conectado para a sessão retomada. O payload deferred_tool_use ainda é incluído para que você possa identificar qual ferramenta desapareceu.
--resume restaura o modo de permissão que estava ativo quando a ferramenta foi adiada, então você não precisa passar --permission-mode novamente. As exceções são plan e bypassPermissions, que nunca são transportados. Passar --permission-mode explicitamente na retomada sobrescreve o valor restaurado.PermissionRequest
Executa quando o usuário é mostrado um diálogo de permissão. Use Controle de decisão PermissionRequest para permitir ou negar em nome do usuário. Corresponde no nome da ferramenta, mesmos valores que PreToolUse.Entrada de PermissionRequest
Hooks PermissionRequest recebem campostool_name e tool_input como hooks PreToolUse, mas sem tool_use_id. Um array permission_suggestions opcional contém as opções “sempre permitir” que o usuário normalmente veria no diálogo de permissão. A diferença é quando o hook dispara: hooks PermissionRequest executam quando um diálogo de permissão está prestes a ser mostrado ao usuário, enquanto hooks PreToolUse executam antes da execução da ferramenta independentemente do status de permissão.
Controle de decisão de PermissionRequest
HooksPermissionRequest podem permitir ou negar solicitações de permissão. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar um objeto decision com esses campos específicos do evento:
Entradas de atualização de permissão
O campo de saídaupdatedPermissions e o campo de entrada permission_suggestions ambos usam o mesmo array de objetos de entrada. Cada entrada tem um type que determina seus outros campos e um destination que controla onde a mudança é escrita.
setMode com bypassPermissions apenas toma efeito se a sessão foi lançada com modo bypass já disponível: --dangerously-skip-permissions, --permission-mode bypassPermissions, --allow-dangerously-skip-permissions ou permissions.defaultMode: "bypassPermissions" em configurações, e o modo não é desabilitado por permissions.disableBypassPermissionsMode. Caso contrário, a atualização é um no-op. bypassPermissions nunca é persistido como defaultMode independentemente de destination.destination em cada entrada determina se a mudança fica em memória ou persiste em um arquivo de configurações.
Um hook pode ecoar uma das
permission_suggestions que recebeu como sua própria saída updatedPermissions, que é equivalente ao usuário selecionar essa opção “sempre permitir” no diálogo.
PostToolUse
Executa imediatamente após uma ferramenta completar com sucesso. Corresponde no nome da ferramenta, mesmos valores que PreToolUse.Entrada de PostToolUse
HooksPostToolUse disparam após uma ferramenta já ter executado com sucesso. A entrada inclui tanto tool_input, os argumentos enviados para a ferramenta, quanto tool_response, o resultado que retornou. O esquema exato para ambos depende da ferramenta.
Controle de decisão de PostToolUse
HooksPostToolUse podem fornecer feedback ao Claude após execução de ferramenta. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar esses campos específicos do evento:
O exemplo abaixo substitui a saída de uma chamada
Bash. O valor de substituição corresponde à forma de saída da ferramenta Bash:
PostToolUseFailure
Executa quando uma ferramenta que começou a executar falha: a ferramenta lançou um erro ou uma ferramenta MCP retornou um resultado de erro. Use isso para registrar falhas, enviar alertas ou fornecer feedback corretivo ao Claude. Corresponde no nome da ferramenta, mesmos valores que PreToolUse.Este evento não dispara para chamadas de ferramenta rejeitadas antes da execução: um nome de ferramenta desconhecido, entrada que falha na validação de esquema ou específica da ferramenta, ou uma negação de permissão. Rejeições de validação são retornadas como resultados
tool_use_error e acontecem antes dos hooks executarem, então eles não disparam nem PreToolUse nem este evento. Negações de permissão disparam PreToolUse mas não este evento; consulte PermissionDenied.Entrada de PostToolUseFailure
Hooks PostToolUseFailure recebem os mesmos campostool_name e tool_input que PostToolUse, junto com informações de erro como campos de nível superior:
Controle de decisão de PostToolUseFailure
HooksPostToolUseFailure podem fornecer contexto ao Claude após falha de ferramenta. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar esses campos específicos do evento:
PostToolBatch
Executa uma vez após cada chamada de ferramenta em um lote ter sido resolvida, antes do Claude Code enviar a próxima solicitação para o modelo.PostToolUse dispara uma vez por ferramenta, o que significa que dispara concorrentemente quando Claude faz chamadas de ferramenta paralelas. PostToolBatch dispara exatamente uma vez com o lote completo, então é o lugar certo para injetar contexto que depende do conjunto de ferramentas que executaram em vez de em qualquer ferramenta única. Não há matcher para este evento.
Entrada de PostToolBatch
Além dos campos de entrada comuns, hooks PostToolBatch recebemtool_calls, um array descrevendo cada chamada de ferramenta no lote:
tool_response contém o mesmo conteúdo que o modelo recebe no bloco tool_result correspondente. O valor é uma string serializada ou array de bloco de conteúdo, exatamente como a ferramenta o emitiu. Para Read, isso significa texto com prefixo de número de linha em vez de conteúdo de arquivo bruto. Respostas podem ser grandes, então analise apenas os campos que você precisa.
A forma
tool_response difere da de PostToolUse. PostToolUse passa o objeto Output estruturado da ferramenta, como {filePath: "...", success: true} para Write; PostToolBatch passa o conteúdo tool_result serializado que o modelo vê.Controle de decisão de PostToolBatch
HooksPostToolBatch podem injetar contexto para Claude. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar esses campos específicos do evento:
decision: "block" ou continue: false para o loop agentic antes da próxima chamada do modelo.
PermissionDenied
Executa quando o classificador de modo automático nega uma chamada de ferramenta. Este hook apenas dispara em modo automático: não executa quando você nega manualmente um diálogo de permissão, quando um hookPreToolUse bloqueia uma chamada ou quando uma regra deny corresponde. Use-o para registrar negações de classificador, ajustar configuração ou dizer ao modelo que pode tentar novamente a chamada de ferramenta.
Corresponde no nome da ferramenta, mesmos valores que PreToolUse.
Entrada de PermissionDenied
Além dos campos de entrada comuns, hooks PermissionDenied recebemtool_name, tool_input, tool_use_id e reason.
Controle de decisão de PermissionDenied
Hooks PermissionDenied podem dizer ao modelo que pode tentar novamente a chamada de ferramenta negada. Retorne um objeto JSON comhookSpecificOutput.retry definido para true:
retry é true, Claude Code adiciona uma mensagem à conversa dizendo ao modelo que pode tentar novamente a chamada de ferramenta. A negação em si não é revertida. Se seu hook não retorna JSON ou retorna retry: false, a negação permanece e o modelo recebe a mensagem de rejeição original.
Notification
Executa quando Claude Code envia notificações. Corresponde no tipo de notificação. Omita o matcher para executar hooks para todos os tipos de notificação.
Os tipos
agent_needs_input e agent_completed requerem Claude Code v2.1.198 ou posterior.
Use matchers separados para executar diferentes manipuladores dependendo do tipo de notificação. Esta configuração aciona um script de alerta específico de permissão quando Claude precisa de aprovação de permissão e uma notificação diferente quando Claude está ocioso:
Entrada de Notification
Além dos campos de entrada comuns, hooks Notification recebemmessage com o texto de notificação, um title opcional e notification_type indicando qual tipo disparou.
systemMessage se aplicam.
SubagentStart
Executa quando um subagente do Claude Code é gerado via ferramenta Agent. Suporta matchers para filtrar por nome de tipo de agente. Para agentes integrados, este é o nome do agente comogeneral-purpose, Explore ou Plan. Para subagentes personalizados, este é o campo name do frontmatter do agente, não o nome do arquivo.
Para subagentes fornecidos por um plugin, o tipo de agente é o identificador com escopo de plugin como my-plugin:reviewer, não o nome frontmatter simples. O dois-pontos coloca um nome com escopo de plugin no caminho de expressão regular, então ancorize o matcher com ^ e $ para uma correspondência exata: ^my-plugin:reviewer$.
Entrada de SubagentStart
Além dos campos de entrada comuns, hooks SubagentStart recebemagent_id com o identificador único para o subagente e agent_type com o nome do agente que o matcher filtra.
SubagentStop
Executa quando um subagente do Claude Code terminou de responder. Corresponde no tipo de agente, mesmos valores que SubagentStart.Entrada de SubagentStop
Além dos campos de entrada comuns, hooks SubagentStop recebemstop_hook_active, agent_id, agent_type, agent_transcript_path e last_assistant_message. O campo agent_type é o valor usado para filtragem de matcher. O transcript_path é a transcrição da sessão principal, enquanto agent_transcript_path é a própria transcrição do subagente armazenada em uma pasta subagents/ aninhada. O campo last_assistant_message contém o conteúdo de texto da resposta final do subagente, então hooks podem acessá-lo sem analisar o arquivo de transcrição.
Hooks SubagentStop também recebem os arrays background_tasks e session_crons descritos em Entrada de Stop, disponíveis no Claude Code v2.1.145 ou posterior. Ambos os arrays têm escopo para a sessão pai, não para o subagente.
hookSpecificOutput.additionalContext com hookEventName definido para "SubagentStop", para feedback não-erro que mantém o subagente em execução. Retornar decision: "block" com uma reason mantém o subagente em execução e entrega reason ao subagente como sua próxima instrução. Para injetar contexto na sessão pai após um subagente retornar, use um hook PostToolUse na ferramenta Agent em vez disso.
TaskCreated
Executa quando uma tarefa está sendo criada via ferramentaTaskCreate. Use isso para impor convenções de nomenclatura, exigir descrições de tarefa ou prevenir que certas tarefas sejam criadas.
Quando um hook TaskCreated sai com código 2, a tarefa não é criada e a mensagem de stderr é alimentada de volta ao modelo como feedback. Para parar o colega inteiramente em vez de re-executá-lo, retorne JSON com {"continue": false, "stopReason": "..."}. Hooks TaskCreated não suportam matchers e disparam em cada ocorrência.
Entrada de TaskCreated
Além dos campos de entrada comuns, hooks TaskCreated recebemtask_id, task_subject e opcionalmente task_description, teammate_name e team_name.
Controle de decisão de TaskCreated
Hooks TaskCreated suportam duas formas de controlar criação de tarefa:- Código de saída 2: a tarefa não é criada e a mensagem de stderr é alimentada de volta ao modelo como feedback.
- JSON
{"continue": false, "stopReason": "..."}: para o colega inteiramente, correspondendo ao comportamento do hookStop. OstopReasoné mostrado ao usuário.
TaskCompleted
Executa quando uma tarefa está sendo marcada como concluída. Isso dispara em duas situações: quando qualquer agente marca explicitamente uma tarefa como concluída através da ferramenta TaskUpdate, ou quando um colega de equipe de agente termina seu turno com tarefas em progresso. Use isso para impor critérios de conclusão como testes aprovados ou verificações de lint antes de uma tarefa fechar. Quando um hookTaskCompleted sai com código 2, a tarefa não é marcada como concluída e a mensagem de stderr é alimentada de volta ao modelo como feedback. Para parar o colega inteiramente em vez de re-executá-lo, retorne JSON com {"continue": false, "stopReason": "..."}. Hooks TaskCompleted não suportam matchers e disparam em cada ocorrência.
Entrada de TaskCompleted
Além dos campos de entrada comuns, hooks TaskCompleted recebemtask_id, task_subject e opcionalmente task_description, teammate_name e team_name.
Controle de decisão de TaskCompleted
Hooks TaskCompleted suportam duas formas de controlar conclusão de tarefa:- Código de saída 2: a tarefa não é marcada como concluída e a mensagem de stderr é alimentada de volta ao modelo como feedback.
- JSON
{"continue": false, "stopReason": "..."}: para o colega inteiramente, correspondendo ao comportamento do hookStop. OstopReasoné mostrado ao usuário.
Stop
Executa quando o agente Claude Code principal terminou de responder. Não executa se a parada ocorreu devido a uma interrupção do usuário. Erros de API disparam StopFailure em vez disso.Entrada de Stop
Além dos campos de entrada comuns, hooks Stop recebemstop_hook_active, last_assistant_message, background_tasks e session_crons. O campo stop_hook_active é true quando Claude Code já está continuando como resultado de um hook stop. Verifique este valor ou processe a transcrição para prevenir que Claude Code execute indefinidamente. Claude Code sobrescreve o hook e termina o turno após 8 bloqueios consecutivos.
O campo last_assistant_message contém o conteúdo de texto da resposta final de Claude, então hooks podem acessá-lo sem analisar o arquivo de transcrição. Para hooks que atuam no turno recém-concluído, como hooks de leitura em voz alta ou notificação, use este campo em vez de ler transcript_path: o arquivo de transcrição não é garantido incluir a mensagem final no tempo de Stop em todas as versões.
Os arrays background_tasks e session_crons, disponíveis no Claude Code v2.1.145 ou posterior, permitem que hooks distingam “sessão está feita” de “sessão está pausada esperando que trabalho em background a acorde novamente”. Ambos os arrays estão presentes quando o registro de tarefas é alcançável e estão vazios quando nada está em voo ou agendado.
Cada entrada em background_tasks descreve uma tarefa em voo e usa esses campos:
Cada entrada em
session_crons descreve um despertar agendado com escopo de sessão, originário de CronCreate, ScheduleWakeup e /loop:
Este exemplo mostra uma entrada de Stop com uma tarefa shell em voo e um cron recorrente:
Controle de decisão de Stop
HooksStop e SubagentStop podem controlar se Claude continua. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar esses campos específicos do evento:
additionalContext quando o hook está funcionando como projetado e dando orientação a Claude, como “execute a suite de testes antes de terminar”. Mantém a conversa indo através das mesmas proteções de loop que decision: "block", a saber a entrada stop_hook_active e o limite de 8 continuações consecutivas, mas a transcrição a rotula como Stop hook feedback e nenhuma notificação de erro de hook é mostrada:
StopFailure
Executa em vez de Stop quando o turno termina devido a um erro de API. Saída e código de saída são ignorados. Use isso para registrar falhas, enviar alertas ou tomar ações de recuperação quando Claude não consegue completar uma resposta devido a limites de taxa, problemas de autenticação ou outros erros de API.Entrada de StopFailure
Além dos campos de entrada comuns, hooks StopFailure recebemerror, error_details opcional e last_assistant_message opcional. O campo error identifica o tipo de erro e é usado para filtragem de matcher.
TeammateIdle
Executa quando um colega de equipe de agente está prestes a ficar ocioso após terminar seu turno. Use isso para impor portões de qualidade antes de um colega parar de trabalhar, como exigir verificações de lint aprovadas ou verificar que arquivos de saída existem. Quando um hookTeammateIdle sai com código 2, o colega recebe a mensagem de stderr como feedback e continua trabalhando em vez de ficar ocioso. Para parar o colega inteiramente em vez de re-executá-lo, retorne JSON com {"continue": false, "stopReason": "..."}. Hooks TeammateIdle não suportam matchers e disparam em cada ocorrência.
Entrada de TeammateIdle
Além dos campos de entrada comuns, hooks TeammateIdle recebemteammate_name e team_name.
Controle de decisão de TeammateIdle
Hooks TeammateIdle suportam duas formas de controlar comportamento de colega:- Código de saída 2: o colega recebe a mensagem de stderr como feedback e continua trabalhando em vez de ficar ocioso.
- JSON
{"continue": false, "stopReason": "..."}: para o colega inteiramente, correspondendo ao comportamento do hookStop. OstopReasoné mostrado ao usuário.
ConfigChange
Executa quando um arquivo de configuração muda durante uma sessão. Use isso para auditar mudanças de configurações, impor políticas de segurança ou bloquear modificações não autorizadas a arquivos de configuração. Hooks ConfigChange disparam para mudanças em arquivos de configurações, configurações de política gerenciada e arquivos de skill. O camposource na entrada diz qual tipo de configuração mudou, e o campo file_path opcional fornece o caminho para o arquivo mudado.
O matcher filtra na fonte de configuração:
Este exemplo registra todas as mudanças de configuração para auditoria de segurança:
Entrada de ConfigChange
Além dos campos de entrada comuns, hooks ConfigChange recebemsource e opcionalmente file_path. O campo source indica qual tipo de configuração mudou, e file_path fornece o caminho para o arquivo específico que foi modificado.
Controle de decisão de ConfigChange
Hooks ConfigChange podem bloquear mudanças de configuração de entrar em efeito. Use código de saída 2 ou um JSONdecision para prevenir a mudança. Quando bloqueado, as novas configurações não são aplicadas à sessão em execução.
policy_settings não podem ser bloqueadas. Hooks ainda disparam para fontes policy_settings, então você pode usá-los para logging de auditoria, mas qualquer decisão de bloqueio é ignorada. Isso garante que configurações gerenciadas por empresa sempre entrem em efeito.
CwdChanged
Executa quando o diretório de trabalho muda durante uma sessão, por exemplo quando Claude executa um comandocd. Use isso para reagir a mudanças de diretório: recarregar variáveis de ambiente, ativar toolchains específicas do projeto ou executar scripts de configuração automaticamente. Emparelha com FileChanged para ferramentas como direnv que gerenciam ambiente por diretório.
Hooks CwdChanged têm acesso a CLAUDE_ENV_FILE. Variáveis escritas para esse arquivo persistem em comandos Bash subsequentes para a sessão, assim como em hooks SessionStart.
CwdChanged não suporta matchers e dispara em cada mudança de diretório.
Entrada de CwdChanged
Além dos campos de entrada comuns, hooks CwdChanged recebemold_cwd e new_cwd.
Saída de CwdChanged
Além dos campos de saída JSON disponíveis para todos os hooks, hooks CwdChanged podem retornarwatchPaths para definir dinamicamente quais caminhos de arquivo FileChanged monitora:
Hooks CwdChanged não têm controle de decisão. Eles não podem bloquear a mudança de diretório.
FileChanged
Executa quando um arquivo monitorado muda no disco. Útil para recarregar variáveis de ambiente quando arquivos de configuração do projeto são modificados. Omatcher para este evento serve dois papéis:
- Construir a lista de monitoramento: o valor é dividido em
|e cada segmento é registrado como um nome de arquivo literal no diretório de trabalho, então".envrc|.env"monitora exatamente esses dois arquivos. Padrões regex não são úteis aqui: um valor como^\.envmonitoraria um arquivo literalmente nomeado^\.env. - Filtrar quais hooks executam: quando um arquivo monitorado muda, o mesmo valor filtra quais grupos de hook executam usando as regras de matcher padrão contra o basename do arquivo alterado.
CLAUDE_ENV_FILE. Variáveis escritas para esse arquivo persistem em comandos Bash subsequentes para a sessão, assim como em hooks SessionStart.
Entrada de FileChanged
Além dos campos de entrada comuns, hooks FileChanged recebemfile_path e event.
Saída de FileChanged
Além dos campos de saída JSON disponíveis para todos os hooks, hooks FileChanged podem retornarwatchPaths para atualizar dinamicamente quais caminhos de arquivo são monitorados:
Hooks FileChanged não têm controle de decisão. Eles não podem bloquear a mudança de arquivo de ocorrer.
WorktreeCreate
Executa quando um worktree está sendo criado, seja declaude --worktree ou de um subagente usando isolation: "worktree". Por padrão Claude Code cria a cópia de trabalho isolada com git worktree. Configurar um hook WorktreeCreate substitui esse comportamento git padrão, permitindo que você use um sistema de controle de versão diferente como SVN, Perforce ou Mercurial.
Porque o hook substitui o comportamento padrão inteiramente, .worktreeinclude não é processado. Se você precisar copiar arquivos de configuração local como .env para o novo worktree, faça isso dentro de seu script de hook.
O hook deve retornar o caminho para o diretório worktree criado. Claude Code usa este caminho como o diretório de trabalho para a sessão isolada. Consulte Saída de WorktreeCreate para como cada tipo de hook retorna o caminho.
Este exemplo cria uma cópia de trabalho SVN e imprime o caminho para Claude Code usar. Substitua a URL do repositório pela sua:
name do worktree da entrada JSON em stdin, verifica uma cópia fresca em um novo diretório e imprime o caminho do diretório. O echo na última linha é o que Claude Code lê como o caminho do worktree. Redirecione qualquer outra saída para stderr para que não interfira com o caminho.
Entrada de WorktreeCreate
Além dos campos de entrada comuns, hooks WorktreeCreate recebem o camponame. Este é um identificador slug para o novo worktree, especificado pelo usuário ou auto-gerado, por exemplo bold-oak-a3f2.
Saída de WorktreeCreate
Hooks WorktreeCreate não usam o modelo de decisão permitir/bloquear padrão. Em vez disso, o sucesso ou falha do hook determina o resultado. O hook deve retornar o caminho para o diretório worktree criado:- Hooks de comando (
type: "command"): imprimem o caminho como a última linha não-vazia de stdout. Claude Code remove códigos de escape ANSI antes de ler essa linha, então banners de inicialização de shell impressos antes de seuechosão ignorados. Redirecione qualquer outra saída de hook para stderr. - Hooks HTTP (
type: "http"): retornam{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }no corpo da resposta.
-p ela ficava parada por cerca de 30 segundos antes de sair com código 0.
WorktreeRemove
Executa quando um worktree está sendo removido, seja quando você sai de uma sessão--worktree e escolhe removê-lo, ou quando um subagente com isolation: "worktree" termina. Esta é a contraparte de limpeza para WorktreeCreate.
Para worktrees baseados em git, Claude Code lida com limpeza automaticamente com git worktree remove. Se você configurou um hook WorktreeCreate para um sistema de controle de versão não-git, emparelhe-o com um hook WorktreeRemove para lidar com limpeza. Sem um, o diretório worktree é deixado no disco.
Claude Code passa o caminho que WorktreeCreate retornou como worktree_path na entrada do hook. Este exemplo lê esse caminho e remove o diretório:
Entrada de WorktreeRemove
Além dos campos de entrada comuns, hooks WorktreeRemove recebem o campoworktree_path, que é o caminho absoluto para o worktree sendo removido.
PreCompact
Executa antes do Claude Code estar prestes a executar uma operação de compactação. O valor do matcher indica se a compactação foi acionada manualmente ou automaticamente:
Saia com código 2 para bloquear compactação. Para um
/compact manual, a mensagem de stderr é mostrada ao usuário. Você também pode bloquear retornando JSON com "decision": "block".
Bloquear compactação automática tem efeitos diferentes dependendo de quando dispara. Se a compactação foi acionada proativamente antes do limite de contexto, Claude Code a ignora e a conversa continua não compactada. Se a compactação foi acionada para recuperar de um erro de limite de contexto já retornado pela API, o erro subjacente superficializa e a solicitação atual falha.
Entrada de PreCompact
Além dos campos de entrada comuns, hooks PreCompact recebemtrigger e custom_instructions. Para manual, custom_instructions contém o que o usuário passa para /compact. Para auto, custom_instructions está vazio.
PostCompact
Executa após Claude Code completar uma operação de compactação. Use este evento para reagir ao novo estado compactado, por exemplo para registrar o resumo gerado ou atualizar estado externo. Os mesmos valores de matcher se aplicam como paraPreCompact:
Entrada de PostCompact
Além dos campos de entrada comuns, hooks PostCompact recebemtrigger e compact_summary. O campo compact_summary contém o resumo de conversa gerado pela operação de compactação.
SessionEnd
Executa quando uma sessão do Claude Code termina. Útil para tarefas de limpeza, logging de estatísticas de sessão ou salvamento de estado de sessão. Suporta matchers para filtrar por razão de saída. O camporeason na entrada do hook indica por que a sessão terminou:
Entrada de SessionEnd
Além dos campos de entrada comuns, hooks SessionEnd recebem um camporeason indicando por que a sessão terminou. Consulte a tabela de razão acima para todos os valores.
/clear e alternância de sessões via /resume interativo. Se um hook precisa de mais tempo, defina um timeout por hook na configuração do hook. O orçamento geral é automaticamente aumentado para o timeout por hook mais alto configurado em arquivos de configurações, até 60 segundos. Timeouts definidos em hooks fornecidos por plugin não aumentam o orçamento. Para sobrescrever o orçamento explicitamente, defina a variável de ambiente CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS em milissegundos.
Elicitation
Executa quando um servidor MCP solicita entrada do usuário no meio da tarefa. Por padrão, Claude Code mostra um diálogo interativo para o usuário responder. Hooks podem interceptar esta solicitação e responder programaticamente, pulando o diálogo inteiramente. O campo matcher corresponde ao nome do servidor MCP.Entrada de Elicitation
Além dos campos de entrada comuns, hooks Elicitation recebemmcp_server_name, message e campos opcionais mode, url, elicitation_id e requested_schema.
Para elicitação em modo de formulário (o caso mais comum):
Saída de Elicitation
Para responder programaticamente sem mostrar o diálogo, retorne um objeto JSON comhookSpecificOutput:
Código de saída 2 nega a elicitação e mostra stderr ao usuário.
ElicitationResult
Executa após um usuário responder a uma elicitação MCP. Hooks podem observar, modificar ou bloquear a resposta antes de ser enviada de volta ao servidor MCP. O campo matcher corresponde ao nome do servidor MCP.Entrada de ElicitationResult
Além dos campos de entrada comuns, hooks ElicitationResult recebemmcp_server_name, action e campos opcionais mode, elicitation_id e content.
Saída de ElicitationResult
Para sobrescrever a resposta do usuário, retorne um objeto JSON comhookSpecificOutput:
Código de saída 2 bloqueia a resposta, mudando a ação efetiva para
decline.
Hooks baseados em prompt
Além de hooks de comando, HTTP e MCP tool, Claude Code suporta hooks baseados em prompt (type: "prompt") que usam um LLM para avaliar se deve permitir ou bloquear uma ação, e hooks de agente (type: "agent") que geram um verificador agentic com acesso a ferramentas. Nem todos os eventos suportam cada tipo de hook.
Eventos que suportam todos os cinco tipos de hook (command, http, mcp_tool, prompt e agent):
PermissionDeniedPermissionRequestPostToolBatchPostToolUsePostToolUseFailurePreToolUseStopSubagentStopTaskCompletedTaskCreatedTeammateIdleUserPromptExpansionUserPromptSubmit
command, http e mcp_tool mas não prompt ou agent:
ConfigChangeCwdChangedElicitationElicitationResultFileChangedInstructionsLoadedNotificationPostCompactPreCompactSessionEndStopFailureSubagentStartWorktreeCreateWorktreeRemove
SessionStart e Setup suportam hooks command e mcp_tool. Eles não suportam hooks http, prompt ou agent.
Como hooks baseados em prompt funcionam
Em vez de executar um comando Bash, hooks baseados em prompt:- Enviam a entrada do hook e seu prompt para um modelo Claude, Haiku por padrão
- O LLM responde com JSON estruturado contendo uma decisão
- Claude Code processa a decisão automaticamente
Configuração de hook de prompt
Definatype para "prompt" e forneça uma string prompt em vez de um command. Use o placeholder $ARGUMENTS para injetar dados de entrada do hook em seu texto de prompt. Claude Code envia o prompt combinado e entrada para um modelo Claude rápido, que retorna uma decisão JSON.
Este hook Stop pede ao LLM para avaliar se todas as tarefas estão completas antes de permitir que Claude termine:
Esquema de resposta
O LLM deve responder com JSON contendo:
O que acontece em
ok: false depende do evento:
StopeSubagentStop: a razão é alimentada de volta para Claude como sua próxima instrução e o turno continuaPreToolUse: a chamada de ferramenta é negada e a razão é retornada a Claude como o erro da ferramenta, equivalente a um hook de comando compermissionDecision: "deny"PostToolUse: por padrão o turno termina e a razão aparece no chat como uma linha de aviso. DefinacontinueOnBlock: truepara alimentar a razão de volta para Claude e continuar o turno em vez dissoPostToolBatch,UserPromptSubmiteUserPromptExpansion: o turno termina e a razão aparece como uma linha de aviso. Esses eventos terminam o turno emdecision: "block"independentemente decontinuePostToolUseFailure,TaskCreatedeTaskCompleted: a razão é retornada a Claude como um erro de ferramenta, similar aPreToolUseTeammateIdle: por padrão o colega para e a razão aparece como uma linha de aviso. DefinacontinueOnBlock: truepara alimentar a razão de volta para o colega e mantê-lo trabalhando em vez dissoPermissionRequest:ok: falsenão tem efeito. Para negar uma aprovação de um hook, use um hook de comando retornandohookSpecificOutput.decision.behavior: "deny"PermissionDenied:ok: falsenão tem efeito porque a negação já aconteceu. A única saída que este evento lê éhookSpecificOutput.retry, que hooks de prompt e agente não podem definir — eles são executados neste evento, mas sua saída é descartada. Use um hook de comando para retornarretry
Verificar múltiplas condições antes de parar
Este hookStop usa um prompt detalhado para verificar três condições antes de permitir que Claude pare. Hooks SubagentStop usam o mesmo formato para avaliar se um subagente deve parar. Se "ok" for false, Claude continua trabalhando com a razão fornecida como sua próxima instrução:
Hooks baseados em agente
Hooks baseados em agente (type: "agent") são como hooks baseados em prompt mas com acesso a ferramentas de múltiplos turnos. Em vez de uma única chamada LLM, um hook de agente gera um subagente que pode ler arquivos, pesquisar código e inspecionar o codebase para verificar condições. Hooks de agente suportam os mesmos eventos que hooks baseados em prompt.
Como hooks de agente funcionam
Quando um hook de agente dispara:- Claude Code gera um subagente com seu prompt e a entrada JSON do hook
- O subagente pode usar ferramentas como Read, Grep e Glob para investigar
- Após até 50 turnos, o subagente retorna uma decisão estruturada
{ "ok": true/false } - Claude Code processa a decisão da mesma forma que um hook de prompt
Configuração de hook de agente
Definatype para "agent" e forneça uma string prompt. Os campos de configuração são os mesmos que hooks de prompt, com um timeout padrão mais longo:
O esquema de resposta é o mesmo que hooks de prompt:
{ "ok": true } para permitir ou { "ok": false, "reason": "..." } para bloquear.
Este hook Stop verifica que todos os testes unitários passam antes de permitir que Claude termine:
Executar hooks em background
Por padrão, hooks bloqueiam a execução de Claude até que completem. Para tarefas de longa duração como deployments, suites de teste ou chamadas de API externas, defina"async": true para executar o hook em background enquanto Claude continua trabalhando. Hooks assíncronos não podem bloquear ou controlar comportamento de Claude: campos de resposta como decision, permissionDecision e continue não têm efeito, porque a ação que controlariam já completou.
Configurar um hook assíncrono
Adicione"async": true à configuração de um hook de comando para executá-lo em background sem bloquear Claude. Este campo está apenas disponível em hooks type: "command".
Este hook executa um script de teste após cada chamada de ferramenta Write. Claude continua trabalhando imediatamente enquanto run-tests.sh executa por até 120 segundos. Quando o script termina, sua saída é entregue no próximo turno de conversa:
timeout define o tempo máximo em segundos para o processo em background. Se não especificado, hooks assíncronos usam o mesmo padrão de 10 minutos que hooks síncronos.
Como hooks assíncronos executam
Quando um hook assíncrono dispara, Claude Code inicia o processo do hook e imediatamente continua sem esperar que termine. O hook recebe a mesma entrada JSON via stdin que um hook síncrono. Após o processo em background sair, se o hook produziu uma resposta JSON com um campoadditionalContext, esse conteúdo é entregue ao Claude como contexto no próximo turno de conversa. Um campo systemMessage é mostrado para você, não para Claude.
Claude Code valida que a resposta JSON contra o mesmo esquema de saída que hooks síncronos, e descarta qualquer campo cujo valor tenha o tipo errado, como um systemMessage que não seja uma string, em vez de entregá-lo. Execute com --debug para ver um aviso nomeando cada campo descartado. Antes da v2.1.202, saída JSON malformada de um hook assíncrono poderia travar a sessão, e a falha recorria cada vez que a sessão era retomada.
Notificações de conclusão de hook assíncrono são suprimidas por padrão. Para vê-las, ative modo verbose com Ctrl+O ou inicie Claude Code com --verbose.
Executar testes após mudanças de arquivo
Este hook inicia uma suite de testes em background sempre que Claude escreve um arquivo, então relata os resultados de volta ao Claude quando os testes terminam. Salve este script em.claude/hooks/run-tests-async.sh em seu projeto e torne-o executável com chmod +x:
.claude/settings.json na raiz do seu projeto. A flag async: true permite que Claude continue trabalhando enquanto testes executam:
Limitações
Hooks assíncronos têm várias restrições comparados a hooks síncronos:- Apenas hooks
type: "command"suportamasync. Hooks baseados em prompt não podem executar assincronamente. - Hooks assíncronos não podem bloquear chamadas de ferramenta ou retornar decisões. Pelo tempo que o hook completa, a ação acionadora já prosseguiu.
- Saída de hook é entregue no próximo turno de conversa. Se a sessão está ociosa, a resposta espera até a próxima interação do usuário. Exceção: um hook
asyncRewakeque sai com código 2 acorda Claude imediatamente mesmo quando a sessão está ociosa. - Cada execução cria um processo em background separado. Não há desduplicação através de múltiplos disparos do mesmo hook assíncrono.
Considerações de segurança
Aviso
Hooks de comando executam com as permissões completas do seu usuário do sistema.Melhores práticas de segurança
Mantenha essas práticas em mente ao escrever hooks:- Valide e sanitize entradas: nunca confie em dados de entrada cegamente
- Sempre cite variáveis shell: use
"$VAR"não$VAR - Bloqueie traversal de caminho: verifique
..em caminhos de arquivo - Use caminhos absolutos: especifique caminhos completos para scripts. Na forma exec, use
${CLAUDE_PROJECT_DIR}e o caminho não precisa de aspas. Na forma shell, envolva-o em aspas duplas - Pule arquivos sensíveis: evite
.env,.git/, chaves, etc.
Ferramenta Windows PowerShell
No Windows, você pode executar hooks individuais em PowerShell definindo"shell": "powershell" em um hook de comando. Hooks geram PowerShell diretamente, então isso funciona independentemente de CLAUDE_CODE_USE_POWERSHELL_TOOL estar definido. Claude Code auto-detecta pwsh.exe, o executável do PowerShell 7 e posterior, e volta para powershell.exe para Windows PowerShell 5.1.
${CLAUDE_PROJECT_DIR} ou $env:CLAUDE_PROJECT_DIR. A partir da v2.1.198, Claude Code reescreve os espaços reservados ${CLAUDE_PROJECT_DIR}, ${CLAUDE_PLUGIN_ROOT} e ${CLAUDE_PLUGIN_DATA} em um comando em forma de shell do PowerShell para a forma ${env:NAME} do PowerShell, independentemente de o hook estar definido em settings.json, um plugin ou uma skill. PowerShell então resolve o valor do ambiente exportado após análise, então o espaço reservado funciona dentro de strings entre aspas duplas, mas não dentro de strings entre aspas simples, onde PowerShell nunca expande variáveis.
Antes da v2.1.198, essa reescrita se aplicava apenas a hooks de plugin. Em versões anteriores, um hook settings.json precisa da forma $env: ou forma exec, onde ${CLAUDE_PROJECT_DIR} é substituído em cada elemento args independentemente de onde o hook está definido.
Não escreva a forma nua $CLAUDE_PROJECT_DIR em um hook do PowerShell. PowerShell a analisa como uma variável local indefinida e a resolve para $null, o que deixa o caminho do script sem seu prefixo de diretório raiz do projeto. Claude Code não reescreve essa forma; em vez disso, registra um aviso no log de depuração.
O exemplo abaixo mostra um hook settings.json que executa um script de projeto com a forma $env:, que funciona em todas as versões:
Debug de hooks
Detalhes de execução de hook, incluindo quais hooks corresponderam, seus códigos de saída e saída completa de stdout e stderr, são escritos no arquivo de log de debug. Inicie Claude Code comclaude --debug-file <path> para escrever o log em um local conhecido, ou execute claude --debug e leia o log em ~/.claude/debug/<session-id>.txt. A flag --debug não imprime no terminal.
CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose para ver linhas de log adicionais como contagens de matcher de hook e correspondência de consulta.
Para troubleshooting de problemas comuns como hooks não disparando, Stop hooks que continuam bloqueando, ou erros de configuração, consulte Limitações e troubleshooting no guia. Para um passo a passo de diagnóstico mais amplo cobrindo /context, /doctor e precedência de configurações, consulte Debug your config.