O que é e porque importa
O vídeo falava do Jev: uma IA que não escreve texto, mas responde com um tipo preciso, ou seja uma escolha, uma pontuação ou um verdadeiro/falso, com as probabilidades e a confiança que tem. O que fazer com a resposta decide-o o teu código. Por agora há uma lista de espera. Aqui interessa-me uma ideia só: um controlo que fica entre a IA e o comando, antes de o comando arrancar. Isso o teu Claude Code já pode ter hoje, sem esperar em lista nenhuma.
O problema é simples. O Claude Code corre comandos no terminal do teu computador. Quase sempre são inofensivos: instala um pacote, corre os testes, lê um ficheiro. Mas alguns não se desfazem. rm -rf apaga uma pasta com tudo lá dentro, sem passar pelo lixo. git push --force reescreve o histórico do projeto online. git reset --hard deita fora as alterações que ainda não guardaste num commit. Um drop table apaga uma tabela da base de dados.
Não é preciso que o Claude se engane de propósito. Basta uma instrução mal percebida, um caminho errado, uma sessão longa em que se baralhou. E se aprovas as confirmações à pressa, ou as reduziste para andar mais depressa, o momento em que podias dizer que não passa sem dares por isso.
Há mais uma coisa a saber. O rewind do Claude Code (Esc duas vezes, ou /rewind) desfaz as alterações feitas com as suas ferramentas de ficheiros, mas não as feitas por comandos no terminal. Se um rm apagar um ficheiro, o rewind não to devolve.
Por isso o travão tem de ser posto antes. Duas maneiras: uma lista de comandos proibidos, a simples, e um pequeno script que lê cada comando antes de arrancar, a mais esperta. Depois há o prompt para o Claude as fazer.
1. A lista de comandos proibidos
O Claude Code lê as definições do projeto no ficheiro .claude/settings.json, na pasta do projeto. Se queres as mesmas regras em todos os projetos, usa ~/.claude/settings.json na tua pasta de utilizador. Lá dentro escreve isto:
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force *)",
"Bash(git reset --hard *)"
]
}
}Um «deny» ganha sempre a qualquer permissão dada. O Claude Code vê primeiro as regras deny, depois as que pedem confirmação e depois as que permitem. Por isso, mesmo que um dia tenhas respondido «sim, não perguntes mais» a um comando, o deny continua mais forte. E vale em todos os modos de permissão, mesmo em bypassPermissions.
O limite: a regra bloqueia o comando escrito assim, não as suas variantes. Bash(rm -rf *) trava rm -rf build/, mas não o mesmo comando dentro de bash -c, ou escrito como /bin/rm -rf build/. Também rm -fr, com as letras trocadas, passa. É uma rede, não um muro.
2. O guardião: um hook que verifica cada comando
Um hook é um script que o Claude Code corre sozinho num momento preciso. O que nos interessa chama-se PreToolUse: corre antes de cada chamada a uma ferramenta, e com o filtro «Bash» só olha para os comandos do terminal. Recebe o comando em JSON. Se o script sair com código 2, o comando não arranca e o Claude lê o motivo que escreveste. Se sair com 0, o comando segue com as permissões normais.
A vantagem em relação à lista: o script procura as palavras perigosas no texto inteiro do comando. Por isso também apanha um rm -rf escondido dentro de bash -c.
Cria o ficheiro .claude/hooks/guardiao.sh no projeto e cola lá isto:
#!/bin/bash
command -v jq >/dev/null || { echo "é preciso o jq" >&2; exit 2; }
CMD=$(jq -r '.tool_input.command')
if echo "$CMD" | grep -Eiq 'rm -rf|git push --force|git reset --hard|drop table'; then
echo "Bloqueado: comando destrutivo. Pede-me autorização primeiro." >&2
exit 2
fi
exit 0Torna-o executável com chmod +x .claude/hooks/guardiao.sh. O script usa o jq para ler o JSON: se não o tens, no Mac instalas com brew install jq. Se faltar, a primeira linha do script bloqueia todos os comandos em vez de os deixar passar.
Depois acrescenta em .claude/settings.json, ao lado de «permissions», esta parte:
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guardiao.sh" }]
}
]
}$CLAUDE_PROJECT_DIR indica a pasta do projeto, e as aspas à volta mantêm o caminho inteiro mesmo que tenha espaços. Juntas, as duas partes dão um ficheiro assim:
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force *)",
"Bash(git reset --hard *)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guardiao.sh" }]
}
]
}
}A lista no script és tu que a aumentas: põe os comandos que no teu projeto fazem estragos, por exemplo o que esvazia a base de dados ou o script que publica a app.
3. Se não te apetece fazer à mão
Podes pedir ao Claude que faça tudo: o script, o ficheiro de definições e o teste. Escreve-lhe:
Configura em .claude/settings.json um hook PreToolUse que bloqueie os comandos destrutivos antes de arrancarem (rm -rf, git push --force, git reset --hard, drop table) e acrescenta as mesmas regras à lista deny das permissões. Depois cria uma pasta vazia de teste e verifica que rm -rf nessa pasta fica bloqueado.
Quando acabar, lê tu o ficheiro .claude/settings.json e o script. São poucas linhas. Se alguma coisa não te bater certo, pede que te explique:
Mostra-me o conteúdo de .claude/settings.json e do script do hook, e explica-me linha a linha o que bloqueia e o que deixa passar.
4. O teste
Uma regra que não testaste é uma regra que esperas que funcione. Escreve /hooks no Claude Code: abre-se a lista dos hooks configurados, e o teu tem de aparecer em PreToolUse. Normalmente o Claude Code lê logo as alterações ao ficheiro de definições. Se o teu hook não aparecer, fecha e volta a abrir o Claude Code.
Atenção a um pormenor: com o deny ativo, um rm -rf escrito normalmente já é travado pela lista. Para veres se o guardião funciona sozinho, pede ao Claude o mesmo comando dentro de bash -c: a lista não o vê, o guardião sim.
Cria uma pasta vazia chamada teste-guardiao e tenta apagá-la com bash -c 'rm -rf teste-guardiao'. Depois diz-me o que te travou: a lista deny ou o hook.
Se o comando passar, o guardião não está a funcionar: normalmente o script não é executável ou o caminho no settings.json está errado, e nesses casos o Claude Code não recebe o código 2 e deixa o comando seguir. Se, pelo contrário, ficar tudo bloqueado, até um simples ls, e o motivo for «é preciso o jq», falta o jq.
5. A rede por baixo: git
O guardião reduz o risco, não o elimina. As variantes de um comando são muitas e não as vais prever todas. Por isso a verdadeira rede por baixo é o git: faz um commit antes de dares ao Claude um trabalho longo, e guarda uma cópia do projeto também online, por exemplo no GitHub. Se alguma coisa correr mal, voltas ao último commit.
E o modo bypassPermissions, o que salta os pedidos de confirmação, a documentação do Claude Code só o recomenda em ambientes isolados, como um contentor ou uma máquina virtual. Não no computador onde tens tudo.
Os erros mais comuns
- Sobrescrever o settings.json que já existia: acrescenta as partes novas ao que lá está e confirma as vírgulas, porque basta faltar uma vírgula para estragar o ficheiro.
- Achar que o deny cobre todas as variantes: bloqueia o comando escrito assim, por isso junta-lhe o guardião que lê o texto inteiro do comando.
- Esquecer o chmod +x: o script não arranca e o guardião não bloqueia nada sem te avisar, por isso faz sempre o teste numa pasta vazia.
- Contar com o rewind para os ficheiros apagados: o rewind não desfaz os comandos do terminal, por isso faz um commit antes dos trabalhos longos.
Checklist
- Regras deny em .claude/settings.json
- Script guardião criado e tornado executável
- jq instalado
- Hook visível em /hooks em PreToolUse
- Teste numa pasta vazia: comando bloqueado
- Commit feito antes dos trabalhos longos
Perguntas frequentes
O Claude Code não pede já autorização antes dos comandos?
No modo Manual, sim: pergunta antes de cada comando que não seja só de leitura. Mas se respondes «sim, não perguntes mais», ou trabalhas num modo que pergunta menos, essa confirmação desaparece. O deny e o guardião, pelo contrário, continuam ativos aí também.
O que é melhor, a lista deny ou o hook?
Os dois. O deny são três linhas e não precisa de mais nada. O hook lê o texto inteiro do comando e apanha as variantes mais comuns. Um tapa os buracos do outro.
O guardião também pode bloquear comandos inofensivos?
Sim: se um comando tiver essas palavras, por exemplo uma pesquisa de texto com «rm -rf» lá dentro, é travado. Não faz mal: o Claude lê o motivo e pergunta-te como continuar. Se acontecer muitas vezes, torna a lista mais precisa.
Vale para todos os meus projetos?
Em .claude/settings.json vale para esse projeto, e se o ficheiro estiver no git vale também para quem trabalha nele contigo. Em ~/.claude/settings.json vale para todos os teus projetos: nesse caso põe o script em ~/.claude/hooks e escreve esse caminho no comando do hook.