Claude Code에서 긴 작업이 무너지는 순간은 보통 모델이 답을 못 해서가 아니다.
작업 상태가 흐려지는 순간이다.
테스트를 세 번 돌렸고.
파일 다섯 개를 고쳤고.
마이그레이션 로그를 봤고.
중간에 실패 원인도 하나 잡았고.
이제 마지막 검증만 남았는데 context compaction이 들어온다.
그러면 대화는 이어지지만, 작업 감각은 달라질 수 있다.
요약은 요약이다.
작업자의 손에 남아 있던 잔상까지 모두 보존하지는 못한다.
그래서 Claude Code의 PreCompact hook이 흥미롭다.
공식 hooks reference에 따르면 PreCompact는 Claude Code가 compact 작업을 실행하려고 하기 전에 동작한다.
트리거는 manual과 auto로 나뉜다.
manual은 사용자가 /compact를 실행할 때다.
auto는 context window가 찼을 때 자동 compact가 걸리는 경우다.
그리고 중요한 대목이 있다.
PreCompact hook은 exit code 2 또는 JSON의 block decision으로 compaction을 막을 수 있다.
말만 들으면 아주 멋지다.
긴 작업 중에는 무조건 막으면 되겠네.
하지만 그렇게 단순하지 않다.
공식 문서는 자동 compaction을 막는 효과가 상황에 따라 다르다고 설명한다.
context limit 전에 proactive하게 걸린 auto compact는 건너뛰고 대화가 계속될 수 있다.
반대로 이미 context-limit error를 복구하려고 compact가 걸린 상황이면, underlying error가 표면화되고 현재 요청이 실패할 수 있다.
그러니까 PreCompact는 안전벨트다.
브레이크가 아니다.
그리고 안전벨트도 운전할 때 매는 거지, 차를 영원히 멈추게 하려고 매는 건 아니다.
이 글은 Claude Code PreCompact hook을 “긴 작업 중단 방지 장치”로 쓸 때 어디까지 기대해도 되는지 정리한다.
실험용 코드를 그대로 붙이기보다, 팀 작업에서 어떤 기준으로 막고 어떤 기준으로 통과시킬지에 집중한다.
먼저 볼 핵심
PreCompact hook은 Claude Code가 context compaction을 실행하기 직전에 개입하는 hook이다.
공식 문서상 matcher 값은 manual과 auto다.
manual은 /compact다.
auto는 context window가 가득 찼을 때의 자동 압축이다.
hook 입력에는 공통 필드 외에 trigger와 custom_instructions가 들어온다.
manual에서는 사용자가 /compact에 넘긴 custom instruction이 들어갈 수 있다.
auto에서는 custom_instructions가 비어 있다.
차단은 가능하다.
command hook에서 exit code 2로 종료하거나, JSON으로 "decision": "block"을 반환하면 된다.
하지만 자동 압축을 막는 것은 항상 안전하지 않다.
압축이 proactive하게 걸린 상황이면 Claude Code가 압축을 건너뛰고 계속 진행할 수 있다.
이미 context limit error를 회복하려는 상황이면 요청이 실패할 수 있다.
그래서 운영 기준은 이렇다.
PreCompact를 모든 압축 차단용으로 쓰지 말자.
대신 작업 상태가 손실되면 위험한 구간에서만 차단하자.
예를 들어 배포 직전.
마이그레이션 도중.
여러 파일을 고친 뒤 검증이 끝나기 전.
서브에이전트들이 아직 결과를 돌려주지 않은 상태.
테스트 실패 원인을 좁히는 중간.
이런 구간에서는 compact 전에 상태 스냅샷을 남기거나, 필요하면 일시 차단하는 게 의미 있다.
반대로 단순 질의응답, 문서 탐색, 작은 코드 수정에서는 굳이 막을 이유가 없다.
hook은 보호 장치다.
습관성 방해물이 되면 안 된다.
왜 긴 작업에서 compaction이 위험해 보이나
긴 작업은 사실 대화가 길어서 어려운 게 아니다.
상태가 많아서 어렵다.
예를 들어 Claude Code로 레거시 테스트 실패를 고친다고 하자.
처음에는 실패 로그를 본다.
그다음 관련 파일을 찾는다.
그다음 이전 커밋의 변경 의도를 본다.
그다음 테스트를 다시 돌린다.
그다음 한 파일을 수정한다.
그다음 다른 실패가 생긴다.
그다음 수정 범위를 줄인다.
이 과정에서 중요한 정보는 단순히 “무엇을 했다”가 아니다.
“왜 그 방향으로 갔는지”다.
요약이 이 이유를 놓치면 다음 행동이 흔들릴 수 있다.
Claude Code의 compaction은 대화를 계속하기 위한 기능이다.
하지만 요약 뒤에는 작업자의 미세한 판단 흔적이 줄어들 수 있다.
특히 멀티파일 수정에서는 더 그렇다.
어느 파일은 내가 바꿨고.
어느 파일은 사용자 변경이라 건드리면 안 되고.
어느 테스트는 실패하지만 이번 작업 범위 밖이고.
어느 실패는 방금 수정 때문에 새로 생겼고.
이런 구분은 단순한 대화 요약보다 더 중요하다.
그래서 긴 작업에는 별도 상태 파일이 필요하다.
그리고 compact 직전 hook은 그 상태 파일이 있는지 확인하는 좋은 지점이다.
PreCompact의 핵심은 “압축을 막는다”가 아니라 “압축 전 상태를 확인한다”에 가깝다.
무조건 막는 hook은 팀을 답답하게 만든다.
상태가 없는 압축만 막는 hook은 팀을 지켜준다.
이 차이가 꽤 크다.
공식 문서 기준으로 가능한 일
Claude Code hooks reference는 hooks를 lifecycle의 특정 시점에 자동 실행되는 사용자 정의 명령, HTTP endpoint, LLM prompt로 설명한다.
hook은 event가 발생하고 matcher가 맞으면 JSON context를 handler에 전달한다.
command hook은 stdin으로 JSON을 받는다.
handler는 입력을 검사하고 선택적으로 decision을 반환할 수 있다.
PreCompact는 hook events 중 하나다.
문서의 event table은 PreCompact를 context compaction 전에 실행되는 이벤트로 설명한다.
PostCompact는 compact 완료 후 실행된다.
즉 둘의 역할은 다르다.
PreCompact는 막거나 준비할 수 있다.
PostCompact는 compact 결과에 반응할 수 있다.
공식 문서는 PostCompact 입력에 compact_summary가 들어온다고 설명한다.
이건 운영상 꽤 중요하다.
PreCompact에서 상태 파일을 확인하고.
PostCompact에서 compact summary를 저장하거나 외부 상태와 비교할 수 있다.
이렇게 하면 compact를 무조건 두려워하지 않아도 된다.
compact 전후를 기록할 수 있기 때문이다.
다만 PostCompact는 compaction 결과에 영향을 줄 수 없다.
막고 싶으면 PreCompact에서 해야 한다.
이미 끝난 뒤에 “잠깐만요”라고 해도 늦다.
회의 끝나고 손드는 느낌이다.
나도 가끔 그러는데, 생산성에는 별 도움이 없다.
막아도 되는 compact와 막으면 곤란한 compact
PreCompact를 쓸 때 가장 중요한 판단은 차단 기준이다.
모든 auto compact를 막으면 안 된다.
context limit 앞에서 압축을 계속 막으면 작업이 실패할 수 있다.
공식 문서도 이미 context-limit error를 복구하려는 상황에서는 underlying error가 표면화되고 현재 request가 fail할 수 있다고 설명한다.
그래서 차단 기준을 세 단계로 나누는 편이 좋다.
첫째, 통과.
상태 파일이 있고, 진행 중인 위험 작업이 없고, 최근 변경이 정리되어 있으면 compact를 통과시킨다.
둘째, 지연.
진행 중인 위험 작업이 있지만 상태 스냅샷만 남기면 compact를 허용할 수 있는 경우다.
이때 hook은 상태 파일이나 로그를 갱신하고 통과시킨다.
셋째, 차단.
지금 compact가 들어가면 실제로 위험한 경우다.
예를 들어 마이그레이션 파일을 수정했는데 테스트 결과를 아직 확인하지 않았다.
여러 파일을 수정했는데 어떤 파일이 사용자 변경인지 기록하지 않았다.
서브에이전트 결과를 기다리는 중인데 메인 세션 요약만 남으면 통합이 꼬인다.
이런 경우에는 block이 의미 있다.
다만 차단 메시지는 짧고 행동 가능해야 한다.
“상태가 위험합니다”는 별 도움이 안 된다.
“작업 상태 파일 .claude/tmp/current-task-state.md를 갱신한 뒤 다시 compact 하세요”가 낫다.
hook이 사람을 혼내면 안 된다.
hook은 다음 행동을 알려줘야 한다.
차단 게이트 설계표
| 상황 | PreCompact 판단 | 이유 | 다음 행동 |
|---|---|---|---|
| 단순 질문 답변 중 | 통과 | 잃을 작업 상태가 적다 | compact 허용 |
| 문서 리서치 중 | 통과 또는 지연 | source URL만 남기면 충분 | source note 저장 |
| 단일 파일 수정 후 테스트 완료 | 통과 | 상태가 닫혔다 | compact 허용 |
| 멀티파일 수정 후 테스트 미실행 | 차단 | 수정 의도와 검증 상태 손실 위험 | 테스트 또는 상태 파일 갱신 |
| 마이그레이션 작성 중 | 차단 | 중간 상태 손실 위험 큼 | migration checklist 저장 |
| 서브에이전트 결과 대기 중 | 차단 | 병렬 작업 통합 맥락 손실 | pending agent 목록 저장 |
| 배포 직전 | 차단 | 잘못된 요약이 사고로 이어질 수 있음 | release gate 확인 |
| context limit 회복 상황 | 신중 | 차단 시 요청 실패 가능 | 상태 저장 후 가능한 통과 |
이 표는 기술적으로 완전한 규칙이 아니다.
운영 기준이다.
팀마다 위험 작업의 정의가 다르다.
백엔드 팀은 마이그레이션을 더 강하게 막을 수 있다.
프론트엔드 팀은 배포 preview 검증 전 compact를 막을 수 있다.
데이터 팀은 notebook 실행 상태와 산출물 경로를 더 중요하게 볼 수 있다.
핵심은 “압축 전에 잃으면 안 되는 상태가 있는가”다.
그 답이 예라면 막거나 저장한다.
아니오라면 통과시킨다.
최소 구현은 상태 파일 확인이다
PreCompact hook을 처음 붙일 때부터 거창한 시스템을 만들 필요는 없다.
가장 작은 구현은 상태 파일 확인이다.
예를 들어 긴 작업을 시작할 때 .claude/tmp/current-task-state.md 같은 파일을 만들게 한다.
그 안에 네 가지를 적는다.
현재 목표.
수정한 파일.
검증 상태.
남은 위험.
PreCompact hook은 이 파일이 있는지 본다.
파일이 없으면 통과한다.
파일이 있고 risk: open 같은 표시가 있으면 차단한다.
파일이 있고 risk: closed이면 통과한다.
이 정도만 해도 꽤 실용적이다.
완벽한 상태 머신을 만들 필요는 없다.
AI workflow에서 완벽한 상태 머신을 만들려다가 workflow 자체가 일이 되는 경우가 많다.
간단한 마커가 이길 때가 많다.
예시는 이런 식이다.
# Current Task State
goal: fix checkout retry failure
risk: open
changed_files:
- app/services/payment_retry.py
- tests/test_payment_retry.py
verification:
- unit tests pending
notes:
- user has unrelated changes in app/config.py; do not touch
이 파일이 있으면 compact 뒤에도 다시 잡을 손잡이가 생긴다.
요약이 조금 부족해도 상태 파일이 버틴다.
이게 hook보다 더 중요하다.
hook은 손잡이를 확인하는 문지기다.
손잡이 자체는 상태 파일이다.
예시 설정은 이렇게 작게 시작한다
공식 문서상 hooks는 settings JSON 안에 이벤트를 고르고, matcher group을 넣고, hook handler를 정의하는 구조다.
PreCompact는 matcher가 manual 또는 auto를 받는다.
처음에는 auto만 보는 게 낫다.
수동 /compact는 사용자가 의도를 가지고 실행하는 경우가 많다.
자동 compact는 갑자기 들어와서 작업 흐름을 흔들 수 있다.
예시 설정은 이런 모양이 된다.
{
"hooks": {
"PreCompact": [
{
"matcher": "auto",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/precompact-gate.sh"
}
]
}
]
}
}
그리고 shell script는 상태 파일만 본다.
#!/usr/bin/env bash
set -euo pipefail
STATE_FILE="$CLAUDE_PROJECT_DIR/.claude/tmp/current-task-state.md"
if [ ! -f "$STATE_FILE" ]; then
exit 0
fi
if grep -q "^risk: open" "$STATE_FILE"; then
echo "PreCompact blocked: current task risk is still open. Update .claude/tmp/current-task-state.md or close the verification step first." >&2
exit 2
fi
exit 0
이 코드는 화려하지 않다.
그래서 좋다.
처음부터 transcript를 파싱하고 tool history를 분석하려고 하면 유지보수 비용이 커진다.
작은 팀은 작은 hook으로 시작하는 편이 낫다.
hook이 똑똑할수록 디버깅할 것도 늘어난다.
AI 자동화에서 똑똑한 장치는 가끔 너무 똑똑한 척을 한다.
그럴 땐 단순한 grep이 마음을 편하게 해준다.
manual과 auto를 다르게 다뤄야 한다
PreCompact 입력에는 trigger가 들어온다.
값은 manual 또는 auto다.
이 차이는 운영에서 중요하다.
manual compact는 사용자가 직접 /compact를 실행한 경우다.
사용자는 보통 지금 대화를 정리하고 싶어서 실행한다.
따라서 manual을 무조건 막으면 사용자가 답답해진다.
대신 manual에서는 경고만 하는 방식을 고려할 수 있다.
“현재 risk가 open입니다. 그래도 compact하려면 상태 파일을 closed로 바꾸거나 custom instruction에 요약 지시를 넣으세요” 같은 방식이다.
반면 auto compact는 사용자가 의도하지 않은 시점에 들어온다.
긴 작업 중에는 auto compact가 더 위험하게 느껴질 수 있다.
그래서 auto에는 더 엄격한 기준을 적용할 수 있다.
다만 앞에서 말했듯이 auto를 너무 자주 막으면 context limit 상황에서 요청 실패로 이어질 수 있다.
따라서 auto 차단은 짧게 유지해야 한다.
예를 들어 차단 메시지에 다음 행동을 넣는다.
테스트를 실행하라.
상태 파일을 갱신하라.
pending subagent 목록을 기록하라.
그 다음 다시 진행하라.
차단은 일시정지여야 한다.
영구정지가 되면 자동화가 아니라 장애물이다.
PostCompact도 같이 쓰면 더 좋다
PreCompact만 보면 압축을 막는 데 집중하게 된다.
하지만 실제 운영에서는 PostCompact도 같이 보는 게 좋다.
공식 문서에 따르면 PostCompact는 compaction이 끝난 뒤 실행된다.
입력에는 trigger와 compact_summary가 포함된다.
PostCompact hook은 compaction 결과에 영향을 줄 수 없다.
하지만 요약을 저장하거나 외부 로그에 남길 수 있다.
이게 중요한 이유는 compact 뒤 문제가 생겼을 때 역추적이 가능해지기 때문이다.
예를 들어 .claude/tmp/compact-history/ 아래에 날짜별 summary를 저장할 수 있다.
이후 작업이 꼬이면 마지막 compact summary를 보고 무엇이 빠졌는지 확인한다.
PreCompact는 문 앞에서 확인하는 사람이다.
PostCompact는 회의록을 보관하는 사람이다.
둘을 같이 두면 훨씬 안정적이다.
작은 팀이라면 처음에는 PreCompact만 넣고.
문제가 반복되면 PostCompact 로그를 추가하면 된다.
처음부터 모든 걸 넣을 필요는 없다.
운영 도구는 한 번에 우주선을 만들면 안 된다.
자전거부터 굴러가야 한다.
언제 PreCompact hook을 쓰지 말아야 하나
PreCompact hook이 유용하다고 모든 팀에 필요한 것은 아니다.
작은 단건 작업만 한다면 필요 없을 수 있다.
짧은 코드 리뷰, 단일 파일 수정, 문서 초안 작성에는 과한 장치다.
Claude Code를 대화형 보조 도구로만 쓴다면 hook 관리 비용이 더 클 수 있다.
또 팀에 상태 파일을 쓰는 습관이 없다면 hook부터 넣어도 효과가 작다.
hook은 문화를 대신하지 못한다.
상태를 남기는 문화가 있어야 hook이 힘을 쓴다.
그리고 hook script 자체가 자주 실패하면 오히려 신뢰를 잃는다.
예를 들어 jq 경로 문제.
권한 문제.
shell 호환성 문제.
CI와 로컬 환경 차이.
이런 문제로 compact가 자꾸 막히면 팀은 hook을 꺼버린다.
그래서 첫 버전은 의존성을 최소화해야 한다.
가능하면 POSIX shell과 grep 정도로 시작한다.
복잡한 분석은 나중이다.
AI workflow 자동화에서 가장 중요한 건 멋진 설계가 아니라 꺼지지 않는 습관이다.
팀 운영 체크리스트
-
긴 작업 시작 시 상태 파일을 만든다.
-
상태 파일에는 목표, 수정 파일, 검증 상태, 남은 위험을 적는다.
-
risk: open이면 auto PreCompact를 차단한다. -
테스트나 검증이 끝나면
risk: closed로 바꾼다. -
수동
/compact는 되도록 막기보다 경고 중심으로 둔다. -
자동 compact 차단 메시지는 다음 행동을 포함한다.
-
PostCompact 로그는 문제가 반복될 때 추가한다.
-
hook script는 가능한 작고 로컬 의존성이 적어야 한다.
-
배포, 마이그레이션, 대규모 리팩터링은 별도 엄격 규칙을 둔다.
-
subagent 병렬 작업은 pending 목록이 남아 있으면 compact를 막는다.
이 체크리스트의 목적은 AI가 더 오래 생각하게 만드는 것이 아니다.
AI가 어디까지 했는지 잃지 않게 만드는 것이다.
긴 작업의 적은 느린 속도가 아니다.
중간 상태의 증발이다.
PreCompact hook은 그 증발을 조금 줄여준다.
하지만 증발을 완전히 없애지는 못한다.
그래서 hook과 상태 파일을 같이 써야 한다.
FAQ
PreCompact hook을 쓰면 context compaction을 완전히 막을 수 있나?
항상 그렇게 보면 안 된다.
공식 문서상 exit code 2 또는 block decision으로 compaction을 막을 수 있다.
하지만 자동 compaction이 context-limit error 복구 과정에서 발생한 경우에는 차단 시 현재 request가 실패할 수 있다.
따라서 완전 차단 장치가 아니라 위험 구간의 게이트로 보는 편이 맞다.
manual과 auto 중 어디에 먼저 붙이는 게 좋나?
처음에는 auto에 붙이는 편이 실용적이다.
manual /compact는 사용자가 의도적으로 실행하는 경우가 많다.
auto compact는 긴 작업 중 예상치 못하게 들어올 수 있다.
다만 auto 차단은 짧고 명확해야 한다.
상태 파일 없이 hook만 써도 되나?
기술적으로는 가능하지만 운영 효과는 약하다.
hook이 무엇을 기준으로 막을지 알아야 하기 때문이다.
가장 단순한 기준은 .claude/tmp/current-task-state.md 같은 상태 파일이다.
PostCompact는 꼭 필요할까?
처음부터 필수는 아니다.
하지만 compact 뒤에 작업 맥락이 자주 흔들린다면 PostCompact로 compact_summary를 저장하는 것이 좋다.
압축 후 어떤 요약이 남았는지 추적할 수 있다.
이걸 Codex나 Cursor workflow에도 적용할 수 있나?
아이디어는 적용할 수 있다.
긴 작업 전에 상태 파일을 만들고, 압축이나 세션 전환 전에 위험 상태를 확인하는 방식은 도구를 가리지 않는다.
다만 PreCompact라는 hook event는 Claude Code의 공식 hook lifecycle에 있는 기능이다.
관련 글
공식 출처
한 줄 정리
Claude Code PreCompact hook은 긴 작업을 영원히 보호하는 방패가 아니다.
압축 전에 위험 상태를 확인하는 게이트다.
상태 파일이 있고, 차단 기준이 작고, 차단 메시지가 행동 가능할 때 가장 쓸모 있다.
무조건 compact를 막는 팀보다, compact 전에 잃으면 안 되는 상태를 남기는 팀이 더 오래 간다.
AI agent workflow에서 진짜 실력은 큰 자동화보다 작은 상태 보존에서 나온다.