Hooks do Cursor: guia completo e por que às vezes eles não disparam

Os hooks do Cursor permitem que um script observe ou bloqueie o que o agente faz: cada comando de shell, chamada MCP, leitura e edição de arquivo. Eles são poderosos e falham de forma silenciosa. Aqui está tudo o que aprendemos ao configurá-los de verdade.

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

RESPOSTA CURTA

Coloque um hooks.json com "version": 1 em ~/.cursor/ (todos os projetos) ou em .cursor/ dentro de um repositório, aponte cada evento para um comando e imprima JSON no stdout. Use beforeShellExecution e beforeMCPExecution para permitir, negar ou perguntar, e defina failClosed: true se um hook quebrado precisar bloquear em vez de deixar o comando passar. Quando um hook parecer ignorado, abra primeiro o canal de saída Hooks: a maioria dos problemas é um caminho, um workspace que não é confiável, JSON inválido ou um evento que a Cursor CLI ainda não envia.

O que são os hooks do Cursor

Um hook é um comando que o Cursor executa em um ponto fixo do loop do agente. O Cursor envia pela entrada padrão do comando um objeto JSON descrevendo o que está prestes a acontecer, espera e lê uma resposta JSON da saída padrão. Alguns hooks só observam (registram a edição, formatam o arquivo). Outros decidem: um hook beforeShellExecution pode deixar um comando rodar, impedi-lo ou perguntar a você antes.

Isso faz dos hooks a ferramenta certa para três tarefas: proteções (nunca executar rm -rf ou git push --force sem um humano), automação (formatar ou rodar o lint depois de cada edição) e visibilidade (registrar ou encaminhar o que o agente faz para você saber quando ele precisa de você).

Onde fica o hooks.json

O Cursor lê hooks de quatro lugares e executa todos eles. Todos os hooks correspondentes de todas as fontes rodam, e o Cursor combina as respostas.

NívelArquivoObservações
Usuário~/.cursor/hooks.jsonVale para todos os projetos. Comandos relativos são resolvidos a partir de ~/.cursor/.
Projeto<project>/.cursor/hooks.jsonVersionado no repositório. Só roda em um workspace confiável. Comandos relativos são resolvidos a partir da raiz do projeto.
EquipePainel web do CursorApenas Enterprise, sincronizado com todos os membros.
EnterpriseC:\ProgramData\Cursor\hooks.json (Windows), /Library/Application Support/Cursor/hooks.json (macOS), /etc/cursor/hooks.json (Linux, WSL)Gerenciado pela TI.

Quando as respostas divergem, vence a mais restritiva: um deny de qualquer fonte vence ask, e ask vence allow. O menor arquivo funcional é assim (é o exemplo da documentação do Cursor):

~/.cursor/hooks.jsonCopiar
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": "./hooks/format.sh" }]
}
}

version precisa ser 1. O Cursor monitora o arquivo e o recarrega quando você salva. Se uma alteração não fizer efeito, reinicie o Cursor. Só isso resolve um número surpreendente de relatos no fórum.

Os eventos que você pode interceptar

A lista atual da documentação do Cursor, agrupada pela finalidade:

GrupoEventosPode bloquear?
Shell e MCPbeforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecutionOs dois hooks before…: permitir, negar ou perguntar
Qualquer ferramentapreToolUse, postToolUse, postToolUseFailurepreToolUse: permitir ou negar (ask não é aplicado hoje)
ArquivosbeforeReadFile, afterFileEditbeforeReadFile: permitir ou negar
PromptbeforeSubmitPromptSim, com continue: false
Loop do agentestop, afterAgentResponse, afterAgentThought, preCompactNão (stop pode enviar uma mensagem de acompanhamento)
SubagentessubagentStart, subagentStopsubagentStart: permitir ou negar (ask conta como deny)
Sessão e appsessionStart, sessionEnd, workspaceOpenNão
Sugestões do TabbeforeTabFileRead, afterTabFileEditbeforeTabFileRead: permitir ou negar

Todo evento recebe alguns campos comuns (conversation_id, generation_id, model, hook_event_name, cursor_version, workspace_roots) além dos seus próprios. beforeShellExecution recebe o command completo e seu cwd; stop recebe um status com o valor completed, aborted ou error.

Permitir, negar e perguntar

Um hook que decide imprime um objeto JSON. Para o hook de shell, fica assim:

