首页
/ Cline Hooks 完全指南:在 Agent 工作流的 8 个关键时机注入自定义脚本

Cline Hooks 完全指南:在 Agent 工作流的 8 个关键时机注入自定义脚本

2026-09-06 21:21:05作者:裴麒琰

Cline 的 Hooks(钩子)机制允许开发者在 Agentic 工作流的特定时机执行自定义脚本:任务开始/恢复/取消/完成、用户提交提示词、工具调用前后、上下文压缩前。本文以 Cline 仓库中的官方文档 .clinerules/hooks/README.md 为主体,逐条覆盖钩子类型、脚本格式、I/O 协议、执行限制与并发合并规则,并结合 hook-factory.tsHookProcess.ts 等源码印证底层实现,读完后你可以编写可阻断、可注入上下文的钩子脚本,并在多根工作区中正确组织全局与项目级规则。

一、机制总览:钩子在哪里、如何生效

Hooks 让 Cline 在特定流程节点自动执行你的脚本,脚本可以阻断操作(返回 cancel: true)或向对话注入上下文contextModification),从而影响模型后续的决策。钩子有两个存放位置:

  • 全局钩子目录~/Documents/Cline/Hooks/(对所有工作区生效,组织级策略、个人通用规则)
  • 工作区钩子目录.clinerules/hooks/(仅对仓库所在工作区生效,项目专属规则、团队约定)

钩子在启用后自动运行,无需手动触发。从源码看,扩展启动时会确保全局钩子目录存在:disk.ts 中的 ensureHooksDirectoryExists() 会创建 ~/Documents/Cline/Hooks,创建失败时回退到该路径并"优雅降级"(后续发现不到脚本即静默跳过);getAllHooksDirs() 则按「运行时目录(可选)→ 全局目录 → 各工作区 .clinerules/hooks」的顺序汇总全部钩子目录。

启用步骤

  1. 在 VS Code 中打开 Cline 设置;
  2. 进入 Feature Settings(功能设置)区;
  3. 勾选 "Enable Hooks" 复选框;
  4. 确保钩子文件可执行(Unix/Linux/macOS 下 chmod +x hookname)。

二、完整钩子类型一览

