GitHub ↗
CHAPTER 06 OF 10
🧠

Memory Architecture — 3-Tier Persistence

메모리 아키텍처 — 3계층 영속성

CLAUDE.md → MEMORY.md → JSONL 트랜스크립트 — 3계층 메모리 구조를 이해하면 세션이 바뀌어도 에이전트가 맥락을 잃지 않는다.

Memory Architecture — 3-Tier Persistence cheatsheet
🍌 NANO BANANA CHEATSHEET · CH 06

Overview

개관

에이전트의 가장 큰 약점은 기억이 없다는 것이다. 새 세션을 시작할 때마다 모든 컨텍스트가 사라진다. 이것은 밤 교대 근무를 하는 엔지니어가 인수인계 없이 일하는 것과 같다.

Claude Code는 3계층 메모리 구조로 이 문제를 해결한다. Layer 1: CLAUDE.md — 프로젝트 관례, 항상 로드됨. Layer 2: MEMORY.md — 진화하는 세션 상태, 첫 200줄 자동 로드. Layer 3: JSONL 트랜스크립트 — 감사 불가능한 세션 기록, 필요시 검색.

Anthropicr의 내부 연구에서 발견된 패턴: JSON 형식의 feature list는 Markdown보다 에이전트가 부적절하게 수정하는 경우가 적다. 구조화된 데이터가 모델의 '창의적 개입'을 억제한다. 이것이 장기 실행 태스크에서 JSON 파일을 중간 상태 저장소로 쓰는 이유다.

🎯 Learning Goals
  • 3계층 메모리(CLAUDE.md, MEMORY.md, JSONL) 각각의 역할과 수명을 설명할 수 있다
  • MEMORY.md의 200줄/25KB 자동 로딩 메커니즘을 설명할 수 있다
  • autoDream이 무엇이고 왜 필요한지 설명할 수 있다
  • 장기 실행 멀티세션 에이전트를 위한 Dual-Agent Architecture를 구현할 수 있다

Sections

본문

3계층 메모리 구조

계층 파일 수명 로딩 방식 용도
1. Procedural CLAUDE.md 영구 항상 자동 프로젝트 관례, 결정 사항
2. Episodic MEMORY.md 세션 간 첫 200줄 자동 아키텍처 상태, 진행 상황
3. Working JSONL 트랜스크립트 세션 내 명시적 요청 도구 호출 기록, 세션 감사

MEMORY.md 자동 로딩: ~/.claude/projects/{hash}/memory/MEMORY.md의 첫 200줄(또는 25KB)이 모든 세션 시작 시 자동으로 로드된다. 이 파일은 가장 중요한 현재 상태를 담아야 한다.

인지과학 기반 메모리: Nemori 연구(arXiv:2508.03341)에 따르면 최적의 에이전트 메모리는 에피소드(episodes) → 시맨틱 지식 → 절차적 스킬 순으로 통합된다. autoDream이 이 통합을 자동화한다.

MEMORY.md 구조 — 무엇을 기록해야 하는가

MEMORY.md는 '현재 상태의 스냅샷'이다. 자주 바뀌는 정보가 아니라 세션이 바뀌어도 Claude가 알아야 할 아키텍처 결정을 담는다.

실전 MEMORY.md 템플릿:

# MEMORY.md — 최종 업데이트: 2026-06-17

