乐于分享
好东西不私藏

Claude Code 源码深度解析(上):1902 个文件背后的架构哲学

Claude Code 源码深度解析(上):1902 个文件背后的架构哲学

本文基于 Claude Code TypeScript 源码结构快照进行逐模块深度分析。我们不浮于表面,而是深入每个关键文件,理解其设计意图和实现细节。

整体架构图

一、项目规模:超出你想象的工程量

先看一组数字:

       

         
           
           
         

维度 数量
TypeScript/TSX 文件 1,902
顶层子系统 35
命令模块 207
工具模块 184
UI 组件 389
服务模块 130
React Hooks 104
Bridge 模块 31
内置技能 16
CLI 传输协议 4 种

       

     

这不是一个 CLI 工具,而是一个完整的 Agent 操作系统。

二、35 个子系统全览

源码快照记录了完整的顶层目录结构:

src/
├── entrypoints/          (8)    入口层:CLI、SDK、MCP、沙箱
├── components/           (389)  渲染层:389 个 React Ink 终端组件
├── screens/              (3)    页面:REPL、Doctor、ResumeConversation
├── state/                (6)    状态层:AppState 全局状态管理
├── services/             (130)  服务层:API、记忆、分析、提示建议
├── bridge/               (31)   桥接层:IDE/远程连接
├── remote/               (4)    远程层:WebSocket、权限桥接
├── cli/                  (19)   CLI层:多传输协议
├── hooks/                (104)  钩子系统:权限回调、通知
├── commands/             (207+) 命令系统:斜杠命令
├── tools/                (184+) 工具系统:Agent 能力单元
├── memdir/               (8)    记忆系统:文件级记忆
├── skills/               (20)   技能系统:内置技能+MCP构建器
├── plugins/              (2)    插件系统
├── constants/            (21)   常量定义
├── types/                (11)   类型系统
├── vim/                  (5)    Vim 模式
├── voice/                (1)    语音模式
├── buddy/                (6)    向导陪伴系统
├── coordinator/          (1)    协调模式
├── bootstrap/            (1)    启动引导
├── moreright/            (1)    右侧面板扩展
├── migrations/           (-)    数据迁移
├── outputStyles/         (1)    输出样式
├── upstreamproxy/        (2)    上游代理
├── native-ts/            (4)    原生模块绑定
├── keybindings/          (-)    键绑定
├── schemas/              (1)    Schema 定义
├── assistant/            (1)    助手会话历史
├── server/               (3)    直接连接服务
├── context/              (-)    上下文管理
├── ink/                  (-)    Ink 渲染辅助
├── query/                (-)    查询引擎辅助
├── tasks/                (-)    任务系统辅助
├── utils/                (-)    工具函数

加粗的根级文件(18 个)也是核心模块:

src/
├── QueryEngine.ts             # 核心:Agent 执行引擎
├── Task.ts                    # 任务结构定义
├── Tool.ts                    # 工具基础类型
├── commands.ts                # 命令注册
├── context.ts                 # 上下文构建
├── cost-tracker.ts            # 成本追踪
├── costHook.ts                # 成本钩子
├── dialogLaunchers.tsx        # 对话启动器
├── history.ts                 # 会话历史
├── ink.ts                     # Ink 渲染辅助
├── interactiveHelpers.tsx     # 交互辅助
├── main.tsx                   # 主入口
├── projectOnboardingState.ts  # 项目引导状态
├── query.ts                   # 查询请求/响应
├── replLauncher.tsx           # REPL 启动器
├── setup.ts                   # 环境初始化
├── tasks.ts                   # 任务列表
└── tools.ts                   # 工具注册

2.2 分层架构全景

三层架构通信图

设计背景:为什么分成这么多层?

