Claude Code技术详解

Claude Code 技术详解 — 第一部分:架构与会话系统


第 1 章:Claude Code 概述

1.1 项目定位

Claude Code 是 Anthropic 官方发布的命令行 AI 编程助手(CLI),版本 2.1.73。它基于 Anthropic Messages API,以 Claude 模型为核心驱动,在本地终端环境中为开发者提供代码生成、文件操作、Shell 执行、多 Agent 协作等能力。

与其他 AI 编码工具不同,Claude Code 是一个 agentic 工具:模型可以连续多轮自主调用工具(读写文件、执行命令、搜索代码、调用 Web 等),直至完成复杂任务,无需人工介入每一步。

1.2 核心能力

能力类别 具体功能
文件操作 读文件、写文件、精确编辑(Edit)、Glob 搜索、正则搜索(Grep)
代码执行 Bash 命令执行(默认超时 120s,最大 600s)
智能工具 LSP 语言服务器协议、Jupyter Notebook 编辑
网络访问 WebFetch(页面抓取)、WebSearch(联网搜索)
多 Agent Agent 子代理、Team 模式多实例协作
任务管理 Task(创建/更新/查询/停止/输出)、Cron 定时任务
会话管理 持久化 JSONL、Resume 恢复、上下文压缩
技能系统 Skill(斜杠命令)加载与执行
Worktree Git Worktree 隔离工作区管理

1.3 运行模式

Claude Code 支持三种主要运行模式:

交互式 REPL 模式(默认)

claude

启动后进入 readline REPL,支持斜杠命令(/help/clear 等)。无轮次上限,持续对话直到用户主动退出。