## Architecture State
- Auth: Clerk (NOT NextAuth — 2026-03 마이그레이션, ADR #003)
- DB: PostgreSQL via Prisma (raw SQL 금지 — SQL injection 이력, ADR #007)
- Deploy: Vercel preview(PR), production(main 머지)
- Testing: Vitest unit, Playwright E2E, 최소 80% coverage

## Current Work
- 작업 중: 결제 플로우 리팩토링 (tickets/PAY-123)
- 블로커: Stripe webhook 타임아웃 문제 (see docs/incidents/2026-06-15.md)
- 다음: 구독 갱신 로직 구현

## Key Decisions (recent)
- 2026-06-10: Redis 캐시 → in-memory 로 교체 (비용 이유)
- 2026-06-08: pagination을 cursor 기반으로 변경 (성능 이슈)

## More Detail On-Demand
- [user_profile.md](user_profile.md)
- [feedback_patterns.md](feedback_patterns.md)

경험칙: MEMORY.md는 새 팀원이 첫날 읽어야 할 '현재 상태 브리핑'이다. 과거 기록이 아니라 지금 이 순간의 상태를 담는다.

autoDream — 자동 메모리 통합

유출된 소스코드에서 확인된 기능: autoDream은 Claude Code의 자동 메모리 가비지 컬렉터다.

  • 유휴 상태에서 백그라운드 실행
  • MEMORY.md에서 중복 제거, 모순 해결, 오래된 컨텍스트 정리
  • 에피소드 메모리 → 의미적 지식으로 통합

실용적 의미: 적극적으로 MEMORY.md를 관리하지 않아도 autoDream이 자동으로 정리한다. 하지만 중요한 정보는 명시적으로 표시해두면 autoDream이 보존한다.

KAIROS: 유출 코드에서 150회 이상 참조된 자율 에이전트 시스템. 5분 크론 사이클, GitHub 웹훅 구독, /dream 스킬로 야간 메모리 정리. 'Your own memory is a hint — verify against actual codebase before acting'이라는 지침이 내장되어 있다.

장기 실행 멀티세션 패턴

Anthropic 엔지니어링 팀이 공개한 200개 이상의 feature를 여러 세션에 걸쳐 구현하는 패턴:

Dual-Agent Architecture:

초기화 에이전트 (첫 세션만):

  1. feature_list.json 생성 — 200개+ feature를 JSON 형식으로 (Markdown 아닌 이유: 모델이 부적절하게 편집하는 것을 방지)
  2. init.sh 생성 — 개발 환경 시작 스크립트
  3. claude-progress.txt 생성 — 세션 작업 로그
  4. 기준 git commit

코딩 에이전트 (이후 모든 세션):

1. pwd 확인
2. git log 읽기
3. MEMORY.md/claude-progress.txt 읽기
4. feature_list.json 읽기 (미완료 feature 파악)
5. init.sh로 개발 서버 시작
6. 정확히 1개 feature만 구현 (컨텍스트 부족 방지)
7. E2E 테스트 (Puppeteer MCP 등)
8. feature_list.json 업데이트 (pass: true)
9. 디스크립티브 커밋
10. 진행 로그 업데이트

JSON feature list의 중요성: JSON 구조는 모델이 '창의적으로 수정'하는 것을 억제한다. Markdown feature list는 종종 모델이 마음대로 체크하거나 삭제했다.

💡 Analogy · 비유
병원 환자 차트 시스템

3계층 메모리를 병원 차트 시스템으로 생각해보자.

CLAUDE.md는 표준 치료 프로토콜 — 어떤 의사가 담당해도 따라야 할 병원 규칙. 바뀌지 않는 기반.

MEMORY.md는 현재 환자 차트 — 오늘 이 환자의 상태, 진행 중인 치료, 주의사항. 교대 근무 때마다 새 의사가 이것을 읽는다. 200줄 이내로 핵심만.

JSONL 트랜스크립트는 상세 처방 기록 — 언제 무슨 약을 줬는지, 어떤 검사를 했는지 상세 기록. 감사나 분쟁 시 꺼내보는 것.

autoDream은 야간 당직 의사 — 모순되는 처방을 정리하고, 오래된 기록을 아카이브하고, 다음 교대를 위해 차트를 정리한다.

교대 근무 인수인계 없이 치료하는 의사 = 세션마다 처음부터 시작하는 에이전트. MEMORY.md는 그 인수인계 문서다.

현재 프로젝트에 MEMORY.md 구조를 자동 생성하고 관리하는 스크립트. 세션 시작 시 자동으로 MEMORY.md를 업데이트한다.

python
#!/usr/bin/env python3
"""memory-manager.py — MEMORY.md 자동 생성 및 관리"""
import json
import subprocess
from pathlib import Path
from datetime import date

def get_project_hash():
    cwd = subprocess.run(['pwd'], capture_output=True, text=True).stdout.strip()
    return cwd.replace('/', '-').lstrip('-')

def get_git_info():
    info = {}
    try:
        info['branch'] = subprocess.run(
            ['git', 'branch', '--show-current'], capture_output=True, text=True
        ).stdout.strip()
        info['recent_commits'] = subprocess.run(
            ['git', 'log', '--oneline', '-5'], capture_output=True, text=True
        ).stdout.strip()
        info['dirty_count'] = len(subprocess.run(
            ['git', 'status', '--short'], capture_output=True, text=True
        ).stdout.strip().split('\n'))
    except:
        pass
    return info

def setup_memory_structure(project_dir: str = '.'):
    """프로젝트에 memory 구조 초기화"""
    proj_hash = get_project_hash()
    memory_dir = Path.home() / '.claude' / 'projects' / proj_hash / 'memory'
    memory_dir.mkdir(parents=True, exist_ok=True)
    
    memory_index = memory_dir / 'MEMORY.md'
    if not memory_index.exists():
        git = get_git_info()
        content = f"""# MEMORY.md — {date.today()}

## Architecture State
<!-- 핵심 기술 결정, 마이그레이션 이력 -->
- Stack: [여기에 기술 스택]
- Branch: {git.get('branch', 'unknown')}

## Current Work  
<!-- 진행 중인 작업, 블로커 -->
- 작업 중: [여기에 현재 태스크]

## Key Decisions (recent)
<!-- 최근 아키텍처 결정 -->

## More Detail On-Demand
- [user_profile.md](user_profile.md)
- [feedback_patterns.md](feedback_patterns.md)
"""
        memory_index.write_text(content)
        print(f"✅ MEMORY.md 생성: {memory_index}")
    else:
        # 날짜 업데이트
        content = memory_index.read_text()
        lines = content.split('\n')
        lines[0] = f"# MEMORY.md — {date.today()}"
        memory_index.write_text('\n'.join(lines))
        print(f"✅ MEMORY.md 날짜 업데이트: {memory_index}")
    
    # line count 체크
    line_count = len(memory_index.read_text().split('\n'))
    if line_count > 200:
        print(f"⚠️  MEMORY.md {line_count}줄 — 200줄 이내 권장 (현재 모두 로드됨)")
    
    print(f"📍 Memory directory: {memory_dir}")
    return memory_dir

def create_feature_list(features: list, output_path: str = 'feature_list.json'):
    """장기 실행 태스크를 위한 JSON feature list 생성"""
    feature_list = [
        {
            'id': i + 1,
            'category': f.get('category', 'general'),
            'description': f.get('description', ''),
            'verification_steps': f.get('verification_steps', []),
            'passes': False,
            'notes': ''
        }
        for i, f in enumerate(features)
    ]
    
    with open(output_path, 'w') as file:
        json.dump({'features': feature_list, 'total': len(features), 'completed': 0}, file, indent=2, ensure_ascii=False)
    
    print(f"✅ {output_path} 생성 ({len(features)} features)")
    print("⚠️  JSON 형식 사용: 모델이 부적절하게 수정하는 것을 방지")

if __name__ == '__main__':
    memory_dir = setup_memory_structure()
    print(f"\n다음 세션에서 Claude Code는 자동으로 MEMORY.md를 로드합니다.")
    print(f"첫 200줄이 항상 컨텍스트에 포함됩니다.")

setup_memory_structure()로 현재 프로젝트의 memory 디렉토리를 초기화하고 MEMORY.md 파일을 생성한다. create_feature_list()는 장기 실행 태스크를 JSON 형식으로 저장해서 여러 세션에 걸쳐 진행 상황을 추적한다.

🏭 현업에서의 평가
메모리 아키텍처를 잘 설계한 팀은 에이전트를 '장기 직원'처럼 쓴다. 매번 컨텍스트를 다시 설명하지 않아도 된다. 이것이 AI 코딩 도구의 진짜 생산성 레버다.

✅ 시니어가 보는 것

  • 모든 프로젝트에 MEMORY.md 파일이 있고 최신 상태로 유지되는가
  • MEMORY.md가 200줄 이내로 관리되는가
  • 장기 태스크에 JSON feature list를 사용하는가
  • 세션 시작 루틴(pwd → git log → MEMORY.md 읽기)이 정착되어 있는가

⚠️ 레드 플래그

  • 세션마다 같은 컨텍스트를 반복해서 설명
  • MEMORY.md가 없어서 에이전트가 이전 결정을 모름
  • Markdown feature list (모델이 마음대로 체크하거나 삭제)

🎤 예상 인터뷰 질문

  1. MEMORY.md의 200줄 자동 로딩 제한이 있을 때 중요한 정보를 어떻게 관리하는가?
  2. Anthropic이 장기 실행 태스크에서 Markdown 대신 JSON feature list를 권장하는 이유는?
  3. autoDream이 MEMORY.md에서 삭제하면 안 되는 정보를 보존하는 방법은?
숙달 vs 익숙함: 단순히 아는 사람은 MEMORY.md 파일을 만든다. 마스터한 사람은 MEMORY.md를 '현재 상태 브리핑'으로 구조화하고, 세션 시작 루틴을 표준화하고, 장기 태스크에 JSON feature list를 쓰고, PreCompact 훅으로 중요 정보가 압축에서 살아남도록 보호한다.

Key Takeaways

핵심 정리

3계층 메모리

CLAUDE.md(영구) → MEMORY.md(세션 간) → JSONL(세션 내). 각각 다른 역할과 수명을 갖는다.

200줄 자동 로딩

MEMORY.md 첫 200줄(또는 25KB)이 항상 자동으로 세션에 포함된다.

JSON > Markdown

feature list는 JSON으로 저장하라. 모델이 Markdown 체크리스트를 부적절하게 수정한다.

autoDream = 메모리 GC

유휴 시 자동 실행되어 MEMORY.md를 정리하고 중복을 제거한다.

Dual-Agent Architecture

초기화 에이전트(1회) + 코딩 에이전트(반복). 세션마다 init.sh + progress 읽기로 시작.

git = 메모리 백업

커밋 메시지와 로그가 documentation이자 recovery 메커니즘이다.

세션 시작 루틴

pwd → git log → MEMORY.md → feature_list.json → init.sh — 이 순서를 CLAUDE.md에 명시하면 에이전트가 자동으로 따른다.

중요 정보 표시

MEMORY.md에서 autoDream이 보존해야 할 정보는 명시적으로 '중요' 표시를 해두면 정리 대상에서 제외된다.