Cursor Hook 本质与常见场景
提要
Hook(钩子) 是 智能体循环中的可编程拦截层,能够在 AI 执行关键操作(如运行命令、读写文件、调用工具)前后进行观察、门禁、改写或自动化。与 Rules/Skills 的“软引导”不同,Hooks 提供硬性控制,是唯一能直接阻止命令、修改参数或自动触发后续动作的扩展机制。
核心要点:
- 定位:项目级(
.cursor/hooks.json)或用户级(~/.cursor/hooks.json)配置,通过脚本或 Prompt 实现。 - 能力:围绕 观察(Observe)、门禁(Gate)、改写(Modify)、延续(Follow-up) 四种模型展开。
- 事件:分为智能体钩子(如
beforeShellExecution、afterFileEdit)、Tab 钩子和应用生命周期钩子,覆盖从会话开始到结束的全流程。 - 实现:支持命令 Hook(确定性脚本)与提示 Hook(LLM 策略判断),通过 stdin/stdout 以 JSON 通信。
- 典型场景:代码自动格式化、安全命令拦截、敏感文件保护、工作流自动化(如 OpenSpec 命令自动提交)、全链路审计等。
- 设计原则:选择最窄事件、脚本可执行、关键策略设
failClosed: true、项目 Hook 纳入版本管理。
适用时机:当需要无论 AI 如何思考都必须强制执行的规则时,应优先选择 Hooks。
一、Hook 的本质
1.1 它是什么
Hook(钩子) 是 Cursor 在 智能体循环(Agent Loop) 的关键节点上插入的 可编程拦截层。
可以把它理解成:
在 Agent 即将执行某个动作(读文件、跑命令、调 MCP、提交 Prompt……)之前或之后,由你自定义的脚本或 LLM 策略介入,对行为进行 观察、放行、拦截、改写或追加后续动作。
技术形态:
| 维度 | 说明 |
|---|---|
| 配置入口 | hooks.json(项目级 .cursor/hooks.json 或用户级 ~/.cursor/hooks.json) |
| 执行体 | Shell 脚本 / Node / Python / Bun 等可执行程序,或 Prompt Hook(由 LLM 做策略判断) |
| 通信协议 | 子进程,stdin 收 JSON → stdout 回 JSON |
| 触发时机 | 智能体循环中某事件的 定义阶段之前或之后 |
| 作用范围 | 可项目共享(进 Git),也可用户全局(仅本机) |
1.2 与 Rules、Skills 的区别
三者都用于「约束 / 增强 AI 行为」,但介入层次不同:
| 能力 | Rules | Skills | Hooks |
|---|---|---|---|
| 介入方式 | 写入系统 Prompt,软性引导 | 按需加载工作流文档,指导 Agent 怎么做 | 在工具执行前后 硬拦截 / 硬改写 |
| 能否阻止命令 | 否(只能建议) | 否 | 能(permission: deny) |
| 能否改工具入参 | 否 | 间接(通过说明) | 能(updated_input) |
| 能否自动跑脚本 | 否 | 可附带脚本,但由 Agent 决定是否调用 | 事件驱动,自动执行 |
| 典型用途 | 编码规范、语言偏好 | 复杂流程 SOP、领域知识 | 安全门禁、格式化、审计、自动化闭环 |
选型口诀:
- 只想让 AI 「知道并遵守」 → Rules / Skills
- 需要 「无论 AI 怎么想都必须执行」 → Hooks
1.3 核心能力模型
每个 Hook 事件都围绕四种能力展开:
观察(Observe) → 记录日志、上报遥测、合规审计
门禁(Gate) → allow / ask / deny,控制是否继续
改写(Modify) → 修改工具入参、注入上下文、后处理文件
延续(Follow-up)→ 自动发 follow-up 消息、串联 subagent 循环
二、Hook 的分类与事件
2.1 三大类别
| 类别 | 触发场景 | 代表事件 |
|---|---|---|
| 智能体钩子 | Cmd+K / Agent Chat 会话期间 | beforeShellExecution、afterFileEdit、preToolUse … |
| Tab 钩子 | 行内补全(Tab)自动化编辑 | beforeTabFileRead、afterTabFileEdit |
| 应用生命周期钩子 | 工作区打开 / 文件夹变更 | workspaceOpen |
2.2 智能体钩子事件一览
| 事件 | 触发时机 | 典型能力 |
|---|---|---|
sessionStart / sessionEnd |
会话开始 / 结束 | 注入初始上下文、会话审计 |
preToolUse / postToolUse / postToolUseFailure |
任意工具调用前 / 后 / 失败 | 通用拦截、追加 additional_context |
subagentStart / subagentStop |
Task 子代理启停 | 控制子代理权限、循环 follow-up |
beforeShellExecution / afterShellExecution |
Shell 命令执行前 / 后 | 命令门禁、输出审计 |
beforeMCPExecution / afterMCPExecution |
MCP 工具调用前 / 后 | MCP 安全策略 |
beforeReadFile / afterFileEdit |
读文件前 / 写文件后 | 敏感文件保护、自动格式化 |
beforeSubmitPrompt |
用户提交 Prompt 前 | Prompt 校验、命令采集 |
preCompact |
上下文窗口压缩前 | 观察压缩行为 |
stop |
Agent 一轮结束 | 自动重试、闭环检查 |
afterAgentResponse / afterAgentThought |
Agent 输出 / 思考后 | 追踪、分析 |
2.3 事件选择速查
| 目标 | 推荐事件 |
|---|---|
| 拦截 / 审批 Shell 命令 | beforeShellExecution |
| 审计命令输出 | afterShellExecution |
| 编辑后自动格式化 | afterFileEdit |
| 拦截 / 改写某个工具调用 | preToolUse |
| 工具成功后注入额外上下文 | postToolUse |
| 控制子代理能否运行 | subagentStart |
| 子代理结束后自动续聊 | subagentStop |
| 检查 Prompt 是否含密钥 / 违规 | beforeSubmitPrompt |
| 保护 MCP 调用 | beforeMCPExecution |
三、配置与实现
3.1 存放位置
| 级别 | 配置文件 | 脚本目录 | 路径写法 |
|---|---|---|---|
| 项目级(推荐团队共享) | .cursor/hooks.json |
.cursor/hooks/ |
相对项目根,如 .cursor/hooks/xxx.sh |
| 用户级(本机全局) | ~/.cursor/hooks.json |
~/.cursor/hooks/ |
相对 ~/.cursor/,如 ./hooks/xxx.sh |
Cursor 会监视 hooks.json,保存后自动重载;不生效时可重启 IDE,并在 Settings → Hooks 或 Hooks 输出通道 排查。
3.2 hooks.json 基本结构
{
"version": 1,
"hooks": {
"afterFileEdit": [
{
"command": ".cursor/hooks/format.sh"
}
]
}
}
常用字段:
| 字段 | 说明 |
|---|---|
command |
可执行脚本路径 |
type |
"command"(默认)或 "prompt" |
timeout |
超时秒数 |
matcher |
正则过滤,仅匹配时触发(JavaScript 正则语法) |
failClosed |
true 时,脚本崩溃 / 超时 / 无效 JSON → 阻断操作 |
loop_limit |
stop / subagentStop 的 follow-up 循环上限 |
3.3 两种 Hook 类型
命令 Hook(Command Hook)
- 执行 Shell 脚本,确定性、可审计
- stdin 收 JSON,stdout 回 JSON
- 退出码:
0成功;2等同deny;其他非零默认 失败放行(除非failClosed: true)
最小示例——拦截网络命令并请求人工确认:
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": ".cursor/hooks/approve-network.sh",
"matcher": "curl|wget|nc ",
"failClosed": true
}
]
}
}
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.command // empty')
if [[ "$command" =~ curl|wget|nc ]]; then
echo '{
"permission": "ask",
"user_message": "该命令可能发起网络请求,请确认后继续。",
"agent_message": "Hook 已将此命令标记为可能的网络调用。"
}'
exit 0
fi
echo '{ "permission": "allow" }'
exit 0
提示 Hook(Prompt Hook)
- 用 LLM 判断自然语言策略,适合轻量策略、不想写脚本
$ARGUMENTS会被替换为 Hook 输入 JSON
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"type": "prompt",
"prompt": "该命令是否安全?仅允许只读操作。输入:$ARGUMENTS",
"timeout": 10
}
]
}
}
原则: 需要精确、可复现、可审计 → 命令 Hook;策略模糊、快速试错 → Prompt Hook。
3.4 各事件可返回的字段(摘要)
| 事件 | 可返回字段 |
|---|---|
preToolUse |
permission、user_message、agent_message、updated_input |
postToolUse |
additional_context;MCP 还可 updated_mcp_tool_output |
subagentStart |
permission、user_message |
subagentStop |
followup_message |
beforeShellExecution / beforeMCPExecution |
permission、user_message、agent_message |
stop |
followup_message |
permission 取值:allow(放行)、ask(弹窗确认)、deny(拒绝)。
四、常见场景
4.1 代码质量与一致性
| 场景 | 事件 | 做法 |
|---|---|---|
| 保存后自动格式化 | afterFileEdit |
调用 prettier / eslint --fix / ktlint |
| Tab 补全后格式化 | afterTabFileEdit |
同上,仅针对 Tab 写入 |
| 禁止编辑 generated 目录 | preToolUse + matcher Write |
检测路径,返回 deny |
4.2 安全与合规
| 场景 | 事件 | 做法 |
|---|---|---|
拦截危险 Shell(rm -rf、生产库写入) |
beforeShellExecution |
正则匹配 + deny / ask |
| 扫描 Prompt 中的密钥 / PII | beforeSubmitPrompt |
正则或密钥扫描脚本 |
| 生产环境 kubectl / SQL 写入审批 | beforeShellExecution |
解析命令参数,命中敏感命名空间则 ask |
| MCP 调用审计与拦截 | beforeMCPExecution |
记录 + 按工具名门禁 |
阻止读取 .env、密钥文件 |
beforeReadFile |
路径匹配后 deny |
4.3 工作流自动化
| 场景 | 事件 | 做法 |
|---|---|---|
| 会话开始注入项目上下文 | sessionStart |
读取 AGENTS.md、OpenSpec 状态写入上下文 |
OpenSpec /opsx-* 命令自动空提交 |
beforeSubmitPrompt |
团队 @xxx/opsx-hook |
| Agent 连续失败后自动重试 | stop |
统计失败次数,返回 followup_message |
| 子代理完成后自动续任务 | subagentStop |
返回 follow-up 指令 |
| 编辑后刷新 Skill 汇总文档 | afterFileEdit |
检测 SKILL.md 变更,触发汇总脚本 |
4.4 观测与治理
| 场景 | 事件 | 做法 |
|---|---|---|
| 全链路审计日志 | 多个事件共用 audit.sh |
stdin JSON 追加写入日志 / 上报 |
| 统计 Agent 工具使用 | postToolUse |
上报遥测平台 |
| 上下文压缩监控 | preCompact |
记录压缩前后 token 估算 |
4.5 团队内已有实践(OpenSpec)
在 Spec-Driven 流程中,项目可安装 @xxx/opsx-hook:
# 前提:Node ≥ 18,配置 @xxx内网源
npx @xxx/opsx-hook@latest install
- 触发事件:
beforeSubmitPrompt - 行为: 识别用户输入的
/opsx-*命令,自动创建空 Git 提交,便于后续采集变更数据 - 卸载:
npx @xxx/opsx-hook@latest uninstall
详见 Spec-Driven 开发流程 第 3 步。
五、云端 Agent 注意事项
云端 Agent 会读取仓库内 项目级 .cursor/hooks.json,但:
| 支持 | 不支持 / 有限 |
|---|---|
beforeShellExecution、afterShellExecution |
sessionStart / sessionEnd(VM 在提交后才创建) |
beforeReadFile、afterFileEdit |
beforeSubmitPrompt(网页端先提交 Prompt) |
preToolUse、postToolUse、subagentStart 等 |
Tab 相关钩子、MCP 钩子(部分未接入) |
| 仅 命令 Hook | Prompt Hook、用户级 ~/.cursor/hooks.json |
设计跨本地 + 云端的 Hook 时,应把策略放在 项目仓库 内,并避免依赖本机路径或用户目录。
六、设计原则与排错
6.1 设计原则
- 选最窄事件:能只用
beforeShellExecution就不要用泛化的preToolUse - 先跑通再加 matcher:matcher 用 JS 正则,POSIX 类(如
[[:space:]])无效 - 脚本必须可执行:
chmod +x,并确认jq/node/python3在 Hook 环境的$PATH中 - 安全策略设
failClosed: true:审计 / 门禁类 Hook 失败时应阻断而非静默放行 - 项目 Hook 进 Git:团队规范、格式化、OpenSpec 采集应可复现
- 保持脚本短小:复杂逻辑可拆到
.cursor/hooks/下的模块,Hook 入口只做编排
6.2 常见问题
| 现象 | 排查方向 |
|---|---|
| Hook 完全不触发 | 路径是否相对正确;脚本是否可执行;重启 Cursor |
| 只有部分命令触发 | 检查 matcher 正则;可先去掉 matcher 验证 |
| 应该拦截却放行了 | 是否未设 failClosed;退出码是否为非 2 的失败 |
| 云端 Agent 不生效 | 是否用了用户级 Hook 或 Prompt Hook |
| Windows 脚本失败 | shebang、换行符(LF)、依赖是否在 PATH 中 |
七、快速决策图
八、小结
| 要点 | 一句话 |
|---|---|
| 本质 | Agent 循环上的可编程事件拦截层,stdin/stdout 交换 JSON |
| 独特价值 | 唯一能 硬拦截、硬改写、事件驱动自动化 的 Cursor 扩展机制 |
| 与 Rules/Skills | Rules/Skills 引导「怎么想」;Hooks 控制「能不能做、怎么做」 |
| 团队落地 | 项目级 .cursor/hooks.json + 可执行脚本,纳入版本管理 |
| 首选场景 | 安全门禁、自动格式化、审计上报、OpenSpec/CI 联动、子代理闭环 |
参考链接
- 官方文档:Cursor 钩子(Hooks)
- 团队实践:@xxx/opsx-hook(OpenSpec 命令自动空提交)
- 相关教程:【教程】 Cursor 自动提交 OpenSpec 命令
更多推荐



所有评论(0)