批处理模式(--print / -p

claude -p "请帮我重构 src/app.ts"
claude -p --output-format json "..."
claude -p --output-format stream-json "..."

单次请求、非交互执行。--max-turns 参数仅在此模式生效,默认内部上限为 25 轮(MAX_TURNS = 25)。支持三种输出格式:text(默认)、jsonstream-json

Team 模式

多个 Claude Code 实例通过共享邮箱(mailbox)文件协同工作。一个实例充当 Team Lead,其余实例作为 Teammate。通过 TeamCreateTeamDeleteSendMessage 工具进行编排。

1.4 关键常量

常量名 说明
DEFAULT_MODEL "claude-opus-4-6" 默认模型,200k 上下文窗口
SMALL_FAST_MODEL "claude-haiku-4-5" 轻量快速模型(内部任务用)
MAX_TURNS 25 --print 模式内部轮次上限
Bash timeout(默认) 120_000 ms Bash 工具默认执行超时
Bash timeout(最大) 600_000 ms Bash 工具最大允许超时
OAuth CLIENT_ID "9d1c250a-e61b-44d9-88ed-5944d1962f5e" Anthropic OAuth 应用 ID
API timeout 600_000 ms HTTP 请求超时(AnthropicClient
MCP_LATEST_PROTOCOL_VERSION "2025-06-18" MCP 协议版本

源码定位:

  • DEFAULT_MODEL / SMALL_FAST_MODELsrc/api/models.ts:178-181
  • Bash timeout:src/tools/bash.ts
  • OAuth CLIENT_ID:src/api/oauth.ts

第 2 章:核心架构

2.1 整体架构图

用户输入(stdin / CLI 参数)
        │
        ▼
┌──────────────────────────────────┐
│  src/entrypoints/cli.ts          │  CLI 入口
│  Commander.js:56 个选项,9 个子命令│
└────────────────┬─────────────────┘
                 │ 构造 ExecutorConfig
                 ▼
┌──────────────────────────────────┐
│  src/session/executor.ts         │  主事件循环
│  ConversationExecutor.chat()     │
│  · 构建系统提示                  │
│  · 调用 API(SSE 流式)          │
│  · 并行执行工具调用              │
│  · 写入 JSONL                   │
└────────┬──────────┬──────────────┘
         │          │
         ▼          ▼
┌──────────────┐  ┌────────────────────────────────┐
│ src/api/     │  │ src/tools/index.ts              │
│ client.ts    │  │ 26 种内置工具 + Team 工具 + ToolSearch│
│ AnthropicClient│ │ getTools() → Tool[]            │
│ SSE 流式解析 │  └────────────────────────────────┘
└──────────────┘
         │
         ▼
┌──────────────────────────────────┐
│  src/session/history.ts          │  会话持久化
│  ConversationHistory             │
│  · appendEntry() 写 JSONL        │
│  · readEntries() 恢复会话        │
│  · listSessions() 列出历史       │
└──────────────────────────────────┘
         │
         ▼
  ~/.claude/projects/<slug>/<sessionId>.jsonl

2.2 主要模块清单

模块路径 职责 关键类/函数
src/entrypoints/cli.ts CLI 入口,Commander.js 注册 main(), dH$(原始名)
src/session/executor.ts 主工具循环,agentic 驱动 ConversationExecutor, chat()
src/session/types.ts 核心数据类型 ConversationSession, ExecutorConfig, ExecutorCallbacks
src/api/client.ts HTTP 客户端,SSE 解析 AnthropicClient, streamMessage()
src/api/models.ts 模型目录,自动压缩阈值 MODELS, getAutoCompactThreshold()
src/tools/index.ts 工具注册表 ALL_TOOLS, getTools(), TOOL_MAP
src/session/history.ts JSONL 读写管理 ConversationHistory, conversationHistory(单例)
src/session/logger.ts 异步批量写入器 SessionLogger(原始名:E39
src/session/paths.ts 文件路径编码 pw(), getSessionFilePath(), getSubagentFilePath()
src/session/compaction.ts 上下文压缩 compactConversation(), SUMMARIZATION_PROMPT
src/session/system-prompt.ts 系统提示构建 buildSystemPromptSections()(原始名:U2()
src/config/settings.ts 配置文件加载合并 SettingsManager, getSettingsManager()
src/teams/ Team 模式多 Agent mailbox.ts, spawn.ts, context.ts
src/mcp/ MCP 协议集成 MCPManager, MCPClient
src/skills/ 斜杠命令技能 SkillRegistry, SkillLoader

2.3 CLI 选项与子命令

入口文件 src/entrypoints/cli.ts 通过 Commander.js 注册了完整的 CLI 接口(原始函数 dH$)。

主要选项分类(共 56 个):

输出/模式控制:
  -p, --print                非交互批处理模式
  --output-format <fmt>      text | json | stream-json
  --input-format <fmt>       text | stream-json
  --include-partial-messages 流式 JSON 包含中间块

模型与行为:
  --model <model>            指定模型(默认 claude-opus-4-6)
  --max-turns <n>            最大轮次(仅 --print 模式)
  --permission-mode <mode>   acceptEdits | bypassPermissions | default | dontAsk | plan | auto
  --effort <level>           low | medium | high | max

会话管理:
  --resume [sessionId]       恢复指定或最新会话
  --continue                 同 --resume(无参数)

系统提示:
  --system-prompt <text>     覆盖默认系统提示
  --append-system-prompt <text> 追加到系统提示

工具控制:
  --allowed-tools <tools>    工具白名单
  --disallowed-tools <tools> 工具黑名单

MCP 集成:
  --mcp-config <path>        MCP 服务配置文件

输出控制:
  --json-schema <path>       验证最终输出的 JSON Schema
  --file <filespec>          Files API 文件预加载
  --verbose                  详细调试输出

9 个子命令:

claude agents          # 管理 Agent 实例
claude auth            # OAuth 认证(login/logout/status)
claude auto-mode       # 自动模式配置
claude doctor          # 环境诊断
claude install         # 安装/集成配置
claude mcp             # MCP 服务管理
claude plugin|plugins  # 插件管理
claude setup-token     # API Token 设置
claude update|upgrade  # 版本更新

第 3 章:会话系统

3.1 三层存储架构

Claude Code 的会话数据使用三层异步写入架构,在性能和持久性之间取得平衡:

┌─────────────────────────────────────────────────────────────────┐
│ 第一层:实时内存层                                               │
│   ConversationSession.turns[]   (ConversationTurn[])            │
│   · executor 每轮直接追加                                       │
│   · _buildMessages() 仅从此处构建 API 请求                      │
└──────────────────────────┬──────────────────────────────────────┘
                           │ append() 立即入队(非阻塞)
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│ 第二层:缓冲队列层                                               │
│   SessionLogger._queue   (Array<{entry, resolve}>)              │
│   · append() 入队后立即返回 Promise                             │
│   · 每 100ms 调度一次 _drain()                                  │
│   · 按 uuid 去重,同一 uuid 不重复写                            │
└──────────────────────────┬──────────────────────────────────────┘
                           │ _drain() → fs.appendFile()
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│ 第三层:持久文件层                                               │
│   JSONL 文件 (每行一个 JSON 对象)                               │
│   · 文件权限:0o600(仅拥有者可读写)                           │
│   · 目录权限:0o700                                             │
│   · 块大小上限:100 MB(MAX_CHUNK_BYTES = 104_857_600)         │
│   · 进程退出时 flushAll() 保证不丢数据                          │
└─────────────────────────────────────────────────────────────────┘

关键源码:

  • 内存层:src/session/types.tsConversationSessionConversationTurn
  • 队列层:src/session/logger.tsSessionLogger,原始名 E39cli.renamed.js:423364
  • 文件层:src/session/history.tsConversationHistory

3.2 文件路径格式

路径编码函数 pw()

pw() 函数(原始名 pw()cli.renamed.js:34565)将任意文件系统路径编码为目录安全的 slug:

规则:
1. 非字母数字字符 → "-"
2. 若 slug 超过 200 字符 → 截断到 200 字符 + "-" + djb2 哈希(base-36)

示例:
/Users/eric/Downloads/claude  →  Users-eric-Downloads-claude

源码位置:src/session/paths.ts:27-32

主会话路径

~/.claude/projects/<pw(cwd)>/<sessionId>.jsonl

对应函数:getSessionFilePath(cwd, sessionId)(原始名 ZA()cli.renamed.js:423269

完整示例:

工作目录:/Users/eric/Downloads/claude
SessionId:550e8400-e29b-41d4-a716-446655440000

路径:~/.claude/projects/Users-eric-Downloads-claude/550e8400-e29b-41d4-a716-446655440000.jsonl

Subagent 路径

~/.claude/projects/<pw(cwd)>/<parentSessionId>/subagents/agent-<agentId>.jsonl

对应函数:getSubagentFilePath(cwd, parentSessionId, agentId)(原始名 c2()cli.renamed.js:423280

配置目录

# 默认
~/.claude/

# 环境变量覆盖
CLAUDE_CONFIG_DIR=/custom/path claude

对应函数:getClaudeConfigDir()(原始名 rq()cli.renamed.js:3803

3.3 JSONL 条目格式

每个会话条目是独立的 JSON 对象,写入文件时以换行符分隔。

主会话条目:

{
  "type": "user",
  "uuid": "turn_01AbCdEf1234",
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "parentUuid": null,
  "isSidechain": false,
  "timestamp": "2026-03-27T10:30:00.000Z",
  "cwd": "/Users/eric/Downloads/claude",
  "version": "2.1.73",
  "message": {
    "role": "user",
    "content": [{ "type": "text", "text": "帮我重构这个函数" }]
  }
}

字段说明:

字段 类型 说明
type "user" | "assistant" | "tool_result" 条目类型
uuid string 唯一 Turn ID(格式:turn_ + 12 位十六进制)
sessionId string 会话 UUID
parentUuid string | null 父 Turn 的 uuid(第一条为 null)
isSidechain boolean Subagent 条目为 true,主会话为 false
timestamp string ISO 8601 时间戳
cwd string 工作目录(NFC 规范化)
version string Claude Code 版本号("2.1.73"
message object Anthropic Messages API 格式的消息体

Subagent 条目额外字段:

{
  "isSidechain": true,
  "agentId": "a3f8c2d1",
  "teamName": "dev-team",
  "agentName": "backend-agent"
}

3.4 SessionLogger 非阻塞写入机制

SessionLogger(原始类名 E39cli.renamed.js:423364)是写入层的核心。其设计目标是让 append() 调用的调用方感受不到 I/O 延迟。

工作流程:

append(entry)
  │
  ├─ uuid 去重检查:若 _writtenUuids.has(uuid) → 直接返回
  │
  ├─ push 到 _queue
  │
  ├─ _scheduleDrain():若无定时器 → setTimeout(100ms)
  │
  └─ 返回 Promise(由 resolve 函数挂在队列项上)

100ms 后:
  _drain()
    ├─ 从 _queue 取出所有项(splice(0))
    ├─ 序列化为 JSON Lines 字符串
    ├─ 若块超过 100MB → 分批写入
    ├─ fs.appendFile(filePath, chunk, { mode: 0o600 })
    │   └─ 若失败(目录不存在)→ mkdir(0o700) → 重试
    └─ 调用所有 resolve(),通知等待方

关键设计点:

  • FLUSH_INTERVAL_MS = 100(批量间隔)
  • MAX_CHUNK_BYTES = 104_857_600(单次写入上限 100MB)
  • 文件权限 0o600,目录权限 0o700
  • 错误静默吞噬(never throws)
  • flush() 方法:清除定时器 → 等待 _activeDrain → 执行 _drain() → 等待所有 pending 完成
  • 进程退出时:conversationHistory.flushAll() 并行 flush 所有 logger

源码:src/session/logger.ts

3.5 Resume 机制

Claude Code 支持恢复历史会话,有三种触发方式:

claude --resume <sessionId>   # 恢复指定 session
claude --resume               # 恢复最新 session(按 mtime 排序)
claude --continue             # 同上

恢复流程:

1. listSessions(cwd)
   └─ 读取 ~/.claude/projects/<slug>/ 目录
   └─ 过滤 *.jsonl 文件,按 mtime 降序排列

2. 若无 sessionId 参数 → 取第一个(最新)

3. readEntries(cwd, sessionId)
   └─ 读取 JSONL 文件,逐行 JSON.parse()
   └─ 跳过解析失败的行

4. 过滤出 type 为 "user" 或 "assistant" 的条目

5. 重建 session.turns[]
   └─ 每个条目 → ConversationTurn
   └─ 恢复 totalInputTokens、totalOutputTokens 等累计值

6. 以恢复后的 session 启动 executor

源码:src/session/history.tsConversationHistory.readEntries()listSessions()

3.6 会话压缩(Compaction)

当输入 token 数接近模型上下文窗口上限时,Claude Code 自动触发会话压缩,用结构化摘要替换历史消息以释放上下文空间。

自动触发阈值

触发阈值由 getAutoCompactThreshold(model) 计算(原始名 jd_()cli.renamed.js:215313):

阈值 = contextWindow - min(maxOutput, 20000) - 13000

以 claude-opus-4-6 为例:
  200000 - min(32000, 20000) - 13000 = 167000 tokens

上下文窗口警告(提前 20000 token 发出):
  警告阈值 = 压缩阈值 - 20000 = 147000 tokens(CONTEXT_WARNING_BUFFER)

源码:src/api/models.ts:202-209src/session/executor.ts:101

9 部分结构化提示

压缩时使用固定的 9 节总结提示(原始常量 RbRcli.renamed.js:177450):

节次 标题 内容
1 Primary Request and Intent 用户的全部明确请求和意图
2 Key Technical Concepts 重要技术概念、框架、技术栈
3 Files and Code Sections 操作过的文件和代码片段
4 Errors and Fixes 遇到的错误及修复方案
5 Problem Solving 已解决的问题和正在进行的调试
6 All User Messages 所有非工具结果的用户消息
7 Pending Tasks 尚未完成的待办任务
8 Current Work 压缩前正在进行的具体工作
9 Optional Next Step 与最近工作直接相关的下一步(直接引用原文)

模型先在 <analysis> 标签内完成分析,再输出 <summary>...</summary> 正文。

增量压缩

重复压缩时,getMessagesSinceLastCompact(messages) 函数(原始名 RL()cli.renamed.js:422791)检测上次压缩的边界标记,只对边界之后的新消息再次汇总,避免重复压缩已压缩内容。

边界标记(COMPACT_SESSION_PREFIX):

"This session is being continued from a previous conversation that ran out of context."

压缩结果格式

压缩后,原始历史消息被替换为一条 user 角色消息:

This session is being continued from a previous conversation that ran out of context.
The summary below covers the earlier portion of the conversation.

<summary 内容>

[可选] If you need specific details from before compaction (like exact code snippets,
error messages, or content you generated), read the full transcript at: <path>

源码:src/session/compaction.tscompactConversation(),原始名 _W_()cli.renamed.js:213964

压缩使用的模型

压缩使用会话当前模型mainLoopModel),而非 SMALL_FAST_MODELmax_tokens = 8192


第 4 章:配置系统

4.1 settings.json 加载优先级

Claude Code 采用多层配置合并策略,后加载的配置覆盖先加载的配置(array 类型字段如 permissions.allow 则合并去重,mcpServers 字段跨所有来源合并)。

加载顺序(优先级由低到高):

1. 内置默认值(代码中硬编码)
2. Policy 设置(MDM / 企业远程下发)
3. ~/.claude/settings.json           ← 用户级,影响所有项目
4. .claude/settings.json             ← 项目级,可纳入 git 追踪
5. .claude/settings.local.json       ← 本地覆盖,应加入 .gitignore
6. CLAUDE_SETTINGS_PATH 或 --settings 指定的文件   ← 最高优先级

源码:src/config/settings.tsSettingsManager,加载顺序注释)

环境变量覆盖:

CLAUDE_CONFIG_DIR=/custom/path   # 覆盖 ~/.claude 根目录
CLAUDE_SETTINGS_PATH=/path/to/settings.json  # 覆盖设置文件路径
ANTHROPIC_API_KEY=sk-ant-...     # API Key(优先于 apiKeyHelper 命令)

settings.json 关键字段示例:

{
  "model": "claude-opus-4-6",
  "permissions": {
    "allow": ["Bash(npm run *)", "Read(**/*.ts)"],
    "deny": ["Bash(rm -rf *)"]
  },
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    }
  },
  "hooks": {
    "PreToolUse": [{ "matcher": "Bash", "command": "echo 'about to run bash'" }]
  },
  "apiKeyHelper": "op read op://vault/anthropic/api-key"
}

4.2 CLAUDE.md 记忆文件

CLAUDE.md 文件在每次 API 调用时自动注入到系统提示中,作为持久化上下文记忆。

加载优先级(从低到高):

1. ~/.claude/CLAUDE.md                  ← 用户级全局记忆
2. ./CLAUDE.md                          ← 项目根,可纳入 git 追踪(团队共享记忆)
3. .claude/CLAUDE.md                    ← 项目级
4. ~/.claude/projects/<slug>/MEMORY.md  ← 自动记忆(AutoMemory)

自动记忆目录路径:autoMemoryDir(cwd) 返回 ~/.claude/projects/<pw(cwd)>/MEMORY.md

控制环境变量:

CLAUDE_CODE_DISABLE_CLAUDE_MDS=1    # 禁用所有 CLAUDE.md 加载
CLAUDE_CODE_DISABLE_AUTO_MEMORY=1   # 禁用自动记忆(AutoMemory)

加载逻辑:src/memory/manager.tsMemoryManager.loadAll()),内容构建:buildClaudeMdContent()

4.3 系统提示结构

系统提示由 buildSystemPromptSections()(原始名 U2()cli.renamed.js:410926)异步构建,分为多个具名节(SystemSection[]):

节名称 原始函数 内容
安全策略 Z19 安全测试授权政策
语言设置 DnK() 响应语言配置
输出风格 wnK() 响应格式偏好
System JnK() 核心工作规范
任务处理 WnK() 任务执行策略
执行操作 XnK() 操作执行准则
工具使用 knK() 工具调用规范
语气风格 hnK() 响应语气要求
环境信息 y19() OS、Shell、工作目录
Agent 工具 MnK() Agent 子调用说明
MCP 指令 ZnK() MCP 服务器使用规范
记忆指令 内存模块 AutoMemory 使用说明

节内容通过 Anthropic prompt caching 机制(cache_control: { type: "ephemeral" })进行缓存,降低重复调用的 token 消耗。缓存策略在 src/api/cache.ts 中实现(buildSystemBlocks()shouldEnablePromptCaching())。

4.4 MCP 协议集成

MCP(Model Context Protocol)允许 Claude Code 连接外部工具服务器,动态扩展可用工具集。

关键常量:

MCP_LATEST_PROTOCOL_VERSION = "2025-06-18"

工作机制:

  1. settings.jsonmcpServers 字段读取服务配置
  2. MCPManagersrc/mcp/manager.ts)启动并维护连接
  3. executor 构造时接收 mcpManager,在每次 API 调用时将 MCP 工具合并到工具列表
  4. MCP 工具命名格式:mcp__<serverName>__<toolName>
  5. MCP 工具调用通过 MCPManager 路由回对应服务器执行

配置示例:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
      "env": { "NODE_ENV": "production" }
    }
  }
}

