Skip to content

Latest commit

 

History

History
911 lines (741 loc) · 34.4 KB

File metadata and controls

911 lines (741 loc) · 34.4 KB

Claude Code 工具系统架构分析

基于 Claude Code v2.1.88 源码分析,源码路径:src/

Architecture Diagrams

Tool System Architecture

Permission Flow

1. Tool 接口定义

工具系统的核心类型定义在 src/Tool.ts,每个工具必须实现 Tool 接口。该接口采用泛型设计,支持类型安全的输入/输出和进度报告。

1.1 Tool 泛型签名

type Tool<
  Input extends AnyObject = AnyObject,    // Zod schema 约束的输入类型
  Output = unknown,                        // 工具执行输出类型
  P extends ToolProgressData = ToolProgressData  // 进度事件类型
>

1.2 核心字段一览

字段 类型 必需 说明
name string 工具唯一标识符,如 BashEdit
aliases string[] 向后兼容的别名(重命名后旧名称仍可用)
inputSchema z.ZodType Zod schema,用于输入验证
inputJSONSchema ToolInputJSONSchema MCP 工具直接指定 JSON Schema 格式
outputSchema z.ZodType 输出类型 schema
maxResultSizeChars number 结果超过此阈值则持久化到磁盘,返回预览
searchHint string ToolSearch 关键词匹配短语(3-10词)
shouldDefer boolean 是否延迟加载(需要 ToolSearch 先发现才能调用)
alwaysLoad boolean 始终加载,不参与延迟机制
isMcp boolean 标记为 MCP 工具
isLsp boolean 标记为 LSP 工具
strict boolean 启用严格模式,API 更严格遵循工具参数 schema
mcpInfo {serverName, toolName} MCP 工具的服务器和工具原始名称

1.3 核心方法签名

执行相关:

// 核心调用方法
call(
  args: z.infer<Input>,
  context: ToolUseContext,
  canUseTool: CanUseToolFn,
  parentMessage: AssistantMessage,
  onProgress?: ToolCallProgress<P>,
): Promise<ToolResult<Output>>

// 输入验证(schema 验证后的业务逻辑验证)
validateInput?(
  input: z.infer<Input>,
  context: ToolUseContext,
): Promise<ValidationResult>

// 权限检查(tool-specific 逻辑)
checkPermissions(
  input: z.infer<Input>,
  context: ToolUseContext,
): Promise<PermissionResult>

行为标记方法:

isEnabled(): boolean           // 工具是否启用
isConcurrencySafe(input): boolean  // 是否可以并发执行(只读工具返回 true)
isReadOnly(input): boolean     // 是否只读操作
isDestructive?(input): boolean // 是否不可逆操作(delete、overwrite)
interruptBehavior?(): 'cancel' | 'block'  // 用户中断时的行为
isSearchOrReadCommand?(input): {isSearch, isRead, isList}  // UI 折叠标记

UI 渲染方法:

renderToolUseMessage(input, options): React.ReactNode      // 渲染调用消息
renderToolResultMessage?(content, progress, options): React.ReactNode  // 渲染结果
renderToolUseProgressMessage?(progress, options): React.ReactNode      // 渲染进度
renderToolUseRejectedMessage?(input, options): React.ReactNode         // 拒绝消息
renderToolUseErrorMessage?(result, options): React.ReactNode           // 错误消息
renderGroupedToolUse?(toolUses, options): React.ReactNode | null       // 分组渲染

工具结果类型:

type ToolResult<T> = {
  data: T
  newMessages?: (UserMessage | AssistantMessage | AttachmentMessage | SystemMessage)[]
  contextModifier?: (context: ToolUseContext) => ToolUseContext  // 仅非并发安全工具有效
  mcpMeta?: {
    _meta?: Record<string, unknown>
    structuredContent?: Record<string, unknown>
  }
}

1.4 buildTool 工厂函数

所有工具通过 buildTool() 工厂函数构建,提供安全的默认值:

const TOOL_DEFAULTS = {
  isEnabled: () => true,
  isConcurrencySafe: () => false,    // 保守默认:不安全
  isReadOnly: () => false,            // 保守默认:假设写操作
  isDestructive: () => false,
  checkPermissions: () => Promise.resolve({ behavior: 'allow', updatedInput }),
  toAutoClassifierInput: () => '',    // 默认跳过分类器
  userFacingName: () => name,
}

