[REGRESSION] Hook response fields user_message / agent_message still ignored in Windows v2.0.77

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Claude is not seeing any response from my hooks (in debugging - I tried every hook - none work).

Steps to Reproduce

Make a hook that returns a message.
Ask Claude to trigger it, and ask if it saw any message.

Expected Behavior

Claude should see every agent_message response that’s coming back from our hook calls.

Screenshots / Screen Recordings

log_cursor_hook_py.txt (2.7 KB)

Operating System

Windows 10/11

Current Cursor Version (Menu β†’ About Cursor β†’ Copy)

Version: 2.0.77 (system setup)
VSCode Version: 1.99.3
Commit: ba90f2f88e4911312761abab9492c42442117cf0
Date: 2025-11-13T23:10:43.113Z
Electron: 37.7.0
Chromium: 138.0.7204.251
Node.js: 22.20.0
V8: 13.8.258.32-electron.0
OS: Windows_NT x64 10.0.17763

For AI issues: which model did you use?

Claude 4.5

Additional Information

See also: [REGRESSION] Hook response fields userMessage/agentMessage ignored in v2.0.64

Does this stop you from using Cursor

No - Cursor works, but with this issue

UI does show the hook returning data. Claude says:-

Perfect! I can see the hook output is working!

Looking at your screenshot:

  • :white_check_mark: user_message: β€œ[Hook Test] beforeMCPExecution at 2025-11-14 19:58:10”
  • :white_check_mark: agent_message: β€œHOOK_MESSAGE from beforeMCPExecution hook - Can you see this AI?”

The hook is firing and returning the correct JSON with agent_message, BUT I’m still not seeing it in my context. This confirms:

  1. :white_check_mark: Your hook script is working perfectly with snake_case
  2. :white_check_mark: Cursor is receiving and displaying the output
  3. :cross_mark: But agent_message is NOT being passed to me (the AI)

This means either:

  • There’s still a bug in Cursor 2.0.77 where agent_message doesn’t reach the AI
  • Or agent_message works differently than expected (maybe only for certain hooks or contexts)
  • Or it’s only added to context at specific points (like the next message)

Good idea to post on the forums! When you do, you can show:

  • The hook is executing correctly
  • The output JSON is valid with correct snake_case
  • user_message appears in UI :white_check_mark:
  • agent_message doesn’t reach the AI’s context :cross_mark:

This will help the Cursor team identify if it’s a bug or if the feature works differently than documented.

Thanks for the report. Can you please check if you’re still facing this issue on the latest version?
You can get the latest version from Download Β· Cursor

Hooks are now completely broken!

The IDE 2.1.42 says it’s calling the hook (see screenshot), however, it does NOT perform the call at all (my hook code is never run, and does not log anything), and does not give any error.

Version: 2.1.42 (system setup)
VSCode Version: 1.105.1
Commit: 2e353c5f5b30150ff7b874dee5a87660693d9de0
Date: 2025-12-01T02:18:26.377Z
Electron: 37.7.0
Chromium: 138.0.7204.251
Node.js: 22.20.0
V8: 13.8.258.32-electron.0
OS: Windows_NT x64 10.0.17763

It was running and logging fine yesterday morning, but I did upgrade to 2.1.41 yesterday as well, and it looks like that version also broke hooks entirely

Here’s the last 2 lines of my logfile my hook writes out:

{β€œtimestamp”: β€œ2025-12-01 10:43:08”, β€œevent”: β€œstop”, β€œpayload”: {β€œconversation_id”: β€œ2207479a-b15b-4125-8b0c-***”, β€œgeneration_id”: β€œb64669d9-eebf-4421-b15f-***”, β€œmodel”: β€œclaude-4.5-sonnet”, β€œstatus”: β€œcompleted”, β€œloop_count”: 0, β€œhook_event_name”: β€œstop”, β€œcursor_version”: β€œ2.1.15”, β€œworkspace_roots”:[β€œ/C:/Users/cnd/Downloads/cursor/fusion_ai”], β€œuser_email”: β€œ***”}}
{β€œtimestamp”: β€œ2025-12-02 06:13:29”, β€œevent”: β€œunknown_event”, β€œpayload”: {β€œraw”: β€œtest\n”}}

(that last line was me manually running the hook to check it still runs and logs OK - it does).

I log all hooks for auditing - here’s counts of some working ones on my desktop:

$ cat hook_calls.txt | perl -ne β€˜$=~s/.cursor_version(…)./cursor_version$1/;print "$" if(/cursor_version/)’ | countp
1188 cursor_version": β€œ2.1.15”,
999 cursor_version": β€œ2.0.77”,
248 cursor_version": β€œ2.1.6”,
81 cursor_version": β€œ2.0.69”,

