Where does the bug appear (feature/product)?
Cursor IDE
Describe the Bug
A project sessionStart hook in .cursor/hooks.json never runs for the chat that a window creates while it is opening. Cursor creates that chat before the window’s hooks service has loaded the project hooks, so the hasHookForStep(sessionStart) check at chat creation returns false, and nothing runs the step for that chat afterward. Messages in that chat reach the model without the hook’s additional_context, and the hook’s env is never set. A chat created later in the same window runs the hook normally.
This differs from the confirmed additional_context race in 158452 (also topics 157141 and 167274): there the hook runs and its output is dropped; here the hook never runs. It matches the pattern of 172939, where workspaceOpen is dispatched before project hooks are registered and never replayed.
Timeline from the Hooks output channel and each chat’s stored createdAt (UTC, single window):
- 21:50:12.352: hooks service starts without a workspace folder (“No workspace folder found, project hooks will not be available”)
- 21:50:14.387: chat A created (
createdAt) - 21:50:14.510: hooks service for the workspace starts
- 21:50:14.801: “Loaded 13 project hook(s) for steps: sessionStart, preToolUse, beforeSubmitPrompt, stop, sessionEnd”
- 21:50:20.603: first message in chat A; the first log entry for its conversation_id is
beforeSubmitPrompt, and the log has no “Hook step requested: sessionStart” for chat A - 21:51:09.488: chat B created in the same window; “Hook step requested: sessionStart” logged at 21:51:09.488 as well; all 5 hooks run
- 21:51:11.308: “Merged 5 valid response(s) for step sessionStart” (chat B)
OursessionStarthook also writes a marker file persession_id: chat B has one, chat A has none.
Inworkbench.desktop.main.jsandworkbench.glass.main.js, the chat-creation path is the only place that runs the step; each bundle has oneexecuteHookForStep(…sessionStartcall and onehasHookForStep(…sessionStart)check:
this.cursorHooksService.initializeSessionTracking(g,x),this.cursorHooksService.hasHookForStep(Du.sessionStart)&&(async()=>{ … executeHookForStep … })();let A;try{A=await this.composerDataService.appendComposer_DO_NOT_CALL_UNLESS_YOU_KNOW_WHAT_YOURE_DOING(E)}
Steps to Reproduce
From the occurrence above; not yet repeated in a clean project.
- Add a project
.cursor/hooks.jsonwith asessionStarthook that appendssession_idto a log file and prints{"additional_context": "Session marker: TEST-123"}. - Open the project in a new window. In our log, the window’s hooks service started without a folder and loaded the project hooks about 2.4 s later.
- Without creating a new chat, send a message in the chat the window shows after opening.
- The Hooks output channel shows no “Hook step requested: sessionStart” for that conversation, and the log file has no line for its
session_id. - Create a new chat in the same window and send a message: the hook runs.
Expected Behavior
sessionStart runs once for every chat, including a chat created before the hooks configuration finishes loading. For example, wait for the hooks service to load before the hasHookForStep check, or run a skipped sessionStart after project hooks are registered and before the chat’s first request.
Operating System
MacOS
Version Information
Cursor 3.27.12 (commit df132ffba90dfc15a12e6b8f020ba4e5d026c4b0), VS Code 1.128.0, macOS 27.0 (26A428), arm64. Structured logs report layout: unifiedAgent.
Does this stop you from using Cursor
No - Cursor works, but with this issue