Claude Code Wiki
首页 深入解析 工具系统

工具架构:Tool 接口与权限模型

中级 工具系统

Claude Code 的工具系统建立在统一的 Tool 接口之上,所有工具(内置工具、MCP 工具、技能工具)都遵循相同的生命周期:输入验证 → 权限检查 → 执行 → 结果映射。权限系统采用多层防御策略,通过权限模式、规则引擎、钩子系统实现细粒度的访问控制,确保 AI 助手在执行敏感操作前必须获得用户授权。这种架构设计既保证了灵活性——工具可以自定义权限逻辑和 UI 渲染——又确保了安全性——权限检查不可绕过且决策可追溯。

Tool 接口核心设计

Tool 接口定义了工具的完整契约,包含生命周期方法、类型定义、渲染函数三个维度的规范。每个工具必须实现 call() 执行逻辑、inputSchema 输入验证、description() 描述生成等核心方法,而权限检查、UI 渲染等方法则提供默认实现,工具可根据需要覆盖。

生命周期方法链

工具执行遵循严格的阶段顺序:validateInput()checkPermissions()call(),每个阶段都能中断执行链。输入验证阶段检查参数合法性(如文件路径是否存在),权限检查阶段确定是否需要用户授权(如危险命令需要确认),执行阶段完成实际操作(如运行 Shell 命令)。这种分层设计将安全检查与业务逻辑解耦,使权限逻辑可独立测试和复用。

// 工具执行的核心流程:验证 → 权限 → 执行
export type Tool<Input, Output, P> = {
  // 1. 输入验证(可选):检查参数合法性
  validateInput?(input, context): Promise<ValidationResult>
  
  // 2. 权限检查(必需):决定是否需要用户授权
  checkPermissions(input, context): Promise<PermissionResult>
  
  // 3. 核心执行(必需):实现工具的实际功能
  call(input, context, canUseTool, parentMessage, onProgress): Promise<ToolResult<Output>>
  
  // 4. 结果映射(必需):将输出转换为 API 格式
  mapToolResultToToolResultBlockParam(output, toolUseID): ToolResultBlockParam
}

buildTool() 工厂函数为可选方法提供安全的默认实现isEnabled() 默认返回 trueisConcurrencySafe() 默认返回 false(假设工具不可并发),isReadOnly() 默认返回 false(假设工具会修改状态),checkPermissions() 默认返回 allow(将决策权交给通用权限系统)。这种”最小权限默认”策略确保即使工具实现不完整,也不会意外绕过安全检查。

Sources: Tool.ts, Tool.ts

类型系统与 Schema 定义

工具使用 Zod Schema 定义输入参数的结构和约束,inputSchema 字段声明完整的参数规范(如 BashToolcommand 字符串、timeout 数字),TypeScript 的泛型系统从 Schema 自动推断 Input 类型,确保 call() 方法的参数类型安全。AnyObject 类型约束 Schema 必须输出对象类型({ [key: string]: unknown }),防止原始类型 Schema(如 z.string())导致的类型错误。

graph LR
    A[工具定义<br/>inputSchema: z.ZodType] --> B[类型推断<br/>Input = z.infer&lt;Schema&gt;]
    B --> C[编译期检查<br/>call(input: Input)]
    B --> D[运行时验证<br/>schema.parse]
    D --> E[API 调用<br/>validate_parameters]

outputSchema 字段(可选)声明工具输出的结构,用于类型检查和文档生成。inputsEquivalent() 方法(可选)定义输入等价性判断逻辑,用于工具结果缓存和去重——例如 BashTool 可忽略 timeout 字段差异,认为 command 相同的输入等价。ToolResult<T> 类型包装执行结果,包含 data 字段(实际输出)和可选的 newMessages 字段(追加到对话的消息),contextModifier 字段允许工具修改后续调用的上下文(如设置工作目录)。

Sources: Tool.ts, Tool.ts

渲染与 UI 集成