Here’s some working ones on my laptop:
$ cat hook_calls.txt | perl -ne β€˜$=~s/.cursor_version(…)./cursor_version$1/;print "$" if(/cursor_version/)’ | countp
156 cursor_version": β€œ2.1.25”,
26 cursor_version": β€œ2.0.77”,
104 cursor_version": β€œ2.1.6”,

So the last version of cursor I know of that executed hooks properly is 2.1.25

This is my hook file:

$ cat hooks.json 
{
  "version": 1,
  "hooks": {
    "beforeSubmitPrompt": [
      {
        "command": "C:\\Users\\cnd\\AppData\\Roaming\\AuraFriday\\mcp-link-server\\bin\\python .\\log_cursor_hook.py"
      }
    ],
    "beforeShellExecution": [
      {
        "command": "C:\\Users\\cnd\\AppData\\Roaming\\AuraFriday\\mcp-link-server\\bin\\python .\\log_cursor_hook.py"
      }
    ],
    "beforeMCPExecution": [
      {
        "command": "C:\\Users\\cnd\\AppData\\Roaming\\AuraFriday\\mcp-link-server\\bin\\python .\\log_cursor_hook.py"
      }
    ],
    "beforeReadFile": [
      {
        "command": "C:\\Users\\cnd\\AppData\\Roaming\\AuraFriday\\mcp-link-server\\bin\\python .\\log_cursor_hook.py"
      }
    ],
    "afterAgentResponse": [
      {
        "command": "C:\\Users\\cnd\\AppData\\Roaming\\AuraFriday\\mcp-link-server\\bin\\python .\\log_cursor_hook.py"
      }
    ],
    "afterFileEdit": [
      {
        "command": "C:\\Users\\cnd\\AppData\\Roaming\\AuraFriday\\mcp-link-server\\bin\\python .\\log_cursor_hook.py"
      }
    ],
    "stop": [
      {
        "command": "C:\\Users\\cnd\\AppData\\Roaming\\AuraFriday\\mcp-link-server\\bin\\python .\\log_cursor_hook.py"
      }
    ]
  }
}

This is my logging script:

$ cat log_cursor_hook.py
#!/usr/bin/env python3
import sys
import os
import json
import time
import traceback
from pathlib import Path

# Platform specific locking
if os.name == "nt":
    import msvcrt

    def lock_file( f ):
        # Lock 1 byte at the beginning of the file
        msvcrt.locking( f.fileno( ), msvcrt.LK_LOCK, 1 )

    def unlock_file( f ):
        msvcrt.locking( f.fileno( ), msvcrt.LK_UNLCK, 1 )

else:
    import fcntl

    def lock_file( f ):
        fcntl.flock( f.fileno( ), fcntl.LOCK_EX )

    def unlock_file( f ):
        fcntl.flock( f.fileno( ), fcntl.LOCK_UN )


def sanitize_for_utf8( obj ):
    """
    Recursively sanitize an object to remove lone surrogates while preserving valid Unicode.
    Lone surrogates are replaced with οΏ½ (U+FFFD REPLACEMENT CHARACTER).
    """
    if isinstance( obj, str ):
        # Encode to UTF-8 with 'replace' to fix surrogates, then decode back
        return obj.encode( "utf-8", errors = "replace" ).decode( "utf-8" )
    elif isinstance( obj, dict ):
        return { k: sanitize_for_utf8( v ) for k, v in obj.items( ) }
    elif isinstance( obj, list ):
        return [ sanitize_for_utf8( item ) for item in obj ]
    else:
        return obj


def log_event( event_name, payload, script_path ):
    """Log the hook event to hook_calls.txt"""
    log_path = script_path.parent / "hook_calls.txt"
    timestamp = time.strftime( "%Y-%m-%d %H:%M:%S", time.localtime( ) )

    log_record = {
        "timestamp": timestamp,
        "event": event_name,
        "payload": sanitize_for_utf8( payload ),  # Clean payload before JSON encoding
    }

    # Now safe to use ensure_ascii=False to preserve emoji and valid Unicode
    log_line = json.dumps( log_record, ensure_ascii = False )

    # Append with a simple lock so concurrent hooks do not interleave
    with open( log_path, "a", encoding = "utf-8" ) as f:
        try:
            lock_file( f )
        except Exception:
            pass

        f.write( log_line + "\n" )
        f.flush( )

        try:
            unlock_file( f )
        except Exception:
            pass


