Claude Code 学习站

Agent SDK 文件检查点(File Checkpointing)指南

介绍 Claude Agent SDK 的文件检查点机制:如何启用、捕获 checkpoint UUID、回退文件到历史状态,以及其限制与常见故障排查。

本页目录21
AI 摘要 · 已核查整理于 2026-07-31原文:Rewind file changes with checkpointing(Anthropic)Agent SDKCheckpointingTypeScriptPython
要点速览
  • 只有通过 Write、Edit、NotebookEdit 三个工具产生的文件改动会被跟踪;Bash 命令(如 echo、sed -i)和子代理(subagent)的编辑不会被记录,除非是以 context: fork 方式在前台运行的 skill
  • 启用需要同时设置 enable_file_checkpointing/enableFileCheckpointing 为 true,并在 extra_args/extraArgs 中加入 replay-user-messages 才能在响应流中拿到带 uuid 的用户消息作为检查点
  • rewindFiles()/rewind_files() 只回退磁盘上的文件状态,不会回退对话历史或上下文
  • 回退历史会话(stream 已结束后)必须先用 resume 恢复该 session 并发送空 prompt 打开连接,再调用 rewind
  • 裸 CLI(claude -p --rewind-files)需要手动设置环境变量 CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=true,SDK 内部会话则会自动设置
  • 回退存在若干限制:仅同一 session 内的检查点有效、不还原目录的创建/移动/删除、不跟踪远程或网络文件、会跳过符号链接/硬链接等非常规文件(v2.1.216+ 起,数量记录在 RewindFilesResult.skippedLinks)

本文是对官方 Agent SDK 某页的中文整理,完整与最新内容以原文为准:https://code.claude.com/docs/en/agent-sdk/file-checkpointing

概述

文件检查点(file checkpointing)会跟踪一次 agent 会话中通过 Write、Edit、NotebookEdit 工具对文件所做的修改,使你能够将文件回退到之前的任意状态。

借助 checkpointing 可以:

  • 撤销不想要的改动:将文件恢复到已知的良好状态
  • 探索其他方案:回退到某个检查点后尝试不同的做法
  • 从错误中恢复:当 agent 做出错误修改时进行纠正

警告:只有通过 Write、Edit、NotebookEdit 工具所做的改动会被跟踪。通过 Bash 命令(例如 echo > file.txtsed -i)所做的改动不会被检查点系统捕获,subagent 所做的编辑同样不会被捕获,除非是以 context: fork 的 skill 在前台运行时产生的编辑。

工作原理

启用文件检查点后,SDK 会在通过 Write、Edit 或 NotebookEdit 工具修改文件之前创建备份。响应流中的用户消息会包含一个可用作恢复点的 checkpoint UUID。

注意:文件回退(rewind)只会把磁盘上的文件恢复到之前的状态,不会回退对话本身。调用 rewindFiles()(TypeScript)或 rewind_files()(Python)之后,对话历史和上下文保持不变。

检查点系统会跟踪:

  • 会话期间创建的文件
  • 会话期间修改的文件
  • 被修改文件的原始内容

当你回退到某个检查点时,Claude Code 会删除它创建的文件,并将它修改过的文件恢复为该检查点时刻的内容。Claude Code 会跳过被跟踪路径中属于符号链接(symlink)、硬链接(hard link)或其他非常规文件的路径。同时也会跳过其父目录在检查点时刻的位置已不再解析一致的被跟踪文件,或者其备份无法被安全读取的文件。RewindFilesResult 会在其 skippedLinks 字段中统计所有被跳过的路径。跳过逻辑需要 Claude Code v2.1.216 或更高版本;在 v2.1.216 之前,回退操作会直接对被跟踪路径处的链接进行写入和删除。

实现 checkpointing

要使用文件检查点,需要先在 options 中启用它,从响应流中捕获 checkpoint UUID,然后在需要恢复时调用 rewindFiles()(TypeScript)或 rewind_files()(Python)。

下面的示例展示了完整流程:启用 checkpointing、从响应流中捕获 checkpoint UUID 和 session ID、之后恢复(resume)该 session 以回退文件。每一步的详细说明见下文。本节示例使用提示词 “Refactor the authentication module”。请在包含 authentication 模块的项目中运行,或将提示词改为你项目中实际存在的文件名,这样才能观察到文件变化以及回退后的还原效果。

