Skip to content

Commit 53482d8

Browse files
noahzwebenclaudeashwin-ant
authored
feat: add file checkpointing and rewind_files support (#395)
## Summary - Add `enable_file_checkpointing` option to `ClaudeAgentOptions` - Add `rewind_files(user_message_id)` method to `ClaudeSDKClient` and `Query` - Add `SDKControlRewindFilesRequest` type for the control protocol - Set `CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING` env var when enabled This adds Python SDK support for the file rewind feature from claude-cli-internal PR #11265. ## Test plan - [x] Verified imports work correctly - [x] Verified linting passes (`ruff check`) - [x] Verified existing tests still pass (106 passed, pre-existing failures unrelated to this change) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Ashwin Bhat <[email protected]>
1 parent 4acfcc2 commit 53482d8

File tree

4 files changed

+56
-0
lines changed

4 files changed

+56
-0
lines changed

src/claude_agent_sdk/_internal/query.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,21 @@ async def set_model(self, model: str | None) -> None:
539539
}
540540
)
541541

542+
async def rewind_files(self, user_message_id: str) -> None:
543+
"""Rewind tracked files to their state at a specific user message.
544+
545+
Requires file checkpointing to be enabled via the `enable_file_checkpointing` option.
546+
547+
Args:
548+
user_message_id: UUID of the user message to rewind to
549+
"""
550+
await self._send_control_request(
551+
{
552+
"subtype": "rewind_files",
553+
"user_message_id": user_message_id,
554+
}
555+
)
556+
542557
async def stream_input(self, stream: AsyncIterable[dict[str, Any]]) -> None:
543558
"""Stream input messages to transport.
544559

src/claude_agent_sdk/_internal/transport/subprocess_cli.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,10 @@ async def connect(self) -> None:
384384
"CLAUDE_AGENT_SDK_VERSION": __version__,
385385
}
386386

387+
# Enable file checkpointing if requested
388+
if self._options.enable_file_checkpointing:
389+
process_env["CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING"] = "true"
390+
387391
if self._cwd:
388392
process_env["PWD"] = self._cwd
389393

src/claude_agent_sdk/client.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,33 @@ async def set_model(self, model: str | None = None) -> None:
261261
raise CLIConnectionError("Not connected. Call connect() first.")
262262
await self._query.set_model(model)
263263

264+
async def rewind_files(self, user_message_id: str) -> None:
265+
"""Rewind tracked files to their state at a specific user message.
266+
267+
Requires file checkpointing to be enabled via the `enable_file_checkpointing` option
268+
when creating the ClaudeSDKClient.
269+
270+
Args:
271+
user_message_id: UUID of the user message to rewind to. This should be
272+
the `uuid` field from a `UserMessage` received during the conversation.
273+
274+
Example:
275+
```python
276+
options = ClaudeAgentOptions(enable_file_checkpointing=True)
277+
async with ClaudeSDKClient(options) as client:
278+
await client.query("Make some changes to my files")
279+
async for msg in client.receive_response():
280+
if isinstance(msg, UserMessage):
281+
checkpoint_id = msg.uuid # Save this for later
282+
283+
# Later, rewind to that point
284+
await client.rewind_files(checkpoint_id)
285+
```
286+
"""
287+
if not self._query:
288+
raise CLIConnectionError("Not connected. Call connect() first.")
289+
await self._query.rewind_files(user_message_id)
290+
264291
async def get_server_info(self) -> dict[str, Any] | None:
265292
"""Get server initialization info including available commands and output styles.
266293

src/claude_agent_sdk/types.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,10 @@ class ClaudeAgentOptions:
673673
# Output format for structured outputs (matches Messages API structure)
674674
# Example: {"type": "json_schema", "schema": {"type": "object", "properties": {...}}}
675675
output_format: dict[str, Any] | None = None
676+
# Enable file checkpointing to track file changes during the session.
677+
# When enabled, files can be rewound to their state at any user message
678+
# using `ClaudeSDKClient.rewind_files()`.
679+
enable_file_checkpointing: bool = False
676680

677681

678682
# SDK Control Protocol
@@ -713,6 +717,11 @@ class SDKControlMcpMessageRequest(TypedDict):
713717
message: Any
714718

715719

720+
class SDKControlRewindFilesRequest(TypedDict):
721+
subtype: Literal["rewind_files"]
722+
user_message_id: str
723+
724+
716725
class SDKControlRequest(TypedDict):
717726
type: Literal["control_request"]
718727
request_id: str
@@ -723,6 +732,7 @@ class SDKControlRequest(TypedDict):
723732
| SDKControlSetPermissionModeRequest
724733
| SDKHookCallbackRequest
725734
| SDKControlMcpMessageRequest
735+
| SDKControlRewindFilesRequest
726736
)
727737

728738

0 commit comments

Comments
 (0)