给AI定规矩:Hooks与权限工程
约 22 分钟驭光者首发于微信公众号「羲和Lab」
信任但验证——给AI员工装上门禁、监控和自动化流程
阅读时长约14分钟 | 教程型 | 智能编码进化论 07/10
导读
前六篇我们给AI配齐了一整套"员工装备":岗位说明书、结构化任务、工具箱、外线电话、编外帮手。AI越来越能干了,但问题也随之而来——它会不会误删重要文件?会不会把.env推到远程仓库?会不会在生产环境执行危险命令?
这些担忧不是杞人忧天。任何有经验的团队leader都知道,员工能力越强,越需要清晰的规则和监控。不是不信任,是信任但要验证。
Hooks和权限系统就是Claude Code的安全体系。一句话区分:权限是门禁卡——决定AI能进哪些门;Hooks是监控摄像头——在关键节点检查发生了什么。 两者配合,让AI在安全边界内自由发挥。
阅读地图:Hooks和权限是什么关系
这篇文章讲两件事:Hooks和权限。它们都管安全,但管法不同。
权限管的是"能不能"——像门禁卡,控制AI能进哪些门。配置一次,每次都按规则执行,不需要写代码。
Hooks管的是"在什么时候做什么检查"——像监控摄像头,在关键节点自动触发。可以写shell脚本,也可以用LLM判断。
两者的关系:
- 权限是静态规则(匹配就生效)
- Hooks是动态脚本(在特定事件触发)
- 执行顺序:权限先判断 → Hooks再检查 → 操作执行 → Hooks记录
你不需要一次记住所有细节。先通读一遍建立印象,需要时回来查具体配置。
一、Hooks:关键节点的自动化守卫
Hooks是什么
Hooks是在特定事件发生时自动触发的自定义操作。像给办公室装的监控摄像头——有人进出时自动记录,有人试图闯入时自动报警。
Claude Code事件流:
用户输入 → AI思考 → 调用工具 → 生成响应 → 通知用户
↑ ↑ ↑
Hook可以 Hook可以 Hook可以
拦截/修改 拦截/修改 发通知
核心机制:事件触发 → Hook执行 → 根据返回结果决定继续/阻止/修改。
第一个Hook:桌面通知
最实用的入门Hook——当AI需要你输入时,发一个桌面通知。
{
"hooks": {
"Notification": [
{
"type": "command",
"command": "osascript -e 'display notification \"$CLAUDE_EVENT\" with title \"Claude Code\"'"
}
]
}
}
配置位置:~/.claude/settings.json(个人级)或 .claude/settings.json(项目级)。
当你离开终端去做别的事,AI需要你确认时,macOS会弹出系统通知。不用一直盯着终端了。
以上为macOS版本。Linux用户替换为
notify-send "Claude Code" "$CLAUDE_EVENT",Windows用户可用PowerShell的New-BurntToastNotification或省略此Hook。
Hook的配置结构
Hooks的配置是三层嵌套:
事件名(如 PreToolUse)
└── matcher组(过滤哪些工具)
└── hook处理器(执行什么操作)
事件:覆盖Claude Code完整生命周期的各种事件,且持续新增中。最常用的6个:
| 事件 | 触发时机 | 典型用途 |
|---|---|---|
PreToolUse | 工具调用前 | 拦截危险操作、自动格式化 |
PostToolUse | 工具调用后 | 审计日志、结果验证 |
Notification | 需要用户注意时 | 桌面通知 |
Stop | AI停止工作时 | 质量检查、防止遗漏 |
UserPromptSubmit | 用户输入后 | 输入预处理 |
SessionStart | 会话开始时 | 环境初始化 |
matcher:过滤条件。比如 PreToolUse 事件可以限定只对 Edit 和 Write 工具触发:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "your-command-here"
}
]
}
]
}
}
Hook处理器类型:5种执行方式
| 类型 | 说明 | 适用场景 |
|---|---|---|
command | 执行shell命令 | 最常用,格式化、通知、检查 |
http | POST到HTTP端点 | 集成外部系统、审计日志 |
prompt | 用LLM判断 | 需要语义理解的场景 |
agent | 用子代理多轮验证 | 复杂审查(实验性) |
mcp_tool | 调用MCP工具 | 复用已有MCP连接 |
Hook的输入输出
输入:通过stdin接收JSON,包含事件上下文(工具名、参数、会话信息等)。
输出:通过exit code控制行为:
| Exit Code | 含义 | 效果 |
|---|---|---|
| 0 | 成功 | 继续执行 |
| 2 | 阻止 | 阻止当前操作 |
| 其他 | 错误 | 忽略错误,继续执行 |
关键:exit code 2 是"阻止"信号。PreToolUse返回2,工具调用被阻止;Stop返回2,AI继续工作。
也可以通过stdout返回JSON来精细控制:
{
"decision": "deny",
"reason": "不允许修改生产环境配置文件"
}
二、实战:四个最实用的Hook
Hook 1:自动格式化代码
每次AI编辑文件后,自动运行格式化工具。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
]
}
]
}
}
AI编辑完文件,Prettier自动格式化。你看到的代码永远是规范格式。
Hook 2:保护敏感文件
阻止AI修改.env、数据库配置等敏感文件。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo '$CLAUDE_INPUT' | jq -r '.file_path // .path // empty'); case \"$FILE\" in *.env|*.env.*|*production*|*secrets*) echo '不允许修改敏感文件: '$FILE; exit 2;; esac"
}
]
}
]
}
}
AI试图编辑 .env 文件时,操作被阻止并显示原因。exit code 2 = 拦截。
这段命令提取AI要编辑的文件路径,检查是否匹配 .env 或包含 production/secrets 关键词。匹配就返回2(阻止),不匹配就返回0(放行)。注意:命令中的单引号是JSON字符串的一部分,实际执行时会正确展开变量。直接在终端测试需去掉单引号。
Hook 3:压缩后重新注入上下文
会话过长时Claude Code会自动压缩上下文,但可能丢失重要信息。用Hook在压缩后自动重新注入关键规则:
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo '记住:本项目使用TypeScript strict模式,测试覆盖率要求>80%。'"
}
]
}
]
}
}
压缩后,核心规则自动重新注入到上下文中。matcher: "compact" 表示只在上下文压缩后重新开始时触发,普通新会话不触发。Claude Code后来也新增了专门的 PostCompact 事件,效果相同。
Hook 4:审计日志
记录所有文件修改操作到日志文件,用于回溯审计。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "echo \"[$(date '+%Y-%m-%d %H:%M:%S')] Edit: $(echo '$CLAUDE_INPUT' | jq -r '.file_path // .path // \"unknown\"')\" >> .claude/edit-log.txt"
}
]
}
]
}
}
每次文件编辑都记录时间、文件路径。出问题时可以回溯。
三、进阶:Prompt-based Hooks
用LLM做判断
前四个Hook用shell搞定,但"检查代码是否包含硬编码密码"——这种需要语义理解的判断,shell无能为力,LLM却很擅长。这就是Prompt Hooks的用武之地。
Prompt-based Hooks用LLM做决策:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "prompt",
"prompt": "检查即将写入的代码是否包含硬编码的API密钥或密码。如果包含,返回 {\"ok\": false, \"reason\": \"检测到硬编码的敏感信息\"}。否则返回 {\"ok\": true}。"
}
]
}
]
}
}
AI每次编辑文件前,另一个LLM会先检查新代码是否包含敏感信息。发现就阻止。
响应格式:
{"ok": true} // 通过,继续执行
{"ok": false, "reason": "..."} // 阻止,显示原因
适用场景
| 场景 | 为什么用prompt | 示例 |
|---|---|---|
| 安全检查 | 需要理解代码语义 | 检测硬编码密钥、SQL注入 |
| 代码规范 | 需要判断风格是否符合 | 检查命名、结构 |
| 内容审核 | 需要理解自然语言 | 检查提交信息是否合规 |
Prompt hooks有延迟(需要LLM推理),不适合高频操作。对低频但重要的检查(如文件编辑前的安全审查)最合适。
四、权限系统:AI能做什么不能做什么
权限模式是整体策略(大方向控制),权限规则是精细化配置(具体操作控制)。模式决定默认行为,规则做例外处理。
四种权限模式
权限模式控制AI的自主程度——从"事事请示"到"放手去做":
| 模式 | 自动批准 | 需要确认 | 适用场景 |
|---|---|---|---|
default | 只读操作 | Bash命令、文件修改 | 日常开发(推荐) |
acceptEdits | 读取+编辑+常用命令 | Bash复杂命令 | 快速迭代 |
plan | 只读 | 一切修改 | 审查代码、调研 |
auto | 大部分操作 | 高风险操作(需Max/Team账号) | 高信任环境 |
dontAsk | 只读+预批准规则 | 其他一切 | CI/CD |
bypassPermissions | 全部 | 仅rm -rf / 和 rm -rf ~ | 隔离容器 |
切换方式:终端按 Shift+Tab 循环切换。
最常用的组合:
- 日常开发用
default——安全,每一步都有确认 - 重构时用
acceptEdits——AI可以自由编辑文件,减少中断 - 代码审查用
plan——AI只能看不能改
auto模式的智能分类器
auto模式不是"什么都允许"。它有一个分类器模型审查每个操作:
默认阻止:下载执行代码、发送敏感数据、生产部署、批量删除、IAM授权、force push。
默认允许:本地文件操作、安装依赖、读取.env、只读HTTP、推送到当前分支。
连续3次被阻止或总共20次被阻止后,auto模式会自动暂停,让你重新评估。
权限规则:精确控制
在 permissions 字段中配置规则,三层优先级:deny > ask > allow。
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force)",
"Edit(./.env)"
],
"allow": [
"Bash(npm run *)",
"Bash(git status)",
"Bash(git diff *)",
"Read(*)"
]
}
}
工具特定规则:
| 工具 | 规则语法 | 示例 |
|---|---|---|
| Bash | Bash(命令模式) | Bash(npm run *) 匹配所有npm scripts |
| Read/Edit | gitignore风格路径 | Edit(./.env) 匹配项目根的.env |
| WebFetch | WebFetch(domain:xxx) | WebFetch(domain:github.com) |
| MCP | mcp__服务器__工具 | mcp__puppeteer__* |
| Agent | Agent(名称) | Agent(Explore) |
通配符 * 匹配任意字符串。Bash(npm run *) 匹配 npm run build、npm run test 等。
受保护路径
某些路径默认受保护,即使权限模式允许,修改这些文件也会触发额外确认:
.git、.vscode、.idea、.claude(部分)、.bashrc、.zshrc、.mcp.json、.claude.json 等。
这是安全底线——AI不应该随意修改版本控制配置、IDE设置或自身配置文件。
五、Hooks与权限的配合
双层防护架构
Hooks和权限系统是两个互补的安全层:
操作请求 → 权限规则检查(deny/ask/allow)→ Hook执行(PreToolUse)→ 执行操作 → Hook执行(PostToolUse)
权限规则是静态的、确定性的——"这个模式匹配吗?匹配就允许/拒绝"。适合明确的黑白名单。
Hooks是动态的、可编程的——"看看这次操作的具体内容,判断是否安全"。适合需要上下文判断的场景。
配合模式
模式1:权限做白名单 + Hook做深度检查
{
"permissions": {
"allow": ["Bash(npm run *)"]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "CMD=$(echo '$CLAUDE_INPUT' | jq -r '.command'); if echo \"$CMD\" | grep -q 'rm\\|drop\\|delete'; then echo '检测到危险关键词'; exit 2; fi"
}]
}
]
}
}
权限允许 npm run *,但Hook会额外检查命令内容是否包含危险关键词。双层防护。
模式2:权限做黑名单 + Hook做审计
{
"permissions": {
"deny": ["Edit(./.env)", "Bash(git push --force)"]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "echo \"[$(date)] Edit: $(echo '$CLAUDE_INPUT' | jq -r '.file_path // .path')\" >> .claude/edit-log.txt"
}]
}
]
}
}
权限直接拦截明确禁止的操作,Hook记录所有文件修改的审计日志。
六、避坑指南
坑一:Hook命令执行失败导致操作被阻止
Hook脚本有bug或依赖缺失,exit code非0非2,理论上应该忽略。但某些情况下可能误阻止操作。
解法:Hook命令加上错误处理。确保正常路径返回0,明确要阻止时才返回2。不确定时用 || true 确保不阻止。
坑二:Hook无限循环
PostToolUse的Hook触发了新的工具调用,新调用又触发PostToolUse——无限循环。
解法:Stop和SubagentStop hook内置了 stop_hook_active 标志,连续被阻止后会强制结束。但最好在设计时就避免。PostToolUse Hook尽量只做通知和日志,不做工具调用。
坑三:权限规则优先级搞混
以为allow规则能覆盖deny规则——不能。deny永远优先于allow。
{
"permissions": {
"deny": ["Bash(*)"],
"allow": ["Bash(git status)"]
}
}
这个配置下,git status 也会被拒绝,因为 Bash(*) 在deny中匹配了一切。
解法:deny规则要精确,不要用宽泛的通配符。需要阻止特定操作时写具体模式,不要一刀切。
坑四:受保护路径的误判
修改 .claude/settings.json 被拦截——这是受保护路径。但你确实需要修改它。
解法:受保护路径的拦截是额外确认,不是阻止。终端会弹出确认提示,你确认后可以继续。
坑五:auto模式不是万能的
auto模式有分类器保护,但它基于概率判断,不是100%准确。高风险操作(生产部署、数据库迁移)不应该依赖auto模式。
解法:高风险操作用 default 或 plan 模式,确保每一步都有人工确认。auto模式适合日常开发,不适合关键操作。
结语
七篇文章下来,AI"员工"从单打独斗进化到了有工具、有帮手、有规矩的完整团队:
- CLAUDE.md是岗位说明书——告诉AI公司规矩
- Skills是工具箱——按需加载专业知识
- MCP是外线电话——连接外部系统
- Subagent是编外帮手——并行处理辅助任务
- Hooks是监控和门禁——自动化检查和拦截
- 权限是门禁卡——控制AI能进哪些门
五个关键要点:
Hooks是自动化守卫——在关键节点自动执行检查、通知、拦截,不用人工盯防。
Exit code 2是阻止信号——PreToolUse返回2阻止操作,PostToolUse用于审计和通知。
Prompt Hooks处理复杂判断——需要语义理解的检查交给LLM,简单的用shell脚本。
权限规则deny优先于allow——先配黑名单(deny),再配白名单(allow)。
Hooks和权限互补——权限做静态黑白名单,Hooks做动态上下文判断。
下一篇,我们组建AI项目组——多会话与CI/CD实战。如果说Hooks是给员工装了门禁,多会话和CI/CD就是把员工从单兵作战升级到项目组协同——并行开发、自动化流水线、代码审查一体化。
互动话题
你的项目中,哪些操作需要自动化保护?是防止误删生产配置、自动格式化代码,还是审计所有文件修改?来评论区分享你的Hooks和权限配置经验。
智能编码进化论 | 第7篇/共10篇
下一篇:AI项目组:多会话与CI/CD实战
本文内容仅供学习交流,所述方法需结合实际场景灵活运用。 AI工具输出结果仅供参考,关键业务决策请结合人工判断。
本文由AI辅助创作,经人工审核编辑后发布。
本文首发于微信公众号「羲和Lab」,公众号内可留言交流
阅读公众号原文