Claude Code 的分层架构遵循一个核心原则——关注点分离。每一层只做一件事:

  • 入口层决定”怎么启动”(CLI、SDK、MCP 三种入口对应三种使用方式)
  • 渲染层决定”怎么显示”(389 个组件确保终端 UI 的精致体验)
  • 引擎层决定”怎么执行”(QueryEngine 是纯逻辑,不关心显示和存储)
  • 工具层决定”能做什么”(184 个工具是 Agent 的能力边界)
  • 服务层决定”怎么通信”(API、分析、记忆都是基础设施)

这种分层让团队可以并行开发——UI 团队改组件、工具团队加工具、引擎团队优化循环,互不干扰。

三、核心引擎 QueryEngine:Agent 的心脏

3.1 配置体系

QueryEngine 是整个系统的心脏,通过 QueryEngineConfig 控制行为:

# query_engine.py — 核心配置
@dataclass(frozen=True)

class
 QueryEngineConfig:
    max_turns: int = 8              # 最大对话轮次
    max_budget_tokens: int = 2000   # Token 预算上限
    compact_after_turns: int = 12   # 消息压缩阈值
    structured_output: bool = False # 结构化输出(JSON)
    structured_retry_limit: int = 2 # 结构化重试次数

对应原始 TypeScript 的 QueryEngine.ts,这些参数控制着 Agent 的”生命体征”:

  • 8 轮上限 — 防止 Agent 陷入无限循环
  • 2000 Token 预算 — 防止 Token 消耗失控
  • 12 轮压缩 — 超过 12 轮对话自动裁剪上下文

3.2 Turn Loop 完整执行流程

Turn Loop 执行流程图

设计背景:为什么采用 Turn Loop 而非单次请求?

传统 LLM 应用采用”一问一答”模式,但 AI Agent 需要连续执行多个步骤(读文件→理解代码→修改→验证),才能完成一个任务。Turn Loop 让 Agent 能在单次用户输入中连续执行多轮工具调用。max_turns 和 max_budget 是防止 Agent 陷入无限循环的安全阀——这是 Agent 系统必须具备的基础保障。

3.3 TurnResult — 每个 Turn 的完整结果

@dataclass(frozen=True)
class
 TurnResult:
    prompt: str                                    # 用户输入
    output: str                                    # Agent 输出
    matched_commands: tuple[str, ...]              # 匹配的命令
    matched_tools: tuple[str, ...]                 # 匹配的工具
    permission_denials: tuple[PermissionDenial, ...] # 权限拒绝
    usage: UsageSummary                            # Token 用量
    stop_reason: str                               # 停止原因

每个 Turn 的结果包含 7 个维度的信息。stop_reason 有三种值:

  • completed — 正常完成
  • max_turns_reached — 达到最大轮次
  • max_budget_reached — 超出预算

3.3 流式事件系统

def stream_submit_message(self, prompt, matched_commands, matched_tools, denied_tools):
    yield
 {'type': 'message_start', 'session_id': self.session_id, 'prompt': prompt}
    if
 matched_commands:
        yield
 {'type': 'command_match', 'commands': matched_commands}
    if
 matched_tools:
        yield
 {'type': 'tool_match', 'tools': matched_tools}
    if
 denied_tools:
        yield
 {'type': 'permission_denial', 'denials': [...]}
    result = self.submit_message(prompt, ...)
    yield
 {'type': 'message_delta', 'text': result.output}
    yield
 {
        'type'
: 'message_stop',
        'usage'
: {'input_tokens': ..., 'output_tokens': ...},
        'stop_reason'
: result.stop_reason,
        'transcript_size'
: len(self.transcript_store.entries),
    }

这是一个完整的 SSE 风格事件流。注意事件是有序的:message_startcommand_match/tool_matchpermission_denialmessage_deltamessage_stop。UI 层可以据此实现实时渲染。

3.4 消息压缩算法

def compact_messages_if_needed(self) -> None:
    if
 len(self.mutable_messages) > self.config.compact_after_turns:
        # 只保留最近 N 条消息

        self
.mutable_messages[:] = self.mutable_messages[-self.config.compact_after_turns:]
    # 转录记录同步压缩

    self
.transcript_store.compact(self.config.compact_after_turns)

