Cursor Hooks: What You Can Run Before and After the Agent
Cursor hooks attach scripts to before/after stages of the agent loop. Per the official Hooks docs, map the timeline first (sessionStart → tool before/after → stop / sessionEnd), then ship a minimal hooks.json—or scaffold with /create-hook. No pricing.
This is not a retell of the save/commit guard post (afterFileEdit / beforeShellExecution deep dive). Focus: lifecycle before/after, hooks.json, /create-hook.
When do hooks run?
One-line answer: For Agent Chat and Cmd+K, hooks follow session start → prompt submit → tool before/after → response/thought → stop → session end. Tab and workspace-open are separate surfaces.
Agent lifecycle hooks (official):
| Phase | Hook | Role (short) |
|---|---|---|
| Session | sessionStart / sessionEnd | Inject env/context / end audit (fire-and-forget) |
| Prompt | beforeSubmitPrompt | Validate or block before send (continue) |
| Generic tools | preToolUse / postToolUse / postToolUseFailure | All tools, before/after/failure |
| Subagents | subagentStart / subagentStop | Task subagent create/complete |
| Shell & MCP | beforeShellExecution·afterShellExecution / beforeMCPExecution·afterMCPExecution | Gate and audit |
| Files | beforeReadFile / afterFileEdit | Read gate / post-edit |
| Context | preCompact | Observe compaction (cannot block) |
| Output | afterAgentResponse / afterAgentThought | Track replies and thinking |
| Loop end | stop | Optional followup_message to continue |
Other surfaces:
- Tab:
beforeTabFileRead/afterTabFileEdit - App:
workspaceOpen— workspace open/folder change (outside agent sessions)
Three practical lifecycle axes:
- Start / inject —
sessionStartforenvandadditional_context(callers do not currently enforce blocking) - Tool before/after — prefer narrow events (
beforeShellExecution, etc.); usepreToolUse/postToolUsewhen you need everything - End / loop —
stop/subagentStopfollowup_messagewithloop_limit(default 5)
Cloud agents load command hooks from repo .cursor/hooks.json. sessionStart/sessionEnd, MCP before/after, Tab, and workspaceOpen are unavailable or deferred in cloud; user hooks in ~/.cursor/hooks.json do not apply (no home dir on the VM).
What is a minimal hooks.json?
One-line answer: version: 1 plus a hooks map. Project: /.cursor/hooks.json (paths from repo root: .cursor/hooks/...). User: ~/.cursor/hooks.json (paths from ~/.cursor/). Fastest scaffold: /create-hook in Agent chat.
/create-hook is a built-in skill listed in official Agent Skills docs. Describe the lifecycle (“audit on sessionStart, follow-up on stop after errors”) and it writes hooks.json plus scripts. Hand-edit? Use Customize → Hooks and the Hooks output channel to confirm load/run.
Minimal project example:
{
"version": 1,
"hooks": {
"sessionStart": [
{ "command": ".cursor/hooks/session-init.sh" }
],
"preToolUse": [
{
"command": ".cursor/hooks/validate-tool.sh",
"matcher": "Shell|Task"
}
],
"stop": [
{
"command": ".cursor/hooks/track-stop.sh",
"loop_limit": 5
}
]
}
}
Scripts need execute bits (chmod +x). They speak JSON over stdin/stdout. Default type is command; "type": "prompt" exists for natural-language checks, but cloud agents run command hooks only.
Per-definition options: command (required), type, timeout, matcher, failClosed (default false = fail-open), loop_limit (stop / subagentStop).
Path rules:
- Project hooks: cwd = project root →
.cursor/hooks/format.sh - User hooks: cwd =
~/.cursor/→./hooks/format.sh
Priority (high → low): Enterprise → Team → Project → User. All matching hooks run; permission merges as deny > ask > allow.
Where do you look when a hook fails?
One-line answer: Customize Hooks tab and the Hooks output channel first, then path, permissions, exit codes, and failClosed.
Checklist:
- Loaded? Cursor reloads
hooks.jsonon save. If missing: Customize → Hooks; then restart Cursor. - Paths — project = root-relative
.cursor/hooks/...; user = under~/.cursor/. Putting./hooks/...in a project looks for/hooksat the repo root. - Execute bit & deps —
chmod +x; ensurejq/pythonetc. exist in the hook environment. - Exit codes —
0success (use JSON).2block (same aspermission: "deny"). Other non-zero = default fail-open. failClosed: true— block on crash/timeout/bad exit for security gates. Permission hooks still block on invalid JSON/schema even whenfailClosedis false.- matcher — if the hook never fires, the regex may be too narrow (
preToolUsematches tool names;beforeShellExecutionmatches the command string).
Cloud misses: only user hooks configured; unsupported events (sessionStart, MCP, Tab, workspaceOpen); or early read-only turns where hooks are not loaded yet.
Wrap-up
Cursor hooks are about what to hang on the agent lifecycle before/after. Start with sessionStart, tool before/after, and stop in a minimal hooks.json, or scaffold with /create-hook. On failure: Hooks tab/channel → paths → exit codes → failClosed. For save/commit guards alone, see the separate hooks guard post; for the full event list, see Hooks.
Sources
- Cursor Hooks — events,
hooks.json, exit codes /failClosed, cloud support - Agent Skills — built-in
/create-hook