🛡️ System Overview
Cada tool use -- comandos bash, edicoes de arquivo, endpoints MCP -- passa por um pipeline de permissoes que produz tres resultados possiveis:
allow
Ferramenta executa imediatamente sem intervencao do usuario.
deny
Ferramenta e bloqueada; Claude recebe o motivo.
ask
Usuario e solicitado a aprovar ou rejeitar.
Tres inputs dirigem o pipeline: a ferramenta solicitada, seus parametros de entrada e o contexto de permissao atual (modo, regras, estado da sessao).
🔍 The Decision Pipeline
Implementado em hasPermissionsToUseToolInner() em permissions.ts. Os passos sao numerados para corresponder aos comentarios no codigo:
checkPermissions() proprio de cada tool (Bash checa prefixos, FileWrite checa limites de diretorio).
requiresUserInteraction -- tools como ExitPlanMode, AskUserQuestion sempre requerem aprovacao humana.
.git/, .claude/, .vscode/, shell configs sempre requer aprovacao.
bypassPermissions mode -- tudo que passou pelo step 1 e permitido.
dontAsk vira deny; auto vai para classificador; headless vai para hooks.
🎯 The 5 Permission Modes
| Modo | Comportamento |
|---|---|
| default | Mostra prompt para cada tool use nao reconhecido |
| plan | Read-only. Write tools bloqueados ate sair do plan mode |
| acceptEdits | Auto-aprova file edits dentro do working directory. Shell ainda pede |
| bypassPermissions | Pula todos os prompts (exceto deny, safety checks, requiresUserInteraction) |
| dontAsk | Converte todo "ask" em "deny". Claude e informado que nao pode usar a tool |
| auto | Roteia decisoes "ask" por um classificador AI em vez de prompt humano |
💡 O que bypassPermissions NAO pode ultrapassar
- Deny rules -- sempre respeitadas, sem excecoes
- requiresUserInteraction -- ExitPlanMode, AskUserQuestion, ReviewArtifact sempre precisam de humano
- Content-specific ask rules --
Bash(npm publish:*)na ask list sempre pergunta - Safety checks -- escrita em
.git/,.claude/,.vscode/, shell configs sempre pergunta
📝 Rule Matching System
Cada regra e uma string no formato ToolName ou ToolName(content), armazenada em listas allow/deny/ask. Tres tipos de content rules:
exact
Igualdade completa apos trim.
Bash(npm install)
prefix (legacy)
Termina com :*. Parte antes de : e prefixo.
Bash(npm:*)
wildcard
Contem * nao-escapado. Convertido para regex.
Bash(git * --dry-run)
// Tool-wide rule
"Bash" // match any Bash command
"mcp__myserver" // match all tools from myserver MCP
// Content-specific rules
"Bash(npm install)" // exact match
"Bash(npm:*)" // legacy prefix
"Bash(git add *)" // wildcard
📚 Rule Sources & Priority
| Fonte | Arquivo | Compartilhado? |
|---|---|---|
| policySettings | Enterprise managed policy | Sim |
| projectSettings | .claude/settings.json | Sim (git) |
| userSettings | ~/.claude/settings.json | Nao |
| localSettings | .claude/settings.local.json | Nao |
| flagSettings | --settings CLI flag | Nao |
| session | In-memory (sessao atual) | Nao |
{
"permissions": {
"allow": ["Bash(npm:*)", "Bash(git status)"],
"deny": ["WebFetch"],
"ask": ["Bash(npm publish:*)"]
}
}
🤖 Auto Mode & AI Classifier
Quando o modo e auto, decisoes ambiguas sao roteadas por um modelo Claude secundario ("YOLO classifier") em vez de prompt humano. Tres fast paths pulam o classificador:
- Safety checks nao-classificaveis -- escrita em
.git/ou shell configs nunca e auto-aprovada - acceptEdits fast path -- file edits dentro do CWD sao permitidos sem chamar classificador
- Safe tool allowlist -- ferramentas read-only pulam o classificador
Denial Tracking
O classificador rastreia negacoes consecutivas e totais. Apos 3 consecutivas ou 20 totais, cai de volta para prompt do usuario. Uma tool use bem-sucedida reseta a contagem consecutiva (mas nao o total).
Dangerous Patterns Stripped at Auto Mode Entry
Ao entrar em auto mode, allow rules que deixariam Claude ultrapassar o classificador sao removidas:
const DANGEROUS_BASH_PATTERNS = [
'python', 'node', 'deno', 'ruby', 'perl',
'npx', 'bunx', 'npm run', 'yarn run',
'bash', 'sh', 'eval', 'exec', 'sudo', 'xargs',
]
👁️ Shadowed Rule Detection
Uma regra pode se tornar inalcancavel -- escrita corretamente mas nunca avaliada porque uma regra mais geral dispara primeiro. shadowedRuleDetection.ts detecta e reporta esses conflitos.
❌ Deny-shadowed
Bash na deny list faz Bash(ls:*) na allow list ser inalcancavel.
permissions.deny = ["Bash"] // bloqueia tudo
permissions.allow = ["Bash(ls:*)"] // nunca alcancada!
⚠️ Ask-shadowed
Bash na ask list sempre pergunta, tornando Bash(ls:*) na allow list inalcancavel.
💬 Permission Explainer
Quando um prompt de permissao aparece, permissionExplainer.ts faz uma chamada API lateral para gerar uma explicacao legivel do que o comando faz, por que Claude quer executa-lo e o nivel de risco.
{
explanation: "What this command does (1-2 sentences)",
reasoning: "I need to check the file contents",
risk: "Modifies files outside the working directory",
riskLevel: "HIGH" // LOW | MEDIUM | HIGH
}
- Usa
sideQuery()-- chamada API separada que NAO conta nos totais de tokens da sessao - Modelo forcado a usar tool especifica (
explain_command) para output estruturado garantido - Inclui ate 1.000 chars de contexto recente para respostas "why" fundamentadas