
1. 先搞清楚 Claude Code Checkpoint 到底在解决什么问题Claude Code 的 Checkpoint 机制简单说就是给对话式编程加了一个“撤销栈”。你在会话里让模型改了三个文件发现方向不对想回到改动之前——这时候需要的不只是文件回滚还有对话上下文的回退。Checkpoint 就是干这个的。它适合谁适合需要在本地复现或调试 Checkpoint 行为的开发者尤其是想搞清楚 JSONL transcript 怎么写入、怎么读取、rewind 怎么触发回滚的人。如果你只是日常用 Claude Code 写代码知道/rewind能回退就够了但如果你想在自己的工具里复刻这套机制或者排查“为什么 rewind 没生效”那就得往下看实现细节。核心难点在于如果每次对话都保存所有文件的完整内容体积会爆炸如果只保存对话文件状态又恢复不了。Claude Code 的解法是两个独立系统加三层存储——文件快照系统负责文件级恢复Transcript 系统负责对话级恢复两者通过 messageId 关联。下面我会从配置骨架开始一步步带你把这条链路跑通包括 settings.json 怎么写、JSONL 长什么样、rewind 怎么验证。2. 前置准备TaoToken 统一 Key 与 API 通道在复现 Checkpoint 行为之前你需要一个能稳定调用 Claude 系列模型的通道。TaoToken 提供统一的 Key 和 API 入口把模型调用、Coding Plan、控制台管理都收在同一个账号体系下省去分别配置多个供应商的麻烦。具体来说你需要做三件事第一拿到 API Key。访问控制台创建密钥地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。创建后复制保存后面配置里要用。第二确认 API 基地址。TaoToken 的 API 入口是 https://taotoken.net/api 注意这个地址不加 UTM 参数直接作为 base_url 使用。第三如果你打算长期跑编码任务或 Agent 流程可以了解 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它适合需要持续调用、频繁触发 Checkpoint 的场景。注意API Key 只显示一次创建后立刻保存到本地环境变量或配置文件不要硬编码在会提交到 Git 的文件里。3. 可复制配置settings.json 骨架与 JSONL 写入路径Claude Code 的 Checkpoint 行为受settings.json控制。下面是一个可复制的最小配置骨架重点开启 file history 并指定 transcript 存储位置。{ fileHistory: { enabled: true, backupRoot: ~/.claude/backups, transcriptPath: ~/.claude/transcripts, snapshotOnUserMessage: true, trackBeforeEdit: true }, api: { baseUrl: https://taotoken.net/api, apiKey: ${TAOTOKEN_API_KEY}, model: claude-sonnet-4-20250514 }, session: { persistTranscript: true, transcriptFormat: jsonl } }几个关键字段说明fileHistory.enabled是总开关关掉之后 Layer 1 和 Layer 2 都不会触发。backupRoot是物理备份的存放目录每个文件按内容哈希分目录版本号从 v1 递增。transcriptPath是 JSONL 文件的落盘位置通常按会话 ID 分文件。snapshotOnUserMessage对应 Layer 2在每条用户消息处理完后创建完整快照。trackBeforeEdit对应 Layer 1在文件被修改前先备份。API 部分用环境变量引用 Key避免明文。baseUrl 指向 TaoToken 的 API 入口这样模型调用走统一通道Checkpoint 的触发链路和模型响应在同一会话里完成。配置写好后启动 Claude Code 时会话目录下会出现类似这样的结构~/.claude/ ├── backups/ │ └── a1b2c3d4/ │ ├── main.pyv1 │ └── main.pyv2 └── transcripts/ └── session-20250610.jsonlJSONL 文件里每一行是一条独立记录Checkpoint 相关的记录长这样{type:file-history-snapshot,messageId:msg-002,snapshot:{files:{main.py:{version:1,backupPath:~/.claude/backups/a1b2c3d4/main.pyv1,timestamp:1749523200}}},isSnapshotUpdate:true} {type:file-history-snapshot,messageId:msg-003,snapshot:{files:{main.py:{version:2,backupPath:~/.claude/backups/a1b2c3d4/main.pyv2,timestamp:1749523260}}},isSnapshotUpdate:false}isSnapshotUpdate为 true 表示这是 Layer 1 的单文件增量备份为 false 表示这是 Layer 2 的完整快照。读取时按 messageId 索引rewind 就是根据 messageId 找到对应快照再回写文件。4. 验证请求触发 Checkpoint 并检查 JSONL 落盘配置就绪后用一次实际修改来验证整条链路。我试过的最小验证流程如下。第一步准备一个测试文件mkdir -p ~/checkpoint-demo cd ~/checkpoint-demo echo def hello(): main.py echo return v1 main.py第二步启动 Claude Code 并让它修改这个文件。在会话里输入把 main.py 里的返回值改成 v2第三步观察备份目录和 transcript 文件的变化。修改完成后执行ls -la ~/.claude/backups/*/ cat ~/.claude/transcripts/session-*.jsonl | tail -5你应该能看到至少两条 file-history-snapshot 记录一条是修改前的 Layer 1 备份isSnapshotUpdatetrue一条是消息处理完后的 Layer 2 完整快照isSnapshotUpdatefalse。备份目录里会出现 main.pyv1 和 main.pyv2 两个文件。第四步验证 rewind。在会话里执行/rewind msg-002其中 msg-002 是你要回退到的消息 ID可以在 transcript 里找到。执行后检查 main.py 内容cat main.py如果返回的是 v1说明 rewind 成功从快照恢复了文件状态。同时 transcript 里 msg-002 之后的消息会被标记为已回退对话上下文也回到对应位置。提示rewind 的 messageId 必须精确匹配 transcript 里的记录。如果记不住 ID可以先grep file-history-snapshot把快照记录列出来再选目标。5. 本篇常见错排查5.1 rewind 报 Snapshot not found最常见的原因是 messageId 写错了或者该消息根本没有触发快照。检查 transcript 里是否存在对应 messageId 的 file-history-snapshot 记录。如果没有说明 Layer 1 或 Layer 2 没触发回到 settings.json 确认fileHistory.enabled和snapshotOnUserMessage是否为 true。另一个可能是 transcript 文件被截断或轮转。JSONL 是追加写入的如果手动清理过文件旧记录会丢失。rewind 依赖完整的历史记录不要随意删 transcript。5.2 备份目录为空如果~/.claude/backups下什么都没有先确认文件修改是否真的发生了。Layer 1 是同步前置钩子只有实际执行文件写入时才会触发。如果模型只是回复了文本没有调用文件编辑工具就不会有备份。还要检查backupRoot路径是否有写权限。在某些系统上~展开可能不符合预期建议用绝对路径测试一次。5.3 JSONL 里只有 isSnapshotUpdatetrue 没有 false这说明 Layer 1 触发了但 Layer 2 没触发。Layer 2 是异步后置钩子在用户消息处理完毕后执行。如果会话被提前中断或者snapshotOnUserMessage被设为 false就不会有完整快照。另外注意 Layer 2 是void调用的异步操作不阻塞主流程。如果进程在异步任务完成前退出记录可能来不及写入。验证时确保会话正常结束再检查文件。5.4 文件恢复了但对话没回退这是两个系统分离设计的正常表现。File History 只负责文件快照Transcript 负责对话记录。rewind 时两者都会处理但如果 Transcript 的写入失败或 messageId 对不上文件可能恢复了而对话没动。检查 transcript 里 rewind 操作本身是否被记录以及后续消息是否正确标记。5.5 API 调用失败导致 Checkpoint 链路中断如果模型请求本身失败文件修改不会发生Layer 1 自然不触发。确认 baseUrl 指向 https://taotoken.net/api Key 有效且额度充足。可以在模型对话页面先做一次简单调用验证通道地址是 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。6. 接入与排障入口Checkpoint 的调试核心在于两件事Key 通道是否通transcript 是否完整。如果你在接入过程中遇到 API 报错或鉴权问题先去 API Keys 页面确认密钥状态地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有 base_url 配置和常见错误码说明。如果你用的是 Claude Code 的 Anthropic 兼容模式参考 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude-code-anthropicutm_campaignrewrite 里的配置示例确保请求格式和 Checkpoint 触发条件匹配。长期跑编码任务的话Coding Plan 能减少频繁鉴权带来的中断地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。把 Key 和通道稳定下来之后Checkpoint 的 JSONL 记录才会连续rewind 才有可靠的目标可查。