클로드 코드로 작업하다 보면 하루에도 몇 번씩 같은 자리로 돌아옵니다. 컨텍스트가 압축되거나, 창을 닫았거나, 한도에 걸렸을 때입니다. 저희 실측으로는 48시간에 압축 11회 — 요청 여섯 번에 한 번꼴이었습니다.
그래서 세션 상태를 파일 하나로 빼내는 도구를 만들어 쓰고 있었습니다. 새 세션이 열리면 제목·마지막 요청·손댄 파일·git 이 자동으로 첫 화면에 뜹니다. 여기까지는 잘 돌았어요.
그런데 정말 값을 하는지 재봤더니 아니었습니다. 이 프로젝트를 전혀 모르는 모델에게 그 주입문만 주고, 우리가 정답을 아는 결정 다섯 개를 물었습니다. 결과는 0개였습니다.
위치는 넘어가는데 이유가 안 넘어갑니다. "무엇을 하던 중"은 알아도 "왜 그렇게 하기로 했는지"는 하나도 안 남습니다. 이 글은 그 구멍을 추가 토큰 0으로 메운 방법과 코드 전문입니다. 라이선스는 MIT 입니다.
먼저 — 만들지 않은 부분
처음 구상엔 한도에 걸리면 다음 계정으로 자동 전환하는 부분이 있었습니다. 그건 만들지 않았습니다. 계정을 돌려가며 사용량 제한을 넘기는 자동화는 이용정책 위반입니다. 여기서 말하는 건 기억이 특정 계정·특정 AI 에 묶여 있지 않다는 것이지, 한도를 우회한다는 게 아닙니다.
원리 ① — 받아 적지 말고 복구한다
처음 만든 버전은 사람이 save 를 눌러야 하는 구조였습니다. 저장을 기억해야 도는 장치는 정작 급할 때 안 돌아갑니다. 끊기는 순간은 예고가 없으니까요.
그래서 방향을 뒤집었습니다. 클로드 코드는 모든 세션을 ~/.claude/projects/ 아래 기록으로 남깁니다. 사람에게 묻지 않고 그 기록에서 거꾸로 복구합니다. 파일이 100MB 를 넘는 게 흔해서 통째로 읽지 않고 앞 400KB·뒤 2.5MB 만 읽습니다 — 495MB 중 4.5%만 읽고 매 턴 650ms 입니다.
- Stop — 매 턴이 끝날 때마다
- PreCompact — 컨텍스트가 압축되기 직전, 지워지기 전 마지막 스냅샷
- SessionStart — 새 세션이 열릴 때 요약을 컨텍스트에 넣는다
커밋마다 git 사실을 얹는 post-commit 훅도 하나 답니다. 사람이 손으로 적는 건 기록이 담지 못하는 것뿐입니다.
이런 실측, 남들보다 먼저 받으실 분?
직접 돌려보고 되는 것만 골라 매주 보내드립니다. 광고성 하이프는 거릅니다.
원리 ② — 「왜」는 압축 요약이 나른다 (토큰 0)
0/5 를 메우려면 요약이 필요한데, 훅은 로컬 Node 프로세스라 LLM 을 못 씁니다. 새로 API 를 붙이면 토큰이 듭니다.
그런데 클로드 코드는 압축할 때 이미 요약을 씁니다. 그 요약이 isCompactSummary 사용자 메시지로 기록에 남아 있습니다. 저희 도구는 그걸 "사람 요청이 아니다"라며 일부러 빼고 있었어요. 그래서 거기서 결정 절만 골라 붙였습니다.
같은 질문을 다시 던졌습니다. 공정하게 하려고 질문도 다시 짰습니다 — 압축 뒤의 결정은 요약에 원리상 없으니, 압축 앞 결정 5개로 냈고 대조군은 같은 주입문에서 압축 줄 하나만 뺐습니다.
| 새 세션이 받은 것 | 주입문 | 맞힌 수 |
|---|---|---|
| 위치만 (제목·파일·git) | 3,105자 | 0 / 5 |
| + 압축 요약 | 4,678자 (+51%) | 5 / 5 |
추가 토큰은 0 입니다. 어차피 압축할 때 만들어지는 글을 주워 쓰는 것뿐이니까요. 대신 주입문이 51% 늘었습니다 — 세션당 900~1,350토큰으로 봅니다.
두 가지를 실측에서 배웠습니다. 첫째, 절 순서는 원문 순서가 아니라 쓸모 순서여야 합니다. 원문 순서로 두면 「오류·수정」 절 1,580자가 상한 2,000자를 혼자 먹고 「남은 일·지금 하던 일·다음」이 통째로 잘렸습니다. 둘째, 같은 폴더를 두 세션이 번갈아 만지면 새 세션이 받는 요약은 마지막으로 손댄 쪽의 것입니다. 이 시험에서 실제로 옆 세션 요약이 들어왔습니다.
덮이지 않는 구간이 있습니다. 압축 요약은 압축 시점까지만 담습니다. 그 뒤 끊기기 전까지의 결정은 안 들어가요. 그 구간용으로 note 를 뒀는데, 사람이 적어야 하는 장치라 안 쓰일 위험을 압니다. 그래서 stats 로 쓰임 횟수를 셉니다 — 아래에 그 숫자도 그대로 적었습니다.
원리 ③ — 파일은 하나, 보는 자리는 셋
상태가 파일 하나(docs/checkpoint.json)에 있으니 그 파일을 보는 자리를 늘릴 수 있습니다. 실제로 써보고 제일 많이 물어보신 게 아래 두 가지입니다.
① 무료 플랜이라도 이어집니다. 한도에 걸려 클로드가 막혀도 창만 오픈코드로 바꾸면 같은 파일을 이어 읽습니다. 오픈코드에 로컬 모델(Ollama 등)을 물리면 한도 자체가 없습니다. 계정을 여러 개 두는 게 아니라 도구를 바꾸는 것입니다.
② 챗지피티 웹에서도 이 작업 얘기를 할 수 있습니다. 커스텀 MCP 커넥터 하나로, 챗지피티 탭에 "지금 뭐 하고 있었지" 라고 물으면 실제 체크포인트 파일을 열어보고 그 값으로 답합니다. 코드를 고치거나 파일을 쓰지는 못합니다 — 대화 상대일 뿐입니다.
| 창구 | 할 수 있는 것 | 어떻게 붙나 |
|---|---|---|
| 클로드 | 쓰기·명령·게시 전부 | 훅이 자동으로 |
| 오픈코드 | 쓰기 가능 · 무료 플랜 한도에 걸려도 여기로 넘어가 계속 · 로컬 모델이면 한도 없음 | 세션 첫 줄에 checkpoint show |
| 챗지피티 웹 | 읽기만 — 그래도 대화는 됩니다 | MCP 커넥터 |
챗지피티 쪽은 커스텀 MCP 커넥터로 붙였습니다. 남의 MCP 서버는 쓰지 않았습니다 — 화제가 됐던 공개 서버 하나를 격리 환경에서 검증했더니 셸 명령이 허용 폴더 밖까지 걸렸습니다. 직접 만든 서버는 도구 다섯 개가 전부 읽기이고, 여는 범위도 목록으로 못 박았습니다. 코드와 .env·토큰은 목록에 없어 못 읽습니다.
../.env 시도가 막힌 기록입니다.솔직하게 적어두는 약점. 챗지피티 커넥터 폼에는 API 키를 넣을 칸이 없습니다. 그래서 붙이는 동안은 토큰 검사를 끈 채로 돕니다. 남는 방어선은 읽기 전용·허용 목록·토큰 가림·무작위 터널 주소, 그리고 쓸 때만 터널을 여는 것입니다. 다 쓰면 터널을 닫으세요.
솔직한 숫자 — 사람이 적는 칸은 썩습니다
이 도구엔 사람이 목표를 직접 적는 칸이 있습니다. 실측해 봤더니 저장 84회 중 사람이 적은 건 1회였고, 그 하나가 주입문의 18%를 차지한 채 내용이 틀려 있었습니다. 없애려던 결함이 사람이 적는 절반에 그대로 남아 있었던 겁니다.
그래서 기계가 판단 없이 처리하게 고쳤습니다. 목표의 낱말이 최근 세션들과 34% 미만으로 겹치면 접고 done 을 안내하고, 24시간이 지나면 맨 아래로 미룹니다. 스스로 지우지는 않습니다 — 잠시 미뤄둔 진짜 일이 사라지면 안 되니까요.
같은 이유로 note(결정 한 줄)를 넣을 때는 계기판을 먼저 달았습니다. stats 가 최근 며칠의 저장을 종류별로 셉니다. 지금 숫자는 이렇습니다.
| 최근 2일 | 횟수 |
|---|---|
| 전체 저장 | 132회 |
| 기계 (recover · auto) | 121회 · 91% |
| 사람·어시스턴트 (save · note · done) | 6회 · 5% |
노트 3개는 전부 도구를 만든 직후 저희가 쓴 것이라, "쓰인다"의 증거가 아니라 계기의 0점입니다. 값이 있는지는 다음 며칠의 stats 가 말합니다. 안 쓰이면 그 숫자를 그대로 공개하고 규칙을 바꾸겠습니다.
그대로 가져가세요 — MIT
설치는 세 걸음입니다.
# 1. 스크립트를 프로젝트의 tools/ 에 (Node 22+ · 의존성 없음)
cp checkpoint.mjs <프로젝트>/tools/checkpoint.mjs
# 2. 훅 3종을 .claude/settings.json 에 (이미 있으면 "hooks" 안에 합칩니다 — 덮어쓰지 마세요)
# 3. 커밋 훅 (한 번만)
node tools/checkpoint.mjs hook
{
"hooks": {
"Stop": [
{ "hooks": [ { "type": "command", "command": "node tools/checkpoint.mjs recover --quiet", "timeout": 20 } ] }
],
"PreCompact": [
{ "hooks": [ { "type": "command", "command": "node tools/checkpoint.mjs recover --quiet", "timeout": 20 } ] }
],
"SessionStart": [
{ "hooks": [ { "type": "command", "command": "node tools/checkpoint.mjs show --brief", "timeout": 20 } ] }
]
}
}
# 지금 어디인지 + 최근 세션들 (SessionStart 훅이 --brief 로 자동 주입)
node tools/checkpoint.mjs show
node tools/checkpoint.mjs show --hours 168
# 기록에서 복구 (훅이 알아서 부릅니다)
node tools/checkpoint.mjs recover --quiet
# 기록이 못 담는 것만 사람이
node tools/checkpoint.mjs save --goal "…" --next "a;b" --blocked "…"
node tools/checkpoint.mjs done
# 압축 뒤~끊김 구간의 결정 한 줄 · 그 쓰임을 세는 계기판
node tools/checkpoint.mjs note "결정: … — 이유: …"
node tools/checkpoint.mjs stats --days 7
파일 네 개가 전부입니다
회원가입도 댓글도 필요 없습니다. MIT 라 고쳐 쓰고 다시 나눠도 됩니다 — 저작권 줄만 남기면 됩니다.
오픈코드 세션까지 같이 보려면 node:sqlite 가 필요합니다. Node 22 이상이면 기본 포함입니다.
이게 못 하는 것
- 끊긴 순간의 대화 자체는 못 살립니다. 대화를 그대로 이으려면 같은 계정·같은 기계에서
claude --resume을 씁니다. - 압축이 없던 세션엔 붙일 요약이 없습니다. 실측 9개 중 3개가 그랬습니다.
- 압축 뒤 ~ 끊김 사이는 여전히 약합니다.
note를 사람이 적어야 메워집니다. - 다른 기계로는 git 에 든 것만 갑니다.
.env·토큰은 안 따라갑니다. 그게 맞습니다. - 계정 전환은 없습니다. 앞에서 적은 이유 그대로입니다.
- 시험은 n=1 입니다. 한 시점·한 모델·질문 5개였고, 정답을 아는 저희가 채점했습니다. 후한 쪽으로 기울 수 있습니다.
기억을 파일로 관리하는 더 넓은 얘기는 클로드 메모리 시스템 4단계에 정리해 뒀습니다. 이 글의 체크포인트는 그중 "지금 위치"만 떼어낸 조각입니다.
카드로 한 번에 보기
실측 위주 AI 뉴스레터 — 직접 돌려보고 되는 것만 골라 매주 보내드립니다.