这是滑动窗口算法——保留最近的 12 轮对话,丢弃更早的。这在 LLM 上下文窗口有限的情况下至关重要。

3.5 会话持久化

# session_store.py
@dataclass(frozen=True)

class
 StoredSession:
    session_id: str           # 会话唯一 ID
    messages: tuple[str, ...] # 所有消息记录
    input_tokens: int         # 输入 Token 累计
    output_tokens: int        # 输出 Token 累计

def
 save_session(session, directory=None):
    target_dir = directory or DEFAULT_SESSION_DIR  # .port_sessions/
    target_dir.mkdir(parents=True, exist_ok=True)
    path = target_dir / f'{session.session_id}.json'
    path.write_text(json.dumps(asdict(session), indent=2))
    return
 path

会话以 JSON 文件形式存储在 .port_sessions/{session_id}.json,包含完整的消息历史和 Token 统计。支持通过 from_saved_session() 恢复。

3.6 TranscriptStore — 转录管理器

# transcript.py
@dataclass

class
 TranscriptStore:
    entries: list[str] = field(default_factory=list)
    flushed: bool = False

    def
 append(self, entry: str):
        self
.entries.append(entry)
        self
.flushed = False

    def
 compact(self, keep_last: int = 10):
        if
 len(self.entries) > keep_last:
            self
.entries[:] = self.entries[-keep_last:]

    def
 replay(self) -> tuple[str, ...]:
        return
 tuple(self.entries)

    def
 flush(self):
        self
.flushed = True

TranscriptStore 是一个独立的转录记录器,与 mutable_messages 并行存在。它支持:

  • append — 追加记录
  • compact — 滑动窗口压缩
  • replay — 回放所有记录
  • flush — 标记已刷入磁盘

flushed 标志是一个简单但重要的设计——用于判断是否有未持久化的数据。

四、启动流程:从 main.tsx 到 Agent 就绪

4.1 Setup 阶段

# setup.py — 环境初始化
@dataclass(frozen=True)

class
 WorkspaceSetup:
    python_version: str       # 运行时版本
    implementation: str       # 实现类型(CPython/PyPy)
    platform_name: str        # 平台信息
    test_command: str         # 测试命令

    def
 startup_steps(self) -> tuple[str, ...]:
        return
 (
            'start top-level prefetch side effects'
,  # 预取副作用
            'build workspace context'
,                 # 构建工作上下文
            'load mirrored command snapshot'
,           # 加载命令快照
            'load mirrored tool snapshot'
,              # 加载工具快照
            'prepare parity audit hooks'
,               # 准备审计钩子
            'apply trust-gated deferred init'
,          # 信任门控延迟初始化
        )

启动分为 6 个步骤,按顺序执行。最值得关注的是信任门控延迟初始化

4.2 Prefetch 预取系统

# prefetch.py — 并行预取
@dataclass(frozen=True)

class
 PrefetchResult:
    name: str
    started: bool
    detail: str

def
 start_mdm_raw_read():       # MDM 原始数据预读
def
 start_keychain_prefetch():   # 密钥链预取
def
 start_project_scan(root):    # 项目扫描

三个预取任务在启动时并行执行:

  • mdm_raw_read — 预读 MDM(移动设备管理)原始数据
  • keychain_prefetch — 预取密钥链凭证(避免后续阻塞)
  • project_scan — 扫描项目结构(为上下文构建做准备)

4.3 延迟初始化(Deferred Init)

# deferred_init.py
@dataclass(frozen=True)

class
 DeferredInitResult:
    trusted: bool         # 是否在信任模式下
    plugin_init: bool     # 插件初始化
    skill_init: bool      # 技能初始化
    mcp_prefetch: bool    # MCP 预取
    session_hooks: bool   # 会话钩子

def
 run_deferred_init(trusted: bool) -> DeferredInitResult:
    enabled = bool(trusted)  # 只有信任模式下才启用
    return
 DeferredInitResult(
        trusted=trusted,
        plugin_init=enabled,
        skill_init=enabled,
        mcp_prefetch=enabled,
        session_hooks=enabled,
    )

