Skill Hooks 与恢复
用可执行 Hooks 约束工具,并理解信任、会话恢复和禁用 Hooks 的边界。
Skill 正文是模型指令;需要在工具执行前检查确定条件时,可在 frontmatter 声明 Hook。它是否真正运行,还取决于 shell、脚本权限、会话开关和工作区信任。
一个执行前检查
---
name: gated-skill
description: Run a downstream command only with a supplied session ID.
hooks:
PreToolUse:
- matcher: run_shell_command
hooks:
- type: command
command: '"$QWEN_SKILL_ROOT/scripts/gate-session-id.sh"'
---脚本可写为:
#!/usr/bin/env bash
if [ -z "${DOWNSTREAM_SESSION_ID:-}" ]; then
echo "Required input DOWNSTREAM_SESSION_ID is not available." >&2
exit 2
fi
exit 0$QWEN_SKILL_ROOT 指向 Skill 自身目录。保留命令字符串内的双引号,才能处理含空格的路径,并给脚本执行权限,例如在 Skill 目录运行 chmod +x scripts/gate-session-id.sh。官方明确指出,未正确引用路径或未赋执行权限可能让检查失败后工具继续执行,且没有转录或日志提示;应在目标环境实际测试拒绝路径。
PreToolUse 退出 2 会阻止调用,并把 stderr 作为原因反馈给模型;也可以输出带 hookSpecificOutput.permissionDecision: "deny" 的 JSON。
生效范围
用户直接调用与模型通过 Skill 工具调用都会注册 Hooks,保留到会话结束;重复调用不会叠加重复 Hook。
matcher 默认不锚定:edit 也会匹配 notebook_edit,精确匹配用 ^edit$。省略或空 matcher 会匹配所有工具。不要沿用旧版“省略就不匹配”的假设。
项目、个人、内置 Skills 支持此字段;扩展 Skills 不支持,应使用扩展清单级 Hooks。
恢复会话的条件
--continue、--resume 会尝试恢复模型通过 Skill 工具加载的 allowedTools 与 Hooks,因为这类调用有工具记录。用户直接输入 /<name> 留下的是普通提示,恢复后需要再次调用才能重新注册。
恢复时要求当前仍可合法调用,而且记录正文与当前文件正文相同。下列情况会跳过:
- Skill 被禁用、隐藏于模型,或路径条件尚未激活。
- 项目 Skill 所属工作区不再受信任。
- 正文被编辑,或者原先发给模型的正文被截断。
- Skill 已不再被发现,或原调用嵌套在
exec脚本中。
前几类对声明 Hooks 或 allowedTools 的 Skill 会留下调试原因;不再发现和 exec 嵌套调用的跳过不留该日志。比对只覆盖正文,所以只改 frontmatter 时会使用新的授权与 Hooks。
信任和禁用开关
disableAllHooks、安全模式或 ACP 客户端 skipHooks 会禁止注册 Hook,即使 Skill 正文和 allowedTools 仍应用,也没有这道检查。Bare 模式进一步不发现任何 Skills。
项目 Hook 只在可信工作区注册,并在每次事件和权限判断时重读信任。连接 IDE companion 时撤销信任会在下一次调用使已注册 Hook 静默停用、暂停 Skill 授权;仅 CLI 的信任值固定于启动,修改信任对话框后要重启。后来授予信任不会补注册,需重新调用 Skill。
平台 shell
macOS、Linux 使用 bash。Windows 检测到 Git Bash 环境时使用它,否则由 cmd.exe 或 PowerShell 执行。上面的 POSIX 示例在 cmd.exe 中不会正确展开变量或执行 .sh,同样可能放行失败。
shell: bash 可以指定 bash,但依赖 PATH 中实际可用的程序。把 Hook 写成目标 shell 支持的形式,并验证失败时确实拦截工具;完整事件与协议见Hooks。