Sala de controle

Settings.json

O painel da Nabucodonosor

A sala de monitores onde Tank controla quem entra na Matrix, quem sai e o que cada um pode fazer. Um arquivo, todo o controle.

Canal Sandeco
"
"

Tudo na Nabucodonosor passa por aquele painel de monitores. Tudo no Claude passa pelo settings.json.

Settings · O centro nervoso

O que é o settings.json?

Quatro características que fazem desse arquivo o painel único de controle de tudo que o Claude Code pode ou não pode fazer.

Centraliza tudo

Permissões, hooks, ambiente, modelo, statusline. Uma única tela, todas as decisões.

Hierárquico

Três níveis, do local ao global. O mais específico sempre vence quem é mais genérico.

JSON declarativo

Sem script, sem mágica. Você descreve o estado desejado; o Claude obedece a configuração.

Compartilhável

Vai pro Git com o projeto. Time inteiro com o mesmo painel, sem improviso de cada dev.

Três níveis, uma só verdade

O Claude lê os três e faz merge. O mais específico vence o mais genérico. Quem está mais perto do seu código manda.

Precedência (do mais forte)
Nível 1 · vence todos .local.json

Overrides locais

Seu PC, sua máquina. Fora do Git.

Nível 2 · time settings.json

Projeto

Vai pro Git, vale para o time.

Nível 3 · global ~/.claude/

Usuário

Vale em todo projeto da sua máquina.

Quanto mais perto do código, mais forte
onde cada arquivo mora
# Nivel 1: overrides locais (fora do git)
.claude/settings.local.json
    ↳ no .gitignore por padrao
    ↳ so vale na sua maquina
    ↳ vence os outros dois

# Nivel 2: configuracao do projeto (vai pro git)
.claude/settings.json
    ↳ compartilhado com o time
    ↳ vence o global do usuario
    ↳ define a "lei" do repositorio

# Nivel 3: configuracao global do usuario
~/.claude/settings.json
    ↳ vale em todos os projetos
    ↳ seu padrao pessoal
    ↳ base quando nao ha override

Regra de ouro: precedência é por chave. Se você define permissions nos três, vale o nível 1. Se só o nível 3 tem env, ele permanece.

Settings · CLAUDE.md · Memory

Três peças que parecem fazer a mesma coisa, mas cobrem aspectos diferentes. Saber quando usar cada uma evita conflito de regras.

Dimensão
settings.json
CLAUDE.md
Memory
Tipo
Configuração executável
Instruções em prosa
Preferências persistentes
Formato
JSON
Markdown
Markdown indexado
O que controla
Permissões, hooks, env
Convenções do projeto
Decisões já tomadas
Quem lê
Runtime do Claude
Prompt do agente
Prompt do agente
Metáfora
Painel da nave
Manual de bordo
Diário do capitão

Em resumo: settings.json diz o que pode acontecer; CLAUDE.md diz como o código deve ser; Memory lembra o que já foi decidido.

Como o Claude resolve

O merge dos três níveis

O Claude lê os três settings em ordem, do mais genérico ao mais específico, e produz uma configuração efetiva única. Quem está em cima, manda.

Global do usuário
Projeto (Git)
Local (override)
Config efetiva

Um settings.json de verdade

Permissões, hooks, env, modelo. Tudo num só arquivo. Esse é o painel inteiro de um projeto sério.

.claude/settings.json
{
  "model": "claude-sonnet-4-6",

  "permissions": {
    "allow": [
      "Bash(npm test:*)",
      "Bash(git status)",
      "Read(./src/**)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./secrets/**)",
      "Bash(rm -rf:*)"
    ],
    "ask": [
      "Bash(git push:*)",
      "WebFetch(domain:*)"
    ]
  },

  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [{ "type": "command", "command": "./scripts/audit.sh" }] }
    ],
    "PostToolUse": [
      { "matcher": "Edit", "hooks": [{ "type": "command", "command": "npm run lint" }] }
    ]
  },

  "env": {
    "ANTHROPIC_LOG_LEVEL": "info",
    "PROJECT_ENV": "dev"
  },

  "includeCoAuthoredBy": true,
  "cleanupPeriodDays": 30
}

