这是进阶内容,假设你已经了解 Claude Code 的基础 Hook 机制。如果还不熟悉,建议先阅读另一篇文章《Claude Code Hooks 工程化指南》。

2026年4月1日,Claude Code 发布了两个重量级 Hook 新能力:PermissionDenied HookDeferred Permission Decision。这两个功能,解决了 Auto Mode(自动执行模式)在生产环境落地的最后两个关键痛点。


一、问题背景:Auto Mode 的「卡住」困境

Claude Code 的 -a / --allow-foremost 自动执行模式,让 AI 可以在不等待确认的情况下执行工具调用。这对于:

是刚需能力。

但过去有个核心问题:当 Auto Mode 的分类器拒绝某次调用时,整个任务就卡住了。

典型场景:

用户:批量重命名 200 个文件,改成 snake_case

Auto Mode 分类器:
  ✓ rename file a/b/CamelCase.ts -> a/b/camel_case.ts ✅
  ✓ rename file a/b/AnotherFile.ts -> another_file.ts ✅
  ✗ delete file a/b/.DS_Store -> 拒绝(可能误判为关键文件)
  
结果:任务在「拒绝」处停住,等待用户介入,但用户可能不在电脑前。

过去你能做的只有:手动执行被拒绝的操作,然后 resume。但这种方式:

  1. 无法让模型自动重试(模型不知道被拒绝的具体原因)
  2. 无法批量处理「先看看行不行」的决策
  3. 对于 CI/CD 无人值守场景,整个流水线就此中断

二、PermissionDenied Hook:拒绝后的自动重试

2.1 是什么

PermissionDenied Hook 是在 Auto Mode 分类器拒绝工具调用后触发的回调。它的独特之处在于:

// Hook 返回值可以包含 retry: true
// 告诉模型:"这次被拒了,但你再试一次"
{
  "action": "allow",
  "retry": true,  // ← 新字段
  "reason": "模型可以基于这个反馈调整参数后重试"
}

2.2 触发时机

用户 Prompt → 模型决策 → 工具调用 → Auto Mode 分类器判定
                                              ↓
                                    ┌─────────┴─────────┐
                                    ↓                   ↓
                              允许执行              拒绝执行
                                    ↓                   ↓
                               执行工具          PermissionDenied Hook
                                                      ↓
                                              返回 retry: true?
                                              ↓           ↓
                                        模型重试      任务终止

2.3 典型使用场景

场景1:智能重试策略

// permission-denied.js
module.exports = async (hook) => {
  const { tool_name, tool_input, reason } = hook;
  
  // 分析拒绝原因,决定是否重试
  if (reason.includes('file might be important') && 
      tool_input.path.endsWith('.tmp')) {
    // 临时文件被误判为重要文件,直接重试
    return { action: 'allow', retry: true };
  }
  
  if (reason.includes('too many files') && tool_input.files?.length > 10) {
    // 批量操作太大,分批重试
    return { action: 'allow', retry: true };
  }
  
  // 其他情况不重试,等待人工介入
  return { action: 'deny', retry: false };
};

场景2:日志与告警

module.exports = async (hook) => {
  // 记录每次拒绝,用于分析 Auto Mode 分类器的误判模式
  await logPermissionDenial({
    tool: hook.tool_name,
    input: hook.tool_input,
    reason: hook.reason,
    timestamp: Date.now(),
    session: hook.sessionId
  });
  
  // 仍然允许重试(如果模型选择重试的话)
  return { action: 'allow', retry: true };
};

2.4 工程价值

维度 价值
自动化 CI/CD 场景不再因单次误判而中断
智能化 模型可以基于拒绝原因调整参数后重试
可观测 拒绝事件有了统一的 Hook 入口,便于分析
可治理 企业可以统一配置重试策略,而不是靠模型「猜」

三、Deferred Permission Decision:延迟决策的正确姿势

3.1 是什么

Deferred Permission Decision 允许 PreToolUse Hook 返回 defer 决策,把「是否允许」这个判断从运行时延后到某个未来的时刻