钩子 触发时机 典型用途 全局位置 工作区位置
TaskStart 启动任务时(恢复任务不触发) 初始化任务上下文、校验任务要求、准备环境 ~/Documents/Cline/Hooks/TaskStart .clinerules/hooks/TaskStart
TaskResume 恢复已有任务时(用户点击 resume 后) 校验恢复状态、还原上下文、检查上次运行以来的变更 ~/Documents/Cline/Hooks/TaskResume .clinerules/hooks/TaskResume
TaskCancel 任务被取消、或用户中止了某个钩子(仅当存在实际活跃工作时) 清理资源、记录取消、保存状态 ~/Documents/Cline/Hooks/TaskCancel .clinerules/hooks/TaskCancel
TaskComplete 任务被标记为完成时(文档标注 coming soon 记录完成状态、最终清理、生成报告 ~/Documents/Cline/Hooks/TaskComplete .clinerules/hooks/TaskComplete
UserPromptSubmit 用户提交提示词/消息时(初始任务、恢复、反馈均触发) 校验用户输入、预处理提示词、为用户消息附加上下文 ~/Documents/Cline/Hooks/UserPromptSubmit .clinerules/hooks/UserPromptSubmit
PreToolUse 工具执行之前 校验参数、阻断执行、附加上下文 ~/Documents/Cline/Hooks/PreToolUse .clinerules/hooks/PreToolUse
PostToolUse 工具执行完成之后 观察结果、追踪模式、附加上下文 ~/Documents/Cline/Hooks/PostToolUse .clinerules/hooks/PostToolUse
PreCompact 对话上下文被压缩/截断之前(文档标注 coming soon 观察压缩事件、记录上下文管理、追踪 token 用量 ~/Documents/Cline/Hooks/PreCompact .clinerules/hooks/PreCompact

两个要点值得注意:

  • TaskCancel 钩子本身不可被取消(NOT cancellable),保证清理逻辑总能执行;
  • 从源码结构看,hook-factory.ts 中的 Hooks 接口还定义了一个 Notification 数据键(NotificationData),它未出现在上述文档表格中,属于源码层面额外暴露的钩子载荷类型,具体触发面文档未展开。

三、跨平台钩子格式:git 式约定

Cline 采用与 git hooks 一致的跨平台设计:

钩子文件规范(全平台)

  • 无文件扩展名:钩子必须精确命名为 PreToolUsePostToolUse 等(不加 .bat.cmd.sh 后缀);
  • Shebang 必需:第一行必须是 shebang,例如 #!/usr/bin/env bash#!/usr/bin/env node
  • Unix 下必须可执行chmod +x PreToolUse
  • Windows:官方文档原文写明 "Not currently supported"(当前不支持)。

源码演进提示:当前仓库代码中 hook-factory.ts 已出现平台分支逻辑——findUnixHook 检查无扩展名候选文件且要求可执行位(fs.access(candidate, fs.constants.X_OK)),而 findWindowsHook 则专门查找 <HookName>.ps1 文件(明确忽略无扩展名文件);HookProcess.ts 中 Windows 分支通过 powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File <script> 启动钩子,并对 PowerShell 可执行文件路径做了 5 分钟缓存。也就是说,就当前源码而言 Windows 支持已在推进中,脚本作者可以以官方 README 的"暂不支持"表述为保守预期,以源码为实际行为参照。

工作原理

与 git hooks 相同,Cline 通过 shell 执行钩子文件并解释 shebang 行:

  • Unix/Linux/macOS:原生 shell 执行,支持 shebang;
  • 因此:同一份钩子脚本可跨平台使用(write once, run anywhere),可以使用任意脚本语言(bash、node、python 等)。

创建钩子(Unix/Linux/macOS)

# 创建钩子文件
nano ~/Documents/Cline/Hooks/PreToolUse

# 赋予可执行权限
chmod +x ~/Documents/Cline/Hooks/PreToolUse

四、I/O 协议:stdin 进 JSON,stdout 出 JSON

4.1 输入(stdin,JSON)

Cline 通过标准输入向每个钩子传入一份 JSON。所有钩子都会收到如下公共字段 + 按类型挂载的专属字段:

{
  "clineVersion": "string",
  "hookName": "TaskStart" | "TaskResume" | "TaskCancel" | "TaskComplete" | "UserPromptSubmit" | "PreToolUse" | "PostToolUse" | "PreCompact",
  "timestamp": "string",
  "taskId": "string",
  "workspaceRoots": ["string"],
  "userId": "string",
  "taskStart": {
    "taskMetadata": { "taskId": "string", "ulid": "string", "initialTask": "string" }
  },
  "taskResume": {
    "taskMetadata": { "taskId": "string", "ulid": "string" },
    "previousState": { "lastMessageTs": "string", "messageCount": "string", "conversationHistoryDeleted": "string" }
  },
  "taskCancel": {
    "taskMetadata": { "taskId": "string", "ulid": "string", "completionStatus": "string" }
  },
  "taskComplete": {
    "taskMetadata": { "taskId": "string", "ulid": "string" }
  },
  "userPromptSubmit": { "prompt": "string", "attachments": ["string"] },
  "preToolUse": { "toolName": "string", "parameters": {} },
  "postToolUse": { "toolName": "string", "parameters": {}, "result": "string", "success": "boolean", "executionTimeMs": "number" },
  "preCompact": { "contextSize": "number", "messagesToCompact": "number", "compactionStrategy": "string" }
}

taskStart / taskResume / taskCancel / taskComplete / userPromptSubmit / preToolUse / postToolUse / preCompact 字段仅在对应钩子出现。从源码看,hook-factory.tscompleteParams() 负责补齐公共元数据(clineVersionhookNametimestampworkspaceRootsuserId),并在其上额外附带一个 model 字段(provider / slug,未知时置为 "unknown")——该字段未在 README 的示例中列出,编写解析脚本时可以容错处理。另外,README 中的输入示例未包含顶层 taskId,而源码会随 params 一并序列化传入,脚本可按需读取。

4.2 输出(stdout,JSON)

钩子必须向 stdout 返回如下结构的 JSON:

{
  "cancel": false,
  "contextModification": "可选:注入给模型后续决策的上下文",
  "errorMessage": "可选:阻断时给用户的错误详情"
}

cancel 字段语义:

  • false(或省略):允许执行继续;
  • true:阻断执行,并向用户展示 errorMessage

源码层面的两个容错细节值得了解:

  1. 旧字段拒绝hook-factory.tsvalidateHookOutput() 检测到已废弃的 shouldContinue 字段时会直接判为无效输出,并给出迁移指引({ shouldContinue: false, ... }{ cancel: true, ... });cancel 若提供必须是布尔值,contextModification / errorMessage 若提供必须是字符串;
  2. JSON 提取容错:即使 stdout 中混有调试输出,解析器也会从 stdout 末尾向前扫描最后一个完整的 JSON 对象(按花括号配对),提取后再校验(见 hook-factory.ts)。因此钩子脚本可以先 echo 调试信息,最后再打印 JSON 响应。

五、上下文注入时机:影响"下一次"决策,而非当前调用

重要:钩子注入的上下文影响的是模型未来的决策,不是当前这次工具执行。

为什么?当钩子运行时:

  1. 模型已经决定了要调用哪个工具、用什么参数;
  2. 钩子无法修改这些参数
  3. 钩子的上下文被追加进对话;
  4. 模型在下一次 API 请求中才能看到它,并据此调整后续决策。

PreToolUse 流程

1. 模型决定:"我将使用 write_to_file,参数如下"
2. PreToolUse 钩子运行 → 可阻断或注入上下文
3. 若放行,工具以原始参数执行
4. 上下文被加入对话
5. 下一次 API 请求携带该上下文
6. 模型基于上下文调整后续决策

PostToolUse 流程

1. 工具执行完成
2. PostToolUse 钩子运行 → 观察结果
3. 钩子针对结果注入上下文
4. 上下文被加入对话
5. 下一次 API 请求携带该上下文
6. 模型可以从结果中学习

六、执行限制与引擎细节

限制项 默认值 源码依据
超时 30 秒(HOOK_EXECUTION_TIMEOUT_MS hook-factory.ts const HOOK_EXECUTION_TIMEOUT_MS = 30000
上下文修改大小 50KB(MAX_CONTEXT_MODIFICATION_SIZE 同上 const MAX_CONTEXT_MODIFICATION_SIZE = 50000,超限截断并追加 [... context truncated due to size limit ...]
子进程输出上限 stdout + stderr 合计 1MB HookProcess.ts MAX_HOOK_OUTPUT_SIZE = 1024 * 1024,超限丢弃后续输出并标记截断

错误处理约定(与源码一致):

  • 预期错误静默处理:文件不存在(ENOENT)、权限拒绝(EACCES,例如用户放了不想执行的钩子)、非目录(ENOTDIR)都会被 hook-factory.tsisExpectedHookError() 静默吞掉;其他文件系统错误(EIO、EMFILE 等)会向上抛出;
  • Fail-open 语义:钩子脚本自身出错(非零退出码)并不会自动阻断工具,只有显式的 cancel: true JSON 响应才会阻断;超时/用户取消则以"失败"状态呈现于 UI(EXIT_CODE_SIGINT = 130 对应 Unix 下 128 + SIGINT 的取消约定);
  • 子进程管理HookProcess 通过 spawn 启动脚本,Unix 下以 detached 进程组方式运行,terminate() 会先对整个进程组发 SIGTERM 优雅退出、2 秒后未退出再 SIGKILL,防止钩子遗留后台子进程。

七、多钩子并发与结果合并(全局 × 工作区 × 多根)

当同一钩子类型同时存在全局钩子与工作区钩子(或多根工作区中每个根目录都有钩子)时:

  • 所有钩子通过 Promise.all 并发执行执行顺序不保证
  • 全部返回 cancel: false 才放行;任何一个返回 cancel: true 即阻断;
  • cancel:任一为 true → 合并结果为 true
  • contextModification:所有非空上下文以双换行 \n\n 拼接;
  • errorMessage:所有非空错误信息以单换行 \n 拼接。

这一合并逻辑在 CombinedHookRunner 中实现(results.some(r => r.cancel)join("\n\n")join("\n"))。

钩子工作目录(cwd)选择

从源码看,工作目录规则与钩子来源绑定(hook-factory.ts):

  • 工作区钩子<root>/.clinerules/hooks/):以其所属工作区根目录为 cwd(嵌套根时取最长匹配,即最内层根),因此脚本内相对路径相对于该项目解析;
  • 全局钩子~/Documents/Cline/Hooks/):以主工作区根目录(第一个工作区文件夹)为 cwd;
  • 若 cwd 目录不存在,HookProcess 会直接失败并给出明确错误,而不是让相对路径落到宿主进程目录上。

示例:全局 + 工作区钩子组合

全局钩子~/Documents/Cline/Hooks/PreToolUse,对所有项目生效):

#!/usr/bin/env bash
# 通用规则:绝不修改 package.json
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
path=$(echo "$input" | jq -r '.preToolUse.parameters.path // ""')

if [[ "$tool_name" == "write_to_file" && "$path" == *"package.json"* ]]; then
  echo '{"cancel": true, "errorMessage": "Global policy: Cannot modify package.json"}'
  exit 0
fi

echo '{"cancel": false}'

工作区钩子.clinerules/hooks/PreToolUse,仅对当前项目生效):