buildTool 的类型签名使用了精心设计的泛型推导:BuiltTool<D> 在类型层面精确镜像 {...TOOL_DEFAULTS, ...def} 的运行时语义,确保 60+ 个工具的类型检查一致性。


2. ToolPermissionContext - 权限上下文

权限上下文是 DeepImmutable 类型,不可变设计确保安全性。

type ToolPermissionContext = DeepImmutable<{
  mode: PermissionMode
  additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
  alwaysAllowRules: ToolPermissionRulesBySource
  alwaysDenyRules: ToolPermissionRulesBySource
  alwaysAskRules: ToolPermissionRulesBySource
  isBypassPermissionsModeAvailable: boolean
  isAutoModeAvailable?: boolean
  strippedDangerousRules?: ToolPermissionRulesBySource
  shouldAvoidPermissionPrompts?: boolean         // 后台 agent 无 UI 时自动拒绝
  awaitAutomatedChecksBeforeDialog?: boolean     // coordinator workers 先等自动检查
  prePlanMode?: PermissionMode                   // plan mode 进入前的模式,退出时恢复
}>

2.1 权限模式 (PermissionMode)

// 外部模式(用户可配置)
type ExternalPermissionMode =
  | 'default'           // 默认:每次询问用户
  | 'acceptEdits'       // 自动接受编辑,其他仍询问
  | 'bypassPermissions' // 跳过所有权限检查(dangerously-skip-permissions)
  | 'dontAsk'           // 不询问,不允许的操作直接拒绝
  | 'plan'              // Plan mode:只允许只读操作

// 内部模式(系统使用)
type InternalPermissionMode = ExternalPermissionMode
  | 'auto'    // 自动模式(基于分类器判断)
  | 'bubble'  // 冒泡模式(子 agent 向上传递权限请求)

2.2 权限规则来源

type PermissionRuleSource =
  | 'userSettings'     // ~/.claude/settings.json
  | 'projectSettings'  // .claude/settings.json (项目级)
  | 'localSettings'    // .claude/settings.local.json
  | 'flagSettings'     // Feature flag 配置
  | 'policySettings'   // 企业策略
  | 'cliArg'           // CLI 参数
  | 'session'          // 会话内临时授权

3. 工具注册表

3.1 注册架构

工具注册在 src/tools.ts,采用函数式组装模式:

getAllBaseTools()         -- 获取所有内置工具(尊重 feature flag)
    |
    v
getTools(permCtx)        -- 过滤 deny 规则 + isEnabled() 检查
    |
    v
assembleToolPool(permCtx, mcpTools)  -- 合并内置工具和 MCP 工具
    |
    v
getMergedTools(permCtx, mcpTools)    -- 简单合并(用于 token 计算)

3.2 getAllBaseTools() - 工具池

核心工具始终注册,条件工具通过 feature flag 或环境变量控制:

function getAllBaseTools(): Tools {
  return [
    // 核心工具 - 始终可用
    AgentTool, TaskOutputTool, BashTool,
    FileReadTool, FileEditTool, FileWriteTool,
    NotebookEditTool, WebFetchTool, TodoWriteTool,
    WebSearchTool, TaskStopTool, AskUserQuestionTool,
    SkillTool, EnterPlanModeTool, ExitPlanModeV2Tool, BriefTool,

    // 条件搜索工具(有嵌入搜索时不注册)
    ...(hasEmbeddedSearchTools() ? [] : [GlobTool, GrepTool]),

    // Feature-gated 工具
    ...(isWorktreeModeEnabled() ? [EnterWorktreeTool, ExitWorktreeTool] : []),
    ...(isToolSearchEnabledOptimistic() ? [ToolSearchTool] : []),
    ...(isTodoV2Enabled() ? [TaskCreateTool, TaskGetTool, ...] : []),

    // 内部/实验性工具
    ...(process.env.USER_TYPE === 'ant' ? [ConfigTool, TungstenTool] : []),
    ...(feature('KAIROS') ? [SleepTool, SendUserFileTool, ...] : []),
    ...(feature('AGENT_TRIGGERS') ? cronTools : []),

    // 仅测试
    ...(process.env.NODE_ENV === 'test' ? [TestingPermissionTool] : []),
  ]
}