工具的 UI 渲染采用组件化设计renderToolUseMessage() 渲染工具调用消息(显示命令/参数),renderToolResultMessage() 渲染执行结果(显示输出/错误),renderToolUseProgressMessage() 渲染进度更新(显示百分比/状态),renderToolUseRejectedMessage() 渲染权限拒绝消息(显示原因/建议)。这些方法返回 React 组件,由 REPL 界面动态渲染,实现统一的视觉风格交互模式

renderGroupedToolUse() 方法(可选)支持批量渲染多个并发的工具调用——例如同时执行 3 个 BashTool 命令时,可在 UI 中合并为一个”批量操作”卡片,避免消息列表爆炸。isSearchOrReadCommand() 方法标记工具是否为”搜索/读取”操作,用于 UI 压缩显示(如 GlobToolGrepTool 的结果默认折叠)。getToolUseSummary() 返回工具调用的简短摘要(如”读取 src/foo.ts”),用于紧凑视图和通知显示。

// BashTool 的 UI 渲染方法示例
const BashTool: Tool = {
  // 渲染工具调用消息:显示命令和参数
  renderToolUseMessage(input, options) {
    return <BashToolUseMessage command={input.command} timeout={input.timeout} />
  },
  
  // 渲染执行结果:显示输出、错误、后台任务信息
  renderToolResultMessage(output, progressMessages, options) {
    return <BashToolResultMessage stdout={output.stdout} stderr={output.stderr} />
  },
  
  // 渲染进度更新:显示命令执行中的状态
  renderToolUseProgressMessage(progressMessages, options) {
    return <BashToolProgress messages={progressMessages} />
  },
  
  // 标记为搜索/读取命令:用于 UI 压缩
  isSearchOrReadCommand(input) {
    return isSearchOrReadBashCommand(input.command)
  }
}

Sources: Tool.ts, BashTool.tsx

权限系统架构

权限系统采用三层防御模型:权限模式定义全局策略(如 bypassPermissions 模式自动批准所有操作),权限规则实现细粒度控制(如 Bash(git *) 规则允许所有 git 命令),钩子系统提供动态拦截(如 PreToolUse 钩子可基于上下文拒绝工具调用)。权限决策结果包含 behavior(allow/ask/deny)、decisionReason(决策原因)、suggestions(更新建议)三个维度,确保决策透明且可审计。

权限模式与规则引擎

PermissionMode 定义了 6 种全局权限策略:default 模式(默认策略,敏感操作需要确认)、acceptEdits 模式(自动批准文件编辑)、bypassPermissions 模式(自动批准所有操作,危险)、dontAsk 模式(自动拒绝需要确认的操作)、plan 模式(规划模式,只读操作)、auto 模式(基于分类器自动决策)。权限模式通过 --permission-mode CLI 参数或 settings.jsondefaultMode 配置,影响所有工具的权限检查。

权限规则采用 ToolName(ruleContent) 语法,支持工具级操作级两种粒度:Bash 规则匹配所有 BashTool 调用,Bash(git *) 规则只匹配以 git 开头的命令。规则来源包括 userSettings(用户全局配置)、projectSettings(项目级配置)、policySettings(企业管理策略)、cliArg(命令行参数)、session(会话级临时规则),优先级从高到低:cliArg > session > policySettings > userSettings > projectSettings > localSettings

权限模式行为特征适用场景安全等级
default敏感操作需要用户确认,规则优先日常开发,推荐默认⭐⭐⭐⭐
acceptEdits自动批准文件编辑,其他操作需确认频繁文件操作⭐⭐⭐
plan只读模式,禁止修改操作代码审查,分析⭐⭐⭐⭐⭐
bypassPermissions自动批准所有操作,无拦截危险,仅测试环境
dontAsk自动拒绝需要确认的操作非交互式脚本⭐⭐
auto基于分类器自动决策(实验性)高级自动化场景⭐⭐⭐
graph TD
    A[权限检查请求] --> B{检查权限模式}
    B -->|bypassPermissions| C[自动批准]
    B -->|dontAsk| D[自动拒绝]
    B -->|default/acceptEdits| E[检查规则引擎]
    E --> F{匹配 alwaysAllow 规则?}
    F -->|是| C
    F -->|否| G{匹配 alwaysDeny 规则?}
    G -->|是| D
    G -->|否| H{匹配 alwaysAsk 规则?}
    H -->|是| I[提示用户确认]
    H -->|否| J[调用工具 checkPermissions]
    J --> K{工具自定义逻辑}
    K -->|返回 allow| C
    K -->|返回 deny| D
    K -->|返回 ask| I

