Hook event 28 of 33

CwdChanged

Runs after the session working directory changes and can refresh persistent environment state or the dynamic file-watch list.

Exit code veto
Exit code cannot block
Matchers
none
if filter
Does not apply
Docs checked
2026-08-29

The directory already moved

Claude runs cd, or you change the working directory some other way. By the time your hook runs, the move is done. CwdChanged fires after the session’s working directory has changed, including when Claude runs cd itself. There is no matcher, so every handler fires on every change. The payload carries old_cwd and new_cwd, and the example in the hooks reference shows the shared cwd field holding the new directory as well.

Two side effects it can drive

watchPaths in the JSON output is an array of absolute paths. Returning it replaces the session’s dynamic file-watch list, the list a hook can grow at runtime, while paths configured through a FileChanged matcher keep being watched. Returning an empty array clears the dynamic list. The reference does not say what happens when two hooks return different arrays for the same change.

The other side effect is outside JSON altogether. The hook can write variables to the file named by CLAUDE_ENV_FILE, and later Bash commands in the session see them. That works whatever the exit code, because it is a file write and not an output field.

What you see, and what Claude sees

Exit 0 leaves the change in place and applies the JSON. Exit 1 cannot undo the move either. The transcript records a hook error and the session carries on. Exit 2 cannot block, and its stderr is shown to you only. systemMessage appears as a brief notification in the terminal and does not enter the message stream an SDK program reads. continue is discarded.

The mistake most people make first

You return {"watchPaths": []} from a hook that has nothing to add this time, reasoning that an empty list is a no-op.

It clears the dynamic list. Files that another hook asked Claude Code to watch are no longer watched, and no FileChanged fires for them. Nothing reports the clear.

Omit the field when you have nothing to say. Return it only to set the list.

Module 09 lists this event beside FileChanged in its inventory.