文件检查点追踪 Agent 会话中通过 Write、Edit、NotebookEdit 工具进行的文件变更,支持将文件回滚到任意之前的状态。注意:只追踪工具调用的文件变更,Bash 命令(echo、sed -i 等)的变更不在追踪范围内。

核心机制

工作原理:启用后,SDK 在工具修改文件前自动备份。每条 UserMessage 携带一个 checkpoint UUID,可作为还原点。调用 rewind_files() 并传入 UUID,已创建的文件被删除,已修改的文件被还原。

文件回滚不回滚对话:rewind_files() 只恢复磁盘文件,对话历史和上下文保持不变。

三步流程:

  1. 启用检查点(enable_file_checkpointing=True + extra_args={"replay-user-messages": None})
  2. 从响应流中捕获 checkpoint UUID(UserMessage.uuid)和 session ID
  3. 需要回滚时,resume 会话并调用 rewind_files(checkpoint_id)

关键细节

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage, ResultMessage
 
options = ClaudeAgentOptions(
    enable_file_checkpointing=True,
    permission_mode="acceptEdits",
    extra_args={"replay-user-messages": None},  # 必须,才能在流中收到 UUID
)
 
checkpoint_id = None
session_id = None
 
async with ClaudeSDKClient(options) as client:
    await client.query("Refactor the authentication module")
    async for message in client.receive_response():
        if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
            checkpoint_id = message.uuid  # 第一个 UUID = 初始状态
        if isinstance(message, ResultMessage):
            session_id = message.session_id
 
# 回滚:resume 会话后调用 rewind_files
async with ClaudeSDKClient(
    ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
) as client:
    await client.query("")  # 空 prompt 打开连接
    async for message in client.receive_response():
        await client.rewind_files(checkpoint_id)
        break

多个还原点:将所有 UserMessage UUID 存入数组,可回滚到任意中间状态(如保留重构但撤销测试添加)。

CLI 回滚:

claude -p --resume <session-id> --rewind-files <checkpoint-uuid>

限制:

  • 只追踪 Write/Edit/NotebookEdit 工具,Bash 命令不追踪
  • 检查点绑定到创建它的会话
  • 不追踪目录的创建/移动/删除

与其他概念的关联

  • sessions - 文件回滚需要 resume 会话(会话只保存对话历史,不保存文件状态)
  • permissions - acceptEdits 模式配合检查点使用

实践要点

  • 捕获第一个 UserMessage UUID 可作为”初始状态”还原点,回滚所有变更
  • 流结束后调用 rewind_files() 会报错(连接已关闭),需要 resume 会话后再调用
  • 高风险操作前可实时检查并立即回滚(在流处理循环中调用 rewind_files())
  • replay-user-messages 是必须的 extra_arg,否则 UserMessage 不包含 UUID