Sources: permissions.ts, permissions.ts

权限决策流程

hasPermissionsToUseTool() 函数实现标准权限检查流程:首先检查全局权限模式(bypassPermissions 直接批准,dontAsk 直接拒绝),然后检查规则引擎(匹配 alwaysAllow/alwaysDeny/alwaysAsk 规则),最后调用工具的 checkPermissions() 方法执行自定义逻辑。BashTool 的 bashToolHasPermission() 方法解析命令(使用 splitCommandWithOperators() 拆分复合命令),为每个子命令检查权限(如 git pushrm -rf 需要不同的授权),聚合所有子命令的决策结果。

权限决策结果 PermissionResult 包含 4 种行为:allow(批准执行,可附带 updatedInput 修改输入)、ask(需要用户确认,附带 message 说明原因)、deny(拒绝执行,附带 decisionReason)、passthrough(透传到下一层检查)。decisionReason 字段记录决策依据,类型包括 rule(规则匹配)、mode(模式限制)、hook(钩子拦截)、classifier(分类器决策)、subcommandResults(子命令聚合),用于审计日志和错误提示。

// 权限检查的核心流程(简化版)
async function hasPermissionsToUseTool(tool, input, context, assistantMessage, toolUseID) {
  // 1. 检查全局权限模式
  if (context.toolPermissionContext.mode === 'bypassPermissions') {
    return { behavior: 'allow', updatedInput: input }
  }
  
  // 2. 检查规则引擎:alwaysAllow 规则
  const allowRule = toolAlwaysAllowedRule(context.toolPermissionContext, tool)
  if (allowRule) {
    return { behavior: 'allow', decisionReason: { type: 'rule', rule: allowRule } }
  }
  
  // 3. 检查规则引擎:alwaysDeny 规则
  const denyRule = getDenyRuleForTool(context.toolPermissionContext, tool)
  if (denyRule) {
    return { behavior: 'deny', decisionReason: { type: 'rule', rule: denyRule } }
  }
  
  // 4. 调用工具自定义权限检查
  return tool.checkPermissions(input, context)
}

Sources: permissions.ts, BashTool.tsx, useCanUseTool.tsx

canUseTool Hook 与用户交互

useCanUseTool Hook 是权限系统的前端入口,封装了完整的权限决策流程:调用 hasPermissionsToUseTool() 获取决策结果,根据 behavior 分发到不同的处理器(handleCoordinatorPermissionhandleSwarmWorkerPermissionhandleInteractivePermission),处理用户交互(显示权限对话框、收集用户选择、更新权限规则),返回最终的 PermissionDecision。Hook 还集成分类器预检查peekSpeculativeClassifierCheck()),在用户确认前异步运行分类器,如果分类器高置信度批准,可自动批准权限请求。

权限对话框显示工具描述(调用 tool.description() 生成)、决策原因(decisionReason.message)、更新建议(suggestions 数组,如”添加规则 Bash(git *) 到用户配置”),用户可选择”允许”、“拒绝”、“总是允许”、“总是拒绝”。选择”总是允许/拒绝”会触发 applyPermissionUpdate() 更新权限配置,持久化到 settings.json 或会话状态。协调器模式(Coordinator Mode)的工作线程会跳过交互式对话框,直接使用协调器的权限决策,避免阻塞后台任务。

