Lesson

Automate Cursor Code Quality with afterFileEdit

Learn how to automatically run a linter/formatter on AI-generated code changes using Cursor's powerful `afterFileEdit` hook.

Access
Included
Transcript
Needs source

AI-generated code often misses your project's formatting and linting standards. You find yourself running manual fixes after every AI edit, breaking your flow and risking inconsistent code. Instead of treating formatting as a manual cleanup step, you can make it automatic.

This lesson shows you how to use the afterFileEdit hook to automatically run your linter or formatter—like Biome, Prettier, or ESLint—every time the AI modifies a file. The hook detects which file was changed, checks if it matches your criteria (e.g., TypeScript files), and executes your formatting tool on it. Code quality standards are enforced instantly and automatically, with zero manual intervention.

Hook Configuration

First, you need to tell Cursor which script to run after a file is edited. This is done in the .cursor/hooks.json file. Here, we define an afterFileEdit hook that executes our TypeScript script using Bun.

{
  "version": 1,
  "hooks": {
    "afterFileEdit": [
      {
        "command": "bun run hooks/after-file-edit.ts"
      }
    ]
  }
}

Implementing the Hook Logic

The hook receives a payload with information about the edited file. You parse this to get the file path, check if it matches your criteria (like a .ts extension), and if so, run your formatting tool on it.

Bun's Bun.$ syntax makes running shell commands from TypeScript elegant and safe—perfect for executing your linter or formatter.

import type { AfterFileEditPayload } from "cursor-hooks";

// Read the payload from standard input
const input: AfterFileEditPayload = await Bun.stdin.json();

// Check if the edited file is a TypeScript file
if (input.file_path.endsWith(".ts")) {
  // Run the Biome linter/formatter on the file
  const result = await Bun.$`bunx @biomejs/biome lint --fix --unsafe ${input.file_path}`;
  
  // Log the output for debugging purposes
  console.log(JSON.stringify(result.stdout, null, 2));
}

Seeing it in Action

Ask the AI to make a code change:

add a const foo = "bar"

The moment the AI applies the edit, your hook triggers automatically in the background. The formatter runs, applies your project's style rules, and the code is cleaned up—all without you doing anything. Your code stays consistent and follows your standards automatically.

Terminal Commands

Initialize a new Bun project in your workspace root.

bun init

This is the underlying command our hook script runs to format a specific file.

bunx @biomejs/biome lint --fix --unsafe index.ts