犀牛鸟 2026 研究笔记 estelledc.github.io

Claude Code 工具系统与权限架构

工具系统和权限架构是 Claude Code 的执行层核心——它们决定了 AI agent 能做什么、不能做什么、以及如何安全地做。


一、工具接口契约

每个工具实现统一的 Tool<Input, Output, P> 接口(约 40 个方法/属性):

interface Tool<Input, Output, P> {
  // 身份
  name: string
  description: string
  inputSchema: ZodSchema<Input>

  // 行为控制
  isConcurrencySafe: boolean      // 是否可并发执行
  shouldDefer: boolean            // 是否延迟加载(需 ToolSearch)
  alwaysLoad: boolean             // 是否始终加载
  interruptBehavior: 'cancel' | 'block'

  // 生命周期
  checkPermissions(ctx): PermissionResult
  call(input, ctx): Promise<Output>
  prompt(ctx): string             // 工具描述(注入 system prompt)

  // 渲染
  renderToolUse(input): ReactNode
  renderToolResult(output): ReactNode
  // ... 更多 render 方法
}

关键设计buildTool() 工厂函数填充默认实现,开发者只需覆盖关心的方法。


二、工具编排层

runTools() — 并发分区

async function runTools(toolUseBlocks: ToolUseBlock[]) {
  // 分区
  const concurrent = blocks.filter(b => b.tool.isConcurrencySafe)
  const serial = blocks.filter(b => !b.tool.isConcurrencySafe)

  // 并发安全组:Promise.all 并行
  const concurrentResults = await Promise.all(
    concurrent.map(b => runToolUse(b))
  )

  // 非并发安全组:串行执行
  const serialResults = []
  for (const block of serial) {
    serialResults.push(await runToolUse(block))
  }
}

并发安全工具(可并行):FileRead、Glob、Grep、WebFetch、WebSearch、TodoWrite

非并发安全工具(必须串行):BashTool、FileEdit、FileWrite、NotebookEdit

StreamingToolExecutor — 流式预执行

当 API 流式返回多个 tool_use blocks 时:

  1. 维护 pendingTools 队列
  2. Block 流完整后立即启动执行(不等待整个响应完成)
  3. 兄弟 abort:一个 Bash 出错 → 取消同轮未启动的兄弟工具
  4. Progress message 转发给上层

三、工具钩子系统

三种钩子运行器覆盖工具执行的完整生命周期:

PreToolUse

工具执行前触发。钩子可以:

安全约束resolveHookPermissionDecision() 确保钩子的 allow 不会覆盖全局 deny 规则。即使钩子返回 allow,如果存在显式 deny 规则,deny 仍然生效。

PostToolUse

工具执行成功后触发,可修改输出。

PostToolUseFailure

工具执行失败后触发,可提供恢复建议。


四、权限系统架构

四层纵深防御

┌─────────────────────────────────────────┐
│ Layer 4: System Prompt 层                │
│ 行为规范(概率性遵循)                    │
├─────────────────────────────────────────┤
│ Layer 3: Permission Rules 层             │
│ 确定性执行(allow/deny 规则)             │
├─────────────────────────────────────────┤
│ Layer 2: Tool 层                         │
│ checkPermissions() 方法                  │
├─────────────────────────────────────────┤
│ Layer 1: 用户确认层                      │
│ 交互式 dialog / auto-approve classifier │
└─────────────────────────────────────────┘

权限上下文 — resolve-once 模式

createPermissionContext() 使用 resolve-once 模式:多个判定源竞争同一个 Promise,第一个解决的结果生效,其他被忽略。

三种权限处理器

处理器 适用场景 策略
interactiveHandler 主 agent 4 源竞赛(UI/Bridge/Channel/Hooks)
coordinatorHandler Coordinator 模式 自动化优先,fallback 到交互
swarmWorkerHandler Swarm worker 转发给 leader

interactiveHandler 详解

最复杂的处理器,同时竞赛 4 个判定源:

                    ┌─── 本地 UI(terminal allow/deny 按钮)
                    │