sequenceDiagram
    participant QE as QueryEngine
    participant Hook as useCanUseTool
    participant Perm as hasPermissionsToUseTool
    participant Tool as Tool.checkPermissions
    participant UI as PermissionDialog
    participant User as 用户
    
    QE->>Hook: canUseTool(BashTool, {command: "git push"})
    Hook->>Perm: 检查权限模式
    alt bypassPermissions 模式
        Perm-->>Hook: {behavior: "allow"}
    else 检查规则
        Perm->>Perm: 匹配 alwaysAllow/alwaysDeny 规则
        alt 规则匹配
            Perm-->>Hook: {behavior: "allow"/"deny", decisionReason}
        else 无规则匹配
            Perm->>Tool: checkPermissions(input, context)
            Tool-->>Perm: {behavior: "ask", message: "需要推送权限"}
            Perm-->>Hook: {behavior: "ask", message, suggestions}
            Hook->>UI: 显示权限对话框
            UI->>User: "允许 git push 吗?"
            User->>UI: "总是允许"
            UI->>Hook: {decision: "accept", persist: true}
            Hook->>Hook: applyPermissionUpdate({type: "addRules", ...})
            Hook-->>QE: {behavior: "allow", updatedInput}
        end
    end

Sources: useCanUseTool.tsx, permissions.ts

工具注册与生命周期管理

getAllBaseTools() 函数是工具注册中心,返回当前环境中所有可用的工具实例(包括内置工具、条件编译工具、实验性工具)。工具通过静态导入import { BashTool } from './tools/BashTool/BashTool.js')或动态加载require('./tools/REPLTool/REPLTool.js').REPLTool)注册,条件编译通过 process.env.USER_TYPEfeature('PROACTIVE') 等标志控制,实现按需加载特性开关

工具集合与过滤

Tools 类型定义为 readonly Tool[],确保工具集合不可变。findToolByName() 工具通过名称或别名查找工具(支持工具重命名后的向后兼容)。getToolsForDefaultPreset() 过滤工具集合,只返回 isEnabled() 返回 true 的工具,实现动态工具集(如 PowerShellTool 只在 Windows 平台启用)。工具过滤逻辑还集成 MCP 工具发现(mcpClients 动态添加工具)、技能加载(skills 目录动态注册),在 QueryEngine 初始化时构建完整的工具集。

// 工具注册示例(src/tools.ts)
export function getAllBaseTools(): Tools {
  return [
    // 内置工具:始终可用
    AgentTool,
    BashTool,
    FileReadTool,
    FileEditTool,
    FileWriteTool,
    
    // 条件编译工具:根据环境变量加载
    ...(process.env.USER_TYPE === 'ant' ? [REPLTool, SuggestBackgroundPRTool] : []),
    ...(feature('PROACTIVE') ? [SleepTool] : []),
    ...(isPowerShellToolEnabled() ? [PowerShellTool] : []),
    
    // 实验性工具:通过特性开关控制
    ...(feature('WEB_BROWSER_TOOL') ? [WebBrowserTool] : []),
  ].filter(Boolean)
}

工具生命周期包含 4 个阶段:注册getAllBaseTools() 加载工具实例)、初始化QueryEngine 构建 ToolUseContext,注入依赖)、执行canUseTool()tool.call() 执行工具)、清理(工具返回结果,更新状态)。ToolUseContext 对象包含工具执行所需的所有上下文:getAppState()/setAppState() 访问全局状态、abortController 处理中断、readFileState 文件缓存、messages 对话历史、toolDecisions 权限决策记录,确保工具在隔离的上下文中执行,避免全局污染。

Sources: tools.ts, Tool.ts, Tool.ts

工具并发与中断控制

isConcurrencySafe() 方法声明工具是否支持并发执行:返回 true 的工具(如 GlobToolGrepTool)可在同一对话中并发调用多个实例,返回 false 的工具(如 BashToolFileEditTool)必须串行执行,避免竞态条件。interruptBehavior() 方法定义用户中断行为:'cancel' 模式立即停止工具并丢弃结果(如 AskUserQuestionTool),'block' 模式继续执行并排队新消息(如 BashTool 的长时间运行命令)。