关键设计:插件、技能、MCP、会话钩子的初始化都受信任模式控制。在非信任环境下,这些都会被跳过——这是一个安全措施。

4.4 System Init 消息

# system_init.py
def
 build_system_init_message(trusted=True):
    setup = run_setup(trusted)
    commands = get_commands()
    tools = get_tools()
    return
 f"""
    # System Init
    Trusted: {setup.trusted}
    Built-in commands: {len(built_in_command_names())}
    Loaded commands: {len(commands)}
    Loaded tools: {len(tools)}
    Startup steps: {setup.setup.startup_steps()}
    """

System Init 消息是注入给 LLM 的系统提示的一部分——告诉模型当前有多少命令和工具可用。

五、Runtime 系统:Agent 的完整生命周期

5.1 RoutedMatch — 智能路由

# runtime.py
@dataclass(frozen=True)

class
 RoutedMatch:
    kind: str          # 'command' 或 'tool'
    name: str          # 模块名称
    source_hint: str   # 源文件路径
    score: int         # 匹配分数

路由系统将用户输入匹配到具体的命令和工具。评分算法基于 token 匹配:

@staticmethod
def
 _score(tokens: set[str], module: PortingModule) -> int:
    haystacks = [
        module.name.lower(),
        module.source_hint.lower(),
        module.responsibility.lower()
    ]
    score = 0
    for
 token in tokens:
        if
 any(token in haystack for haystack in haystacks):
            score += 1
    return
 score

这是一个简单但有效的 TF 匹配——用户输入的每个词如果在模块名称、源路径或职责描述中出现,就加 1 分。

5.2 路由策略

def route_prompt(self, prompt: str, limit: int = 5) -> list[RoutedMatch]:
    tokens = {token.lower() for token in prompt.replace('/', ' ').replace('-', ' ').split() if token}

    by_kind = {
        'command'
: self._collect_matches(tokens, PORTED_COMMANDS, 'command'),
        'tool'
: self._collect_matches(tokens, PORTED_TOOLS, 'tool'),
    }

    selected = []
    # 每种类型取最高分的一个

    for
 kind in ('command', 'tool'):
        if
 by_kind[kind]:
            selected.append(by_kind[kind].pop(0))

    # 剩余按分数排序补充

    leftovers = sorted(
        [match for matches in by_kind.values() for match in matches],
        key=lambda item: (-item.score, item.kind, item.name),
    )
    selected.extend(leftovers[:max(0, limit - len(selected))])
    return
 selected[:limit]

路由策略很有讲究:

  1. 1. 先分命令和工具两组
  2. 2. 每组取最高分的一个(保证类型多样性)
  3. 3. 剩余按分数降序补充到 limit

5.3 Turn Loop — 多轮执行

def run_turn_loop(self, prompt, limit=5, max_turns=3, structured_output=False):
    engine = QueryEnginePort.from_workspace()
    engine.config = QueryEngineConfig(
        max_turns=max_turns,
        structured_output=structured_output
    )
    matches = self.route_prompt(prompt, limit)
    command_names = tuple(m.name for m in matches if m.kind == 'command')
    tool_names = tuple(m.name for m in matches if m.kind == 'tool')

    results = []
    for
 turn in range(max_turns):
        turn_prompt = prompt if turn == 0 else f'{prompt} [turn {turn + 1}]'
        result = engine.submit_message(turn_prompt, command_names, tool_names, ())
        results.append(result)
        if
 result.stop_reason != 'completed':
            break
  # 非正常停止就退出循环
    return
 results

run_turn_loop 是外部可调用的多轮执行接口。注意第 2 轮开始 prompt 会附加 [turn N] 标记——这帮助 LLM 理解当前是第几轮执行。

5.4 完整的 RuntimeSession