// PreToolUse Hook 可以返回 "defer"
{
  "action": "defer",  // ← 暂停,等待后续决策
  "reason": "需要人工确认,稍后可通过 -p --resume 决策"
}

当使用 -p --resume 时,模型会重新走一遍 PreToolUse Hook,这次 Hook 可以返回 allowdeny

3.2 工作流程

1. 用户发起任务(可能在 CI 上)
      ↓
2. PreToolUse Hook 判断:这次需要人工确认,但不阻塞
      ↓
3. Hook 返回 { action: "defer" },工具调用暂停
      ↓
4. Claude Code 输出提示:"某些操作需要后续确认,使用 --resume 继续"
      ↓
5. (人在忙其他事情...)
      ↓
6. 用户回来后,执行: claude -p --resume
      ↓
7. 模型重新尝试这些被 defer 的调用
      ↓
8. PreToolUse Hook 再次被触发,这次可以返回 allow/deny

3.3 典型使用场景

场景1:批量修改前的敏感文件检查

// pre-tool-use.js
module.exports = async (hook) => {
  const { tool_name, tool_input } = hook;
  
  // 判断是否是敏感操作
  const sensitivePatterns = [
    /schema\.sql$/i,
    /migration/i,
    /\.env$/i,
    /secrets\.json$/i
  ];
  
  if (tool_name === 'Write' || tool_name === 'Edit') {
    const path = tool_input.file_path || tool_input.path;
    if (sensitivePatterns.some(p => p.test(path))) {
      // 敏感文件,延迟决策
      return {
        action: "defer",
        reason: `修改敏感文件 ${path},需要确认`
      };
    }
  }
  
  return { action: "allow" };
};

场景2:多阶段任务的阶段性确认

module.exports = async (hook) => {
  const { tool_name, task_context } = hook;
  
  // 如果任务涉及到「删除」操作,且是批量删除,延迟决策
  if (tool_name === 'Bash' && 
      (tool_input.command.includes('rm ') || 
       tool_input.command.includes('delete'))) {
    return {
      action: "defer",
      reason: "检测到删除操作,需要确认"
    };
  }
  
  return { action: "allow" };
};

3.4 结合 forceRemoteSettingsRefresh:企业级治理

2026年4月4日发布的 forceRemoteSettingsRefresh 政策,让整个权限治理更严格:

// settings.json
{
  "permissions": {
    "defaultMode": "auto"
  },
  "policies": {
    "forceRemoteSettingsRefresh": true
  }
}

效果:启动时强制从远程拉取托管配置,如果拉取失败则直接退出(fail-closed)。

组合价值

Remote Settings (集中配置)
    ↓
forceRemoteSettingsRefresh (启动时强制拉取)
    ↓
PreToolUse Hook + defer (运行时灵活决策)
    ↓
PermissionDenied Hook + retry (拒绝后自动重试)
    ↓
完整的企业级权限治理闭环

四、何时用「拒绝」,何时用「延迟」

场景 推荐方式 理由
明显危险的操作(删除整个目录、格式化磁盘) deny 安全第一,不用犹豫
临时文件、缓存文件可能被误判 defer + retry 给模型调整参数的机会
敏感文件需要确认但不紧急 defer 不阻塞当前任务,稍后确认
CI/CD 无人值守场景 retry: true 让模型有重试机会,减少人工介入
需要人工确认才能继续的关键节点 defer 只有确认后才能继续

五、总结:权限治理的完整图景

PermissionDenied Hook 和 Deferred Permission Decision 的组合,让 Claude Code 的权限系统从「二元判定」(允许/拒绝),进化到「多态决策」(允许/拒绝/延迟/重试)。

这对于:

都是实质性提升。

这两个功能刚发布一周,还没有多少人真正用起来。这恰恰是最好的时间窗口——现在学懂、用熟,等它成为社区共识时,你已经是「过来人」了。


延伸阅读