工具的 isReadOnly() 方法标记操作是否只读(如 FileReadToolGrepTool),影响权限检查和 UI 显示(只读操作显示灰色图标,写操作显示警告图标)。isDestructive() 方法标记操作是否不可逆(如 BashToolrm -rfFileWriteTool 的覆盖写入),触发额外的安全检查和用户确认。isOpenWorld() 方法标记工具是否访问外部资源(如 WebFetchToolWebSearchTool),用于沙箱隔离和网络策略检查。

工具方法用途默认值安全影响
isConcurrencySafe()是否支持并发执行false避免竞态条件
isReadOnly()是否只读操作false影响权限检查严格度
isDestructive()是否不可逆操作false触发额外确认
isOpenWorld()是否访问外部资源-网络策略隔离
interruptBehavior()中断行为'block'用户体验控制

Sources: Tool.ts, BashTool.tsx

实战案例:BashTool 权限实现

BashTool 是权限系统最复杂的工具之一,实现了命令解析子命令权限检查沙箱隔离后台任务管理等多层安全机制。bashToolHasPermission() 方法使用 splitCommandWithOperators() 拆分复合命令(如 git add . && git commit -m "msg" 拆分为 git add .git commit),为每个子命令独立检查权限,聚合所有子命令的决策结果,确保最严格的安全策略(任一子命令需要确认,整个命令就需要确认)。

命令解析与权限规则匹配

BashTool 的权限规则支持通配符匹配Bash(git *) 规则匹配所有以 git 开头的命令,Bash(npm *) 规则匹配所有 npm 命令,Bash(rm *) 规则匹配所有 rm 命令。permissionRuleExtractPrefix() 函数提取命令前缀(如 git push origin main 提取 git),与规则内容进行前缀匹配。matchWildcardPattern() 函数支持 * 通配符(如 Bash(curl *api.example.com*) 匹配特定域名的 curl 请求),实现灵活的权限控制

命令分类(isSearchOrReadBashCommand())标记命令为”搜索”、“读取”、“列表”操作,用于 UI 压缩显示。搜索命令(grepfindrgag)和读取命令(catheadtailjq)的结果默认折叠,避免消息列表爆炸。列表命令(lstreedu)单独分类,显示”列出 N 个目录”摘要。语义中性命令echoprintftruefalse)不影响命令分类,确保 ls dir && echo "---" && ls dir2 仍被识别为列表命令。

// BashTool 权限检查流程(简化版)
async function bashToolHasPermission(input, context): Promise<PermissionResult> {
  const { command } = input
  
  // 1. 检查沙箱覆盖:用户是否要求跳过沙箱
  if (input.sandbox !== undefined && !input.sandbox) {
    return {
      behavior: 'ask',
      message: 'Run outside of the sandbox',
      decisionReason: { type: 'sandboxOverride' }
    }
  }
  
  // 2. 检查工作目录:是否在允许的目录范围内
  const cwd = input.workingDir || process.cwd()
  if (!isWithinAllowedDirectories(cwd, context)) {
    return {
      behavior: 'deny',
      message: `Working directory ${cwd} is outside allowed paths`,
      decisionReason: { type: 'workingDir', reason: '...' }
    }
  }
  
  // 3. 拆分复合命令,检查每个子命令的权限
  const subcommands = splitCommandWithOperators(command)
  const subcommandResults = new Map<string, PermissionResult>()
  
  for (const subcmd of subcommands) {
    // 检查规则引擎:Bash(prefix:*) 规则
    const rule = matchBashRule(subcmd, context)
    if (rule) {
      subcommandResults.set(subcmd, {
        behavior: rule.ruleBehavior,
        decisionReason: { type: 'rule', rule }
      })
    } else {
      // 无规则匹配,需要用户确认
      subcommandResults.set(subcmd, {
        behavior: 'ask',
        message: `Command "${subcmd}" requires approval`
      })
    }
  }
  
  // 4. 聚合所有子命令的决策结果
  const needsApproval = Array.from(subcommandResults.entries())
    .filter(([_, result]) => result.behavior === 'ask' || result.behavior === 'passthrough')
  
  if (needsApproval.length > 0) {
    return {
      behavior: 'ask',
      message: `This command contains ${needsApproval.length} operations that require approval`,
      decisionReason: { type: 'subcommandResults', reasons: subcommandResults }
    }
  }
  
  // 5. 所有子命令都批准,返回允许
  return { behavior: 'allow', updatedInput: input }
}