@dataclass
class
 RuntimeSession:
    prompt: str                              # 原始输入
    context: PortContext                     # 工作上下文
    setup: WorkspaceSetup                    # 环境信息
    setup_report: SetupReport                # 启动报告
    system_init_message: str                 # 系统初始化消息
    history: HistoryLog                      # 会话历史
    routed_matches: list[RoutedMatch]        # 路由匹配结果
    turn_result: TurnResult                  # Turn 结果
    command_execution_messages: tuple[str, ...]  # 命令执行结果
    tool_execution_messages: tuple[str, ...]     # 工具执行结果
    stream_events: tuple[dict, ...]          # 流式事件
    persisted_session_path: str              # 持久化路径

一个完整的 RuntimeSession 包含 13 个维度 的信息——从环境配置到执行结果到持久化路径,确保整个执行过程可审计、可恢复。

六、工具系统:184 个工具模块详解

模块关联图

设计背景:为什么是 184 个工具而不是一个大工具?

Claude Code 选择了”小工具、多职责”的微工具架构,而非将所有能力塞进一个”万能工具”。这种设计有三个关键优势:

  1. 1. LLM 精度更高 — 工具描述越精准,LLM 越容易选对工具。BashTool 和 FileEditTool 的 Prompt 差异巨大,模型能精确选择
  2. 2. 权限控制更细 — 可以单独授权/拒绝每个工具,而非一刀切
  3. 3. 可测试性强 — 每个工具独立测试,互不影响

这是 Anthropic 在 Agent 工程实践中的重要设计决策——工具粒度决定了 Agent 的能力上限。

6.1 工具注册与发现

# tools.py — 工具注册
@lru_cache(maxsize=1)

def
 load_tool_snapshot() -> tuple[PortingModule, ...]:
    raw_entries = json.loads(SNAPSHOT_PATH.read_text())
    return
 tuple(
        PortingModule(
            name=entry['name'],
            responsibility=entry['responsibility'],
            source_hint=entry['source_hint'],
            status='mirrored',
        )
        for
 entry in raw_entries
    )

PORTED_TOOLS = load_tool_snapshot()

工具从 JSON 快照加载,使用 lru_cache 缓存——确保只加载一次。每个工具模块记录了:

  • name — 工具名称
  • source_hint — 原始 TS 文件路径
  • responsibility — 职责描述
  • status — 状态(mirrored = 已映射)

6.2 工具池动态组装

# tool_pool.py
@dataclass(frozen=True)

class
 ToolPool:
    tools: tuple[PortingModule, ...]
    simple_mode: bool     # 简单模式(只有3个基础工具)
    include_mcp: bool     # 是否包含 MCP 工具

def
 assemble_tool_pool(simple_mode=False, include_mcp=True, permission_context=None):
    return
 ToolPool(
        tools=get_tools(simple_mode, include_mcp, permission_context),
        simple_mode=simple_mode,
        include_mcp=include_mcp,
    )

工具池在运行时动态组装——根据模式(simple/full)、是否包含 MCP、权限上下文三个维度过滤。

6.3 工具过滤策略

def get_tools(simple_mode=False, include_mcp=True, permission_context=None):
    tools = list(PORTED_TOOLS)

    # 简单模式:只保留 3 个基础工具

    if
 simple_mode:
        tools = [t for t in tools if t.name in {
            'BashTool'
, 'FileReadTool', 'FileEditTool'
        }]

    # 排除 MCP 工具

    if
 not include_mcp:
        tools = [t for t in tools
                 if
 'mcp' not in t.name.lower()
                 and
 'mcp' not in t.source_hint.lower()]

    # 权限过滤

    return
 filter_tools_by_permission_context(tuple(tools), permission_context)

三层过滤的设计精妙之处:

  1. 1. 简单模式 — 新手安全区,只有读写和执行三个工具
  2. 2. MCP 过滤 — 在不信任外部工具时关闭
  3. 3. 权限上下文 — 最精细的控制,可以按名称或前缀拒绝特定工具

6.4 ExecutionRegistry — 执行注册表

# execution_registry.py
@dataclass(frozen=True)