stdout de um hook beforeShellExecutionCopiar
{
"permission": "ask",
"user_message": "This pushes to main. Run it?",
"agent_message": "The user wants to confirm pushes."
}
  • permission é allow, deny ou ask.
  • user_message é o que você vê no Cursor.
  • agent_message é o que o agente recebe, para que ele mude de rumo em vez de tentar o mesmo comando de novo.

Os códigos de saída importam tanto quanto o JSON. Sair com 0 significa “use meu JSON”. Sair com 2 bloqueia a ação, assim como deny. Qualquer outro código de saída é tratado como hook com falha, e a ação segue em frente, a menos que você defina failClosed. Em hooks de permissão, JSON inválido ou fora do esquema bloqueia a ação.

A documentação do Cursor indica ask como suportado em beforeShellExecution e beforeMCPExecution. Em março de 2026, a equipe do Cursor escreveu no fórum que os hooks só aplicavam deny e que allow e ask eram “basically ignored” (basicamente ignorados), principalmente com a lista de permissões de comandos ou o sandbox ativados. Não encontramos nenhum anúncio de correção. Se uma proteção precisa funcionar, retorne deny, não ask, e teste na sua própria versão.

failClosed e timeout

Cada entrada de hook pode ter opções ao lado de command:

.cursor/hooks.jsonCopiar
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": "./.cursor/hooks/guard.sh",
"timeout": 30,
"failClosed": true
}
]
}
}
  • failClosed: true transforma uma falha, um timeout, uma saída diferente de zero ou uma saída vazia em bloqueio. O padrão é false: uma proteção quebrada deixa tudo passar em silêncio. Para um hook de segurança, você quase sempre quer true.
  • timeout é em segundos. Deixe folga suficiente se o seu hook espera por um humano: uma pessoa lendo um diff precisa de mais de cinco segundos.
  • matcher filtra quando o hook roda. Em hooks de shell, ele é comparado com a string completa do comando; em hooks de ferramenta, com o tipo da ferramenta, como Shell, Read, Write ou MCP:<tool_name>.

Há uma contrapartida. Em julho de 2026, um usuário de macOS deu de cara com “MainThreadShellExec not initialized”: o host de shell do próprio Cursor não estava pronto e, como o hook era fail-closed, o shell do agente ficou bloqueado. A equipe do Cursor disse que a correção já tinha sido lançada e recomendou manter failClosed: true. Se você vir esse erro em uma build mais antiga, a solução paliativa era “Developer: Reload Window”.

Hooks no Windows

No Windows, o app desktop do Cursor executa os comandos de hook pelo PowerShell e passa o JSON por pipe. Um script PowerShell o lê de $input; qualquer outro programa lê a entrada padrão normalmente. Três coisas costumam dar problema:

  1. Scripts bash não rodam como estão. Um guard.sh de um colega de macOS falha no PowerShell. Use um script .ps1, um programa compilado ou chame o interpretador explicitamente (python .cursor/hooks/guard.py). Um tópico do fórum de janeiro de 2026 mostra uma configuração com Git Bash falhando com syntax error near unexpected token '[Convert]::FromBase64String', ou seja, código PowerShell chegando ao bash.
  2. Política de execução. Se o PowerShell se recusar a executar scripts, inicie-os com powershell -NoProfile -ExecutionPolicy Bypass -File …, imprima o JSON e termine com exit 0.
  3. Programas GUI retornam cedo demais. Este nos custou um dia. Se o seu hook é um programa Windows compilado para o subsistema GUI, o PowerShell o inicia e segue em frente sem esperar. O Cursor lê uma saída vazia, então parece que o hook não fez nada (ou, com failClosed, bloqueia tudo). Compile o hook como programa de console ou encapsule-o para que o PowerShell espere ele terminar.

Hooks de projeto também precisam de um workspace confiável. Um membro da equipe do Cursor listou o que verificar quando eles não fazem nada: a linha de log de Hooks “Hook N produced no output”, Settings → Hooks mostrando o workspace como confiável e erros como spawn, ENOENT, EPERM ou ExecutionPolicy no console.

Hooks na Cursor CLI

A Cursor CLI (cursor-agent) lê os mesmos ~/.cursor/hooks.json e .cursor/hooks.json, mas nunca enviou todos os eventos que o editor envia. Em janeiro de 2026, só os dois hooks de shell disparavam. Em abril, a equipe do Cursor confirmou que beforeShellExecution, afterShellExecution, afterFileEdit, postToolUse, stop e sessionStart funcionavam na CLI, enquanto afterAgentResponse e afterAgentThought ainda não (confirmado de novo em maio). Para qualquer evento fora dessa lista, teste antes de depender dele.