#!/usr/bin/env bash
# 项目规则:只允许 TypeScript 文件
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
path=$(echo "$input" | jq -r '.preToolUse.parameters.path // ""')

if [[ "$tool_name" == "write_to_file" && "$path" == *.js ]]; then
  echo '{"cancel": true, "errorMessage": "Project rule: Use .ts files only"}'
  exit 0
fi

echo '{"cancel": false}'

所有钩子都必须放行,工具才会执行;多钩子之间可能并发运行。多根工作区场景下同样适用上述合并规则,且不同目录的钩子之间不保证执行顺序

八、常见用例(可直接复制的钩子脚本)

1. 校验——阻断非法操作

#!/usr/bin/env bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
path=$(echo "$input" | jq -r '.preToolUse.parameters.path // ""')

if [[ "$tool_name" == "write_to_file" && "$path" == *.js ]]; then
  cat <<EOF
{
  "cancel": true,
  "errorMessage": "Cannot create .js files in TypeScript project",
  "contextModification": "Use .ts/.tsx extensions only"
}
EOF
  exit 0
fi

echo '{"cancel": false}'

2. 上下文构建——从操作中学习

#!/usr/bin/env bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.postToolUse.toolName')
success=$(echo "$input" | jq -r '.postToolUse.success')
path=$(echo "$input" | jq -r '.postToolUse.parameters.path // ""')