class
 MirroredCommand:
    name: str
    source_hint: str
    def
 execute(self, prompt: str) -> str:
        return
 execute_command(self.name, prompt).message

@dataclass(frozen=True)

class
 MirroredTool:
    name: str
    source_hint: str
    def
 execute(self, payload: str) -> str:
        return
 execute_tool(self.name, payload).message

@dataclass(frozen=True)

class
 ExecutionRegistry:
    commands: tuple[MirroredCommand, ...]
    tools: tuple[MirroredTool, ...]

    def
 command(self, name: str) -> MirroredCommand | None:
        lowered = name.lower()
        for
 cmd in self.commands:
            if
 cmd.name.lower() == lowered:
                return
 cmd
        return
 None

    def
 tool(self, name: str) -> MirroredTool | None:
        lowered = name.lower()
        for
 t in self.tools:
            if
 t.name.lower() == lowered:
                return
 t
        return
 None

ExecutionRegistry 是命令和工具的统一执行注册表——名字查找是大小写不敏感的,这是一个小但重要的用户体验优化。

6.5 工具目录结构全景

源码快照揭示了每个工具的完整文件组织。以最复杂的 BashTool 为例:

tools/BashTool/
├── BashTool.tsx                    # 主执行逻辑
├── BashToolResultMessage.tsx       # 结果消息 UI 渲染
├── UI.tsx                          # 工具 UI 组件
├── bashCommandHelpers.ts           # 命令辅助函数
├── bashPermissions.ts              # 权限检查
├── bashSecurity.ts                 # 安全审计(最关键)
├── commandSemantics.ts             # 命令语义解析
├── commentLabel.ts                 # 命令注释标签
├── destructiveCommandWarning.ts    # 危险命令预警
├── modeValidation.ts               # 执行模式校验
├── pathValidation.ts               # 路径安全校验
├── prompt.ts                       # 工具的 System Prompt
├── readOnlyValidation.ts           # 只读模式校验
├── sedEditParser.ts                # sed 编辑解析器
├── sedValidation.ts                # sed 命令校验
├── shouldUseSandbox.ts             # 沙箱自动判定
├── toolName.ts                     # 工具名称常量
└── utils.ts                        # 工具函数

18 个文件实现一个 Bash 工具!其中安全相关的就有 5 个(bashSecurity、destructiveCommandWarning、pathValidation、readOnlyValidation、shouldUseSandbox)。

6.6 其他工具的文件组织

AgentTool(14 个文件)— 多 Agent 核心:

tools/AgentTool/
├── AgentTool.tsx             # 入口
├── UI.tsx                    # 显示
├── agentColorManager.ts      # Agent 颜色标识
├── agentDisplay.ts           # 状态显示
├── agentMemory.ts            # Agent 记忆
├── agentMemorySnapshot.ts    # 记忆快照
├── agentToolUtils.ts         # 工具辅助
├── builtInAgents.ts          # 内置 Agent 注册
├── constants.ts              # 常量
├── forkSubagent.ts           # 子 Agent 派生
├── loadAgentsDir.ts          # 自定义 Agent 目录加载
├── prompt.ts                 # 系统 Prompt
├── resumeAgent.ts            # 恢复暂停的 Agent
└── runAgent.ts               # Agent 执行
    └── built-in/             # 内置 Agent 实现
        ├── claudeCodeGuideAgent.ts   # 使用指南 Agent
        ├── exploreAgent.ts           # 探索 Agent
        ├── generalPurposeAgent.ts    # 通用 Agent
        ├── planAgent.ts              # 规划 Agent
        ├── statuslineSetup.ts        # 状态栏设置
        └── verificationAgent.ts      # 验证 Agent

LSPTool(5 个文件)— 代码语义:

tools/LSPTool/
├── LSPTool.ts          # LSP 工具入口
├── UI.tsx              # UI
├── formatters.ts       # 输出格式化
├── prompt.ts           # Prompt
├── schemas.ts          # 请求 Schema
└── symbolContext.ts    # 符号上下文提取

