Five files Claude Code watches while you work
You change a settings file mid-session and expect the new value to stick. Claude Code does not apply it blindly. It watches five sources: your user settings, the project’s settings, the project-local settings file, on-machine managed policy, and any file under .claude/skills/. Touch one while a session is open and ConfigChange fires before the new value takes effect. The matcher names which source changed: user_settings, project_settings, local_settings, policy_settings, or skills. The payload carries source and, where there is one, file_path.
The hooks reference does not list which individual setting keys reload this way, and it does not say whether file_path is absent for any particular source. Module 06 notes which keys it found reload and which do not.
Policy that arrives by another road never fires it
Your organisation may push settings through channels this event never sees. It covers managed settings files on the machine. It does not fire for server-managed settings, for macOS managed preferences, for a Windows registry policy, or for a Windows-side policy update inherited into WSL. If policy arrives through any of those paths, ConfigChange never runs.
A block nobody sees
Exit 2 stops the new configuration from applying to the running session. No message reaches you and none reaches Claude. The block is recorded in the debug log and nowhere else. The JSON path is a top-level decision: "block", and reason is accepted but never shown. systemMessage and continue are discarded. Exit 0 and exit 1 let the change apply unless that JSON blocks it.
policy_settings is exempt
Managed policy is a different class of change. When source is policy_settings, a managed policy change applies whatever the hook returns. Exit 2, decision: "block", both are ignored. Policy sits above every other configuration source in Claude Code’s precedence, and this event does not give a local hook a way to reach above it.
You block edits to .claude/settings.json during a session so that a change from a teammate cannot loosen permissions mid-run. Someone edits the file.
Nothing appears in the terminal. Not a refusal, not a notice, and not the change. The hook worked, and the only record is the debug log. The person who edited the file sees their change ignored and has no idea why.
Write the reason somewhere they will look, from inside the hook: a file, a message. reason on this event is accepted and never shown. And note what the same hook does to a policy_settings change, which is nothing.