子命令管理:claude mcp listclaude mcp addclaude mcp remove


附录 A:工具完整列表

Claude Code v2.1.73 共注册 26 种内置工具(Team 模式额外 3 种),加上 ToolSearch 元工具共 27 种(Team 模式共 30 种)。

分组 工具名 原始变量名 功能
文件 I/O Bash F6 Shell 命令执行
文件 I/O Glob pO 文件模式匹配
文件 I/O Grep c$ 内容正则搜索
文件 I/O Read J7 文件读取
文件 I/O Write a4 文件写入
文件 I/O Edit a7 精确字符串替换
代码智能 LSP Vl_ 语言服务协议
代码智能 NotebookEdit cD Jupyter 编辑
Web WebFetch ij 网页抓取
Web WebSearch oG 联网搜索
Agent Agent U7 子代理调用
任务管理 TaskCreate SV 创建任务
任务管理 TaskUpdate vN 更新任务
任务管理 TaskList Wt 列出任务
任务管理 TaskGet Jt 查询任务
任务管理 TaskStop vS 停止任务
任务管理 TaskOutput VS 获取任务输出
定时任务 CronCreate OL 创建定时任务
定时任务 CronDelete WF 删除定时任务
定时任务 CronList YW_ 列出定时任务
计划模式 EnterPlanMode Yt 进入计划模式
计划模式 ExitPlanMode NN 退出计划模式
交互 AskUserQuestion N5 向用户提问
Worktree EnterWorktree skT 进入 Git Worktree
Worktree ExitWorktree tkT 退出 Git Worktree
技能 Skill qf 执行斜杠命令技能
元工具 ToolSearch 工具发现与过滤
Team(可选) TeamCreate 创建 Team
Team(可选) TeamDelete 删除 Team
Team(可选) SendMessage 发送 Team 消息

源码:src/tools/index.tsALL_TOOLSgetTools()


附录 B:关键源码文件索引