import asyncio
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    UserMessage,
    ResultMessage,
)


async def main():
    # Step 1: Enable checkpointing
    options = ClaudeAgentOptions(
        enable_file_checkpointing=True,
        permission_mode="acceptEdits",  # Auto-accept file edits without prompting
        extra_args={
            "replay-user-messages": None
        },  # Required to receive checkpoint UUIDs in the response stream
    )

    checkpoint_id = None
    session_id = None

    # Run the query and capture checkpoint UUID and session ID
    async with ClaudeSDKClient(options) as client:
        await client.query("Refactor the authentication module")

        # Step 2: Capture checkpoint UUID from the first user message
        async for message in client.receive_response():
            if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
                checkpoint_id = message.uuid
            if isinstance(message, ResultMessage) and not session_id:
                session_id = message.session_id

    # Step 3: Later, rewind by resuming the session with an empty prompt
    if checkpoint_id and session_id:
        async with ClaudeSDKClient(
            ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
        ) as client:
            await client.query("")  # Empty prompt to open the connection
            async for message in client.receive_response():
                await client.rewind_files(checkpoint_id)
                break
        print(f"Rewound to checkpoint: {checkpoint_id}")


asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";

async function main() {
  // Step 1: Enable checkpointing
  const opts = {
    enableFileCheckpointing: true,
    permissionMode: "acceptEdits" as const, // Auto-accept file edits without prompting
    extraArgs: { "replay-user-messages": null } // Required to receive checkpoint UUIDs in the response stream
  };

  const response = query({
    prompt: "Refactor the authentication module",
    options: opts
  });

  let checkpointId: string | undefined;
  let sessionId: string | undefined;

  // Step 2: Capture checkpoint UUID from the first user message
  try {
    for await (const message of response) {
      if (message.type === "user" && message.uuid && !checkpointId) {
        checkpointId = message.uuid;
      }
      if ("session_id" in message && !sessionId) {
        sessionId = message.session_id;
      }
    }
  } catch (error) {
    // A single-shot query() throws after yielding an error result. If the
    // failure was an error result, sessionId and checkpointId were already
    // captured by the loop above; connection or process failures yield no
    // result message.
    console.error(`Session ended with an error: ${error}`);
  }

  // Step 3: Later, rewind by resuming the session with an empty prompt
  if (checkpointId && sessionId) {
    const rewindQuery = query({
      prompt: "", // Empty prompt to open the connection
      options: { ...opts, resume: sessionId }
    });

    for await (const msg of rewindQuery) {
      await rewindQuery.rewindFiles(checkpointId);
      break;
    }
    console.log(`Rewound to checkpoint: ${checkpointId}`);
  }
}

main();

步骤 1:启用 checkpointing

配置 SDK options,启用 checkpointing 并接收 checkpoint UUID:

选项PythonTypeScript说明
启用 checkpointingenable_file_checkpointing=TrueenableFileCheckpointing: true跟踪文件改动以便回退
接收 checkpoint UUIDextra_args={"replay-user-messages": None}extraArgs: { 'replay-user-messages': null }需要设置此项,才能在响应流中获取用户消息的 UUID
options = ClaudeAgentOptions(
    enable_file_checkpointing=True,
    permission_mode="acceptEdits",
    extra_args={"replay-user-messages": None},
)

async with ClaudeSDKClient(options) as client:
    await client.query("Refactor the authentication module")
const response = query({
  prompt: "Refactor the authentication module",
  options: {
    enableFileCheckpointing: true,
    permissionMode: "acceptEdits" as const,
    extraArgs: { "replay-user-messages": null }
  }
});

步骤 2:捕获 checkpoint UUID 与 session ID

设置好 replay-user-messages 选项(如上所示)后,响应流中的每条用户消息都会带有一个可作为检查点的 UUID。

对大多数场景,只需捕获第一条用户消息的 UUID(message.uuid);回退到它会把被跟踪的文件恢复为最初状态。如果想存储多个检查点并回退到中间状态,参见下文「多个恢复点」。

