O Verboo Code deixa você plugar um comando de shell, ou até uma checagem feita por modelo, pra rodar sozinho toda vez que algo específico acontece na sessão, sem escrever plugin nem depender do agente lembrar de fazer isso. Isso se chama hook, e a configuração inteira vive no seu settings.json.
O que é um hook no Verboo Code?
Um hook é um comando que a CLI dispara sozinha quando um evento específico acontece, como logo antes de usar uma ferramenta, logo depois, ou quando a sessão começa. Você configura no settings.json, sem precisar de plugin nem de lembrar de rodar nada na mão.
A Verboo Code tem 27 eventos de hook diferentes. Os mais usados no dia a dia:
| Evento | Quando dispara |
|---|---|
PreToolUse | logo antes de qualquer ferramenta rodar |
PostToolUse | logo depois que a ferramenta terminou |
PostToolUseFailure | quando a ferramenta falha |
UserPromptSubmit | quando você envia uma mensagem |
SessionStart | ao abrir, retomar ou limpar a sessão |
Stop | logo antes do agente concluir a resposta |
Onde eu escrevo um hook?
Em um de três arquivos, dependendo do alcance que você quer:
~/.claude/settings.json: vale pra você, em qualquer projeto.claude/settings.json: vale só pra esse projeto, e entra no versionamento, o time inteiro herda.claude/settings.local.json: vale só pra esse projeto, só pra você, não versionado
A estrutura é sempre a mesma: uma chave hooks, com o nome do evento, um matcher opcional pra filtrar por ferramenta, e a lista de hooks que rodam quando bate:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": "..." }
]
}
]
}
}
Como faço o agente formatar o código sozinho depois de editar um arquivo?
Esse é o uso mais comum de hook: rodar um formatador toda vez que o Verboo Code escreve ou edita um arquivo, sem precisar pedir. Adicione isto no settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "file=$(cat | jq -r '.tool_input.file_path'); npx prettier --write \"$file\" 2>/dev/null || true"
}
]
}
]
}
}
matcher é testado como expressão regular contra o nome da ferramenta, então Write|Edit pega as duas. O comando recebe o payload do evento como JSON pelo stdin, não por variável de ambiente. Em PostToolUse, esse JSON tem tool_name, tool_input (o que foi passado pra ferramenta), tool_response (o que ela devolveu), session_id e cwd. Por isso o exemplo lê o file_path com jq em vez de assumir um nome de arquivo fixo.
Por que um hook em PostToolUse não impede a ferramenta de rodar? Porque PostToolUse dispara depois que a ferramenta já terminou. Não tem como travar o que já aconteceu, só reagir: avisar o modelo, gravar um log, disparar uma correção. Quem trava a ferramenta é o PreToolUse, com um comportamento de código de saída bem específico, conferido direto no código-fonte:
| Evento | exit 0 | exit 2 | outro código |
|---|---|---|---|
PreToolUse | segue normal | cancela a chamada, stderr volta pro modelo | segue, mas mostra o erro só pra você |
PostToolUse | segue normal | mostra o stderr pro modelo, mas a ferramenta já rodou | segue, mostra o erro só pra você |
Se você precisa impedir uma edição de acontecer, o hook tem que estar em PreToolUse, terminando com exit 2.
Como faço um hook rodar só para um tipo de comando, tipo só git?
Use o campo if, com a mesma sintaxe de regra de permissão que você já usa em allow e deny, por exemplo Bash(git *). Ele filtra antes mesmo de o processo do hook ser criado, então comandos que não batem nem chegam a rodar o script. Um exemplo real: travar push direto na main.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git *)",
"command": "cmd=$(cat | jq -r '.tool_input.command'); if echo \"$cmd\" | grep -qE 'push.*(origin|upstream)[[:space:]]+main'; then echo 'Push direto na main bloqueado. Abra um PR.' >&2; exit 2; fi"
}
]
}
]
}
}
Hook sempre precisa ser um script de shell?
Não. Existem 4 tipos, e cada um serve pra uma coisa diferente:
| Tipo | O que faz | Consome token? |
|---|---|---|
command | roda um comando de shell, bash ou powershell | não |
http | faz um POST do JSON do evento pra uma URL | não |
prompt | avalia o payload com um modelo rápido e responde ok ou não | sim |
agent | roda um agente verificador completo, com o modelo que você escolher | sim |
Um hook de tipo agent em Stop, por exemplo, serve pra checar se os testes rodaram e passaram antes de considerar a tarefa concluída, sem confiar só no que o próprio agente principal diz que fez.
Como eu vejo quais hooks estão ativos numa sessão?
Rode /hooks. Ele abre um navegador por evento, depois por matcher, mostrando cada hook configurado e de onde ele vem: configuração de usuário, de projeto, local, de plugin ou da própria sessão. É só leitura: pra criar ou mudar um hook, você edita o settings.json na mão, ou pede pro próprio Verboo Code editar pra você. A tela de edição antiga só lidava com hooks do tipo command; sustentar os 4 tipos dentro do mesmo menu virou peso demais de manter, então o caminho oficial hoje é o arquivo de configuração.
Hooks de tipo prompt e agent chamam um modelo a cada disparo, então numa ferramenta com contagem de token isso é motivo pra usar com moderação: cada PostToolUse, cada Stop, cada checagem custa. Na Verboo Code esse hook consome do mesmo pool de token ilimitado da sessão normal, então dá pra colocar um verificador em agent em todo Stop sem fazer conta de quanto isso custa por rodada.