if [[ "$tool_name" == "write_to_file" && "$success" == "true" ]]; then
  cat <<EOF
{
  "cancel": false,
  "contextModification": "Created '$path'. Maintain consistency with this file's patterns in future operations."
}
EOF
else
  echo '{"cancel": false}'
fi

3. 性能监控

#!/usr/bin/env bash
input=$(cat)
execution_time=$(echo "$input" | jq -r '.postToolUse.executionTimeMs')
tool_name=$(echo "$input" | jq -r '.postToolUse.toolName')

if [[ "$execution_time" -gt 5000 ]]; then
  cat <<EOF
{
  "cancel": false,
  "contextModification": "Tool '$tool_name' took ${execution_time}ms. Consider optimizing future similar operations."
}
EOF
else
  echo '{"cancel": false}'
fi

4. 日志与遥测

#!/usr/bin/env bash
input=$(cat)

# 记录到文件
echo "$input" >> ~/.cline/hook-logs/tool-usage.jsonl

# 放行执行
echo '{"cancel": false}'

仓库 sdk/examples/hooks/ 目录还随附了更多语言的钩子示例(PreToolUse.pyPreToolUse.shPostToolUse.tsPreToolUse_BlockDestructive.shSessionShutdown.shTaskComplete.sh 等),可作为现成模板参考,并配合 sdk/examples/hooks/README.md 阅读。

九、故障排查

钩子没有运行

  • 确认 "Enable Hooks" 设置已勾选;
  • 确认钩子文件可执行(chmod +x hookname);
  • 检查脚本语法错误;
  • 查看 VS Code Output 面板(Cline 通道)中的报错。

钩子超时

  • 降低脚本复杂度;
  • 避免昂贵操作(网络调用、重计算);
  • 把复杂逻辑移到后台进程(注意 30 秒超时由 HOOK_EXECUTION_TIMEOUT_MS 控制,超时后子进程会被 SIGTERM)。

上下文没有影响模型行为

  • 记住:上下文影响的是未来决策,不是当前工具调用;
  • 确保注入的上下文清晰、可操作;
  • 检查上下文是否被截断(50KB 限制,截断后会出现 [... context truncated due to size limit ...] 标记)。

十、安全注意事项与最佳实践

安全(钩子以 VS Code 相同权限运行):

  • 对来自不可信来源的钩子保持警惕;
  • 启用前审阅钩子脚本;
  • 可考虑用 .gitignore 避免提交敏感钩子逻辑;
  • 钩子可访问工作区内所有文件与环境变量。

最佳实践

  1. 保持快速——目标执行时间 < 100ms;
  2. 让上下文可操作——明确告诉模型该做什么;
  3. 使用结构化前缀——帮助模型对上下文分类;
  4. 优雅处理错误——始终返回合法 JSON;
  5. 记录日志便于排障——保留钩子执行日志;
  6. 渐进式测试——从简单钩子起步,再逐步增加复杂度;
  7. 为钩子写注释——说明目的与逻辑。

十一、延伸阅读

登录后查看全文
热门项目推荐
相关项目推荐