3.3 工具过滤流水线

原始工具池
    |-- filterToolsByDenyRules()  过滤 blanket deny 规则
    |-- REPL 模式过滤              隐藏被 REPL 包装的原始工具
    |-- isEnabled() 检查           过滤禁用的工具
    |-- SIMPLE 模式                只保留 Bash + Read + Edit
    v
最终工具集

filterToolsByDenyRules 使用与运行时权限检查相同的匹配器,确保 MCP 服务器前缀规则(如 mcp__server)在模型看到工具之前就将其过滤掉。

3.4 assembleToolPool() - 合并与缓存

function assembleToolPool(permCtx, mcpTools): Tools {
  const builtInTools = getTools(permCtx)
  const allowedMcpTools = filterToolsByDenyRules(mcpTools, permCtx)

  // 分区排序:内置工具作为连续前缀,确保 prompt cache 稳定性
  // 服务器的 cache breakpoint 在最后一个内置工具之后
  const byName = (a, b) => a.name.localeCompare(b.name)
  return uniqBy(
    [...builtInTools].sort(byName).concat(allowedMcpTools.sort(byName)),
    'name',  // 按名称去重,内置工具优先
  )
}

3.5 工具查找

// 按名称或别名查找
function findToolByName(tools: Tools, name: string): Tool | undefined {
  return tools.find(t => toolMatchesName(t, name))
}

function toolMatchesName(tool, name): boolean {
  return tool.name === name || (tool.aliases?.includes(name) ?? false)
}

4. 工具执行流程

4.1 完整执行流程图

模型输出 tool_use block
         |
         v
  ┌──────────────────┐
  │ StreamingToolExecutor.addTool()
  │   或 toolOrchestration.runTools()
  └────────┬─────────┘
           |
           v
  ┌──────────────────┐
  │ runToolUse()      │ -- toolExecution.ts
  └────────┬─────────┘
           |
    1. 查找工具定义
    2. 检查 abort signal
           |
           v
  ┌──────────────────────────────┐
  │ checkPermissionsAndCallTool() │
  └────────┬─────────────────────┘
           |
    3. Zod schema 验证(inputSchema.safeParse)
    4. tool.validateInput() 业务验证
    5. tool.backfillObservableInput() 填充派生字段
           |
           v
  ┌──────────────────────────────┐
  │ PreToolUse Hooks             │ -- 并行执行
  │   - 可返回 allow/deny/ask    │
  │   - 可修改 input             │
  │   - 可阻止继续执行           │
  └────────┬─────────────────────┘
           |
           v
  ┌──────────────────────────────┐
  │ resolveHookPermissionDecision│
  │   Hook allow + deny/ask规则? │──> 规则优先
  │   Hook deny?                 │──> 直接拒绝
  │   Hook ask / 无决定?         │──> 正常权限流
  └────────┬─────────────────────┘
           |
           v
  ┌──────────────────────────────┐
  │ canUseTool()                 │ -- 交互式权限对话框
  │   或 checkRuleBasedPermissions│
  └────────┬─────────────────────┘
           |
     ┌─────┴─────┐
     │           │
   allow       deny
     │           │
     v           v
  ┌────────┐  返回错误消息
  │tool.call│
  └───┬────┘
      |
      v
  ┌──────────────────────────────┐
  │ PostToolUse Hooks            │
  │   - 可修改 MCP 工具输出      │
  │   - 可注入附加上下文         │
  │   - 可阻止后续执行           │
  └────────┬─────────────────────┘
      |
      v
  结果序列化 → mapToolResultToToolResultBlockParam
  结果大小检查 → processToolResultBlock(超限则持久化到磁盘)

4.2 权限决策层次

resolveHookPermissionDecision 中关键不变量:Hook 的 allow 不会绕过 settings.json 的 deny/ask 规则

async function resolveHookPermissionDecision(hookResult, tool, input, ...):
  if hookResult.behavior === 'allow':
    // deny/ask 规则仍然生效
    ruleCheck = await checkRuleBasedPermissions(tool, input, context)
    if ruleCheck === null:
      return hookResult           // 无规则阻止,hook 生效
    if ruleCheck.behavior === 'deny':
      return ruleCheck            // deny 规则覆盖 hook
    if ruleCheck.behavior === 'ask':
      return canUseTool(...)      // ask 规则要求用户确认

  if hookResult.behavior === 'deny':
    return hookResult             // hook 拒绝直接生效

  // 无 hook 决策或 'ask' → 正常权限流
  return canUseTool(...)

