El punto de control de archivos rastrea las modificaciones de archivos realizadas a través de las herramientas Write, Edit y NotebookEdit durante una sesión de agente, permitiéndote revertir archivos a cualquier estado anterior. ¿Quieres probarlo? Salta al ejemplo interactivo.
Con los puntos de control, puedes:
Solo se rastrean los cambios realizados a través de las herramientas Write, Edit y NotebookEdit. Los cambios realizados a través de comandos Bash (como echo > file.txt o sed -i) no son capturados por el sistema de puntos de control.
Cuando habilitas el punto de control de archivos, el SDK crea copias de seguridad de archivos antes de modificarlos a través de las herramientas Write, Edit o NotebookEdit. Los mensajes del usuario en el flujo de respuesta incluyen un UUID de punto de control que puedes usar como punto de restauración.
El punto de control funciona con estas herramientas integradas que el agente usa para modificar archivos:
| Herramienta | Descripción |
|---|---|
| Write | Crea un nuevo archivo o sobrescribe un archivo existente con contenido nuevo |
| Edit | Realiza ediciones dirigidas a partes específicas de un archivo existente |
| NotebookEdit | Modifica celdas en cuadernos Jupyter (archivos .ipynb) |
La reversión de archivos restaura los archivos en disco a un estado anterior. No revierte la conversación en sí. El historial de conversación y el contexto permanecen intactos después de llamar a rewindFiles() (TypeScript) o rewind_files() (Python).
El sistema de puntos de control rastrea:
Cuando reviertes a un punto de control, los archivos creados se eliminan y los archivos modificados se restauran a su contenido en ese momento.
Para usar el punto de control de archivos, habilítalo en tus opciones, captura los UUID de puntos de control del flujo de respuesta, luego llama a rewindFiles() (TypeScript) o rewind_files() (Python) cuando necesites restaurar.
El siguiente ejemplo muestra el flujo completo: habilita los puntos de control, captura el UUID del punto de control y el ID de sesión del flujo de respuesta, luego reanuda la sesión más tarde para revertir archivos. Cada paso se explica en detalle a continuación.
Estos patrones muestran diferentes formas de capturar y usar UUID de puntos de control dependiendo de tu caso de uso.
Este patrón mantiene solo el UUID de punto de control más reciente, actualizándolo antes de cada turno del agente. Si algo sale mal durante el procesamiento, puedes revertir inmediatamente al último estado seguro y salir del bucle.
Si Claude realiza cambios en múltiples turnos, es posible que desees revertir a un punto específico en lugar de todo el camino de regreso. Por ejemplo, si Claude refactoriza un archivo en el turno uno y agrega pruebas en el turno dos, es posible que desees mantener la refactorización pero deshacer las pruebas.
Este patrón almacena todos los UUID de puntos de control en una matriz con metadatos. Después de que se complete la sesión, puedes revertir a cualquier punto de control anterior:
Este ejemplo completo crea un pequeño archivo de utilidad, hace que el agente agregue comentarios de documentación, te muestra los cambios, luego pregunta si deseas revertir.
Antes de comenzar, asegúrate de tener el Claude Agent SDK instalado.
El punto de control de archivos tiene las siguientes limitaciones:
| Limitación | Descripción |
|---|---|
| Solo herramientas Write/Edit/NotebookEdit | Los cambios realizados a través de comandos Bash no se rastrean |
| Misma sesión | Los puntos de control están vinculados a la sesión que los creó |
| Solo contenido de archivo | La creación, movimiento o eliminación de directorios no se deshace al revertir |
| Archivos locales | Los archivos remotos o de red no se rastrean |
Si enableFileCheckpointing o rewindFiles() no están disponibles, es posible que estés en una versión anterior del SDK.
Solución: Actualiza a la última versión del SDK:
pip install --upgrade claude-agent-sdknpm install @anthropic-ai/claude-agent-sdk@latestSi message.uuid es undefined o está faltando, no estás recibiendo UUID de puntos de control.
Causa: La opción replay-user-messages no está establecida.
Solución: Agrega extra_args={"replay-user-messages": None} (Python) o extraArgs: { 'replay-user-messages': null } (TypeScript) a tus opciones.
Este error ocurre cuando los datos del punto de control no existen para el UUID de mensaje de usuario especificado.
Causas comunes:
CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING no está establecidaSolución: Asegúrate de haber establecido la variable de entorno (consulta Establecer la variable de entorno), luego usa el patrón mostrado en los ejemplos: captura el UUID del primer mensaje de usuario, completa la sesión completamente, luego reanuda con un mensaje vacío y llama a rewindFiles() una vez.
Este error ocurre cuando llamas a rewindFiles() o rewind_files() después de haber terminado de iterar a través de la respuesta. La conexión al proceso de CLI se cierra cuando se completa el bucle.
Solución: Reanuda la sesión con un mensaje vacío, luego revertir en la nueva consulta:
# 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():
await client.rewind_files(checkpoint_id)
breakquery() y el método rewindFiles().ClaudeAgentOptions y el método rewind_files().import asyncio
import os
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
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)
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())Establecer la variable de entorno
El punto de control de archivos requiere la variable de entorno CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING. Puedes establecerla a través de la línea de comandos antes de ejecutar tu script, o directamente en las opciones del SDK.
Opción 1: Establecer a través de la línea de comandos
export CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=1Opción 2: Establecer en las opciones del SDK
Pasa la variable de entorno a través de la opción env al configurar el SDK:
import os
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)Habilitar puntos de control
Configura tus opciones del SDK para habilitar los puntos de control y recibir UUID de puntos de control:
| Opción | Python | TypeScript | Descripción |
|---|---|---|---|
| Habilitar puntos de control | enable_file_checkpointing=True | enableFileCheckpointing: true | Rastrea cambios de archivos para reversión |
| Recibir UUID de puntos de control | extra_args={"replay-user-messages": None} | extraArgs: { 'replay-user-messages': null } | Requerido para obtener UUID de mensajes de usuario en el flujo |
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")Capturar UUID de punto de control e ID de sesión
Con la opción replay-user-messages establecida (mostrada arriba), cada mensaje de usuario en el flujo de respuesta tiene un UUID que sirve como punto de control.
Para la mayoría de los casos de uso, captura el UUID del primer mensaje de usuario (message.uuid); revertir a él restaura todos los archivos a su estado original. Para almacenar múltiples puntos de control y revertir a estados intermedios, consulta Múltiples puntos de restauración.
Capturar el ID de sesión (message.session_id) es opcional; solo lo necesitas si deseas revertir más tarde, después de que se complete el flujo. Si estás llamando a rewindFiles() inmediatamente mientras aún procesas mensajes (como lo hace el ejemplo en Punto de control antes de operaciones arriesgadas), puedes omitir la captura del ID de sesión.
checkpoint_id = None
session_id = None
async for message in client.receive_response():
# Update checkpoint on each user message (keeps the latest)
if isinstance(message, UserMessage) and message.uuid:
checkpoint_id = message.uuid
# Capture session ID from the result message
if isinstance(message, ResultMessage):
session_id = message.session_idRevertir archivos
Para revertir después de que se complete el flujo, reanuda la sesión con un mensaje vacío y llama a rewind_files() (Python) o rewindFiles() (TypeScript) con tu UUID de punto de control. También puedes revertir durante el flujo; consulta Punto de control antes de operaciones arriesgadas para ese patrón.
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)
breakSi capturaste el ID de sesión y el ID de punto de control, también puedes revertir desde la CLI:
claude --resume <session-id> --rewind-files <checkpoint-uuid>import asyncio
import os
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},
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)
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 asyncio
import os
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},
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)
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())Crear un archivo de prueba
Crea un nuevo archivo llamado utils.py (Python) o utils.ts (TypeScript) y pega el siguiente código:
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 / bEjecutar el ejemplo interactivo
Crea un nuevo archivo llamado try_checkpointing.py (Python) o try_checkpointing.ts (TypeScript) en el mismo directorio que tu archivo de utilidad, y pega el siguiente código.
Este script le pide a Claude que agregue comentarios de documentación a tu archivo de utilidad, luego te da la opción de revertir y restaurar el original.
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())Este ejemplo demuestra el flujo de trabajo completo de puntos de control:
enable_file_checkpointing=True y permission_mode="acceptEdits" para aprobar automáticamente ediciones de archivosrewind_files() para restaurar el archivo originalEjecutar el ejemplo
Establece la variable de entorno y ejecuta el script desde el mismo directorio que tu archivo de utilidad.
Abre tu archivo de utilidad (utils.py o utils.ts) en tu IDE o editor antes de ejecutar el script. Verás que el archivo se actualiza en tiempo real mientras el agente agrega comentarios de documentación, luego se revierte al original cuando elijas revertir.
export CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=1
python try_checkpointing.pyVerás que el agente agrega comentarios de documentación, luego un mensaje preguntando si deseas revertir. Si eliges sí, el archivo se restaura a su estado original.