SessionStart hook only fires for the first ~5 project switches per Claude Code Desktop launch

Resolved 💬 1 comment Opened May 14, 2026 by kalta Closed Jun 12, 2026

Bug: SessionStart hook only fires for the first ~5 project switches per Claude Code Desktop launch

Summary

In Claude Code Desktop on macOS, the SessionStart hook fires reliably for the first 5 project switches after launching the app, then stops firing entirely for any further project switches — until the Desktop app is restarted, at which point the count resets and the next 5 switches fire again.

This breaks any workflow that relies on SessionStart to react to project changes (in my case: opening Zed in the same project the user just switched to in Claude Code Desktop).

CwdChanged was also tested and never fires on Desktop project switches.

Environment

  • Claude Code Desktop: 1.7196.0
  • macOS: 26.3.1 (build 25D771280a)
  • Apple Silicon

Repro

  1. Configure ~/.claude/settings.json with a SessionStart hook that appends to a log file:
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date '+%H:%M:%S')  [SessionStart]  cwd=$CLAUDE_PROJECT_DIR\" >> /tmp/hook.log",
            "async": true
          }
        ]
      }
    ]
  }
}
  1. Launch Claude Code Desktop.
  2. Switch among projects in the Desktop UI more than 5 times (alternating between 2-3 projects is enough).
  3. Inspect /tmp/hook.log.

Expected

SessionStart fires on every project switch.

Actual

SessionStart fires exactly 5 times per Desktop launch, then stops permanently until the app is restarted. Subsequent project switches do not fire SessionStart (and do not fire CwdChanged either).

Evidence

Real log from my machine (annotated). The Desktop was restarted between groups:

# Run 1 — 5 fires, then silence
19:05:34  cwd=/Users/carlosj
19:05:34  cwd=/Volumes/Jellyfin/yt-dlp
19:06:04  cwd=/Users/carlosj/Desarrollo/Public/rcp2_svc
19:06:16  cwd=/Volumes/Jellyfin/yt-dlp
19:06:21  cwd=/Users/carlosj/Desarrollo/Public/rcp2_svc
# … then continued switching for ~3 minutes with NO further hook fires

# Run 2 (Desktop restarted) — 5 fires again, then silence
19:09:34  [SessionStart]  cwd=/Users/carlosj
19:09:35  [SessionStart]  cwd=/Volumes/Jellyfin/yt-dlp
19:09:43  [SessionStart]  cwd=/Users/carlosj/Desarrollo/Public/rcp2_svc
19:09:52  [SessionStart]  cwd=/Volumes/Jellyfin/yt-dlp
19:10:00  [SessionStart]  cwd=/Users/carlosj/Desarrollo/Public/rcp2_svc

# Run 3 (Desktop restarted) — same pattern, 5 fires then silence
19:12:43  [SessionStart]  cwd=/Users/carlosj
19:12:43  [SessionStart]  cwd=/Volumes/Jellyfin/yt-dlp
19:13:01  [SessionStart]  cwd=/Users/carlosj/Desarrollo/Public/rcp2_svc
19:13:09  [SessionStart]  cwd=/Volumes/Jellyfin/yt-dlp
19:13:18  [SessionStart]  cwd=/Users/carlosj/Desarrollo/Public/rcp2_svc
# Switched many more times, no further [SessionStart].
# UserPromptSubmit (used as fallback) DOES still fire from this point onward.

Hypothesis

Claude Code Desktop appears to maintain a pool of up to ~5 pre-warmed SDK processes (visible as claude --resume <id> in ps). The first 5 unique project visits each spawn a fresh SDK process and fire SessionStart. After the pool is full, subsequent project switches route the user to a cached process without firing SessionStart (and without firing CwdChanged).

If this is by design, please consider either:

  1. Firing SessionStart on cached-session reuse as well, OR
  2. Exposing a separate event (e.g. ProjectActivated or SessionResumed) that fires on every project switch in the Desktop UI, regardless of whether a new SDK process spawns.

Workaround currently in use

UserPromptSubmit with deduplication (only call open -a Zed <path> when the path differs from the last) is a working fallback, but adds a lag of one prompt before the editor follows the project switch.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