5. 流式工具执行

5.1 StreamingToolExecutor

StreamingToolExecutorsrc/services/tools/StreamingToolExecutor.ts)是新版执行器,支持工具在流式解析过程中立即开始执行:

class StreamingToolExecutor {
  private tools: TrackedTool[] = []
  private hasErrored = false
  private siblingAbortController: AbortController  // 兄弟工具错误时终止

  // 工具流入即加入队列
  addTool(block: ToolUseBlock, assistantMessage: AssistantMessage): void

  // 并发控制
  private canExecuteTool(isConcurrencySafe: boolean): boolean {
    const executing = this.tools.filter(t => t.status === 'executing')
    return executing.length === 0 ||
           (isConcurrencySafe && executing.every(t => t.isConcurrencySafe))
  }
}

并发策略:

  • 并发安全工具isConcurrencySafe = true):可以与其他并发安全工具并行执行
  • 非并发安全工具isConcurrencySafe = false):必须独占执行

工具状态机:queued → executing → completed → yielded

错误传播:当一个 Bash 工具出错时,siblingAbortController 会终止所有兄弟子进程,但不会终止父级 query 控制器。

5.2 toolOrchestration - 批处理模式

src/services/tools/toolOrchestration.ts 提供传统的批处理执行:

function partitionToolCalls(toolUseMessages, context): Batch[] {
  // 将工具调用分区为:
  // 1. 多个连续的并发安全工具 → 一个并发批次
  // 2. 单个非并发安全工具 → 一个串行批次
}

async function* runTools(toolUses, assistants, canUseTool, context) {
  for (const { isConcurrencySafe, blocks } of partitionToolCalls(...)) {
    if (isConcurrencySafe) {
      yield* runToolsConcurrently(blocks, ...)  // 并行,最大并发 10
    } else {
      yield* runToolsSerially(blocks, ...)      // 串行
    }
  }
}

最大并发度通过环境变量 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY 控制,默认 10。


6. 关键工具实现分析

6.1 BashTool - 命令执行

位置src/tools/BashTool/

BashTool 是最复杂的工具,包含 18 个子模块,涵盖安全、权限、沙箱等多个层面。

输入 schema

z.object({
  command: z.string(),
  timeout: z.number().optional(),
  description: z.string().optional(),
  run_in_background: z.boolean().optional(),
  dangerouslyDisableSandbox: z.boolean().optional(),
})

安全子系统

模块 职责
bashPermissions.ts 命令级权限匹配(前缀、精确、通配符规则)
bashSecurity.ts AST 解析安全检查
modeValidation.ts 权限模式验证(plan mode 下的只读约束)
pathValidation.ts 路径约束检查
readOnlyValidation.ts 只读模式下的命令验证
sedValidation.ts sed 编辑命令特殊处理
shouldUseSandbox.ts 沙箱决策逻辑
commandSemantics.ts 命令语义分析(判断命令类型)
destructiveCommandWarning.ts 危险命令警告

沙箱机制

function shouldUseSandbox(input: {command?, dangerouslyDisableSandbox?}): boolean {
  if (!SandboxManager.isSandboxingEnabled()) return false
  if (input.dangerouslyDisableSandbox && SandboxManager.areUnsandboxedCommandsAllowed())
    return false
  if (!input.command) return false
  if (containsExcludedCommand(input.command)) return false  // 用户排除列表
  return true
}

沙箱排除命令匹配支持三种模式:

  • 前缀匹配docker:* → 匹配所有 docker 开头的命令
  • 精确匹配git status → 只匹配该精确命令
  • 通配符匹配git * → 匹配 git 任意子命令

环境变量剥离(BINARY_HIJACK_VARS)和包装命令剥离(timeoutnice 等)确保 FOO=bar timeout 30 bazel run 仍能匹配 bazel:*

命令分类(用于 UI 折叠):

  • 搜索命令findgreprgagacklocatewhich
  • 读取命令catheadtailwcstatjqawkcut
  • 列表命令lstreedu
  • 语义中性命令echoprintftruefalse:(不影响管道的搜索/读取语义)