permissions

Allow, deny, ask

hooks

Eventos do ciclo

env

Variáveis injetadas

model

Modelo default

Anatomia: permissions

Três listas controlam o que o agente pode fazer sem perguntar, o que está proibido e o que precisa confirmar.

allow

Pode sem perguntar

"allow": [
  "Bash(npm test:*)",
  "Bash(git status)",
  "Bash(git log:*)",
  "Read(./src/**)",
  "Edit"
]

O agente executa direto. Bom para comandos repetitivos e seguros do dia a dia.

deny

Bloqueio absoluto

"deny": [
  "Read(./.env)",
  "Read(./secrets/**)",
  "Bash(rm -rf:*)",
  "Bash(curl:*)"
]

Nem com confirmação. Use para tudo que jamais pode acontecer: segredos, comandos destrutivos.

ask

Pergunta antes

"ask": [
  "Bash(git push:*)",
  "Bash(npm publish)",
  "WebFetch(domain:*)",
  "Bash(docker:*)"
]

Ações sensíveis mas legítimas. O agente pede um "sim" antes de executar.

Sintaxe de matcher

Bash(npm test)

Match exato. Só esse comando, nada mais.

Bash(npm test:*)

Wildcard. Qualquer coisa que começa com "npm test".

Read(./src/**)

Glob. Qualquer arquivo recursivo dentro de src.

WebFetch(domain:example.com)

Modificador. Restringe ao domínio indicado.

Anatomia: hooks

Comandos shell que rodam automaticamente em eventos do ciclo de vida do agente. Vigilância contínua, sem você precisar lembrar.

eventos disponíveis
PreToolUse Antes do agente usar uma ferramenta
PostToolUse Depois de usar uma ferramenta
UserPromptSubmit Quando você envia um prompt
Stop Quando o agente termina o turno
SessionStart No início da sessão
configuração de um hook
"hooks": {
  "PreToolUse": [
    {
      "matcher": "Bash",
      "hooks": [
        {
          "type": "command",
          "command": "./scripts/audit.sh"
        }
      ]
    }
  ],
  "PostToolUse": [
    {
      "matcher": "Edit|Write",
      "hooks": [
        {
          "type": "command",
          "command": "npm run lint"
        }
      ]
    }
  ]
}

Por que vive no settings.json: hooks são gatilhos do sistema; precisam ser declarativos, versionados e aplicados antes do agente decidir. Não dá pra deixar isso para o prompt.

env

Ambiente injetado

Variáveis que aparecem em todos os comandos shell e hooks do projeto. Sem precisar exportar no terminal, sem depender do dotfile do dev.

Padrão de log do projeto

Feature flags por ambiente

Chaves de API públicas (nunca segredos)

.claude/settings.json
{
  "env": {
    "ANTHROPIC_LOG_LEVEL": "debug",
    "NODE_ENV": "development",
    "PROJECT_NAME": "engenharia-software",
    "FEATURE_NEW_PARSER": "on"
  }
}

Nunca coloque segredos no settings.json do projeto. Esse arquivo vai pro Git. Para chaves de API use apiKeyHelper ou um settings.local.json com a chave fora do versionamento.

Hands-on · 60 segundos

Seu primeiro settings.json

Um arquivo, três blocos, um painel inteiro funcionando. Sem instalar nada, sem mexer no código.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "Bash(npm test:*)",
      "Bash(git status)"
    ],
    "deny": [
      "Read(./.env)"
    ]
  },
  "env": {
    "PROJECT_ENV": "dev"
  },
  "includeCoAuthoredBy": true
}

Três blocos: permissions protege o que importa, env injeta contexto, includeCoAuthoredBy assina os commits.

Claude Code · sessão ativa
> rode os testes
Bash(npm test)
executado sem perguntar (allow)
> leia o .env
Read(./.env)
bloqueado pelo deny
painel ativo, regras aplicadas...

O Claude leu o settings antes de qualquer ação. Cada ferramenta passou pelo painel; o painel decidiu se libera, bloqueia ou pergunta.

1

Crie a pasta

.claude/ na raiz do projeto.

2

Salve o JSON

.claude/settings.json com o conteúdo acima.

3

Reinicie a sessão

O Claude relê os settings no início e aplica imediatamente.

Quando você não quer abrir o JSON

Dois slash commands abrem o painel sem você precisar mexer no arquivo na mão.

Slash command

/permissions

Editor visual para a seção de permissões. Adiciona, remove, muda entre allow, deny e ask sem você abrir o JSON.

> /permissions
⎿ Abrindo editor de permissões...
[✓] allow · Bash(npm test:*)
[✓] allow · Bash(git status)
[✓] deny · Read(./.env)
[ ] ask · Bash(git push:*)

Slash command

/config

Painel geral de configuração. Modelo, tema, statusline, includeCoAuthoredBy, tudo num menu.

> /config
⎿ Configurações do Claude Code
Modelo: claude-sonnet-4-6
Tema: dark
Co-author commits: true
Cleanup days: 30

Sacada: os dois comandos escrevem no mesmo arquivo. UI bonita por cima, JSON honesto por baixo. Quando o time precisa revisar, o diff sai limpo.

Mãos no painel

Cinco settings que valem o setup

Configurações que viram músculo do seu projeto. Escreve uma vez, vale para sempre.

allow Bash comum deny segredos hook auditoria env log debug statusLine git

Setting 1 · allowlist

Bash sem fricção

Comandos triviais e repetitivos não precisam de confirmação a cada turno. Coloque tudo que é seguro no allow e libere o ritmo do agente.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "Bash(npm test:*)",
      "Bash(npm run lint)",
      "Bash(npm run build)",
      "Bash(git status)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(git branch:*)",
      "Bash(ls:*)",
      "Bash(pwd)"
    ]
  }
}
no terminal
> rode os testes e me diga o que falhou
⎿ Executando npm test...
Permitido pelo settings.json
PASS src/auth/jwt.test.ts
PASS src/user/user.test.ts
FAIL src/order/total.test.ts
O teste de total falhou
na linha 42. Vou olhar.

Ganho prático: zero "permite?" para tarefas óbvias. O agente roda, observa, decide o próximo passo sem você precisar babá-lo.

Setting 2 · denylist

Segredos intocáveis

Nada de "ah, ele não vai ler o .env". Bloqueie no painel e durma tranquilo. O agente nem cogita acessar.

.claude/settings.json
{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Read(./**/*.pem)",
      "Read(./**/*credentials*)",
      "Bash(rm -rf:*)",
      "Bash(curl:*)",
      "Bash(sudo:*)"
    ]
  }
}
no terminal
> olhe o .env para ver a chave
⎿ Tentando Read(./.env)...
✗ BLOQUEADO PELO SETTINGS
Read(./.env) está em deny.
Não é possível, nem com /yes.
Não posso ler esse arquivo.
Se a chave precisa estar
disponível, configure via
apiKeyHelper no settings.