捕获 session ID(message.session_id)是可选的;只有当你希望在响应流结束之后再回退时才需要它。如果你是在处理消息的过程中立即调用 rewindFiles()(参见下文「在风险操作前设置检查点」的示例),则可以跳过捕获 session ID。

checkpoint_id = None
session_id = None

async for message in client.receive_response():
    # Capture the first user message UUID as the checkpoint
    if isinstance(message, UserMessage) and message.uuid and checkpoint_id is None:
        checkpoint_id = message.uuid
    # Capture session ID from the result message
    if isinstance(message, ResultMessage):
        session_id = message.session_id
let checkpointId: string | undefined;
let sessionId: string | undefined;

for await (const message of response) {
  // Capture the first user message UUID as the checkpoint
  if (message.type === "user" && message.uuid && !checkpointId) {
    checkpointId = message.uuid;
  }
  // Capture session ID from any message that has it
  if ("session_id" in message) {
    sessionId = message.session_id;
  }
}

步骤 3:回退文件

要在响应流结束之后回退,需先用空 prompt 恢复(resume)该 session,再调用带上你的 checkpoint UUID 的 rewind_files()(Python)或 rewindFiles()(TypeScript)。你也可以在流处理过程中直接回退,参见下文「在风险操作前设置检查点」中的模式。

async with ClaudeSDKClient(
    ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
) as client:
    await client.query("")  # Empty prompt to open the connection
    async for message in client.receive_response():
        if checkpoint_id:
            await client.rewind_files(checkpoint_id)
        break
const rewindQuery = query({
  prompt: "", // Empty prompt to open the connection
  options: { ...opts, resume: sessionId }
});

for await (const msg of rewindQuery) {
  if (checkpointId) {
    await rewindQuery.rewindFiles(checkpointId);
  }
  break;
}

如果同时捕获了 session ID 和 checkpoint ID,也可以从 CLI 进行回退。此命令需要 claude 可执行文件(来自 安装 Claude Code,不随 SDK 包一起安装)。SDK 会自动为你启用 checkpointing,但如果你直接运行 claude -p,则必须自行设置环境变量 CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING:

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

--rewind-files 参数不会出现在 claude --help 的输出中,但 CLI 确实支持该参数,用法如上所示。

常见模式

以下模式展示了根据不同使用场景捕获与使用 checkpoint UUID 的不同方式。

在风险操作前设置检查点

此模式只保留最新的一个 checkpoint UUID,在每个 agent 回合前更新它。如果处理过程中出现问题,可以立即回退到最后一个安全状态并跳出循环。

运行此示例前,请将 your_revert_condition(Python)或 yourRevertCondition(TypeScript)替换为你自己的判断逻辑,例如错误检测或校验失败;示例中该占位符并未实际定义。

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage


async def main():
    options = ClaudeAgentOptions(
        enable_file_checkpointing=True,
        permission_mode="acceptEdits",
        extra_args={"replay-user-messages": None},
    )

    safe_checkpoint = None

    async with ClaudeSDKClient(options) as client:
        await client.query("Refactor the authentication module")

        async for message in client.receive_response():
            # Update checkpoint before each agent turn starts
            # This overwrites the previous checkpoint. Only keep the latest
            if isinstance(message, UserMessage) and message.uuid:
                safe_checkpoint = message.uuid

            # Decide when to revert based on your own logic
            # For example: error detection, validation failure, or user input
            if your_revert_condition and safe_checkpoint:
                await client.rewind_files(safe_checkpoint)
                # Exit the loop after rewinding, files are restored
                break


asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";

async function main() {
  const response = query({
    prompt: "Refactor the authentication module",
    options: {
      enableFileCheckpointing: true,
      permissionMode: "acceptEdits" as const,
      extraArgs: { "replay-user-messages": null }
    }
  });

  let safeCheckpoint: string | undefined;

  for await (const message of response) {
    // Update checkpoint before each agent turn starts
    // This overwrites the previous checkpoint. Only keep the latest
    if (message.type === "user" && message.uuid) {
      safeCheckpoint = message.uuid;
    }

    // Decide when to revert based on your own logic
    // For example: error detection, validation failure, or user input
    if (yourRevertCondition && safeCheckpoint) {
      await response.rewindFiles(safeCheckpoint);
      // Exit the loop after rewinding, files are restored
      break;
    }
  }
}