并发安全判断:BashTool 的 isConcurrencySafe 基于命令语义分析,只读命令返回 true

后台执行run_in_background: true 时命令在后台 shell 任务中执行,2 秒后显示进度提示。在 assistant 模式下,阻塞式 bash 在主 agent 中运行 15 秒后自动后台化。

6.2 FileEditTool - 差异化编辑

位置src/tools/FileEditTool/

FileEditTool 实现基于字符串替换的精确编辑模型。

输入 schema

z.object({
  file_path: z.string(),
  old_string: z.string(),   // 要替换的文本
  new_string: z.string(),   // 替换后的文本
  replace_all: z.boolean().optional().default(false),
})

验证层validateInput)执行了严格的多重检查:

  1. 团队内存秘密检查checkTeamMemSecrets 阻止向团队内存文件写入秘密
  2. 空操作检查old_string === new_string 时拒绝
  3. deny 规则检查matchingRuleForInput 匹配路径级 deny 规则
  4. UNC 路径安全:跳过 UNC 路径的文件系统操作,防止 NTLM 凭据泄露
  5. 文件大小限制:最大 1 GiB
  6. 编码检测:支持 UTF-8 和 UTF-16LE
  7. 文件存在性检查:不存在 + 空 old_string = 新文件创建
  8. Jupyter notebook 重定向.ipynb 文件引导使用 NotebookEditTool
  9. 读取时间戳校验:必须先 Read 再 Edit,且文件在 Read 后未被修改
  10. 唯一性检查:多处匹配时必须 replace_all: true 或提供更多上下文
  11. Settings 文件特殊验证:防止无效的 Claude 配置文件修改

执行流程(call)

1. 扩展路径 → expandPath()
2. 发现技能目录 → discoverSkillDirsForPaths()
3. 诊断追踪器通知 → diagnosticTracker.beforeFileEdited()
4. 确保父目录存在 + 文件历史备份
5. ─── 原子性临界区 ───
   a. 同步读取文件 → readFileSyncWithMetadata()
   b. 陈旧性检查(时间戳 + 内容比对)
   c. findActualString()(引号归一化匹配)
   d. preserveQuoteStyle()(保持弯引号风格)
   e. getPatchForEdit()(生成 patch)
   f. writeTextContent()(写入磁盘,保持编码和换行风格)
   ─── 临界区结束 ───
6. LSP 通知 → didChange + didSave
7. VSCode 通知 → diff view
8. 更新 readFileState 时间戳(使后续写入的陈旧性检查生效)
9. 分析日志

关键设计:临界区内避免异步操作,防止并发编辑交错。

6.3 AgentTool - 子 agent 生成

位置src/tools/AgentTool/,包含 20+ 子模块。

AgentTool 是 Claude Code 多 agent 架构的核心,支持多种子 agent 模式。

输入 schema

z.object({
  description: z.string(),           // 3-5 词任务描述
  prompt: z.string(),                // 任务详细提示
  subagent_type: z.string().optional(),  // 专用 agent 类型
  model: z.enum(['sonnet', 'opus', 'haiku']).optional(),  // 模型覆盖
  run_in_background: z.boolean().optional(),  // 后台运行
  // 多 agent 参数
  name: z.string().optional(),       // agent 名称(可通过 SendMessage 寻址)
  team_name: z.string().optional(),  // 团队名称
  mode: PermissionMode.optional(),   // 权限模式
  isolation: z.enum(['worktree', 'remote']).optional(),  // 隔离模式
  cwd: z.string().optional(),        // 工作目录覆盖
})

内置 Agent 类型

Agent 文件 用途
general_purpose generalPurposeAgent.ts 通用子 agent(默认)
explore exploreAgent.ts 代码探索
plan planAgent.ts 规划 agent
verification verificationAgent.ts 验证 agent
claude_code_guide claudeCodeGuideAgent.ts Claude Code 使用指南

隔离模式

  • worktree:创建临时 git worktree,agent 在隔离的仓库副本上工作
  • remote(仅内部):在远程 CCR 环境中启动 agent

执行分支