FileEditTool(6 个文件)— 精确编辑:

tools/FileEditTool/
├── FileEditTool.ts     # 编辑逻辑
├── UI.tsx              # 编辑 UI
├── constants.ts        # 常量
├── prompt.ts           # Prompt
├── types.ts            # 编辑操作类型
└── utils.ts            # 编辑算法

6.7 共享工具

tools/shared/
├── gitOperationTracking.ts   # Git 操作追踪
└── spawnMultiAgent.ts        # 多 Agent 并发派生

spawnMultiAgent 是多 Agent 并发的核心——不在任何单个工具内部,而是放在 shared/ 目录下,供所有工具共享。

6.8 任务工具链(6 个工具)

tools/TaskCreateTool/   → 创建任务(目标 + Agent 分配)
tools/TaskGetTool/      → 获取任务详情
tools/TaskListTool/     → 列出所有任务
tools/TaskUpdateTool/   → 更新任务状态
tools/TaskStopTool/     → 停止任务
tools/TaskOutputTool/   → 获取任务输出

6.9 团队与调度

tools/TeamCreateTool/   → 创建 Agent 团队
tools/TeamDeleteTool/   → 解散 Agent 团队
tools/TodoWriteTool/    → TODO 写入
tools/ToolSearchTool/   → 动态工具发现
tools/ScheduleCronTool/
├── CronCreateTool.ts   → 创建定时任务
├── CronDeleteTool.ts   → 删除定时任务
└── CronListTool.ts     → 列出定时任务

七、权限系统:三道防线

权限过滤流程图

设计背景:为什么需要三层权限过滤?

AI Agent 的核心矛盾是能力 vs 安全。Agent 越强大(拥有 shell 执行、文件写入、网络访问能力),误操作的风险越高。三层过滤的设计思路是:

  • 第一层(工具池裁剪) — 在 Agent 启动前决定它能看到哪些工具。简单模式只有 3 个工具,把出错概率降到最低
  • 第二层(运行时权限上下文) — 根据用户信任级别动态调整。高级用户可以开放更多工具
  • 第三层(场景化处理器) — 即使同一个人,在不同场景下(交互模式 vs 协调模式 vs 群集模式)的权限策略也不同

这种”洋葱模型”是安全工程的经典范式——每一层都独立可配置,任何一层被突破还有下一层保护。

7.1 ToolPermissionContext

# permissions.py
@dataclass(frozen=True)

class
 ToolPermissionContext:
    deny_names: frozenset[str] = field(default_factory=frozenset)
    deny_prefixes: tuple[str, ...] = ()

    def
 blocks(self, tool_name: str) -> bool:
        lowered = tool_name.lower()
        return
 (lowered in self.deny_names
                or
 any(lowered.startswith(prefix) for prefix in self.deny_prefixes))

权限上下文支持两种拒绝方式:

  • 按名称 — 精确拒绝(如 deny_names={'BashTool'}
  • 按前缀 — 模式拒绝(如 deny_prefixes=('mcp',)} 拒绝所有 MCP 工具)

7.2 权限推断

# runtime.py
def
 _infer_permission_denials(self, matches):
    denials = []
    for
 match in matches:
        if
 match.kind == 'tool' and 'bash' in match.name.lower():
            denials.append(PermissionDenial(
                tool_name=match.name,
                reason='destructive shell execution remains gated'
            ))
    return
 denials

系统会自动推断权限拒绝——例如 Bash 工具默认会被标记为需要额外权限。

7.3 三种权限处理器(hooks层)

源码快照记录了 hooks/toolPermission/handlers/ 中的三种处理器:

hooks/toolPermission/handlers/
├── coordinatorHandler.ts    # 协调模式:多 Agent 编排时
├── interactiveHandler.ts    # 交互模式:用户直接对话时
└── swarmWorkerHandler.ts    # 群集模式:大规模并行任务时