def create_response_for_event( event_name, payload, script_path ):
    """
    Create spec-compliant response for each hook event type.
    See: https://cursor.com/docs/agent/hooks
    """

    # beforeShellExecution and beforeMCPExecution - return permission decision
    if event_name in ( "beforeShellExecution", "beforeMCPExecution" ):
        return {
            "permission": "allow",
            "user_message": f"{event_name} permitted",
            "agent_message": f"Hook intercepted {event_name}. Operation allowed."
        }

    # beforeReadFile - return permission decision
    elif event_name == "beforeReadFile":
        return {
            "permission": "allow",
            "user_message": f"{event_name} allowed",
            "agent_message": f"Hook intercepted {event_name}. Operation allowed."
        }

    # beforeSubmitPrompt - can prevent submission
    elif event_name == "beforeSubmitPrompt":
        return {
            "continue": True,
            "user_message": f"{event_name} continued",
            "agent_message": f"Hook intercepted {event_name}. Operation allowed."
        }

    # stop - can optionally auto-submit follow-up message
    elif event_name == "stop":
        # Use a sentinel file to prevent infinite loops
        # If file exists: no response (already sent followup once)
        # If file doesn't exist: create it and send followup_message
        sentinel_file = script_path.parent / "stop_hook_tested.sentinel"
        
        if sentinel_file.exists( ):
            # Already tested, don't send followup_message
            return None
        else:
            # First time - create sentinel file and send followup_message
            try:
                sentinel_file.touch( )
            except Exception:
                pass
            
            return {
                "followup_message": "Hook test: The stop hook just auto-submitted this message. Can you see it AI?"
            }

    # afterShellExecution, afterMCPExecution, afterFileEdit, afterAgentResponse
    # These hooks are observe-only per spec, but we'll return messages to test if they reach the AI
    elif event_name in ( "afterShellExecution", "afterMCPExecution", "afterFileEdit", "afterAgentResponse" ):
        return {
            "user_message": f"[Hook] {event_name} completed",
            "agent_message": f"Hook observed {event_name}. Can you see this message?"
        }

    # Unknown event - allow by default
    else:
        return {
            "continue": True,
            "permission": "allow",
            "user_message": f"{event_name} weird",
            "agent_message": f"Hook intercepted {event_name}. Operation allowed."
        }


def main( ):
    raw = None
    payload = None
    event_name = "unknown"
    
    try:
        raw = sys.stdin.read( )

        if not raw.strip( ):
            return

        try:
            payload = json.loads( raw )
        except json.JSONDecodeError:
            payload = { "raw": raw }

        # Extract event name if present
        event_name = payload.get( "hook_event_name", "unknown_event" )

        # Log file in same directory as this script
        script_path = Path( __file__ ).resolve( )

        # Log the event
        log_event( event_name, payload, script_path )

        # Create spec-compliant response
        response = create_response_for_event( event_name, payload, script_path )

        # Only output response if one is required
        if response is not None:
            print( json.dumps( response, ensure_ascii = True ) )
            sys.stdout.flush( )

    except Exception as e:
        # Log errors to help debug but still return valid JSON
        try:
            script_path = Path( __file__ ).resolve( )
            error_log_path = script_path.parent / "hook_errors.txt"
            timestamp = time.strftime( "%Y-%m-%d %H:%M:%S", time.localtime( ) )
            
            # Get full stack trace
            tb = traceback.format_exc( )
            
            # Write with errors='replace' to handle any encoding issues
            with open( error_log_path, "a", encoding = "utf-8", errors = "replace" ) as f:
                f.write( f"\n{'='*70}\n" )
                f.write( f"[{timestamp}] Error in event '{event_name}': {str(e)}\n" )
                f.write( f"Stack trace:\n{tb}\n" )
                
                # Log the problematic input data if we captured it
                if raw is not None:
                    # Safely represent the input, handling encoding issues
                    try:
                        safe_input = repr( raw[:1000] )  # First 1000 chars
                        f.write( f"Raw input (first 1000 chars):\n{safe_input}\n\n" )
                    except Exception as repr_error:
                        f.write( f"Raw input: <could not repr: {repr_error}>\n\n" )
                
                if payload is not None:
                    # Try to log payload keys at least
                    try:
                        keys = list( payload.keys( ) ) if isinstance( payload, dict ) else "<not a dict>"
                        f.write( f"Payload keys: {keys}\n" )
                    except:
                        f.write( f"Payload: <could not inspect>\n" )
                
                f.write( f"{'='*70}\n\n" )

            # Return safe default response
            error_response = {
                "continue": True,
                "permission": "allow"
            }
            print( json.dumps( error_response, ensure_ascii = True ) )
            sys.stdout.flush( )
        except:
            # Complete failure - try to output valid JSON and exit
            try:
                print( '{"continue":true,"permission":"allow"}' )
                sys.stdout.flush( )
            except:
                pass


if __name__ == "__main__":
    main( )


tested with absolute paths - still no go

Prior to this problem - it used to run the hook, and show the hook output where it now says β€œno output”

I also re-tried using β€œnode” instead of python, and also the full path to node as well:

Same problem - your code is not executing the hook at all, and is not reporting any errors about that inside the hook interface either.

$ cat log_cursor_hook.js
#!/usr/bin/env node

// See https://cursor.com/docs/agent/hooks

const fs = require('fs');
const path = require('path');