文件路径 说明
src/entrypoints/cli.ts CLI 入口,56 个选项,9 个子命令
src/session/executor.ts ConversationExecutor,主 agentic 循环
src/session/types.ts ConversationSessionExecutorConfig 等核心类型
src/session/history.ts ConversationHistory,JSONL 读写管理器
src/session/logger.ts SessionLogger,异步批量写入(原始 E39
src/session/paths.ts pw()getSessionFilePath() 等路径函数
src/session/compaction.ts compactConversation(),上下文压缩
src/session/system-prompt.ts buildSystemPromptSections(),系统提示构建
src/api/client.ts AnthropicClient,HTTP + SSE 客户端
src/api/models.ts 模型目录,getAutoCompactThreshold()
src/tools/index.ts ALL_TOOLSgetTools()TOOL_MAP
src/config/settings.ts SettingsManager,多层配置合并
src/memory/manager.ts MemoryManager,CLAUDE.md 加载
src/teams/ Team 模式(mailbox、spawn、context 等)
src/mcp/manager.ts MCPManager,MCP 服务器连接管理

Claude Code 技术详解 — 第二部分:工具系统与 Hooks


第 5 章:工具系统

5.1 工具注册(src/tools/index.ts)

Claude Code 的工具系统由 ALL_TOOLS 数组集中管理,按功能分为 8 个分组,共 26 个内置工具。Team 模式下额外追加 3 个团队工具,总计最多 29 个。

工具完整列表

分组 A:文件 I/O(File I/O)

工具名 原始变量名 说明
Bash F6 执行 shell 命令,默认超时 120s,最大 600s
Glob pO 文件模式匹配,按修改时间排序返回
Grep c$ 基于 ripgrep 的内容搜索,支持正则
Read J7 读取文件内容,支持 offset/limit 分页
Write a4 写入文件,整体覆盖(必须先 Read)
Edit a7 基于精确字符串替换的文件局部编辑

分组 B:代码智能(Code Intelligence)

工具名 原始变量名 说明
LSP Vl_ Language Server Protocol 诊断与符号查询
NotebookEdit cD Jupyter Notebook 单元格编辑(replace/insert/delete)

分组 C:Web 工具

工具名 原始变量名 说明
WebFetch ij 抓取 URL 内容并用 AI 提取摘要,带 15 分钟缓存
WebSearch oG 网页搜索,返回结构化结果块,末尾必须附 Sources 列表

分组 D:Agent 编排

工具名 原始变量名 说明
Agent U7 启动子 Agent 完成复杂多步任务,支持前台/后台两种模式

分组 E:任务管理(Task Management)

工具名 原始变量名 说明
TaskCreate SV 创建新任务
TaskUpdate vN 更新任务状态、所有者、优先级等
TaskList Wt 列出任务列表(可按状态筛选)
TaskGet Jt 获取单个任务详情
TaskStop vS 停止运行中的任务
TaskOutput VS 获取任务输出(Original: VS (TaskOutput)

分组 F:后台调度(Cron)

工具名 原始变量名 说明
CronCreate OL 创建定时任务
CronDelete WF 删除定时任务
CronList YW_ 列出所有定时任务

分组 G:规划与交互

工具名 原始变量名 说明
EnterPlanMode Yt 进入只读规划模式(model 被限制为只能使用只读工具)
ExitPlanMode NN 退出规划模式,可选触发 plan_approval 流程
AskUserQuestion N5 暂停执行,向用户提问并等待答复

分组 H:工作区与技能

工具名 原始变量名 说明
EnterWorktree skT 创建隔离的 git worktree 并切换工作目录
ExitWorktree tkT 退出 worktree(keep 或 remove)
Skill qf 执行用户定义的 Skill(slash command 展开)

分组 I:元工具(Meta-tools)

工具名 说明
ToolSearch 按需加载延迟工具的 schema,始终位于列表末尾

Team 模式专属工具(需 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1

工具名 说明
TeamCreate 创建多 Agent 协作团队
TeamDelete 解散当前团队,清理所有文件
SendMessage 向队友发送消息(DM、广播、shutdown 协议等)

工具注册接口

getTools() 函数(对应原始 YB() cli.renamed.js:351036)在运行时动态决定是否追加 Team 工具:

export function getTools(): Tool[] {
  return [
    ...ALL_TOOLS,
    ...(isTeamMode() ? [TeamCreateTool, TeamDeleteTool, SendMessageTool] : []),
  ];
}

工具属性(Tool 接口)关键字段:

字段 类型 说明
name string 工具唯一标识符
description string 发给模型的工具说明,用于 ToolSearch 评分
inputSchema object JSON Schema,定义参数
isReadOnly boolean 只读工具不会修改文件系统
isConcurrencySafe boolean 是否可与同类工具并发执行
requiresPermission boolean 是否需要用户确认
shouldDefer boolean 是否默认延迟(ToolSearch 机制)
searchHint string? ToolSearch 优先匹配的简短描述
isEnabled() function? 动态判断工具是否可用(如 Team 工具)

权限分类集合:

// 需要路径权限检查的工具
export const filePatternTools = new Set(["Bash","Read","Write","Edit","Glob","NotebookEdit"]);

// 只读工具(由 isReadOnly 标志自动筛选)
export const readOnlyTools = new Set(ALL_TOOLS.filter(t => t.isReadOnly).map(t => t.name));

5.2 工具执行流程

Claude Code 采用标准的 tool_use → tool_result 循环驱动 Agent 推理,由 ConversationExecutorsrc/session/executor.ts)实现。

主循环流程图

用户输入 / chat(prompt)
  │
  ▼
构建消息历史 + system prompt
  │
  ▼
调用 Anthropic API(流式 SSE)
  │
  ▼
收到响应(stopReason 判断)
  ├─ "end_turn" ──────────────────────────────→ 返回最终文本,结束
  ├─ "max_tokens" ────────────────────────────→ 注入恢复提示,重试(最多 3 次)
  └─ "tool_use" ──────────────────────────────┐
                                              │
  ┌───────────────────────────────────────────┘
  │
  ▼
提取所有 tool_use 块(一轮可能有多个)
  │
  ▼
并行执行每个工具调用:
  ├─ PreToolUse Hook(权限检查 / 修改 input / 可拒绝)
  ├─ 检查 permissionMode,必要时请求用户确认
  ├─ tool.validateInput(input)
  ├─ tool.execute(input, context)
  └─ PostToolUse / PostToolUseFailure Hook
  │
  ▼
组装 tool_result 列表,追加到消息历史
  │
  ▼
再次调用 API(下一轮)

关键实现细节

并行执行:当一轮中出现多个 tool_use 块时,所有工具调用通过 Promise.all 并行执行。isConcurrencySafe=false 的工具(如 Bash)在实际实现中仍可并行,但部分状态修改工具会顺序化处理。

上下文窗口监控:Executor 持续追踪 token 用量。当接近 auto-compact 阈值时(留 20,000 token 缓冲,原始常量 hrR/ZrR),触发 compactConversation() 压缩历史记录。

最大轮次限制:交互式 REPL 模式无硬性轮次上限;--print 模式下有 MAX_TURNS = 25 的限制。

agentId 生成:子 Agent 的 ID 格式为 "a" + randomBytes(8).toString("hex")(17 字符),与磁盘上的 JSONL 文件名对应,例如 agent-ad81ffcbbe3472f6f.jsonl

ToolContext 传递给工具

每次调用 tool.execute(input, context) 时传入的 ToolContext 包含:

字段 说明
workingDirectory 当前工作目录
sessionId 父会话 ID(用于子 Agent JSONL 路径)
agentId 本 Agent 的 ID
isReadOnly 是否只读模式(plan mode)
verbose 是否输出调试信息
_allTools 完整工具列表(供 ToolSearch 使用)
permissionMode 权限模式(bypassPermissions / plan / default 等)

5.3 PTC(Programmatic Tool Calling)

PTC 是 Anthropic 服务端沙箱与 CLI 客户端之间的工具调用协议扩展,允许服务端代码执行沙箱(如 Python 解释器)在其内部代码中调用 Claude Code 的本地工具。

工作原理

服务端                           CLI 客户端
  │                                  │
  │  server_tool_use(启动沙箱)       │
  │ ─────────────────────────────→   │
  │                                  │
  │  沙箱内代码执行,调用 CLI 工具      │
  │  tool_use + caller 字段           │
  │ ─────────────────────────────→   │
  │                                  │
  │                        识别 caller,剥离后执行工具
  │                        正常 tool_result 流程
  │  ←────────────────────────────── │

核心数据结构

启动沙箱的 server_tool_use 块:

{
  "type": "server_tool_use",
  "id": "srvtoolu_abc123",
  "name": "code_execution",
  "input": { "code": "import subprocess; result = bash('ls -la')" }
}

沙箱内代码调用 CLI 工具时附带的 caller 字段:

{
  "type": "tool_use",
  "id": "toolu_xyz",
  "name": "Bash",
  "input": { "command": "ls -la" },
  "caller": {
    "type": "code_execution_20260120",
    "tool_id": "srvtoolu_abc123"
  }
}

架构分工

职责 负责方 实现位置
沙箱容器创建与生命周期管理 服务端 Anthropic 服务器
容器内代码执行 服务端 Anthropic 服务器
识别 caller 字段 CLI uH9() cli.renamed.js:421556
剥离 caller,按普通工具执行 CLI executor.ts
追踪 container ID CLI executor 内部状态

关键设计:PTC 不需要特殊路由——CLI 端的工具执行逻辑与普通 tool_use 完全相同,区别仅在于对 caller 字段的预处理(识别来源并剥离后再交给标准执行流程)。

相关类型

// 上传内容给沙箱
type ContainerUploadContentBlock = {
  type: "container_upload";
  file_id: string;
};

// 沙箱中 Bash 执行结果
type BashCodeExecutionToolResultBlock = {
  type: "tool_result";
  tool_use_id: string;
  content: string;
};

// 代码执行工具标识符
type CodeExecutionTool = {
  type: "code_execution_20260120";
};

5.4 Deferred Tools / ToolSearch

ToolSearch 是 Claude Code 的工具按需加载机制。当工具数量(尤其是 MCP 工具)较多时,将全部 schema 一次性发给模型代价高昂。Deferred 机制将工具分为两类:立即可用(发送完整 schema)和延迟加载(仅发送名称列表,按需搜索)。

工具延迟判断逻辑

isDeferred() 函数(对应原始 WX(),cli.renamed.js:182282)按优先级顺序判断:

export function isDeferred(tool: Tool): boolean {
  if (tool.name === TOOL_SEARCH_NAME) return false;      // ToolSearch 本身永不延迟
  if (process.env.TOOL_SEARCH_DEFER_ALL === "true") return true;  // 环境变量强制全部延迟
  if (tool.name.startsWith("mcp__")) return true;        // MCP 工具始终延迟
  if (tool.shouldDefer === true) return true;            // 工具自身标记
  return false;
}

注意:当前代码库中 TOOL_SEARCH_DEFER_ALL 环境变量对应文档中所说的 tengu_defer_all_bn4 feature flag 的行为——凡是 TOOL_SEARCH_DEFER_ALL=true,所有工具(包括内置工具)均被延迟。实际上查看 team.ts 源码,TeamCreateToolTeamDeleteToolSendMessageToolshouldDefer 均设为 true,因此默认延迟加载。

ToolSearch 启用条件

isToolSearchEnabled() 函数(对应 Td_(),cli.renamed.js:411622)检查以下所有条件:

  1. 模型支持:必须是 claude-sonnet-4claude-opus-4 系列(不含 Haiku)
  2. 工具存在ToolSearch 工具必须在工具列表中
  3. 有延迟工具:至少存在一个 deferred tool
  4. 模式检查ENABLE_TOOL_SEARCH 环境变量决定模式(见下表)
  5. 代理守卫:未设置 ENABLE_TOOL_SEARCH 时,若检测到 API 通过代理(非 api.anthropic.com),则禁用(代理可能不支持 tool_reference 块)

ENABLE_TOOL_SEARCH 模式系统

环境变量值 模式 行为
未设置 / true / 1 / yes / on tst 始终开启(第一方 API)
false / 0 / no / off standard 始终关闭
auto tst-auto 阈值模式(默认 10%)
auto:N(0–100) tst-auto 自定义阈值 N%
auto:0 tst 阈值为 0 = 始终开启
auto:100 standard 阈值为 100% = 始终关闭

tst-auto 模式下的阈值计算:

char_threshold = floor(200000 × N/100 × 2.5)

当所有 deferred 工具的 name + description + schema 字符总数 ≥ char_threshold 时才启用 ToolSearch。

Beta 头部标识符

常量 用途
TOOL_REFERENCE_BETA_HEADER_FIRST_PARTY advanced-tool-use-2025-11-20 第一方 Anthropic API
TOOL_REFERENCE_BETA_HEADER_VERTEX_BEDROCK tool-search-tool-2025-10-19 Vertex AI / Bedrock

ToolSearch 输入 Schema

interface ToolSearchInput {
  query: string;         // 必填:搜索查询
  max_results?: number;  // 可选:最大结果数,默认 5
}

查询语法:

语法 说明 示例
select:Name1,Name2 按名称直接获取(大小写不敏感) select:Read,Edit,Grep
关键词 BM25 评分匹配 notebook jupyter
+term 前缀 强制要求(不匹配则排除) +slack send

BM25 评分规则

评分函数 scoreTools()(对应 TIR(),cli.renamed.js:182381):

匹配类型 MCP 工具(mcp__ 前缀) 非 MCP 工具
name-part 精确匹配 +12 +10
name-part 包含 term +6 +5
完整工具名包含 term +3 +3
searchHint 词边界匹配 +4 +4
description 词边界匹配 +2 +2

名称拆分规则(splitNameParts()):

  • MCP 工具:去掉 mcp__ 前缀,按 ___ 分割
  • 普通工具:按驼峰命名边界分割(如 TaskCreate["task", "create"]

ToolSearch 返回格式

有结果时:返回 tool_reference 块数组(而非文本):

[
  { "type": "tool_reference", "tool_name": "Read" },
  { "type": "tool_reference", "tool_name": "Edit" }
]

无结果时:返回文本,如有等待连接的 MCP 服务器则附上提示:

No matching deferred tools found. Some MCP servers are still connecting: my-server.
Their tools will become available shortly — try searching again.

tool_reference 块是 Anthropic API 的扩展类型,不在标准 ContentBlock union 中。当模型收到 tool_reference 后,即可直接调用对应工具,无需再次调用 ToolSearch。

<available-deferred-tools> 注入

在每次 API 调用前,Executor 通过 buildDeferredToolsMessage() 构建一条前置消息,告知模型当前有哪些延迟工具可以搜索:

<available-deferred-tools>
Agent
CronCreate
CronDelete
...(按字母排序的工具名列表)
</available-deferred-tools>

该消息以 role: "user" 注入,使模型知道延迟工具的存在,从而决定是否调用 ToolSearch。

filterEffectiveTools 过滤逻辑

每次 API 调用前,filterEffectiveTools() 决定实际发送给模型的工具集:

export function filterEffectiveTools(
  tools: Tool[],
  toolSearchActive: boolean,
  discoveredTools: Set<string>,
): Tool[] {
  if (toolSearchActive) {
    // 发送:非延迟工具 + ToolSearch 自身 + 已发现的延迟工具
    return tools.filter(
      (t) => !isDeferred(t) || t.name === TOOL_SEARCH_NAME || discoveredTools.has(t.name),
    );
  }
  // ToolSearch 未激活时:发送所有工具,但排除 ToolSearch 自身
  return tools.filter((t) => t.name !== TOOL_SEARCH_NAME);
}

discoveredTools 通过 extractDiscoveredToolNames() 扫描历史消息中的 tool_reference 块获取,持续累积。


5.5 Agent 工具详解

Agent 工具(src/tools/agent.ts)是 Claude Code 中最复杂的工具,支持三种执行模式。

执行模式

1. 前台同步模式(默认)

创建新的 ConversationExecutor 实例,等待子 Agent 完成后返回文本摘要:

const executor = new ConversationExecutor({
  model,
  workingDirectory: context.workingDirectory,
  permissionMode: context.isReadOnly ? "plan" : "bypassPermissions",
  agentId: "a" + randomBytes(8).toString("hex"),
  parentSessionId: context.sessionId,
  systemPrompt: buildSubagentSystemPrompt(input),
});
const result = await executor.chat(input.prompt);

2. 后台异步模式(run_in_background: true

立即返回任务 ID,异步执行:

{
  "task_id": "agent_bg_1",
  "status": "started",
  "description": "Analyze test coverage",
  "message": "Background task started with ID agent_bg_1. It will complete asynchronously."
}

后台任务注册在 backgroundTasks: Map<string, BackgroundTask> 中,可供后续查询。

3. Team 模式(name + team_name 参数)

当同时提供 nameteam_name 时,以子进程方式启动队友(spawnChildTeammate()),而非 in-process 执行。这是 Team 模式的核心机制:

const { pid, agentId } = await spawnChildTeammate({
  name: input.name,
  teamName: input.team_name,
  prompt: input.prompt,
  model: input.model,
  planModeRequired: input.mode === "plan",
  parentSessionId,
  cwd: context.workingDirectory,
});

// 注册到团队配置
addTeamMember(input.team_name, {
  agentId, name: input.name,
  color: getAgentColor(agentId),
  spawnVariant: "child", pid,
});

Team 模式守卫

  • 队友不能再生成其他队友(团队结构是扁平的,只有 team-lead 可以 spawn)
  • isTeammate() 检查当前进程是否为队员,若是则阻断

Agent 输入参数

参数 类型 必填 说明
description string 3-5 词的简短描述,显示在 UI
prompt string 完整任务提示,需自包含
subagent_type string 特化 Agent 类型标签(如 Explorecode-reviewer
run_in_background boolean true=异步执行
isolation "none"|"worktree" 文件系统隔离模式
model string 覆盖父会话模型
resume string 恢复之前的 Agent 会话 ID
name string Team 模式:队友名称
team_name string Team 模式:加入的团队名
mode string Team 模式:权限模式覆盖

子 Agent 元数据文件路径:

<workingDir>/.claude/projects/<sessionId>/subagents/agent-<agentId>.meta.json

内容:{ "agentType": "Explore" }(用于 UI 显示)。


5.6 Team 工具详解

Team 模式(src/tools/team.ts)实现了多 Agent 协作框架,需通过环境变量 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1--agent-teams CLI 标志启用。

TeamCreate

创建团队后的副作用:

  1. ~/.claude/teams/{team-name}/ 创建团队目录(若名称冲突则生成随机名称)
  2. ~/.claude/tasks/{team-name}/ 创建任务目录
  3. 清空旧的任务文件和收件箱(clearTeamTaskDir() / clearTeamInboxes()
  4. 生成 leadAgentId = makeAgentId("team-lead", teamName)
  5. 写入配置文件(config.json),包含 team-lead 作为初始成员
  6. 调用 setTeamContext() 标记当前进程为 team-lead

返回值:

{
  "team_name": "my-project",
  "team_file_path": "~/.claude/teams/my-project/config.json",
  "lead_agent_id": "team-lead@my-project"
}

TeamDelete

删除团队前检查:必须先关闭所有非 team-lead 的活跃成员(isActive !== false),否则返回错误。删除 teams/{name}/tasks/{name}/ 目录并清除 team context。

SendMessage 消息类型

SendMessage 工具支持 5 种消息类型:

type 必填参数 说明
message recipient, content, summary 点对点直发,写入收件人的 mailbox 文件
broadcast content, summary 广播给所有成员,代价随成员数线性增长
shutdown_request recipient 请求队员优雅退出,生成 requestId
shutdown_response request_id, approve 响应关闭请求;approve=true 时调用 process.exit(0)
plan_approval_response recipient, request_id, approved 批准或拒绝队员的规划方案

Mailbox 机制:消息写入磁盘上的收件箱文件(~/.claude/teams/{team}/mailbox/{agent}.json),对方进程在每轮结束后检查并消费。消息自动投递,无需手动轮询。

重要shutdown_responseapprove=true 时,发送方进程会直接调用 process.exit(0) 终止自身,这是队员进程退出的主要路径。


第 6 章:Hooks 系统

Hooks 是 Claude Code 的扩展点,允许用户通过配置外部 shell 脚本,在特定事件发生时注入逻辑。Hooks 在 src/session/executor.ts 中通过 HookRunner 类调用。

6.1 工具 Hooks(PreToolUse / PostToolUse / PostToolUseFailure)

工具 Hooks 在每次工具调用的前后触发,可以检查、修改或阻断工具执行。

能力矩阵

能力 PreToolUse PostToolUse PostToolUseFailure
阻断执行(exit 2)
修改工具输入 是(updatedInput
修改工具输出 是(MCP 工具专属)
注入 system-reminder 上下文

PreToolUse 输出格式

脚本通过 stdout 输出 JSON 控制执行行为:

{
  "hookEventName": "PreToolUse",
  "permissionDecision": "allow",
  "permissionDecisionReason": "已验证路径在白名单内",
  "updatedInput": {
    "command": "ls -la /safe/path"
  },
  "additionalContext": "注入到下一轮 system-reminder 的内容"
}

字段说明:

字段 类型 说明
permissionDecision "allow"|"deny"|"ask" 允许/拒绝/要求用户确认
permissionDecisionReason string? 决策原因,显示给用户
updatedInput object? 替换原始工具输入(仅 PreToolUse 有效)
additionalContext string? 注入到 system-reminder 的附加上下文

Exit Code 语义

退出码 含义
0 成功。PreToolUse 中 stdout 静默处理;PostToolUse 中 stdout 显示在转录
2 阻断执行。阻止工具运行(PreToolUse)或阻止结果传递给模型(PostToolUse)
其他非零 非阻断错误,记录到日志但继续执行

Matcher 规则

Hooks 配置通过 matcher 指定触发范围:

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [...] },
      { "matcher": "Edit|Write", "hooks": [...] },
      { "matcher": "", "hooks": [...] }
    ]
  }
}
  • "Bash":精确匹配单个工具名
  • "Edit|Write":正则或分隔符,匹配多个工具
  • ""(空字符串):匹配所有工具

6.2 会话 Hooks(UserPromptSubmit / SessionStart)

会话 Hooks 作用于整个请求级别,而非单次工具调用。

触发时机

Hook 事件 触发条件 典型用途
SessionStart 新会话建立时,触发一次 初始化上下文、检查环境
UserPromptSubmit 每次用户提交消息时 动态注入上下文、访问控制

输出格式

{
  "hookSpecificOutput": {
    "additionalContext": "当前 Git 分支:feature/auth\n上次构建:成功"
  }
}

执行语义

情况 行为
exit 0 + 空输出 不注入任何上下文,静默通过
exit 0 + JSON 输出 解析 hookSpecificOutput.additionalContext 并注入 system-reminder
exit 2 阻断整个请求,不调用模型
其他非零 非阻断错误,记录日志,请求继续处理

UserPromptSubmit 是最常用的会话 Hook,可用于:

  • 自动附加 Git 状态信息
  • 检查用户权限或项目配置
  • 强制注入某些规范约束
  • 拦截不符合规范的请求(exit 2)

6.3 system-reminder 注入机制

system-reminder 是 Claude Code 动态向模型注入上下文的核心机制。与静态 system prompt 不同,system-reminder 的内容随会话状态变化而更新。

注入位置

system-reminder 不在 system prompt 中,而是以 user 角色消息的形式注入,内容被 <system-reminder> 标签包裹,并标记 isMeta=true(不显示给用户)。模型被告知这些标签来自系统,与具体工具结果或用户消息无关。

来自系统提示(src/session/system-prompt.ts 中的 buildSystemSection()):

“Tool results and user messages may include <system-reminder> or other tags. Tags contain information from the system. They bear no direct relation to the specific tool results or user messages in which they appear.”

所有注入来源

来源标识符 触发条件 内容
hook_additional_context UserPromptSubmit 或 SessionStart Hook 有输出 Hook 脚本 stdout 的 additionalContext 字段
critical_system_reminder context.criticalSystemReminder_EXPERIMENTAL 存在 配置中指定的关键提醒文本
date_change 跨日检测到系统日期变化 更新后的当前日期
todo_reminders 每 N 轮有未完成 TodoWrite 任务 待办事项列表摘要
plan_mode 进入或退出 plan 模式 模式切换通知
team_context Team 模式首轮(buildTeamContextAttachment() 团队配置、队友列表、角色信息
deferred_tools_delta 工具集发生变化(ToolSearch 发现新工具后) <available-deferred-tools>
PreToolUse Hook Hook 脚本 exit 0 + additionalContext 字段 Hook 注入的动态上下文
PostToolUse Hook Hook 脚本 exit 0 + additionalContext 字段 工具执行后注入的上下文

deferred_tools_delta attachment

当 ToolSearch 被调用后,工具集发生变化(新工具从 deferred 变为 discovered),Executor 通过 attachment 机制将变更通知模型:

interface DeferredToolsDeltaAttachment {
  addedNames: string[];    // 新加入的工具名列表
  addedLines: string[];    // 格式:"name — searchHint"
  removedNames: string[];  // 被移除的工具名列表
}

注入格式示例:

<available-deferred-tools>
Agent
CronCreate
TaskCreate
WebFetch
</available-deferred-tools>

ReminderManager

ReminderManagersrc/session/reminders.ts)负责管理 system-reminder 的触发逻辑,追踪:

  • 上次注入的轮次编号(控制 todo_reminders 频率)
  • 上次检测到的日期(用于 date_change 检测)
  • 各 reminder 类型的去重状态

wrapSystemReminder(content) 函数将内容包裹为标准格式:

<system-reminder>
{content}
</system-reminder>

6.4 Hooks 配置结构

Hooks 配置存储在 ~/.claude/settings.json 或项目级 .claude/settings.json 中:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/bash-guard.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/format-check.sh"
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/context-injector.sh"
          }
        ]
      }
    ],
    "SessionStart": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/session-init.sh"
          }
        ]
      }
    ]
  }
}