main();

多个恢复点

如果 Claude 在多个回合中做了改动,你可能想回退到某个特定的中间点,而不是一次性全部撤销。例如,Claude 在第一回合重构了一个文件、第二回合添加了测试,你可能希望保留重构结果,只撤销测试改动。

此模式将所有 checkpoint UUID 连同元数据存入数组。会话结束后,你可以回退到之前任意一个检查点:

import asyncio
from dataclasses import dataclass
from datetime import datetime
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    UserMessage,
    ResultMessage,
)


# Store checkpoint metadata for better tracking
@dataclass
class Checkpoint:
    id: str
    description: str
    timestamp: datetime


async def main():
    options = ClaudeAgentOptions(
        enable_file_checkpointing=True,
        permission_mode="acceptEdits",
        extra_args={"replay-user-messages": None},
    )

    checkpoints = []
    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:
                checkpoints.append(
                    Checkpoint(
                        id=message.uuid,
                        description=f"After turn {len(checkpoints) + 1}",
                        timestamp=datetime.now(),
                    )
                )
            if isinstance(message, ResultMessage) and not session_id:
                session_id = message.session_id

    # Later: rewind to any checkpoint by resuming the session
    if checkpoints and session_id:
        target = checkpoints[0]  # Pick any checkpoint
        async with ClaudeSDKClient(
            ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
        ) as client:
            await client.query("")  # Empty prompt to open the connection
            async for message in client.receive_response():
                await client.rewind_files(target.id)
                break
        print(f"Rewound to: {target.description}")


asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";

// Store checkpoint metadata for better tracking
interface Checkpoint {
  id: string;
  description: string;
  timestamp: Date;
}

async function main() {
  const opts = {
    enableFileCheckpointing: true,
    permissionMode: "acceptEdits" as const,
    extraArgs: { "replay-user-messages": null }
  };

  const response = query({
    prompt: "Refactor the authentication module",
    options: opts
  });

  const checkpoints: Checkpoint[] = [];
  let sessionId: string | undefined;

  try {
    for await (const message of response) {
      if (message.type === "user" && message.uuid) {
        checkpoints.push({
          id: message.uuid,
          description: `After turn ${checkpoints.length + 1}`,
          timestamp: new Date()
        });
      }
      if ("session_id" in message && !sessionId) {
        sessionId = message.session_id;
      }
    }
  } catch (error) {
    // A single-shot query() throws after yielding an error result. If the
    // failure was an error result, sessionId and the checkpoints array were
    // already populated by the loop above; connection or process failures
    // yield no result message.
    console.error(`Session ended with an error: ${error}`);
  }

  // Later: rewind to any checkpoint by resuming the session
  if (checkpoints.length > 0 && sessionId) {
    const target = checkpoints[0]; // Pick any checkpoint
    const rewindQuery = query({
      prompt: "", // Empty prompt to open the connection
      options: { ...opts, resume: sessionId }
    });

    for await (const msg of rewindQuery) {
      await rewindQuery.rewindFiles(target.id);
      break;
    }
    console.log(`Rewound to: ${target.description}`);
  }
}

main();

亲自试一试

下面这个完整示例会创建一个小工具文件,让 agent 为其添加文档注释,展示改动结果,然后询问你是否要回退。

开始之前,请确认已安装 Claude Agent SDK

步骤 1:创建测试文件

创建一个名为 utils.py(Python)或 utils.ts(TypeScript)的新文件,粘贴以下代码:

def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b
export function add(a: number, b: number): number {
  return a + b;
}

export function subtract(a: number, b: number): number {
  return a - b;
}

export function multiply(a: number, b: number): number {
  return a * b;
}

export function divide(a: number, b: number): number {
  if (b === 0) {
    throw new Error("Cannot divide by zero");
  }
  return a / b;
}

步骤 2:运行交互式示例

在与工具文件相同的目录下,创建一个名为 try_checkpointing.py(Python)或 try_checkpointing.ts(TypeScript)的新文件,粘贴以下代码。

此脚本会让 Claude 为你的工具文件添加文档注释,然后让你选择是否回退并还原原文件。

import asyncio
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    UserMessage,
    ResultMessage,
)


