Config Schemas

Description

The configuration schema system uses Zod v4 to validate all settings.json files across 5 configuration scopes. It defines the structure for user settings, project settings, enterprise policies, permission rules, hooks, MCP server configs, and sandbox settings. Managed settings follow a systemd-style drop-in convention for enterprise customization.

Configuration scopes

5 setting sources with defined precedence (later overrides earlier):

Priority Source Location Editable
1 userSettings ~/.claude/settings.json Yes
2 projectSettings .claude/settings.json (shared) Yes
3 localSettings Gitignored project-local Yes
4 flagSettings --settings CLI flag No
5 policySettings managed-settings.json or remote API No

policySettings and flagSettings are always loaded. User/project/local sources can be selectively enabled via --setting-sources user,project,local.

SettingsSchema structure

The unified SettingsSchema (in src/utils/settings/types.ts) covers all configuration:

Authentication

Permissions

MCP

Hooks

Model and behavior

UI and display

Enterprise

Other

Hook schemas

Hooks are defined in src/schemas/hooks.ts (extracted to break import cycles). Four hook types:

Type Key fields
command (bash) command, if (matcher), shell, timeout, once, async
prompt prompt (with $ARGUMENTS), if, model, timeout, once
http url, headers (with $VAR_NAME interpolation), allowedEnvVars, timeout
agent prompt, if, model, timeout, once

All hooks support: statusMessage, once (run only first time), and if condition (permission rule syntax like "Bash(git *)" to filter when the hook fires).

Validation approach

Managed settings

loadManagedFileSettings() follows the systemd/sudoers drop-in convention:

  1. Load managed-settings.json from platform-specific managed path
  2. Load managed-settings.d/*.json (sorted alphabetically)
  3. Merge using lodash-es/mergeWith with settingsMergeCustomizer

Base file provides defaults; drop-in files customize for specific teams or environments.

Trade-offs

  1. Single unified schema — all scopes use the same SettingsSchema, making it easy to understand but meaning every scope can potentially set any field (policy enforcement must be separate from validation).
  2. Graceful degradation — invalid fields are ignored rather than rejecting the whole file. Good for forward compatibility but can mask configuration errors silently.
  3. Drop-in convention — flexible for enterprise deployment but adds precedence complexity beyond the 5-scope hierarchy.
  4. lazySchema() wrapper — breaks import cycles but makes the schema harder to inspect statically.

Depends on

Key claims

Relations

Sources

src-20260409-a5fc157bc756, source code analysis of src/schemas/hooks.ts, src/utils/settings/types.ts, src/utils/settings/constants.ts