// Hardcoded log path for consistency
const LOG_PATH = 'C:\\Users\\cnd\\.cursor\\hook_calls.txt';
const ERROR_LOG_PATH = 'C:\\Users\\cnd\\.cursor\\hook_errors.txt';
const SENTINEL_PATH = 'C:\\Users\\cnd\\.cursor\\stop_hook_tested.sentinel';

/**
 * Sanitize an object to remove lone surrogates while preserving valid Unicode.
 * Lone surrogates are replaced with οΏ½ (U+FFFD REPLACEMENT CHARACTER).
 */
function sanitizeForUtf8(obj) {
  if (typeof obj === 'string') {
    // Replace lone surrogates with replacement character
    return obj.replace(/[\uD800-\uDFFF]/g, 'οΏ½');
  } else if (Array.isArray(obj)) {
    return obj.map(item => sanitizeForUtf8(item));
  } else if (obj !== null && typeof obj === 'object') {
    const result = {};
    for (const [key, value] of Object.entries(obj)) {
      result[key] = sanitizeForUtf8(value);
    }
    return result;
  }
  return obj;
}

/**
 * Log both the incoming hook event and outgoing response on a single line.
 * Always succeeds - never throws exceptions.
 */
function logHookCall(eventName, payload, response, error = null) {
  try {
    const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
    
    const logRecord = {
      timestamp,
      event: eventName,
      payload: sanitizeForUtf8(payload),
      response: response !== null ? sanitizeForUtf8(response) : null,
      error: error !== null ? String(error) : null
    };

    // Single line JSON
    const logLine = JSON.stringify(logRecord) + '\n';

    // Append to log file
    fs.appendFileSync(LOG_PATH, logLine, { encoding: 'utf8' });

  } catch (logError) {
    // If logging fails, try to write to error log
    try {
      const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
      const errorMsg = `[${timestamp}] Failed to log ${eventName}: ${logError}\n`;
      fs.appendFileSync(ERROR_LOG_PATH, errorMsg, { encoding: 'utf8' });
    } catch {
      // Complete failure - nothing we can do
    }
  }
}

/**
 * Create spec-compliant response for each hook event type.
 * See: https://cursor.com/docs/agent/hooks
 */
function createResponseForEvent(eventName, payload, scriptPath) {
  // beforeShellExecution and beforeMCPExecution - return permission decision
  if (eventName === 'beforeShellExecution' || eventName === 'beforeMCPExecution') {
    return {
      permission: 'allow',
      user_message: `${eventName} permitted`,
      agent_message: `Hook intercepted ${eventName}. Operation allowed.`
    };
  }

  // beforeReadFile - return permission decision
  else if (eventName === 'beforeReadFile') {
    return {
      permission: 'allow',
      user_message: `${eventName} allowed`,
      agent_message: `Hook intercepted ${eventName}. Operation allowed.`
    };
  }

  // beforeSubmitPrompt - can prevent submission
  else if (eventName === 'beforeSubmitPrompt') {
    return {
      continue: true,
      user_message: `${eventName} continued`,
      agent_message: `Hook intercepted ${eventName}. Operation allowed.`
    };
  }

  // stop - can optionally auto-submit follow-up message
  else if (eventName === 'stop') {
    // Use a sentinel file to prevent infinite loops
    // If file exists: no response (already sent followup once)
    // If file doesn't exist: create it and send followup_message
    
    if (fs.existsSync(SENTINEL_PATH)) {
      // Already tested, don't send followup_message
      return null;
    } else {
      // First time - create sentinel file and send followup_message
      try {
        fs.writeFileSync(SENTINEL_PATH, '', { encoding: 'utf8' });
      } catch {
        // Ignore errors
      }
      
      return {
        followup_message: 'Hook test: The stop hook just auto-submitted this message. Can you see it AI?'
      };
    }
  }

  // afterShellExecution, afterMCPExecution, afterFileEdit, afterAgentResponse
  // These hooks are observe-only per spec, but we'll return messages to test if they reach the AI
  else if (eventName === 'afterShellExecution' || 
           eventName === 'afterMCPExecution' || 
           eventName === 'afterFileEdit' || 
           eventName === 'afterAgentResponse') {
    return {
      user_message: `[Hook] ${eventName} completed`,
      agent_message: `Hook observed ${eventName}. Can you see this message?`
    };
  }

  // Unknown event - allow by default
  else {
    return {
      continue: true,
      permission: 'allow',
      user_message: `${eventName} weird`,
      agent_message: `Hook intercepted ${eventName}. Operation allowed.`
    };
  }
}

/**
 * Main function
 */