async def main():
    # Configure the SDK with checkpointing enabled
    # - enable_file_checkpointing: Track file changes for rewinding
    # - permission_mode: Auto-accept file edits without prompting
    # - extra_args: Required to receive user message UUIDs in the stream
    options = ClaudeAgentOptions(
        enable_file_checkpointing=True,
        permission_mode="acceptEdits",
        extra_args={"replay-user-messages": None},
    )

    checkpoint_id = None  # Store the user message UUID for rewinding
    session_id = None  # Store the session ID for resuming

    print("Running agent to add doc comments to utils.py...\n")

    # Run the agent and capture checkpoint data from the response stream
    async with ClaudeSDKClient(options) as client:
        await client.query("Add doc comments to utils.py")

        async for message in client.receive_response():
            # Capture the first user message UUID - this is our restore point
            if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
                checkpoint_id = message.uuid
            # Capture the session ID so we can resume later
            if isinstance(message, ResultMessage):
                session_id = message.session_id

    print("Done! Open utils.py to see the added doc comments.\n")

    # Ask the user if they want to rewind the changes
    if checkpoint_id and session_id:
        response = input("Rewind to remove the doc comments? (y/n): ")

        if response.lower() == "y":
            # Resume the session with an empty prompt, then rewind
            async with ClaudeSDKClient(
                ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
            ) as client:
                await client.query("")  # Empty prompt opens the connection
                async for message in client.receive_response():
                    await client.rewind_files(checkpoint_id)  # Restore files
                    break

            print(
                "\n✓ File restored! Open utils.py to verify the doc comments are gone."
            )
        else:
            print("\nKept the modified file.")


asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
import * as readline from "readline";

async function main() {
  // Configure the SDK with checkpointing enabled
  // - enableFileCheckpointing: Track file changes for rewinding
  // - permissionMode: Auto-accept file edits without prompting
  // - extraArgs: Required to receive user message UUIDs in the stream
  const opts = {
    enableFileCheckpointing: true,
    permissionMode: "acceptEdits" as const,
    extraArgs: { "replay-user-messages": null }
  };

  let sessionId: string | undefined; // Store the session ID for resuming
  let checkpointId: string | undefined; // Store the user message UUID for rewinding

  console.log("Running agent to add doc comments to utils.ts...\n");

  // Run the agent and capture checkpoint data from the response stream
  const response = query({
    prompt: "Add doc comments to utils.ts",
    options: opts
  });

  try {
    for await (const message of response) {
      // Capture the first user message UUID - this is our restore point
      if (message.type === "user" && message.uuid && !checkpointId) {
        checkpointId = message.uuid;
      }
      // Capture the session ID so we can resume later
      if ("session_id" in message) {
        sessionId = message.session_id;
      }
    }
  } catch (error) {
    // A single-shot query() throws after yielding an error result. If the
    // failure was an error result, checkpointId and sessionId were already
    // captured by the loop above; connection or process failures yield no
    // result message.
    console.error(`Session ended with an error: ${error}`);
  }

  console.log("Done! Open utils.ts to see the added doc comments.\n");

  // Ask the user if they want to rewind the changes
  if (checkpointId && sessionId) {
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout
    });

    const answer = await new Promise<string>((resolve) => {
      rl.question("Rewind to remove the doc comments? (y/n): ", resolve);
    });
    rl.close();

    if (answer.toLowerCase() === "y") {
      // Resume the session with an empty prompt, then rewind
      const rewindQuery = query({
        prompt: "", // Empty prompt opens the connection
        options: { ...opts, resume: sessionId }
      });

      for await (const msg of rewindQuery) {
        await rewindQuery.rewindFiles(checkpointId); // Restore files
        break;
      }

      console.log("\n✓ File restored! Open utils.ts to verify the doc comments are gone.");
    } else {
      console.log("\nKept the modified file.");
    }
  }
}

main();

步骤 3:运行示例

在与工具文件相同的目录下运行脚本。

提示:在运行脚本前,先用你的 IDE 或编辑器打开工具文件(utils.pyutils.ts)。你会看到 agent 添加文档注释时文件的实时变化,选择回退后又会看到文件还原为原始内容。

Python:

python try_checkpointing.py

TypeScript:

npx tsx try_checkpointing.ts

