克劳德代码为何如此稳定?开发人员深入了解其本地存储设计
最近,克劳德代码无处不在。开发人员正在使用它来更快地发布功能、实现工作流程自动化,以及开发能在实际项目中发挥作用的 Agents 原型。更令人吃惊的是,许多非编码人员也加入其中--构建工具、连接任务,几乎无需任何设置就能获得有用的结果。人工智能编码工具能如此迅速地普及到如此多不同技能水平的人,实属罕见。
不过,真正突出的是它的稳定性。克劳德代码会记住在不同会话中发生的事情,在崩溃时也不会丢失进度,它的行为更像是一个本地开发工具,而不是聊天界面。这种可靠性来自于它处理本地存储的方式。
Claude Code 不会将你的编码会话视为临时聊天,而是读写真实文件,将项目状态存储在磁盘上,并记录代理工作的每一步。会话可以恢复、检查或回滚,无需猜测,而且每个项目都保持干净隔离,避免了许多 Agents 工具会遇到的交叉污染问题。
在这篇文章中,我们将仔细研究这种稳定性背后的存储架构,以及为什么它在让克劳德代码感觉日常开发实用性方面发挥了如此大的作用。
每个本地人工智能编码助手都会面临的挑战
在解释 Claude Code 如何处理存储问题之前,我们先来看看本地 AI 编码工具容易遇到的常见问题。当一个助手直接在你的文件系统上工作并长期保持状态时,这些问题自然而然就会出现。
1.项目数据在不同工作区之间混杂。
大多数开发人员每天都会在多个版本库之间切换。如果助手将状态从一个项目带入另一个项目,就会变得更难理解其行为,也更容易做出错误的假设。每个项目都需要有自己干净、独立的状态和历史记录空间。
2.崩溃会导致数据丢失。
在编码过程中,助手会产生源源不断的有用数据--文件编辑、工具调用、中间步骤。如果不立即保存这些数据,系统崩溃或强制重启就会导致数据丢失。可靠的系统会在创建重要状态后立即将其写入磁盘,这样工作就不会意外丢失。
3.Agents 实际做了什么并不总是很清楚。
一个典型的会话涉及许多小操作。如果没有清晰、有序的操作记录,就很难追溯助手是如何实现特定输出的,或者找到出错的步骤。有了完整的历史记录,调试和审查工作就容易多了。
4.撤销错误太费劲。
有时,助手做出的更改并不完全奏效。如果没有回退这些更改的内置方法,最终只能在整个版本库中手动查找编辑内容。系统应该自动跟踪更改的内容,这样你就可以干净利落地撤销更改,而无需额外的工作。
5.不同的项目需要不同的设置。
本地环境各不相同。有些项目需要特定的权限、工具或目录规则;其他项目则需要自定义脚本或工作流程。助手需要尊重这些差异,允许按项目设置,同时保持核心行为一致。
克劳德代码背后的存储设计原则
Claude 代码的存储设计围绕四个简单明了的理念展开。它们看似简单,却能共同解决人工智能助手直接在你的机器上跨多个项目工作时出现的实际问题。
1.每个项目都有自己的存储空间。
克劳德代码会将所有会话数据绑定到所属的项目目录。这意味着对话、编辑和日志都会保留在它们来自的项目中,不会泄漏到其他项目中。将存储空间分开可以让助手的行为更容易理解,也可以轻松检查或删除特定 repo 的数据。
2.数据立即保存到磁盘。
克劳德代码不会将交互数据保存在内存中,而是在数据创建后立即将其写入磁盘。每个事件--消息、工具调用或状态更新--都会被添加为新条目。如果程序意外崩溃或关闭,几乎所有内容都还在。这种方法既能保持会话的持久性,又不会增加太多复杂性。
3.每个操作在历史中都有明确的位置。
克劳德代码将每条信息和工具操作与之前的信息和工具操作联系起来,形成一个完整的序列。有了这种有序的历史记录,就可以回顾会话是如何展开的,并追溯导致特定结果的步骤。对于开发人员来说,有了这种跟踪记录,调试和理解 Agents 的行为就容易多了。
4.代码编辑很容易回滚。
在助手更新文件之前,克劳德代码会保存其先前状态的快照。如果发现更改是错误的,你可以还原之前的版本,而无需翻阅版本库或猜测更改了什么。这个简单的安全网让人工智能驱动的编辑风险大大降低。
克劳德代码本地存储布局
克劳德代码将所有本地数据存储在一个地方:你的主目录。这样可以保持系统的可预测性,并在需要时更容易检查、调试或清理。存储布局围绕两个主要部分展开:一个小型全局配置文件和一个较大的数据目录,所有项目级状态都存放在该目录中。
两个核心组件
~/.claude.json存储全局配置和快捷方式,包括项目映射、MCP 服务器设置和最近使用的提示。~/.claude/主数据目录,克劳德代码在此存储对话、项目会话、权限、插件、技能、历史和相关运行时数据。
接下来,让我们仔细看看这两个核心组件。
(1) 全局配置:~/.claude.json
该文件的作用是索引而非数据存储。它记录了你参与过的项目、每个项目附带的工具以及你最近使用过的提示。对话数据本身并不存储在这里。
{
"projects": {
"/Users/xxx/my-project": {
"mcpServers": {
"jarvis-tasks": {
"type": "stdio",
"command": "python",
"args": ["/path/to/run_mcp.py"]
}
}
}
},
"recentPrompts": [
"Fix the bug in auth module",
"Add unit tests"
]
}
(2) 主数据目录:~/.claude/
~/.claude/ 目录是克劳德代码的大部分本地状态所在。它的结构反映了几个核心设计理念:项目隔离、即时持久性和错误后的安全恢复。
~/.claude/
├── settings.json # Global settings (permissions, plugins, cleanup intervals)
├── settings.local.json # Local settings (machine-specific, not committed to Git)
├── history.jsonl # Command history
│
├── projects/ # 📁 Session data (organized by project, core directory)
│ └── -Users-xxx-project/ # Path-encoded project directory
│ ├── {session-id}.jsonl # Primary session data (JSONL format)
│ └── agent-{agentId}.jsonl # Sub-agent session data
│
├── session-env/ # Session environment variables
│ └── {session-id}/ # Isolated by session ID
│
├── skills/ # 📁 User-level skills (globally available)
│ └── mac-mail/
│ └── SKILL.md
│
├── plugins/ # 📁 Plugin management
│ ├── config.json # Global plugin configuration
│ ├── installed_plugins.json # List of installed plugins
│ ├── known_marketplaces.json # Marketplace source configuration
│ ├── cache/ # Plugin cache
│ └── marketplaces/
│ └── anthropic-agent-skills/
│ ├── .claude-plugin/
│ │ └── marketplace.json
│ └── skills/
│ ├── pdf/
│ ├── docx/
│ └── frontend-design/
│
├── todos/ # Task list storage
│ └── {session-id}-*.json # Session-linked task files
│
├── file-history/ # File edit history (stored by content hash)
│ └── {content-hash}/ # Hash-named backup directory
│
├── shell-snapshots/ # Shell state snapshots
├── plans/ # Plan Mode storage
├── local/ # Local tools / node_modules
│ └── claude # Claude CLI executable
│ └── node_modules/ # Local dependencies
│
├── statsig/ # Feature flag cache
├── telemetry/ # Telemetry data
└── debug/ # Debug logs
这种布局有意简单化:克劳德代码生成的所有内容都存放在一个目录下,按项目和会话组织。这样就不会有隐藏状态散落在系统中,而且在必要时也很容易检查或清理。
克劳德代码如何管理配置
克劳德代码的配置系统是围绕一个简单的理念设计的:在不同的机器上保持默认行为一致,但仍允许个人环境和项目定制自己需要的内容。为了做到这一点,克劳德代码采用了三层配置模型。当同一设置出现在多个地方时,更具体的配置层总是胜出。
三个配置层
克劳德代码按以下顺序加载配置,从最低优先级到最高优先级:
┌─────────────────────────────────────────┐
│ Project-level configuration │ Highest priority
│ project/.claude/settings.json │ Project-specific, overrides other configs
├─────────────────────────────────────────┤
│ Local configuration │ Machine-specific, not version-controlled
│ ~/.claude/settings.local.json │ Overrides global configuration
├─────────────────────────────────────────┤
│ Global configuration │ Lowest priority
│ ~/.claude/settings.json │ Base default configuration
└─────────────────────────────────────────┘
你可以认为这是从全局默认值开始,然后应用特定于机器的调整,最后应用特定于项目的规则。
接下来,我们将详细介绍每个配置级别。
(1) 全局配置:~/.claude/settings.json
全局配置定义了克劳德代码在所有项目中的默认行为。在这里,你可以设置基线权限、启用插件和配置清理行为。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": ["Read(**)", "Bash(npm:*)"],
"deny": ["Bash(rm -rf:*)"],
"ask": ["Edit", "Write"]
},
"enabledPlugins": {
"document-skills@anthropic-agent-skills": true
},
"cleanupPeriodDays": 30
}
(2) 本地配置:~/.claude/settings.local.json
本地配置只针对一台机器。它不用于共享或在版本控制中检查。这使得它成为 API 密钥、本地工具或特定环境权限的好地方。
{
"permissions": {
"allow": ["Bash(git:*)", "Bash(docker:*)"]
},
"env": {
"ANTHROPIC_API_KEY": "sk-ant-xxx"
}
}
(3) 项目级配置:project/.claude/settings.json
项目级配置只适用于单个项目,优先级最高。在这里,你可以定义在该版本库中工作时始终适用的规则。
{
"permissions": {
"allow": ["Bash(pytest:*)"]
}
}
定义了配置层后,下一个问题就是Claude Code 如何在运行时实际解决配置和权限问题。
克劳德代码分三层应用配置:首先是全局默认值,然后是特定机器的覆盖,最后是特定项目的规则。当同一设置出现在多个地方时,最具体的配置优先。
权限遵循固定的评估顺序:
deny- 始终阻止
询问- 需要确认
允许- 自动运行
默认- 仅在无规则匹配时应用
这样既能保证系统的默认安全性,又能为项目和单个机器提供所需的灵活性。
会话存储:克劳德代码如何保存核心交互数据
在克劳德代码中,会话是数据的核心单位。会话记录了用户与人工智能之间的整个交互过程,包括对话本身、工具调用、文件更改和相关上下文。如何存储会话对系统的可靠性、可调试性和整体安全性有直接影响。
为每个项目单独保存会话数据
会话定义完成后,下一个问题就是Claude Code如何存储会话,以保持数据的有序性和隔离性。
克劳德代码按项目隔离会话数据。每个项目的会话都存储在由项目文件路径导出的目录下。
存储路径遵循这种模式:
~/.claude/projects/ + path-encoded project directory
要创建一个有效的目录名,特殊字符(如/ 、空格和~ )将被替换为- 。
例如
/Users/bill/My Project → -Users-bill-My-Project
这种方法可确保来自不同项目的会话数据不会混合,并可按项目进行管理或删除。
为何使用 JSONL 格式存储会话
克劳德代码使用 JSONL(JSON 行)而不是标准 JSON 来存储会话数据。
在传统的 JSON 文件中,所有信息都被捆绑在一个大型结构中,这意味着每当文件发生变化时,都必须读取和重写整个文件。相比之下,JSONL 将每条信息作为独立的一行存储在文件中。一行等于一条信息,没有外层包装。
| 优点 | 标准 JSON | JSONL (JSON 行) |
|---|---|---|
| 数据存储方式 | 一个大结构 | 每行一条信息 |
| 何时保存数据 | 通常在最后 | 立即,每条信息 |
| 崩溃影响 | 整个文件可能崩溃 | 只影响最后一行 |
| 写入新数据 | 重写整个文件 | 添加一行 |
| 内存使用 | 加载所有内容 | 逐行读取 |
JSONL 在几个关键方面更胜一筹:
立即保存:每条信息生成后都会立即写入磁盘,而不是等待会话结束。
抗崩溃:如果程序崩溃,可能只会丢失最后一条未完成的信息。在此之前写入的所有内容都不会丢失。
快速追加:新信息会添加到文件末尾,无需读取或重写现有数据。
内存使用率低:会话文件可以一行一行地读取,因此无需将整个文件加载到内存中。
简化的 JSONL 会话文件如下所示:
{"type":"user","message":{"role":"user","content":"Hello"},"timestamp":"2026-01-05T10:00:00Z"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}]}}
{"type":"user","message":{"role":"user","content":"Help me fix this bug"}}
会话信息类型
会话文件记录了与克劳德代码交互过程中发生的一切。为了清晰地记录,会话文件针对不同类型的事件使用了不同的消息类型。
用户消息代表进入系统的新输入。这不仅包括用户输入的内容,还包括工具返回的结果,如 shell 命令的输出。从人工智能的角度来看,这两者都是它需要响应的输入。
助手信息捕捉了克劳德的回应。这些信息包括人工智能的推理、生成的文本以及决定使用的任何工具。它们还记录了使用细节,如令牌计数,以提供交互的完整信息。
文件历史快照是克劳德修改任何文件前创建的安全检查点。通过先保存原始文件状态,克劳德代码可以在出错时撤销更改。
摘要提供了会话的简要概述,并与最终结果相关联。无需重放每个步骤,就能更容易地了解会话的内容。
这些消息类型加在一起,不仅记录了对话,还记录了会话过程中发生的所有操作和效果。
为了更具体地说明这一点,我们来看看用户信息和助手信息的具体示例。
(1) 用户信息示例:
{
"type": "user",
"uuid": "7d90e1c9-e727-4291-8eb9-0e7b844c4348",
"parentUuid": null,
"sessionId": "e5d52290-e2c1-41d6-8e97-371401502fdf",
"timestamp": "2026-01-05T10:00:00.000Z",
"message": {
"role": "user",
"content": "Analyze the architecture of this project"
},
"cwd": "/Users/xxx/project",
"gitBranch": "main",
"version": "2.0.76"
}
(2) 助手信息示例:
{
"type": "assistant",
"uuid": "e684816e-f476-424d-92e3-1fe404f13212",
"parentUuid": "7d90e1c9-e727-4291-8eb9-0e7b844c4348",
"message": {
"role": "assistant",
"model": "claude-opus-4-5-20251101",
"content": [
{
"type": "thinking",
"thinking": "The user wants to understand the project architecture, so I need to check the directory structure first..."
},
{
"type": "text",
"text": "Let me take a look at the project structure first."
},
{
"type": "tool_use",
"id": "toolu_01ABC",
"name": "Bash",
"input": {"command": "ls -la"}
}
],
"usage": {
"input_tokens": 1500,
"output_tokens": 200,
"cache_read_input_tokens": 50000
}
}
}
会话消息如何关联
克劳德代码不会将会话消息存储为孤立的条目。相反,它会将它们连接起来,形成一个清晰的事件链。每条信息都包含一个唯一的标识符(uuid )和一条对之前信息的引用(parentUuid )。这样,我们不仅能看到发生了什么,还能知道发生的原因。
会话以用户消息开始,用户消息是会话链的起点。克劳德的每个回复都会指向引起回复的消息。工具调用及其输出以同样的方式添加,每一步都与前一步相关联。当会话结束时,最后一条信息会附加一个摘要。
由于每个步骤都相互关联,因此 Claude Code 可以重放完整的操作序列,并了解结果是如何产生的,从而使调试和分析变得更加容易。
利用文件快照让代码更改易于撤销
人工智能生成的编辑并不总是正确的,有时甚至会走向完全错误的方向。为了让这些修改能安全地进行实验,Claude 代码使用了一个简单的快照系统,让你无需翻阅差异或手动清理文件就能撤销编辑。
其原理很简单:在克劳德代码修改文件之前,它会保存一份原始内容的副本。如果编辑结果是错误的,系统可以立即恢复之前的版本。
什么是文件历史快照?
文件历史快照是在文件被修改前创建的检查点。它记录了克劳德即将编辑的每个文件的原始内容。这些快照是撤销和回滚操作的数据源。
当用户发送可能更改文件的信息时,克劳德代码会为该信息创建一个空快照。编辑前,系统会将每个目标文件的原始内容备份到快照中,然后将编辑内容直接应用到磁盘。如果用户触发撤消,克劳德代码会恢复已保存的内容并覆盖修改过的文件。
实际上,可撤销编辑的生命周期如下:
用户发送信息克劳德代码创建一个新的、空的
file-history-snapshot记录。克劳德准备修改文件系统确定哪些文件将被编辑,并将其原始内容备份到
trackedFileBackups。克劳德执行编辑编辑和写入操作,并将修改后的内容写入磁盘。
用户触发撤消用户按Esc + Esc 键,表示应恢复更改。
恢复原始内容Claude代码从
trackedFileBackups读取保存的内容,并覆盖当前文件,完成撤销。
为什么撤消有效?快照保存旧版本
克劳德代码中的撤消之所以有效,是因为系统会在任何编辑发生之前保存原始文件内容。
克劳德代码没有试图在事后逆转修改,而是采用了一种更简单的方法:它会复制修改前的文件,并将该副本存储在trackedFileBackups 中。当用户触发撤销时,系统就会恢复这个保存的版本,并覆盖已编辑的文件。
下图逐步展示了这一流程:
┌─────────────────────────┐
│ before edit, app.py │
│ print("old") │───────→ Backed up into snapshot trackedFileBackups
└─────────────────────────┘
↓
┌──────────────────────────┐
│ After Claude edits │
│ print(“new”) │───────→ Written to disk (overwrites the original file)
└──────────────────────────┘
↓
┌──────────────────────────┐
│ User triggers undo │
│ Press Esc + Esc │───────→ Restore “old” content to disk from snapshot
└──────────────────────────┘
文件历史快照的内部结构
快照本身以结构化记录的形式存储。它捕获有关用户信息、快照时间的元数据,最重要的是文件与其原始内容的映射。
下面的示例显示了克劳德编辑任何文件前创建的单个file-history-snapshot 记录。trackedFileBackups 中的每个条目都存储了文件编辑前的内容,这些内容随后可用于在撤消过程中还原文件。
{
"type": "file-history-snapshot",
"messageId": "7d90e1c9-e727-4291-8eb9-0e7b844c4348",
"snapshot": {
"messageId": "7d90e1c9-e727-4291-8eb9-0e7b844c4348",
"trackedFileBackups": {
"/path/to/file1.py": "Original file content\ndef hello():\n print('old')",
"/path/to/file2.js": "// Original content..."
},
"timestamp": "2026-01-05T10:00:00.000Z"
},
"isSnapshotUpdate": false
}
快照的存储位置和保存时间
快照元数据的存储位置:快照记录与特定会话绑定,并以 JSONL 文件形式保存在
~/.claude/projects/-path-to-project/{session-id}.jsonl下。备份原始文件内容的位置:每个文件编辑前的内容按内容哈希值单独存储在
~/.claude/file-history/{content-hash}/下。快照默认保存多长时间:快照数据保留 30 天,与全局
cleanupPeriodDays设置一致。如何更改保留期限:保留天数可通过
~/.claude/settings.json中的cleanupPeriodDays字段进行调整。
相关命令
| 命令/操作 | 说明 |
|---|---|
| Esc + Esc | 撤销最近一轮文件编辑(最常用) |
| /rewind | 恢复到先前指定的检查点(快照) |
| /diff | 查看当前文件与快照备份之间的差异 |
其他重要目录
(1) plugins/ - 插件管理
plugins/ 目录存储赋予克劳德代码额外功能的附加组件。
该目录存储已安装的插件、插件的来源以及这些插件提供的额外技能。它还保存下载插件的本地副本,这样就不需要再次下载。
~/.claude/plugins/
├── config.json
│ Global plugin configuration (e.g., enable/disable rules)
├── installed_plugins.json
│ List of installed plugins (including version and status)
├── known_marketplaces.json
│ Plugin marketplace source configuration (e.g., Anthropic official marketplace)
├── cache/
│ Plugin download cache (avoids repeated downloads)
└── marketplaces/
Marketplace source storage
└── anthropic-agent-skills/
Official plugin marketplace
├── .claude-plugin/
│ └── marketplace.json
│ Marketplace metadata
└── skills/
Skills provided by the marketplace
├── pdf/
│ PDF-related skills
├── docx/
│ Word document processing skills
└── frontend-design/
Frontend design skills
(2) skills/ - 储存和应用技能的地方
在克劳德代码中,技能是一种小型、可重复使用的能力,可帮助克劳德执行特定任务,如处理 PDF、编辑文档或遵循编码工作流程。
并非所有技能都能随处使用。有些技能适用于全球,而其他技能则仅限于单个项目或由插件提供。克劳德代码将技能存储在不同的位置,以控制每种技能的使用范围。
下面的层次结构显示了技能如何按范围分层,从全球可用技能到特定项目和插件提供的技能。
| 级别 | 存储位置 | 说明 |
|---|---|---|
| 用户 | ~/.claude/skills/ | 全球可用,所有项目均可访问 |
| 项目 | project/.claude/skills/ | 仅对当前项目有效,针对特定项目进行定制 |
| 插件 | ~/.claude/plugins/marketplaces/*/skills/ | 与插件一起安装,取决于插件启用状态 |
(3) todos/ - 任务列表存储
todos/ 目录存储 Claude 在对话过程中为跟踪工作而创建的任务列表,如要完成的步骤、进行中的项目和已完成的任务。
任务列表以 JSON 文件的形式保存在~/.claude/todos/{session-id}-*.json 下。每个文件名都包含会话 ID,用于将任务列表与特定对话联系起来。
这些文件的内容来自TodoWrite 工具,包括任务描述、当前状态、优先级和相关元数据等基本任务信息。
(4) local/ - 本地运行时和工具
local/ 目录包含 Claude Code 在机器上运行所需的核心文件。
其中包括claude 命令行可执行文件和包含其运行时依赖项的node_modules/ 目录。通过将这些组件保持在本地,克劳德代码可以独立运行,而无需依赖外部服务或系统安装。
(5)其他支持目录
shell-snapshots/:存储 shell 会话状态快照(如当前目录和环境变量),实现 shell 操作符回滚。
plans/:存储由计划模式生成的执行计划(例如,多步骤编程任务的分步分解)。
statsig/:缓存功能标志配置(如是否启用新功能),以减少重复请求。
telemetry/:存储匿名遥测数据(如功能使用频率),用于产品优化。
debug/:存储调试日志(包括错误堆栈和执行跟踪),以帮助排除故障。
结论
在深入了解 Claude Code 如何在本地存储和管理所有内容后,我们可以清楚地看到:该工具之所以感觉稳定,是因为其基础非常扎实。没有什么花哨的东西,只是经过深思熟虑的工程设计。每个项目都有自己的空间,每个操作都会被记录下来,文件编辑会在任何更改之前被备份。这样的设计能让你专注于自己的工作。
我最喜欢的是,这里没有任何神秘的东西。克劳德代码》之所以运行良好,是因为基础工作都做得很好。如果你曾经尝试过创建一个接触真实文件的 Agents,你就会知道事情是多么容易分崩离析--状态混淆、崩溃抹杀进度、撤销变成猜测。Claude Code 采用简单、一致且不易损坏的存储模型,避免了所有这些问题。
对于构建本地或内部人工智能 Agents 的团队来说,尤其是在安全环境中,这种方法展示了强大的存储和持久性如何使人工智能工具在日常开发中变得可靠和实用。
如果您正在设计本地或 on-prem AI 代理,并希望更详细地讨论存储架构、会话设计或安全回滚,欢迎加入我们的Slack 频道。您还可以通过Milvus Office Hours预约 20 分钟的一对一服务,获得个性化指导。
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word



