From 0e8753f0db99b0b59a929c6e301e672e9e9e9da3 Mon Sep 17 00:00:00 2001 From: Noah Zweben MacBook Date: Mon, 8 Dec 2025 12:56:28 -0800 Subject: [PATCH] feat: add file checkpointing and rewind_files support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the file rewind feature from claude-cli-internal PR #11265: - Add `enable_file_checkpointing` option to ClaudeAgentOptions - Add `rewind_files(user_message_id)` method to ClaudeSDKClient - Add `SDKControlRewindFilesRequest` type for the control protocol - Set `CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING` env var when enabled This allows SDK users to enable file checkpointing and rewind tracked files to their state at any previous user message during a session. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/claude_agent_sdk/_internal/query.py | 15 +++++++++++ .../_internal/transport/subprocess_cli.py | 4 +++ src/claude_agent_sdk/client.py | 27 +++++++++++++++++++ src/claude_agent_sdk/types.py | 10 +++++++ 4 files changed, 56 insertions(+) diff --git a/src/claude_agent_sdk/_internal/query.py b/src/claude_agent_sdk/_internal/query.py index 8f0ac19..a49773c 100644 --- a/src/claude_agent_sdk/_internal/query.py +++ b/src/claude_agent_sdk/_internal/query.py @@ -539,6 +539,21 @@ class Query: } ) + async def rewind_files(self, user_message_id: str) -> None: + """Rewind tracked files to their state at a specific user message. + + Requires file checkpointing to be enabled via the `enable_file_checkpointing` option. + + Args: + user_message_id: UUID of the user message to rewind to + """ + await self._send_control_request( + { + "subtype": "rewind_code", + "user_message_id": user_message_id, + } + ) + async def stream_input(self, stream: AsyncIterable[dict[str, Any]]) -> None: """Stream input messages to transport. diff --git a/src/claude_agent_sdk/_internal/transport/subprocess_cli.py b/src/claude_agent_sdk/_internal/transport/subprocess_cli.py index c7c7420..a4882db 100644 --- a/src/claude_agent_sdk/_internal/transport/subprocess_cli.py +++ b/src/claude_agent_sdk/_internal/transport/subprocess_cli.py @@ -384,6 +384,10 @@ class SubprocessCLITransport(Transport): "CLAUDE_AGENT_SDK_VERSION": __version__, } + # Enable file checkpointing if requested + if self._options.enable_file_checkpointing: + process_env["CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING"] = "true" + if self._cwd: process_env["PWD"] = self._cwd diff --git a/src/claude_agent_sdk/client.py b/src/claude_agent_sdk/client.py index 742d7d6..2f74260 100644 --- a/src/claude_agent_sdk/client.py +++ b/src/claude_agent_sdk/client.py @@ -261,6 +261,33 @@ class ClaudeSDKClient: raise CLIConnectionError("Not connected. Call connect() first.") await self._query.set_model(model) + async def rewind_files(self, user_message_id: str) -> None: + """Rewind tracked files to their state at a specific user message. + + Requires file checkpointing to be enabled via the `enable_file_checkpointing` option + when creating the ClaudeSDKClient. + + Args: + user_message_id: UUID of the user message to rewind to. This should be + the `uuid` field from a `UserMessage` received during the conversation. + + Example: + ```python + options = ClaudeAgentOptions(enable_file_checkpointing=True) + async with ClaudeSDKClient(options) as client: + await client.query("Make some changes to my files") + async for msg in client.receive_response(): + if isinstance(msg, UserMessage): + checkpoint_id = msg.uuid # Save this for later + + # Later, rewind to that point + await client.rewind_files(checkpoint_id) + ``` + """ + if not self._query: + raise CLIConnectionError("Not connected. Call connect() first.") + await self._query.rewind_files(user_message_id) + async def get_server_info(self) -> dict[str, Any] | None: """Get server initialization info including available commands and output styles. diff --git a/src/claude_agent_sdk/types.py b/src/claude_agent_sdk/types.py index fa6ca35..9a7accf 100644 --- a/src/claude_agent_sdk/types.py +++ b/src/claude_agent_sdk/types.py @@ -673,6 +673,10 @@ class ClaudeAgentOptions: # Output format for structured outputs (matches Messages API structure) # Example: {"type": "json_schema", "schema": {"type": "object", "properties": {...}}} output_format: dict[str, Any] | None = None + # Enable file checkpointing to track file changes during the session. + # When enabled, files can be rewound to their state at any user message + # using `ClaudeSDKClient.rewind_files()`. + enable_file_checkpointing: bool = False # SDK Control Protocol @@ -713,6 +717,11 @@ class SDKControlMcpMessageRequest(TypedDict): message: Any +class SDKControlRewindFilesRequest(TypedDict): + subtype: Literal["rewind_code"] + user_message_id: str + + class SDKControlRequest(TypedDict): type: Literal["control_request"] request_id: str @@ -723,6 +732,7 @@ class SDKControlRequest(TypedDict): | SDKControlSetPermissionModeRequest | SDKHookCallbackRequest | SDKControlMcpMessageRequest + | SDKControlRewindFilesRequest )