Cursor hooks are scripts that Cursor runs before or after stages of the agent loop, defined in a hooks.json file at the project or user level; they talk to Cursor over stdio in JSON and can observe, block or modify what the agent does, according to Cursor’s Hooks documentation.

Applies to: Cursor Agent, Tab and cloud agents, per Cursor’s Hooks documentation. Last checked: October 24, 2026.

On this page

Where hooks.json goes

Cursor’s quickstart gives two locations:

File Scope Where scripts run from
.cursor/hooks.json in the project That project only The project root, so paths look like .cursor/hooks/format.sh
~/.cursor/hooks.json Every project (user level) ~/.cursor/, so paths look like ./hooks/format.sh

The docs say Cursor watches hooks config files and reloads them automatically. Hooks can also be installed through plugins from Customize, and Cursor supports loading hooks from third-party tools such as Claude Code; the Claude Code hooks guide covers that format.

A first project hook

The project-level example from Cursor’s docs runs a script after every file edit. The config in .cursor/hooks.json:

{
  "version": 1,
  "hooks": {
    "afterFileEdit": [{ "command": ".cursor/hooks/format.sh" }]
  }
}

The script at .cursor/hooks/format.sh:

#!/bin/bash
# Read input, do something, exit 0
cat > /dev/null
exit 0

Make it executable:

chmod +x .cursor/hooks/format.sh

Hook events

The Hooks documentation splits events into three groups.

Agent hooks (Agent Chat):

Event What it covers
sessionStart / sessionEnd Session lifecycle
preToolUse / postToolUse / postToolUseFailure Every tool call
subagentStart / subagentStop Subagent (Task tool) lifecycle
beforeShellExecution / afterShellExecution Shell commands
beforeMCPExecution / afterMCPExecution MCP tool calls
beforeReadFile / afterFileEdit File reads and edits
beforeSubmitPrompt Prompts before submission
preCompact Context window compaction
stop Agent completion
afterAgentResponse / afterAgentThought Agent responses

Tab hooks (inline completions): beforeTabFileRead controls file access for Tab completions, and afterTabFileEdit post-processes Tab edits.

App lifecycle hooks: workspaceOpen fires when Cursor opens a workspace and on every workspace folder change, and can return additional plugin paths to load.

Command hooks, matchers and exit codes

Command hooks, the default type, receive JSON on stdin and return JSON on stdout. Cursor’s example adds a timeout and a matcher so the script only runs for some commands:

{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      {
        "command": "./scripts/approve-network.sh",
        "timeout": 30,
        "matcher": "curl|wget|nc"
      }
    ]
  }
}

Exit codes, as the docs define them:

Exit code Result
0 The hook succeeded and Cursor uses its JSON output
2 The action is blocked, the same as returning permission: "deny"
Any other The hook failed and the action proceeds (fail-open by default)

For the permission hooks (beforeShellExecution, beforeMCPExecution, beforeReadFile, beforeTabFileRead, subagentStart, preToolUse), the docs say invalid JSON or a response that doesn’t match the hook’s schema blocks the action. Cursor’s example beforeShellExecution script answers with "permission": "deny", "ask" or "allow", plus optional user_message and agent_message fields. On Windows, the desktop app runs hook commands through PowerShell and pipes the JSON in, so a PowerShell script reads it from $input.

Prompt-based hooks

A hook with "type": "prompt" asks a model to evaluate a natural-language condition instead of running a script. Cursor’s example:

{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      {
        "type": "prompt",
        "prompt": "Does this command look safe to execute? Only allow read-only operations.",
        "timeout": 10
      }
    ]
  }
}

According to the docs, it returns { ok: boolean, reason?: string }, uses a fast model by default (an optional model field overrides it), and replaces $ARGUMENTS with the hook input JSON or appends the input when the placeholder is absent.

Hooks in cloud agents

Cloud agents run command-based hooks from .cursor/hooks.json in your repository; on Enterprise plans they also run team and enterprise-managed hooks from the web dashboard. The docs list these limits:

  • User-level hooks in ~/.cursor/hooks.json are not available, because cloud agent VMs don’t have your home directory.
  • Prompt-based hooks don’t run; only command-based hooks do.
  • sessionStart, sessionEnd, beforeMCPExecution, afterMCPExecution, the Tab hooks and workspaceOpen don’t run in cloud agents.
  • Hooks don’t run during early read-only turns; they start once the agent has a writable environment.
  • For HTTP MCP servers, preToolUse can deny a call but Cursor ignores updated_input, and postToolUse receives {"redacted": true} instead of the tool result.

For project instructions in .cursor/rules and AGENTS.md, see Cursor rules: .mdc files, AGENTS.md and scope. Hooks in other agents are covered in Codex hooks and Copilot hooks.