Writing hooks without type safety means you're guessing at property names, relying on documentation for payload structure, and hoping your response format is correct. Every hook becomes an exercise in trial and error, with no editor assistance to guide you.
This lesson introduces the cursor-hooks package, which provides complete TypeScript definitions for all hook payloads and responses. Combined with Bun's elegant Bun.stdin.json() method for reading input, you'll write hooks with full autocomplete support, compile-time error checking, and absolute confidence that your code is correct.
Bun.stdin.json() reads and parses hook input in a single, clean line of code.The workflow is simple and produces reliable, maintainable code:
cursor-hooks package to your Bun project for complete type definitions.await Bun.stdin.json() and apply the appropriate payload type (e.g., BeforeSubmitPromptPayload).BeforeSubmitPromptResponse).Install the package providing TypeScript types for Cursor hooks.
bun install cursor-hooks
A test prompt that will be blocked by the hook's logic.
jump
A test prompt that includes the required keyword to be allowed by the hook.
allow jump
This before-submit-prompt.ts script shows the elegance of type-safe hooks. Notice how the types guide the entire implementation—from reading the payload to building the response.
import type { BeforeSubmitPromptPayload, BeforeSubmitPromptResponse } from "cursor-hooks";
const input: BeforeSubmitPromptPayload = await Bun.stdin.json();
const output: BeforeSubmitPromptResponse = {
continue: input.prompt.includes("allow"),
};
console.log(JSON.stringify(output, null, 2));
With types in place, your editor becomes a powerful assistant, showing you exactly what properties are available on the input and what shape your output must take. This transforms hook development from guesswork into a guided, confident process.
[00:00] So back in our hooks directory where we initialized a blank bun project, I'll clear this out real quick, and I'm going to bun install a project I put together called cursor-hooks, which has typings for all of the hooks based on the documentation. And for a little bit more organization, let's rename index to before submit prompt. Then in our hooks, rename this to before submit prompt. Then in our before submit prompt script, we can now import some types like the before submit prompt response, and we can type our output to that, meaning that we'll get IntelliSense for continue, so we can be much more confident in the hooks we're building. Now the main reason we're using bun is because bun has something called bun.standardIn() with a JSON method on it, which converts the standard in to JSON in this single line.
[00:57] So the input can be this, and then we can type the input as a beforeSubmitPrompt payload. We'll let that automatically import. And now we can define continue as if the input prompt, and you'll see we get autocomplete for all this, includes allow, then continue will be true. If it doesn't include allow continue will be false. So open our agent we'll say jump, hit enter, it's blocked.
[01:24] We'll say allow jump, hit enter, and now you see it starts trying to do this action. We'll just reject this sample use case And you'll see we now have a typed version of the input and the output where we can easily add conditions around the prompt that's being submitted and whether or not to allow that prompt to actually continue.