📚 The 5-Layer Cascade
Settings fazem merge em ordem de prioridade, da mais baixa para a mais alta:
1. userSettings
~/.claude/settings.json -- Preferencias globais do dev, gravavel
2. projectSettings
.claude/settings.json -- Commitado no repo, compartilhado pelo time
3. localSettings
.claude/settings.local.json -- Overrides pessoais por projeto, auto-gitignored
4. flagSettings
--settings <path> -- CLI flag com settings inline opcionais, read-only
5. policySettings
IT/MDM enforced -- usa first-source-wins internamente
Invariante: A cascata e read-only em runtime. Apenas as 3 primeiras camadas sao graveis via updateSettingsForSource().
🏢 Policy Settings Sub-Cascade
Diferente de outras camadas que fazem merge, policySettings aplica exatamente uma fonte interna (first-source-wins):
- Remote Anthropic API -- Enterprise/Team + Console users
- MDM -- macOS plist / Windows HKLM
- File-based --
managed-settings.json+ drop-in directory - HKCU registry -- Windows only, user-writable
🔧 Merge Semantics
Claude Code usa lodash mergeWith() com um customizer:
function settingsMergeCustomizer(objValue, srcValue) {
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
return uniq([...objValue, ...srcValue]) // concatenacao deduplicada
}
return undefined // lodash lida com objetos/scalars
}
undefined via updateSettingsForSource🗄️ The 3-Tier Cache
Tres camadas de cache previnem I/O de disco redundante e re-parsing Zod:
| Cache | Chave | Conteudo |
|---|---|---|
sessionSettingsCache | Singleton | Settings totalmente fundidos |
perSourceCache | SettingSource | Settings por fonte |
parseFileCache | File path | Parsed { settings, errors } |
Todos os tres sao limpos atomicamente por resetSettingsCache(). Clone-on-read previne que callers mutem entradas de cache via mergeWith().
🔍 Change Detection
O settingsChangeDetector observa arquivos com chokidar e faz poll de registros MDM a cada 30 minutos.
FILE_STABILITY_THRESHOLD_MS = 1000 // espera escrita estabilizar
FILE_STABILITY_POLL_INTERVAL = 500 // chokidar awaitWriteFinish
INTERNAL_WRITE_WINDOW_MS = 5000 // suprime escritas proprias
MDM_POLL_INTERVAL_MS = 30min // poll MDM
DELETION_GRACE_MS = 1700 // absorve delete-and-recreate
💡 Internal Writes Suppression
Quando Claude Code escreve settings, chama markInternalWrite(filePath) antes. Quando chokidar dispara o evento, consumeInternalWrite(path, 5000) detecta origem interna e pula reload silenciosamente.
☁️ Remote Managed Settings
Para Enterprise/Team e todos os Console users, Claude Code busca settings da Anthropic API no startup -- a sub-fonte de maior prioridade dentro de policySettings.
ETag-Based Caching
SHA-256 checksums de settings em cache sao enviados como headers If-None-Match. O servidor retorna 304 Not Modified se nada mudou.
Fail-Open Design
- Fetch falhou com cache? Usa cache stale
- Fetch falhou sem cache? Prossegue sem remote settings
- Auth errors (401/403)? Nao tenta novamente
- Network errors? Retry ate 5 vezes com backoff exponencial
🔒 Security Constraints
Varias chaves de settings excluem intencionalmente projectSettings de seu dominio de confianca para prevenir repos maliciosos de injetar settings perigosos:
| Setting | Por que excluir projectSettings |
|---|---|
skipDangerousModePermissionPrompt | Repo poderia auto-bypassar dialogo de danger-mode (risco RCE) |
skipAutoPermissionPrompt | Opt-in para auto-mode deve ser dirigido pelo usuario |
useAutoModeDuringPlan | Semantica de plan-mode e safety-critical |
allowManagedPermissionRulesOnly -- quando true em managed settings, APENAS regras allow/deny/ask de managed settings sao respeitadas. Todas as regras user, project, local e CLI sao silenciosamente ignoradas.
🔄 Settings Sync (CCR)
Settings sync e ortogonal a remote managed settings -- sincroniza os proprios settings do usuario entre ambientes, principalmente entre CLI interativo e CCR headless.
| Direcao | Trigger | O que sincroniza |
|---|---|---|
| Upload (CLI -> cloud) | CLI startup | user settings.json, user CLAUDE.md, local settings, project CLAUDE.local.md |
| Download (cloud -> CCR) | CCR headless startup | Mesmos 4 arquivos, por path + git remote hash |
Limite: cada arquivo e limitado a 500 KB (MAX_FILE_SIZE_BYTES). Arquivos maiores sao silenciosamente pulados.