Claude Code의 영구 메모리: 세션 간 컨텍스트가 실제로 작동하는 방식
금요일, 세 시간 동안의 세션을 마치고 노트북을 닫습니다. 그동안 Claude Code는 인증 모듈을 리팩터링했고, 팀이 예외를 던지는 대신 사용자 정의 Result<T> 래퍼를 사용한다는 사실을 배웠으며, 마침내 UserService 에서 다음 모듈을 가져올 수 없는 이유를 이해했습니다. billing/. 월요일에 새 세션을 열면 Claude는 자신 있게 새 함수를 try/catch로 감싸고 금지된 모듈을 가져옵니다. 배운 내용은 모두 사라졌습니다.
이것이 에이전트 기반 코딩 도구의 핵심적인 사용성 문제입니다. 모델에는 일화 기억이 없습니다. 매 세션은 수동으로 기록해 둔 내용만 더해진 백지 상태에서 시작합니다. 작동하지 않는 부분까지 솔직하게 짚어 보면서, 엔지니어링으로 이 문제를 해결해 봅시다.
핵심 문제: 세션은 설계상 상태를 유지하지 않습니다
Claude Code 세션은 하나의 대화입니다. 세션이 끝나면 대화 기록은 보관되지만, 수십 번의 도구 호출을 통해 쌓인 이해, 즉 작업 컨텍스트는 사라집니다. 다음 세션은 세 가지 출처에서 컨텍스트를 재구성합니다.
- 사용자의
CLAUDE.mdfiles (project and user scope) - Claude가 세션 중 읽는 파일
- 사용자가 입력하는 내용
이 중 어느 것도 다음과 같은 지식을 담아내지 못합니다. 추론을 통해 얻은 지식, 즉 이미 탐색한 막다른 길, 특이한 우회 방법이 존재하는 이유, 접근 방식 A를 시도했더니 CI가 실패했다는 사실입니다. 이 지식을 다시 도출하려면 매 세션마다 토큰과 실제 경과 시간이 듭니다.
자연스럽게 떠오르는 방법은 메모리 계층을 만드는 것입니다. 일어난 일을 기록하고 압축한 뒤, 시작할 때 관련 부분을 다시 주입하는 방식입니다. 오픈 소스 claude-mem 프로젝트는 바로 이 패턴의 깔끔한 참조 구현이며, 도입 여부와 관계없이 살펴볼 가치가 있습니다.
Claude Code 영구 메모리의 기반 아키텍처 패턴
Claude Code의 영구 메모리를 제대로 구현하는 모든 방식은 동일한 세 단계 순환 구조를 따릅니다. 각 단계를 개별적으로 이해하면 어떤 단계는 직접 구축하고, 어떤 단계는 구매하거나 생략할지 결정할 수 있습니다.
1단계: 수집
세션에서 어떤 일이 일어났는지 관찰해야 합니다. Claude Code는 수명 주기 훅 을 제공합니다. 훅은 이벤트가 발생할 때 실행되는 셸 명령입니다. 관련 훅은 다음과 같습니다.
| 훅 | 실행 시점 | 용도 |
|---|---|---|
SessionStart | 세션이 시작될 때 | 메모리 주입 |
SessionEnd | 세션이 종료될 때 | 수집 시작 |
PostToolUse | 모든 도구 호출 이후 | 세부 활동 스트리밍 |
Stop | 에이전트가 응답을 마쳤을 때 | 체크포인트 |
다음에 설정하는 최소한의 수집 훅: .claude/settings.json:
{
"hooks": {
"SessionEnd": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/mem/capture.sh"
}
]
}
]
}
}
훅은 이벤트를 설명하는 JSON을 표준 입력으로 받습니다. 다음의 경우: SessionEnd 세션 ID와 대화 기록 경로를 받으므로, capture.sh 에서 전체 대화 로그를 읽을 수 있습니다.
#!/usr/bin/env bash
INPUT=$(cat)
TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path')
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id')
# Hand the raw transcript to the compression stage
python3 "$CLAUDE_PROJECT_DIR/.claude/mem/compress.py" \
--transcript "$TRANSCRIPT" \
--session "$SESSION_ID"
흔히 놓치는 점이 있습니다. 훅에는 실행 시간 제한이 있으며, 대용량 대화 기록을 LLM에 동기적으로 전달하면 이 제한을 초과하게 됩니다. 실제로는 수집을 실행 후 기다리지 않는 방식으로 처리하는 것이 좋습니다. 대화 기록 경로를 큐에 기록하고 백그라운드 워커에서 처리하세요. 훅 안에서 직접 처리하지 마세요.
2단계: 압축
원본 대화 기록은 메모리로 쓰기에 쓸모가 없습니다. 크기가 엄청나고 파일 덤프, 과도한 도구 출력, 오타 같은 잡음으로 가득하기 때문입니다. 압축 단계에서는 LLM을 사용해 세션을 장기적으로 유효한 사실로 정제합니다. 이 단계에는 Opus가 아니라 Haiku 4.5 호출을 사용하세요. 요약은 Haiku의 가격 책정에 딱 맞는, 처리량이 많고 오류의 영향이 작은 작업입니다.
import anthropic
client = anthropic.Anthropic()
PROMPT = """You are a memory compressor. From this coding session
transcript, extract ONLY durable facts worth remembering next session:
- Architectural decisions and their rationale
- Conventions discovered (naming, error handling, imports)
- Dead ends already explored (so we don't repeat them)
- Unresolved TODOs
Output JSON: a list of {fact, category, files[], confidence}.
Omit anything transient. If nothing durable happened, output []."""
resp = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1500,
system=PROMPT,
messages=[{"role": "user", "content": transcript_text}],
)
memories = resp.content[0].text
다음 항목에 주목하세요: confidence 필드와 다음을 출력하라는 명시적 지시: []. 둘 다 뒤에서 다룰 실패 유형의 피해를 줄이기 위한 조치입니다. 출력은 쿼리할 수 있는 곳에 저장하세요. 임베딩 열이 있는 SQLite나 프로젝트와 파일 경로를 키로 사용하는 벡터 저장소가 적합합니다.
3단계: 주입
세션이 시작되면 관련 메모리를 검색해 주입합니다. 다음 SessionStart 훅은 표준 출력으로 내용을 출력할 수 있으며, 이 출력은 Claude의 컨텍스트에 추가됩니다.
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/mem/inject.sh" }
]
}
]
}
}
엔지니어링에서 핵심적으로 결정해야 할 사항은 관련성 필터링입니다. 모든 메모리를 주입하는 것은 단순하지만 잘못된 접근입니다. 컨텍스트가 비대해지고 유용한 사실이 묻히게 됩니다. 더 나은 방법은 세션에서 다룰 가능성이 높은 주제를 기준으로 검색하는 것입니다. 아직 주제를 알 수 없다면 신뢰도가 높은 프로젝트 전반의 사실만 주입하고, 나머지는 다음을 통해 제공하세요: MCP 서버 그러면 Claude가 필요할 때 메모리를 조회할 수 있습니다.
# A tiny MCP tool the agent calls when it wants history
@mcp.tool()
def recall(query: str, files: list[str] = []) -> list[dict]:
"""Retrieve relevant memories about this codebase."""
return memory_store.search(query, files=files, min_confidence=0.6)
실제로는 이 풀 방식이 푸시 방식보다 낫습니다. 시작 시점에 무엇이 관련 있는지 추측하는 대신, 에이전트가 필요한 바로 그 순간에 “이 결제 코드를 이전에 다룬 적이 있나요?”라고 물을 수 있게 합니다. 훅은 항상 컨텍스트에 유지할 짧은 요약을 넣고, MCP 서버는 특정 정보를 찾아오는 역할을 담당합니다.
이 방식이 실패하는 지점 — 실제로 실패합니다
저는 메모리 계층을 충분히 오래 운영해 봤기에 회의적인 시각을 갖고 있습니다. 실패 유형은 실제로 존재하며, 서로 겹치면서 문제가 커집니다.
AI로 압축한 메모리는 환각을 일으킵니다. 압축기 자체도 언어 모델입니다. 실제로는 폐기된 아이디어를 “결정 사항”으로 기록하거나, 어떤 선택의 근거를 정반대로 기록하는 일이 가끔 발생합니다. 그러면 권위 있어 보이는 거짓 메모리가 시작 시점에 주입되고, 에이전트는 이를 필요 이상으로 신뢰합니다. 확신에 차서 틀린 정보를 제시하므로 메모리가 아예 없는 것보다 나쁩니다. 다음 confidence 필드와 사람이 메모리 저장소를 검토하는 것만이 실질적인 완화책입니다.
오래된 컨텍스트는 조용히 문제를 일으킵니다. 화요일에 다음을 리팩터링합니다: UserService 월요일의 메모리에는 여전히 “인증 기능은 다음 위치에 있다”라고 적혀 있습니다: UserService. 이를 무효화하는 것은 아무것도 없습니다. 코드가 바뀌는 순간 메모리의 정확도는 떨어지며, 메모리를 만료시킬 명확한 신호도 없습니다. 메모리를 파일 해시나 커밋 SHA에 연결하고, 기반 파일이 이동하면 해당 메모리를 의심스러운 것으로 취급하세요.
세션마다 토큰 비용이 늘어납니다. 주입된 메모리는 사용 여부와 관계없이 매 턴 비용을 지불하는 컨텍스트입니다. 시작 시점에 4K개의 토큰을 주입하는 메모리 계층은 세션 전체의 입력 비용에 그만큼을 더합니다. 풀 기반 MCP 모델이 도움이 되지만, 수집과 압축에도 별도의 반복 비용이 듭니다.
솔직하게 비교하면 다음과 같습니다.
| 접근 방식 | 설정 비용 | 반복 토큰 사용량 | 정보 노후화 위험 | 적합한 용도 |
|---|---|---|---|---|
CLAUDE.md 만 사용 | 몇 분 | 낮고 예측 가능함 | 직접 관리 | 대부분의 프로젝트 |
| 범위가 한정된 MCP 도구 | 몇 시간 | 요청 시에만 | 낮음 | 실시간 시스템 상태 |
| 전체 메모리 계층 | 며칠 | 더 높음, 세션마다 발생 | 높음 | 장기간의 탐색적 작업 |
불편한 진실: 아마 필요하지 않을 것입니다
이런 것을 구축하기 전에, 먼저 다음 파일을 잘 작성하세요: CLAUDE.md. 사람이 직접 정리한 파일에 “우리는 다음을 사용한다: Result<T>, 예외를 던지지 않는다; UserService 에서는 다음을 가져오면 안 된다: billing/; 인증 기능은 다음 위치로 이동했다: auth/ 이동 시점은 이 분기였다”라고 적어 두면 환각 위험 없이 예측 가능한 비용으로 메모리 문제의 80%를 해결할 수 있습니다. 사람이 작성했으므로 본질적으로 신뢰할 수 있습니다.
메모리 계층이 제값을 하는 범위는 과장된 홍보에서 말하는 것보다 좁습니다. 장기간 진행되는 탐색적 작업에서 다음과 같은 추론을 통해 얻은 지식, 즉 막다른 시도나 아직 끝내지 못한 조사 내용을 아직 알지 못하기 때문에 실제로 미리 작성할 수 없는 경우입니다. 일상적인 기능 개발에서는, CLAUDE.md 와 범위가 한정된 MCP 서버 몇 개를 함께 사용하는 편이 자동화된 메모리 파이프라인보다 더 많은 요구를 충족하며, 거짓 정보를 전달하지도 않습니다.
파이프라인을 구축한다면 비용에 가장 신경 써야 할 곳은 압축 단계입니다. Haiku로 자주 요약하는 것은 저렴하지만, 애초에 토큰당 가격이 합리적일 때만 그렇습니다. 팀들이 이런 대량의 백그라운드 작업을 AI Prime Tech 같은 제공업체를 통해 처리하는 이유 중 하나도 여기에 있습니다.
실무 핵심 사항
- 세션은 상태를 유지하지 않습니다. 실제로 사라지는 것은 막다른 시도, 판단 근거, 관례처럼 작업을 통해 얻은 지식이며, 이를 다시 알아내는 데 많은 비용이 듭니다.
- 패턴은 수집 → 압축 → 주입입니다. 수집과 주입은 다음의
SessionEnd/SessionStart훅으로 연결하세요. 훅의 시간 제한을 피하려면 수집을 비동기로 수행하세요. - 푸시보다 풀 방식을 우선하세요. 시작 시점에는 아주 짧은 요약을 넣고, 이후 다음
recallMCP 도구를 제공해 에이전트가 관련성이 있을 때만 메모리를 가져오도록 하세요. - Haiku 4.5으로 압축하세요. 모든 메모리에 신뢰도와 원본 파일 해시를 표시하고, 파일이 변경되면 해당 메모리를 의심스러운 것으로 취급하세요.
- 자동화된 메모리는 거짓 정보를 전달할 수 있습니다. 환각으로 생성되거나 오래된 컨텍스트는 권위 있는 정보처럼 받아들여지므로, 컨텍스트가 없는 것보다 나쁩니다. 사람이 메모리 저장소 검토에 계속 참여하도록 하세요.
- 다음을 사용해 보세요:
CLAUDE.md먼저 사용하세요. 대부분의 프로젝트에서는 직접 작성한 컨텍스트 파일과 범위가 한정된 도구를 함께 사용하는 편이 비용, 신뢰성, 유지보수 측면에서 전체 메모리 계층보다 낫습니다. 작업이 실제로 장기간에 걸친 탐색적 작업일 때만 영구 메모리를 도입하세요.
API 키 하나로 Claude Opus 5.5, Sonnet 5, Haiku 4.5, Fable 5.1 및 GPT-6개 모델을 이용하세요. 구독 없이 사용한 만큼만 결제합니다.
API 키 받기 →