claude mem 아키텍처 까보기
Claude Code 세션의 모든 작업을 자동으로 기록하고, AI로 압축하여 미래 세션에 컨텍스트를 주입하는 메모리 시스템입니다.
들어가며
Claude Code를 쓰다 보면 이런 생각이 듭니다. "어제 이 버그 어떻게 고쳤더라?", "저번 주에 이 API 왜 이렇게 설계했지?" 기억이 안 납니다. 히스토리를 뒤져봐도 대화가 너무 많고, 핵심만 찾기 어렵습니다.
claude-mem은 이 문제를 해결합니다. 모든 작업을 자동으로 기록하고, AI가 "기록할 가치가 있는 것"만 추려서 저장합니다. 그리고 다음 세션에서 자연어로 "어제 auth token 관련해서 뭐 했어?"라고 물으면, 관련 맥락을 찾아서 주입해줍니다.
이 글에서는 claude-mem이 어떻게 동작하는지 내부를 까봅니다. 쓰기(어떻게 기록하는가)와 읽기(어떻게 검색하는가), 그리고 이 둘을 연결하는 Hook 시스템을 중심으로 살펴보겠습니다.
1. 시스템 아키텍처 개요
전체 데이터 흐름
```mermaid flowchart LR subgraph INPUT["🖥️ Claude Code"] direction TB U["👤 사용자"] --> CC["Claude Code"] CC --> T["🔧 도구 실행"] end
subgraph CAPTURE["🪝 Hook Layer"]
direction TB
H1["SessionStart"]
H2["UserPromptSubmit"]
H3["⭐ PostToolUse"]
H4["Stop"]
end
subgraph PROCESS["⚙️ Worker Service"]
direction TB
W1["HTTP :37777(Bun)"]
W2["🤖 AI 분석"]
W3["📝 Observation"]
W1 --> W2 --> W3
end
subgraph STORE["💾 Storage"]
direction TB
DB[("SQLite")]
MCP["🔍 MCP Server"]
DB --> MCP
end
T -.->|"tool data"| H3
H3 ==>|"POST"| W1
W3 ==>|"INSERT"| DB
MCP -.->|"context inject"| CC
style H3 fill:#ff6b6b,color:#fff
style W2 fill:#4ecdc4,color:#fff
style DB fill:#45b7d1,color:#fff
```
위 다이어그램이 claude-mem의 전체 구조입니다. 복잡해 보이지만, 핵심은 단순합니다.
쓰기 흐름 (실선 화살표): 사용자 입력 → 도구 실행 → Hook 캡처 → Worker 분석 → DB 저장
읽기 흐름 (점선 화살표): MCP Server가 DB에서 검색 → Claude Code에 컨텍스트 주입
컴포넌트 역할
| 🪝 Hook Layer | ⚙️ Worker Service | 💾 Storage |
|---|---|---|
| Claude Code 이벤트를 가로채서 Worker에 전달합니다. PostToolUse가 핵심입니다. 모든 도구 사용을 캡처합니다. | Bun 백그라운드 프로세스 (port 37777)입니다. AI로 observation-worthy 판단을 하고, 구조화된 데이터를 생성합니다. | SQLite + MCP Server입니다. 영구 저장 및 검색을 담당하고, 다음 세션에 컨텍스트를 주입합니다. |
💡 핵심 인사이트: 모든 도구 사용이 `PostToolUse` hook을 통해 캡처되고, AI가 observation-worthy 여부를 판단 후 observation을 저장합니다.
2. 쓰기: Observation이 생성되는 과정
도구(Tool)란 무엇인가
Claude Code에서 "도구"라는 개념을 이해해야 합니다. Read, Grep, Bash, Edit, Write, WebSearch... Claude의 모든 작업은 도구 실행입니다. 파일을 읽는 것도 도구, 검색하는 것도 도구, 코드를 수정하는 것도 도구입니다.
사용자가 "이 파일 읽어줘"라고 하면 Claude는 `Read` 도구를 실행합니다. "버그 고쳐줘"라고 하면 `Grep`으로 찾고, `Read`로 읽고, `Edit`으로 수정합니다. 하나의 요청이 수십 개의 도구 실행으로 이어집니다.
claude-mem은 이 도구 실행을 전부 감시합니다.
PostToolUse Hook의 역할
도구가 실행될 때마다 `PostToolUse` hook이 트리거됩니다. 이 hook은 Worker 서비스에 POST 요청을 보냅니다. "방금 이런 도구가 실행됐어. 기록할까?"
Worker 서비스는 AI(claude-sonnet-4-5)를 활용하여 판단합니다. "이 작업, 기록할 가치가 있는가?"
판단 기준은 두 가지입니다:
-
Skip Tools: 단순 조회성 도구는 건너뜁니다
- ListMcpResourcesTool, SlashCommand, Skill, TodoWrite, AskUserQuestion
- 이런 도구들은 실제 작업이 아니라 보조 동작입니다
-
인사이트 여부: 기록할 가치가 있는가?
- 버그를 발견하고 수정했다 → 기록
- 아키텍처를 파악했다 → 기록
- 중요한 의사결정을 내렸다 → 기록
- 단순히 파일 목록을 봤다 → 스킵
가치가 있다고 판단되면 Observation이 생성됩니다.
Observation: 작업의 추상화
Observation은 claude-mem의 핵심 개념입니다. 작업 내용을 데이터베이스에 저장할 수 있도록 구조화한 추상화 단위입니다. 그냥 로그를 쌓는 게 아닙니다. AI가 분석하고, 분류하고, 요약해서 저장합니다.
```mermaid mindmap root((Observation)) 메타데이터 id memory_session_id project prompt_number created_at 분류 type bugfix feature refactor discovery decision change concepts how-it-works why-it-exists what-changed problem-solution gotcha pattern trade-off 내용 title subtitle facts JSON narrative 파일 추적 files_read files_modified 토큰 discovery_tokens ```
각 필드를 살펴보겠습니다.
type - 작업의 종류:
- `bugfix`: 버그 수정
- `feature`: 새 기능 추가
- `refactor`: 코드 구조 개선
- `discovery`: 새로운 사실 발견
- `decision`: 중요한 결정
- `change`: 변경 사항
concepts - 작업에서 얻은 지식의 성격:
- `how-it-works`: 시스템 동작 방식 파악
- `why-it-exists`: 존재 이유 이해
- `gotcha`: 주의해야 할 함정 발견
- `pattern`: 반복 패턴 인식
- `trade-off`: 트레이드오프 고민
내용 - 실제 기록:
- `title`: 한 줄 요약 ("인증 토큰 만료 버그 수정")
- `subtitle`: 부가 설명
- `facts`: 핵심 사실 (JSON 배열)
- `narrative`: 맥락 설명 서술
파일 추적 - 읽고 수정한 파일:
- `files_read`: 읽은 파일 목록
- `files_modified`: 수정한 파일 목록
이렇게 구조화된 Observation이 SQLite 데이터베이스에 INSERT됩니다.
데이터베이스 스키마
```mermaid erDiagram sdk_sessions ||--o{ observations : has sdk_sessions ||--o{ session_summaries : has sdk_sessions ||--o{ user_prompts : has sdk_sessions ||--o{ pending_messages : queues
sdk_sessions {
int id PK
text content_session_id UK
text memory_session_id UK
text project
text user_prompt
int started_at_epoch
text status
int prompt_counter
}
observations {
int id PK
text memory_session_id FK
text project
text type
text title
text subtitle
text facts
text narrative
text concepts
text files_read
text files_modified
int prompt_number
int discovery_tokens
}
session_summaries {
int id PK
text memory_session_id FK
text request
text investigated
text learned
text completed
text next_steps
}
user_prompts {
int id PK
text content_session_id FK
int prompt_number
text prompt_text
}
```
데이터베이스 구조는 `sdk_sessions`를 중심으로 설계되어 있습니다.
- sdk_sessions: 하나의 Claude Code 세션. 세션 ID, 프로젝트명, 시작 시간 등 저장
- observations: 세션 중 발생한 개별 관찰. 하나의 세션에 여러 observation 연결
- session_summaries: 세션 종료 시 생성되는 요약. 요청, 조사, 학습, 완료 내용 기록
- user_prompts: 사용자가 입력한 프롬프트
3. 읽기: 자연어로 과거 작업 검색하기
문제: 어떻게 가져올 것인가
저장은 됐습니다. 그런데 어떻게 가져올까요?
SQL을 직접 쓸 수는 없습니다. 사용자는 "어제 auth token 관련해서 뭐 했지?"라고 자연어로 질문합니다. 이걸 어떻게 데이터베이스 쿼리로 변환할 것인가요?
여기서 MCP가 등장합니다.
MCP란 무엇인가
MCP(Model Context Protocol)는 Claude가 외부 도구와 통신하는 표준 프로토콜입니다. claude-mem은 MCP 서버를 제공합니다. Claude가 이 서버를 호출하면, 서버가 자연어를 구조화된 쿼리로 변환해서 DB를 검색합니다.
예를 들어 사용자가 이렇게 질문한다고 가정해봅시다:
"2일 전에 auth token 관련해서 뭐 했는지 자세히 알려줘"
Claude는 이 자연어를 분석해서 MCP 도구를 호출합니다:
- "2일 전" → `dateStart: "2026-01-31"`
- "auth token" → `query: "auth token"`
- "자세히" → `get_observations` 호출 필요
사용자는 SQL을 몰라도 됩니다. "어제 뭐 했지?"라고 물으면 됩니다. Claude가 알아서 변환합니다.
MCP 도구
| 도구 | 용도 |
|---|---|
| search | 키워드/시맨틱 검색. 관련 observation 인덱스 반환 |
| timeline | 특정 ID 주변 시간순 조회. 맥락 파악에 유용 |
| get\_observations | ID로 상세 정보 조회. narrative, facts 등 반환 |
3-Layer 검색 워크플로우
```mermaid flowchart LR A[search query] --> B[Index 반환\\n~50-100 tokens/result] B --> C[timeline anchor=ID] C --> D[주변 컨텍스트] D --> E[get_observations IDs] E --> F[상세 정보]
style A fill:#e1f5fe
style F fill:#c8e6c9
```
여기서 중요한 설계 결정이 있습니다. 왜 한 번에 안 가져오고 3단계로 나눴을까요?
토큰 때문입니다.
모든 observation을 한 번에 가져오면 토큰이 폭발합니다. narrative 하나가 수백 토큰입니다. 100개를 가져오면 수만 토큰입니다. 컨텍스트 윈도우가 터집니다.
그래서 3단계로 좁혀갑니다:
- search: 키워드 검색. 인덱스(ID, 제목, 시간)만 반환. 결과당 50-100 토큰으로 가벼움
- timeline: 관심 ID 주변 시간대 확인. 맥락 파악
- get_observations: 필요한 ID만 선택하여 상세 정보 조회
이 방식으로 10배의 토큰을 절약합니다.
🎯 3-Layer Workflow: search → timeline → get\_observations (10x 토큰 절약)
4. Hook 시스템: 쓰기와 읽기를 연결하는 고리
Hook이란
Hook은 Claude Code의 생명주기 이벤트를 가로채는 장치입니다. 세션이 시작될 때, 사용자가 입력할 때, 도구가 실행될 때, 세션이 종료될 때... 이런 이벤트마다 특정 동작을 끼워넣을 수 있습니다.
claude-mem은 이 Hook을 활용해서 자동으로 기록하고, 자동으로 컨텍스트를 주입합니다. 사용자가 의식하지 않아도 됩니다. 그냥 Claude Code를 쓰면 알아서 돌아갑니다.
Hook 종류
| Hook | 트리거 시점 | 동작 |
|---|---|---|
| SessionStart | 세션 시작, /clear, /compact | Worker 시작 → 과거 컨텍스트 주입 |
| UserPromptSubmit | 사용자 입력 | Session 초기화 |
| PostToolUse | 모든 도구 사용 후 | Observation 생성 |
| Stop | 세션 종료 | 세션 요약 생성 |
Hook 동작 흐름
```mermaid sequenceDiagram participant U as User participant CC as Claude Code participant H as Hooks participant W as Worker participant DB as SQLite
U->>CC: 질문/명령
CC->>H: UserPromptSubmit
H->>W: session-init
CC->>CC: Read/Bash/Grep 등 도구 사용
CC->>H: PostToolUse
H->>W: observation 요청
W->>W: AI 분석 (claude-sonnet-4-5)
W->>DB: 저장
CC->>U: 응답
U->>CC: 세션 종료
CC->>H: Stop
H->>W: summarize
W->>DB: 세션 요약 저장
```
시퀀스를 따라가 보겠습니다:
-
세션 시작: `SessionStart` hook이 Worker를 깨웁니다. Worker는 과거 세션에서 관련 컨텍스트를 가져와서 주입합니다. "지난번에 이런 작업 했었어" 하고 알려주는 것입니다.
-
사용자 입력: `UserPromptSubmit` hook이 세션을 초기화합니다. 새로운 대화가 시작됐음을 기록합니다.
-
도구 실행: Claude가 도구를 사용할 때마다 `PostToolUse` hook이 트리거됩니다. Worker가 AI로 분석해서 가치 있는 작업만 DB에 저장합니다.
-
세션 종료: `Stop` hook이 전체 세션을 요약합니다. "이번 세션에서 뭘 요청받았고, 뭘 조사했고, 뭘 배웠고, 뭘 완료했는지"를 정리해서 저장합니다.
-
다음 세션: 다시 1번으로 돌아갑니다. 이전 세션의 요약이 다음 세션의 컨텍스트가 됩니다.
이렇게 순환합니다. 사용자가 아무것도 안 해도, 작업이 쌓이고, 기억이 누적됩니다.
5. 파일 구조
플러그인 코드 경로: `~/.claude/plugins/cache/thedotmack/claude-mem/9.0.12/`
- `.mcp.json` - MCP 서버 설정
- `hooks/hooks.json` - Hook 정의
- `scripts/worker-service.cjs` - 백그라운드 워커 (1.8MB)
- `scripts/mcp-server.cjs` - MCP 검색 서버
- `scripts/context-generator.cjs` - 컨텍스트 생성
- `scripts/worker-cli.js` - 워커 CLI
- `scripts/smart-install.js` - 자동 설치
데이터 저장 경로: `~/.claude-mem/`
- `claude-mem.db` - SQLite 데이터베이스
- `settings.json` - 설정 파일
- `worker.pid` - 워커 프로세스 ID
- `logs/` - 로그 디렉토리
- `vector-db/` - 벡터 DB (시맨틱 검색)
플러그인 코드는 `/.claude/plugins/` 아래에, 데이터는 `/.claude-mem/` 아래에 저장됩니다.
`vector-db/`는 시맨틱 검색을 위한 벡터 데이터베이스입니다. 단순 키워드 매칭이 아니라, "비슷한 의미"를 가진 observation도 찾을 수 있습니다.
6. 주요 설정
| 설정 | 기본값 | 설명 |
|---|---|---|
| CLAUDE\_MEM\_MODEL | claude-sonnet-4-5 | Observation 생성 AI 모델 |
| CLAUDE\_MEM\_WORKER\_PORT | 37777 | Worker HTTP 서버 포트 |
| CLAUDE\_MEM\_CONTEXT\_OBSERVATIONS | 50 | 컨텍스트 주입 observation 수 |
| CLAUDE\_MEM\_SKIP\_TOOLS | ListMcpResourcesTool, SlashCommand, Skill, TodoWrite, AskUserQuestion | 기록 제외 도구 |
| CLAUDE\_MEM\_PROVIDER | claude | AI 제공자 (claude/gemini/openrouter) |
`CLAUDE_MEM_CONTEXT_OBSERVATIONS`가 50이라는 건, 세션 시작 시 최대 50개의 과거 observation을 컨텍스트로 주입한다는 뜻입니다. 너무 많으면 토큰이 부족하고, 너무 적으면 맥락이 부족합니다. 50은 균형점입니다.
마치며
claude-mem의 핵심을 정리하면 다음과 같습니다:
- 쓰기: 모든 도구 실행을 PostToolUse hook으로 캡처 → AI가 가치 판단 → Observation으로 구조화 → DB 저장
- 읽기: 자연어 질문 → Claude가 MCP 도구 호출 → 3-Layer 검색으로 토큰 절약 → 컨텍스트 주입
- Hook: 이 둘을 자동으로 연결하는 고리입니다. 사용자가 의식하지 않아도 동작합니다.
결국 claude-mem은 "AI가 AI를 위해 기록하는 시스템"입니다. AI가 작업하고, AI가 기록 가치를 판단하고, AI가 검색해서 가져옵니다. 사람은 그냥 쓰면 됩니다.
다음에 "어제 그거 어떻게 했더라?"라는 생각이 드시면, 그냥 물어보세요. claude-mem이 기억하고 있습니다.