Sources: bashPermissions.ts, BashTool.tsx, permissions.ts

沙箱隔离与后台任务

BashTool 集成 SandboxManager 实现操作系统级隔离:在 macOS 上使用 Seatbelt 配置文件限制文件系统访问、网络连接、进程创建;在 Linux 上使用 bwrap(Bubblewrap)创建沙箱命名空间。shouldUseSandbox() 函数根据命令类型(读取命令禁用沙箱,网络命令启用沙箱)、用户配置(sandbox: false 参数)、环境变量(CLAUDE_CODE_DISABLE_SANDBOX)决定是否启用沙箱。沙箱配置通过 parseForSecurity() 解析命令 AST,自动推断所需的权限(如 curl 需要网络权限,cat 需要文件读取权限)。

后台任务管理通过 spawnShellTask() 实现:长时间运行的命令(超过 ASSISTANT_BLOCKING_BUDGET_MS 15 秒)自动转移到后台,分配唯一的 backgroundTaskId,输出重定向到任务输出文件(getTaskOutputPath())。工具结果包含 backgroundInfo 消息,告知模型任务 ID 和输出路径,模型可使用 TaskOutputTool 获取最终结果。用户可通过 Ctrl+Z 手动后台化命令,markTaskNotified()unregisterForeground() 管理前台任务注册,确保中断信号正确传播。

graph TD
    A[BashTool.call] --> B{命令类型判断}
    B -->|读取命令<br/>cat/head/tail| C[禁用沙箱]
    B -->|网络命令<br/>curl/wget| D[启用沙箱<br/>网络权限]
    B -->|修改命令<br/>rm/mv/cp| E[启用沙箱<br/>文件权限]
    B -->|混合命令| F[AST 解析<br/>推断权限]
    
    C --> G[直接执行]
    D --> H[SandboxManager.wrap]
    E --> H
    F --> H
    
    H --> I{执行时间}
    I -->|< 15s| J[返回结果]
    I -->|> 15s| K[自动后台化]
    K --> L[返回 backgroundTaskId]
    L --> M[TaskOutputTool 轮询结果]

Sources: shouldUseSandbox.ts, BashTool.tsx, sandbox-adapter.ts

高级特性:钩子系统与分类器集成

权限系统集成了 PreToolUse/PostToolUse 钩子,允许用户在工具执行前后注入自定义逻辑。executePermissionRequestHooks() 函数在权限检查阶段调用所有 permissionRequest 钩子,钩子可返回 allow/deny/ask 决策覆盖默认权限逻辑。钩子的 if 条件支持工具参数模式匹配(如 Bash(git *)),preparePermissionMatcher() 方法预处理输入参数,返回闭包函数高效匹配钩子模式。

分类器自动决策

Transcript Classifierfeature('TRANSCRIPT_CLASSIFIER'))是实验性的 AI 安全分类器,自动评估工具调用的安全性。classifierDecision() 函数将对话历史和当前工具调用发送到分类 API,返回 allow/deny 决策和置信度。高置信度的 allow 决策可自动批准权限请求,无需用户确认。auto-mode 权限模式启用分类器驱动的自动决策,实现无人工干预的自动化流程(适用于 CI/CD 管道、后台代理)。