AgentTool.call()
    |
    ├── fork subagent (feature gate)
    │     └── buildForkedMessages() → 共享父级消息上下文
    │
    ├── 同步执行
    │     └── runAgent() → query() → 返回完整结果
    │
    ├── 后台执行 (run_in_background: true)
    │     └── registerAsyncAgent() → runAsyncAgentLifecycle()
    │           → 完成后通知主线程
    │
    └── 远程执行 (isolation: 'remote')
          └── teleportToRemote() → registerRemoteAgentTask()

子 agent 工具限制constants/tools.ts):

// 所有 agent 禁止的工具
ALL_AGENT_DISALLOWED_TOOLS = {
  TaskOutputTool, ExitPlanModeTool, EnterPlanModeTool,
  AgentTool (非内部用户), AskUserQuestionTool, TaskStopTool,
  WorkflowTool
}

// 异步 agent 允许的工具白名单
ASYNC_AGENT_ALLOWED_TOOLS = {
  FileReadTool, WebSearchTool, TodoWriteTool, GrepTool, GlobTool,
  BashTool, FileEditTool, FileWriteTool, NotebookEditTool,
  SkillTool, ToolSearchTool, EnterWorktreeTool, ExitWorktreeTool
}

// Coordinator 模式仅允许的工具
COORDINATOR_MODE_ALLOWED_TOOLS = {
  AgentTool, TaskStopTool, SendMessageTool, SyntheticOutputTool
}

runAgent 核心流程runAgent.ts):

1. 创建子 agent 上下文 → createSubagentContext()
2. 组装工具池 → assembleToolPool()(含 MCP 工具)
3. 注册 frontmatter hooks
4. 构建系统提示 → getSystemPrompt() + enhanceSystemPromptWithEnvDetails()
5. 执行 query loop → query()(与主循环相同的 API 调用)
6. 记录 sidechain transcript
7. 清理:kill shell tasks、清理 hooks

6.4 MCPTool - 外部工具桥接

位置src/tools/MCPTool/

MCPTool 是 MCP (Model Context Protocol) 工具的桥接层。其独特之处在于 MCPTool.ts 定义的是一个模板对象,实际字段在 mcpClient.ts 中被运行时覆盖。

模板定义

const MCPTool = buildTool({
  isMcp: true,
  name: 'mcp',                // 运行时覆盖为 mcp__server__tool
  maxResultSizeChars: 100_000,

  // 以下方法全部在 mcpClient.ts 中被覆盖
  async description() { return DESCRIPTION },
  async prompt() { return PROMPT },
  async call() { return { data: '' } },
  userFacingName: () => 'mcp',

  // 权限采用 passthrough 模式
  async checkPermissions(): Promise<PermissionResult> {
    return { behavior: 'passthrough', message: 'MCPTool requires permission.' }
  },
})

MCP 工具注册流程

MCP 服务器连接 → fetchToolsForClient()
    |
    v
为每个远程工具创建 MCPTool 的克隆
    |-- name: mcp__<serverName>__<toolName>(归一化)
    |-- description: 从 MCP 服务器获取
    |-- inputJSONSchema: 从 MCP 服务器获取
    |-- call: 代理到 MCP 客户端的 callTool
    |-- mcpInfo: { serverName, toolName }
    v
注入 appState.mcp.tools → assembleToolPool 合并

权限特殊处理:MCPTool 返回 behavior: 'passthrough',意味着不做 tool-specific 权限判断,完全交给通用权限系统处理。

UI 折叠classifyForCollapse.ts):根据 MCP 工具的语义对 UI 显示进行分类折叠。


7. 工具权限模型

7.1 权限决策流水线

           ┌─────────────────────────────┐
           │ 1. Zod Schema 验证           │ -- 输入格式检查
           └────────────┬────────────────┘
                        │ 通过
           ┌────────────v────────────────┐
           │ 2. tool.validateInput()      │ -- 业务逻辑验证
           └────────────┬────────────────┘
                        │ 通过
           ┌────────────v────────────────┐
           │ 3. PreToolUse Hooks          │ -- 可 allow/deny/ask
           └────────────┬────────────────┘
                        │
           ┌────────────v────────────────┐
           │ 4. tool.checkPermissions()   │ -- 工具特定权限
           │    (BashTool: 多层检查)      │
           │    (FileEdit: 路径检查)      │
           │    (MCPTool: passthrough)    │
           └────────────┬────────────────┘
                        │
           ┌────────────v────────────────┐
           │ 5. checkRuleBasedPermissions  │ -- settings.json 规则
           │    alwaysAllow > alwaysDeny   │
           │    > alwaysAsk 规则匹配       │
           └────────────┬────────────────┘
                        │ 无规则匹配
           ┌────────────v────────────────┐
           │ 6. 权限模式决策              │
           │  default → 询问用户          │
           │  acceptEdits → 编辑自动通过  │
           │  bypassPermissions → 全通过  │
           │  dontAsk → 拒绝             │
           │  plan → 仅只读工具通过       │
           │  auto → 分类器判断           │
           └─────────────────────────────┘

