[Bug] Plugin-registered CwdChanged and FileChanged hooks don't fire (settings.json works) — v2.1.153

Resolved 💬 3 comments Opened May 28, 2026 by justfalter Closed May 28, 2026

[Bug] CwdChanged and FileChanged hooks never fire in v2.1.153

Summary

Neither CwdChanged nor FileChanged hooks fire under the conditions described in the hooks docs. SessionStart from the same plugin works fine, so plugin loading itself is not the issue.

This appears to be a continuation of the unresolved #44925 (closed stale, same use case: re-applying mise env on cwd/file changes).

Environment

  • Claude Code 2.1.153
  • macOS (Darwin 25.5.0)
  • Plain terminal — no cmux, no IDE extension, no managed-settings policy
  • Plugin installed via local marketplace, enabled in ~/.claude/settings.json

Plugin hooks/hooks.json

{
  "hooks": {
    "SessionStart": [
      { "hooks": [{ "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/apply-mise-env.sh\"" }] }
    ],
    "CwdChanged": [
      { "hooks": [{ "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/apply-mise-env.sh\"" }] }
    ],
    "FileChanged": [
      {
        "matcher": "mise.toml",
        "hooks": [{ "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/apply-mise-env.sh\"" }]
      }
    ]
  }
}

The hook script logs every invocation (stdin + timestamp + pid) to a tmp file before doing anything else, so we can see every fire unconditionally.

Reproduction

  1. Start Claude in a project directory containing mise.toml.
  2. SessionStart fires — log entry appears. ✅
  3. Ask Claude to cd ./subdir (a directory inside the project). The Bash tool reports the new cwd and it persists across subsequent Bash calls — this matches the exact example in the CwdChanged docs (/Users/my-project/Users/my-project/subdir). No CwdChanged log entry appears. ❌
  4. Externally edit mise.toml (mtime updates). No FileChanged log entry appears. ❌

Repeated across multiple fresh claude startups and /resumes. The hook script is never invoked for either event.

What I checked

  • Hook JSON shape matches docs (matcher-wrapped form for SessionStart works; same shape for CwdChanged; matcher: "mise.toml" per the docs' literal-filename syntax for FileChanged).
  • Plugin is loaded (SessionStart proves this).
  • $CLAUDE_ENV_FILE machinery in the hook script is irrelevant — the script writes the log entry before anything else, so even a no-op hook would show up.
  • No managed settings restricting hooks.
  • Version 2.1.153 is well past 2.1.83 which added these events; no CHANGELOG entries since suggest any bug fix to them.
  • #44925 reports the same symptom with the same use case (mise env reload) and was closed stale without developer comment.

Expected

Per docs, CwdChanged should fire when Claude executes cd (the docs' own example matches the test), and FileChanged should fire when a file matched by the matcher is modified on disk.

Actual

Neither fires. Only SessionStart from the same plugin definition produces hook invocations.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