Hook 匹配器与事件范围
用运行时工具名和锚定正则精确选择事件,避免混淆权限元类别。
matcher 根据事件提供的目标值过滤。先确定事件是否支持 matcher,再写表达式;无 matcher 支持的事件会忽略这个字段。
各事件的目标
| 目标 | 事件 |
|---|---|
| 工具 ID | PreToolUse、PostToolUse、PostToolUseFailure、PermissionRequest、PermissionDenied |
| agent 类型 | SubagentStart、SubagentStop |
| 会话来源 / 结束原因 | SessionStart / SessionEnd |
| 压缩触发方式 | PreCompact、PostCompact |
命令名,不含 / | UserPromptExpansion |
| 错误类型 | StopFailure |
| 通知类型 | Notification |
| 文件路径 | InstructionsLoaded |
| 不支持 | PostToolBatch、UserPromptSubmit、SessionDelete、MessageDisplay、Stop、TodoCreated、TodoCompleted |
精确和正则匹配
空字符串、*、.* 表示匹配全部。运行时会先尝试精确比较,再处理不锚定正则。例如 edit 也匹配 notebook_edit,只要 edit 工具应写 ^edit$。
新配置优先使用 write_file、read_file、run_shell_command 等运行时 ID。排除 write_file 可写 ^(?!write_file).*$;不锚定的 (?!write_file).* 仍可能匹配它。
竖线列表的细节
permission_prompt | idle_prompt 可以按去除周围空白的条目精确匹配。仅分组和字符类之外、且未转义的 | 分隔条目;notes\|todo\.md、foo[ |]bar、a(b | c) 中的竖线属于正则本身。
整体以 ^ 或 ( 开始时只按原样正则编译,不能再期待去掉尾部空项。于是 read_(file|edit)| 的空尾项会被忽略,而 ^write_file| 的尾部空分支会匹配全部。只有 | 的列表匹配不到任何值。
别名不等于权限元类别
兼容工具显示名和权限别名,例如 Bash、Read、Write,按精确名称接受。锚定时应写运行时名 ^write_file$,不要写锚定显示名并期待别名转换。
每个 Hook 别名只对应一个工具:Read 不包括 grep_search 或 glob,Bash 不包括 monitor。这与权限规则中 Read 元类别覆盖多个工具的行为不同。
Skills 注册的 Hooks 使用同样规则。正则无效可在调试日志 [HOOK_MATCHER] 查原因;先测试应命中和不应命中的工具,避免仅凭一条成功日志判断范围正确。