7.2 BashTool 特殊权限层

BashTool 的权限检查是最复杂的,涉及多个子系统:

// bashPermissions.ts 中的权限匹配
type ShellPermissionRule =
  | { type: 'prefix'; prefix: string }     // "git:*" → 匹配 git 开头的命令
  | { type: 'exact'; command: string }      // "git status" → 精确匹配
  | { type: 'wildcard'; pattern: string }   // "git *" → 通配符匹配

BashTool 权限检查顺序:

  1. 权限模式检查(checkPermissionMode
  2. 路径约束检查(checkPathConstraints
  3. 只读约束检查(checkReadOnlyConstraints
  4. sed 编辑约束检查(checkSedConstraints
  5. 命令级权限规则匹配
  6. AST 安全分析(parseForSecurity
  7. 分类器检查(auto 模式下的推测性并行检查)

7.3 规则匹配示例

// settings.json 中的权限配置
{
  "permissions": {
    "allow": [
      "Bash(git *)",           // 允许所有 git 命令
      "Bash(npm test)",        // 允许 npm test
      "Edit(src/**/*.ts)",     // 允许编辑 src 下的 TypeScript 文件
      "mcp__memory"            // 允许 memory MCP 服务器的所有工具
    ],
    "deny": [
      "Bash(rm -rf *)",        // 禁止危险删除
      "mcp__dangerous_server"  // 禁止整个 MCP 服务器
    ]
  }
}

7.4 权限结果类型

type PermissionResult =
  | { behavior: 'allow'; updatedInput?: Record<string, unknown>; decisionReason?: ... }
  | { behavior: 'deny'; message: string; decisionReason?: ... }
  | { behavior: 'ask'; message?: string; updatedInput?: ...; forceDecision?: ... }
  | { behavior: 'passthrough'; message: string }  // MCP 工具使用

权限决策来源追踪(用于遥测):

type PermissionDecisionReason =
  | { type: 'rule'; rule: PermissionRule; source: string }
  | { type: 'hook'; hookName: string; hookSource?: string }
  | { type: 'mode'; mode: PermissionMode }
  | { type: 'classifier'; ... }
  | { type: 'permissionPromptTool'; toolResult?: unknown }
  | { type: 'sandboxOverride' }
  | { type: 'workingDir' }
  | { type: 'safetyCheck' }
  | { type: 'other' }

8. 完整工具清单

8.1 核心工具

工具名称 文件 并发安全 只读 说明
Bash BashTool/ 视命令 视命令 Shell 命令执行,支持沙箱
Edit FileEditTool/ 字符串替换式文件编辑
Read FileReadTool/ 文件读取(含图片、PDF、Notebook)
Write FileWriteTool/ 完整文件写入
Glob GlobTool/ 文件模式匹配搜索
Grep GrepTool/ 基于 ripgrep 的内容搜索
NotebookEdit NotebookEditTool/ Jupyter Notebook 编辑
WebFetch WebFetchTool/ URL 内容获取与摘要
WebSearch WebSearchTool/ 网络搜索
Agent AgentTool/ 子 agent 生成(同步/异步/远程)
TaskOutput TaskOutputTool/ - - 异步任务输出
TaskStop TaskStopTool/ - - 终止后台任务
AskUserQuestion AskUserQuestionTool/ - - 向用户提问
TodoWrite TodoWriteTool/ 待办事项管理
Skill SkillTool/ - 技能调用
Brief BriefTool/ - - 简报生成
SendMessage SendMessageTool/ - - 向其他 agent 发送消息
ToolSearch ToolSearchTool/ 延迟工具发现

8.2 Plan Mode 工具

工具名称 文件 说明
EnterPlanMode EnterPlanModeTool/ 进入 plan 模式
ExitPlanModeV2 ExitPlanModeTool/ 退出 plan 模式

8.3 Worktree 工具

工具名称 文件 说明
EnterWorktree EnterWorktreeTool/ 创建并进入 git worktree
ExitWorktree ExitWorktreeTool/ 退出并可选删除 worktree

8.4 Task 管理工具(Todo V2)

工具名称 文件 说明
TaskCreate TaskCreateTool/ 创建任务
TaskGet TaskGetTool/ 获取任务详情
TaskUpdate TaskUpdateTool/ 更新任务状态
TaskList TaskListTool/ 列出任务

8.5 MCP 相关工具

工具名称 文件 说明
mcp__* MCPTool/ MCP 工具桥接(动态注册)
ListMcpResources ListMcpResourcesTool/ 列出 MCP 资源
ReadMcpResource ReadMcpResourceTool/ 读取 MCP 资源

8.6 多 Agent 协作工具

工具名称 文件 说明
TeamCreate TeamCreateTool/ 创建 agent 团队
TeamDelete TeamDeleteTool/ 删除 agent 团队
ListPeers ListPeersTool/ 列出对等 agent

8.7 条件/Feature-Gated 工具

工具名称 Feature Gate 说明
Config USER_TYPE=ant 配置管理
Tungsten USER_TYPE=ant 虚拟终端
REPL USER_TYPE=ant REPL 模式(包装原始工具)
PowerShell Windows Windows PowerShell 执行
LSP ENABLE_LSP_TOOL 语言服务器协议工具
Sleep PROACTIVE/KAIROS 等待工具
CronCreate/Delete/List AGENT_TRIGGERS 定时任务管理
RemoteTrigger AGENT_TRIGGERS_REMOTE 远程触发器
Monitor MONITOR_TOOL 监控工具
WebBrowser WEB_BROWSER_TOOL 浏览器自动化
Snip HISTORY_SNIP 历史修剪
Workflow WORKFLOW_SCRIPTS 工作流脚本
SuggestBackgroundPR USER_TYPE=ant 后台 PR 建议
SendUserFile KAIROS 发送文件给用户
PushNotification KAIROS 推送通知
SubscribePR KAIROS_GITHUB_WEBHOOKS PR 订阅
CtxInspect CONTEXT_COLLAPSE 上下文检查
TerminalCapture TERMINAL_PANEL 终端面板捕获
OverflowTest OVERFLOW_TEST_TOOL 溢出测试

8.8 特殊工具

工具名称 说明
SyntheticOutput 合成输出(不在常规工具池中)
VerifyPlanExecution 计划执行验证(CLAUDE_CODE_VERIFY_PLAN=true
TestingPermission 测试专用权限工具(NODE_ENV=test
McpAuth MCP 认证工具

9. 架构要点总结

  1. Fail-Closed 安全设计buildTool 默认值假设工具不安全(非并发、可写),只有显式标记为安全的工具才能获得并发执行和跳过权限检查。

  2. 多层权限纵深防御:Zod 验证 → 业务验证 → PreToolUse hooks → 工具特定权限 → 规则匹配 → 模式决策 → 用户确认。Hook 的 allow 不会绕过 deny/ask 规则。

  3. 不可变权限上下文ToolPermissionContext 使用 DeepImmutable 确保权限状态在传播过程中不被意外修改。

  4. 流式执行优化StreamingToolExecutor 支持工具在 API 响应流式解析时就开始执行,减少端到端延迟。兄弟工具错误通过独立的 siblingAbortController 传播,不影响 query 级别的 abort。

  5. MCP 桥接模式:MCPTool 使用模板对象 + 运行时属性覆盖,将外部 MCP 工具无缝集成到内部工具系统,共享权限和执行基础设施。

  6. 子 agent 工具隔离:通过 ALL_AGENT_DISALLOWED_TOOLSASYNC_AGENT_ALLOWED_TOOLSCOORDINATOR_MODE_ALLOWED_TOOLS 三个集合精确控制不同 agent 角色可用的工具,防止递归和权限逃逸。

  7. Prompt Cache 稳定性assembleToolPool 通过分区排序(内置工具作为连续前缀)确保工具顺序不受 MCP 工具注册时序影响,维护 API prompt cache 的命中率。