你会看到 agent 添加文档注释,然后出现是否回退的提示。如果选择是,文件会被恢复到原始状态。

限制

文件检查点存在以下限制:

限制说明
仅限 Write/Edit/NotebookEdit 工具通过 Bash 命令所做的改动不会被跟踪
子代理(subagent)编辑subagent 所做的编辑既不被跟踪也不会被恢复,除非是以 context: fork 方式在前台运行的 skill;要撤销未被跟踪的编辑需使用 git
同一会话检查点与创建它们的 session 绑定
仅文件内容目录的创建、移动或删除不会因回退而被撤销
本地文件远程或网络文件不会被跟踪

故障排查

Checkpointing 选项无法识别

如果 enableFileCheckpointingrewindFiles() 不可用,可能是 SDK 版本过旧。

解决方案:升级到最新版本 SDK:

  • Python: pip install --upgrade claude-agent-sdk
  • TypeScript: npm install @anthropic-ai/claude-agent-sdk@latest

用户消息没有 UUID

如果 message.uuidundefined 或缺失,说明你没有接收到 checkpoint UUID。

原因:未设置 replay-user-messages 选项。

解决方案:在 options 中加入 extra_args={"replay-user-messages": None}(Python)或 extraArgs: { 'replay-user-messages': null }(TypeScript)。

出现「No file checkpoint found for this message」错误

当指定的用户消息 UUID 不存在对应的检查点数据时会出现此错误。

常见原因

  • 原始 session 未启用文件检查点(enable_file_checkpointingenableFileCheckpointing 未设置为 true
  • 在尝试 resume 并回退之前,session 未正常完成

解决方案:确保原始 session 上设置了 enable_file_checkpointing=True(Python)或 enableFileCheckpointing: true(TypeScript),并按照示例中的模式操作:捕获第一条用户消息的 UUID、让 session 完整结束、然后用空 prompt resume 并只调用一次 rewindFiles()

出现「File rewinding is not enabled」错误

当你在未启用 checkpointing 的情况下尝试非交互式回退时会出现此错误,包括:直接用 claude -p 配合 --rewind-files 运行裸 CLI,或运行一个(包括已 resume 的)options 未启用 checkpointing 的 SDK session。SDK 只有在执行回退的 session 上启用了 enable_file_checkpointing(Python)或 enableFileCheckpointing(TypeScript)时,才会在内部自动设置 CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING 环境变量;裸 CLI 永远不会自动设置该变量。

解决方案:对于裸 CLI,运行命令时手动设置环境变量:

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

对于 SDK,在执行回退的 resume session 上设置 enable_file_checkpointing=True(Python)或 enableFileCheckpointing: true(TypeScript),如本文示例所示。

出现「ProcessTransport is not ready for writing」错误

当你在遍历完响应流之后才调用 rewindFiles()rewind_files() 时会出现此错误。循环结束后,与 CLI 进程的连接就会关闭。

解决方案:用空 prompt resume 该 session,然后在新的 query 上调用回退:

# Resume session with empty prompt, then rewind
async with ClaudeSDKClient(
    ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
) as client:
    await client.query("")
    async for message in client.receive_response():
        if checkpoint_id:
            await client.rewind_files(checkpoint_id)
        break
// Resume session with empty prompt, then rewind
const rewindQuery = query({
  prompt: "",
  options: { ...opts, resume: sessionId }
});

try {
  for await (const msg of rewindQuery) {
    if (checkpointId) {
      await rewindQuery.rewindFiles(checkpointId);
    }
    break;
  }
} catch (error) {
  // An error here means the rewind didn't complete, for example the checkpoint
  // wasn't found or the session couldn't be resumed.
  console.error(`Rewind session ended with an error: ${error}`);
}

下一步

  • Sessions:了解如何 resume session,这是响应流结束后进行回退的前提。涵盖 session ID、恢复会话、会话分叉(forking)等内容。
  • Permissions:配置 Claude 可使用的工具以及文件修改的审批方式。如果你想更精细地控制编辑发生的时机,这会很有用。
  • TypeScript SDK 参考:完整 API 参考,包括 query() 的所有选项及 rewindFiles() 方法。
  • Python SDK 参考:完整 API 参考,包括 ClaudeAgentOptions 的所有选项及 rewind_files() 方法。