Os cloud agents são ainda mais restritos: hooks de usuário de ~/.cursor/hooks.json simplesmente não rodam lá.

Quando um hook não dispara: checklist

  1. Abra o canal de saída Hooks (View → Output → Hooks) ou a aba Hooks em Customize. Ele mostra quais hooks foram carregados, cada execução e os erros.
  2. Confira o próprio arquivo JSON. "version": 1 presente, nomes de eventos escritos exatamente (eles diferenciam maiúsculas de minúsculas), JSON válido.
  3. Confira o caminho. Comandos relativos são resolvidos a partir da raiz do projeto em hooks de projeto e a partir de ~/.cursor/ em hooks de usuário.
  4. Confie no workspace. Hooks de projeto não rodam em uma pasta não confiável.
  5. Execute o hook manualmente. Passe um JSON de exemplo pelo pipe e olhe o stdout. Qualquer coisa além de um único objeto JSON (um echo perdido, um aviso) quebra o parsing.
  6. Reinicie o Cursor. Salvar recarrega o arquivo, mas vários relatos do fórum só foram resolvidos com uma reinicialização completa.
  7. Conheça as lacunas. Há relatos de ask e allow ignorados junto com a lista de permissões e o sandbox; de subagentStart/subagentStop sem disparar em algumas versões; e a CLI pula alguns eventos. Commits feitos pelo painel Source Control integrado não são interceptados: não existe evento de hook pre-commit.

Hooks, auto-run e Auto-review

Os hooks são separados das configurações de aprovação do próprio Cursor (Settings → Agents → Approvals & Execution). O auto-run e o Auto-review decidem se o Cursor pergunta a você no painel dele; seu hook adiciona a própria decisão por cima. É por isso que “meu hook disse ask, mas o comando simplesmente rodou” é um relato tão comum: outro caminho de permissão já tinha permitido.

Mais uma coisa que aprendemos a duras penas: com o Auto-review, o Cursor pode perguntar sobre alguns comandos na própria janela. Um hook nunca vê essa pergunta. Ela acontece dentro do Cursor, não no pipeline de hooks.

Onde o Pet Island entra

Se o que você quer dos hooks é “mostre cada comando arriscado e me deixe decidir sem trocar de janela”, é isso que o Pet Island faz com o Cursor. Ele instala os hooks para você (beforeShellExecution e beforeMCPExecution, com failClosed ativado para que um helper travado nunca deixe um comando passar) e coloca cada solicitação em uma pequena ilha no topo da sua tela, com o comando completo. Você permite ou nega ali; o agente do Cursor espera.

Comandos e edições de arquivo do editor Cursor funcionam pela ilha. Perguntas e planos aparecem na ilha, e você responde no Cursor. Na Cursor CLI, os comandos funcionam pela ilha; os outros eventos dependem do que a CLI envia. Desinstalar remove apenas as entradas que o Pet Island adicionou; seus próprios hooks continuam lá.

PERGUNTAS FREQUENTES

Os hooks do Cursor funcionam no Windows?

Sim. O app desktop os executa pelo PowerShell e passa o JSON pela entrada padrão ($input em um script PowerShell). Scripts bash escritos para macOS precisam de uma versão em PowerShell ou Python, e programas do subsistema GUI precisam ser encapsulados para que o PowerShell espere por eles.

Por que meu hook retorna ask, mas o comando roda mesmo assim?

A equipe do Cursor disse em março de 2026 que os hooks só aplicavam deny de forma confiável; allow e ask podiam ser sobrepostos pela lista de permissões ou pelo sandbox. Use deny para tudo o que não pode rodar e confira o canal de saída Hooks para ver o que o seu hook realmente retornou.

O que o failClosed faz?

Com failClosed definido como true, uma falha, um timeout, uma saída diferente de zero ou uma saída vazia bloqueia a ação. Sem ele, um hook quebrado deixa a ação seguir em frente.

Onde vejo os erros dos hooks?

No canal de saída Hooks (View → Output → Hooks) e na aba Hooks em Customize.

Os hooks funcionam na Cursor CLI?

Em parte. A CLI lê os mesmos arquivos hooks.json. Até maio de 2026, a equipe do Cursor confirmou os hooks de shell, afterFileEdit, postToolUse, stop e sessionStart, mas não afterAgentResponse nem afterAgentThought.

Um hook pode impedir um git commit feito pelo painel Source Control?

Não. O Cursor não tem evento de hook pre-commit, e commits feitos pela interface Source Control integrada não são interceptados. Para isso, use um hook pre-commit normal do git.

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