Ganho prático: defesa em profundidade. Mesmo se o prompt induzir o agente ao erro, o painel impede o vazamento.

Setting 3 · hook UserPromptSubmit

Auditoria de prompts

Toda vez que você manda um prompt, um script registra. Útil para compliance, retroativa de erros, ou para entender quanto tempo gasta em cada tipo de tarefa.

.claude/settings.json
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/audit-prompt.sh"
          }
        ]
      }
    ]
  }
}
scripts/audit-prompt.sh
#!/bin/bash
# Le o prompt do stdin (JSON do Claude)
PROMPT=$(jq -r .prompt)
DATE=$(date --iso-8601=seconds)
echo "$DATE | $USER | $PROMPT" \
  >> .claude/audit.log
.claude/audit.log (após uso)
# registro automático de prompts
2026-05-21T09:14:02 | sandeco |
rode os testes da pasta auth
2026-05-21T09:18:33 | sandeco |
refatore total.ts
2026-05-21T09:25:11 | sandeco |
crie testes para revoke
2026-05-21T09:30:48 | sandeco |
/commit
4 prompts em 16 minutos

Ganho prático: rastro auditável de tudo que foi pedido ao agente. Em ambiente regulado, isso vale ouro. Em ambiente normal, vira métrica de produtividade.