Hook 脚本通过环境变量接收工具信息(如 CLAUDE_TOOL_NAMECLAUDE_TOOL_INPUT),通过 stdout 返回 JSON 控制决策,通过 exit code 表示是否阻断。

系统提示中向模型说明了 Hooks 的存在(hooksNote() 函数):

“Users may configure ‘hooks’, shell commands that execute in response to events like tool calls. Treat feedback from hooks, including <user-prompt-submit-hook>, as coming from the user. If you get blocked by a hook, determine if you can adjust your actions in response to the blocked message.”

这意味着模型可以感知自己被 Hook 阻断,并有能力调整行为策略或通过 AskUserQuestion 询问用户如何处理。

Claude Code 技术详解 — 第三部分:Team 模式与 Agent 系统

第 7 章:Team 模式

7.1 概述与启用

Team 模式允许 TL(Team Lead)协调多个 Agent 并行工作,需设置环境变量:

export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
# 或启动时传入 --agent-teams 标志

Team 相关工具共 10 个:

类别 工具 说明
团队管理 TeamCreate 创建团队,初始化配置和任务目录
团队管理 TeamDelete 解散团队,清理所有文件(需成员全部关闭)
团队管理 SendMessage 发消息(DM/广播/shutdown/plan 审批)
任务看板 TaskCreate 创建任务
任务看板 TaskUpdate 更新任务状态/owner/依赖
任务看板 TaskList 列出所有任务
任务看板 TaskGet 获取任务详情
任务看板 TaskStop 停止后台任务
任务看板 TaskOutput 获取后台任务输出
Spawn Agent name+team_name 参数时 spawn 成员

