Agent SDK 파일 체크포인팅으로 되돌리기
공식 기준: https://code.claude.com/docs/en/agent-sdk/file-checkpointing
기준일: 2026-07-26 · CLI 기준 2.1.220
개요
파일 체크포인팅은 에이전트 세션 중 Write, Edit, NotebookEdit 도구로 수정된 파일을 추적해 이전 상태로 되돌립니다. 원치 않는 변경 취소, 대안 탐색, 잘못된 수정 복구에 사용합니다.
중요: Bash 명령(echo > file, sed -i 등)으로 만든 변경은 추적되지 않습니다. 파일 되감기는 디스크 파일만 복원하며 대화 기록·컨텍스트는 그대로 둡니다.
핵심 개념
| 도구 | 설명 |
|---|---|
| Write | 파일 생성·전체 덮어쓰기 |
| Edit | 기존 파일 부분 수정 |
| NotebookEdit | Jupyter .ipynb 셀 수정 |
체크포인트 시스템은 생성·수정된 파일과 수정 전 원본을 추적합니다. 되감기 시 생성 파일은 삭제되고 수정 파일은 해당 시점 내용으로 복원됩니다.
상세
구현 흐름
- 옵션에서 체크포인팅 활성화 +
replay-user-messages로 UUID 수신 - 응답 스트림의 user message UUID를 체크포인트로 캡처
- 필요 시
rewindFiles()/rewind_files()호출
| 옵션 | Python | TypeScript |
|---|---|---|
| 체크포인팅 활성 | enable_file_checkpointing=True |
enableFileCheckpointing: true |
| UUID 수신 | extra_args={"replay-user-messages": None} |
extraArgs: { "replay-user-messages": null } |
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, UserMessage, ResultMessage
import asyncio
async def main():
options = ClaudeAgentOptions(
enable_file_checkpointing=True,
permission_mode="acceptEdits",
extra_args={"replay-user-messages": None},
)
checkpoint_id = None
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 and not checkpoint_id:
checkpoint_id = message.uuid
if isinstance(message, ResultMessage) and not session_id:
session_id = message.session_id
if checkpoint_id and session_id:
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)
break
print(f"Rewound to checkpoint: {checkpoint_id}")
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
const opts = {
enableFileCheckpointing: true,
permissionMode: "acceptEdits" as const,
extraArgs: { "replay-user-messages": null }
};
const response = query({
prompt: "Refactor the authentication module",
options: opts
});
let checkpointId: string | undefined;
let sessionId: string | undefined;
for await (const message of response) {
if (message.type === "user" && message.uuid && !checkpointId) {
checkpointId = message.uuid;
}
if ("session_id" in message && !sessionId) {
sessionId = message.session_id;
}
}
if (checkpointId && sessionId) {
const rewindQuery = query({
prompt: "",
options: { ...opts, resume: sessionId }
});
for await (const msg of rewindQuery) {
await rewindQuery.rewindFiles(checkpointId);
break;
}
}
대부분 첫 user message UUID를 캡처하면 원본 상태로 복원됩니다. 중간 상태는 여러 UUID를 저장해 선택합니다. 스트림 처리 중 즉시 rewind하면 session ID 캡처를 생략할 수 있습니다. 나중에 되감을 때는 resume으로 세션을 열고 빈 프롬프트로 연결한 뒤 rewind합니다.
공통 패턴
- 위험 작업 전 체크포인트: 대규모 리팩터 직전 UUID 저장 후 실패 시 rewind
- 다중 restore point: 각 턴의 user message UUID 목록 유지
- 대화는 유지되므로 파일만 되돌린 뒤 다른 접근을 계속 지시할 수 있습니다
제한
- Bash/시스템 명령 변경 미추적
- 대화 history 되감기 아님
- 세션 밖 수동 편집과의 병합 충돌 가능
문제 해결
| 증상 | 원인·조치 |
|---|---|
| 옵션 미인식 | SDK/CLI 버전 확인, 옵션 이름 snake_case/camelCase |
| user message에 UUID 없음 | replay-user-messages 누락 |
| No file checkpoint found | 해당 UUID 시점 이후 추적 대상 도구 변경 없음, 또는 잘못된 UUID |
| File rewinding is not enabled | enableFileCheckpointing 미설정 |
| ProcessTransport not ready | 연결 종료 후 rewind — 빈 프롬프트로 resume 후 호출 |
체크리스트
-
enableFileCheckpointing과replay-user-messages를 함께 켰다 - checkpoint UUID와 (필요 시) session ID를 저장한다
- Bash 경로 변경은 체크포인트 밖임을 팀에 공유했다
- rewind가 대화가 아닌 파일만 복원함을 이해했다