Compare commits

..

10 Commits

Author SHA1 Message Date
Shangding Gu
53faa8b216 Fix links in README for analysis documents
Updated links in the README to point to the correct file paths.
2026-04-04 17:30:24 -07:00
Shangding Gu
da51538b92 Fix links and add note in README.md
Updated links in the README to point to the correct locations and added a note about the original analysis material.
2026-04-04 17:29:23 -07:00
Shangding Gu
ed870e0ece Update news section with Chinese documentation link 2026-04-04 09:55:00 -07:00
Shangding Gu
ab169fda98 Update news section with latest entries 2026-04-04 09:50:33 -07:00
Shangding Gu
ab515aedd6 Revise analysis section with link and summary
Updated the analysis section to include a link to the documents and removed the detailed list of individual analyses.
2026-04-04 09:49:43 -07:00
Shangding Gu
49234517b8 Update README with analysis documents for Claude Code
Added detailed analysis documents and notes for Claude Code, including context management, multi-agent architecture, and memory systems.
2026-04-04 09:47:51 -07:00
Chauncygu
7f33e40f22 add claude code analysis 20260404 2026-04-04 09:43:49 -07:00
Chauncygu
23ae8ec64b add claude code analysis 20260404 2026-04-04 09:43:09 -07:00
Shangding Gu
a8bcdfbe2e Clarify source archive description in README
Updated description to clarify repository contents.
2026-04-03 18:17:17 -07:00
Shangding Gu
fa8e3d407d Revise README-CN with latest updates and project details
Updated README-CN.md to include recent developments and project comparisons.
2026-04-03 10:42:31 -07:00
15 changed files with 5281 additions and 26 deletions

View File