// 分类器集成示例(useCanUseTool.tsx)
const decisionPromise = hasPermissionsToUseTool(tool, input, context, assistantMessage, toolUseID)
  .then(async result => {
    if (result.behavior === 'allow') {
      // 分类器批准:记录决策并返回
      if (result.decisionReason?.type === 'classifier' && 
          result.decisionReason.classifier === 'auto-mode') {
        setYoloClassifierApproval(toolUseID, result.decisionReason.reason)
      }
      return buildAllow(result.updatedInput ?? input, { decisionReason: result.decisionReason })
    }
    
    if (result.behavior === 'ask' && result.pendingClassifierCheck) {
      // 异步运行分类器,可能在用户确认前自动批准
      const speculativePromise = peekSpeculativeClassifierCheck(input.command)
      const raceResult = await Promise.race([
        speculativePromise,
        timeout(2000) // 2 秒超时
      ])
      
      if (raceResult.type === 'result' && 
          raceResult.result.matches && 
          raceResult.result.confidence === 'high') {
        // 高置信度匹配:自动批准
        consumeSpeculativeClassifierCheck(input.command)
        return buildAllow(input, {
          decisionReason: {
            type: 'classifier',
            classifier: 'bash_allow',
            reason: `Allowed by prompt rule: "${raceResult.result.matchedDescription}"`
          }
        })
      }
    }
    
    // 无分类器匹配或低置信度:显示权限对话框
    handleInteractivePermission(ctx, description, result, resolve)
  })

Sources: hooks.ts, useCanUseTool.tsx, classifierDecision.ts

权限拒绝追踪与降级策略

DenialTrackingState 记录连续的权限拒绝次数,当拒绝次数超过阈值(DENIAL_LIMITS 配置)时,触发降级策略:从 auto-mode 降级到 default 模式,强制用户确认后续操作。recordDenial() 函数在每次权限拒绝时递增计数器,recordSuccess() 函数在权限批准时重置计数器,shouldFallbackToPrompting() 函数判断是否触发降级。这种机制防止 AI 陷入无限重试循环(如反复尝试被拒绝的命令),强制切换到交互模式。

权限决策的审计日志通过 logPermissionDecision() 函数记录:包含工具名称、输入参数、决策结果、决策来源(规则/钩子/分类器/用户)、时间戳。日志写入诊断文件(diagLogs.ts),支持事后分析和合规审计。toolDecisions Map 缓存会话内的所有权限决策,避免重复检查相同操作,提高性能。

Sources: denialTracking.ts, permissionLogging.ts, useCanUseTool.tsx

总结与最佳实践

Claude Code 的工具架构通过统一的 Tool 接口实现了高度的一致性和可扩展性,所有工具遵循相同的生命周期(验证 → 权限 → 执行 → 渲染),通过 Zod Schema 保证类型安全,通过 React 组件实现灵活的 UI 渲染。权限系统的多层防御模型(权限模式 + 规则引擎 + 钩子系统 + 分类器)提供了细粒度的访问控制,确保 AI 助手在执行敏感操作前必须获得用户授权,同时支持自动化场景(bypassPermissions 模式)和实验性特性(auto-mode 分类器)。

开发者指南

实现新工具时,优先使用 buildTool() 工厂函数,只实现必需的方法(callinputSchemadescriptionpromptmapToolResultToToolResultBlockParam),依赖默认实现处理可选方法。权限检查逻辑应放在 checkPermissions() 方法中,遵循”最小权限默认”原则(默认需要确认,只有明确规则才批准)。UI 渲染方法应保持简洁,复杂 UI 拆分为独立组件,使用 isSearchOrReadCommand() 标记只读操作以启用 UI 压缩。

配置权限规则时,优先使用项目级配置(.claude/settings.json)而非用户级配置(~/.claude/settings.json),确保权限规则与代码仓库一起版本控制。规则语法应尽量具体(如 Bash(git push origin main) 而非 Bash(git *)),避免过度授权。生产环境应避免使用 bypassPermissions 模式,开发环境可临时启用以提高效率,但需定期审查权限日志。

调试权限问题时,检查 toolDecisions Map 了解决策链路,查看 decisionReason 字段确定决策来源(规则匹配/钩子拦截/分类器决策/用户选择)。权限对话框的 suggestions 数组提供更新建议,可直接应用(点击”总是允许”)或手动编辑配置文件。诊断日志(diagLogs.ts)记录完整的权限检查历史,支持事后分析和问题排查。