Promise.race ──────├─── Bridge(Claude.ai / CCR 远程控制)
                    │
                    ├─── Channel(Telegram/iMessage 等)
                    │
                    └─── Hooks + Classifier(自动化规则)

第一个 resolve 的生效,AbortController 取消其他。

coordinatorHandler

自动化优先策略:

1. 先尝试 hooks 判定 → 如果有结果,直接返回
2. 再尝试 classifier 判定 → 如果有结果,直接返回
3. 两者都不做判定 → fallback 到交互式 dialog

swarmWorkerHandler

Worker 将权限请求转发给 leader:

Worker 需要权限
    ↓
通过 mailbox 发送权限请求
    ↓
registerPermissionCallback() 注册回调
    ↓
useSwarmPermissionPoller 每 500ms 轮询
    ↓
Leader 响应到达 → 回调触发 → 权限判定完成

权限模式

模式 行为 触发方式
default 交互式,每次确认 默认
auto 分类器自动判定 GrowthBook gate
bypassPermissions 跳过所有检查 --dangerously-skip-permissions
acceptEdits 自动接受编辑 配置
bubble 冒泡到父终端 fork 子 agent
plan 需要计划审批 teammate plan mode

五、Auto Mode 分类器

Auto mode 是 Claude Code 的”YOLO mode”——通过分类器自动判定工具调用是否安全:

// 分类器规则示例
{
  tool: "Bash",
  command_pattern: "^(cat|ls|find|grep|rg|head|tail|wc)\\b",
  decision: "allow"  // 只读命令自动允许
}

{
  tool: "FileEdit",
  path_pattern: "^/tmp/",
  decision: "allow"  // /tmp 下的编辑自动允许
}

CLI 子命令:


六、ToolSearch — 延迟加载机制

为了节省 token,非常用工具不加载到初始 prompt 中:

初始加载的工具(alwaysLoad=true):
  FileRead, FileWrite, FileEdit, Bash, Grep, Glob, AgentTool, ...

延迟加载的工具(shouldDefer=true):
  CronCreate, CronDelete, EnterPlanMode, ExitPlanMode,
  EnterWorktree, ExitWorktree, Monitor, NotebookEdit,
  PushNotification, RemoteTrigger, SendMessage,
  TaskCreate/Get/List/Output/Stop/Update,
  TeamCreate, TeamDelete, WebFetch, WebSearch, ...

模型需要使用延迟工具时,先调用 ToolSearch

ToolSearch({ query: "select:TeamCreate,SendMessage" })
    ↓
工具 schema 加载到当前上下文
    ↓
模型可以调用 TeamCreate / SendMessage

七、Services 层

API 服务

上下文压缩

MCP 集成

记忆服务


八、设计模式总结

1. Fail-closed 安全

所有工具默认需要权限。没有显式 allow 规则的操作一律拒绝。这与传统的 fail-open 设计(默认允许,显式拒绝)相反。

2. 竞赛式权限判定

多个判定源通过 Promise.race 竞争,第一个结果生效。这允许最快的判定源(如本地 hooks)立即响应,而不需要等待所有源。

3. 并发安全标记

工具自声明是否可并发执行(isConcurrencySafe),编排层据此自动分区。这比全局锁或手动管理并发更优雅。

4. 钩子不可覆盖 deny

即使 PreToolUse 钩子返回 allow,全局 deny 规则仍然生效。这确保了安全策略的不可绕过性。

5. 延迟加载节省 token

通过 ToolSearch 按需加载工具 schema,初始 prompt 只包含常用工具。这在 43+ 工具的规模下显著节省 token 成本。


参考资源

资源 链接
工具系统逆向 github.com/zong0728/claude-code-internals
权限系统分析 deepwiki.com/ai-ml-architect/claude-code/3-permission-system
Hook 系统文档 code.claude.com/docs/en/hooks
Auto Mode 配置 code.claude.com/docs/en/auto-mode
学术论文 arXiv:2604.14228 Section 4.2