7.2 文件系统结构

~/.claude/
├── teams/
│   └── {teamName}/
│       ├── config.json              # 团队成员信息
│       └── inboxes/
│           ├── team-lead.json       # TL 的 mailbox
│           ├── worker-1.json        # 成员 mailbox(纯 ASCII 名)
│           └── ---d4f5a6b7.json     # Unicode 名称追加 SHA-256 前8位防碰撞
└── tasks/
    └── {teamName}/
        ├── 1.json                   # 每个任务一个 JSON 文件
        └── 2.json

sanitizeName 规则:非 [a-zA-Z0-9_-] 字符替换为 -。当原名含 Unicode 字符(codepoint > 127)时,追加 SHA-256 前 8 位确保唯一性:

"产品"      → "---d4f5a6b7"   (唯一,避免与"研发"碰撞)
"研发"      → "---a1b2c3d4"   (唯一)
"team-lead" → "team-lead"     (纯 ASCII 不变)

对应源码:GP_() (cli.renamed.js:166453),PR_() (cli.renamed.js:185248)

7.3 Spawn 三种模式

原码通过 QkK() (cli.renamed.js:318331) 路由:

if (isInProcessMode()) return spawnInProcess();       // 同进程异步
if (use_splitpane !== false) return spawnSplitPane(); // tmux split-pane
return spawnExternalTmux();                           // tmux new-window