不同场景下的权限策略不同:

  • 交互模式 — 弹出确认对话框,等待用户批准
  • 协调模式 — 主 Agent 可以代表用户做部分决策
  • 群集模式 — 更严格的限制,因为大量 Agent 并发执行

八、成本追踪系统

# cost_tracker.py
@dataclass

class
 CostTracker:
    total_units: int = 0
    events: list[str] = field(default_factory=list)

    def
 record(self, label: str, units: int):
        self
.total_units += units
        self
.events.append(f'{label}:{units}')

# costHook.py — 钩子方式记录

def
 apply_cost_hook(tracker, label, units):
    tracker.record(label, units)
    return
 tracker

成本追踪通过 Hook 模式集成——在任何需要记录成本的地方调用 apply_cost_hookevents 列表保留了完整的成本事件历史。

九、上下文构建

# context.py
@dataclass(frozen=True)

class
 PortContext:
    source_root: Path        # 源码根目录
    tests_root: Path         # 测试根目录
    assets_root: Path        # 资源根目录
    archive_root: Path       # 归档根目录
    python_file_count: int   # Python 文件数
    test_file_count: int     # 测试文件数
    asset_file_count: int    # 资源文件数
    archive_available: bool  # 归档是否可用

上下文构建时会扫描整个工作空间,统计文件数量,判断归档是否可用。这些信息会注入到 Agent 的系统提示中。

十、远程运行时模式

# remote_runtime.py
@dataclass(frozen=True)

class
 RuntimeModeReport:
    mode: str        # 'remote' | 'ssh' | 'teleport'
    connected: bool  # 是否已连接
    detail: str      # 详情

def
 run_remote_mode(target): ...   # 远程模式
def
 run_ssh_mode(target): ...      # SSH 模式
def
 run_teleport_mode(target): ... # Teleport 模式

三种远程模式:

  • remote — 通过 WebSocket 远程控制
  • ssh — 通过 SSH 代理
  • teleport — Teleport 协议(恢复/创建)

十一、直接连接与深度链接

# direct_modes.py
@dataclass(frozen=True)

class
 DirectModeReport:
    mode: str       # 'direct-connect' | 'deep-link'
    target: str     # 目标
    active: bool    # 是否激活

def
 run_direct_connect(target): ...
def
 run_deep_link(target): ...

两种特殊连接模式:

  • direct-connect — 直连模式(不经过 Bridge)
  • deep-link — 深度链接(从外部应用跳转)

十二、Parity Audit — 持续一致性审计

# parity_audit.py — 关键映射表
ARCHIVE_ROOT_FILES = {
    'QueryEngine.ts'
: 'QueryEngine.py',
    'Task.ts'
: 'task.py',
    'Tool.ts'
: 'Tool.py',
    'commands.ts'
: 'commands.py',
    # ... 18 个根文件映射

}

ARCHIVE_DIR_MAPPINGS = {
    'assistant'
: 'assistant',
    'bridge'
: 'bridge',
    # ... 35 个目录映射

}

Parity Audit 持续检查 Python 移植版本与原始 TS 快照的一致性,确保没有遗漏关键模块。

十三、HistoryLog — 会话历史

# history.py
@dataclass(frozen=True)

class
 HistoryEvent:
    title: str
    detail: str

@dataclass

class
 HistoryLog:
    events: list[HistoryEvent] = field(default_factory=list)

    def
 add(self, title, detail):
        self
.events.append(HistoryEvent(title=title, detail=detail))

    def
 as_markdown(self):
        lines = ['# Session History', '']
        lines.extend(f'- {e.title}: {e.detail}' for e in self.events)
        return
 '\n'.join(lines)

每个重要操作都通过 history.add() 记录,形成可读的 Markdown 格式历史。


下篇预告:《Claude Code 源码深度解析(下):多 Agent 编排、记忆三层架构与创新设计》将深入分析 AgentTool 的 6 种内置 Agent、三层记忆系统、Plan Mode、Thinkback 回溯、Coordinator 协调模式、技能系统、Buddy 向导等创新设计。