Capture Agent Context with Your First Cursor Hook

Cursor hooks provide a powerful way to run custom scripts in response to AI agent actions, giving you the ability to intercept workflows, inject context, or trigger automations. This lesson introduces the fundamental mechanics of hooks through the beforeReadFile event, which executes a command just before the AI agent accesses a file.

You'll configure the .cursor/hooks.json file, write a simple shell script to capture the JSON payload sent by the hook, and examine the rich contextual data it contains—details like file path, content, and conversation ID. This data opens up endless possibilities for automation and workflow enhancement.

A critical and often-missed step is making your script executable with chmod. Without this, your hooks will fail silently, and you'll wonder why nothing is working. By the end of this lesson, you'll have a working hook and understand the foundation for building more sophisticated automations.

The Configuration: hooks.json

First, create a .cursor directory in your project root and add a hooks.json file. This file defines which scripts to run for specific events. For this example, we'll run a debug.sh script every time the beforeReadFile event is triggered.

{ "version": 1, "hooks": { "beforeReadFile": [ { "command": "./debug.sh" } ] } }

The Script: debug.sh

Next, create the debug.sh script inside the .cursor directory. The hook will pass a JSON payload to this script via standard input. We can capture this payload by redirecting stdin to a file.

cat > stdin.json

The Critical Step: Making it Executable

For the hook to successfully run the script, the script file must have execute permissions. This is a common point of failure. Open your terminal and run the following command:

chmod +x .cursor/debug.sh

Triggering the Hook

Now, you can ask the agent to perform an action that reads a file.

Please read the debug file.

After the agent attempts to read the file, the hook will execute, and you will find a new stdin.json file in your .cursor directory.

The Result: The Captured Payload

The generated stdin.json file contains a wealth of information about the event, including the conversation context and details about the file being accessed. This data can be parsed and used in more complex scripts to build powerful automations.

{ "conversation_id": "b962916e-5236-47e9-a469-9b4ac8847737", "generation_id": "fbf381f2-40b6-4b4c-9642-4bdbfd618fc2", "content": "cat > stdin.json", "file_path": "/Users/johnlindquist/dev/cursor-hooks-lessons/.cursor/debug.sh", "attachments": [], "hook_event_name": "beforeReadFile", "workspace_roots": ["/Users/johnlindquist/dev/cursor-hooks-lessons"] }
Advanced Cursor Hooks
8 lessons

Advanced Cursor Hooks

Learn to build type-safe Cursor hooks with TypeScript & Bun. Automate AI-assisted coding, enforce standards, and streamline your development workflow.

Share with a coworker

Transcript

[00:00] To set up our first cursor hook we're going to create a cursor directory with a hooks.json file inside of it. And once we create that, this has a couple requirements. It needs a version, which we'll set to version 1, and then it needs a hooks property, which is an object, where we define what will trigger the hook. So for our simple example we'll use before read file which will trigger any time the agent is going to read a file. Then before read file will be an array of objects with commands in them and all of these commands can run each time a file is read.

[00:32] So that means we need to create this script of debug.sh which is going to live next to the hooks.json file because it's critical to remember that all of these scripts will be relative to the hooks.json file not the project root. So we'll create a debug.sh and all we're going to do here is essentially redirect standard in to a JSON file. By redirect I mean this script will receive an object. If you think of a hook or callback or event handler in JavaScript, they always receive a payload and that's being passed to the script and in Bash this just redirects it into this file. So you'll see that in action when we tell the agent please read the debug file.

[01:16] We'll hit enter and then you'll see nothing happens because we missed the critical step of making this file executable. So to make a file executable we use chmod plus X and then the path to the file which is .cursor slash debug. Hit enter and I can say please try that again. And you'll see now that the file was executable, the hook was able to run and create this object which has the payload. I'll go ahead and format it, which has the payload of the conversation ID, generation ID, the file path that it read, and the content of that file path so that you can take actions in your script based on this object.