isInProcessMode()Kx() cli.renamed.js:317421)返回 true 的条件:

  • 非交互式会话(w6() 为 true)
  • CLAUDE_CODE_BACKEND=in-process 环境变量显式指定
  • 不在 tmux 内部(!NVT()
模式 触发条件 实现 进程模型
in-process 普通 shell / CI / 无 tmux GkK() 同进程异步循环 共享 AppState,内存+文件双路通信
split-pane 在 tmux 内部运行 tmux send-keys 新 pane 独立进程,tmux 可视化
external-tmux 有 tmux 但不在其内 claude-swarm session 新 window 独立进程,独立窗口

还原代码现状(src/tools/agent.ts):始终走 spawnChildTeammate()(子进程),三路路由尚未还原。

Spawn 命令格式(tmux 模式,ckK() 构建):

cd <cwd> && env \
  CLAUDECODE=1 \
  CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 \
  [ANTHROPIC_BASE_URL=...] \
  [CLAUDE_CODE_USE_BEDROCK=1] \
  <claude_path> \
  --agent-id worker@team \
  --agent-name worker \
  --team-name myteam \
  --agent-color "#ff0000" \
  --parent-session-id <TL_sessionId> \
  [--plan-mode-required] \
  [--agent-type general-purpose] \
  [--model claude-opus-4-6]

转发的后端环境变量(ykK 数组,cli.renamed.js:316724):
CLAUDE_CODE_USE_BEDROCKCLAUDE_CODE_USE_VERTEXCLAUDE_CODE_USE_FOUNDRYANTHROPIC_BASE_URLCLAUDE_CONFIG_DIR

重要:无 --resume 参数,team config 不存储 sessionId,每次 spawn 都是全新 session

7.4 Mailbox 通信机制

每个成员有独立的 JSON 文件 inbox,使用 proper-lockfile 防止并发写入冲突。

消息文件格式VK() cli.renamed.js:185279):

[
  {
    "from": "team-lead",
    "text": "消息内容(普通文本或结构化 JSON payload)",
    "timestamp": "2026-03-27T10:00:00.000Z",
    "color": "#ff0000",
    "summary": "简短摘要",
    "read": false
  }
]

in-process 模式额外的内存队列(性能优化):

TL 调用 jc_(taskId, message) → 直接写 AppState.pendingUserMessages[]
                                          ↓ 延迟 ~0ms
Worker MkK() 轮询:先查内存队列,再查文件(500ms 间隔)

Worker 轮询优先级MkK() cli.renamed.js:316106):

  1. 内存队列 pendingUserMessages(in-process 专属,0ms 延迟)
  2. Mailbox 文件中的 shutdown_request(最高优先级,优先于普通消息)
  3. 来自 "team-lead" 的未读消息
  4. 其他任意未读消息

结构化消息协议(JSON 序列化后存入 text 字段):

消息类型 发送方 接收方 用途
shutdown_request TL Worker 请求成员优雅关闭
shutdown_approved Worker TL 批准关闭,随即退出
shutdown_rejected Worker TL 拒绝关闭,含原因
plan_approval_request Worker TL 请求审批实现计划
plan_approval_response TL Worker 批准/拒绝计划
mode_set_request TL Worker 变更 Worker 权限模式
idle_notification Worker TL 成员完成工作,进入空闲

7.5 SendMessage 工具使用

// 普通消息(必须提供 summary)
SendMessage({
  type: "message",
  recipient: "worker",
  content: "请实现用户登录功能,保存到 src/auth/login.ts",
  summary: "分配登录功能实现任务"
})

