Bash scripts work for basic hooks, but they quickly become unwieldy when you need to parse JSON, implement complex logic, or maintain the code over time. This lesson transforms your hook development workflow by introducing Bun—a fast JavaScript runtime that lets you write hooks in TypeScript.
You'll set up a dedicated Bun project for your hooks, learn how to handle the JSON payloads Cursor provides, and return properly formatted responses to control the AI's behavior. This approach gives you the full power of TypeScript and the Node.js ecosystem, making your hooks more maintainable, testable, and powerful.
Key Benefits:
- Write hooks in a familiar, strongly-typed language (TypeScript).
 
- Avoid the complexities of shell scripting and JSON manipulation in Bash.
 
- Leverage the entire Node.js/Bun ecosystem within your hooks.
 
- Simplify setup, as 
bun run handles script execution without needing chmod. 
Building Your First TypeScript Hook
The workflow is straightforward. You'll create a dedicated directory for your hooks, initialize a Bun project, and write a TypeScript script that demonstrates controlling the AI.
- 
Initialize a Bun Project: Create a .cursor/hooks directory and initialize a new Bun project within it. This gives you a dedicated environment for your hook logic with TypeScript support out of the box.
mkdir .cursor/hooks
cd .cursor/hooks
bun init
 
 
- 
Configure hooks.json: Update your .cursor/hooks.json to execute the TypeScript script using bun run. This command points to the entry file generated by Bun.
{
  "version": 1,
  "hooks": {
    "beforeSubmitPrompt": [
      {
        "command": "bun run hooks/index.ts"
      }
    ]
  }
}
 
 
- 
Handle Hook Output: Each hook type expects a specific JSON response structure. For beforeSubmitPrompt, you return an object with a continue property. Setting it to false blocks the AI from processing the prompt—a powerful demonstration of controlling the AI's behavior.
const output = {
  continue: false,
};
console.log(JSON.stringify(output, null, 2));
 
 
With this foundation in place, you can create sophisticated automations that integrate seamlessly with Cursor, all while working in a familiar TypeScript environment with full access to the Node.js ecosystem.
Prompts Used
Transcript
[00:00] So now because nobody likes to write bash or manipulate JSON in bash, we're going to create a directory called .cursor/.hooks and in this directory we're going to bun and knit a project. And then instead of invoking this debug script we're going to use this before submit prompt, remove before read file, and tell this to run bun run. And remember that this is relative to the hooks.json file So it'll be hooks and then index.ts. So we'll say hooks and index.ts. And then if we simply run anything in the agent and we hop over to the output hooks output, I'm going to clear this for now.
[00:45] I'll say do anything, hit enter, and you'll see it at least tried to run this file. Now all the errors come from the fact that it's expecting JSON as the output, but you can see that it at least logged the input. Now if you take a quick peek at the cursor docs you'll see that the expected output for before submit prompt is an object with continue set to true or false. So I'm going to say in our script, and I'll reject these changes of whatever it tried to do when I asked it to do anything, I'm going to say that the output is an object with continue set to false. And instead of logging out this string we're going to log out the JSON version of the output.
[01:31] Meaning that if we attempt to run another prompt inside of our agent, I'll try please say hello, hit enter, you'll see that our hook successfully blocked any submission from running. Then if we look down in our output you can see the output was continue false and that we ran the hook with a valid response. Then the final thing to note here is that because we're now using bun run inside of our command, we no longer have to worry about making scripts executable since bun is executable by default.