O settings.json que acaba com os pedidos de permissão
As regras de permissão são a única configuração do Claude Code que soma entre arquivos em vez de substituir. Entendendo isso, dá pra montar uma allowlist que se sustenta — e parar de aprovar o mesmo comando quarenta vezes por dia.
- #claude-code
- #settings
- #permissions
A maioria das pessoas conhece o settings.json tentando calar um pedido de permissão: adiciona uma linha e nunca abre o arquivo de novo. Só que existe um detalhe que faz esse arquivo finalmente fazer sentido, e ele está escondido na documentação: toda configuração do Claude Code substitui a de escopo menor, menos as permissões, que se somam.
Mude o model em três arquivos e só o de maior precedência vale. Adicione regras de allow em três arquivos e você fica com todas. Essa assimetria é exatamente o motivo pelo qual vale investir numa allowlist: o que você escreve nas suas configurações de usuário continua valendo dentro de todo projeto, e um projeto pode acrescentar regras sem apagar as suas.
A ordem de precedência, na versão curta
Do mais forte pro mais fraco: managed (instalado pelo TI, não tem como sobrepor) → flags de linha de comando → .claude/settings.local.json (seu, fora do git) → .claude/settings.json (do time, versionado) → ~/.claude/settings.json (seu, valendo em todos os projetos).
Três regras de bolso que saem daí:
- Convenção que o time todo precisa → arquivo do projeto, versionado.
- Caminho que só existe na sua máquina →
settings.local.json. - Hábito que você quer em tudo →
~/.claude/settings.json.
Rode /status pra ver quais arquivos realmente carregaram. Permissões, hooks e env recarregam na hora que você salva; model e outputStyle só valem na próxima sessão ou depois de um /clear.
Escreva regras que casam com o que você digita de verdade
As regras têm o formato Tool(padrão). A pegadinha que rouba mais tempo é o alcance do curinga:
Bash(npm run test)— só a string exata.npm run test unitnão casa.Bash(npm run test *)— casa comnpm run test unit, mas não comnpm run test unit/advanced. Um*sozinho não atravessa barra.Bash(npm run *)— casa com tudo abaixo denpm run, barras incluídas.
Ou seja: a regra que quase todo mundo escreve, Bash(npm run test), é justamente a que nunca mais dispara depois do primeiro teste com parâmetro. Abra o curinga de propósito.
Uma allowlist inicial larga o bastante pra ser útil e estreita o bastante pra ser segura:
{
"permissions": {
"allow": [
"Bash(pnpm lint)",
"Bash(pnpm typecheck)",
"Bash(pnpm --filter * test *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Read(./**)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(git push --force *)"
]
}
}
Repare no que está no deny: ler o .env. Liberar Read(./**) sem esse par é exatamente como credencial vai parar num histórico de conversa. deny sempre ganha de allow, em qualquer escopo — então a lista de deny é sua rede de segurança real. Coloque ela nas configurações de usuário e ela protege todo repositório em que você encostar.
A allowlist não te salva de tudo
Essa parte eu aprendi na marra, e ela não está em nenhuma cola. O matcher quebra o comando inteiro em token e compara a sequência de argumentos — o que significa que certos formatos de comando vão pedir permissão por mais que você libere, porque o que você digitou não é o formato que a sua regra descreve.
Dois que me pegaram várias vezes:
cdno começo junto com redirecionamento.cd apps/web && node script.ts > out.jsonnão é o comando que a sua regraBash(node script.ts *)reconhece. Use caminho absoluto e semcdna frente.- Expansão de variável de shell.
test -n "$MEU_TOKEN"precisa ser resolvido pelo shell antes de alguém saber o que ele faz, então não vira um padrão estável.
Minha regra de bolso depois de meses nisso: escreva comandos pensando em serem reconhecíveis. Caminho absoluto, sem cd, sem $VAR, um comando por chamada. Se você está aprovando a mesma coisa sem parar, quase sempre a correção é reescrever o comando, não afrouxar a regra.
Quatro outras chaves que valem no primeiro dia
permissions.defaultMode— o padrão é"ask"."auto"entrega cada chamada a um classificador em vez de você, e combina bem com uma lista dedenysólida."deny"é um bom modo pra um repositório que você só está lendo.fallbackModel— até três modelos pra tentar quando o principal está fora, tipo["claude-sonnet-5", "claude-haiku-4-5"]. Não custa nada até o dia em que salva sua sessão. Atenção: esse não se soma entre escopos.env— variáveis aplicadas em toda sessão. Pare de exportar as mesmas três coisas na mão.cleanupPeriodDays— os arquivos de sessão ficam guardados 30 dias por padrão. Se você mexe com coisa sensível, diminua.
E uma pra conhecer mais do que pra configurar: claudeMdExcludes. Num monorepo, o Claude carrega todo CLAUDE.md das pastas acima, inclusive os de outros times. Exclua por glob no settings.local.json e você recupera contexto.
Faça isso hoje
Abra o ~/.claude/settings.json — o de usuário, não o de um projeto — e adicione só o bloco de deny aí de cima. Quatro linhas protegendo todo repositório da sua máquina, pra sempre. Depois, no projeto atual, rode /status, veja quais arquivos carregaram e olhe os três últimos comandos que você aprovou. Se algum começa com cd, reescreva com caminho absoluto antes de criar uma regra de allow que nunca ia casar.
Fontes
Continue lendo
Mais guias parecidos com este.
Por que o Claude ignora o seu CLAUDE.md
Seu CLAUDE.md não é configuração — é uma mensagem que o Claude lê e tenta seguir. Esse detalhe explica toda regra que ele insiste em furar, e muda a forma de escrever o arquivo.
Os 7 níveis do Claude Code — ache o seu, suba um
A maioria dos engenheiros empaca no nível 3, tratando o Claude Code como um terminal mais esperto. Aqui está a escada, do chat aos times de agentes — com o arquivo ou comando exato que te sobe cada degrau.
Claude Code para engenheiros: de chat a colega de time
A maioria dos engenheiros usa o Claude como uma busca mais esperta. Aqui está o caminho curto pra usá-lo como um colega de time que de fato entrega trabalho na sua máquina.