// 广播(每个成员一次 API 调用,慎用)
SendMessage({
  type: "broadcast",
  content: "发现严重 bug,请所有人暂停当前工作",
  summary: "紧急暂停通知"
})

// TL 请求成员关闭
SendMessage({
  type: "shutdown_request",
  recipient: "worker",
  content: "所有任务已完成,请安全退出"
})

// Worker 批准关闭(执行后 process.exit(0))
SendMessage({ type: "shutdown_response", request_id: "req-xxx", approve: true })

// Worker 拒绝关闭
SendMessage({
  type: "shutdown_response",
  request_id: "req-xxx",
  approve: false,
  content: "Task #3 尚未完成,需要约 10 分钟"
})

// TL 审批 Worker 的 plan(plan_mode_required 场景)
SendMessage({
  type: "plan_approval_response",
  recipient: "worker",
  request_id: "req-xxx",
  approved: true
})

7.6 Shutdown 完整流程

TL                                      Worker
 │                                        │
 ├─ SendMessage(shutdown_request) ──────→ │
 │   writeToMailbox(worker inbox)         │
 │                                        │  (500ms 轮询)
 │                                        ├─ 检测到 shutdown_request
 │                                        ├─ markMessageAsReadByIndex()
 │                                        ├─ 包装为 <teammate-message> XML
 │                                        ├─ executor.chat(xml) → 交给 LLM
 │                                        │  LLM 决定同意并调用 SendMessage
 │ ←─ writeToMailbox(team-lead, approved) ┤
 │                                        ├─ process.exit(0)  💀 进程退出
 │                                        │
 ├─ 下次 chat() 前 _pollMailbox()          │
 ├─ 收到 shutdown_approved               │
 └─ removeTeamMember() 从 config 删除     │

设计原则:LLM 是中间人——shutdown_request 不直接杀进程,让 LLM 优雅同意后再退出,给 LLM 机会做最后汇报。

双保险机制src/tools/team.ts + src/teams/config.ts):

  1. 主路径:Worker process.exit(0)writeToMailbox 之后立即调用)
  2. Fallback:PID 存储在 team config(TeamMember.pid 字段),TL 可 process.kill(pid, 'SIGTERM')

7.7 存活感知

原码无显式心跳机制,依赖三层被动感知:

层次 机制 触发时机 适用模式
被动通知 Worker 完成后发 idle_notification 每轮工作结束 全部
AppState 直读 TL 直接检查 status/isIdle 任意时刻 in-process 专属
异常捕获 抛异常 → status="failed" → 发通知 进程异常 全部

idle_notification 格式(cE7() cli.renamed.js:316061):

{
  "type": "idle_notification",
  "from": "worker",
  "idleReason": "available"
}

idleReason 可选值:"available"(正常空闲)、"interrupted"(被中断)、"failed"(异常退出)

7.8 Task 看板

每个 Task 存储为独立 JSON 文件(~/.claude/tasks/{team}/{id}.json):

{
  "id": "1",
  "subject": "实现登录功能",
  "description": "详细要求和验收条件...",
  "status": "in_progress",
  "owner": "worker-1",
  "blocks": ["3"],
  "blockedBy": [],
  "activeForm": "实现登录功能中"
}

status 流转pending → in_progress → completeddeleted 永久删除)

关联成员:成员调用 TaskUpdate(taskId, owner="自己的名字") 认领任务。

外部查看看板

for f in ~/.claude/tasks/my-team/*.json; do
  python3 -c "
import json; d=json.load(open('$f'))
icon={'completed':'✅','in_progress':'🔄','pending':'⏳'}.get(d['status'],'?')
owner=f\" [{d['owner']}]\" if d.get('owner') else ''
print(f\"{icon} #{d['id']} {d['subject']}{owner}\")
"
done

7.9 重启已关闭成员

成员 shutdown 后从 config 完全删除pJ_() cli.renamed.js:185742,filter 而非标记 inactive):

shutdown → 成员从 members[] 删除
    ↓
Agent(name="worker", team_name="myteam")
    ↓
sxq() 检查 members:已删除 → 无冲突 → 用原名 "worker"
    ↓
新进程,新 agentId,全新 session

同 session 中未关闭即再 spawn 同名sxq() 自动递增 → worker-2worker-3


第 8 章:Agent 系统

8.1 Agent 定义文件(.claude/agents/)

文件格式(YAML Frontmatter + Markdown):

---
name: code-reviewer
description: 审查代码质量、设计合理性和潜在风险
model: sonnet
tools:
  - Read
  - Grep
  - Bash
disallowedTools:
  - Write
  - Edit
memory: user
permissionMode: dontAsk
maxTurns: 30
---

## 你的角色

你是一位严格的代码审查专家...

Frontmatter 字段说明

字段 类型 必须 说明
name string :white_check_mark: Agent 类型标识符
description string :white_check_mark: 用途描述
model enum :x: haiku/sonnet/inherit/完整 modelId
tools string[] :x: 允许工具列表(["*"] = 全部)
disallowedTools string[] :x: 明确禁止的工具
memory enum :x: user/project/local
permissionMode enum :x: dontAsk/plan/bypassPermissions
maxTurns number :x: 最大对话轮数
isolation enum :x: worktree(独立 git worktree)

加载优先级(低→高,bh() cli.renamed.js:211088):

built-in → plugin → ~/.claude/agents/ → ./.claude/agents/ → flags/policy

同名 Agent 高优先级覆盖低优先级,支持项目级定义覆盖内置行为。

8.2 Agent 专属记忆(agent-memory/)

每个 agentType 独立的记忆目录,不同于共享的 CLAUDE.md(LJ_() cli.renamed.js:183997):

memory 路径 特点
user ~/.claude/agent-memory/{agentType}/ 跨项目持久化
project ./.claude/agent-memory/{agentType}/ 项目级,可 git 追踪
local ./.claude/agent-memory-local/{agentType}/ 本地临时,不追踪
  • 目录中的 CLAUDE.md 注入到 Agent 系统提示末尾(wR_() cli.renamed.js:184034)
  • agentType 中的 : 替换为 - 作为目录名
  • 默认不加载,需在定义文件中显式配置 memory:

8.3 主会话 vs 子 Agent 系统提示对比

特性 主会话 子 Agent
系统提示来源 buildMainSystemPrompt()(完整) buildSubagentSystemPrompt()(精简)
项目 CLAUDE.md :white_check_mark: 自动加载 :x: 不加载
工具列表说明 :white_check_mark: 完整包含 :x: 不包含
专属定义文件 .claude/agents/{type}.md
持久记忆 ~/.claude/CLAUDE.md .claude/agent-memory/{type}/CLAUDE.md
工具限制 无(继承父会话) 可通过定义文件限制

子 Agent 系统提示格式src/tools/agent.ts:buildSubagentSystemPrompt):

You are a sub-agent launched by Claude Code to complete a specific task.
[You are a specialised {subagent_type} agent.]
Complete the assigned task thoroughly, using available tools as needed.
When done, provide a concise summary of what you accomplished.
[{agent-memory 内容,如配置了 memory: 字段}]

8.4 subagent_type 使用

// 内置只读类型:限制写入工具,专注探索
Agent({ subagent_type: "Explore", prompt: "搜索所有 REST API 端点" })

// 通用类型:全工具权限
Agent({ subagent_type: "general-purpose", prompt: "实现用户认证模块" })

// 自定义类型(需在 .claude/agents/code-reviewer.md 中定义)
Agent({ subagent_type: "code-reviewer", prompt: "审查最近提交的代码变更" })
// → 应用定义文件中的工具限制 + 自定义系统提示

8.5 子 Agent 会话隔离

每个子 Agent 有独立的 JSONL 会话文件:

~/.claude/projects/{pw(cwd)}/{parentSessionId}/subagents/agent-{agentId}.jsonl
  • 完全独立的 ConversationExecutor 实例,不共享父会话消息历史
  • agentId 格式:"a" + 16位十六进制(如 a1b2c3d4e5f6a7b8
  • spawn 时写入元数据文件:agent-{agentId}.meta.json{"agentType": "general-purpose"}