Setting 4 · env

Debug ligado por padrão

Quando algo não funciona, você precisa de log. Ative o nível debug no settings.local.json e o Claude passa a contar tudo que faz, sem você lembrar de exportar variável.

.claude/settings.local.json
{
  "env": {
    "ANTHROPIC_LOG_LEVEL": "debug",
    "CLAUDE_TRACE": "1",
    "DEBUG": "claude:*"
  }
}

Use o settings.local.json: debug é seu, não do time. Não suja o painel compartilhado.

saída detalhada
[DEBUG] tool_call: Bash(npm test)
[DEBUG] permission_check: allow
[DEBUG] hook PreToolUse: audit.sh
[DEBUG] hook exit_code: 0
[DEBUG] executing: npm test
⎿ output stream...
[DEBUG] tool_result: 2.3s
[DEBUG] hook PostToolUse: lint
[DEBUG] hook exit_code: 0
Tudo visível. Quando algo
quebra, você sabe onde.

Ganho prático: debug não fica esquecido. O painel local já liga. Quando precisar desligar, é uma linha.

Setting 5 · statusLine

Linha de status vivente

A linha de status é o painel embaixo do prompt. Por padrão mostra modelo e diretório. Com statusLine ela passa a mostrar branch, status do Git e qualquer coisa que você quiser.

.claude/settings.json
{
  "statusLine": {
    "type": "command",
    "command": "./scripts/statusline.sh"
  }
}
scripts/statusline.sh
#!/bin/bash
BRANCH=$(git branch --show-current)
DIRTY=$(git status --porcelain | wc -l)
MODEL=$(jq -r .model)

echo "⎇  $BRANCH" \
     "·" \
     "$DIRTY arquivos sujos" \
     "·" \
     "$MODEL"
no terminal
> refatore o middleware
⎿ Analisando middleware...
Vou começar pela função
de validação JWT.
⎇ feature/auth-jwt · 3 arquivos sujos · sonnet-4-6
A statusline está sempre visível.

Ganho prático: contexto perene à vista. Você nunca esquece em qual branch está nem quanto trabalho não comitado tem na fila.

Os cinco settings lado a lado

Resumo das configurações práticas que você acabou de ver.

Chave O que resolve Ganho
permissions.allow Libera Bash repetitivo (test, lint, status, log) Zero fricção
permissions.deny Bloqueia .env, segredos e comandos destrutivos Defesa absoluta
hooks.UserPromptSubmit Registra cada prompt enviado em um log local Auditoria contínua
env.ANTHROPIC_LOG_LEVEL Liga debug detalhado sem variável manual Diagnóstico fácil
statusLine Mostra branch, sujeira do Git e modelo o tempo todo Contexto perene

Cinco chaves dentro de um único arquivo. Você cola, ajusta os caminhos e seu projeto inteiro passa a se comportar como um produto sério.

Quer dominar cada peça?

O livro Engenharia de Software para Agentes Inteligentes destrincha settings, commands, hooks, skills, MCP, subagents e tudo que faz o agente trabalhar a seu favor.

Canal Sandeco · @canalsandeco
Permissions quem pode
+
Hooks quando dispara
+
Env em qual mundo
=
settings.json centro nervoso

Quem pode, quando dispara, em qual mundo. Tudo num só painel, e a Nabucodonosor faz o resto.

Sem settings, o agente improvisa. Com settings, o projeto tem lei. Esse arquivo conecta hooks, permissions, env e o restante do ecossistema num único ponto de verdade.

Capítulo 5 · Settings.json