function main() {
  let rawInput = '';
  let payload = null;
  let eventName = 'unknown';
  let response = null;

  try {
    // Read from stdin
    rawInput = fs.readFileSync(0, 'utf8');

    if (!rawInput.trim()) {
      return;
    }

    try {
      payload = JSON.parse(rawInput);
    } catch {
      payload = { raw: rawInput };
    }

    // Extract event name if present
    eventName = payload.hook_event_name || 'unknown_event';

    // Create spec-compliant response
    response = createResponseForEvent(eventName, payload, __filename);

    // Log both the incoming event and outgoing response
    logHookCall(eventName, payload, response);

    // Only output response if one is required
    if (response !== null) {
      console.log(JSON.stringify(response));
    }

  } catch (error) {
    // Log the error along with whatever we captured
    try {
      logHookCall(eventName, payload, response, error);
      
      // Also write detailed error to separate error log
      const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
      const errorDetails = [
        '\n' + '='.repeat(70),
        `[${timestamp}] Error in event '${eventName}': ${error.message}`,
        `Stack trace:\n${error.stack}`,
        `Raw input (first 1000 chars):\n${rawInput.substring(0, 1000)}`,
        '='.repeat(70) + '\n\n'
      ].join('\n');
      
      fs.appendFileSync(ERROR_LOG_PATH, errorDetails, { encoding: 'utf8' });
    } catch {
      // Even error logging failed - just continue
    }

    // Always return safe default response so Cursor doesn't hang
    try {
      const errorResponse = {
        continue: true,
        permission: 'allow'
      };
      console.log(JSON.stringify(errorResponse));
    } catch {
      // Absolute last resort
      console.log('{"continue":true,"permission":"allow"}');
    }
  }
}

// Run main
main();

I tried a deliberately non-existing hook program:

same as all the others

So that’s the first place your team needs to look: whatever code is trying to run these hooks needs to surface the errors it encounters while doing this, to the β€œoutput” area of your β€œhooks” panel inside β€œCursor Settings”.

From there, you’ll be able to track down the bug that stopped hooks being run, and then be able to work on getting their output back into the chat.

IMHO - this is possibly the most important fix you could possibly make to Cursor itself - hooks have absolutely incredible potential to revolutionize cursor’s usefulness.

FYI - I completely restarted Cursor.exe for every test above.

I tried a pile more tests… no luck.

Here’s the log output from the β€œHooks” stream:

