- AI Agent
- 代码智能体
- 人工智能
- 大模型
- CLI
【免费下载链接】kimi-code
Kimi Code CLI — The Starting Point for Next-Gen Agents
Kimi Code CLI 的 Hooks 是一套"事件驱动"的自动化触发机制:你预先告诉 CLI"当某件事发生时,运行某个脚本",脚本运行在你的本机,内部可以承载任意逻辑。本文以 docs/en/customization/hooks.md 为骨架,完整讲解 Hooks 的配置语法、事件参考表、返回值语义与阻断能力,并结合 agent-core-v2 的源码实现剖析其底层执行原理。读完本文,你将能独立编写安全拦截、桌面通知、上下文注入三类典型 Hook,并理解其 fail-open 设计在安全场景下的边界。
Hooks 是什么
Hooks 是一种自动触发机制:你提前告诉 Kimi Code CLI "每当 X 发生时,运行这个脚本"。脚本在你的本地机器上运行,内部可以放置任何逻辑。典型的使用场景包括:
- 安全拦截:在 Agent 执行 shell 命令之前,检查命令是否包含危险操作(如
rm -rf),发现则阻止执行; - 桌面通知:后台任务完成时弹出系统通知,提醒你回来审查结果;
- 自动检查:每次用户提交消息时,自动向上下文追加一些背景信息(例如当前的 Git 分支)。
Hooks 的工作原理
配置一条 Hook 规则需要指定三样东西:触发哪个事件、匹配哪些目标、运行哪个脚本。
当被触发时,CLI 会将事件详情(触发原因、工具名称、命令内容等)打包成 JSON,通过**标准输入(stdin)**传递给脚本。脚本读取这些信息后决定如何响应。
脚本的响应由两件事决定:
- 退出码:
0表示放行,2表示阻止,其他非零值默认放行; - 标准输出(stdout):可携带说明性文本。
即使脚本出错或超时,CLI也不会因此中断你的工作。这种"失败即放行"的设计称为 fail-open,目的是防止 Hook 自身出错成为阻塞项。
⚠️ 注意:正因为是 fail-open 设计,Hooks 适合用于告警和轻量级拦截,但不应作为唯一的安全屏障。对于真正高风险的操作,应依赖权限审批(permission approvals)和人工确认。
快速开始:一个最小 Hook
下面这个 Hook 在每次后台任务完成时,在终端标题栏闪烁一条通知(macOS 需要安装terminal-notifier):
# 写在 ~/.kimi-code/config.toml [[hooks]] event = "Notification" # 触发点:后台任务状态变化时 matcher = "task\\.completed" # 只关心 "completed" 类型的通知 command = "terminal-notifier -title Kimi -message 'Task done'"保存配置后,启动一个新的会话,下次后台任务完成时就会出现通知。
配置详解
所有 Hook 规则都写在~/.kimi-code/config.toml的[[hooks]]数组中,每个条目即一条规则:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
event | string | 是 | 触发事件名称;必须是事件参考中列出的事件之一 |
matcher | string | 否 | 用于过滤事件目标的正则表达式;省略则匹配所有 |
command | string | 是 | 触发时要运行的 shell 命令 |
timeout | integer | 否 | 超时秒数,范围 1–600;默认 30 秒 |
[[hooks]]只允许这四个字段;多余的字段会导致配置文件加载失败。这一点在源码中有严格校验:packages/agent-core-v2/src/features/externalHooks/configSection.ts中定义了HookDefSchema(z.object({...}).strict()),其中event必须是HOOK_EVENT_TYPES枚举之一、command非空、timeout为 1–600 的整数——严格模式(.strict())意味着 schema 之外的任何字段都会直接使配置校验失败,这正是"多余字段导致配置文件无法加载"的实现依据。
当多个规则匹配同一事件时,所有匹配的 Hook 并行运行;多条command值完全相同的规则只运行一次。这一行为在packages/agent-core-v2/src/features/externalHooks/internal/matchHooks.ts的runMatchedHooks中有明确实现:先按事件索引所有 Hook(indexHooks),再用正则逐一过滤matcher,最后以(cwd + '\0' + command)为 key 去重,剩余规则通过Promise.all并行执行。
Hook 命令的工作目录是当前会话的项目目录。
进程组与超时处理
在非 Windows 平台上,Hook 进程运行在独立的进程组中;超时时,CLI 会先发送信号给脚本一个清理的机会,然后再强制终止它。源码层面(packages/agent-core-v2/src/features/externalHooks/internal/runHook.ts)的细节是:进程以shell: true、detached: process.platform !== 'win32'的方式派生,超时后先kill('SIGTERM'),等待 100ms 宽限期(KILL_GRACE_MS)后再kill('SIGKILL')强制结束;同时支持通过AbortSignal取消运行中的 Hook。
事件数据格式
每次 Hook 触发时,CLI 通过 stdin 向脚本传递以下基础信息:
{ "hook_event_name": "PreToolUse", "session_id": "session_abc", "session_title": "Fix the login page", "client_type": "kimi_code_cli", "cwd": "/path/to/project" }特定事件还会附带额外字段(如工具名称、命令内容),详见事件参考。所有字段名均使用 snake_case——这是matchHooks.ts中camelToSnake转换函数的约定,无论内部实现使用何种 camelCase 字段名,传入 Hook 的 JSON 一律转为snake_case。
返回值语义
脚本退出后,CLI 根据退出码判断 Hook 的意图:
| 退出码 | 含义 | CLI 行为 |
|---|---|---|
0 | 正常退出,放行 | 继续执行;stdout 内容(如有)可能被追加到上下文 |
2 | 主动阻止 | 停止当前操作;stderr 内容(通过console.error输出)作为阻止原因 |
| 其他非零 | 脚本出错 | 默认放行(fail-open) |
| 超时或崩溃 | 脚本异常 | 默认放行(fail-open) |
你还可以通过 stdout 返回 JSON 对象来阻止:
{ "hookSpecificOutput": { "permissionDecision": "deny", "permissionDecisionReason": "Please use rg instead of grep" } }这条 JSON 路径在runHook.ts的structuredOutput函数中实现:当退出码为0且 stdout 是合法 JSON 时,CLI 解析hookSpecificOutput.permissionDecision,若为deny则视为阻止,permissionDecisionReason作为阻止原因。注意 schema 中还支持顶层的message字段(HookJsonOutputSchema),供 Hook 向上下文补充说明。
哪些事件支持阻断?只有可阻断事件(
PreToolUse、Stop、UserPromptSubmit)的返回值会影响主流程。其余事件均为纯观察事件:触发即忘(fire and forget),无论脚本返回什么,主流程都不受影响。
事件参考
| 事件 | Matcher 匹配对象 | 支持阻断? | 说明 |
|---|---|---|---|
UserPromptSubmit | 用户提交的文本 | ✓ | 用户发送消息时触发;返回文本会追加到上下文;阻断则跳过本轮模型调用 |
UserPromptQueued | 排队中的提示词文本 | — | 一轮仍在运行时消息被排队时触发;payload 包含prompt_id、prompt、queue_length |
PreToolUse | 工具名称 | ✓ | 工具调用前触发(在权限检查之前);被阻断则工具不会执行 |
Stop | 空字符串 | ✓ | 模型即将结束本轮时触发;阻断后可追加消息让模型继续 |
TurnStarted | 轮次来源类型(如user、task、system_trigger) | — | 新的一轮开始时触发;payload 包含turn_id、origin_kind、origin_name、prompt |
PostToolUse | 工具名称 | — | 工具成功执行后触发 |
PostToolUseFailure | 工具名称 | — | 工具失败或被阻断后触发 |
PermissionRequest | 工具名称 | — | 即将等待用户审批前触发 |
PermissionResult | 工具名称 | — | 审批完成后触发 |
SessionStart | startup或resume | — | 会话开始或恢复后触发;payload 包含source、model、profile |
SessionEnd | exit或archive | — | 会话关闭后触发;archive表示会话被归档而非退出 |
SessionHeartbeat | 空字符串 | — | 会话存活期间每 60 秒触发一次;仅当配置了该事件时计时器才运行;payload 包含uptime_ms |
SubagentStart | 子代理名称 | — | 子代理开始运行前触发 |
SubagentStop | 子代理名称 | — | 子代理成功完成后触发 |
TaskStarted | 任务类型(agent、process或question) | — | 后台任务开始时触发;payload 包含task_id、description、detached |
StopFailure | 错误类型 | — | 本轮因错误失败后触发 |
Interrupt | 空字符串 | — | 用户中断本轮时触发(如按 Esc);超时或程序化中止不触发;取代Stop触发;payload 包含reason |
PreCompact | manual或auto | — | 上下文压缩开始前触发;返回值完全被忽略 |
PostCompact | manual或auto | — | 上下文压缩完成后触发 |
Notification | 通知类型(如task.completed) | — | 后台任务状态变化时触发 |
以上 20 个事件与源码packages/agent-core-v2/src/features/externalHooks/internal/types.ts中导出的HOOK_EVENT_TYPES枚举完全一致,可作为配置时的权威清单。从调用架构看(packages/agent-core-v2/src/features/externalHooks/app/externalHooksRunner.ts),事件触发分为三种入口:trigger(等待结果)、triggerBlock(等待并解析阻断决策)与fireAndForgetTrigger(纯观察、触发即忘),分别对应上表"支持阻断"与"纯观察"两类事件。
示例:拦截危险的 Shell 命令
下面的 Hook 在 Agent 调用Bash工具前检查命令内容,发现rm -rf则阻止:
[[hooks]] event = "PreToolUse" matcher = "Bash" command = "node ~/.kimi-code/hooks/block-dangerous-bash.mjs" timeout = 5// block-dangerous-bash.mjs // 从 stdin 读取 CLI 传入的事件数据 let input = ''; process.stdin.on('data', (chunk) => { input += chunk; }); process.stdin.on('end', () => { const payload = JSON.parse(input); // 解析事件数据 const command = payload.tool_input?.command ?? ''; if (command.includes('rm -rf')) { // 通过 stderr 说明阻止原因;退出码 2 表示阻止 console.error('Dangerous command detected, blocked'); process.exit(2); } // 正常退出(退出码 0)表示放行 });阻断之后,Kimi Code CLI 会把阻止原因写回上下文,模型可据此选择更安全的替代方案。
⚠️ 注意:这个示例仅演示阻断机制,并非生产级的安全解析器。真实场景更适合用白名单,或专门的 shell 解析器来处理引号、变量展开和多命令序列等问题。
从源码看 Hooks 的执行链路
结合 agent-core-v2 的代码,可以把 Hooks 的完整执行链路梳理为五个环节:
- 配置注册:configSection.ts 将
hooks段落注册为配置项,用严格模式 schema 校验每条规则的四个字段; - 索引与匹配:matchHooks.ts 的
indexHooks按事件建立索引,matches用正则测试 matcher,非法正则直接视为不匹配; - 进程派生:runHook.ts 以
shell: true派生子进程,通过 stdin 写入 JSON 事件数据; - 结果判定:退出码
2→ 阻断;退出码0且 stdout 为合法 JSON 且permissionDecision === "deny"→ 阻断;其余情况一律放行(包括超时、崩溃、派生失败); - 决策汇总:多个匹配 Hook 并行执行后,任一返回阻断即整体阻断(
blockDecision取第一个阻断结果,未提供原因时回退为Blocked by <event> hook)。
这些行为均有对应测试覆盖,可参考 packages/agent-core-v2/test/features/externalHooks 目录下的runner.test.ts与integration.test.ts,它们验证了并行执行、去重、超时与阻断决策等关键路径。
下一步
- 配置详解 —
config.toml中[[hooks]]的完整字段参考 - Agents and sub-agents — 结合
SubagentStop事件,在子代理完成后触发通知
- AI Agent
- 代码智能体
- 人工智能
- 大模型
- CLI
【免费下载链接】kimi-code
Kimi Code CLI — The Starting Point for Next-Gen Agents
相关推荐
Kimi Code CLI Hooks 钩子机制实战指南:事件驱动脚本扩展与安全拦截
Kimi Code CLI Hooks 钩子机制实战指南:事件驱动脚本扩展与安全拦截 导读 Hooks(钩子)是 Kimi Code CLI 提供的自动化触发机
AI Agent代码智能体人工智能大模型CLI让Claude Code自动干活:Hooks事件钩子机制完全指南
让Claude Code自动干活:Hooks事件钩子机制完全指南 Claude Code Ultimate Guide 是社区最全面的 Claude Code
从0到1掌握coat_lite_mini.in1k:初学者必备的图像分类模型教程
从0到1掌握coat_lite_mini.in1k:初学者必备的图像分类模型教程 想要快速入门图像分类领域?今天我将为你详细介绍coat_lite_mini.i
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考