@@ -1,23 +1,96 @@
# claude-code-source-code
# Claude Code 开源代码合集
> Claude Code 源码档案与 Python 重写的研究仓库
本仓库包含两个子项目,从不同角度对 Claude CodeAnthropic 官方 CLI 工具)进行深度研究:
## 🔥🔥🔥 最新动态(太平洋时间)
| 子项目 | 语言 | 性质 | 文件数 |
|--------|------|------|--------|
| [claude-code-source-code](#一-claude-code-source-code) | TypeScript | 反编译源码档案v2.1.88 | 1,884 个 |
| [claw-code](#二-claw-code) | Python | 清室架构重写 | 66 个 |
- 2026年4月2日 12:20[Nano Claude Code v3.0多智能体包multi_agent/、记忆包memory/、技能包skill/内置技能、参数替换、fork/inline 执行、AI 记忆搜索、git worktree 隔离、代理类型定义(~5000 行 Python](https://github.com/SafeRL-Lab/nano-claude-code)
- 2026年4月2日 07:40[Nano Claude Code v2.0:最小 Python 重实现(~3400 行),支持开源与闭源模型、技能与记忆](https://github.com/SafeRL-Lab/nano-claude-code)
- 2026年4月1日 08:36[Nano Claude Code v1.0:最小 Python 重实现(~1300 行)](https://github.com/SafeRL-Lab/nano-claude-code)
- 2026年4月1日 00:20[Claude Code 源码解析(视频:中文)](https://www.youtube.com/watch?v=xsg6_Gvr2J0&t=10s)
- 2026年3月31日 19:45[Claude Code 研究报告(中文)](https://github.com/chauncygu/collection-claude-code-source-code/blob/main/docs/claude-code-deep-dive-xelatex.pdf)
- 2026年3月31日 17:13[Claude Code 架构分析(中文)](https://mp.weixin.qq.com/s?__biz=MzI0ODk2NDIyMQ==&mid=2247502519&idx=1&sn=1072dd7a822a78709bc7cc3bf0e1dcc2&chksm=e8de6705e2bacc854211663aa02903738560f9e858eb6ce72b94c32fdbf67917badfab2d6536&mpshare=1&scene=1&srcid=0401KpkqfaXFBReRof6AwJ74&sharer_shareinfo=30fa54f1602d1d8bb1a65e7008074e08&sharer_shareinfo_first=30fa54f1602d1d8bb1a65e7008074e08#rd)
- 2026年3月31日 16:43[Claude Code 功能全览(中文)](https://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666572944&idx=1&sn=c54e34711e67a2e961acb341f51d2190&chksm=81ca164af949bdfe90a616c8ef8d7e729116a4a12a480cd9d012f42f5b8d7ecd6d05e284db09&mpshare=1&scene=1&srcid=04017JkKs9qrCh4AHcfZq7qL&sharer_shareinfo=95eb268167dd1b3d98271b8b26e7553e&sharer_shareinfo_first=95eb268167dd1b3d98271b8b26e7553e#rd)
- 2026年3月31日 15:00[Hacker News 社区关于 Claude Code 泄露的讨论](https://news.ycombinator.com/item?id=47586778)
- 2026年3月31日 11:48[Anthropic 如何为 Claude Code 构建 7 层记忆与梦境系统](https://x.com/troyhua/status/2039052328070734102)
- 2026年3月31日 09:50[Claude Code 记忆系统解析](https://x.com/henryl_ai/status/2039022608310808965)
- 2026年3月31日 09:48[Claude Code 源代码疑似泄露:我们目前所知道的](https://venturebeat.com/technology/claude-codes-source-code-appears-to-have-leaked-heres-what-we-know)
- 2026年3月31日 09:04[拆解 Claude Code 架构(中文)](https://mp.weixin.qq.com/s?__biz=MzA3NzUxMzM5MQ==&mid=2453898430&idx=1&sn=1c4051fb17a15b17e449b7eb85d3e1c5&chksm=897cc501d472cdd6916679a0766ab146b5347bc78e48171d9da97de282a05c10eea8d22c3605&mpshare=1&scene=1&srcid=0401oXuLa2VmhvrcRZk7VHfH&sharer_shareinfo=e7ff02258e887208db510104bc343079&sharer_shareinfo_first=6c39c564855be1e2372289b5c09b6247#rd)
- 2026年3月31日 07:07[逐步解读 Claude Code 源码(中文)](https://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655937729&idx=1&sn=0afb97062ef5f229910e3e54dd36abb6&chksm=bc66bca5b0f4171b56075506f208efea18381031c5ffa33070701ee1200bef7e411ea10188e9&mpshare=1&scene=1&srcid=0331PBEUSD8CVryQYEluyZbc&sharer_shareinfo=c5a329d2cc3ec432238f5fc1d9d70723&sharer_shareinfo_first=c5a329d2cc3ec432238f5fc1d9d70723#rd)
- 2026年3月31日 05:41[Claude Code 为何优于其他工具:深度分析](https://x.com/YukerX/status/2038959908968919297)
- 2026年3月31日 05:03[Anthropic AI 编程工具再次泄露自身源代码](https://www.ndtv.com/science/anthropics-ai-coding-tool-leaks-its-own-source-code-for-the-second-time-in-a-year-11291517)
- 2026年3月31日 03:28[Claude Code 源码曝光:提示词、自愈机制与多代理架构(中文)](https://mp.weixin.qq.com/s?__biz=MzI3ODY3ODg2Nw==&mid=2247484425&idx=1&sn=f77d3b97e88cb8019f014ca2eb95db65&chksm=ea98ee5bb2249e1c637520cf02b525b98b434671f2cc23ec554e5faa868e890deeead939c578&mpshare=1&scene=1&srcid=0401kVgDQ41tx7AECPzvch3W&sharer_shareinfo=5d97c04d957d52383c9b59245e421c5a&sharer_shareinfo_first=5d97c04d957d52383c9b59245e421c5a#rd)
- 2026年3月31日 03:02[社区对 Claude Code 源码曝光的反应](https://x.com/hank_aibtc/status/2038919948370616330)
- 2026年3月31日 02:57[Claude Code 背后的代码](https://x.com/mal_shaik/status/2038918662489510273)
- 2026年3月31日 01:23[关于 Claude Code 源码泄露的病毒式传播帖子](https://x.com/Fried_rice/status/2038894956459290963?s=20)
---
## 一、claude-code-source-code
## 目录
Claude Code v2.1.88 的反编译/解包源码,从 npm 包 `@anthropic-ai/claude-code@2.1.88` 还原,约 163,318 行 TypeScript 代码。
- [一、original-source-code](#一original-source-code)
- [二、claude-code-source-code](#二claude-code-source-code)
- [整体架构](#整体架构)
- [核心执行流程](#核心执行流程)
- [技术栈](#技术栈)
- [主要模块说明](#主要模块说明)
- [工具系统40+ 工具)](#工具系统40-工具)
- [斜杠命令(~87 个)](#斜杠命令87-个)
- [权限系统](#权限系统)
- [上下文管理](#上下文管理)
- [分析文档docs/](#分析文档docs)
- [三、claw-code](#三claw-code)
- [整体架构](#整体架构-1)
- [核心类](#核心类)
- [CLI 命令](#cli-命令)
- [设计特点](#设计特点)
- [四、nano-claude-code](#四nano-claude-code)
- [功能特性](#功能特性)
- [支持的模型](#支持的模型)
- [项目结构](#项目结构)
- [四个项目对比](#四个项目对比)
- [许可与声明](#许可与声明)
---
本仓库包含四个子项目,从不同角度对 Claude CodeAnthropic 官方 CLI 工具)进行深度研究:
| 子项目 | 语言 | 性质 | 文件数 |
|--------|------|------|--------|
| [original-source-code](#一original-source-code) | TypeScript | 原始泄露源码档案 | 1,884 个 |
| [claude-code-source-code](#二claude-code-source-code) | TypeScript | 反编译源码档案v2.1.88+ 文档 | 1,940 个 |
| [claw-code](#三claw-code) | Python | 清室架构重写 | 109 个 |
| [nano-claude-code](#四nano-claude-code) | Python | 最小化多模型提供商重实现 | ~30 个 |
---
## 一、original-source-code
2026 年 3 月 31 日原始泄露的 Claude Code TypeScript 源码,按原始状态完整保存。包含 1,884 个 TypeScript/TSX 文件(打包为 `src.zip`,约 9.5MB),覆盖完整的 `src/` 目录树——正是这批文件引发了社区讨论和后续研究。
```text
original-source-code/
├── src/ # 完整 TypeScript 源码树1,884 个 .ts/.tsx 文件)
│ ├── main.tsx # CLI 入口
│ ├── query.ts # 核心代理循环
│ ├── commands.ts # 斜杠命令定义
│ ├── tools.ts # 工具注册
│ └── ... # 其余所有源码目录(与 claude-code-source-code/src 结构相同)
├── src.zip # 压缩档案(~9.5MB
└── readme.md
```
此目录作为未修改的原始参考快照保存,未添加任何注释、文档或构建工具。如需研究注解版本,请使用 `claude-code-source-code`
---
## 二、claude-code-source-code
Claude Code v2.1.88 的反编译/解包源码,从 npm 包 `@anthropic-ai/claude-code@2.1.88` 还原,约 163,318 行 TypeScript 代码,并附有深度分析文档。
### 整体架构
```
```text
claude-code-source-code/
├── src/
│ ├── main.tsx # CLI 入口与 REPL 引导4,683 行)
@@ -63,7 +136,7 @@ claude-code-source-code/
### 核心执行流程
```
```text
用户输入
processUserInput() # 解析 /slash 命令
@@ -138,13 +211,13 @@ yield SDKMessage # 流式返回给消费者
---
## 、claw-code
## 、claw-code
对 Claude Code 的 Python 清室重写(不包含原始代码副本),专注于架构镜像与研究。由 [@instructkr](https://github.com/instructkr)Sigrid Jin完成成为全球最快达到 30K stars 的 GitHub 仓库之一。
### 整体架构
```
```text
claw-code/
├── src/
│ ├── __init__.py # 包导出接口
@@ -244,25 +317,142 @@ tool-pool # 工具池组装视图
- **快照驱动**:通过 JSON 快照文件加载命令/工具元数据,无需完整实现逻辑
- **清室重写**:不包含原始 TypeScript 代码,独立实现
- **奇偶审计**:内置 `parity_audit.py` 追踪与原实现的差距
- **轻量架构**66 个文件实现核心框架,适合学习与扩展
- **轻量架构**109 个文件实现核心框架,适合学习与扩展
---
## 两个项目对比
## 四、nano-claude-code
| 维度 | claude-code-source-code | claw-code |
|------|------------------------|-----------|
| 语言 | TypeScript | Python |
| 代码量 | ~163,000 行 | ~5,000 行 |
| 性质 | 反编译源码档案 | 清室架构重写 |
| 功能完整度 | 完整100% | 架构框架(~20% |
| 核心循环 | `query.ts`785KB | `QueryEnginePort`~200 行) |
| 工具系统 | 40+ 完整实现 | 快照元数据 + 执行框架 |
| 命令系统 | ~87 个完整实现 | 快照元数据 + 执行框架 |
| 主要用途 | 深度学习完整实现细节 | 架构理解、移植研究 |
Claude Code 的最小化可运行 Python 重实现(~5,000 行)。与专注架构映射的 `claw-code` 不同nano-claude-code 是一个真正可立即使用的编程助手。支持 20+ 闭源模型和本地开源模型,已从 ~900 行原型成长为具备多智能体编排、持久记忆和技能系统的 v3.0 版本。
### 功能特性
| 功能 | 详情 |
|------|------|
| 多模型提供商 | Anthropic · OpenAI · Gemini · Kimi · Qwen · Zhipu · DeepSeek · Ollama · LM Studio · 自定义端点 |
| 交互式 REPL | readline 历史、Tab 补全斜杠命令 |
| 代理循环 | 流式 API + 自动工具调用循环 |
| 18 个内置工具 | Read · Write · Edit · Bash · Glob · Grep · WebFetch · WebSearch · MemorySave · MemoryDelete · MemorySearch · MemoryList · Agent · SendMessage · CheckAgentResult · ListAgentTasks · ListAgentTypes · Skill · SkillList |
| Diff 视图 | Edit 和 Write 操作的 Git 风格红绿差异显示 |
| 上下文压缩 | 自动压缩长对话,保持在模型上下文限制内 |
| 持久记忆 | 双作用域记忆(用户 + 项目4 种类型AI 搜索,过期警告 |
| 多智能体 | 生成类型化子代理coder/reviewer/researcher/…git worktree 隔离,后台模式 |
| 技能系统 | 内置 `/commit` · `/review` + 支持参数替换和 fork/inline 执行的自定义 Markdown 技能 |
| 插件工具 | 通过 `tool_registry.py` 注册自定义工具 |
| 权限系统 | `auto` / `accept-all` / `manual` 三种模式 |
| 17 个斜杠命令 | `/model` · `/config` · `/save` · `/cost` · `/memory` · `/skills` · `/agents` · … |
| 上下文注入 | 自动加载 `CLAUDE.md`、git 状态、当前目录、持久记忆 |
| 会话持久化 | 保存/加载对话至 `~/.nano_claude/sessions/` |
| 扩展思考 | 开启/关闭(仅限 Claude 模型) |
| 成本追踪 | Token 用量 + 估算 USD 费用 |
| 非交互模式 | `--print` 参数用于脚本/CI 场景 |
### 支持的模型
**闭源API** ClaudeAnthropic、GPT / o 系列OpenAI、GeminiGoogle、KimiMoonshot AI、Qwen阿里云百炼、GLM智谱、DeepSeek
**开源(本地,通过 Ollama** llama3.3/3.2、qwen2.5-coder、deepseek-r1、phi4、mistral、mixtral、gemma3、codellama 及 `ollama list` 中的任意模型
**自托管:** vLLM、LM Studio 或任何通过 `CUSTOM_BASE_URL` 配置的 OpenAI 兼容端点
### 项目结构
```text
nano-claude-code/
├── nano_claude.py # 入口REPL + 斜杠命令 + 渲染 (~748 行)
├── agent.py # 代理循环:消息格式 + 工具分发 (~174 行)
├── providers.py # 多提供商适配器 + 消息格式转换 (~507 行)
├── tools.py # 工具分发 + 所有包的自动注册 (~467 行)
├── tool_registry.py # 中央工具注册表 + 插件入口 (~98 行)
├── context.py # 系统提示构建CLAUDE.md + git + 记忆 (~135 行)
├── compaction.py # 上下文压缩auto-compact (~196 行)
├── config.py # 配置加载/保存/默认值 (~72 行)
├── memory.py # 向后兼容 shim → memory/
├── skills.py # 向后兼容 shim → skill/
├── subagent.py # 向后兼容 shim → multi_agent/
├── memory/ # 持久记忆包
│ ├── store.py # 记忆条目的保存/加载/删除/搜索
│ ├── scan.py # 索引扫描、新鲜度助手
│ ├── context.py # 系统提示注入 + AI 排名搜索
│ ├── types.py # MEMORY_TYPES 定义
│ └── tools.py # MemorySave · MemoryDelete · MemorySearch · MemoryList
├── skill/ # 技能系统包
│ ├── loader.py # SkillDef、文件解析、参数替换
│ ├── builtin.py # 内置技能:/commit、/review
│ ├── executor.py # inline + fork 执行模式
│ └── tools.py # Skill · SkillList
├── multi_agent/ # 多智能体编排包
│ ├── subagent.py # AgentDefinition、SubAgentTask、SubAgentManager、worktree 工具
│ └── tools.py # Agent · SendMessage · CheckAgentResult · ListAgentTasks · ListAgentTypes
├── tests/ # 101 个测试monkeypatch不触碰真实 ~/.nano_claude/
├── docs/ # 文档与演示素材
└── requirements.txt
```
**快速开始:**
```bash
pip install anthropic openai httpx rich
export ANTHROPIC_API_KEY=sk-ant-...
python nano_claude.py
# 启动时切换模型
python nano_claude.py --model gpt-4o
python nano_claude.py --model ollama/qwen2.5-coder
# 非交互 / CI 场景
python nano_claude.py --print "写一个 Python 斐波那契函数" --accept-all
```
**记忆**——跨会话持久化,双作用域(用户 `~/.nano_claude/memory/` 和项目 `.nano_claude/memory/`
```
/memory # 列出所有记忆(含新鲜度信息)
MemorySave(name="...", type="feedback", content="...", scope="user")
MemorySearch(query="...", use_ai=True)
```
**技能**——可复用提示模板,在 REPL 中直接调用:
```
/commit # 内置:审查暂存变更并创建 git commit
/review 123 # 内置:审查 PR #123
/skills # 列出所有可用技能及触发词和参数提示
```
**多智能体**——生成类型化子代理,支持可选的 git worktree 隔离:
```
Agent(prompt="...", subagent_type="coder", isolation="worktree", wait=False)
SendMessage(agent_name="my-agent", message="...")
/agents # 显示所有活跃和已完成的子代理任务
```
---
## 四个项目对比
| 维度 | original-source-code | claude-code-source-code | claw-code | nano-claude-code |
|------|---------------------|------------------------|-----------|-----------------|
| 语言 | TypeScript | TypeScript | Python | Python |
| 代码量 | ~163,000 行 | ~163,000 行 + 文档 | ~5,000 行 | ~5,000 行 |
| 性质 | 原始泄露源码档案 | 反编译源码档案 + 分析 | 清室架构重写 | 最小化功能重实现 |
| 功能完整度 | 完整100% | 完整100% | 架构框架(~20% | 核心循环 + 记忆 + 多智能体 + 技能 |
| 核心循环 | `query.ts`785KB | `query.ts`785KB | `QueryEnginePort`~200 行) | `agent.py`~174 行) |
| 工具系统 | 40+ 完整实现 | 40+ 完整实现 | 快照元数据 + 执行框架 | 18 个完整实现 + 插件注册表 |
| 记忆系统 | 是7 层,复杂) | 是7 层,复杂) | 否 | 是双作用域4 类型AI 搜索) |
| 多智能体 | 是(完整协调器) | 是(完整协调器) | 否 | 是类型化代理worktree 隔离) |
| 技能系统 | 是(~87 个命令) | 是(~87 个命令) | 仅快照元数据 | 是(内置 + 自定义 Markdown 技能) |
| 多模型提供商 | 否(仅 Anthropic | 否(仅 Anthropic | 否 | 是10+ 提供商) |
| 可立即运行 | 否 | 否 | 有限(仅 CLI 元数据) | 是 |
| 主要用途 | 原始参考快照 | 深度学习完整实现细节 | 架构理解、移植研究 | 轻量级全功能编程助手 |
---
## 许可与声明
本仓库仅供学术研究与教育目的使用。两个子项目均基于公开可获取的信息构建。使用者应自行遵守相关法律法规及服务条款。
本仓库仅供学术研究与教育目的使用。所有子项目均基于公开可获取的信息构建。使用者应自行遵守相关法律法规及服务条款。

View File

@@ -1,9 +1,10 @@
# A collection of the newest Claude Code open source
> Source archive of Claude Code and a clean-room Python rewrite research repository
> Source archive of Claude Code and different versions of the clean-room Python rewrite research repository
## 🔥🔥🔥 News (Pacific Time)
- 9:50 AM · Apr 04, 2026: [Deep-dive analysis docs added (In Chinese): context compression, multi-agent architecture, memory system, hidden features, model-switching, rollback mechanism, effort level, and tracking-data cleanup guide](#5-docscc_analysis)
- 12:20 PM · Apr 02, 2026: [Nano Claude Code v3.0: Multi-agent packages, memory package, skill package with built-in skills, argument substitution, fork/inline execution, AI memory search, git worktree isolation, agent type definitions (~5000 Lines)](https://github.com/SafeRL-Lab/nano-claude-code)
- 7:40 AM · Apr 02, 2026: [Nano Claude Code v2.0: A Minimal Python Reimplementation (~3400 Lines), support open and closed source models, skill and memory](https://github.com/SafeRL-Lab/nano-claude-code)
- 8:36 AM · Apr 01, 2026: [Nano Claude Code v1.0: A Minimal Python Reimplementation (~1300 Lines)](https://github.com/SafeRL-Lab/nano-claude-code)
@@ -48,6 +49,7 @@
+ [Features](#features)
+ [Supported Models](#supported-models)
+ [Project Structure](#project-structure)
* [5. docs/cc\_analysis](#5-docscc_analysis)
* [Comparison of the Projects](#comparison-of-the-projects)
* [License and Disclaimer](#license-and-disclaimer)
@@ -437,6 +439,14 @@ SendMessage(agent_name="my-agent", message="...")
/agents # show all active and finished sub-agent tasks
```
---
## 5. docs/cc\_analysis
Analysis documents produced from the leaked Claude Code source snapshot (2026-03-31). All documents are based on the TypeScript source and are primarily written in Chinese, see [here](https://github.com/chauncygu/collection-claude-code-source-code/tree/main/docs/cc_analysis/analysis_20260401).
---
## Comparison of the Projects

View File

@@ -0,0 +1,38 @@
# Claude Code 默认 Effort Level 设置为 Max
## 问题
`/effort max` 命令只对当前会话生效,重启 Claude Code 后会恢复为默认的 `medium`
## 解决方案
`~/.zshrc` 中添加环境变量:
```bash
export CLAUDE_CODE_EFFORT_LEVEL=max
```
新开终端窗口后自动生效。
## 为什么不能用 settings.json
Claude Code 的 `~/.claude/settings.json` 支持 `effortLevel` 字段,但只接受 `low``medium``high` 三个值。`max` 是 Opus 4.6 专属的深度推理模式,只能通过环境变量持久化。
## Effort Level 一览
| 级别 | 说明 |
|------|------|
| `low` | 快速响应,适合简单问答 |
| `medium` | 默认级别 |
| `high` | 更深入的推理 |
| `max` | 最深度推理,无 token 限制(仅 Opus 4.6 |
## 其他设置方式
- **启动参数**(单次):`claude --effort max`
- **会话内**(单次):`/effort max`
- **环境变量**(永久):`export CLAUDE_CODE_EFFORT_LEVEL=max` ← 推荐
---
*记录于 2026-03-30*

View File

@@ -0,0 +1,150 @@
# Claude Code 自动回滚机制解析与版本切换指南
> 日期2026-03-31
## 背景
Claude Code 从 v2.1.88 自动回滚到 v2.1.87,本文记录了完整的排查过程和解决方案。
## 回滚原因
**Anthropic 在 npm 做了服务端回滚**,不是本地触发的。
### npm Registry 状态
| dist-tag | 版本 |
|----------|------|
| `stable` | 2.1.81 |
| `latest` | 2.1.87 |
| `next` | 2.1.89 |
- v2.1.88 **已被完全从 npm 删除**registry 中不存在)
- `latest` tag 从 2.1.88 退回到 2.1.87
### 时间线
| 时间 | 事件 |
|------|------|
| Mar 28 19:25 | 自动更新下载 v2.1.87 |
| Mar 30 18:31 | 自动更新下载 v2.1.88 |
| Mar 30 ~ Mar 31 | Anthropic 从 npm 撤掉 v2.1.88,将 `latest` tag 退回 v2.1.87 |
| Mar 31 05:59 | 自动更新器检查 npm registry发现 `latest` 是 2.1.87,将 symlink 切回 |
## 自动更新机制
### 核心架构
```
~/.local/bin/claude → symlink → ~/.local/share/claude/versions/{version}
```
- 包名:`@anthropic-ai/claude-code`
- 版本二进制存储:`~/.local/share/claude/versions/`
- 入口 symlink`~/.local/bin/claude`
### AutoUpdater 工作流程
1. 每次 Claude Code 启动时AutoUpdater 检查 npm registry 的 `latest` dist-tag
2. 如果本地版本与 `latest` 不匹配,下载目标版本二进制到 `versions/` 目录
3. 更新 symlink 指向新版本
4. 逻辑是**跟随 `latest` tag**,不是单调递增 — 所以 Anthropic 退 tag 就等于回滚
### 关键发现
- 二进制是 Bun 编译的 Mach-O arm64 可执行文件
- 内部包含 `auto_updater_disabled``AutoUpdater``autoUpdaterStatus` 等标识
- 启动遥测会上报 `auto_updater_disabled` 状态
- 并发更新有互斥锁保护("Another instance is currently performing an update"
## 禁用自动更新的正确方式
通过逆向二进制中的 `h1H()` / `isAutoUpdaterDisabled` 函数,确认自动更新器的检查逻辑:
```javascript
// 反编译后的禁用检查逻辑(简化)
function getAutoUpdaterDisabledReason() {
if (process.env.DISABLE_AUTOUPDATER) return { type: "env" };
if (config.autoUpdates === false) return { type: "config" };
return null; // 未禁用,自动更新正常运行
}
```
### 踩坑记录
`autoUpdaterDisabled: true` 是**错误的 key**,写了不生效,自动更新器仍会在启动时抢先将 symlink 切回 `latest` 指向的版本。
### 方法 A环境变量推荐最可靠
```bash
# 加到 ~/.zshrc每次 shell 启动自动生效
echo 'export DISABLE_AUTOUPDATER=1' >> ~/.zshrc
source ~/.zshrc
```
### 方法 Bsettings.json
编辑 `~/.claude/settings.json`,注意 key 是 `autoUpdates`
```json
"autoUpdates": false
```
> 注意:对于 native 安装方式,如果同时设置了 `autoUpdatesProtectedForNative: true`,则 `autoUpdates: false` 会被覆盖,此时只能用环境变量方式。
## 解决方案:切回 v2.1.88
### 步骤 1禁用自动更新
```bash
# 确保环境变量已生效
export DISABLE_AUTOUPDATER=1
```
### 步骤 2切换 symlink
```bash
ln -sf ~/.local/share/claude/versions/2.1.88 ~/.local/bin/claude
```
### 步骤 3验证
```bash
claude --version
# 输出2.1.88 (Claude Code)
```
### 步骤 4使用
```bash
claude --dangerously-skip-permissions
```
## 恢复自动更新
```bash
# 1. 从 ~/.zshrc 删掉 export DISABLE_AUTOUPDATER=1
# 2. 如果用了方法 B从 settings.json 删掉 "autoUpdates": false
# 3. 重启终端,自动更新器会在下次启动时恢复工作
```
## 其他版本切换方式
```bash
# 切到 next channel (v2.1.89)
claude update --channel next
# 切到 stable channel (v2.1.81)
claude update --channel stable
# 查看本地已有的版本
ls ~/.local/share/claude/versions/
# 手动切换到任意本地版本
ln -sf ~/.local/share/claude/versions/<版本号> ~/.local/bin/claude
```
## 注意事项
- v2.1.88 被 Anthropic 从 npm 删除,可能存在已知问题
- 禁用自动更新后不会收到安全修复,需定期手动检查
- 本地残留的 v2.1.88 二进制不会被自动清理

View File

@@ -0,0 +1,297 @@
# Claude Code 上下文管理算法学习笔记
> 来源Claude Code 源码快照2026-03-31
> 核心文件:`src/query.ts`, `src/services/compact/`, `src/utils/toolResultStorage.ts`
---
## 架构总览7 层递进式防御
每轮 query loop 按以下顺序执行,从便宜到昂贵,每一层减轻压力,可能阻止下一层触发:
```
1. Tool Result Budget ← 单轮预算(同步,零 API 调用)
2. Snip Compact ← 历史裁剪(零 API 调用)
3. Microcompact ← 工具结果精细清理(零或极低 API 成本)
4. Context Collapse ← 增量投影摘要(零 API 调用)
5. Auto-Compact ← LLM 全量摘要(昂贵)
6. Blocking Limit ← 硬停(所有自动措施关闭时)
7. Reactive Compact ← 413 错误后紧急摘要(最后手段)
```
互斥门控防止昂贵操作竞争Context Collapse 启用时抑制 Auto-CompactReactive Compact 实验模式抑制主动 Auto-Compact。
---
## 第 1 层Tool Result Budget — 单轮聚合预算
**问题**N 个并行工具可能在一轮中集体产生超大上下文。
**三分区算法**
| 分区 | 含义 | 处理 |
|------|------|------|
| mustReapply | 之前已替换过的结果 | 直接重用缓存的替换字符串(零 I/O字节级一致 |
| frozen | 之前见过但没替换 | 永不替换(保护 prompt cache |
| fresh | 新结果 | 参与预算分配 |
**阈值**
- 总预算200K 字符/消息(远程可配置)
- 单工具上限50K 字符(默认)
- 超出时:保留前 ~2KB 预览 + 持久化到磁盘,模型可用 Read 按需读取
**核心洞察**frozen 分区 — 宁可浪费空间也不破坏缓存命中率。**Prompt cache 稳定性优先于空间效率**。
---
## 第 2 层Snip Compact — 历史裁剪
**特点**:零 API 调用,直接删除旧消息。
**协调机制**snipTokensFreed 传递给下游层,因为 tokenCountWithEstimation 读的是上一轮 API 返回的 input_tokens反映 snip 前的数值),需要手动减去 snip 释放的量。
**双视图**REPL 保留被 snip 的消息用于 UI 回滚,但投影层在发送 API 前过滤掉它们。
---
## 第 3 层Microcompact — 三种精细清理路径
### 3a. 基于时间的清理
```
触发条件:距上次助手消息 > 60 分钟(= 服务端 cache TTL
逻辑cache 已过期 → 全量前缀会被重写 → 趁机清理旧工具结果
行为:替换为 "[Old tool result content cleared]"
保留:最近 5 个结果
```
**洞察**:利用缓存 TTL 过期的"免费窗口"搭车做清理。
### 3b. 缓存编辑Cache Editing— 最精妙的设计
```
触发条件:可压缩工具结果数超过阈值
关键创新:不修改本地消息!使用 API 的 cache_edits / cache_reference 机制
效果:服务端缓存被精确编辑,本地保持不变
确认:用 API 返回的 cache_deleted_input_tokens非客户端估算
范围仅主线程仅特定工具FileRead, Bash, Grep, Glob 等)
```
**洞察**:读写分离 — 本地消息不变(保证重放一致性),服务端缓存被精确编辑(节省空间)。
### 3c. API 原生上下文管理
```
策略clear_tool_uses + clear_thinking
触发:输入超 180K tokens
目标:保留最后 40K tokens
思考块cache 冷(>1h时仅保留最后一轮思考
```
---
## 第 4 层Context Collapse — 增量投影式摘要CQRS 思想)
**核心思想**:不破坏性替换消息,而是维护一个 commit log每轮查询时 project 出压缩视图。
**阈值**
- 90% 上下文窗口 → 开始提交 collapse
- 95% 上下文窗口 → 阻塞新 spawn
- ~93%auto-compact 位置)→ 被抑制避免竞争
**关键 API**
- `applyCollapsesIfNeeded()` — 投影压缩视图 + 可选提交新 collapse
- `recoverFromOverflow()` — 413 时排空所有暂存 collapse第一道防线
- `projectView()` — 每轮重放提交日志
**设计亮点**
- Collapse 摘要存在 commit store 中,而非 REPL 消息数组 → 跨轮持久化
- REPL 保留完整历史UI 回滚API 调用看到投影视图(节省 tokens
- 会话恢复时从 commits + snapshot 重建
---
## 第 5 层Auto-Compact — 带熔断的 LLM 摘要
**触发**`tokenCount > contextWindow - 13,000`
### 摘要 prompt 结构
```xml
<analysis>(内部草稿,生成后丢弃)</analysis>
<summary>
1. Primary Request / Intent
2. Key Technical Concepts
3. Files / Code
4. Errors / Fixes
5. Problem Solving
6. All User Messages用户说过的每句话都保留
7. Pending Tasks
8. Current Work
9. Optional Next Step
</summary>
```
### Prompt Cache 共享优化
摘要子 agent 复用主对话的缓存前缀(通过 runForkedAgent
没有此优化cache miss 率 98%,浪费全局 ~38B tok/天的 cache_creation。
### PTLPrompt-Too-Long重试
```
最多重试 3 次:
→ 按 API 轮次分组groupMessagesByApiRound
→ 丢弃最老的组以覆盖 token 缺口
→ 无法精确计算时 fallback 丢弃 20% 的组
图片:所有图片/文档块替换为 [image]/[document] 标记后再发送
```
### 熔断器
```
MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3
触发后:本会话剩余时间停止尝试
背景数据:~1,279 个会话曾出现 50+ 次连续失败(最高 3,272 次),
每天浪费 ~250K API 调用
```
### Post-Compact 恢复清单
| 恢复项 | 预算 |
|--------|------|
| 最近读取的文件 | 最多 5 个,每个 5K tokens总计 50K |
| Skill 附件 | 每个 5K总计 25K |
| Plan 状态 | 完整恢复 |
| Deferred tools | 完整恢复 |
| Agent 列表 | 完整恢复 |
| MCP 指令 | 完整恢复 |
### Session Memory Compact替代路径
在 auto-compact 中**优先尝试**,失败回退到完整 LLM 摘要:
```
用预提取的 session memory 替代 LLM 摘要
保留范围:从最后摘要消息向后扩展
满足 minTokens(10K) 且 minMessages(5)
不超过 maxTokens(40K)
不变量tool_use / tool_result 对永不拆分
```
---
## 第 6-7 层Reactive Compact + 错误恢复级联
### 5 层错误恢复(从便宜到昂贵)
```
API 返回 prompt_too_long 或媒体尺寸被拒
|
v
Layer 1: Context Collapse drain排空所有暂存 collapse最便宜
| 失败
v
Layer 2: Reactive Compact完整 LLM 摘要)
| 失败
v
Layer 3: Max Output 升级8K → 64K tokens
| 失败
v
Layer 4: Multi-turn Recovery注入 nudge 消息,最多 3 次)
| 失败
v
Layer 5: Model Fallback切换到备用模型
```
### 错误扣留Error Withholding模式
```
流式传输期间,可恢复错误不 yield 给调用者
→ 推入 assistantMessages 供恢复检查
→ 防止 SDK 消费者终止会话
→ 所有恢复手段都失败后才暴露给用户
```
防循环守卫:`hasAttemptedReactiveCompact` 防止同一轮无限重试。
---
## Token Budget Continuation — 输出预算跟踪(附加机制)
```
用途:长任务自动续跑(不是上下文管理,是输出预算控制)
完成阈值:输出 < 预算 90% → 继续
递减检测:连续 3+ 次续跑 且 最近两次增量 < 500 tokens → 停止
每次续跑注入 nudge 消息告知进度百分比
```
---
## 值得借鉴的设计原则
### 1. Prompt Cache 稳定性高于空间效率
- frozen 分区:进入 cache 的内容永不修改
- 字节级替换一致性mustReapply 重用完全相同的替换字符串
- Tool pool 排序稳定:`assembleToolPool()` 排序防止 MCP 变化破坏缓存
- 缓存编辑不改本地消息:读写分离保证重放一致性
### 2. 分层防御,从便宜到昂贵
7 层递进每层有可能阻止下一层触发。互斥门控防止昂贵操作竞争collapse 抑制 autocompact。snipTokensFreed 显式传递确保下游层看到真实 token 数。
### 3. 错误扣留 + 延迟恢复
流式传输中不立即暴露可恢复错误。给恢复机制留出空间后再决定是否暴露。这个模式可以推广到任何有多层 fallback 的系统。
### 4. CQRS 式双视图
REPL 保留完整历史UI 回滚 + 会话恢复API 看到投影视图(节省 tokens。Context Collapse 的 commit log 和 projectView 就是这个思想的实现。
### 5. 熔断器模式
连续失败 3 次后停止重试。用真实数据驱动1,279 个会话的失控循环 → 250K API 调用/天的浪费。
### 6. 利用缓存 TTL 做"免费清理"
cache 自然过期60min时搭车执行清理。既然前缀要重建就把脏活一起干了。
### 7. Post-Compact 不从零开始
摘要后精心恢复关键上下文最近文件、plan、skills。有明确的 token 预算分配,不是全量恢复也不是什么都不恢复。
### 8. 不变量保护无处不在
- tool_use / tool_result 对永不拆分
- Compact 边界消息记录 pre-compact 状态供恢复重链
- Partial compact 的 "up_to" 变体清除旧边界防止级联剪枝 bug
- 子 agent compact 不重置主线程的模块级状态
---
## Query Loop 状态机一览
```typescript
State = {
messages,
toolUseContext,
autoCompactTracking, // 熔断计数
maxOutputTokensRecoveryCount, // 输出恢复计数
hasAttemptedReactiveCompact, // 防循环守卫
maxOutputTokensOverride, // 8K → 64K 升级
pendingToolUseSummary,
stopHookActive,
turnCount,
transition // 状态转移原因
}
transition 类型:
collapse_drain_retry
reactive_compact_retry
max_output_tokens_escalate
max_output_tokens_recovery
stop_hook_blocking
token_budget_continuation
```
每轮不是递归而是 `while(true)` + 显式状态转移,避免长会话栈溢出。

View File

@@ -0,0 +1,710 @@
# Claude Code 值得借鉴的算法与设计模式
> 来源Claude Code 源码快照2026-03-31
> 上下文管理部分见另一份笔记 `Claude_Code_Context_Management_Notes.md`
---
## 目录
1. [权限系统:多层安全级联](#1-权限系统多层安全级联)
2. [流式工具执行:模型推理与工具执行重叠](#2-流式工具执行模型推理与工具执行重叠)
3. [并发控制与重试策略](#3-并发控制与重试策略)
4. [终端渲染引擎:双缓冲 + Diff 写入](#4-终端渲染引擎双缓冲--diff-写入)
5. [纯 TypeScript 原生模块移植](#5-纯-typescript-原生模块移植)
6. [FileEditTool12 步验证链](#6-filedittool12-步验证链)
7. [记忆系统:提取与召回](#7-记忆系统提取与召回)
8. [多 Agent 协调Swarm 架构](#8-多-agent-协调swarm-架构)
9. [启动优化:并行预取](#9-启动优化并行预取)
10. [其他精巧设计](#10-其他精巧设计)
---
## 1. 权限系统:多层安全级联
### 1.1 Bash 命令权限解析8 步级联)
文件:`src/tools/BashTool/bashPermissions.ts`
```
Step 0: Tree-sitter AST 解析
→ simple干净命令/ too-complex无法静态分析/ parse-unavailable降级正则
+ Shadow 模式Tree-sitter 观察性运行,记录与 legacy 路径的分歧
Step 1: 沙盒自动放行
→ sandboxing 启用 + autoAllowBashIfSandboxed → 允许
→ 复合命令拆分,逐子命令检查 deny 规则
Step 2: 精确匹配权限检查
→ 优先级deny > ask > allow > passthrough
Step 3: LLM 分类器 deny/ask 规则
→ Haiku 模型并行分类 deny 和 ask 描述列表
→ 仅高置信度结果触发
Step 4: 命令操作符拆分
→ 对 |, &&, ||, ; 递归调用权限检查
→ 即使管道段被允许,原始命令仍重新验证
Step 5: Legacy 误解析门控
→ 仅当 Tree-sitter 不可用时运行
Step 6: 逐子命令检查
→ splitCommand → 过滤 cd ${cwd} → checkCommandAndSuggestRules
Step 7: 8 步子级联
→ 精确匹配 → 前缀 deny → ask 规则 → 路径约束
→ 精确 allow → 前缀/通配符 allow → sed 约束
→ 模式权限 → 只读检查 → passthrough
```
### 1.2 规则匹配中的安全技巧
**复合命令防护**:前缀和通配符规则拒绝匹配复合命令。防止 `cd /path && python3 evil.py``cd:*` 规则放行。
**环境变量剥离的不对称设计**
- Deny 规则:使用激进的 `stripAllLeadingEnvVars`(固定点循环剥离所有环境变量),防止 `FOO=bar denied_cmd` 绕过
- Allow 规则:使用保守的 `stripSafeWrappers`,只接受白名单中的 ~60 个安全环境变量
**安全环境变量白名单**SAFE_ENV_VARS
- 包含:`NODE_ENV`, `RUST_LOG`, `CGO_ENABLED`
- 排除:`PATH`, `LD_PRELOAD`, `LD_LIBRARY_PATH`, `DYLD_*`, `PYTHONPATH`, `NODE_OPTIONS`, `BASH_ENV`
### 1.3 Shell 安全分析23 个验证器)
文件:`src/tools/BashTool/bashSecurity.ts`
按安全优先级排序的验证链:
| 验证器 | 检测内容 |
|--------|---------|
| `validateJqCommand` | `system()`, `-f`, `--from-file`, `-L` |
| `validateObfuscatedFlags` | 引号内隐藏的标志(如 `"-rf"` |
| `validateShellMetacharacters` | 参数中的 `;`, `\|`, `&` |
| `validateDangerousVariables` | `BASH_ENV`, `PROMPT_COMMAND`, `PS1`, `BASH_FUNC_*` |
| `validateCommentQuoteDesync` | 引号内的 `#`(注释跟踪混淆) |
| `validateCarriageReturn` | CR 字符shell-quote/bash 分词差异) |
| `validateIFSInjection` | `IFS=` 赋值 |
| `validateDangerousPatterns` | 反引号, `$()`, `${}`, zsh 扩展 (`=cmd`, `~[`, `(e:`) |
| `validateUnicodeWhitespace` | 非 ASCII 空白字符 |
| `validateBraceExpansion` | `{...,...}` 模式 |
| `validateZshDangerousCommands` | 20+ 个 zsh 内建命令(`zmodload`, `syswrite`, `ztcp` 等) |
**关键排序技巧**:非误解析验证器的 `ask` 结果被延迟返回。循环继续运行误解析验证器;只有没有误解析验证器触发时,延迟的非误解析结果才被返回。防止非误解析的 `ask` 掩盖应该设置 `isBashSecurityCheckForMisparsing` 的误解析 `ask`
### 1.4 只读命令分类(双层判定)
文件:`src/tools/BashTool/readOnlyValidation.ts`
**Tier 1 — Flag 级别白名单**:每个命令的每个 flag 都有类型标注(`none`, `number`, `string`, 特定字面量)。特例:
- `xargs``-i`/`-e` 被移除GNU `getopt_long` 可选参数语义漏洞)
- `tree``-R` 被移除(它会写文件)
- `fd`/`fdfind``-x`/`--exec` 被排除
**Tier 2 — 正则匹配**`cat`, `head`, `tail`, `wc`, `jq`, `echo`, `pwd` 等简单命令。
**复合命令安全**`cd && git` 组合被阻止(沙盒逃逸 — 通过恶意 git hooks。检测写入 `.git/hooks/``objects/``refs/` 后运行 git 的命令链。
### 1.5 Auto-Mode (YOLO) 分类器
文件:`src/utils/permissions/yoloClassifier.ts`
**不是传统 ML — 是 LLM 即分类器**
**两阶段 XML 分类**
```
Stage 1快速判定
max_tokens=64, stop_sequences=['</block>']
→ "no"(允许):立即返回
→ "yes" 或无法解析:升级到 Stage 2
Stage 2深度推理
max_tokens=4096, 启用 chain-of-thought
→ 用 <thinking> 标签推理后再决定
→ 解析时先剥离 <thinking> 块再匹配 <block> 标签
```
**200ms 竞赛模式**interactiveHandler.ts
```
5 个参赛者同时启动:
1. 用户权限对话框
2. Hooks 异步执行
3. Bash 分类器异步执行
4. Bridge 权限响应claude.ai
5. Channel 权限中继Telegram 等)
createResolveOnce 原子 claim() — 第一个到达的赢,其他 no-op
200ms 宽限期:
前 200ms 内忽略用户交互(防止意外按键取消分类器)
200ms 后任何用户交互都会杀死分类器的自动批准机会
```
**投机性分类器检查**:在权限对话框出现之前就启动分类器(`startSpeculativeClassifierCheck`),与 deny/ask 分类器、hooks、对话框设置并行运行。
---
## 2. 流式工具执行:模型推理与工具执行重叠
文件:`src/services/tools/StreamingToolExecutor.ts`
### 核心思想
工具在模型**还在生成 token 时就开始执行**,而非等完整响应结束。
### 并发控制算法
```typescript
canExecuteTool(isConcurrencySafe: boolean): boolean {
const executing = this.tools.filter(t => t.status === 'executing')
return (
executing.length === 0 ||
(isConcurrencySafe && executing.every(t => t.isConcurrencySafe))
)
}
```
- 没有正在执行的工具 → 可以执行
- 自身并发安全 且 所有正在执行的也并发安全 → 可以执行
- 否则 → 等待
### 工具状态机
```
queued → executing → completed → yielded
```
队列有序处理。非并发工具遇到无法执行时直接 break保持严格顺序并发工具可跳过。
### 错误级联
**只有 Bash 错误才取消兄弟工具**。原因Bash 命令有隐式依赖链mkdir 失败 → 后续命令无意义。Read/WebFetch 等独立工具不取消。
`siblingAbortController` 是 parent 的子控制器 — 兄弟子进程立即死亡,但父 query loop 不中断。
### 进度流式传输
使用 Promise 信号机制(`progressAvailableResolve`)。`getRemainingResults()` async generator 用 `Promise.race` 在工具完成和新进度到达之间等待,确保进度消息实时传递而非缓冲。
### 与 query.ts 的集成
```
流式循环中:
API content_block_stop 事件
→ 立即 yield AssistantMessage
→ query.ts 喂给 StreamingToolExecutor.addTool()
事件间隙:
→ getCompletedResults() 收割已完成的工具
流式结束后:
→ getRemainingResults() 排空所有待处理工具
```
---
## 3. 并发控制与重试策略
### 3.1 并发 Generator 合并all 函数)
文件:`src/utils/generators.ts`
```
维护 waiting 队列 + active Promise 集合
1. 初始填充 concurrencyCap 个 generator
2. Promise.race 所有活跃 generator
3. 某个 yield → 立即 .next() 推进它
4. 某个完成 → waiting 中取一个填补
5. 公平交错 + 有界并行(默认上限 10
```
### 3.2 工具并发安全分类
| 分类 | 工具 | 依据 |
|------|------|------|
| 始终安全 | FileRead, LSP, TaskCreate, TaskGet, Brief | 返回 `true` |
| 输入依赖 | BashTool | 委托给 `isReadOnly(input)`,只读命令并发,写命令独占 |
| 默认不安全 | FileEdit, FileWrite 等 | 使用默认 `false`fail-closed |
### 3.3 指数退避 + 抖动重试
文件:`src/services/api/withRetry.ts`
```
baseDelay = min(500ms * 2^(attempt-1), 32s)
jitter = random(0, 25% * baseDelay) // 加性抖动,非乘性
finalDelay = baseDelay + jitter
// server retry-after header 存在时覆盖
```
**529过载处理 — 级联放大防护**
```
非前台查询(摘要、标题、分类器)→ 收到 529 立即放弃(不重试)
前台查询 → 重试最多 3 次
3 次 529 后 → FallbackTriggeredError → 切换备用模型
```
**Fast Mode 降级**
```
429/529 + fast mode 激活:
retry-after < 20s → 继续 fast mode 重试(保持 prompt cache
retry-after ≥ 20s → 冷却(最少 10min切换标准速度
```
**无人值守模式**`CLAUDE_CODE_UNATTENDED_RETRY`
```
429/529 无限重试,最大退避 5 分钟
长休眠拆为 30s 心跳间隔(防止主机标记会话空闲)
6 小时硬上限重置
```
### 3.4 流式看门狗
文件:`src/services/api/claude.ts`
```
空闲超时默认 90s可配置
50% 时间 → 警告
100% 时间 → 硬中止挂起的流
每个 chunk 重置计时器
```
---
## 4. 终端渲染引擎:双缓冲 + Diff 写入
### 4.1 双缓冲帧交换
文件:`src/ink/ink.tsx`, `src/ink/output.ts`, `src/ink/screen.ts`
```
每次渲染后:
backFrame = frontFrame
frontFrame = newFrame
```
**Screen 缓冲区**packed `Int32Array`,每个单元格 2 个 word8 bytes
- Word 0: char pool ID
- Word 1: style ID + hyperlink ID + cell width位打包
- `resetScreen()` 复用同一 buffer只增不缩`BigInt64Array` 视图批量清零
**charCache**16384 上限):跨帧缓存 grapheme 聚类结果,大多数行不变时直接命中。
### 4.2 Diff 算法
文件:`src/ink/screen.ts` (diffEach), `src/ink/log-update.ts`
```
1. 计算两帧 damage rectangle 的并集
2. 仅在 damage 区域内逐 word 比较 Int32Array
3. findNextDiff() 是纯函数,设计为 JIT 内联
4. VirtualScreen 跟踪光标位置,只在目标不一致时发移动指令
```
**关键优化**
- **DECSTBM 硬件滚动**ScrollBox 的 scrollTop 变化时用终端硬件滚动(`CSI top;bot r + CSI n S/T`),而非重写整个区域。先对 prev.screen 执行 `shiftRows()` 模拟硬件位移,后续 diff 自然只找到新滚入的行。
- **StylePool.transition()**:按 (fromId, toId) 对缓存 ANSI 样式转换字符串 — 预热后零分配
- **fg-only 空格跳过**:只有前景色的空格单元格视为不可见,跳过写入
### 4.3 Blit 优化
文件:`src/ink/render-node-to-output.ts`
```
节点干净not dirty且布局位置不变
→ 直接从 prevScreen 复制单元格blit
→ blitRegion() 使用 TypedArray.set() 批量内存拷贝
→ 每行一次调用,连续全宽区域只需一次
→ 跳过整个子树的重新渲染
```
### 4.4 渲染器 Peephole 优化
文件:`src/ink/optimizer.ts`
单趟扫描 Diff 数组:
- 合并连续 `cursorMove`(加 dx/dy
- 折叠连续 `cursorTo`(只保留最后一个)
- 拼接相邻 `styleStr`
- 取消 cursor hide/show 对
- 去重相同 URI 的 hyperlink patch
- 移除 count=0 的 clear patch
---
## 5. 纯 TypeScript 原生模块移植
### 5.1 Yoga 布局引擎C++ → TypeScript
文件:`src/native-ts/yoga-layout/index.ts`~2400 行)
完整的 Flexbox 布局实现,消除了 native binary 依赖。
**多层缓存策略**
| 缓存 | 机制 | 效果 |
|------|------|------|
| Dirty-flag | 干净子树 + 匹配输入 → 跳过 | 最基本的剪枝 |
| 双槽缓存 | 分别缓存 layout 和 measure 结果 | 同一节点两种调用模式 |
| 4 槽环形缓存 | packed Float64Array | 500 消息 scrollbox: 76k→4k layoutNode 调用 |
| flex-basis 缓存 | generation-stamped | 短路递归 computeFlexBasis |
| 快速路径标志 | `_hasAutoMargin` 等 | 全零情况单分支跳过 |
**`resolveEdges4Into()`**:一次遍历解析全部 4 条物理边到预分配元组,提升共享 fallback 查找。
### 5.2 模糊搜索Rust nucleo/fzf → TypeScript
文件:`src/native-ts/file-index/index.ts`
**逐步过滤架构**
```
Step 1: 字符位图过滤O(1) 拒绝)
→ 每个路径一个 26-bit charBits 掩码
→ (charBits & needleBitmap) !== needleBitmap → 跳过
Step 2: 融合 indexOf 扫描
→ String.indexOf()V8/JSC 中 SIMD 加速)
→ 同时找到匹配位置 + 累积 gap/consecutive 分数
→ 无需第二次评分遍历
Step 3: Gap-bound 拒绝
→ 计算分数上限(所有边界奖励)减去已知 gap 惩罚
→ 无法超过当前 top-k 阈值 → 跳过昂贵的边界评分
Step 4: 边界/驼峰评分
→ 路径分隔符 (/\-_.) 匹配奖励
→ 驼峰转换匹配奖励
→ 首字符匹配奖励
→ 常数近似 nucleo/fzf-v2 权重
Top-k 维护:升序数组 + 二分插入(避免全量 O(n log n) 排序)
```
**其他特性**
- 异步构建:每 ~4ms yield 事件循环,`readyCount` 支持构建中的部分索引搜索
- 智能大小写:全小写查询 = 大小写不敏感;有大写 = 敏感
- 测试文件惩罚:路径包含 "test" → 1.05x 分数惩罚
### 5.3 语法高亮 + Word-Level DiffRust syntect/bat → TypeScript
文件:`src/native-ts/color-diff/index.ts`
- highlight.js 延迟加载(避免 ~200ms 的 190+ 语法注册启动成本)
- `diff` npm 包的 `diffArrays` 做词级 diff
- RGB → ANSI-256 颜色近似:移植 `ansi_colours` Rust crate 的立方体 vs 灰阶感知最近索引算法
- Monokai Extended / GitHub-light 作用域到颜色映射
- Storage 关键字重分割highlight.js 把 `const`/`function`/`class` 归为 "keyword";端口重分割以匹配 syntect 的 cyan storage 颜色)
---
## 6. FileEditTool12 步验证链
文件:`src/tools/FileEditTool/FileEditTool.ts`
```
1. 密钥检测 → 阻止向 team memory 文件写入密钥
2. 空操作检测 → old_string === new_string 直接拒绝
3. Deny 规则检查 → 文件路径匹配 deny 权限规则
4. UNC 路径安全 → 跳过 \\server\share防止 NTLM 凭证泄露)
5. 文件大小守卫 → > 1 GiB 拒绝
6. 编码检测 → UTF-16LE BOM (0xFF 0xFE) / UTF-8, \r\n → \n
7. 文件存在检查 → 不存在时建议相似文件findSimilarFile
8. 空 old_string → 仅在文件为空时允许(创建文件场景)
9. Notebook 重定向 → .ipynb 必须使用 NotebookEditTool
10. 陈旧性检测 → mtime 比较,失败时回退到内容比较(避免云同步/杀毒软件时间戳干扰的误报)
11. 引号规范化 → 弯引号→直引号搜索;写入时用启发式恢复弯引号样式
12. 歧义匹配 → 多处匹配 + 非 replace_all → 拒绝并要求更多上下文
```
### 引号规范化算法utils.ts
```
搜索阶段:
1. 精确匹配 old_string → 找到则使用
2. normalizeQuotes(old_string) → 弯引号转直引号
3. 在 normalizeQuotes(fileContent) 中搜索
4. 返回 fileContent 中的原始子串(保留弯引号)
写入阶段preserveQuoteStyle
检测到规范化被应用时:
→ 将 new_string 中的直引号转回弯引号
→ 启发式:空白/行首/开括号后 = 开引号;字母间 = 撇号
```
### 反序列化映射desanitizeMatchString
模型不会看到某些 XML 标签(发送给 API 前被清理)。当模型在编辑中输出清理后的形式时,反向映射:
- `<fnr>``<function_results>`
- `\n\nH:``\n\nHuman:`
### call() 写入路径中的双重陈旧性检查
```
validateInput 时检查一次陈旧性
→ 通过
→ call() 中重新同步读取文件,再次检查
→ 防止 validate 和 call 之间的 TOCTOU 竞态
```
---
## 7. 记忆系统:提取与召回
### 7.1 记忆提取extractMemories
文件:`src/services/extractMemories/`
**架构**:每个完整 query loop 结束时fork 一个子 agent共享父级 prompt cache执行提取。
```
提取流程:
1. 门控:仅主 agent非子 agent非远程模式
2. 重叠守卫:已有提取在运行 → 暂存当前上下文(最新覆盖旧的)
3. 轮次节流:合格轮次未达阈值 → 跳过
4. 互斥:主 agent 已手动写入记忆 → 跳过并推进游标
5. 注入记忆清单:扫描目录 + 读 frontmatter → 预格式化
6. Fork agent 执行:最多 5 轮,受限工具访问
7. 游标推进:仅在成功后;失败时留在原位以重新考虑
8. 尾随运行:完成后检查暂存的待处理上下文
```
**工具限制**Read/Grep/Glob 无限制;只读 BashEdit/Write 仅限记忆目录内。
### 7.2 记忆召回findRelevantMemories
文件:`src/memdir/findRelevantMemories.ts`
**不是启发式评分 — 是 LLM 评分**
```
Phase 1: 扫描
→ 读取记忆目录所有 .md 文件(排除 MEMORY.md
→ 每个文件读前 30 行提取 frontmattername, description, type
→ 按 mtime 降序排列,上限 200 个文件
→ 单遍设计:读取后排序(而非 stat-排序-读取syscall 减半
Phase 2: LLM 选择
→ 发送查询 + 格式化清单 + 最近使用工具列表给 Sonnet
→ 结构化 JSON 输出
→ "只包含你确定有帮助的记忆。不确定就不包含。最多 5 个。"
→ 最近使用工具列表防止为已活跃使用的工具推荐 API 文档
→ 但关于这些工具的警告/陷阱仍然会被选中
Phase 3: 新鲜度处理
→ 超过 1 天的记忆注入 <system-reminder> 告警
→ "此记忆已 N 天。关于代码行为的声明可能过时。"
```
**already-surfaced 过滤**过滤掉之前轮次已展示的路径5 个名额全部花在新候选上。
---
## 8. 多 Agent 协调Swarm 架构
### 8.1 协调者模式Coordinator
文件:`src/coordinator/coordinatorMode.ts`
```
任务工作流阶段:
Research并行 workers→ Synthesis协调者→ Implementationworkers→ Verificationworkers
并发规则:
只读任务 → 自由并行
写密集任务 → 按文件区域串行
验证可与不同文件的实现重叠
Worker prompt 必须自包含:
Worker 看不到协调者对话 → 每个 prompt 需要完整上下文(文件路径、行号等)
Continue vs Spawn 决策:
高上下文重叠 → continue复用已加载上下文
低上下文重叠 → spawn 新 worker
```
### 8.2 两种后端策略
| 后端 | 隔离方式 | 通信 | 特点 |
|------|---------|------|------|
| In-Process | `AsyncLocalStorage` 上下文隔离 | 基于文件的 mailbox | 共享 API client + MCP 连接;独立 AbortControllerleader 中断不杀 worker |
| Pane-Based (tmux/iTerm2) | 独立 OS 进程 | 基于文件的 mailbox | CLI flag 传播(`--agent-id`, `--agent-name`, `--team-name`, `--agent-color`leader 的模型/权限/环境变量全部传播 |
### 8.3 权限桥接
In-process teammate 通过 `leaderPermissionBridge` 路由权限提示到 leader 的 UI复用 BashPermissionRequest、FileEditToolDiff 等对话框。Bridge 不可用时回退到 mailbox 权限同步。
### 8.4 Fork Subagent
文件:`src/tools/AgentTool/forkSubagent.ts`
```
子进程继承父级完整对话上下文 + system prompt
递归 fork 防护:
isInForkChild() 检查对话历史中的 <fork_boilerplate> 标签
Cache 共享设计:
保留完整父级 assistant 消息(所有 tool_use 块)
构建 tool_result 块(占位文本:"Fork started -- processing in background"
只有最后的 text 块不同 → 最大化 prompt cache 命中
子进程 10 条严格规则:
不生成子 agent、不评论、只用工具、提交变更、
结构化输出Scope/Result/Key files/Files changed/Issues、最多 500 字
```
---
## 9. 启动优化:并行预取
文件:`src/main.tsx` 前 20 行
```typescript
// 这些副作用必须在所有其他 import 之前运行:
profileCheckpoint('main_tsx_entry') // 标记入口(在 ~135ms import 之前)
startMdmRawRead() // 并行MDM 子进程读取plutil/reg query
startKeychainPrefetch() // 并行macOS 钥匙串双读取
// 无此优化:~65ms 同步阻塞(每次 macOS 启动)
```
**启动分析器**`startupProfiler.ts`
- 采样日志:内部 100%,外部 0.5%。记录 import_time, init_time, settings_time, total_time
- 详细分析:`CLAUDE_CODE_PROFILE_STARTUP=1`,带 `process.memoryUsage()` 快照的完整时间线
- 非采样用户零开销(`profileCheckpoint` 立即返回)
---
## 10. 其他精巧设计
### 10.1 35 行状态管理
文件:`src/state/store.ts`
```typescript
createStore<T>(initialState, onChange?) => {
getState() // 返回当前状态
setState(updater) // updater: (prev) => next
// Object.is() 相等检查(引用相同则跳过)
// 触发 onChange + 通知 Set<Listener>
subscribe(listener) // 返回 unsubscribe
}
```
无中间件,无选择器,无 devtools。配合 `useSyncExternalStore` 实现最小化重渲染。
### 10.2 ToolSearchTool — 延迟工具发现
文件:`src/tools/ToolSearchTool/ToolSearchTool.ts`
**两种查询模式**
直接选择(`select:ToolA,ToolB`):精确查找,返回 `tool_reference` 块。
关键词搜索评分:
| 匹配类型 | 分数 |
|---------|------|
| 名称部分精确匹配 | +10MCP: +12 |
| 名称部分子串匹配 | +5MCP: +6 |
| 全名回退 | +3 |
| searchHint 词边界匹配 | +4 |
| 描述词边界匹配 | +2 |
`+` 前缀标记必需词(全部必须匹配才入围)。
工具名解析MCP 工具去 `mcp__` 前缀后按 `__``_` 分割;普通工具按驼峰转换和 `_` 分割。
### 10.3 Token 估算(无 API 调用)
文件:`src/utils/tokens.ts`
```
粗略估算content.length / bytesPerToken
文件类型感知:
JSON/JSONL/JSONC: 2 bytes/token密集单字符 token
其他: 4 bytes/token
区块级估算:
text/thinking: length / 4
image/document: 固定 2000 tokens
tool_use: (name + JSON.stringify(input)).length / 4
上下文窗口估算tokenCountWithEstimation
1. 从后向前找到最后一条有 API usage 数据的消息
2. 处理并行工具调用:跨越共享 message.id 的兄弟记录
3. 返回 usage.input_tokens + 粗略估算(后续消息)
4. 无 usage 数据时全量粗略估算
```
### 10.4 错误扣留模式Error Withholding
```
流式传输中可恢复错误不暴露给调用者:
→ prompt_too_long, media_size, max_output_tokens
→ 推入 assistantMessages 供恢复检查
→ 所有恢复失败后才 yield 给用户
→ 防止 SDK 消费者在中间错误时终止会话
```
### 10.5 Prompt Cache 稳定性设计集锦
| 技术 | 位置 | 效果 |
|------|------|------|
| 工具池排序 | `assembleToolPool()` | 防止 MCP 变更破坏缓存前缀 |
| 系统 prompt 分界标记 | `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` | 静态部分 `scope: global` 跨组织缓存 |
| Agent 列表附件注入 | AgentTool prompt.ts | 从工具描述中移出动态列表(减少 10.2% cache_creation |
| Fork 消息构造 | forkSubagent.ts | 所有子进程共享相同 tool_result 占位符,仅最后文本块不同 |
| Tool result 替换一致性 | toolResultStorage.ts | mustReapply 重用完全相同的替换字符串(字节级一致) |
| frozen 分区 | toolResultStorage.ts | 进入 cache 的内容永不修改 |
### 10.6 文本选择算法
文件:`src/ink/selection.ts`
- anchor + focus 点用屏幕缓冲区坐标col, row
- 双击/三击选词/行模式:`anchorSpan` 启用拖拽时按词/行扩展
- 滚动捕获:`scrolledOffAbove`/`scrolledOffBelow` 累加器捕获拖拽滚动时离开视口的行
- 词边界检测匹配 iTerm2 默认行为(路径字符 `/-+\~_.` 视为词字符)
- `getSelectedText()` 合并离屏和在屏行,尊重软换行标记重建逻辑行
### 10.7 鼠标 Hit Testing
文件:`src/ink/hit-test.ts`
递归深度优先遍历 DOM 树。**子节点逆序遍历**(后绘制的在上层),确保正确 z-order。
- `dispatchClick()`:从最深命中节点沿 parentNode 冒泡
- `dispatchHover()`:类 DOM mouseEnter/mouseLeave非冒泡diff hovered-node 集合
### 10.8 GrepTool 分页
```
默认限制250 条(未指定时)
head_limit=0无限制谨慎使用
offset 参数:跳过前 N 条
分页在 ripgrep 返回后、路径相对化之前应用(节省 CPU
appliedLimit 仅在实际截断时报告(让模型知道有更多结果)
```
### 10.9 Partial Compact 方向性
```
from默认
摘要 pivot 之后的消息,保留之前的
→ prompt cache 保留(保留的消息在前)
up_to
摘要 pivot 之前的消息,保留之后的
→ prompt cache 失效(摘要在保留消息之前)
→ 剥离旧 compact 边界和摘要(防止陈旧边界混淆扫描器)
```
### 10.10 API 消息轮次分组
文件:`src/services/compact/grouping.ts`
```
groupMessagesByApiRound
按 API 轮次边界分组(不同 message.id 标记新轮次)
比之前的 human-turn 分组更细粒度
→ 支持单 human turn 的 SDK/CCR/eval 会话中的精确 compact
流式 chunk 共享 id → 同一响应内的交错 tool_result 保持正确分组
```

View File

@@ -0,0 +1,871 @@
# Claude Code 上下文压缩算法深度分析
> 基于 Claude Code 源码2026-03-31 快照512K 行 TypeScript逆向分析
> 核心文件:`src/services/compact/` 目录下 11 个文件
---
## 目录
1. [架构总览](#1-架构总览)
2. [第1层微压缩Microcompact](#2-第1层微压缩microcompact)
3. [第2层自动压缩Auto-Compact](#3-第2层自动压缩auto-compact)
4. [第3层传统压缩Full Compact](#4-第3层传统压缩full-compact)
5. [第4层Session Memory 压缩](#5-第4层session-memory-压缩)
6. [消息分组算法](#6-消息分组算法)
7. [Token 估算算法](#7-token-估算算法)
8. [压缩提示词工程](#8-压缩提示词工程)
9. [5层错误恢复中的压缩角色](#9-5层错误恢复中的压缩角色)
10. [各层对比与设计哲学](#10-各层对比与设计哲学)
---
## 1. 架构总览
Claude Code 的上下文压缩不是单一算法,而是一个 **4层递进的压缩体系**,每层解决不同层面的问题:
```
用户消息 → [第1层微压缩] → [第2层自动压缩] → API 调用
↓ ↓
细粒度清理旧工具输出 上下文即将超限时触发
(不丢语义,<1ms) (调用 LLM 或 Session Memory)
┌──────────────┴──────────────┐
[第4层SM压缩] [第3层传统压缩]
(用已有摘要,<10ms) (Fork Agent 生成摘要5-30s)
```
**核心原则:** 尽可能用廉价的规则操作延迟昂贵的 LLM 调用,只在不得已时丢弃信息。
### 涉及的源文件
| 文件 | 行数 | 职责 |
|------|------|------|
| `microCompact.ts` | ~400 | 微压缩:规则清理旧工具结果 |
| `apiMicrocompact.ts` | — | API 层缓存编辑集成 |
| `timeBasedMCConfig.ts` | — | 时间触发微压缩配置 |
| `autoCompact.ts` | ~350 | 自动压缩:阈值判断 + 断路器 |
| `compact.ts` | ~600+ | 传统压缩Fork Agent 摘要 |
| `prompt.ts` | ~375 | 压缩提示词模板 |
| `sessionMemoryCompact.ts` | ~630 | Session Memory 压缩路径 |
| `grouping.ts` | ~63 | 消息按 API 轮次分组 |
| `postCompactCleanup.ts` | — | 压缩后清理 |
| `compactWarningHook.ts` | — | 压缩警告钩子 |
| `compactWarningState.ts` | — | 压缩警告状态 |
---
## 2. 第1层微压缩Microcompact
**源文件:** `microCompact.ts`
### 核心思想
不调用 LLM纯规则操作——清理旧的、大块的工具输出结果保留语义信息。这是每轮查询前都会执行的最轻量操作。
### 可压缩工具白名单
```typescript
const COMPACTABLE_TOOLS = new Set([
'Read', // 文件读取结果可能很大
'Bash', // Shell 输出可能很长
'Grep', // 搜索结果
'Glob', // 文件列表
'WebSearch', // 网页搜索结果
'WebFetch', // 网页抓取结果
'Edit', // 文件编辑的 diff
'Write', // 文件写入确认
])
```
不在白名单中的工具(如 Agent、Skill、MCP 等)的结果不会被微压缩。
### 两个子路径
#### 子路径 A时间触发微压缩
```
触发条件距上次助手消息的时间间隔超过阈值API 缓存已过期)
执行逻辑:
1. 收集所有可压缩工具的 tool_use ID
2. 保留最近 N 个工具结果
3. 将更早的 tool_result 内容替换为:
"[Old tool result content cleared]"
4. 不修改 tool_use 块(保持 API 配对完整性)
特点:
- 缓存已过期,所以无需保护缓存
- 直接修改本地消息内容
- 减少重传时的 token 消耗
```
#### 子路径 B缓存编辑微压缩Cached MC
这是更精巧的路径——在缓存仍然有效时工作:
```
触发条件:
- 特性开关 CACHED_MICROCOMPACT 开启
- 模型支持缓存编辑 API
- 当前是主线程查询(非 fork agent
执行逻辑:
1. collectCompactableToolIds(): 收集所有可压缩的 tool_use ID
2. registerToolResult(): 注册每个工具结果(按用户消息分组)
3. registerToolMessage(): 记录工具消息组
4. getToolResultsToDelete(): 根据 count/keep 阈值决定删除哪些
5. createCacheEditsBlock(): 生成 cache_edits API 块
关键区别:
- 不修改本地消息内容!
- 通过 API 的 cache_edits 字段告诉服务端删除特定工具结果的缓存
- 保持 prompt cache 命中率
- 状态通过 pendingCacheEdits / pinnedCacheEdits 管理
```
**缓存编辑的状态管理:**
```typescript
// 全局状态
let cachedMCState: CachedMCState | null = null
let pendingCacheEdits: CacheEditsBlock | null = null
// consumePendingCacheEdits():
// 返回待插入的缓存编辑块,然后清空 pending 状态
// 调用者在 API 请求后必须调用 pinCacheEdits() 固定它们
// getPinnedCacheEdits():
// 返回之前已固定的缓存编辑,需要在后续请求中重新发送
// markToolsSentToAPIState():
// 标记工具已发送给 API成功响应后调用
```
### Token 估算辅助
```typescript
function calculateToolResultTokens(block: ToolResultBlockParam): number {
if (typeof block.content === 'string') {
return roughTokenCountEstimation(block.content) // 字符数 / 4
}
// 数组:逐项计算
return block.content.reduce((sum, item) => {
if (item.type === 'text') return sum + roughTokenCountEstimation(item.text)
if (item.type === 'image' || item.type === 'document') return sum + 2000
return sum
}, 0)
}
function estimateMessageTokens(messages: Message[]): number {
let totalTokens = 0
for (const message of messages) {
for (const block of message.message.content) {
switch (block.type) {
case 'text': totalTokens += roughTokenCountEstimation(block.text); break
case 'tool_result': totalTokens += calculateToolResultTokens(block); break
case 'image':
case 'document': totalTokens += 2000; break // 固定估算
case 'thinking': totalTokens += roughTokenCountEstimation(block.thinking); break
case 'redacted_thinking': totalTokens += roughTokenCountEstimation(block.data); break
case 'tool_use': totalTokens += roughTokenCountEstimation(block.name + JSON.stringify(block.input ?? {})); break
default: totalTokens += roughTokenCountEstimation(JSON.stringify(block)); break
}
}
}
return Math.ceil(totalTokens * (4 / 3)) // × 4/3 保守填充
}
```
---
## 3. 第2层自动压缩Auto-Compact
**源文件:** `autoCompact.ts`
### 阈值计算
```typescript
// 有效上下文窗口 = 模型上下文窗口 - 摘要输出预留
const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000 // p99.99 的摘要输出是 17,387 tokens
function getEffectiveContextWindowSize(model: string): number {
const reservedTokensForSummary = Math.min(
getMaxOutputTokensForModel(model),
MAX_OUTPUT_TOKENS_FOR_SUMMARY,
)
let contextWindow = getContextWindowForModel(model)
// 支持环境变量覆盖(用于测试)
if (process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW) {
contextWindow = Math.min(contextWindow, parsed)
}
return contextWindow - reservedTokensForSummary
}
// 自动压缩阈值 = 有效上下文窗口 - 13K 缓冲
const AUTOCOMPACT_BUFFER_TOKENS = 13_000
function getAutoCompactThreshold(model: string): number {
return getEffectiveContextWindowSize(model) - AUTOCOMPACT_BUFFER_TOKENS
}
// 举例Opus 200K 上下文):
// 有效窗口 = 200,000 - 20,000 = 180,000
// 自动压缩阈值 = 180,000 - 13,000 = 167,000 tokens
```
### 其他阈值
```typescript
const WARNING_THRESHOLD_BUFFER_TOKENS = 20_000 // 警告阈值
const ERROR_THRESHOLD_BUFFER_TOKENS = 20_000 // 错误阈值
const MANUAL_COMPACT_BUFFER_TOKENS = 3_000 // 手动 /compact 的阻塞限制
```
### 断路器机制
```typescript
const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3
// BQ 数据分析发现1,279 个会话连续失败 50+ 次(最多 3,272 次),
// 每天浪费约 250K 次 API 调用。所以加了断路器。
if (tracking.consecutiveFailures >= MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES) {
return { wasCompacted: false } // 直接跳过,不再尝试
}
```
### shouldAutoCompact 决策树
```
shouldAutoCompact(messages, model, querySource):
1. querySource 是 'session_memory' 或 'compact'
→ 返回 false防止递归死锁——压缩代理自己不能触发压缩
2. querySource 是 'marble_origami'(上下文折叠代理)?
→ 返回 false防止破坏主线程的已提交日志
3. isAutoCompactEnabled() 返回 false
→ 返回 false
(检查 DISABLE_COMPACT、DISABLE_AUTO_COMPACT 环境变量和用户配置)
4. 响应式压缩模式开启tengu_cobalt_raccoon gate
→ 返回 false让 API 的 prompt-too-long 错误触发响应式压缩)
5. 上下文折叠模式开启?
→ 返回 false上下文折叠是 90%/95% 流程,自动压缩在 93% 会干扰它)
6. tokenCountWithEstimation(messages) - snipTokensFreed >= threshold
→ 返回 true
```
### autoCompactIfNeeded 执行流程
```
autoCompactIfNeeded(messages, context, ...):
1. DISABLE_COMPACT 环境变量?→ 跳过
2. 断路器检查consecutiveFailures >= 3→ 跳过
3. shouldAutoCompact() 返回 true
↓ 是
4. 优先尝试 Session Memory 压缩
↓ 成功 → 返回结果
↓ 失败
5. 回退到传统压缩compactConversation
↓ 成功 → 重置 consecutiveFailures = 0返回结果
↓ 失败
6. consecutiveFailures++
↓ 达到 3 次
7. 日志:断路器触发,本次会话不再尝试自动压缩
```
---
## 4. 第3层传统压缩Full Compact
**源文件:** `compact.ts` + `prompt.ts`
### 核心机制Fork Agent
传统压缩使用一个 **Fork Agent**——创建当前会话的一个分支,让它生成摘要。关键优势是**共享主会话的 prompt cache**。
```
主会话消息: [user1, assistant1, user2, assistant2, ...]
↓ 全部传入
Fork Agent共享 prompt cache
↓ 单轮回复
生成结构化摘要(<analysis> + <summary>
后处理 → 替换原消息
```
### 预处理管线
```
原始消息
stripImagesFromMessages() ← 图片 → "[image]",文档 → "[document]"
↓ (防止压缩请求自身超过上下文限制)
stripReinjectedAttachments() ← 删除技能发现/列表附件
↓ (压缩后会自动重新注入)
normalizeMessagesForAPI() ← 规范化消息格式
发送给 Fork Agent
```
### 摘要输出格式
Fork Agent 被要求生成两个 XML 块:
```xml
<analysis>
[思考草稿——用于提高摘要质量的中间推理过程]
[这部分最终会被删除,不会进入压缩后的上下文]
</analysis>
<summary>
1. Primary Request and Intent:
[详细描述用户的所有请求和意图]
2. Key Technical Concepts:
- [概念1]
- [概念2]
3. Files and Code Sections:
- [文件名1]
- [为什么这个文件重要]
- [代码片段]
- [文件名2]
- [代码片段]
4. Errors and fixes:
- [错误描述]:
- [修复方式]
- [用户反馈]
5. Problem Solving:
[问题解决过程]
6. All user messages:
- [逐条列出所有非工具结果的用户消息]
7. Pending Tasks:
- [待办事项1]
- [待办事项2]
8. Current Work:
[精确描述当前工作内容,包含文件名和代码片段]
9. Optional Next Step:
[下一步计划,包含最近对话的直接引用]
</summary>
```
### 防止工具调用的强力前导词
```typescript
const NO_TOOLS_PREAMBLE = `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.
- Do NOT use Read, Bash, Grep, Glob, Edit, Write, or ANY other tool.
- You already have all the context you need in the conversation above.
- Tool calls will be REJECTED and will waste your only turn — you will fail the task.
- Your entire response must be plain text: an <analysis> block followed by a <summary> block.
`
```
为什么需要这么强力?注释解释了:
```
// Sonnet 4.6+ 自适应思考模型有时会忽略较弱的尾部指令并尝试调用工具。
// 在 maxTurns: 1 的情况下,被拒绝的工具调用意味着没有文本输出
// → 回退到流式备用路径4.6 上 2.79% vs 4.5 上 0.01%)。
// 把这个放在最前面并明确说明拒绝后果,可以防止浪费轮次。
```
### 后处理formatCompactSummary
```typescript
function formatCompactSummary(summary: string): string {
// 1. 删除 <analysis> 块(草稿,已无价值)
summary = summary.replace(/<analysis>[\s\S]*?<\/analysis>/, '')
// 2. 提取 <summary> 内容,替换为可读标题
const match = summary.match(/<summary>([\s\S]*?)<\/summary>/)
if (match) {
summary = summary.replace(/<summary>[\s\S]*?<\/summary>/,
`Summary:\n${match[1].trim()}`)
}
// 3. 清理多余空行
summary = summary.replace(/\n\n+/g, '\n\n')
return summary.trim()
}
```
### 压缩后消息序列
```
[CompactBoundaryMessage] ← 标记压缩边界(含 token 统计、trigger 类型)
[SummaryUserMessage] ← 格式化后的摘要
[messagesToKeep] ← 保留的最近消息(如果有)
[Attachments] ← 重新注入的附件
- 最近读取的文件(前 5 个,每个 ≤ 5K tokens总预算 50K
- Plan 文件(如果有活跃计划)
- MCP 指令增量
- 技能发现增量
- 代理列表增量
[HookResults] ← PreCompact/PostCompact 钩子结果
```
### Prompt-Too-Long 重试机制
当压缩请求本身超过上下文限制时:
```typescript
const MAX_PTL_RETRIES = 3
function truncateHeadForPTLRetry(messages, ptlResponse): Message[] | null {
// 1. 移除上一次重试的标记消息(防止重试停滞)
// 2. 按 API 轮次分组
const groups = groupMessagesByApiRound(messages)
if (groups.length < 2) return null // 无法再裁剪
// 3. 决定删除多少组
const tokenGap = getPromptTooLongTokenGap(ptlResponse)
if (tokenGap !== undefined) {
// 能解析出 token 缺口 → 精确删除
let acc = 0, dropCount = 0
for (const g of groups) {
acc += roughTokenCountEstimationForMessages(g)
dropCount++
if (acc >= tokenGap) break
}
} else {
// 不能解析 → 删除 20% 最旧的组
dropCount = Math.max(1, Math.floor(groups.length * 0.2))
}
// 4. 保证至少保留 1 组
dropCount = Math.min(dropCount, groups.length - 1)
// 5. 如果裁剪后第一条是 assistant 消息,补一个 user marker
// API 要求第一条消息必须是 user
const sliced = groups.slice(dropCount).flat()
if (sliced[0]?.type === 'assistant') {
return [createUserMessage({ content: PTL_RETRY_MARKER, isMeta: true }), ...sliced]
}
return sliced
}
```
### 部分压缩Partial Compact
支持两个方向:
| 方向 | 提示词 | 用途 |
|------|--------|------|
| `from`(默认) | `PARTIAL_COMPACT_PROMPT` | 保留旧消息,仅摘要"最近的消息" |
| `up_to` | `PARTIAL_COMPACT_UP_TO_PROMPT` | 摘要旧消息,保留新消息。摘要会放在开头,后续消息跟在后面 |
`up_to` 模式的摘要包含一个特殊的第 9 章节 "Context for Continuing Work",专门为后续消息提供上下文。
---
## 5. 第4层Session Memory 压缩
**源文件:** `sessionMemoryCompact.ts`
### 核心思想
不调用 LLM 生成新摘要,而是直接使用已经通过后台记忆提取(`extractMemories`)积累的 Session Memory 作为"摘要"。
### 优势
- **速度快**:不需要 API 调用,<10ms
- **质量可预测**Session Memory 是在每轮查询后渐进更新的不是一次性压缩
- **保留近期消息**不像传统压缩那样替换所有消息
### 配置参数
```typescript
const DEFAULT_SM_COMPACT_CONFIG = {
minTokens: 10_000, // 至少保留 10K tokens 的最近消息
minTextBlockMessages: 5, // 至少保留 5 条含文本的消息
maxTokens: 40_000, // 最多保留 40K tokens硬上限
}
// 这些值通过 GrowthBook 远程配置,可动态调整
```
### calculateMessagesToKeepIndex 算法
这是 Session Memory 压缩的核心算法——决定保留哪些最近的消息
```
输入messages[], lastSummarizedIndexSession Memory 已覆盖到哪条消息)
算法:
1. startIndex = lastSummarizedIndex + 1
(即:从 Session Memory 尚未覆盖的消息开始)
2. 计算当前 [startIndex, end] 范围的 token 总量和含文本消息数
3. 如果已经超过 maxTokens (40K) → 直接返回(不再扩展)
4. 如果同时满足 ≥ minTokens (10K) AND ≥ minTextBlockMessages (5)
→ 直接返回(已足够)
5. 否则,从 startIndex 往前逐条扩展:
- 每加入一条消息,更新 token 和消息计数
- 停止条件:
a. 达到 maxTokens (40K)
b. 同时满足 minTokens 和 minTextBlockMessages
c. 到达上一个 CompactBoundary不跨越旧的压缩边界
6. adjustIndexToPreserveAPIInvariants(messages, startIndex)
→ 确保不切断 tool_use/tool_result 配对
→ 确保不分离共享 message.id 的 thinking 块
```
### adjustIndexToPreserveAPIInvariants 算法
这个算法解决一个棘手的问题——流式传输时一个 API 响应会产生多条消息thinkingtool_use 它们共享同一个 `message.id`如果在中间切断`normalizeMessagesForAPI` 合并时会丢失 thinking
```
输入messages[], startIndex
步骤 1修复 tool_use/tool_result 配对
1a. 收集 [startIndex, end] 范围内所有 tool_result 的 tool_use_id
1b. 收集范围内已有的 tool_use_id
1c. 找出缺失的 tool_use_id在范围外
1d. 向前搜索,把包含缺失 tool_use 的 assistant 消息纳入范围
步骤 2修复 thinking 块分离
2a. 收集范围内所有 assistant 消息的 message.id
2b. 向前搜索,把共享同一 message.id 的 assistant 消息纳入范围
返回:调整后的 startIndex
```
**源码注释中的真实 bug 场景:**
```
Session 存储(压缩前):
Index N: assistant, message.id: X, content: [thinking]
Index N+1: assistant, message.id: X, content: [tool_use: ORPHAN_ID]
Index N+2: assistant, message.id: X, content: [tool_use: VALID_ID]
Index N+3: user, content: [tool_result: ORPHAN_ID, tool_result: VALID_ID]
如果 startIndex = N+2
旧代码:只检查 N+2 的 tool_results找不到返回 N+2
normalizeMessagesForAPI 合并后:
msg[1]: assistant with [tool_use: VALID_ID] ← ORPHAN tool_use 被排除!
msg[2]: user with [tool_result: ORPHAN_ID, tool_result: VALID_ID]
API 报错:孤立的 tool_result 引用了不存在的 tool_use
```
### trySessionMemoryCompaction 完整流程
```
trySessionMemoryCompaction(messages, agentId, autoCompactThreshold):
1. shouldUseSessionMemoryCompaction()
→ 检查 tengu_session_memory AND tengu_sm_compact 特性开关
→ 支持 ENABLE_CLAUDE_CODE_SM_COMPACT / DISABLE_CLAUDE_CODE_SM_COMPACT 环境变量
2. 初始化远程配置(仅首次)
3. 等待正在进行的 Session Memory 提取完成(带超时)
4. 获取 lastSummarizedMessageId 和 sessionMemory 内容
5. Session Memory 文件不存在?→ 返回 null
6. Session Memory 是空模板?→ 返回 null
7. 确定 lastSummarizedIndex
a. 正常情况:在 messages 中查找 lastSummarizedMessageId 的索引
b. 恢复的会话:设为 messages.length - 1从末尾开始
8. calculateMessagesToKeepIndex() → startIndex
9. 过滤掉 messagesToKeep 中的旧 CompactBoundary
10. 执行 SessionStart 钩子(恢复 CLAUDE.md 等上下文)
11. 创建压缩结果:
- 截断过大的 Session Memory 章节
- 生成摘要用户消息
- 附加 Plan 文件(如果有)
12. 检查压缩后 token 是否仍超过阈值
→ 是:返回 null回退到传统压缩
→ 否:返回 CompactionResult
```
---
## 6. 消息分组算法
**源文件:** `grouping.ts`
```typescript
function groupMessagesByApiRound(messages: Message[]): Message[][] {
const groups: Message[][] = []
let current: Message[] = []
let lastAssistantId: string | undefined
for (const msg of messages) {
// 当出现新的 assistant message.id 时,开始新的一组
if (
msg.type === 'assistant' &&
msg.message.id !== lastAssistantId &&
current.length > 0
) {
groups.push(current)
current = [msg]
} else {
current.push(msg)
}
if (msg.type === 'assistant') {
lastAssistantId = msg.message.id
}
}
if (current.length > 0) {
groups.push(current)
}
return groups
}
```
**设计细节:**
- 同一 API 请求的流式块共享同一个 `message.id`
- `StreamingToolExecutor` 在流式输出期间交错插入 `tool_result`但它们属于同一轮次
- 只要 `message.id` 不变所有消息都在同一组内
- 不跟踪未解决的 `tool_use` ID——让分组边界自然形成 `ensureToolResultPairing` API 层修复残留的配对问题
---
## 7. Token 估算算法
贯穿所有压缩路径的核心辅助
### 粗略估算
```typescript
function roughTokenCountEstimation(text: string): number {
return text.length / 4 // 经验法则4 字符 ≈ 1 token
}
```
### 消息级估算
```typescript
function estimateMessageTokens(messages: Message[]): number {
let totalTokens = 0
for (const message of messages) {
if (message.type !== 'user' && message.type !== 'assistant') continue
for (const block of message.message.content) {
switch (block.type) {
case 'text':
totalTokens += roughTokenCountEstimation(block.text)
break
case 'tool_result':
totalTokens += calculateToolResultTokens(block)
break
case 'image':
case 'document':
totalTokens += 2000 // 固定值,不论实际大小
break
case 'thinking':
totalTokens += roughTokenCountEstimation(block.thinking)
// 注意不计算签名signature 是元数据,不被模型 tokenize
break
case 'redacted_thinking':
totalTokens += roughTokenCountEstimation(block.data)
break
case 'tool_use':
totalTokens += roughTokenCountEstimation(
block.name + JSON.stringify(block.input ?? {})
)
// 不计算 JSON wrapper 和 id 字段
break
default:
totalTokens += roughTokenCountEstimation(JSON.stringify(block))
break
}
}
}
return Math.ceil(totalTokens * (4 / 3)) // 保守填充 33%
}
```
### 精确计算
```typescript
// 当有 API 响应的 usage 数据时,使用精确值
function tokenCountFromLastAPIResponse(messages: Message[]): number | undefined {
// 从最后一条 assistant 消息的 usage 字段读取
// usage.input_tokens 包含了 API 看到的实际 token 数
}
// 混合策略
function tokenCountWithEstimation(messages: Message[]): number {
// 优先使用 API 返回的精确值
// 不可用时回退到估算
}
```
---
## 8. 压缩提示词工程
**源文件:** `prompt.ts`
### 三种提示词模板
| 模板 | 变量名 | 用途 |
|------|--------|------|
| 完整压缩 | `BASE_COMPACT_PROMPT` | 摘要整个对话 |
| 部分压缩from | `PARTIAL_COMPACT_PROMPT` | 只摘要最近的消息 |
| 部分压缩up_to | `PARTIAL_COMPACT_UP_TO_PROMPT` | 摘要旧消息作为后续消息的前导 |
### 提示词结构
```
[NO_TOOLS_PREAMBLE] ← 强力禁止工具调用
[DETAILED_ANALYSIS_INSTRUCTION] ← 要求 <analysis> 思考草稿
[MAIN_PROMPT] ← 9 章节结构化摘要要求 + 示例
[Custom Instructions] ← 用户自定义指令(如果有)
[NO_TOOLS_TRAILER] ← 再次强调不要调用工具
```
### <analysis> 块的作用
```
提示词要求模型先在 <analysis> 中"打草稿"
1. 按时间顺序分析每条消息
2. 识别用户意图、技术决策、代码模式
3. 特别关注用户反馈("用户让你做不同的事情"
4. 双重检查技术准确性和完整性
这类似于 Chain-of-Thought但最终会被 formatCompactSummary() 删除,
只保留 <summary> 部分进入压缩后的上下文。
```
### 压缩后的摘要消息
```typescript
function getCompactUserSummaryMessage(summary, suppressFollowUp, transcriptPath, recentPreserved): string {
let msg = `This session is being continued from a previous conversation that ran out of context.
The summary below covers the earlier portion of the conversation.
${formatCompactSummary(summary)}`
// 如果有 transcript 路径,提供回溯指引
if (transcriptPath) {
msg += `\n\nIf you need specific details from before compaction
(like exact code snippets, error messages, or content you generated),
read the full transcript at: ${transcriptPath}`
}
// 如果保留了最近消息
if (recentMessagesPreserved) {
msg += `\n\nRecent messages are preserved verbatim.`
}
// 如果是自动压缩suppressFollowUp = true
if (suppressFollowUpQuestions) {
msg += `\nContinue the conversation from where it left off
without asking the user any further questions.
Resume directly — do not acknowledge the summary,
do not recap what was happening,
do not preface with "I'll continue" or similar.
Pick up the last task as if the break never happened.`
}
// 如果是 Proactive/KAIROS 模式
if (proactiveModule?.isProactiveActive()) {
msg += `\n\nYou are running in autonomous/proactive mode.
This is NOT a first wake-up — you were already working autonomously before compaction.
Continue your work loop: pick up where you left off based on the summary above.
Do not greet the user or ask what to work on.`
}
return msg
}
```
---
## 9. 5层错误恢复中的压缩角色
`query.ts` 5 层错误恢复机制中压缩系统承担了前 2
```
API 调用失败
第1层上下文折叠排水Context Collapse Drain
↓ 失败
第2层响应式压缩Reactive Compact ← 使用 compact.ts
↓ 失败
第3层最大输出升级8K → 64K tokens
↓ 失败
第4层多轮恢复注入"请继续"消息,最多 3 次)
↓ 失败
第5层模型回退切换到备用模型剥离 thinking 签名块)
↓ 失败
暴露错误给用户
```
**响应式压缩** vs **主动压缩**
| 属性 | 主动压缩Auto-Compact | 响应式压缩Reactive Compact |
|------|--------------------------|-------------------------------|
| 触发 | token 数超过阈值 | API 返回 prompt-too-long 错误 |
| 时机 | API 调用前 | API 调用失败后 |
| 路径 | `autoCompact.ts` `compact.ts` | `query.ts` 错误恢复层 |
| 回退 | SM 传统压缩 放弃 | 传统压缩 裁剪最旧消息 |
---
## 10. 各层对比与设计哲学
### 横向对比
| 属性 | 微压缩 | Session Memory | 传统压缩 | PTL Recovery |
|------|--------|---------------|----------|-------------|
| **调用 LLM** | | | Fork Agent | |
| **信息损失** | 最小仅删工具输出 | 中等靠已有摘要 | 中等9章摘要 | 丢弃最旧消息 |
| **延迟** | <1ms | <10ms | 5-30s | ~0 |
| **触发** | 每轮自动 | 自动压缩优先路径 | 自动/手动 | 压缩自身超限 |
| **prompt cache** | 保留缓存编辑 | 破坏 | 共享Fork | 破坏 |
| **最大输出** | | | 20K tokens | |
| **断路器** | | | 3次 | 3次 |
| **token 预算** | | 40K 最大保留 | 50K 文件重注入 | 按组裁剪 |
### 设计哲学总结
1. **渐进式降级**从无损操作微压缩到有损操作传统压缩到丢弃操作PTL Recovery每一层都比上一层代价更高
2. **缓存优先**微压缩的缓存编辑路径专门设计为不破坏 prompt cache传统压缩通过 Fork Agent 共享 cache
3. **安全性保证**
- 永远不切断 tool_use/tool_result 配对
- 永远不分离共享 message.id 的消息块
- 断路器防止失败时无限重试
- 递归保护防止压缩代理触发自身压缩
4. **可观测性**每个压缩操作都记录 `logEvent` `tengu_compact`, `tengu_cached_microcompact`包含压缩前后的 token 触发原因重试次数等
5. **可配置性**几乎所有阈值都支持环境变量覆盖用于测试 GrowthBook 远程配置用于动态调整
---
*来自AI超元域 | B站频道https://space.bilibili.com/3493277319825652*
*基于 Claude Code 源码逆向分析2026-03-31*

View File

@@ -0,0 +1,441 @@
# Claude Code 是否偷换模型?源码级逆向分析
> 基于 Claude Code 源码2026-03-31 快照512K 行 TypeScript逆向分析
> 核心文件:`src/utils/model/model.ts`、`src/services/api/withRetry.ts`、`src/query.ts`、`src/services/api/claude.ts`
---
## 结论先行
**不存在"偷换模型"。你的主对话模型完全由你控制,不会被偷偷降级。**
但 Claude Code 确实在后台使用 Haiku弱模型执行辅助任务配额检查、摘要生成等这些 Haiku 调用不会出现在你的对话中,也不会替代你与 Opus 的交互。
唯一可能改变主对话模型的场景是 **529 连续过载回退**Opus → Sonnet此时会显示明确的系统消息通知用户。
---
## 1. 主对话模型选择:完全由用户控制
### 模型选择优先级(源码确认)
```typescript
// src/utils/model/model.ts:92
function getMainLoopModel(): ModelName {
const model = getUserSpecifiedModelSetting()
if (model !== undefined && model !== null) {
return parseUserSpecifiedModel(model)
}
return getDefaultMainLoopModel()
}
// src/utils/model/model.ts:61
function getUserSpecifiedModelSetting(): ModelSetting | undefined {
// 优先级从高到低:
// 1. /model 命令(会话内切换)— 最高优先级
const modelOverride = getMainLoopModelOverride()
if (modelOverride !== undefined) return modelOverride
// 2. --model 启动参数 / ANTHROPIC_MODEL 环境变量 / settings.json
return process.env.ANTHROPIC_MODEL || settings.model || undefined
}
```
**你设了 Opus主对话就用 Opus。没有任何代码在你不知情的情况下把它换掉。**
### 默认模型
```typescript
// src/utils/model/model.ts:105
function getDefaultOpusModel(): ModelName {
// 支持环境变量覆盖
if (process.env.ANTHROPIC_DEFAULT_OPUS_MODEL) {
return process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
}
return getModelStrings().opus46 // 默认 Opus 4.6
}
function getDefaultSonnetModel(): ModelName {
if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL) {
return process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
}
// 3P 提供商默认 Sonnet 4.5(可能尚未支持 4.6
if (getAPIProvider() !== 'firstParty') return getModelStrings().sonnet45
return getModelStrings().sonnet46
}
function getDefaultHaikuModel(): ModelName {
if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
return process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
}
return getModelStrings().haiku45 // Haiku 4.5(所有平台通用)
}
```
---
## 2. 唯一会改变主对话模型的场景529 过载回退
### 触发条件(极其严格)
```typescript
// src/services/api/withRetry.ts:326-350
// 必须同时满足以下所有条件:
// 1. 收到 529 错误(服务器过载)
// 2. 连续 529 次数 >= MAX_529_RETRIES
// 3. 配置了 fallbackModel
// 4. 以下二选一:
// a. 设置了 FALLBACK_FOR_ALL_PRIMARY_MODELS 环境变量
// b. 非 Claude.ai 订阅用户 且 使用非自定义 Opus 模型
if (is529Error(error) &&
(process.env.FALLBACK_FOR_ALL_PRIMARY_MODELS ||
(!isClaudeAISubscriber() && isNonCustomOpusModel(options.model)))) {
consecutive529Errors++
if (consecutive529Errors >= MAX_529_RETRIES) {
if (options.fallbackModel) {
// 触发回退
throw new FallbackTriggeredError(options.model, options.fallbackModel)
}
}
}
```
**关键限制:**
| 条件 | 说明 |
|------|------|
| `!isClaudeAISubscriber()` | **Claude.ai 订阅用户默认不触发回退** |
| `isNonCustomOpusModel()` | 仅对标准 Opus 模型生效(自定义模型 ID 不触发) |
| `MAX_529_RETRIES` | 需要连续多次 529 才触发 |
### 回退执行过程(透明可见)
```typescript
// src/query.ts:894-946
if (innerError instanceof FallbackTriggeredError && fallbackModel) {
// 1. 切换模型
currentModel = fallbackModel // Opus → Sonnet不是 Haiku
// 2. 清理孤立的 assistant 消息
yield* yieldMissingToolResultBlocks(assistantMessages, 'Model fallback triggered')
assistantMessages.length = 0
// 3. 剥离 thinking 签名块(签名绑定原模型,发给回退模型会导致 400
// 源码注释:
// "Strip before retry so the fallback model gets clean history."
// 4. 更新工具上下文中的模型引用
toolUseContext.options.mainLoopModel = fallbackModel
// 5. 记录分析事件
logEvent('tengu_api_opus_fallback_triggered', {
original_model: options.model,
fallback_model: options.fallbackModel,
})
// 6. 显示系统消息通知用户(在 UI 中可见)
`Switched to ${renderModelName(fallbackModel)} due to high demand
for ${renderModelName(originalModel)}`
}
```
### 回退目标
```typescript
// src/main.tsx:1336-1337
// 回退模型必须与主模型不同
if (fallbackModel && options.model && fallbackModel === options.model) {
// 验证失败,不设置回退
}
// 回退目标是 Sonnet不是 Haiku
// 通过 getDefaultSonnetModel() 获取
```
### 用户如何知道发生了回退
回退时UI 中会显示一条系统消息:
```
Switched to Claude Sonnet 4.6 due to high demand for Claude Opus 4.6
```
同时在 `AssistantTextMessage.tsx:178` 中提供操作建议:
```
To continue immediately, use /model to switch to Sonnet and continue coding.
```
---
## 3. 后台辅助任务使用 Haiku — 不影响主对话
Claude Code 在后台使用 Haiku`getSmallFastModel()`)执行多种轻量辅助任务。这些调用**完全独立于你的对话**,不会出现在消息流中。
### 所有 Haiku 使用场景(逐一列出)
#### 3.1 配额检查
```typescript
// src/services/claudeAiLimits.ts:199-218
async function makeTestQuery() {
const model = getSmallFastModel() // → Haiku
const anthropic = await getAnthropicClient({ maxRetries: 0, model, source: 'quota_check' })
// 发送 max_tokens: 1 的最小请求,仅读取响应头的配额信息
return anthropic.beta.messages.create({
model,
max_tokens: 1,
messages: [{ role: 'user', content: 'quota' }],
}).asResponse()
}
```
**用途:** 检测用户是否已达配额限制。只读取 HTTP 响应头,不使用模型输出。
#### 3.2 离开摘要Away Summary
```typescript
// src/services/awaySummary.ts:44-52
// 当用户长时间离开后返回时,生成一个简短摘要
{
thinkingConfig: { type: 'disabled' }, // 关闭思考
tools: [], // 不给工具
model: getSmallFastModel(), // → Haiku
}
```
**用途:** 用户长时间不操作后返回时,快速生成"你离开期间发生了什么"的简要摘要。
#### 3.3 Token 计数
```typescript
// src/services/api/claude.ts:540-543
// WARNING: if you change this to use a non-Haiku model,
// this request will fail in 1P unless it uses getCLISyspromptPrefix.
const model = getSmallFastModel() // → Haiku
// 调用 countTokens API 获取精确 token 数
```
**用途:** 调用 Anthropic 的 `countTokens` 端点获取精确 token 计数,用于自动压缩阈值判断。
#### 3.4 工具使用摘要
```typescript
// src/services/api/claude.ts:3273-3280
// 在主模型流式输出期间,并行用 Haiku 生成工具调用的简短描述
{
model: getSmallFastModel(), // → Haiku
enablePromptCaching: false,
}
```
**用途:** 当模型连续调用多个工具时,生成简短的工具使用描述(如"读取了 config.ts 并修改了第 42 行")。
源码注释明确说明了并行关系:
```typescript
// src/query.ts:1054
// Yield tool use summary from previous turn —
// haiku (~1s) resolved during model streaming (5-30s)
```
Haiku 在后台 1 秒内完成摘要,同时 Opus 还在处理你的主对话。
#### 3.5 记忆相关性评分
```typescript
// src/memdir/findRelevantMemories.ts
// 用 Sonnet非 Haiku评估记忆文件的相关性
// 从标题中选择最多 5 条与当前查询相关的记忆
```
#### 3.6 Web 搜索预处理
```typescript
// src/tools/WebSearchTool/WebSearchTool.ts:280
model: useHaiku ? getSmallFastModel() : context.options.mainLoopModel,
toolChoice: useHaiku ? { type: 'tool', name: 'web_search' } : undefined,
```
**用途:** 当条件满足时(`useHaiku` 标志),用 Haiku 预处理搜索查询。
#### 3.7 其他辅助调用
| 调用者 | 模型 | 用途 |
|--------|------|------|
| `tokenEstimation.ts` | Haiku | Vertex 全局区域 token 计数回退 |
| `analyzeContext.ts` | Haiku | 上下文分析的 countTokens 回退 |
| `claudeAiLimits.ts` | Haiku | 配额状态检查 |
| Bedrock `client.ts` | Haiku | 小模型可指定不同 AWS 区域 |
### 辅助任务 vs 主对话的隔离
```
你的对话:
用户 → [Opus 4.6] → 助手响应 → [Opus 4.6] → 助手响应 → ...
后台并行:
[Haiku] → 配额检查1 token
[Haiku] → 工具使用摘要(~1s
[Haiku] → token 计数
两条线完全隔离Haiku 的输出不进入你的对话消息流。
```
---
## 4. Fast Mode同模型加速不换模型
这是一个常见误解,源码中有明确声明:
```typescript
// src/constants/prompts.ts:702
`Fast mode for Claude Code uses the same ${FRONTIER_MODEL_NAME} model
with faster output. It does NOT switch to a different model.
It can be toggled with /fast.`
```
Fast Mode 通过 API 的 speed 参数请求更快的输出,模型不变。如果 API 拒绝 fast mode如组织未启用会自动降回标准速度
```typescript
// src/services/api/withRetry.ts:310-313
if (wasFastModeActive && isFastModeNotEnabledError(error)) {
handleFastModeRejectedByAPI()
retryContext.fastMode = false
continue // 重试,同一模型,标准速度
}
```
---
## 5. Plan Mode 临时模型切换 — 透明可见
```typescript
// src/commands/model/model.tsx:214
// Do not update fast mode in settings since this is an automatic downgrade
// src/commands/model/model.tsx:256
onDone(`Current model: ${chalk.bold(renderModelLabel(mainLoopModelForSession))}
(session override from plan mode)\nBase model: ${displayModel}`)
```
Plan Mode 可能临时使用 Sonnet 执行实现步骤,但:
- UI 显示 "session override from plan mode"
- 显示 Base model 让你知道原始模型
- 不修改 settings 中的模型设置
---
## 6. Effort 降级 — 不换模型,换参数
```typescript
// src/utils/effort.ts:162
// API rejects 'max' on non-Opus-4.6 models — downgrade to 'high'.
```
如果设置了 `effort: max` 但模型不支持,会降级 effort 参数max → high不换模型。
---
## 7. 全局搜索:不存在的场景
通过对 512K 行源码的全局搜索,以下场景**被确认不存在**
| 假设的偷换场景 | 搜索结果 | 证据 |
|----------------|----------|------|
| 根据订阅层级偷换弱模型 | **不存在** | `getMainLoopModel()` 不检查订阅类型 |
| 根据额度用量偷换弱模型 | **不存在** | 额度用完返回 429 错误,不换模型 |
| 随机/概率性降级到弱模型 | **不存在** | 无 `Math.random()` 与模型选择相关的代码 |
| A/B 测试使用弱模型回答 | **不存在** | GrowthBook 控制功能开关,不控制模型 |
| 静默替换后不通知用户 | **不存在** | 529 回退有系统消息,其他场景不换主模型 |
| 把 Opus 对话路由到 Haiku | **不存在** | Haiku 仅用于辅助任务 |
| 根据问题复杂度选择弱模型 | **不存在** | 主循环始终使用用户指定的模型 |
| 根据时间段降级(如高峰期) | **不存在** | 无时间相关的模型选择逻辑 |
| 首次用户用弱模型 | **不存在** | 默认模型是 Opus 4.6 |
---
## 8. 模型使用全景图
```
┌─────────────────────────────────────────────────────────┐
│ 你的主对话 │
│ │
│ 模型:你指定的(默认 Opus 4.6
│ 控制:/model 命令 > --model 参数 > 环境变量 > 设置 │
│ 唯一例外529 连续过载 → Sonnet 回退(有通知) │
│ │
├─────────────────────────────────────────────────────────┤
│ 后台辅助任务Haiku
│ │
│ 配额检查 → 1 token 请求,只读响应头 │
│ Token 计数 → countTokens API 调用 │
│ 工具摘要 → 并行于主对话,~1s 完成 │
│ 离开摘要 → 用户回来时显示简要信息 │
│ Web 搜索 → 搜索查询预处理(条件触发) │
│ │
│ 这些不进入你的对话消息流 │
│ │
├─────────────────────────────────────────────────────────┤
│ Fork Agent 任务 │
│ │
│ 上下文压缩 → 使用你的主模型(共享 prompt cache
│ 记忆提取 → 使用你的主模型 │
│ 权限分类器 → Haikuauto 模式下的命令安全分类) │
│ │
│ 压缩结果进入上下文,但不替代你的对话 │
└─────────────────────────────────────────────────────────┘
```
---
## 9. 如何验证你正在使用的模型
### 方法 1查看 API 响应
每条助手消息的内部结构中包含模型信息:
```typescript
// AssistantMessage.message.model 字段包含实际使用的模型 ID
// 例如:"claude-opus-4-6-20260301"
```
### 方法 2使用 /cost 命令
`/cost` 命令显示按模型分类的 token 使用量,你可以看到每个模型消耗了多少 token。
### 方法 3检查 status line
状态栏显示当前模型名称。如果发生回退,会更新为回退后的模型。
### 方法 4环境变量调试
```bash
# 查看所有 API 调用的模型信息
export CLAUDE_CODE_DEBUG=1
# 强制禁用回退
unset FALLBACK_FOR_ALL_PRIMARY_MODELS
```
---
## 10. 总结
| 问题 | 答案 | 依据 |
|------|------|------|
| Opus 会被偷偷换成 Haiku 吗? | **不会** | Haiku 仅用于辅助任务,不进入主对话 |
| Opus 会被偷偷换成 Sonnet 吗? | **仅在 529 连续过载时,且会通知** | `withRetry.ts:347` + `query.ts:946` |
| Claude.ai 订阅用户会被降级吗? | **默认不会** | `!isClaudeAISubscriber()` 条件排除 |
| 后台有 Haiku 调用吗? | **有,但不影响你的对话** | 6 种辅助任务,全部隔离 |
| Fast Mode 换模型吗? | **不换** | 源码明确声明 "does NOT switch to a different model" |
| 有没有根据问题难度选模型? | **没有** | 主循环始终使用用户指定模型 |
**一句话:你付费用 Opus对话就用 Opus。Haiku 只在幕后干杂活。**
---
*来自AI超元域 | B站频道https://space.bilibili.com/3493277319825652*
*基于 Claude Code 源码逆向分析2026-03-31*

View File

@@ -0,0 +1,764 @@
# Claude Code Memory 记忆系统深度分析
> 基于 Claude Code 源码2026-03-31 快照512K 行 TypeScript逆向分析
> 核心文件:`src/memdir/`8个文件、`src/services/extractMemories/`2个、`src/services/SessionMemory/`3个、`src/services/teamMemorySync/`5个
---
## 1. 三层记忆架构总览
Claude Code 的记忆系统不是一个简单的文件存储,而是一个**三层递进的知识管理体系**
```
┌─────────────────────────────────────────────────────────────┐
│ 第3层团队记忆Team Memory
│ 跨用户、按仓库 │ 服务端同步 │ REST API + 乐观锁 │
│ 秘密扫描保护 │ 文件监听器 │ 30种凭证检测规则 │
├─────────────────────────────────────────────────────────────┤
│ 第2层持久记忆Persistent Memory / extractMemories
│ 跨会话、按项目 │ 本地文件 │ 后台 Fork Agent 自动提取 │
│ 4种类型分类 │ MEMORY.md 索引 │ AI 相关性召回 │
├─────────────────────────────────────────────────────────────┤
│ 第1层会话记忆Session Memory
│ 仅当前会话 │ 单个文件 │ 10个固定章节 │ 服务于压缩 │
└─────────────────────────────────────────────────────────────┘
```
| 层级 | 范围 | 持久性 | 触发方式 | 存储位置 |
|------|------|--------|----------|----------|
| 会话记忆 | 当前会话 | 临时(会话结束即停用) | 后采样钩子token+工具调用阈值) | 会话目录下单文件 |
| 持久记忆 | 跨会话、按项目 | 永久(直到手动删除) | 每轮查询结束时Stop Hook | `~/.claude/projects/<项目>/memory/` |
| 团队记忆 | 跨用户、按仓库 | 远程服务器 + 本地镜像 | 文件监听器2秒去抖 | `memory/team/` + Anthropic API |
---
## 2. 持久记忆系统(核心)
### 2.1 记忆文件格式
每条记忆是一个独立的 Markdown 文件,带 YAML frontmatter
```markdown
---
name: 用户偏好-简洁回复
description: 用户不希望在每次回复末尾加总结
type: feedback
---
不要在回复末尾总结刚做了什么,用户能看到 diff。
**Why:** 用户明确要求过"stop summarizing what you just did"
**How to apply:** 所有回复结束时,直接结束,不加回顾性总结。
```
### 2.2 四种记忆类型
```typescript
const MEMORY_TYPES = ['user', 'feedback', 'project', 'reference'] as const
```
| 类型 | 用途 | 保存时机 | 作用域(团队模式) |
|------|------|----------|:------------------:|
| **user** | 用户角色、目标、知识背景 | 了解到用户的身份信息时 | 始终私有 |
| **feedback** | 用户对工作方式的指导 | 用户纠正或确认做法时 | 默认私有 |
| **project** | 项目进展、目标、事件 | 了解到工作计划、截止日期时 | 偏向团队 |
| **reference** | 外部系统指针 | 了解到 Linear/Grafana/Slack 等资源时 | 通常团队 |
**每种类型要求的结构:**
- feedback 和 project 类型必须包含 `**Why:**``**How to apply:**`
- 相对日期必须转换为绝对日期(如"周四"→"2026-03-05"
- user 类型的示例:"深度 Go 经验React 新手——用后端类比解释前端概念"
### 2.3 明确不保存的内容
源码中硬编码了 6 类排除项(即使用户明确要求也不保存):
1. 代码模式、架构、文件路径、项目结构——可从代码推导
2. Git 历史、最近变更——`git log`/`git blame` 是权威来源
3. 调试方案或修复步骤——修复在代码中commit message 有上下文
4. CLAUDE.md 中已有的内容——不重复
5. 临时任务细节:进行中的工作、当前对话上下文
6. 如果用户要求保存 PR 列表或活动摘要,要追问"什么是令人意外的或不明显的?"——只保存那部分
### 2.4 MEMORY.md 索引机制
```
MEMORY.md 是索引,不是记忆本身
```
**格式:** 纯 Markdown无 frontmatter。每条一行约 150 字符以内:
```markdown
- [用户偏好-简洁回复](feedback_concise.md) — 不在回复末尾加总结
- [项目-合并冻结](project_freeze.md) — 3月5日起移动端发布冻结
```
**限制:**
- 最大 200 行(`MAX_ENTRYPOINT_LINES`
- 最大 25,000 字节(`MAX_ENTRYPOINT_BYTES`
- 超出时在末尾追加截断警告
- 截断按行边界执行(不会切断一行的中间)
**两步保存流程:**
1. 写入记忆文件(如 `feedback_concise.md`
2. 在 MEMORY.md 中添加索引行
可选的 `skipIndex` 模式(通过 `tengu_moth_copse` 特性开关可跳过第2步。
### 2.5 存储目录结构
```
~/.claude/
projects/
-Users-charlesqin-Desktop-myproject/ ← sanitizePath(项目根目录)
memory/ ← AUTO_MEM_DIRNAME
MEMORY.md ← 索引文件
user_role.md ← 私有记忆文件
feedback_testing.md
project_deadline.md
reference_linear.md
team/ ← 团队记忆子目录
MEMORY.md ← 团队索引
project_api_migration.md
reference_oncall_board.md
logs/ ← KAIROS 每日日志
2026/
03/
2026-03-31.md
```
### 2.6 路径安全机制
`paths.ts` 包含多层安全验证:
| 安全层 | 检查内容 | 防御目标 |
|--------|----------|----------|
| 绝对路径检查 | 拒绝相对路径 | 路径遍历 |
| 根路径检查 | 拒绝长度 < 3 的路径 | 写入系统根目录 |
| UNC 路径检查 | 拒绝 `\\server\share` `//server/share` | NTLM 凭证泄露 |
| Null 字节检查 | 拒绝包含 `\0` 的路径 | 路径截断攻击 |
| Tilde 展开限制 | 拒绝 `~``~/``~/.``~/..` | 匹配整个 HOME |
| **项目设置排除** | `.claude/settings.json` 不能设 `autoMemoryDirectory` | **恶意仓库重定向写入到 `~/.ssh`** |
| NFC 规范化 | Unicode NFC 标准化 | macOS 路径不一致 |
| Git 根规范化 | worktree 共享主仓库的记忆 | 避免重复记忆目录 |
**关键安全设计:** `projectSettings`提交到仓库的 `.claude/settings.json`被有意排除在 `autoMemoryDirectory` 的信任来源之外源码注释明确说明原因
```typescript
// SECURITY: projectSettings is intentionally excluded —
// a malicious repo could set autoMemoryDirectory: "~/.ssh"
// and gain write access to sensitive directories
```
---
## 3. 自动记忆提取extractMemories
### 3.1 触发时机
```
用户输入 → 模型响应 → 工具执行 → 循环... → 模型最终响应(无工具调用)
Stop Hooks 执行
executeExtractMemories() ← 即发即忘
```
**前置条件(全部满足才执行):**
1. `EXTRACT_MEMORIES` 编译时特性开关开启
2. `isExtractModeActive()` = true`tengu_passport_quail` GrowthBook 开关
3. `isAutoMemoryEnabled()` = true
4. 非子代理`!toolUseContext.agentId`
5. bare 模式
6. 自上次提取以来有新的模型可见消息
### 3.2 互斥机制
```typescript
// 如果主代理在对话中已经直接写了记忆文件,跳过自动提取
if (hasMemoryWritesSince(lastMemoryMessageUuid)) {
// 推进游标但不执行提取——避免覆盖用户显式保存的记忆
lastMemoryMessageUuid = messages[messages.length - 1].uuid
return
}
```
这防止了自动提取和用户手动保存之间的冲突
### 3.3 Fork Agent 执行
```typescript
const result = await runForkedAgent({
messages: conversationMessages,
system: extractionPrompt,
maxTurns: 5, // 硬上限5轮读1轮 + 写1-4轮
canUseTool: createAutoMemCanUseTool(autoMemPath),
// ... 共享主会话的 prompt cache
})
```
**工具权限白名单:**
| 工具 | 权限 |
|------|------|
| FileRead | 允许无限制 |
| Grep | 允许无限制 |
| Glob | 允许无限制 |
| Bash | 仅只读命令ls, find, grep, cat, stat, wc, head, tail |
| FileEdit | 仅限 `autoMemPath` |
| FileWrite | 仅限 `autoMemPath` |
| MCP / Agent / 写入型 Bash | **全部禁止** |
### 3.4 提取节流
```typescript
let turnsSinceLastExtraction = 0
const turnsBeforeExtraction = getFeatureValue('tengu_bramble_lintel', 1)
// 每 N 轮查询才执行一次提取(默认每轮都执行)
if (turnsSinceLastExtraction < turnsBeforeExtraction) {
turnsSinceLastExtraction++
return
}
```
### 3.5 提取后通知
成功提取后将写入的文件路径列表作为 `SystemMemorySavedMessage` 追加到主对话中这样主代理知道记忆已更新
---
## 4. AI 驱动的记忆召回findRelevantMemories
### 4.1 召回流程
```
用户发送消息
scanMemoryFiles(memoryDir)
↓ 递归读取所有 .md 文件(排除 MEMORY.md
↓ 解析前 30 行 frontmatterdescription + type
↓ 按 mtime 降序排序,上限 200 个文件
过滤掉 alreadySurfaced之前轮次已展示的路径
selectRelevantMemories(query, memories, signal, recentTools)
↓ 构建文本清单:每行 "- [type] filename (timestamp): description"
↓ 附加 "Recently used tools: ..." 部分
sideQuery → Sonnet 模型
↓ 系统提示SELECT_MEMORIES_SYSTEM_PROMPT
↓ 用户消息Query + Available memories
↓ 结构化输出:{ selected_memories: string[] }
↓ max_tokens: 256
返回最多 5 条 RelevantMemory路径 + mtime
```
### 4.2 选择提示词的关键规则
```
- 返回最多 5 个文件名
- 要有选择性和辨别力;如果不确定,不要包含
- 如果提供了最近使用的工具列表:
✗ 不要选择这些工具的使用参考/API 文档(已经在用了)
✓ 仍然选择这些工具的警告/陷阱/已知问题
```
### 4.3 记忆新鲜度标注
```typescript
function memoryAge(mtimeMs: number): string {
const days = memoryAgeDays(mtimeMs)
if (days === 0) return 'today'
if (days === 1) return 'yesterday'
return `${days} days ago`
}
function memoryFreshnessText(mtimeMs: number): string {
if (memoryAgeDays(mtimeMs) <= 1) return '' // 新鲜记忆不加警告
return `This memory is ${days} days old.
Memories are point-in-time observations, not live state —
claims about code behavior or file:line citations may be outdated.
Verify against current code before asserting as fact.`
}
```
**设计动机(源码注释):** 用户报告过过期的记忆被模型当作事实断言。"47 days ago" ISO 时间戳更能触发模型的过期推理
### 4.4 召回前的验证要求
源码中注入的系统提示明确要求模型在使用记忆前验证
```
- 如果记忆提到一个文件路径 → 检查文件是否存在
- 如果记忆提到一个函数或标志 → grep 搜索它
- 如果用户即将根据你的建议行动 → 先验证
- "记忆说 X 存在"不等于"X 现在存在"
- 活动日志、架构快照是冻结在某个时间点的,优先使用 git log
```
---
## 5. 会话记忆Session Memory
### 5.1 与持久记忆的关键区别
| 维度 | 会话记忆 | 持久记忆 |
|------|----------|----------|
| 生命周期 | 当前会话 | 跨会话永久 |
| 文件数量 | 1 | 多个 |
| 触发频率 | 每次后采样需满足阈值 | 每轮查询结束 |
| 主要用途 | **服务于上下文压缩** | 跨会话知识保留 |
| 记忆提取者 | Fork Agent FileEdit | Fork AgentRead/Write/Edit/Grep |
| 格式 | 10个固定章节 | 自由格式 + frontmatter |
### 5.2 触发阈值
```typescript
// 默认配置(可通过 GrowthBook tengu_sm_config 远程调整)
const defaults = {
minimumMessageTokensToInit: 10_000, // 上下文达到 10K tokens 才激活
minimumTokensBetweenUpdate: 5_000, // 每增长 5K tokens 更新一次
toolCallsBetweenUpdates: 3, // 且至少 3 次工具调用
}
// 触发条件:
// (token 阈值满足 AND 工具调用阈值满足)
// OR (token 阈值满足 AND 最后一轮助手消息无工具调用)
```
### 5.3 会话记忆模板10 个固定章节)
```markdown
# Session Memory
## Session Title
_Brief description of what this session is about_
## Current State
_What is the current status of the work_
## Task specification
_Detailed description of the current task requirements_
## Files and Functions
_Key files and functions being worked on_
## Workflow
_Steps being followed or processes in use_
## Errors & Corrections
_Errors encountered and how they were resolved_
## Codebase and System Documentation
_Important codebase patterns, conventions, and system behavior_
## Learnings
_Insights gained during this session_
## Key results
_Important outputs, measurements, or achievements_
## Worklog
_Chronological log of actions taken_
```
### 5.4 大小限制
```typescript
const MAX_SECTION_LENGTH = 2_000 // 每个章节最大 2K tokens
const MAX_TOTAL_SESSION_MEMORY_TOKENS = 12_000 // 整个文件最大 12K tokens
```
### 5.5 与压缩的集成
Session Memory 是上下文压缩的优先路径参见 `sessionMemoryCompact.ts`
- 自动压缩触发时优先尝试用 Session Memory 作为摘要
- 保留最近 10K-40K tokens 的消息
- 比传统压缩快得多不调用 LLM且摘要质量更可预测
### 5.6 自定义
用户可以自定义模板和提示词
- 模板`~/.claude/session-memory/config/template.md`
- 提示词`~/.claude/session-memory/config/prompt.md`支持 `{{variableName}}` 替换
---
## 6. 团队记忆同步
### 6.1 前置条件
同时满足才启用
1. `TEAMMEM` 编译时特性开关开启
2. `isTeamMemoryEnabled()` = true`tengu_herring_clock` GrowthBook 开关
3. 第一方 OAuth + 同时拥有 `INFERENCE_SCOPE` `PROFILE_SCOPE`
4. Git remote github.com GitHub 仓库不同步
### 6.2 API 端点
```
基础 URL: {baseUrl}/api/claude_code/team_memory?repo={owner/repo}
```
| 方法 | 参数 | 用途 | 关键状态码 |
|------|------|------|:----------:|
| GET | `repo={slug}` | 拉取全部团队记忆 | 200 / 304 / 404 |
| GET | `repo={slug}&view=hashes` | 仅拉取哈希轻量探测 | 200 / 404 |
| PUT | `repo={slug}` | 上传记忆条目upsert | 200 / 412 / 413 |
**认证头:** `Authorization: Bearer {oauthToken}`
### 6.3 同步协议
#### 拉取Pull
```
1. GET 请求,携带 ETag条件请求
2. 304 = 未变化,跳过
3. 200 = 有更新:
a. 对每个条目验证路径(防遍历攻击)
b. 跳过 >250KB 的文件
c. 跳过本地内容已匹配的文件
d. 并行写入本地文件系统
e. 刷新 serverChecksums
```
#### 推送Push — Delta 上传 + 乐观锁)
```
1. readLocalTeamMemory(): 遍历 team/ 目录
→ 每个文件扫描秘密30种规则
→ 跳过 >250KB 的文件
→ 计算 SHA-256 哈希
2. 计算 delta仅本地哈希与 serverChecksums 不同的 key
3. 分批上传:贪心装箱,每批 ≤ 200KB (MAX_PUT_BODY_BYTES)
4. 每批携带 If-Match 头(乐观锁)
5. 冲突处理:
412 Conflict → 探测 ?view=hashes → 刷新 serverChecksums → 重算 delta → 重试(最多 2 次)
413 Too Many → 学习 serverMaxEntries 上限,截断后重试
6. 冲突策略本地优先local-wins
→ 当前用户正在编辑的内容覆盖服务端
```
### 6.4 文件监听器
```typescript
// watcher.ts
fs.watch(teamMemDir, { recursive: true })
// macOS: FSEventsO(1) 文件描述符)
// Linux: inotifyO(子目录数)
// 2 秒去抖:最后一次变更后 2 秒才触发推送
```
**推送抑制:** 永久失败no_oauthno_repo4xx 409/429抑制后续推送直到发生文件删除恢复动作或会话重启
### 6.5 团队 vs 私有的作用域划分
源码注入的系统提示中每种记忆类型都带有 XML 作用域标签
```xml
<type>
<name>user</name>
<scope>always private</scope>
...
</type>
<type>
<name>project</name>
<scope>strongly bias toward team</scope>
...
</type>
```
额外安全要求
```
MUST avoid saving sensitive data within shared team memories
```
---
## 7. 秘密扫描保护
### 7.1 双层防护
| | 时机 | 文件 | 行为 |
|----|------|------|------|
| 写入时拦截 | FileWrite/FileEdit 调用 | `teamMemSecretGuard.ts` | 阻止写入返回错误 |
| 上传前扫描 | pushTeamMemory 读取本地文件 | `secretScanner.ts` | 跳过该文件不上传 |
### 7.2 检测的 30 种秘密模式
**云服务商:**
- AWS Access TokenA3T/AKIA/ASIA/ABIA/ACCA 前缀
- GCP API KeyAIza 前缀
- Azure AD Client Secret
- DigitalOcean PAT / Access Token
**AI API**
- Anthropic API Key`sk-ant-api03-` 前缀运行时拼接避免自身匹配
- Anthropic Admin API Key`sk-ant-admin01-`
- OpenAI API Key`sk-proj`/`svcacct`/`admin` + `T3BlbkFJ` 标记
- HuggingFace Access Token`hf_`
**版本控制:**
- GitHub PAT / Fine-grained PAT / App Token / OAuth / Refresh Token
- GitLab PAT / Deploy Token
**通信平台:**
- Slack Bot/User/App Token`xoxb-`/`xoxp-`/`xapp-`
- Twilio API Key
- SendGrid API Token
**开发工具:**
- npm Access Token
- PyPI Upload Token
- Databricks API Token
- HashiCorp Terraform API Token
- Pulumi API Token
- Postman API Token
**可观测性:**
- Grafana API Key / Cloud API Token / Service Account Token
- Sentry User/Org Token
**支付:**
- Stripe Access Token`sk_test`/`live`/`prod` `rk_`
- Shopify Access Token / Shared Secret
**密码学:**
- PEM 格式私钥`BEGIN/END PRIVATE KEY`
### 7.3 设计原则
```typescript
// 匹配到的秘密值永远不被记录或返回——只返回规则 ID 和人类可读标签
// Anthropic API key 前缀在运行时拼接,避免匹配自身的 excluded-strings 检查:
const prefix = ['sk', 'ant', 'api'].join('-')
```
---
## 8. KAIROS 模式的记忆(每日日志)
KAIROSAI 助手模式激活时记忆范式完全改变
```
普通模式:写独立文件 + 更新 MEMORY.md 索引
KAIROS 模式:追加到 logs/YYYY/MM/YYYY-MM-DD.md 日志文件
```
- 只追加不编辑已有内容
- 每日一个文件按日期路径组织
- 由单独的 `/dream` 技能在夜间蒸馏日志为主题文件和 MEMORY.md
- 提示词中使用 `YYYY-MM-DD` 占位符而非实际日期因为提示词被缓存日期变化不会触发失效
---
## 9. 记忆系统注入的完整系统提示词
### 9.1 个人模式auto memory
```
# auto memory
You have a persistent, file-based memory system at `<memoryDir>`.
This directory already exists — write to it directly with the Write tool.
You should build up this memory system over time so that future conversations
can have a complete picture of who the user is, how they'd like to collaborate
with you, what behaviors to avoid or repeat, and the context behind the work.
[如果用户要求记住 → 立即保存]
[如果用户要求忘记 → 找到并删除]
## Types of memory
[4种类型每种含 description/when_to_save/how_to_use/examples]
## What NOT to save in memory
[6类排除项]
## How to save memories
Step 1: 写入文件(带 frontmatter
Step 2: 在 MEMORY.md 中添加索引行
## When to access memories
- 看起来相关时
- 用户明确要求时(必须访问)
- 用户说"忽略记忆"时,假装 MEMORY.md 为空
## Before recommending from memory
- 提到文件路径 → 检查文件是否存在
- 提到函数/标志 → grep 搜索
- 用户要行动 → 先验证
## Memory and other forms of persistence
- 实施方案 → 用 Plan不用记忆
- 当前对话步骤 → 用 Tasks不用记忆
## Searching past context
[grep 记忆文件,或搜索会话 transcript]
## MEMORY.md
[实际的 MEMORY.md 内容,或"当前为空"]
```
### 9.2 团队模式额外内容
在个人模式基础上增加
```
## Memory scope
- 私有记忆:<privateDir> — 你的个人偏好、反馈
- 团队记忆:<teamDir> — 项目上下文、外部引用
[类型定义中增加 <scope> XML 标签]
额外安全规则:不得在团队记忆中保存敏感数据
```
---
## 10. 团队记忆的路径安全(深度防御)
`teamMemPaths.ts` 是整个记忆系统中安全措施最密集的文件
### 10.1 自定义错误类
```typescript
class PathTraversalError extends Error {
name = 'PathTraversalError'
}
```
### 10.2 sanitizePathKey — 服务端提供的相对路径清理
```typescript
function sanitizePathKey(key: string): string {
// 1. 拒绝 null 字节
// 2. URL 编码遍历检测:解码 %2e%2e%2f 等
// 3. Unicode 规范化攻击:全角字符 \uFF0E\uFF0E\uFF0F → ../
// 4. 拒绝反斜杠Windows 路径遍历)
// 5. 拒绝绝对路径
}
```
### 10.3 realpathDeepestExisting — 符号链接解析
```typescript
async function realpathDeepestExisting(path: string): Promise<string> {
// 逐级向上 realpath() 直到成功
// 检测悬挂符号链接link 存在但 target 不存在)
// → 安全威胁writeFile 会跟随链接在 team 目录外创建文件
// 检测符号链接循环ELOOP→ PathTraversalError
// 不可恢复的错误EACCES, EIO→ fail-closed
}
```
### 10.4 validateTeamMemWritePath — 双重验证
```
写入团队记忆文件前的完整验证链:
第1遍字符串级
1. Null 字节检查
2. path.resolve() 解析
3. startsWith(teamDir) 验证
第2遍符号链接级
4. realpathDeepestExisting() 解析实际路径
5. isRealPathWithinTeamDir() 验证实际路径在团队目录内
通过 → 返回解析后的路径
失败 → 抛出 PathTraversalError
```
### 10.5 前缀攻击防护
```typescript
// 团队目录路径以分隔符结尾:/foo/team/
// 这样 /foo/team-evil/ 不会通过 startsWith 检查
```
---
## 11. 记忆的生命周期全景
```
会话开始
├─ loadMemoryPrompt()
│ → 读取 MEMORY.md → 注入系统提示
├─ initSessionMemory()
│ → 注册后采样钩子
├─ startTeamMemoryWatcher()
│ → 拉取服务端 → 启动文件监听
每轮对话
├─ findRelevantMemories(query)
│ → 扫描文件 → Sonnet 选择 → 返回最多 5 条
│ → 新鲜度标注(>1天 → 加过期警告)
├─ [模型可能直接读/写记忆文件]
│ → 写入团队记忆 → checkTeamMemSecrets() 拦截秘密
│ → 文件监听触发 → 2秒后推送到服务端
├─ Session Memory 后采样钩子
│ → 检查阈值 → Fork Agent 更新单文件
├─ 模型最终响应(无工具调用)
│ → Stop Hooks → executeExtractMemories()
│ → 互斥检查 → Fork Agent 提取 → 更新持久记忆文件
自动压缩触发时
├─ trySessionMemoryCompaction()(优先路径)
│ → 用 Session Memory 内容作为摘要
│ → 保留最近 10K-40K tokens 的消息
├─ compactConversation()(回退路径)
│ → Fork Agent 生成 9 章节结构化摘要
会话结束
├─ drainPendingExtraction()
│ → 等待进行中的记忆提取完成
└─ 团队记忆推送最后一批变更
```
---
## 12. 关键设计决策总结
| 决策 | 原因 |
|------|------|
| 记忆文件是独立的 .md 文件不是数据库 | 用户可以直接编辑Git 追踪跨工具使用 |
| MEMORY.md 是索引不是记忆 | 防止单文件膨胀支持截断不丢核心内容 |
| 自动提取在 Stop Hook 中即发即忘 | 不阻塞主对话循环 |
| 互斥检查主代理 vs 自动提取 | 防止覆盖用户显式保存的内容 |
| 召回用 Sonnet 不用 Haiku | 需要理解语义相关性Haiku 不够准确 |
| 新鲜度用"X days ago"不用 ISO 时间 | 模型对相对时间的推理比绝对时间好 |
| 项目设置排除 autoMemoryDirectory | 防止恶意仓库劫持写入路径 |
| 团队记忆双重路径验证 | 符号链接攻击需要在文件系统层面检查 |
| 秘密模式在运行时拼接 | 避免自身的 excluded-strings 检查 |
| 本地优先的冲突策略 | 用户正在编辑 = 最新意图 |
| 断路器MAX_CONFLICT_RETRIES = 2 | 防止推送冲突的无限重试 |
---
*来自AI超元域 | B站频道https://space.bilibili.com/3493277319825652*
*基于 Claude Code 源码逆向分析2026-03-31*

View File

@@ -0,0 +1,805 @@
# Claude Code 隐藏高级功能全景图
> 基于 Claude Code 源码2026-03-31 快照512K 行 TypeScript逆向分析
> 发现 55+ 个特性开关、20+ 个隐藏命令、以及多个未公开系统
---
## 目录
1. [你现在就能用的隐藏功能](#1-你现在就能用的隐藏功能)
2. [55+ 个编译时特性开关完整清单](#2-55-个编译时特性开关完整清单)
3. [KAIROS — AI 助手守护进程](#3-kairos--ai-助手守护进程)
4. [CHICAGO_MCP — Computer Use 电脑控制](#4-chicago_mcp--computer-use-电脑控制)
5. [投机执行系统Speculation](#5-投机执行系统speculation)
6. [Undercover 隐身模式](#6-undercover-隐身模式)
7. [Dream Mode 记忆梦境整合](#7-dream-mode-记忆梦境整合)
8. [Voice Mode 语音输入](#8-voice-mode-语音输入)
9. [Proactive 自主代理模式](#9-proactive-自主代理模式)
10. [伴侣精灵系统Buddy](#10-伴侣精灵系统buddy)
11. [多代理团队/Swarm 系统](#11-多代理团队swarm-系统)
12. [Anthropic 内部专用命令](#12-anthropic-内部专用命令)
13. [隐藏键盘快捷键](#13-隐藏键盘快捷键)
14. [隐藏环境变量](#14-隐藏环境变量)
15. [其他彩蛋与冷知识](#15-其他彩蛋与冷知识)
---
## 1. 你现在就能用的隐藏功能
这些功能在当前公开版本中存在,但很少被提及:
| 功能 | 触发方式 | 说明 |
|------|----------|------|
| 实体贴纸 | `/stickers` | 打开 Claude Code 实体贴纸购买页 |
| 堆转储 | `/heapdump` | 把 JS 堆转储到 `~/Desktop`(隐藏命令,不在 /help 中) |
| 裸模式 | `--bare``CLAUDE_CODE_SIMPLE=1` | 极简模式:只保留 Bash、Read、Edit 三个工具 |
| 自定义加载词 | `settings.json``spinnerVerbs` | 替换或追加 200+ 个花式加载词("Clauding"、"Flibbertigibbeting"…) |
| 输出风格切换 | `/config` → output style | **Explanatory**(教学模式,附 Insight 解说)或 **Learning**(动手练习,含 TODO(human) 标记) |
| Vim 模式 | `/vim` | 完整状态机d/c/y 操作符、h/l/w/b/e/$ 移动、f/t 查找、文本对象、dot-repeat |
| 消息动作选择器 | `shift+up` | 进入消息导航j/k 上下移动c 复制消息p 固定消息 |
| 年度回顾 | `/think-back` | "Your 2025 Claude Code Year in Review" 动画回顾 |
| 转储系统提示 | `--dump-system-prompt` | 打印完整系统提示词后退出(需特性开关) |
| 多代理团队 | `--agent-teams``CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` | 多 Claude 实例在 tmux/iTerm 分屏中并行工作 |
| 后台任务 | `ctrl+b` | 把当前运行中的任务转入后台 |
| 历史搜索 | `ctrl+r` | 反向搜索命令历史 |
| Transcript 模式 | `ctrl+o` | 查看完整对话记录,支持搜索 |
| Todo 面板 | `ctrl+t` | 任务追踪面板 |
| 速率限制选项 | `/rate-limit-options` | 隐藏命令,速率限制时显示选项 |
| 使用洞察 | `/insights` | 分析你的 Claude Code 使用历史113KB 延迟加载模块) |
| 全局文件搜索 | `ctrl+shift+f` | 跨文件搜索(需 QUICK_SEARCH 开关) |
| 快速打开 | `ctrl+shift+p` | 快速打开文件 |
---
## 2. 55+ 个编译时特性开关完整清单
所有开关通过 `feature('FLAG')` 在 Bun 编译时评估。外部构建中为 `false` 的分支会被彻底删除(死代码消除)。
### 核心功能开关
| 开关 | 功能 | 状态 |
|------|------|:----:|
| `VOICE_MODE` | 语音输入push-to-talk | 内部 |
| `KAIROS` | AI 助手守护进程模式 | 内部 |
| `KAIROS_DREAM` | 梦境记忆整合 | 内部 |
| `KAIROS_BRIEF` | Brief 摘要工具 | 内部 |
| `KAIROS_CHANNELS` | 频道通知系统 | 内部 |
| `KAIROS_PUSH_NOTIFICATION` | 推送通知工具 | 内部 |
| `KAIROS_GITHUB_WEBHOOKS` | GitHub PR 订阅 | 内部 |
| `CHICAGO_MCP` | Computer Use 电脑控制 | 付费用户 |
| `PROACTIVE` | 自主代理模式Sleep + 自动唤醒) | 内部 |
| `BRIDGE_MODE` | Remote Control 桥接 | 公开 |
| `DAEMON` | 后台守护进程 | 内部 |
### 上下文管理开关
| 开关 | 功能 |
|------|------|
| `CONTEXT_COLLAPSE` | 智能上下文折叠(替代暴力压缩) |
| `REACTIVE_COMPACT` | 响应式压缩API 报 prompt-too-long 时触发) |
| `CACHED_MICROCOMPACT` | 缓存感知微压缩(不破坏 prompt cache |
| `HISTORY_SNIP` | 历史裁剪SnipTool + /force-snip |
| `TOKEN_BUDGET` | Token 预算追踪和递减收益检测 |
| `EXTRACT_MEMORIES` | 自动记忆提取 |
| `TEAMMEM` | 团队记忆同步 |
### 工具和代理开关
| 开关 | 功能 |
|------|------|
| `COORDINATOR_MODE` | 多代理协调者模式 |
| `AGENT_TRIGGERS` | 定时触发器Cron |
| `AGENT_TRIGGERS_REMOTE` | 远程触发器 |
| `MONITOR_TOOL` | 监控工具和任务 |
| `WEB_BROWSER_TOOL` | 网页浏览器自动化工具 |
| `TERMINAL_PANEL` | 终端面板meta+j |
| `WORKFLOW_SCRIPTS` | 工作流脚本系统 |
| `BG_SESSIONS` | 后台会话claude ps/logs/attach/kill |
| `OVERFLOW_TEST_TOOL` | 上下文溢出测试工具 |
| `BUDDY` | 伴侣精灵系统 |
### UI 和体验开关
| 开关 | 功能 |
|------|------|
| `MESSAGE_ACTIONS` | 消息动作选择器shift+up |
| `QUICK_SEARCH` | 全局搜索和快速打开 |
| `AUTO_THEME` | 自动主题检测 |
| `STREAMLINED_OUTPUT` | 流式 JSON 模式优化输出 |
| `CONNECTOR_TEXT` | 连接器文本摘要 beta |
### 安全和调试开关
| 开关 | 功能 |
|------|------|
| `BASH_CLASSIFIER` | Bash 命令 ML 安全分类器 |
| `TRANSCRIPT_CLASSIFIER` | 基于 transcript 的权限模式分类 |
| `NATIVE_CLIENT_ATTESTATION` | 客户端证明头cch= |
| `HARD_FAIL` | 硬失败模式(任何错误都崩溃) |
| `DUMP_SYSTEM_PROMPT` | --dump-system-prompt 隐藏 CLI 标志 |
| `ABLATION_BASELINE` | A/B 测试消融基线 |
| `PROMPT_CACHE_BREAK_DETECTION` | Prompt 缓存失效检测 |
### 基础设施开关
| 开关 | 功能 |
|------|------|
| `LODESTONE` | `cc://` 深度链接协议注册 |
| `DIRECT_CONNECT` | 通过 cc:// 深度链接直连 |
| `SSH_REMOTE` | SSH 远程会话 |
| `BYOC_ENVIRONMENT_RUNNER` | 自带计算环境运行器 |
| `SELF_HOSTED_RUNNER` | 自托管运行器 |
| `CCR_REMOTE_SETUP` | /remote-setup 命令 |
| `FORK_SUBAGENT` | /fork 子代理分叉命令 |
| `MCP_SKILLS` | MCP 提供的技能 |
| `EXPERIMENTAL_SKILL_SEARCH` | 实验性技能模糊搜索 |
| `REVIEW_ARTIFACT` | 审查工件工具 |
| `BUILDING_CLAUDE_APPS` | /claude-api 技能 |
| `RUN_SKILL_GENERATOR` | 技能生成器 |
| `ULTRAPLAN` | 超级计划模式 |
| `TORCH` | /torch 命令 |
| `TEMPLATES` | 任务分类器/模板系统 |
| `VERIFICATION_AGENT` | 验证代理 |
| `COMMIT_ATTRIBUTION` | 提交归属Co-Authored-By |
| `AWAY_SUMMARY` | 离开摘要生成 |
| `FILE_PERSISTENCE` | 跨轮次文件持久化追踪 |
| `MEMORY_SHAPE_TELEMETRY` | 记忆文件形状遥测 |
| `COWORKER_TYPE_TELEMETRY` | Coworker 类型遥测 |
| `DOWNLOAD_USER_SETTINGS` | 设置下载同步 |
| `UPLOAD_USER_SETTINGS` | 设置上传同步 |
| `BREAK_CACHE_COMMAND` | /break-cache 命令 |
---
## 3. KAIROS — AI 助手守护进程
**代号含义:** KAIROS希腊语"决定性时刻"
### 架构
```
claude assistant ← 启动入口
永驻守护进程
├── 每日日志: logs/YYYY/MM/YYYY-MM-DD.md仅追加
├── SleepTool: 休眠 → 定时自主唤醒
├── PushNotificationTool: 向用户推送通知
├── SendUserFileTool: 发送文件给用户
├── SubscribePRTool: 订阅 GitHub PR webhook
├── BriefTool: 简短状态报告ctrl+shift+b
├── 频道通知: 通过 MCP 接收外部消息
└── /dream: 夜间记忆蒸馏
```
### 关键特性
- **记忆范式不同**:不写独立记忆文件,而是追加到每日日志
- **夜间梦境**`/dream` 技能自动将日志蒸馏为主题文件
- **自主循环**SleepTool + 自动唤醒 = 完全自主的工作循环
- **压缩后行为**:提示词包含 "你正在自主模式中运行,这不是首次唤醒——继续工作循环"
- **涉及 6 个子特性开关**KAIROS + KAIROS_DREAM + KAIROS_BRIEF + KAIROS_CHANNELS + KAIROS_PUSH_NOTIFICATION + KAIROS_GITHUB_WEBHOOKS
---
## 4. CHICAGO_MCP — Computer Use 电脑控制
**代号:** Chicago子门控以芝加哥地标命名`tengu_malort_pedway`
### 功能
- 创建**进程内 MCP 服务器**控制屏幕
- macOS 上使用**原生 Swift 执行器**
- 支持 `pixels``normalized` 两种坐标模式
- 自动列出已安装应用供模型参考
- **ESC 热键**紧急中断电脑控制
- 可通过 `--computer-use-mcp` 独立启动 MCP 服务器
### 子功能门控
| 子门控 | 功能 |
|--------|------|
| `pixelValidation` | 像素坐标验证 |
| `clipboardPasteMultiline` | 多行剪贴板粘贴 |
| `mouseAnimation` | 鼠标移动动画 |
| `hideBeforeAction` | 操作前隐藏 UI |
| `autoTargetDisplay` | 自动目标显示器选择 |
| `clipboardGuard` | 剪贴板保护 |
### 访问控制
- 需要 **Max 或 Pro 订阅**(外部用户)
- Anthropic 员工可直接使用(绕过订阅检查)
- 有专用权限 UI`ComputerUseApproval.tsx`
---
## 5. 投机执行系统Speculation
**仅 Anthropic 内部**`USER_TYPE === 'ant'`
### 工作原理
```
1. 系统生成"下一步建议"提示词
2. 用户看到建议的同时,后台 Fork Agent 已开始执行
3. 文件写入到 overlay 目录copy-on-write 隔离)
~/.claude/tmp/speculation/<pid>/<id>/
4. 用户接受建议 → 投机结果注入对话 + overlay 文件复制到真实文件系统
用户拒绝/修改 → 丢弃投机结果
```
### 安全约束
| 工具类型 | 投机执行中的权限 |
|----------|:----------------:|
| 只读工具Read, Glob, Grep | 允许 |
| 写入工具Edit, Write | 仅在权限模式允许自动接受时 |
| Bash 命令 | 必须通过只读验证 |
| 未知工具 | 遇到即暂停boundary |
### 限制
- 最多 **20 轮**、**100 条消息**
- 可以**流水线化**:当前投机完成后预生成下一步建议
### 用户反馈(内部可见)
```
Speculated 5 tool uses — +12s saved (47s this session)
```
---
## 6. Undercover 隐身模式
**仅 Anthropic 员工**,自动激活条件:在公开/开源仓库工作。
### 激活后的行为
| 行为 | 说明 |
|------|------|
| 剥除归属 | 所有 `Co-Authored-By` 行被移除 |
| 禁止提及内部代号 | Capybara、Tengu 等动物代号 |
| 禁止提及版本号 | 未发布的模型版本 |
| 禁止提及内部仓库 | Anthropic 内部仓库名 |
| 禁止提及 Slack 频道 | 内部 Slack 频道名 |
| 禁止提及 "Claude Code" | commit 消息必须看起来像人类写的 |
### 控制
- 自动检测:仓库 remote 不在内部白名单 → 自动开启
- 强制开启:`CLAUDE_CODE_UNDERCOVER=1`
- 无强制关闭选项
- 首次激活有说明对话框
---
## 7. Dream Mode 记忆梦境整合
### 自动触发条件
同时满足:
- 距上次整合 ≥ **24 小时**`minHours`,可配置)
- 且触及 ≥ **5 个会话**`minSessions`,可配置)
- 无其他进程正在整合(锁机制)
### 四阶段执行
```
阶段 1 — 定向
读取记忆目录和 MEMORY.md 索引
阶段 2 — 收集
从每日日志和会话 transcript 中提取新信号
阶段 3 — 整合
将新信息合并到已有主题文件
转换相对日期为绝对日期
删除被新事实矛盾的旧事实
阶段 4 — 修剪
保持索引在 25KB 以内
清理过时条目
```
### 工具限制
Dream 运行期间Bash 被限制为只读命令。
### 手动触发
`/dream` 技能在前台执行同样的整合流程(需 KAIROS 或 KAIROS_DREAM 开关)。
---
## 8. Voice Mode 语音输入
### 激活方式
**按住空格键说话**push-to-talk通过 `/voice` 命令开启。
### 技术栈
```
原生音频捕获
macOS → CoreAudio (audio-capture-napi / cpal)
Linux → ALSA
回退 → SoX rec / arecord
录音参数
采样率: 16kHz
声道: 单声道
静音检测: 2.0秒3% 阈值SoX 回退路径)
STT 流式传输
→ claude.ai voice_stream 端点
→ 需要 Anthropic OAuthAPI key/Bedrock/Vertex 不支持)
```
### UI 元素
- 音频电平指示器
- 语音状态显示
- 语言选择器(`LanguagePicker.tsx`
- 自定义关键词词汇表(`voiceKeyterms.ts`
### 控制
- GrowthBook 杀开关:`tengu_amber_quartz_disabled`
- 默认 fail-open新安装时启用
---
## 9. Proactive 自主代理模式
### 核心工具SleepTool
```typescript
// 代理可以休眠指定时间后自主唤醒
SleepTool.call({ duration: '5m' })
// 5 分钟后自动恢复执行
```
### 与 KAIROS 结合
```
claude assistant
[工作] → [SleepTool 5m] → [自动唤醒] → [继续工作] → [SleepTool 10m] → ...
↑ |
└──────────────────────────── 无限循环 ────────────────────────────────┘
```
### 压缩后的特殊行为
普通模式压缩后:提示用户是否有问题
自主模式压缩后:
```
你正在自主/主动模式中运行。这不是首次唤醒——你在压缩前已经在自主工作。
继续你的工作循环:根据上面的摘要从离开的地方接续。不要问候用户或询问要做什么。
```
---
## 10. 伴侣精灵系统Buddy
`feature('BUDDY')` — 一个完整的收藏型宠物系统。
### 物种18种
duck、goose、blob、cat、dragon、octopus、owl、penguin、turtle、snail、ghost、axolotl、capybara、cactus、robot、rabbit、mushroom、chonk
### 外观组合
```
18 种物种 × 6 种眼睛 × 8 种帽子 = 864 种外观组合
× 5 种稀有度 = 4,320 种可能的精灵
```
### 稀有度
| 等级 | 概率 | 显示 | 属性底值 |
|------|:----:|------|:--------:|
| Common | 60% | 1星 | 低 |
| Uncommon | 25% | 2星 | 略高 |
| Rare | 10% | 3星 | 中等 |
| Epic | 4% | 4星 | 高 |
| Legendary | 1% | 5星 | 最高 |
### 5种属性
- **DEBUGGING** — 调试力
- **PATIENCE** — 耐心
- **CHAOS** — 混沌
- **WISDOM** — 智慧
- **SNARK** — 吐槽力
每只精灵有一个巅峰属性和一个低谷属性。
### 确定性生成
```typescript
// 种子 = hash(userId + 'friend-2026-401')
// PRNG = Mulberry32
// 无论何时重新生成,同一用户始终得到同一只精灵
// 编辑配置文件无法伪造稀有度——bones 从 hash 重新计算
```
### ASCII 动画
```
每种物种 3 帧动画5行×12字符
500ms tick 的闲置动画
包含眨眼帧和特殊效果(烟雾、天线发光、墨水泡泡等)
```
### 互动
```
/buddy pet → 触发 2.5 秒心形粒子特效(❤ 字符向上飘浮)
模型可以让精灵"说话"(通过 speech bubble 系统)
用户对精灵说话时,模型会自动退让
```
### 反作弊
```
物种名中某些与模型代号冲突的名称用 String.fromCharCode 十六进制编码
配置文件编辑不影响生成结果bones 从 hash 重算)
```
### 启动引导
首次未孵化时显示彩虹色 `/buddy` 提示文本。
---
## 11. 多代理团队/Swarm 系统
### 激活方式
```bash
# 外部用户
claude --agent-teams
# 或
export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
```
### 三种后端
| 后端 | 实现 | 特点 |
|------|------|------|
| **TmuxBackend** | 隔离 tmux socket `claude-swarm-<PID>` | 彩色边框,不影响用户的 tmux |
| **ITermBackend** | iTerm2 的 `it2` CLI + Python API | 原生分屏 |
| **InProcessBackend** | 进程内运行 | 无终端 UI |
自动检测选择最佳可用后端。
### Tmux 隔离
```typescript
// Claude 创建自己的 tmux socket防止命令影响用户会话
const SWARM_SESSION_NAME = 'claude-swarm'
const HIDDEN_SESSION_NAME = 'claude-hidden'
// socket 名: claude-<PID>
```
### Coordinator 模式
```bash
export CLAUDE_CODE_COORDINATOR_MODE=1
```
Claude 变为协调者,通过 `AgentTool``SendMessageTool``TaskStopTool` 编排 worker 代理。Worker 拥有独立工具访问权限。
### 团队工具
| 工具 | 功能 |
|------|------|
| `TeamCreateTool` | 创建代理团队 |
| `TeamDeleteTool` | 删除代理团队 |
| `SendMessageTool` | 代理间消息传递 |
| `TaskStopTool` | 停止子任务 |
| `TungstenTool`(内部) | tmux 会话管理 |
### 共享便签本
`tengu_scratch` 门控开启时worker 获得共享 scratchpad 目录,跨 worker 知识交换绕过权限提示。
---
## 12. Anthropic 内部专用命令20+个)
全部在外部构建中被替换为 `{ isEnabled: false, isHidden: true }` 存根。
### 调试和诊断
| 命令 | 用途 |
|------|------|
| `/bridge-kick` | 注入 bridge 故障close/poll/register/heartbeat 等 10+ 子命令) |
| `/mock-limits` | 模拟各种速率限制场景 |
| `/reset-limits` | 重置速率限制状态 |
| `/ctx-viz` | 上下文窗口可视化 |
| `/debug-tool-call` | 工具调用调试 |
| `/ant-trace` | Anthropic 内部追踪 |
| `/perf-issue` | 性能问题报告 |
| `/env` | 显示环境变量 |
| `/stuck` | 诊断冻结/慢会话(扫描 CPU、进程状态、内存泄漏 |
| `/force-snip` | 强制历史裁剪 |
| `/break-cache` | 使 prompt cache 失效 |
### 工作流和自动化
| 命令 | 用途 |
|------|------|
| `/autofix-pr` | 自动修复 PR 问题 |
| `/bughunter` | 远程审查的 bug 猎人模式 |
| `/teleport` | 远程传送到其他环境 |
| `/backfill-sessions` | 回填会话数据 |
| `/agents-platform` | 代理平台管理 |
| `/ultraplan` | 超级计划模式 |
| `/share` | 分享对话 |
### 开发辅助
| 命令 | 用途 |
|------|------|
| `/lorem-ipsum` | 精确 token 计数的填充文本生成(用 1-token 词汇实现精确计数) |
| `/oauth-refresh` | OAuth token 手动刷新 |
| `/good-claude` | (已存根化) |
| `/onboarding` | 引导流程 |
| `/init-verifiers` | 初始化验证器 |
### 内部专用工具
| 工具 | 用途 |
|------|------|
| `ConfigTool` | 直接修改配置 |
| `TungstenTool` | tmux 会话管理 |
| `REPLTool` | 沙盒 REPL VM |
| `SuggestBackgroundPRTool` | 建议后台 PR |
| `CtxInspectTool` | 上下文检查 |
| `OverflowTestTool` | 溢出测试 |
| `SnipTool` | 历史裁剪 |
| `MonitorTool` | 监控 |
### Bridge Kick 详细子命令
```
/bridge-kick close <code> — 触发 WebSocket close
/bridge-kick poll 404 [type] — 下次轮询 404
/bridge-kick poll transient — 下次轮询 5xx
/bridge-kick register fail [N] — 下 N 次注册失败
/bridge-kick register fatal — 注册 403终端失败
/bridge-kick reconnect-session fail — 重连失败
/bridge-kick heartbeat <status> — 心跳致命错误
/bridge-kick reconnect — 直接触发重连
/bridge-kick status — 打印 bridge 状态
```
支持**组合故障序列**,复现真实生产故障链。
---
## 13. 隐藏键盘快捷键
### 全局快捷键
| 快捷键 | 动作 |
|--------|------|
| `ctrl+t` | 切换 Todo 面板 |
| `ctrl+o` | 切换 Transcript 查看器 |
| `ctrl+r` | 历史反向搜索 |
| `ctrl+l` | 重绘屏幕 |
| `ctrl+b` | 后台运行当前任务 |
| `shift+tab` | 循环切换权限模式 |
| `meta+p` | 模型选择器 |
| `meta+o` | Fast Mode 切换 |
| `meta+t` | Thinking 模式切换 |
### Chord 快捷键(两步组合)
| 快捷键 | 动作 |
|--------|------|
| `ctrl+x ctrl+k` | 终止所有代理 |
| `ctrl+x ctrl+e``ctrl+g` | 打开外部编辑器 |
### 编辑快捷键
| 快捷键 | 动作 |
|--------|------|
| `ctrl+_` / `ctrl+shift+-` | 撤销文本输入 |
| `ctrl+s` | 暂存当前输入 |
| `ctrl+v` / `alt+v`(Win) | 粘贴图片 |
### 特性门控快捷键
| 快捷键 | 动作 | 需要 |
|--------|------|------|
| `shift+up` | 消息动作选择器 | `MESSAGE_ACTIONS` |
| `ctrl+shift+f` / `cmd+shift+f` | 全局文件搜索 | `QUICK_SEARCH` |
| `ctrl+shift+p` / `cmd+shift+p` | 快速打开 | `QUICK_SEARCH` |
| `meta+j` | 终端面板 | `TERMINAL_PANEL` |
| `ctrl+shift+b` | Brief 模式切换 | `KAIROS` |
| `ctrl+shift+o` | 队友预览切换 | 团队模式 |
| `space`(按住) | Push-to-talk 语音 | `VOICE_MODE` |
### 滚动快捷键
| 快捷键 | 动作 |
|--------|------|
| `pageup` / `pagedown` | 翻页滚动 |
| `wheelup` / `wheeldown` | 鼠标滚轮滚动 |
| `ctrl+shift+c` / `cmd+c` | 复制选中内容(滚动模式中) |
### 保留快捷键(不可重绑定)
- `ctrl+c` — 中断
- `ctrl+d` — 退出
---
## 14. 隐藏环境变量
### 核心配置
| 变量 | 效果 |
|------|------|
| `CLAUDE_CODE_SIMPLE=1` | 极简模式3个工具 |
| `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1` | 禁用自动记忆提取 |
| `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` | 禁用所有非必要网络流量 |
| `CLAUDE_CODE_DISABLE_THINKING=1` | 禁用 thinking 模式 |
| `CLAUDE_CODE_DISABLE_FAST_MODE=1` | 禁用 fast mode |
| `CLAUDE_CODE_DISABLE_CLAUDE_MDS=1` | 禁用 CLAUDE.md 加载 |
| `CLAUDE_CODE_DISABLE_COMMAND_INJECTION_CHECK=1` | 禁用命令注入检查 |
| `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1` | 禁用后台任务 |
### 性能调优
| 变量 | 效果 |
|------|------|
| `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY=N` | 最大并发工具数默认10 |
| `CLAUDE_CODE_AUTO_COMPACT_WINDOW=N` | 覆盖自动压缩窗口 |
| `CLAUDE_CODE_MAX_OUTPUT_TOKENS=N` | 覆盖最大输出 token |
| `CLAUDE_CODE_MAX_RETRIES=N` | 覆盖最大重试次数 |
| `CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE=N` | 覆盖阻塞限制 |
| `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80` | 在 80% 上下文时触发压缩 |
### API 控制
| 变量 | 效果 |
|------|------|
| `ANTHROPIC_MODEL=model-id` | 覆盖默认模型 |
| `ANTHROPIC_SMALL_FAST_MODEL=model-id` | 覆盖后台辅助任务模型 |
| `ANTHROPIC_BASE_URL=url` | 自定义 API 基础 URL |
| `ANTHROPIC_CUSTOM_HEADERS='{"k":"v"}'` | 注入自定义 HTTP 头 |
| `CLAUDE_CODE_EXTRA_BODY='{"k":"v"}'` | 注入额外 API 请求体 |
| `CLAUDE_CODE_EXTRA_METADATA='{"k":"v"}'` | 注入额外元数据 |
| `CLAUDE_CODE_USE_BEDROCK=1` | 使用 AWS Bedrock |
| `CLAUDE_CODE_USE_VERTEX=1` | 使用 Google Vertex |
| `CLAUDE_CODE_USE_FOUNDRY=1` | 使用 Azure Foundry |
| `CLAUDE_CODE_UNATTENDED_RETRY=1` | 无人值守无限重试 |
### 调试
| 变量 | 效果 |
|------|------|
| `CLAUDE_CODE_DEBUG=1` | 启用调试日志 |
| `CLAUDE_CODE_FRAME_TIMING_LOG=/path` | 记录帧渲染时间 |
| `CLAUDE_CODE_BASH_SANDBOX_SHOW_INDICATOR=1` | 显示沙盒指示器 |
| `CLAUDE_CODE_SYNTAX_HIGHLIGHT=1` | 启用语法高亮 |
| `OTEL_LOG_TOOL_DETAILS=1` | 遥测中记录工具详情 |
| `OTEL_LOG_USER_PROMPTS=1` | 遥测中记录用户提示词(默认 REDACTED |
| `DISABLE_COMPACT=1` | 完全禁用压缩 |
| `DISABLE_AUTO_COMPACT=1` | 仅禁用自动压缩 |
### 代理团队
| 变量 | 效果 |
|------|------|
| `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` | 启用多代理团队 |
| `CLAUDE_CODE_COORDINATOR_MODE=1` | 协调者模式 |
| `CLAUDE_CODE_TEAMMATE_COMMAND=cmd` | 队友启动命令 |
| `CLAUDE_CODE_AGENT_COLOR=color` | 代理颜色 |
| `CLAUDE_CODE_PLAN_MODE_REQUIRED=1` | 强制 plan 模式 |
---
## 15. 其他彩蛋与冷知识
### 200+ 花式加载词
`spinnerVerbs.ts` 中的精选:
```
Clauding, Boondoggling, Canoodling, Flibbertigibbeting,
Hullaballooing, Moonwalking, Prestidigitating, Razzmatazzing,
Shenaniganing, Tomfoolering, Whatchamacalliting, Beboppin'
```
完成时的过去式:
```
Baked for 5s, Cogitated for 12s, Noodled for 8s
```
### VCR 录制/回放模式
`FORCE_VCR=1`(内部):录制和回放 API 交互,用于测试。
### Lorem Ipsum 精确 token 生成
`/lorem-ipsum 50000`(内部):使用经过验证的 1-token 单词生成精确 token 数的填充文本。
### Fennec 代号
内部模型迁移中有 `migrateFennecToOpus.ts`:将 `fennec-latest` 映射到 `opus``fennec-fast-latest` 映射到 `opus[1m]` + fast mode。
### 消融基线模式
`CLAUDE_CODE_ABLATION_BASELINE`:降级功能用于 A/B 测试,验证各功能的实际贡献。
### 深度链接协议
`feature('LODESTONE')`:注册 `cc://` URL 协议处理器,其他应用可直接打开 Claude Code 会话。
### 物种名编码
```typescript
// 伴侣精灵的某个物种名与内部模型代号冲突
// 用 String.fromCharCode 十六进制编码避免 excluded-strings 检查
```
### 权限模式循环
`shift+tab` 在以下模式间循环:
```
default → acceptEdits → plan → auto → default → ...
```
### Anthropic API Key 自检回避
```typescript
// 秘密扫描器中 Anthropic API key 前缀在运行时拼接
// 避免匹配自身源码的 excluded-strings 检查
const prefix = ['sk', 'ant', 'api'].join('-')
```
---
## 总结:冰山模型
```
╭───────────────╮
公开版本 │ CLI + 43工具 │ ← 你看到的
│ /命令 + UI │
╰───────┬───────╯
╭───────────────┼───────────────╮
编译时剥离 │ KAIROS守护进程 │ Computer Use │ ← 源码中存在
│ Voice Mode │ Speculation │ 但外部构建被删除
│ Dream Mode │ Undercover │
│ Buddy Pet │ Swarm/Teams │
│ Workflows │ BG Sessions │
│ Deep Links │ Cron Triggers │
╰───────────────┴───────────────╯
╭───────────────┼───────────────╮
内部专用 │ 20+ 调试命令 │ bridge-kick │ ← 仅 Anthropic 员工
│ mock-limits │ VCR 录放 │
│ lorem-ipsum │ 消融基线 │
│ stuck 诊断 │ ctx-viz │
╰───────────────┴───────────────╯
```
**Claude Code 不只是一个 CLI 工具——它的源码中隐藏着一个完整的 AI 助手操作系统的雏形。** 守护进程、语音输入、电脑控制、投机执行、梦境记忆整合、多代理协作、隐身模式——当前公开版本只暴露了冰山一角。
---
*来自AI超元域 | B站频道https://space.bilibili.com/3493277319825652*
*基于 Claude Code 源码逆向分析2026-03-31*

View File

@@ -0,0 +1,23 @@
### analysis\_20260401
| Document | Content |
| -------- | ------- |
| [Claude Code 上下文管理算法学习笔记](https://github.com/chauncygu/collection-claude-code-source-code/blob/main/docs/cc_analysis/analysis_20260401/Claude_Code_Context_Management_Notes.md) | Step-by-step walkthrough of the context management algorithm: `autoCompact`, micro/reactive/trimmed compression strategies, and `toolResultStorage` |
| [Claude Code 多 Agent 架构深度分析](claude-code-multi-agent-architecture.md) | Deep analysis of the multi-agent architecture across 37+ files: `src/utils/swarm/`, `AgentTool/`, `coordinator/` |
| [Claude Code 值得借鉴的算法与设计模式](Claude_Code_Notable_Algorithms.md) | Notable algorithms and design patterns worth borrowing from the source (complements the context management notes) |
| [Claude Code 自动回滚机制解析与版本切换指南](docs/cc_analysis/analysis_20260401/Claude-Code-Version-Rollback.md) | How the automatic rollback mechanism works and a practical version-switching guide |
| [Claude Code 上下文压缩算法深度分析](Claude_Code上下文压缩算法深度分析.md) | Detailed reverse-engineering of the 11-file `src/services/compact/` compression pipeline |
| [Claude Code 是否偷换模型?模型切换机制深度分析](docs/cc_analysis/analysis_20260401/Claude_Code模型切换机制深度分析.md) | Source-level analysis of model-selection logic: `model.ts`, `withRetry.ts`, and `claude.ts` |
| [Claude Code Memory 记忆系统深度分析](Claude_Code记忆系统深度分析.md) | Full analysis of the 7-layer memory system: `memdir/`, `extractMemories/`, `SessionMemory/`, `teamMemorySync/` |
| [Claude Code 隐藏高级功能全景图](Claude_Code隐藏高级功能全景图.md) | Map of 55+ feature flags, 20+ hidden commands, and several undisclosed subsystems |
| [Claude Code 默认 Effort Level 设置笔记](Claude%20Code%20默认%20Effort%20Level%20设置笔记.md) | How to persist `/effort max` across sessions (default resets to `medium` on restart) |
| [清除 Claude Code 追踪数据指南](清除Claude_Code追踪数据指南.md) | macOS guide for clearing telemetry and tracking data stored by Claude Code |
| [Claude Code 深度分析报告 (PDF)](Claude_Code_深度分析报告.pdf) | Comprehensive analysis report in PDF format (Chinese) |
| [Claude Code Deep Analysis Report (PDF)](Claude_Code_Deep_Analysis_Report.pdf) | Comprehensive analysis report in PDF format (English) |
---
Note, here, the original analysis material from the [link](https://github.com/win4r/cc-notebook/tree/main)

View File

@@ -0,0 +1,682 @@
# Claude Code 多 Agent 架构深度分析
> 基于源码约 **13,700 行、37+ 文件**的深度探索,涵盖 `src/utils/swarm/`、`src/tools/AgentTool/`、`src/coordinator/` 等核心模块。
---
## 一、整体架构
系统采用 **Leader-Worker 模型**,核心有三种执行后端和两种编排模式:
```
┌─────────────────────────────┐
│ 用户请求 (REPL/CLI) │
└──────────┬──────────────────┘
┌──────────▼──────────────────┐
│ Leader Agent (team-lead) │
│ QueryEngine → query() │
└──┬────────┬────────┬────────┘
│ │ │
┌────────────▼┐ ┌────▼─────┐ ┌▼────────────┐
│ InProcess │ │ Tmux │ │ iTerm2 │
│ (同进程) │ │ (分屏) │ │ (分屏) │
└──────────────┘ └──────────┘ └─────────────┘
│ │ │
AsyncLocalStorage 独立进程 独立进程
隔离上下文 文件邮箱通信 文件邮箱通信
```
**两种编排模式:**
- **Team Mode** — 通过 `TeamCreate` 创建团队,手动管理 Worker
- **Coordinator Mode** — 自动化编排Coordinator 只能用 Agent/TaskStop/SendMessage 三个工具
---
## 二、Agent Tool — 统一入口
`src/tools/AgentTool/AgentTool.tsx` 是所有子 Agent 的统一入口。
### 2.1 输入参数
| 参数 | 类型 | 作用 |
|------|------|------|
| `prompt` | string | 任务描述 |
| `subagent_type` | string | Agent 类型 (Explore, Plan, 自定义等) |
| `model` | `'sonnet'\|'opus'\|'haiku'` | 模型覆盖 |
| `run_in_background` | boolean | 后台异步执行 |
| `name` | string | 命名,使其可通过 SendMessage 寻址 |
| `team_name` | string | 团队名 |
| `mode` | string | 权限模式 (plan, acceptEdits 等) |
| `isolation` | `'worktree'` | Git worktree 隔离 |
### 2.2 路由决策树
```
call() 入口 (AgentTool.tsx:284)
├── team_name + name → spawnTeammate() → 生成持久化队友
├── isolation === 'remote' → Cloud Code Runner
├── run_in_background === true → runAsyncAgentLifecycle() (fire-and-forget)
└── 默认 → runAgent() 同步执行,阻塞父 Agent
```
### 2.3 关键常量
```typescript
// src/tools/AgentTool/constants.ts
AGENT_TOOL_NAME = 'Agent'
LEGACY_AGENT_TOOL_NAME = 'Task' // 向后兼容
ONE_SHOT_BUILTIN_AGENT_TYPES = {'Explore', 'Plan'}
```
---
## 三、Agent 定义系统
`src/tools/AgentTool/loadAgentsDir.ts` (755行) 负责从多来源加载 Agent 定义。
### 3.1 AgentDefinition 类型
```typescript
type AgentDefinition = {
agentType: string // 唯一标识
whenToUse: string // 何时使用的描述
tools: string[] // 可用工具列表,['*'] 表示全部
disallowedTools: string[] // 禁用工具
model: string // 模型选择
permissionMode: string // 权限模式
maxTurns: number // 最大对话轮次
background: boolean // 是否后台运行
isolation: 'worktree' // 隔离方式
getSystemPrompt() // 系统提示词生成函数
}
```
### 3.2 三种来源
- `BuiltInAgentDefinition` — 内置 Agent (source: 'built-in')
- `CustomAgentDefinition` — 用户自定义 `.claude/agents/*.md` 文件
- `PluginAgentDefinition` — 插件提供的 Agent
### 3.3 内置 Agent 类型
| Agent | 模型 | 工具 | 特点 |
|-------|------|------|------|
| `general-purpose` | 默认 | `['*']` | 全能通用 |
| `Explore` | haiku | 只读工具 | 代码探索,禁止编辑/写入/嵌套 Agent |
| `Plan` | inherit | 只读工具 | 架构规划,禁止编辑 |
| `verification` | inherit | 只读 | 后台对抗性测试,红色标识 |
| `statusline-setup` | sonnet | Read, Edit | 状态栏配置专用 |
| `fork` (合成) | inherit | `['*']` | 继承父上下文,权限冒泡 |
| `claude-code-guide` | — | 有限工具 | Claude Code 使用指南 |
### 3.4 加载优先级
```
built-in < plugin < userSettings < projectSettings < flagSettings < policySettings
```
后加载的同名 Agent 覆盖先加载的。
---
## 四、三大执行后端
### 4.1 InProcess 后端 (同进程)
**文件**: `src/utils/swarm/backends/InProcessBackend.ts` (339行)
最轻量的方式——所有 Worker 运行在**同一个 Node.js 进程**中:
```
Leader 进程
├── AsyncLocalStorage<TeammateContext> #1 → Worker A
├── AsyncLocalStorage<TeammateContext> #2 → Worker B
└── AsyncLocalStorage<TeammateContext> #3 → Worker C
```
**核心流程:**
1. `spawn()``spawnInProcessTeammate()` 注册到 AppState
2. `startInProcessTeammate()` fire-and-forget 启动 Agent 循环
3. 通过 `runWithTeammateContext(context, fn)` 包裹执行,实现上下文隔离
4. 权限请求直接使用 Leader 的 `ToolUseConfirm` 对话框(通过 `leaderPermissionBridge.ts`
**上下文隔离** (`src/utils/teammateContext.ts`, 96行)
```typescript
// AsyncLocalStorage 实现进程内隔离
const teammateContextStorage = new AsyncLocalStorage<TeammateContext>()
function runWithTeammateContext(context: TeammateContext, fn: () => T): T {
return teammateContextStorage.run(context, fn)
}
function isInProcessTeammate(): boolean {
return teammateContextStorage.getStore() !== undefined
}
```
### 4.2 Tmux 后端 (终端分屏)
**文件**: `src/utils/swarm/backends/TmuxBackend.ts` (764行)
每个 Worker 是一个**独立的 Claude CLI 进程**,运行在 tmux 分屏中。
**两种模式:**
**Leader 在 tmux 内:**
```
┌─────────────────┬──────────────────┐
│ │ Worker A │
│ Leader ├──────────────────┤
│ (30%) │ Worker B │
│ ├──────────────────┤
│ │ Worker C │
└─────────────────┴──────────────────┘
main-vertical 布局
```
**Leader 在 tmux 外:** 创建 `claude-swarm-{pid}` 独立 sessiontiled 布局。
**关键细节:**
- `acquirePaneCreationLock()` 序列化并行 spawn防止竞态
- 200ms shell 初始化延迟等待 rc 文件加载
- 通过 `tmux send-keys` 向 pane 发送命令
- 支持 `hidePane()` (break-pane) / `showPane()` (join-pane)
### 4.3 iTerm2 后端
**文件**: `src/utils/swarm/backends/ITermBackend.ts` (370行)
通过 `it2` CLI (Python 自动化工具) 控制 iTerm2
- 首个 Worker 垂直分割,后续水平分割
- 死会话恢复split 失败时验证 session list 并重试
- `setPaneBorderColor`/`rebalancePanes` 为 no-op避免频繁启动 Python 进程)
- `supportsHideShow = false`(无等效的 tmux break-pane
### 4.4 后端选择逻辑
`src/utils/swarm/backends/registry.ts``detectAndGetBackend()` (line 136)
```
优先级瀑布:
1. 在 tmux 内? → TmuxBackend (原生)
2. 在 iTerm2 且有 it2 CLI → ITermBackend
3. 在 iTerm2 无 it2 → 回退 tmux提示安装 it2
4. 有 tmux → TmuxBackend (外部 session)
5. 非交互模式 (-p) → InProcessBackend
6. teammateMode 配置为 'in-process' → InProcessBackend
7. 都没有 → 报错并给出平台特定安装指引
```
---
## 五、核心通信机制 — 文件邮箱
### 5.1 邮箱结构
`src/utils/teammateMailbox.ts` (1,183行)
每个 Agent 拥有一个 JSON 文件邮箱:
```
~/.claude/teams/{team_name}/inboxes/{agent_name}.json
```
```typescript
type TeammateMessage = {
from: string // 发送者名称
text: string // 消息内容
timestamp: string // 时间戳
read: boolean // 是否已读
color?: string // 发送者 UI 颜色
summary?: string // 5-10 字摘要
}
```
### 5.2 核心操作
| 函数 | 作用 |
|------|------|
| `writeToMailbox()` | 原子写入 + `proper-lockfile` 文件锁10次重试5-100ms 退避) |
| `readMailbox()` | 读取所有消息 |
| `readUnreadMessages()` | 过滤未读消息 |
| `markMessagesAsRead()` | 标记已读 |
### 5.3 结构化消息类型
邮箱不仅传递文本,还定义了一套协议消息:
- `createShutdownRequestMessage` / `createShutdownApprovedMessage` — 关闭协议
- `createPermissionRequestMessage` / `createPermissionResponseMessage` — 权限请求/响应
- `createSandboxPermissionRequestMessage` / `createSandboxPermissionResponseMessage` — 沙箱网络权限
- `createIdleNotification` — Worker 空闲通知
### 5.4 轮询机制
| Agent 类型 | 轮询方式 |
|------------|----------|
| Pane 类 Worker | `useInboxPoller` React hook 定期轮询 |
| InProcess Worker | `waitForNextPromptOrShutdown()` 直接读邮箱 |
| Leader | `useInboxPoller` 处理权限请求、空闲通知等 |
---
## 六、SendMessage Tool — Agent 间通信
`src/tools/SendMessageTool/SendMessageTool.ts` (917行)
### 6.1 输入参数
```typescript
{
to: string // 收件人名称、"*" 广播、"uds:<socket>"、"bridge:<session-id>"
summary: string // 5-10 字摘要
message: string | ShutdownRequest | ShutdownResponse | PlanApprovalResponse
}
```
### 6.2 路由逻辑
```
SendMessage.call() (line 741)
├── to: "bridge:<session-id>" → postInterClaudeMessage (跨机器 Remote Control)
├── to: "uds:<socket>" → sendToUdsSocket (Unix Domain Socket 本地通信)
├── to: "*" → 广播到所有团队成员邮箱
├── to: "<name>" → 查 agentNameRegistry:
│ ├── InProcess Agent running → queuePendingMessage (内存队列)
│ ├── InProcess Agent stopped → resumeAgentBackground (自动唤醒!)
│ └── Pane Agent → writeToMailbox (文件邮箱)
└── 结构化消息 → 分发到对应处理器
```
**关键设计Agent 的纯文本输出对其他 Agent 不可见,必须通过 SendMessage 通信。**
---
## 七、权限委托系统
### 7.1 完整流程
`src/utils/swarm/permissionSync.ts` (928行)
```
Worker 遇到需要权限的操作
检查 bash classifier 能否自动批准 (swarmWorkerHandler.ts:52)
↓ 不能
创建 PermissionRequest 对象 (line 71)
注册回调 BEFORE 发送请求 (避免竞态, line 79)
发送 permission_request 到 Leader 邮箱 (line 123)
显示 "waiting for leader" 状态 (line 126)
Leader 轮询检测到请求
在 Leader UI 展示权限对话框(带 worker badge
用户批准/拒绝
Leader 发送 permission_response 到 Worker 邮箱
Worker 轮询获取响应(每 500ms继续执行
```
### 7.2 InProcess 优化路径
通过 `leaderPermissionBridge.ts` (54行)InProcess Worker 直接使用 Leader 的 `ToolUseConfirm` 队列:
```typescript
// REPL 注册权限 UI
registerLeaderPermissionQueue(setToolUseConfirmQueue, setToolPermissionContext)
// Worker 推送权限请求到 Leader UI带 worker badge
pushToLeaderPermissionQueue(request, workerBadge)
```
跳过文件邮箱的 I/O 开销,提供与 Leader 自身工具相同的 UI 体验。
### 7.3 SwarmPermissionRequest 结构
```typescript
type SwarmPermissionRequest = {
id: string
workerId: string
workerName: string
toolName: string
toolUseId: string
description: string
input: any
permissionSuggestions: any
status: 'pending' | 'approved' | 'rejected'
resolvedBy?: string
feedback?: string
updatedInput?: any
permissionUpdates?: any
}
```
### 7.4 权限模式继承
当 Leader 批准 Worker 的 plan 时:
```typescript
const modeToInherit = leaderMode === 'plan' ? 'default' : leaderMode
```
团队文件中每个成员有独立的 `mode` 字段,支持通过 `setMemberMode()` / `setMultipleMemberModes()` 动态调整。
---
## 八、Agent 执行引擎
### 8.1 runAgent() — 子 Agent 核心驱动
`src/tools/AgentTool/runAgent.ts` (973行)
`runAgent()` 是一个 `AsyncGenerator<Message, void>`
```
runAgent() (line 248)
1. 解析模型 → getAgentModel()
2. 创建隔离上下文 → createSubagentContext()
- fork 父消息到独立上下文
- 隔离的文件状态缓存
3. 初始化 Agent 专属 MCP servers → initializeAgentMcpServers()
4. 解析工具集 → resolveAgentTools()
5. 构建系统提示词 (Agent 自身 + 环境信息)
6. 注册 Perfetto 追踪, hooks
7. 调用 query() — 与主 REPL 完全相同的 agentic 循环
8. yield 每条消息回父 Agent
9. 清理 MCP servers, shell tasks, agent tracking
```
**核心设计:子 Agent 复用完全相同的 `query()` 循环**,递归地拥有完整的工具执行能力。
### 8.2 异步 Agent 生命周期
`agentToolUtils.ts``runAsyncAgentLifecycle()` (line 508)
```
registerAsyncAgent() → 创建 task entry
注册 name 到 agentNameRegistry (用于 SendMessage 路由)
void runWithAgentContext(...) → fire-and-forget
迭代 runAgent() 的消息流
ProgressTracker 追踪:
- tool use 次数
- token 消耗
- 最近活动
完成时 finalizeAgentTool():
- 提取最终文本内容
- 计算 totalDurationMs, totalTokens, totalToolUseCount
completeAsyncAgent() → 标记 task 完成
发送 <task-notification> XML 通知父 Agent
```
**多个异步 Agent 是真正并行的**——每个都是独立的 async 操作。
### 8.3 工具过滤
`agentToolUtils.ts``filterToolsForAgent()` (line 70) 使用多层禁用列表:
| 禁用列表 | 适用范围 | 禁用的工具 |
|----------|----------|-----------|
| `ALL_AGENT_DISALLOWED_TOOLS` | 所有 Agent | TaskOutput, ExitPlanMode, EnterPlanMode, AskUserQuestion, TaskStop |
| `CUSTOM_AGENT_DISALLOWED_TOOLS` | 非内置 Agent | 同上 + AgentTool |
| `ASYNC_AGENT_ALLOWED_TOOLS` | 后台 Agent | 白名单制Read, Grep, Glob, Edit, Write, WebSearch 等 |
| `COORDINATOR_MODE_ALLOWED_TOOLS` | Coordinator | 仅 Agent, TaskStop, SendMessage, SyntheticOutput |
---
## 九、Coordinator Mode — 自动化编排
`src/coordinator/coordinatorMode.ts` (369行)
### 9.1 激活条件
```typescript
function isCoordinatorMode(): boolean {
return feature('COORDINATOR_MODE') && process.env.CLAUDE_CODE_COORDINATOR_MODE === '1'
}
```
### 9.2 工作流程
```
Coordinator (只能用 Agent + TaskStop + SendMessage)
├── Research Phase → 并行派出多个 Worker 调研
│ ├── Worker A: 搜索代码
│ ├── Worker B: 读取文档
│ └── Worker C: 分析依赖
├── Synthesis Phase → Coordinator 综合分析研究结果
├── Implementation Phase → Worker 执行代码实现
└── Verification Phase → Worker 验证实现结果
```
### 9.3 Coordinator 系统提示词要点
`getCoordinatorSystemPrompt()` (line 111) 的 369 行提示词规定:
- Coordinator 通过 `Agent` 工具派出 Worker通过 `SendMessage` 继续对话,通过 `TaskStop` 终止
- Worker 完成时发送 `<task-notification>` XML
- 明确的 spawn vs continue 决策指导
- 并发管理策略
---
## 十、Team Mode — 持久化协作
### 10.1 团队文件结构
`~/.claude/teams/{team-name}/config.json`
```typescript
type TeamFile = {
name: string
description: string
createdAt: string
leadAgentId: string
leadSessionId: string
hiddenPaneIds: string[]
teamAllowedPaths: string[]
members: [{
agentId: string // 格式: name@teamName
name: string
agentType: string
model: string
color: string
planModeRequired: boolean
joinedAt: string
tmuxPaneId?: string
cwd: string
worktreePath?: string
sessionId: string
subscriptions: string[]
backendType: 'tmux' | 'iterm2' | 'in-process'
isActive: boolean
mode: string
}]
}
```
### 10.2 团队工作流
```
1. TeamCreate → 创建 config.json + tasks 目录
2. TaskCreate → 在 ~/.claude/tasks/{team-name}/ 创建任务
3. Agent tool (team_name + name) → 派出 teammate
4. TaskUpdate → 分配任务 owner
5. Teammate 工作 → 完成后自动发送 idle notification
6. SendMessage(shutdown_request) → 优雅关闭 teammate
```
### 10.3 Teammate 系统提示词附加
`src/utils/swarm/teammatePromptAddendum.ts`
> "You are running as an agent in a team. To communicate with anyone on your team, use the SendMessage tool. Just writing a response in text is not visible to others."
---
## 十一、Worktree 隔离
`src/utils/worktree.ts``createAgentWorktree()` (line 902)
### 11.1 创建流程
```
Agent spawn 时 isolation='worktree'
→ 生成 slug: agent-{agentId前8字符}
→ validateWorktreeSlug() — 拒绝路径穿越限制64字符
→ 路径: .claude/worktrees/<slug>
→ 分支: worktree-<slug>
→ git worktree add -B worktree-<slug>
→ performPostCreationSetup():
- 复制 settings.local.json
- 配置 git hooks
- 符号链接目录
- 复制 .worktreeinclude 文件
```
### 11.2 清理流程
```
Agent 完成时:
→ hasWorktreeChanges()?
├── 有改动 → 保留 worktree在 <task-notification> 中报告路径和分支
└── 无改动 → removeAgentWorktree() 自动清理
```
---
## 十二、Worker 完整生命周期
### 12.1 诞生
```
Leader 调用 Agent tool
├── InProcess: spawnInProcessTeammate()
│ 1. 生成 agentId = name@teamName
│ 2. 创建独立 AbortController不链接到 Leader
│ 3. 创建 TeammateContext for AsyncLocalStorage
│ 4. 注册 InProcessTeammateTaskState 到 AppState
│ 5. startInProcessTeammate() → runWithTeammateContext() → runAgent()
└── Pane: PaneBackendExecutor.spawn()
1. assignTeammateColor() 分配颜色
2. createTeammatePaneInSwarmView() 创建分屏
3. 构建 CLI 命令:
claude --agent-id X --agent-name Y --team-name Z
--agent-color C --parent-session-id P
4. sendCommandToPane() 发送命令
5. writeToMailbox() 写入初始 prompt
```
### 12.2 执行
```
InProcess Runner (inProcessRunner.ts, 1552行):
runWithTeammateContext() 包裹:
→ runAgent() → query() 循环
→ 轮询邮箱获取新消息(注入为 user-turn messages
→ 权限请求转发到 Leader UI
→ ProgressTracker 追踪工具使用和 token
→ 支持 auto-compact上下文过大时自动压缩
```
### 12.3 通信
```
Worker → Leader: writeToMailbox() 或 queuePendingMessage (InProcess)
Leader → Worker: writeToMailbox() 或 SendMessage
Worker → Worker: SendMessage tool → writeToMailbox()
广播: SendMessage(to: "*") → 写入所有成员邮箱
```
### 12.4 终止
三条终止路径:
| 方式 | 触发 | 流程 |
|------|------|------|
| 优雅关闭 | `shutdown_request` via mailbox | Worker 处理请求 → 退出 → idle notification |
| 强制终止 (InProcess) | `killInProcessTeammate()` | abort AbortController → 更新 task 状态为 'killed' → 移出团队文件 |
| 强制终止 (Pane) | `backend.killPane(paneId)` | 杀死 tmux/iTerm2 pane |
### 12.5 会话清理
`cleanupSessionTeams()` 在 Leader 退出时运行:
- 杀死所有孤立 pane
- 移除团队和任务目录
- 销毁 git worktree
---
## 十三、Feature Gates 汇总
| Feature Flag | 控制内容 | 激活方式 |
|-------------|---------|---------|
| `COORDINATOR_MODE` | Coordinator 自动编排 | 编译时 + `CLAUDE_CODE_COORDINATOR_MODE=1` |
| `FORK_SUBAGENT` | Fork 模式子 Agent | 编译时 feature gate |
| `BUILTIN_EXPLORE_PLAN_AGENTS` | Explore/Plan 内置 Agent | 编译时 + A/B test `tengu_amber_stoat` |
| `VERIFICATION_AGENT` | 验证 Agent | 编译时 + gate `tengu_hive_evidence` |
| Agent Teams (Swarm) | 团队协作模式 | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` + GrowthBook gate |
---
## 十四、通信协议总览
| 通道 | 机制 | 方向 | 用途 |
|------|------|------|------|
| 文件邮箱 `inboxes/{name}.json` | JSON + 文件锁 | 任意 Agent → 任意 Agent | 所有 teammate 消息、权限、关闭协议 |
| 内存队列 `pendingUserMessages` | AppState | 父 → InProcess 子 | 运行中 Agent 的即时消息 |
| Leader Permission Bridge | 模块级函数注册 | InProcess Worker → Leader UI | 权限弹窗 |
| UDS Socket | Unix Domain Socket | Session → Session (本地) | 跨 session 消息 |
| Bridge (Remote Control) | HTTP via Anthropic | Session → Session (跨机器) | 远程控制消息 |
| Task 系统 | 文件 `~/.claude/tasks/` | 所有团队成员 | 工作项追踪、状态更新 |
| `<task-notification>` XML | 注入对话 | 后台 Agent → 父 Agent | 完成/失败通知 |
---
## 十五、架构规模统计
| 层次 | 核心组件 | 代码规模 |
|------|---------|---------|
| 入口 | AgentTool | ~800行 |
| 执行引擎 | runAgent + query() 循环 | ~2,700行 |
| Agent 定义 | loadAgentsDir + builtInAgents | ~850行 |
| 后端管理 | registry + 3个后端实现 | ~1,800行 |
| 通信 | teammateMailbox + SendMessageTool | ~2,100行 |
| 权限委托 | permissionSync + leaderPermissionBridge | ~1,000行 |
| 团队管理 | teamHelpers + spawnMultiAgent | ~1,800行 |
| 上下文隔离 | agentContext + teammateContext | ~300行 |
| Coordinator | coordinatorMode + workerAgent | ~400行 |
| InProcess Runner | inProcessRunner | ~1,550行 |
| **总计** | **37+ 文件** | **~13,700行** |
---
## 十六、核心设计理念
1. **query() 循环复用** — 子 Agent 使用与主 REPL 完全相同的 agentic 循环,天然具备完整工具能力
2. **AsyncLocalStorage 隔离** — InProcess 模式下零 IPC 开销,通过 Node.js 原生机制隔离上下文
3. **文件邮箱统一通信** — 跨进程、跨后端的统一消息协议,用文件锁保证并发安全
4. **权限始终由人类把控** — 无论多少层 Agent 嵌套,危险操作最终都路由到 Leader 的 UI 由用户决定
5. **优雅降级** — 从 iTerm2 → tmux → InProcess自动选择最佳可用后端
6. **Fire-and-forget 异步** — 后台 Agent 通过 `<task-notification>` XML 非侵入式通知父 Agent

View File

@@ -0,0 +1,274 @@
# macOS 上清除 Claude Code 追踪数据指南
> 基于 Claude Code 源码2026-03-31 泄露快照512K 行 TypeScript的逆向分析。
> 所有文件路径和字段名均从源码中确认。
---
## 背景Claude Code 追踪了什么?
Claude Code **不收集硬件指纹**(无 MAC 地址、CPU 型号、内存大小、GPU 信息),但通过以下机制实现用户追踪:
| 追踪标识 | 持久性 | 存储位置 | 说明 |
|----------|--------|----------|------|
| `userID` | 永久(直到手动删除) | `~/.claude.json` | 随机生成的 64 位十六进制字符串,跨会话追踪主键 |
| `anonymousId` | 永久 | `~/.claude.json` | 格式 `claudecode.v1.<uuid>`,备用追踪 ID |
| `accountUuid` | 永久(绑定账号) | `~/.claude.json``oauthAccount` | OAuth 登录后直接关联身份 |
| `emailAddress` | 永久 | `~/.claude.json``oauthAccount` | 登录邮箱 |
| `rh` (仓库哈希) | 按仓库 | 每次 API 请求 Header | git remote URL 的 SHA256 前 16 位 |
| Statsig Stable ID | 永久 | `~/.claude/statsig/` | 特性开关系统的设备标识 |
**数据流向:**
- **Anthropic 1P** → `/api/event_logging/batch`(完整环境数据 + Auth
- **Datadog** → `https://http-intake.logs.us5.datadoghq.com`(白名单事件,已脱敏)
- **OTLP**(可选)→ 用户自配的端点(默认关闭)
---
## 第一级:重置设备标识(最重要)
这是跨会话追踪的主键。清除后你对 Anthropic 来说就是一台"全新设备"。
```bash
# 查看当前的追踪 ID
grep -E '"userID"|"anonymousId"|"firstStartTime"|"claudeCodeFirstTokenDate"' ~/.claude.json
```
```bash
# 删除追踪标识(保留其他配置不变)
python3 -c "
import json, os
p = os.path.expanduser('~/.claude.json')
with open(p, 'r') as f: d = json.load(f)
removed = []
for k in ['userID', 'anonymousId', 'firstStartTime', 'claudeCodeFirstTokenDate']:
if k in d:
removed.append(k)
del d[k]
with open(p, 'w') as f: json.dump(d, f, indent=2)
print(f'已删除: {removed}')
print('下次启动 Claude Code 会自动生成新的 userID')
"
```
**效果:** 下次启动时会生成全新的 `userID`,之前的使用记录无法与你关联。
---
## 第二级:清除遥测和分析数据
```bash
# 未成功上报的分析事件(包含完整的环境信息、会话数据)
rm -rf ~/.claude/telemetry/
# Statsig/GrowthBook 特性开关缓存(包含 stable_id 设备标识)
rm -rf ~/.claude/statsig/
# 统计缓存
rm -f ~/.claude/stats-cache.json
```
**效果:** 清除本地缓存的遥测数据和特性开关系统的设备标识。
---
## 第三级:清除会话和历史记录
```bash
# 完整命令历史(你输入过的所有提示词)
rm -f ~/.claude/history.jsonl
# 会话快照
rm -rf ~/.claude/sessions/
# 大段粘贴内容的哈希缓存
rm -rf ~/.claude/paste-cache/
# Shell 环境快照
rm -rf ~/.claude/shell-snapshots/
# 会话环境变量
rm -rf ~/.claude/session-env/
# 文件编辑历史Claude 做过的每次文件修改)
rm -rf ~/.claude/file-history/
# 调试日志
rm -rf ~/.claude/debug/
```
**效果:** 清除所有本地会话痕迹。不影响 Claude Code 正常使用。
---
## 第四级:清除 OAuth 账号关联
```bash
# 查看当前关联的账号信息
python3 -c "
import json, os
with open(os.path.expanduser('~/.claude.json')) as f: d = json.load(f)
oa = d.get('oauthAccount', {})
print(f\"账号 UUID: {oa.get('accountUuid', '无')}\")
print(f\"邮箱: {oa.get('emailAddress', '无')}\")
"
```
```bash
# 从 macOS Keychain 删除 OAuth Token
security delete-generic-password -s "claude-code" 2>/dev/null
security delete-generic-password -s "claude-code-credentials" 2>/dev/null
# 清除配置文件中的账号缓存
python3 -c "
import json, os
p = os.path.expanduser('~/.claude.json')
with open(p, 'r') as f: d = json.load(f)
removed = []
for k in ['oauthAccount', 's1mAccessCache', 'groveConfigCache',
'passesEligibilityCache', 'clientDataCache',
'cachedExtraUsageDisabledReason', 'githubRepoPaths']:
if k in d:
removed.append(k)
del d[k]
with open(p, 'w') as f: json.dump(d, f, indent=2)
print(f'已删除: {removed}')
"
```
**效果:** 断开与 Claude.ai 账号的本地关联。下次使用需要重新登录。
---
## 第五级:完全重置(核弹选项)
```bash
# 1. 备份你的自定义配置
mkdir -p ~/Desktop/claude-backup
cp ~/.claude/CLAUDE.md ~/Desktop/claude-backup/ 2>/dev/null
cp ~/.claude/settings.json ~/Desktop/claude-backup/ 2>/dev/null
cp -r ~/.claude/skills ~/Desktop/claude-backup/ 2>/dev/null
cp -r ~/.claude/hooks ~/Desktop/claude-backup/ 2>/dev/null
echo "已备份到 ~/Desktop/claude-backup/"
# 2. 删除所有 Claude Code 数据
rm -rf ~/.claude/
rm -f ~/.claude.json
# 3. 清除 Keychain 中的 Token
security delete-generic-password -s "claude-code" 2>/dev/null
security delete-generic-password -s "claude-code-credentials" 2>/dev/null
echo "已完全重置。下次启动 Claude Code 会重新初始化。"
```
**效果:** 等同于全新安装。所有配置、历史、记忆、技能、插件设置全部清除。
---
## 防止未来追踪
### 方法 1禁用非必要网络流量
`~/.claude/settings.json` 中添加:
```json
{
"env": {
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
}
}
```
**效果:** 禁用分析上报、GrowthBook 特性开关拉取、配额预检等非必要请求。
### 方法 2使用第三方云后端
源码确认:使用 Bedrock 或 Vertex 时,`isAnalyticsDisabled()` 返回 `true`,完全跳过所有分析代码。
```bash
# 使用 AWS Bedrock需要 AWS 凭证)
export CLAUDE_CODE_USE_BEDROCK=1
# 或使用 Google Vertex AI需要 GCP 凭证)
export CLAUDE_CODE_USE_VERTEX=1
```
### 方法 3定期自动清理
创建一个定时清理脚本 `~/claude-privacy-clean.sh`
```bash
#!/bin/bash
# 清除 Claude Code 追踪数据(保留配置)
rm -rf ~/.claude/telemetry/
rm -rf ~/.claude/statsig/
rm -f ~/.claude/stats-cache.json
rm -f ~/.claude/history.jsonl
rm -rf ~/.claude/sessions/
rm -rf ~/.claude/paste-cache/
rm -rf ~/.claude/shell-snapshots/
rm -rf ~/.claude/session-env/
rm -rf ~/.claude/debug/
# 重置 device ID
python3 -c "
import json, os
p = os.path.expanduser('~/.claude.json')
if os.path.exists(p):
with open(p,'r') as f: d = json.load(f)
for k in ['userID','anonymousId','firstStartTime','claudeCodeFirstTokenDate']:
d.pop(k, None)
with open(p,'w') as f: json.dump(d,f,indent=2)
"
echo "[$(date)] Claude Code 追踪数据已清除"
```
```bash
# 添加执行权限
chmod +x ~/claude-privacy-clean.sh
# 可选:添加到 crontab 每天自动执行
# crontab -e
# 0 3 * * * ~/claude-privacy-clean.sh >> ~/claude-clean.log 2>&1
```
---
## 各级清理的影响对比
| 操作 | 对 Anthropic 的效果 | 对你的影响 |
|------|---------------------|------------|
| **重置 Device ID** | 无法关联历史使用数据 | 无感知,自动生成新 ID |
| **清除遥测** | 本地缓存的分析事件不会补发 | 无感知 |
| **清除历史** | — | 丢失命令历史和 ctrl+r 搜索 |
| **清除 OAuth** | 断开账号关联 | 需要重新登录 |
| **完全重置** | 等同全新用户 | 丢失所有自定义配置 |
| **禁用非必要流量** | 不再接收分析数据 | 特性开关可能不更新 |
| **使用 Bedrock/Vertex** | 分析代码完全不执行 | 需要云厂商凭证 |
---
## 附:数据文件速查表
| 文件/目录 | 包含的追踪数据 |
|-----------|----------------|
| `~/.claude.json` | userID, anonymousId, oauthAccount, 首次使用时间, GitHub 仓库映射 |
| `~/.claude/telemetry/` | 未上报的 1P 分析事件JSON含完整 EnvContext |
| `~/.claude/statsig/` | Statsig stable_id, 特性开关缓存 |
| `~/.claude/stats-cache.json` | 统计数据缓存 |
| `~/.claude/history.jsonl` | 完整命令历史(你输入的每一条提示词) |
| `~/.claude/sessions/` | 会话元数据 |
| `~/.claude/paste-cache/` | 粘贴内容的哈希地址缓存 |
| `~/.claude/file-history/` | Claude 做过的文件修改记录 |
| `~/.claude/debug/` | 调试日志 |
| `~/.claude/shell-snapshots/` | Shell 环境快照 |
| macOS Keychain → `claude-code` | OAuth access/refresh token |
---
*来自AI超元域 | B站频道https://space.bilibili.com/3493277319825652*
*基于 Claude Code 源码逆向分析2026-03-31*