1> ## Documentation Index
2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
3> Use this file to discover all available pages before exploring further.
4
5# Rewind file changes with checkpointing
6
7> Track file changes during agent sessions and restore files to any previous state
8
9File checkpointing tracks file modifications made through the Write, Edit, and NotebookEdit tools during an agent session, allowing you to rewind files to any previous state. Want to try it out? Jump to the [interactive example](#try-it-out).
10
11With checkpointing, you can:
12
13* **Undo unwanted changes** by restoring files to a known good state
14* **Explore alternatives** by restoring to a checkpoint and trying a different approach
15* **Recover from errors** when the agent makes incorrect modifications
16
17<Warning>
18 Only changes made through the Write, Edit, and NotebookEdit tools are tracked. Changes made through Bash commands (like `echo > file.txt` or `sed -i`) are not captured by the checkpoint system.
19</Warning>
20
21## How checkpointing works
22
23When you enable file checkpointing, the SDK creates backups of files before modifying them through the Write, Edit, or NotebookEdit tools. User messages in the response stream include a checkpoint UUID that you can use as a restore point.
24
25Checkpoint works with these built-in tools that the agent uses to modify files:
26
27| Tool | Description |
28| ------------ | ------------------------------------------------------------------ |
29| Write | Creates a new file or overwrites an existing file with new content |
30| Edit | Makes targeted edits to specific parts of an existing file |
31| NotebookEdit | Modifies cells in Jupyter notebooks (`.ipynb` files) |
32
33<Note>
34 File rewinding restores files on disk to a previous state. It does not rewind the conversation itself. The conversation history and context remain intact after calling `rewindFiles()` (TypeScript) or `rewind_files()` (Python).
35</Note>
36
37The checkpoint system tracks:
38
39* Files created during the session
40* Files modified during the session
41* The original content of modified files
42
43When you rewind to a checkpoint, created files are deleted and modified files are restored to their content at that point.
44
45## Implement checkpointing
46
47To use file checkpointing, enable it in your options, capture checkpoint UUIDs from the response stream, then call `rewindFiles()` (TypeScript) or `rewind_files()` (Python) when you need to restore.
48
49The following example shows the complete flow: enable checkpointing, capture the checkpoint UUID and session ID from the response stream, then resume the session later to rewind files. Each step is explained in detail below. The examples in this section use the prompt "Refactor the authentication module". Run them in a project that contains an authentication module, or change the prompt to name files that exist in your project, so you can watch files change and see the rewind restore them.
50
51<CodeGroup>
52 ```python Python theme={null}
53 import asyncio
54 from claude_agent_sdk import (
55 ClaudeSDKClient,
56 ClaudeAgentOptions,
57 UserMessage,
58 ResultMessage,
59 )
60
61
62 async def main():
63 # Step 1: Enable checkpointing
64 options = ClaudeAgentOptions(
65 enable_file_checkpointing=True,
66 permission_mode="acceptEdits", # Auto-accept file edits without prompting
67 extra_args={
68 "replay-user-messages": None
69 }, # Required to receive checkpoint UUIDs in the response stream
70 )
71
72 checkpoint_id = None
73 session_id = None
74
75 # Run the query and capture checkpoint UUID and session ID
76 async with ClaudeSDKClient(options) as client:
77 await client.query("Refactor the authentication module")
78
79 # Step 2: Capture checkpoint UUID from the first user message
80 async for message in client.receive_response():
81 if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
82 checkpoint_id = message.uuid
83 if isinstance(message, ResultMessage) and not session_id:
84 session_id = message.session_id
85
86 # Step 3: Later, rewind by resuming the session with an empty prompt
87 if checkpoint_id and session_id:
88 async with ClaudeSDKClient(
89 ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
90 ) as client:
91 await client.query("") # Empty prompt to open the connection
92 async for message in client.receive_response():
93 await client.rewind_files(checkpoint_id)
94 break
95 print(f"Rewound to checkpoint: {checkpoint_id}")
96
97
98 asyncio.run(main())
99 ```
100
101 ```typescript TypeScript theme={null}
102 import { query } from "@anthropic-ai/claude-agent-sdk";
103
104 async function main() {
105 // Step 1: Enable checkpointing
106 const opts = {
107 enableFileCheckpointing: true,
108 permissionMode: "acceptEdits" as const, // Auto-accept file edits without prompting
109 extraArgs: { "replay-user-messages": null } // Required to receive checkpoint UUIDs in the response stream
110 };
111
112 const response = query({
113 prompt: "Refactor the authentication module",
114 options: opts
115 });
116
117 let checkpointId: string | undefined;
118 let sessionId: string | undefined;
119
120 // Step 2: Capture checkpoint UUID from the first user message
121 for await (const message of response) {
122 if (message.type === "user" && message.uuid && !checkpointId) {
123 checkpointId = message.uuid;
124 }
125 if ("session_id" in message && !sessionId) {
126 sessionId = message.session_id;
127 }
128 }
129
130 // Step 3: Later, rewind by resuming the session with an empty prompt
131 if (checkpointId && sessionId) {
132 const rewindQuery = query({
133 prompt: "", // Empty prompt to open the connection
134 options: { ...opts, resume: sessionId }
135 });
136
137 for await (const msg of rewindQuery) {
138 await rewindQuery.rewindFiles(checkpointId);
139 break;
140 }
141 console.log(`Rewound to checkpoint: ${checkpointId}`);
142 }
143 }
144
145 main();
146 ```
147</CodeGroup>
148
149<Steps>
150 <Step title="Enable checkpointing">
151 Configure your SDK options to enable checkpointing and receive checkpoint UUIDs:
152
153 | Option | Python | TypeScript | Description |
154 | ------------------------ | ------------------------------------------- | --------------------------------------------- | ------------------------------------------------ |
155 | Enable checkpointing | `enable_file_checkpointing=True` | `enableFileCheckpointing: true` | Tracks file changes for rewinding |
156 | Receive checkpoint UUIDs | `extra_args={"replay-user-messages": None}` | `extraArgs: { 'replay-user-messages': null }` | Required to get user message UUIDs in the stream |
157
158 <CodeGroup>
159 ```python Python theme={null}
160 options = ClaudeAgentOptions(
161 enable_file_checkpointing=True,
162 permission_mode="acceptEdits",
163 extra_args={"replay-user-messages": None},
164 )
165
166 async with ClaudeSDKClient(options) as client:
167 await client.query("Refactor the authentication module")
168 ```
169
170 ```typescript TypeScript theme={null}
171 const response = query({
172 prompt: "Refactor the authentication module",
173 options: {
174 enableFileCheckpointing: true,
175 permissionMode: "acceptEdits" as const,
176 extraArgs: { "replay-user-messages": null }
177 }
178 });
179 ```
180 </CodeGroup>
181 </Step>
182
183 <Step title="Capture checkpoint UUID and session ID">
184 With the `replay-user-messages` option set (shown above), each user message in the response stream has a UUID that serves as a checkpoint.
185
186 For most use cases, capture the first user message UUID (`message.uuid`); rewinding to it restores all files to their original state. To store multiple checkpoints and rewind to intermediate states, see [Multiple restore points](#multiple-restore-points).
187
188 Capturing the session ID (`message.session_id`) is optional; you only need it if you want to rewind later, after the stream completes. If you're calling `rewindFiles()` immediately while still processing messages (as the example in [Checkpoint before risky operations](#checkpoint-before-risky-operations) does), you can skip capturing the session ID.
189
190 <CodeGroup>
191 ```python Python theme={null}
192 checkpoint_id = None
193 session_id = None
194
195 async for message in client.receive_response():
196 # Update checkpoint on each user message (keeps the latest)
197 if isinstance(message, UserMessage) and message.uuid:
198 checkpoint_id = message.uuid
199 # Capture session ID from the result message
200 if isinstance(message, ResultMessage):
201 session_id = message.session_id
202 ```
203
204 ```typescript TypeScript theme={null}
205 let checkpointId: string | undefined;
206 let sessionId: string | undefined;
207
208 for await (const message of response) {
209 // Update checkpoint on each user message (keeps the latest)
210 if (message.type === "user" && message.uuid) {
211 checkpointId = message.uuid;
212 }
213 // Capture session ID from any message that has it
214 if ("session_id" in message) {
215 sessionId = message.session_id;
216 }
217 }
218 ```
219 </CodeGroup>
220 </Step>
221
222 <Step title="Rewind files">
223 To rewind after the stream completes, resume the session with an empty prompt and call `rewind_files()` (Python) or `rewindFiles()` (TypeScript) with your checkpoint UUID. You can also rewind during the stream; see [Checkpoint before risky operations](#checkpoint-before-risky-operations) for that pattern.
224
225 <CodeGroup>
226 ```python Python theme={null}
227 async with ClaudeSDKClient(
228 ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
229 ) as client:
230 await client.query("") # Empty prompt to open the connection
231 async for message in client.receive_response():
232 await client.rewind_files(checkpoint_id)
233 break
234 ```
235
236 ```typescript TypeScript theme={null}
237 const rewindQuery = query({
238 prompt: "", // Empty prompt to open the connection
239 options: { ...opts, resume: sessionId }
240 });
241
242 for await (const msg of rewindQuery) {
243 await rewindQuery.rewindFiles(checkpointId);
244 break;
245 }
246 ```
247 </CodeGroup>
248
249 If you capture the session ID and checkpoint ID, you can also rewind from the CLI. This command requires the `claude` executable, which comes from [installing Claude Code](/en/setup) and is not installed by the SDK package:
250
251 ```bash theme={null}
252 claude -p --resume <session-id> --rewind-files <checkpoint-uuid>
253 ```
254 </Step>
255</Steps>
256
257## Common patterns
258
259These patterns show different ways to capture and use checkpoint UUIDs depending on your use case.
260
261### Checkpoint before risky operations
262
263This pattern keeps only the most recent checkpoint UUID, updating it before each agent turn. If something goes wrong during processing, you can immediately rewind to the last safe state and break out of the loop.
264
265<CodeGroup>
266 ```python Python theme={null}
267 import asyncio
268 from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage
269
270
271 async def main():
272 options = ClaudeAgentOptions(
273 enable_file_checkpointing=True,
274 permission_mode="acceptEdits",
275 extra_args={"replay-user-messages": None},
276 )
277
278 safe_checkpoint = None
279
280 async with ClaudeSDKClient(options) as client:
281 await client.query("Refactor the authentication module")
282
283 async for message in client.receive_response():
284 # Update checkpoint before each agent turn starts
285 # This overwrites the previous checkpoint. Only keep the latest
286 if isinstance(message, UserMessage) and message.uuid:
287 safe_checkpoint = message.uuid
288
289 # Decide when to revert based on your own logic
290 # For example: error detection, validation failure, or user input
291 if your_revert_condition and safe_checkpoint:
292 await client.rewind_files(safe_checkpoint)
293 # Exit the loop after rewinding, files are restored
294 break
295
296
297 asyncio.run(main())
298 ```
299
300 ```typescript TypeScript theme={null}
301 import { query } from "@anthropic-ai/claude-agent-sdk";
302
303 async function main() {
304 const response = query({
305 prompt: "Refactor the authentication module",
306 options: {
307 enableFileCheckpointing: true,
308 permissionMode: "acceptEdits" as const,
309 extraArgs: { "replay-user-messages": null }
310 }
311 });
312
313 let safeCheckpoint: string | undefined;
314
315 for await (const message of response) {
316 // Update checkpoint before each agent turn starts
317 // This overwrites the previous checkpoint. Only keep the latest
318 if (message.type === "user" && message.uuid) {
319 safeCheckpoint = message.uuid;
320 }
321
322 // Decide when to revert based on your own logic
323 // For example: error detection, validation failure, or user input
324 if (yourRevertCondition && safeCheckpoint) {
325 await response.rewindFiles(safeCheckpoint);
326 // Exit the loop after rewinding, files are restored
327 break;
328 }
329 }
330 }
331
332 main();
333 ```
334</CodeGroup>
335
336### Multiple restore points
337
338If Claude makes changes across multiple turns, you might want to rewind to a specific point rather than all the way back. For example, if Claude refactors a file in turn one and adds tests in turn two, you might want to keep the refactor but undo the tests.
339
340This pattern stores all checkpoint UUIDs in an array with metadata. After the session completes, you can rewind to any previous checkpoint:
341
342<CodeGroup>
343 ```python Python theme={null}
344 import asyncio
345 from dataclasses import dataclass
346 from datetime import datetime
347 from claude_agent_sdk import (
348 ClaudeSDKClient,
349 ClaudeAgentOptions,
350 UserMessage,
351 ResultMessage,
352 )
353
354
355 # Store checkpoint metadata for better tracking
356 @dataclass
357 class Checkpoint:
358 id: str
359 description: str
360 timestamp: datetime
361
362
363 async def main():
364 options = ClaudeAgentOptions(
365 enable_file_checkpointing=True,
366 permission_mode="acceptEdits",
367 extra_args={"replay-user-messages": None},
368 )
369
370 checkpoints = []
371 session_id = None
372
373 async with ClaudeSDKClient(options) as client:
374 await client.query("Refactor the authentication module")
375
376 async for message in client.receive_response():
377 if isinstance(message, UserMessage) and message.uuid:
378 checkpoints.append(
379 Checkpoint(
380 id=message.uuid,
381 description=f"After turn {len(checkpoints) + 1}",
382 timestamp=datetime.now(),
383 )
384 )
385 if isinstance(message, ResultMessage) and not session_id:
386 session_id = message.session_id
387
388 # Later: rewind to any checkpoint by resuming the session
389 if checkpoints and session_id:
390 target = checkpoints[0] # Pick any checkpoint
391 async with ClaudeSDKClient(
392 ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
393 ) as client:
394 await client.query("") # Empty prompt to open the connection
395 async for message in client.receive_response():
396 await client.rewind_files(target.id)
397 break
398 print(f"Rewound to: {target.description}")
399
400
401 asyncio.run(main())
402 ```
403
404 ```typescript TypeScript theme={null}
405 import { query } from "@anthropic-ai/claude-agent-sdk";
406
407 // Store checkpoint metadata for better tracking
408 interface Checkpoint {
409 id: string;
410 description: string;
411 timestamp: Date;
412 }
413
414 async function main() {
415 const opts = {
416 enableFileCheckpointing: true,
417 permissionMode: "acceptEdits" as const,
418 extraArgs: { "replay-user-messages": null }
419 };
420
421 const response = query({
422 prompt: "Refactor the authentication module",
423 options: opts
424 });
425
426 const checkpoints: Checkpoint[] = [];
427 let sessionId: string | undefined;
428
429 for await (const message of response) {
430 if (message.type === "user" && message.uuid) {
431 checkpoints.push({
432 id: message.uuid,
433 description: `After turn ${checkpoints.length + 1}`,
434 timestamp: new Date()
435 });
436 }
437 if ("session_id" in message && !sessionId) {
438 sessionId = message.session_id;
439 }
440 }
441
442 // Later: rewind to any checkpoint by resuming the session
443 if (checkpoints.length > 0 && sessionId) {
444 const target = checkpoints[0]; // Pick any checkpoint
445 const rewindQuery = query({
446 prompt: "", // Empty prompt to open the connection
447 options: { ...opts, resume: sessionId }
448 });
449
450 for await (const msg of rewindQuery) {
451 await rewindQuery.rewindFiles(target.id);
452 break;
453 }
454 console.log(`Rewound to: ${target.description}`);
455 }
456 }
457
458 main();
459 ```
460</CodeGroup>
461
462## Try it out
463
464This complete example creates a small utility file, has the agent add documentation comments, shows you the changes, then asks if you want to rewind.
465
466Before you begin, make sure you have the [Claude Agent SDK installed](/en/agent-sdk/quickstart).
467
468<Steps>
469 <Step title="Create a test file">
470 Create a new file called `utils.py` (Python) or `utils.ts` (TypeScript) and paste the following code:
471
472 <CodeGroup>
473 ```python utils.py theme={null}
474 def add(a, b):
475 return a + b
476
477
478 def subtract(a, b):
479 return a - b
480
481
482 def multiply(a, b):
483 return a * b
484
485
486 def divide(a, b):
487 if b == 0:
488 raise ValueError("Cannot divide by zero")
489 return a / b
490 ```
491
492 ```typescript utils.ts theme={null}
493 export function add(a: number, b: number): number {
494 return a + b;
495 }
496
497 export function subtract(a: number, b: number): number {
498 return a - b;
499 }
500
501 export function multiply(a: number, b: number): number {
502 return a * b;
503 }
504
505 export function divide(a: number, b: number): number {
506 if (b === 0) {
507 throw new Error("Cannot divide by zero");
508 }
509 return a / b;
510 }
511 ```
512 </CodeGroup>
513 </Step>
514
515 <Step title="Run the interactive example">
516 Create a new file called `try_checkpointing.py` (Python) or `try_checkpointing.ts` (TypeScript) in the same directory as your utility file, and paste the following code.
517
518 This script asks Claude to add doc comments to your utility file, then gives you the option to rewind and restore the original.
519
520 <CodeGroup>
521 ```python try_checkpointing.py theme={null}
522 import asyncio
523 from claude_agent_sdk import (
524 ClaudeSDKClient,
525 ClaudeAgentOptions,
526 UserMessage,
527 ResultMessage,
528 )
529
530
531 async def main():
532 # Configure the SDK with checkpointing enabled
533 # - enable_file_checkpointing: Track file changes for rewinding
534 # - permission_mode: Auto-accept file edits without prompting
535 # - extra_args: Required to receive user message UUIDs in the stream
536 options = ClaudeAgentOptions(
537 enable_file_checkpointing=True,
538 permission_mode="acceptEdits",
539 extra_args={"replay-user-messages": None},
540 )
541
542 checkpoint_id = None # Store the user message UUID for rewinding
543 session_id = None # Store the session ID for resuming
544
545 print("Running agent to add doc comments to utils.py...\n")
546
547 # Run the agent and capture checkpoint data from the response stream
548 async with ClaudeSDKClient(options) as client:
549 await client.query("Add doc comments to utils.py")
550
551 async for message in client.receive_response():
552 # Capture the first user message UUID - this is our restore point
553 if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
554 checkpoint_id = message.uuid
555 # Capture the session ID so we can resume later
556 if isinstance(message, ResultMessage):
557 session_id = message.session_id
558
559 print("Done! Open utils.py to see the added doc comments.\n")
560
561 # Ask the user if they want to rewind the changes
562 if checkpoint_id and session_id:
563 response = input("Rewind to remove the doc comments? (y/n): ")
564
565 if response.lower() == "y":
566 # Resume the session with an empty prompt, then rewind
567 async with ClaudeSDKClient(
568 ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
569 ) as client:
570 await client.query("") # Empty prompt opens the connection
571 async for message in client.receive_response():
572 await client.rewind_files(checkpoint_id) # Restore files
573 break
574
575 print(
576 "\n✓ File restored! Open utils.py to verify the doc comments are gone."
577 )
578 else:
579 print("\nKept the modified file.")
580
581
582 asyncio.run(main())
583 ```
584
585 ```typescript try_checkpointing.ts theme={null}
586 import { query } from "@anthropic-ai/claude-agent-sdk";
587 import * as readline from "readline";
588
589 async function main() {
590 // Configure the SDK with checkpointing enabled
591 // - enableFileCheckpointing: Track file changes for rewinding
592 // - permissionMode: Auto-accept file edits without prompting
593 // - extraArgs: Required to receive user message UUIDs in the stream
594 const opts = {
595 enableFileCheckpointing: true,
596 permissionMode: "acceptEdits" as const,
597 extraArgs: { "replay-user-messages": null }
598 };
599
600 let sessionId: string | undefined; // Store the session ID for resuming
601 let checkpointId: string | undefined; // Store the user message UUID for rewinding
602
603 console.log("Running agent to add doc comments to utils.ts...\n");
604
605 // Run the agent and capture checkpoint data from the response stream
606 const response = query({
607 prompt: "Add doc comments to utils.ts",
608 options: opts
609 });
610
611 for await (const message of response) {
612 // Capture the first user message UUID - this is our restore point
613 if (message.type === "user" && message.uuid && !checkpointId) {
614 checkpointId = message.uuid;
615 }
616 // Capture the session ID so we can resume later
617 if ("session_id" in message) {
618 sessionId = message.session_id;
619 }
620 }
621
622 console.log("Done! Open utils.ts to see the added doc comments.\n");
623
624 // Ask the user if they want to rewind the changes
625 if (checkpointId && sessionId) {
626 const rl = readline.createInterface({
627 input: process.stdin,
628 output: process.stdout
629 });
630
631 const answer = await new Promise<string>((resolve) => {
632 rl.question("Rewind to remove the doc comments? (y/n): ", resolve);
633 });
634 rl.close();
635
636 if (answer.toLowerCase() === "y") {
637 // Resume the session with an empty prompt, then rewind
638 const rewindQuery = query({
639 prompt: "", // Empty prompt opens the connection
640 options: { ...opts, resume: sessionId }
641 });
642
643 for await (const msg of rewindQuery) {
644 await rewindQuery.rewindFiles(checkpointId); // Restore files
645 break;
646 }
647
648 console.log("\n✓ File restored! Open utils.ts to verify the doc comments are gone.");
649 } else {
650 console.log("\nKept the modified file.");
651 }
652 }
653 }
654
655 main();
656 ```
657 </CodeGroup>
658
659 This example demonstrates the complete checkpointing workflow:
660
661 1. **Enable checkpointing**: configure the SDK with `enable_file_checkpointing=True` and `permission_mode="acceptEdits"` to auto-approve file edits
662 2. **Capture checkpoint data**: as the agent runs, store the first user message UUID (your restore point) and the session ID
663 3. **Prompt for rewind**: after the agent finishes, check your utility file to see the doc comments, then decide if you want to undo the changes
664 4. **Resume and rewind**: if yes, resume the session with an empty prompt and call `rewind_files()` to restore the original file
665 </Step>
666
667 <Step title="Run the example">
668 Run the script from the same directory as your utility file.
669
670 <Tip>
671 Open your utility file (`utils.py` or `utils.ts`) in your IDE or editor before running the script. You'll see the file update in real-time as the agent adds doc comments, then revert back to the original when you choose to rewind.
672 </Tip>
673
674 <Tabs>
675 <Tab title="Python">
676 ```bash theme={null}
677 python try_checkpointing.py
678 ```
679 </Tab>
680
681 <Tab title="TypeScript">
682 ```bash theme={null}
683 npx tsx try_checkpointing.ts
684 ```
685 </Tab>
686 </Tabs>
687
688 You'll see the agent add doc comments, then a prompt asking if you want to rewind. If you choose yes, the file is restored to its original state.
689 </Step>
690</Steps>
691
692## Limitations
693
694File checkpointing has the following limitations:
695
696| Limitation | Description |
697| ---------------------------------- | -------------------------------------------------------------------- |
698| Write/Edit/NotebookEdit tools only | Changes made through Bash commands are not tracked |
699| Same session | Checkpoints are tied to the session that created them |
700| File content only | Creating, moving, or deleting directories is not undone by rewinding |
701| Local files | Remote or network files are not tracked |
702
703## Troubleshooting
704
705### Checkpointing options not recognized
706
707If `enableFileCheckpointing` or `rewindFiles()` isn't available, you may be on an older SDK version.
708
709**Solution**: Update to the latest SDK version:
710
711* **Python**: `pip install --upgrade claude-agent-sdk`
712* **TypeScript**: `npm install @anthropic-ai/claude-agent-sdk@latest`
713
714### User messages don't have UUIDs
715
716If `message.uuid` is `undefined` or missing, you're not receiving checkpoint UUIDs.
717
718**Cause**: The `replay-user-messages` option isn't set.
719
720**Solution**: Add `extra_args={"replay-user-messages": None}` (Python) or `extraArgs: { 'replay-user-messages': null }` (TypeScript) to your options.
721
722### "No file checkpoint found for message" error
723
724This error occurs when the checkpoint data doesn't exist for the specified user message UUID.
725
726**Common causes**:
727
728* File checkpointing was not enabled on the original session (`enable_file_checkpointing` or `enableFileCheckpointing` was not set to `true`)
729* The session wasn't properly completed before attempting to resume and rewind
730
731**Solution**: Ensure `enable_file_checkpointing=True` (Python) or `enableFileCheckpointing: true` (TypeScript) was set on the original session, then use the pattern shown in the examples: capture the first user message UUID, complete the session fully, then resume with an empty prompt and call `rewindFiles()` once.
732
733### "ProcessTransport is not ready for writing" error
734
735This error occurs when you call `rewindFiles()` or `rewind_files()` after you've finished iterating through the response. The connection to the CLI process closes when the loop completes.
736
737**Solution**: Resume the session with an empty prompt, then call rewind on the new query:
738
739<CodeGroup>
740 ```python Python theme={null}
741 # Resume session with empty prompt, then rewind
742 async with ClaudeSDKClient(
743 ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
744 ) as client:
745 await client.query("")
746 async for message in client.receive_response():
747 await client.rewind_files(checkpoint_id)
748 break
749 ```
750
751 ```typescript TypeScript theme={null}
752 // Resume session with empty prompt, then rewind
753 const rewindQuery = query({
754 prompt: "",
755 options: { ...opts, resume: sessionId }
756 });
757
758 for await (const msg of rewindQuery) {
759 await rewindQuery.rewindFiles(checkpointId);
760 break;
761 }
762 ```
763</CodeGroup>
764
765## Next steps
766
767* **[Sessions](/en/agent-sdk/sessions)**: learn how to resume sessions, which is required for rewinding after the stream completes. Covers session IDs, resuming conversations, and session forking.
768* **[Permissions](/en/agent-sdk/permissions)**: configure which tools Claude can use and how file modifications are approved. Useful if you want more control over when edits happen.
769* **[TypeScript SDK reference](/en/agent-sdk/typescript)**: complete API reference including all options for `query()` and the `rewindFiles()` method.
770* **[Python SDK reference](/en/agent-sdk/python)**: complete API reference including all options for `ClaudeAgentOptions` and the `rewind_files()` method.