分清两类结果
识别显式 Deny 与 Hook 自身执行失败,它们对工具调用产生相反结果。
把 Hook 看成事件上的可编程检查点。PreToolUse 可以返回明确拒绝,进程崩溃、超时和不可解析输出则走 fail-open,让工具调用继续。
识别显式 Deny 与 Hook 自身执行失败,它们对工具调用产生相反结果。
掌握 matcher 的精确名、正则模式与 Bash 兼容别名。
按用户指南的 JSON 结构配置命令 Hook,并设计四条故障测试。
SessionStart、SessionEnd、Stop、StopFailure、PreToolUse、PostToolUse、PostToolUseFailure、PermissionDenied。其中只有 PreToolUse 的 is_blocking() 为真。
UserPromptSubmit、Notification、SubagentStart、SubagentStop、兼容别名 SubagentEnd、PreCompact、PostCompact。
事件枚举负责定义触发点,is_blocking() 单独声明阻断能力。读取事件列表时,要同时追踪结果如何回到调用方。
deny2allow,退出码 2安全含义:Hook 适合策略提醒、审计和可恢复的前置检查。需要强制保证时,还应使用权限层与沙箱。源码注释明确要求 Hook 故障不能破坏工具可用性。
match result {
HookRunnerResult::Decision(
HookDecision::Deny { reason, .. }
) => {
return PreToolUseResult {
decision: HookDecision::Deny { ... },
results: run_results,
};
}
HookRunnerResult::Failed(err) => {
tracing::warn!(
error = %err,
"hook failed; ignoring (fail-open)"
);
}
_ => {}
}
crates/codegen/xai-grok-hooks/src/dispatcher.rs
pub const DENY_EXIT_CODE: i32 = 2;
pub fn matches(&self, tool_name: &str) -> bool {
self.regex.is_match(tool_name)
|| self.matches_compat_alias(tool_name)
}
兼容映射让配置里的 Bash 可命中内部工具名 run_terminal_command。匹配器由正则编译,用户指南示例使用工具名。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bin/safe-shell-guard.sh",
"timeout": 5
}
]
}
]
}
}
配置层级是「事件 → matcher 组 → 处理器列表」。命令从 stdin 接收事件信封;有效 JSON 决策优先,无有效 JSON 时再按退出码解释,退出码 2 表达拒绝。全局 Hook 位于 ~/.grok/hooks/,项目 Hook 位于 .grok/hooks/ 且受 folder trust 控制。保留环境变量会被过滤,未解析变量会在启动前报错。
提交物
配置、脚本、测试记录
Bash 的 PreToolUse 命令 Hook。rm -rf 返回 JSON deny,记录工具被阻断的结果。判断 Hook 是否安全,先问两个问题:它能否表达明确拒绝,以及它自己失效时主流程如何处理。Grok Build 的答案很清楚,显式 deny 阻断,Hook 故障 fail-open。
源码快照说明:本页依据本地 grok-build-main 快照中的 hooks crate、用户指南与示例配置整理。代码片段为教学截取,省略日志字段和错误包装;事件名、JSON 层级、退出码与决策语义保持源码一致。