O checkpointing de arquivo rastreia modificações de arquivo feitas através das ferramentas Write, Edit e NotebookEdit durante uma sessão de agente, permitindo que você desfaça arquivos para qualquer estado anterior. Quer experimentar? Vá para o exemplo interativo.
Com checkpointing, você pode:
Apenas alterações feitas através das ferramentas Write, Edit e NotebookEdit são rastreadas. Alterações feitas através de comandos Bash (como echo > file.txt ou sed -i) não são capturadas pelo sistema de checkpoint.
Quando você ativa o checkpointing de arquivo, o SDK cria backups de arquivos antes de modificá-los através das ferramentas Write, Edit ou NotebookEdit. Mensagens de usuário no fluxo de resposta incluem um UUID de checkpoint que você pode usar como ponto de restauração.
O checkpoint funciona com essas ferramentas integradas que o agente usa para modificar arquivos:
| Ferramenta | Descrição |
|---|---|
| Write | Cria um novo arquivo ou sobrescreve um arquivo existente com novo conteúdo |
| Edit | Faz edições direcionadas em partes específicas de um arquivo existente |
| NotebookEdit | Modifica células em notebooks Jupyter (arquivos .ipynb) |
A restauração de arquivo restaura arquivos no disco para um estado anterior. Não desfaz a conversa em si. O histórico de conversa e contexto permanecem intactos após chamar rewindFiles() (TypeScript) ou rewind_files() (Python).
O sistema de checkpoint rastreia:
Quando você volta para um checkpoint, arquivos criados são deletados e arquivos modificados são restaurados para seu conteúdo naquele ponto.
Para usar checkpointing de arquivo, ative-o em suas opções, capture UUIDs de checkpoint do fluxo de resposta, então chame rewindFiles() (TypeScript) ou rewind_files() (Python) quando precisar restaurar.
O exemplo a seguir mostra o fluxo completo: ative checkpointing, capture o UUID de checkpoint e ID de sessão do fluxo de resposta, então retome a sessão mais tarde para desfazer arquivos. Cada passo é explicado em detalhes abaixo.
Esses padrões mostram diferentes maneiras de capturar e usar UUIDs de checkpoint dependendo do seu caso de uso.
Este padrão mantém apenas o UUID de checkpoint mais recente, atualizando-o antes de cada turno do agente. Se algo der errado durante o processamento, você pode imediatamente desfazer para o último estado seguro e sair do loop.
Se Claude fizer alterações em múltiplos turnos, você pode querer desfazer para um ponto específico em vez de voltar completamente. Por exemplo, se Claude refatorar um arquivo no turno um e adicionar testes no turno dois, você pode querer manter a refatoração mas desfazer os testes.
Este padrão armazena todos os UUIDs de checkpoint em um array com metadados. Após a sessão ser concluída, você pode desfazer para qualquer checkpoint anterior:
Este exemplo completo cria um pequeno arquivo utilitário, faz o agente adicionar comentários de documentação, mostra as alterações, então pergunta se você quer desfazer.
Antes de começar, certifique-se de ter o Claude Agent SDK instalado.
O checkpointing de arquivo tem as seguintes limitações:
| Limitação | Descrição |
|---|---|
| Apenas ferramentas Write/Edit/NotebookEdit | Alterações feitas através de comandos Bash não são rastreadas |
| Mesma sessão | Checkpoints estão vinculados à sessão que os criou |
| Apenas conteúdo de arquivo | Criar, mover ou deletar diretórios não é desfeito por desfazer |
| Arquivos locais | Arquivos remotos ou de rede não são rastreados |
Se enableFileCheckpointing ou rewindFiles() não estiver disponível, você pode estar em uma versão mais antiga do SDK.
Solução: Atualize para a versão mais recente do SDK:
pip install --upgrade claude-agent-sdknpm install @anthropic-ai/claude-agent-sdk@latestSe message.uuid for undefined ou estiver faltando, você não está recebendo UUIDs de checkpoint.
Causa: A opção replay-user-messages não está definida.
Solução: Adicione extra_args={"replay-user-messages": None} (Python) ou extraArgs: { 'replay-user-messages': null } (TypeScript) às suas opções.
Este erro ocorre quando os dados de checkpoint não existem para o UUID de mensagem de usuário especificado.
Causas comuns:
CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING não está definidaSolução: Certifique-se de ter definido a variável de ambiente (veja Defina a variável de ambiente), então use o padrão mostrado nos exemplos: capture o UUID da primeira mensagem de usuário, conclua a sessão completamente, então retome com um prompt vazio e chame rewindFiles() uma vez.
Este erro ocorre quando você chama rewindFiles() ou rewind_files() após ter terminado de iterar através da resposta. A conexão com o processo CLI fecha quando o loop é concluído.
Solução: Retome a sessão com um prompt vazio, então desfaça na nova 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() e o método rewindFiles().ClaudeAgentOptions e o 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())Defina a variável de ambiente
O checkpointing de arquivo requer a variável de ambiente CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING. Você pode defini-la via linha de comando antes de executar seu script, ou diretamente nas opções do SDK.
Opção 1: Defina via linha de comando
export CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=1Opção 2: Defina nas opções do SDK
Passe a variável de ambiente através da opção env ao configurar o SDK:
import os
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
env={**os.environ, "CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING": "1"}
)Ative o checkpointing
Configure suas opções de SDK para ativar checkpointing e receber UUIDs de checkpoint:
| Opção | Python | TypeScript | Descrição |
|---|---|---|---|
| Ativar checkpointing | enable_file_checkpointing=True | enableFileCheckpointing: true | Rastreia alterações de arquivo para desfazer |
| Receber UUIDs de checkpoint | extra_args={"replay-user-messages": None} | extraArgs: { 'replay-user-messages': null } | Necessário para obter UUIDs de mensagem de usuário no fluxo |
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")Capture UUID de checkpoint e ID de sessão
Com a opção replay-user-messages definida (mostrada acima), cada mensagem de usuário no fluxo de resposta tem um UUID que serve como um checkpoint.
Para a maioria dos casos de uso, capture o UUID da primeira mensagem de usuário (message.uuid); desfazer para ele restaura todos os arquivos para seu estado original. Para armazenar múltiplos checkpoints e desfazer para estados intermediários, veja Múltiplos pontos de restauração.
Capturar o ID de sessão (message.session_id) é opcional; você só precisa dele se quiser desfazer mais tarde, após o fluxo ser concluído. Se você estiver chamando rewindFiles() imediatamente enquanto ainda processa mensagens (como o exemplo em Checkpoint antes de operações arriscadas faz), você pode pular a captura do ID de sessão.
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_idDesfaça arquivos
Para desfazer após o fluxo ser concluído, retome a sessão com um prompt vazio e chame rewind_files() (Python) ou rewindFiles() (TypeScript) com seu UUID de checkpoint. Você também pode desfazer durante o fluxo; veja Checkpoint antes de operações arriscadas para esse padrão.
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)
breakSe você capturar o ID de sessão e ID de checkpoint, você também pode desfazer a partir da 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())Crie um arquivo de teste
Crie um novo arquivo chamado utils.py (Python) ou utils.ts (TypeScript) e cole o seguinte 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 / bExecute o exemplo interativo
Crie um novo arquivo chamado try_checkpointing.py (Python) ou try_checkpointing.ts (TypeScript) no mesmo diretório que seu arquivo utilitário, e cole o seguinte código.
Este script pede ao Claude para adicionar comentários de documentação ao seu arquivo utilitário, então oferece a opção de desfazer e restaurar o 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 exemplo demonstra o fluxo de trabalho completo de checkpointing:
enable_file_checkpointing=True e permission_mode="acceptEdits" para aprovar automaticamente edições de arquivorewind_files() para restaurar o arquivo originalExecute o exemplo
Defina a variável de ambiente e execute o script do mesmo diretório que seu arquivo utilitário.
Abra seu arquivo utilitário (utils.py ou utils.ts) em seu IDE ou editor antes de executar o script. Você verá o arquivo atualizar em tempo real conforme o agente adiciona comentários de documentação, então reverter para o original quando você escolher desfazer.
export CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=1
python try_checkpointing.pyVocê verá o agente adicionar comentários de documentação, então um prompt perguntando se você quer desfazer. Se você escolher sim, o arquivo é restaurado para seu estado original.