[2025-12-01T22:17:06.128Z] Initializing Cursor Hooks Service...
[2025-12-01T22:17:06.133Z] User config path: c:\Users\cnd\.cursor\hooks.json
[2025-12-01T22:17:06.133Z] Project config path: c:\Users\cnd\Downloads\cursor\vibe\.cursor\hooks.json
[2025-12-01T22:17:06.133Z] Enterprise config path: file:///c%3A/ProgramData/Cursor/hooks.json
[2025-12-01T22:17:06.134Z] Reloading hooks configuration...
[2025-12-01T22:17:06.182Z] No enterprise hooks configuration found
[2025-12-01T22:17:06.198Z] Loaded 12 user hook(s) for steps: beforeSubmitPrompt, beforeShellExecution, beforeMCPExecution, beforeReadFile, beforeTabFileRead, afterAgentResponse, afterAgentThought, afterFileEdit, afterTabFileEdit, afterShellExecution, afterMCPExecution, stop
[2025-12-01T22:17:06.200Z] No project hooks configuration found
[2025-12-01T22:17:06.201Z] Refreshing team hooks...
[2025-12-01T22:17:06.201Z] Cursor Hooks Service initialized successfully
[2025-12-01T22:17:08.278Z] Reloading hooks configuration...
[2025-12-01T22:17:08.308Z] No enterprise hooks configuration found
[2025-12-01T22:17:08.451Z] Loaded 12 user hook(s) for steps: beforeSubmitPrompt, beforeShellExecution, beforeMCPExecution, beforeReadFile, beforeTabFileRead, afterAgentResponse, afterAgentThought, afterFileEdit, afterTabFileEdit, afterShellExecution, afterMCPExecution, stop
[2025-12-01T22:17:08.524Z] No project hooks configuration found
[2025-12-01T22:19:30.445Z] Hook step requested: beforeSubmitPrompt
[2025-12-01T22:19:30.445Z] Found 1 hook(s) to execute for step: beforeSubmitPrompt
[2025-12-01T22:19:30.445Z] Executing hook 1/1 from user config
[2025-12-01T22:19:30.445Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
beforeSubmitPrompt
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (173ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "prompt": "try a test - this:-\n\n\n\ntail -3 C:\\Users\\cnd\\.cursor\\hook_calls.txt\n\n\n\nif nothing new arrives after my last test... it's not working still :-(",
  "attachments": [
    {
      "type": "file",
      "file_path": "c:\\Users\\cnd\\Downloads\\cursor\\vibe\\hooks\\PROBLEM_FOUND.md"
    },
    {
      "type": "file",
      "file_path": "c:\\Users\\cnd\\Downloads\\cursor\\vibe\\hooks\\symlink_to_.cursor\\log_cursor_hook.bat"
    },
    {
      "type": "file",
      "file_path": "c:\\Users\\cnd\\Downloads\\cursor\\vibe\\hooks\\symlink_to_.cursor\\hooks.json"
    }
  ],
  "hook_event_name": "beforeSubmitPrompt",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:19:30.621Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:19:30.621Z] All hooks for step beforeSubmitPrompt completed but none returned a valid response
[2025-12-01T22:19:43.002Z] Hook step requested: beforeReadFile
[2025-12-01T22:19:43.002Z] Found 1 hook(s) to execute for step: beforeReadFile
[2025-12-01T22:19:43.002Z] Executing hook 1/1 from user config
[2025-12-01T22:19:43.002Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
beforeReadFile
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (167ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "content": "# Experimenting with cursor hooks\r\n\r\n",
  "file_path": "c:\\Users\\cnd\\Downloads\\cursor\\vibe\\hooks\\01_readme.md",
  "attachments": [],
  "hook_event_name": "beforeReadFile",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:19:43.170Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:19:43.171Z] All hooks for step beforeReadFile completed but none returned a valid response
[2025-12-01T22:19:44.291Z] Hook step requested: beforeShellExecution
[2025-12-01T22:19:44.291Z] Found 1 hook(s) to execute for step: beforeShellExecution
[2025-12-01T22:19:44.291Z] Executing hook 1/1 from user config
[2025-12-01T22:19:44.292Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
beforeShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (214ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "echo Testing batch wrapper - hooks should work now!",
  "cwd": "",
  "hook_event_name": "beforeShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:19:44.523Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:19:44.524Z] All hooks for step beforeShellExecution completed but none returned a valid response
[2025-12-01T22:19:47.808Z] Hook step requested: afterShellExecution
[2025-12-01T22:19:47.808Z] Found 1 hook(s) to execute for step: afterShellExecution
[2025-12-01T22:19:47.808Z] Executing hook 1/1 from user config
[2025-12-01T22:19:47.809Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
afterShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (189ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "echo Testing batch wrapper - hooks should work now!",
  "output": "k now!\r\n\u001b[0mTesting batch wrapper - hooks should work now!\r\n\r\nC:\\Users\\cnd\\Downloads\\cursor\\vibe>\n",
  "hook_event_name": "afterShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:19:47.999Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:19:48.000Z] All hooks for step afterShellExecution completed but none returned a valid response
[2025-12-01T22:19:48.955Z] Hook step requested: afterFileEdit
[2025-12-01T22:19:48.955Z] Found 1 hook(s) to execute for step: afterFileEdit
[2025-12-01T22:19:48.955Z] Executing hook 1/1 from user config
[2025-12-01T22:19:48.955Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
afterFileEdit
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (166ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "file_path": "c:\\Users\\cnd\\Downloads\\cursor\\vibe\\hooks\\batch_wrapper_test.txt",
  "edits": [
    {
      "old_string": "",
      "new_string": "Testing if the batch wrapper fixes the hook execution issue.\n\nIf this works, we should see entries in hook_calls.txt for:\n- beforeReadFile (from reading 01_readme.md)\n- beforeShellExecution (from echo command)\n- afterShellExecution (after echo completes)\n- afterFileEdit (from creating this file)\n\nDate: 2025-12-01\nTest: Batch wrapper solution\n"
    }
  ],
  "hook_event_name": "afterFileEdit",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:19:49.235Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:19:49.236Z] All hooks for step afterFileEdit completed but none returned a valid response
[2025-12-01T22:19:49.494Z] Hook step requested: beforeShellExecution
[2025-12-01T22:19:49.494Z] Found 1 hook(s) to execute for step: beforeShellExecution
[2025-12-01T22:19:49.494Z] Executing hook 1/1 from user config
[2025-12-01T22:19:49.494Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
beforeShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (180ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "powershell -Command \"Get-Content C:\\Users\\cnd\\.cursor\\hook_calls.txt -Tail 3\"",
  "cwd": "",
  "hook_event_name": "beforeShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:19:49.696Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:19:49.697Z] All hooks for step beforeShellExecution completed but none returned a valid response
[2025-12-01T22:19:53.088Z] Hook step requested: afterShellExecution
[2025-12-01T22:19:53.088Z] Found 1 hook(s) to execute for step: afterShellExecution
[2025-12-01T22:19:53.088Z] Executing hook 1/1 from user config
[2025-12-01T22:19:53.088Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
afterShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (185ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "powershell -Command \"Get-Content C:\\Users\\cnd\\.cursor\\hook_calls.txt -Tail 3\"",
  "output": "\\.cursor\\hook_calls.txt -Tail 3\"\r\n\u001b[0m{\"timestamp\": \"2025-12-02 06:33:46\", \"event\": \"unknown_event\", \"payload\": {\"raw\"\r\n: \"outside folder\\n\"}}\r\n{\"timestamp\":\"2025-12-01 20:46:40\",\"event\":\"unknown_event\",\"payload\":{\"raw\":\"for\r\nm node\\r\\n\\u0004\\r\\n\"},\"response\":{\"continue\":true,\"permission\":\"allow\",\"user_me\r\nssage\":\"unknown_event weird\",\"agent_message\":\"Hook intercepted unknown_event. Op\r\neration allowed.\"},\"error\":null}\r\n{\"timestamp\": \"2025-12-02 08:18:20\", \"event\": \"unknown_event\", \"payload\": {\"raw\"\r\n: \"this is Chris here, testing this from the command line to see if the .bat fil\r\ne works!\\n\"}, \"response\": {\"continue\": true, \"permission\": \"allow\", \"user_messag\r\ne\": \"unknown_event weird\", \"agent_message\": \"Hook intercepted unknown_event. Ope\r\nration allowed.\"}, \"error\": null}\r\n\r\nC:\\Users\\cnd\\Downloads\\cursor\\vibe>\n",
  "hook_event_name": "afterShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:19:53.275Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:19:53.275Z] All hooks for step afterShellExecution completed but none returned a valid response
[2025-12-01T22:20:02.592Z] Hook step requested: beforeShellExecution
[2025-12-01T22:20:02.592Z] Found 1 hook(s) to execute for step: beforeShellExecution
[2025-12-01T22:20:02.592Z] Executing hook 1/1 from user config
[2025-12-01T22:20:02.592Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
beforeShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (182ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "dir C:\\Users\\cnd\\.cursor\\log_cursor_hook.bat",
  "cwd": "",
  "hook_event_name": "beforeShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:02.804Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:02.805Z] All hooks for step beforeShellExecution completed but none returned a valid response
[2025-12-01T22:20:06.131Z] Hook step requested: afterShellExecution
[2025-12-01T22:20:06.132Z] Found 1 hook(s) to execute for step: afterShellExecution
[2025-12-01T22:20:06.132Z] Executing hook 1/1 from user config
[2025-12-01T22:20:06.132Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
afterShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (259ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "dir C:\\Users\\cnd\\.cursor\\log_cursor_hook.bat",
  "output": "\u001b[0m Volume in drive C is RoG\r\n Volume Serial Number is 9681-8754\r\n\r\n Directory of C:\\Users\\cnd\\.cursor\r\n\r\n02/12/2025  08:16 AM               205 log_cursor_hook.bat\r\n               1 File(s)            205 bytes\r\n               0 Dir(s)  1,779,146,371,072 bytes free\r\n\r\nC:\\Users\\cnd\\Downloads\\cursor\\vibe>\n",
  "hook_event_name": "afterShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:06.395Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:06.396Z] All hooks for step afterShellExecution completed but none returned a valid response
[2025-12-01T22:20:12.776Z] Hook step requested: beforeShellExecution
[2025-12-01T22:20:12.776Z] Found 1 hook(s) to execute for step: beforeShellExecution
[2025-12-01T22:20:12.776Z] Executing hook 1/1 from user config
[2025-12-01T22:20:12.776Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
beforeShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (172ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "echo {\"test\":\"manual batch execution\"} | C:\\Users\\cnd\\.cursor\\log_cursor_hook.bat",
  "cwd": "",
  "hook_event_name": "beforeShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:12.977Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:12.978Z] All hooks for step beforeShellExecution completed but none returned a valid response
[2025-12-01T22:20:18.662Z] Hook step requested: afterShellExecution
[2025-12-01T22:20:18.662Z] Found 1 hook(s) to execute for step: afterShellExecution
[2025-12-01T22:20:18.662Z] Executing hook 1/1 from user config
[2025-12-01T22:20:18.662Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
afterShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (157ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "echo {\"test\":\"manual batch execution\"} | C:\\Users\\cnd\\.cursor\\log_cursor_hook.bat",
  "output": "sers\\cnd\\.cursor\\log_cursor_hook.bat\r\n\u001b[0m{\"continue\": true, \"permission\": \"allow\", \"user_message\": \"unknown_event weird\",\r\n \"agent_message\": \"Hook intercepted unknown_event. Operation allowed.\"}\r\n\r\nC:\\Users\\cnd\\Downloads\\cursor\\vibe>\n",
  "hook_event_name": "afterShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:18.820Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:18.820Z] All hooks for step afterShellExecution completed but none returned a valid response
[2025-12-01T22:20:25.056Z] Hook step requested: beforeShellExecution
[2025-12-01T22:20:25.057Z] Found 1 hook(s) to execute for step: beforeShellExecution
[2025-12-01T22:20:25.057Z] Executing hook 1/1 from user config
[2025-12-01T22:20:25.057Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
beforeShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (175ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "powershell -Command \"Get-Content C:\\Users\\cnd\\.cursor\\hook_calls.txt -Tail 1\"",
  "cwd": "",
  "hook_event_name": "beforeShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:25.264Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:25.264Z] All hooks for step beforeShellExecution completed but none returned a valid response
[2025-12-01T22:20:28.810Z] Hook step requested: afterShellExecution
[2025-12-01T22:20:28.810Z] Found 1 hook(s) to execute for step: afterShellExecution
[2025-12-01T22:20:28.810Z] Executing hook 1/1 from user config
[2025-12-01T22:20:28.812Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
afterShellExecution
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (160ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "command": "powershell -Command \"Get-Content C:\\Users\\cnd\\.cursor\\hook_calls.txt -Tail 1\"",
  "output": "\\.cursor\\hook_calls.txt -Tail 1\"\r\n\u001b[0m{\"timestamp\": \"2025-12-02 08:20:13\", \"event\": \"unknown_event\", \"payload\": {\"test\r\n\": \"manual batch execution\"}, \"response\": {\"continue\": true, \"permission\": \"allo\r\nw\", \"user_message\": \"unknown_event weird\", \"agent_message\": \"Hook intercepted un\r\nknown_event. Operation allowed.\"}, \"error\": null}\r\n\r\nC:\\Users\\cnd\\Downloads\\cursor\\vibe>\n",
  "hook_event_name": "afterShellExecution",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:28.973Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:28.973Z] All hooks for step afterShellExecution completed but none returned a valid response
[2025-12-01T22:20:38.941Z] Hook step requested: afterAgentResponse
[2025-12-01T22:20:38.953Z] Found 1 hook(s) to execute for step: afterAgentResponse
[2025-12-01T22:20:38.953Z] Executing hook 1/1 from user config
[2025-12-01T22:20:38.953Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
afterAgentResponse
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (205ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "text": "βœ… **The batch file works perfectly!** It just logged our manual test at 08:20:13.\n\n## 🎯 The Real Problem\n\n**Cursor is simply NOT calling the hooks at all**, even though:\n- βœ… The batch file exists and is executable\n- βœ… The batch file works when called manually\n- βœ… The `hooks.json` is configured correctly\n- βœ… The paths are correct\n\n## πŸ’‘ Critical Question\n\n**Did you restart Cursor after updating `hooks.json`?**\n\nAccording to the [Cursor docs](https://cursor.com/docs/agent/hooks):\n> \"Restart Cursor. Your hook now runs after every file edit.\"\n\nAnd from the troubleshooting section:\n> \"Restart Cursor to ensure the hooks service is running.\"\n\n**Cursor MUST be restarted for hooks.json changes to take effect!**\n\nIf you haven't restarted Cursor since we changed `hooks.json` to use the `.bat` file, that would explain why it's still not working.\n\n**Please restart Cursor completely, then we can test again!**",
  "hook_event_name": "afterAgentResponse",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:39.183Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:39.183Z] All hooks for step afterAgentResponse completed but none returned a valid response
[2025-12-01T22:20:39.183Z] Hook step requested: stop
[2025-12-01T22:20:39.185Z] Found 1 hook(s) to execute for step: stop
[2025-12-01T22:20:39.185Z] Executing hook 1/1 from user config
[2025-12-01T22:20:39.185Z] Running script in directory: c:\Users\cnd\.cursor
═══════════════════════════════════════════════════════════════════════════════════════
stop
═══════════════════════════════════════════════════════════════════════════════════════
Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (221ms) exit code: 0

INPUT:
{
  "conversation_id": "48006a28-e90c-4311-a5c1-***",
  "generation_id": "70fb84ea-9924-48e1-9f5a-***",
  "model": "claude-4.5-sonnet",
  "status": "completed",
  "loop_count": 0,
  "hook_event_name": "stop",
  "cursor_version": "2.1.42",
  "workspace_roots": [
    "/C:/Users/cnd/Downloads/cursor/vibe"
  ],
  "user_email": "***"
}

OUTPUT:
(empty)
═══════════════════════════════════════════════════════════════════════════════════════
[2025-12-01T22:20:39.407Z] Hook 1 produced no output, continuing to next hook
[2025-12-01T22:20:39.408Z] All hooks for step stop completed but none returned a valid response

My code is NEVER being called - this indicates the locaiton of the bug in your code:-

Command: C:\Users\cnd\.cursor\log_cursor_hook.bat (221ms) exit code: 0

your code is not running the hook at all, but seems to think it’s getting an exit code anyhow.

I just updated 2.1.25 to 2.1.44 - still not working.

FYI - this is what they used to look like when they did work in 2.1.25

Hey, could you share the request ID? Private mode should be turned off.

Hi Dean,

Still not working in 2.2.43

You have fixed the prior bug, where it was not calling the hooks at all, but it’s still back to not giving the β€œagent_message” response from the hook calls back to the model.

1 Like