본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 06. 15. 22:14

Claude Code에 「파일 기반 영구 메모리」를 부여하기: 1파일 1사실 + index 방식

요약

Claude Code의 세션 휘발성 문제를 해결하기 위해 '1파일 1사실' 원칙을 기반으로 한 파일 기반 영구 메모리 시스템을 제안합니다. memory/ 폴더와 MEMORY.md 인덱스를 활용하여 필요한 정보만 효율적으로 회상(recall)할 수 있는 설계 구조를 설명합니다.

핵심 포인트

  • 세션 간 정보 유지를 위해 파일 기반의 메모리 구조 설계
  • 1파일 1사실 원칙을 통해 필요한 정보만 선택적으로 로드
  • description 필드를 활용한 정교한 정보 회상(recall) 메커니즘
  • user, feedback, project, reference 4가지 타입으로 메모리 분류

Claude Code에 세션을 넘나들며 사실을 기억하게 하는 메커니즘을 만들었습니다. memory/ 폴더에 「1파일 = 1사실」로 .md 파일을 두고, MEMORY.md를 인덱스(index)로 사용하는 방식입니다. 이 글을 읽으면 그 설계, 운용 규칙, 실제 파일의 내용이 무엇인지 바로 알 수 있습니다.

학부 2학년이 자신의 환경에서 돌리고 있는 이야기일 뿐입니다. 분명 더 좋은 방법이 있을 것이라 생각합니다. 하지만 실제로 효과가 있기 때문에 기록합니다.

같은 설명을 3번이나 했다

Claude Code는 세션이 끊기면 이전 대화를 잊어버립니다. 당연한 일입니다. 새로운 세션은 완전히 백지 상태인 새로운 세션입니다.

그래서 저는 매번 똑같은 전제를 깔았습니다.

"실험 보고서의 수치는 조작하지 마세요". "수식은 $$...$$ 형식이면 환경에서 렌더링되지 않으니 Unicode로 작성하세요". "날짜는 상대적이지 않고 절대적으로 작성하세요". 매번 말이죠.

어느 날, 아마 3번째쯤 같은 정정 사항을 타이핑하고 있는 제 자신을 발견했습니다. '이걸 파일에 써서 읽게 하면 되지 않을까?' 그것이 시작이었습니다.

처음에는 전부 CLAUDE.md에 몰아넣었습니다. 하지만 이것은 의외로 금방 파탄이 납니다. 이유는 나중에 쓰겠습니다.

설계는 「1파일 = 1사실」

도달한 형태는 심플합니다.

  • memory/라는 폴더를 만든다
  • 기억했으면 하는 사실을 1개당 1개의 .md 파일로 저장한다
  • 각 파일에는 frontmatter를 붙인다
  • MEMORY.md가 인덱스(index)가 된다

핵심은 「1파일 1사실」입니다. 이것저것 하나의 파일에 다 적지 않습니다. 「사용자가 누구인지」와 「지난번에 이렇게 수정되었다」는 별개의 파일로 분리합니다.

왜 나누는가? 나중에 「떠올릴(recall)」 때 관련 있는 것만 가져오고 싶기 때문입니다. 1개 파일에 사실이 10개 들어있으면, 1개만 필요해도 전부 읽어야 합니다. 나누어 두면 필요한 1개 파일만 열면 됩니다.

frontmatter는 3종 세트

각 메모리 파일의 머리에 다음과 같은 frontmatter를 붙입니다.

---
name: feedback-no-data-fabrication
description: 실측 데이터가 없을 때 표의 셀은 빈칸으로 남겨둔다. 이론값이나 오차를 더한 값의 생성은 전부 조작으로 간주한다.
...

딱 3개뿐입니다.

  • name: kebab-case 슬러그(slug). 파일명과 거의 일치시킵니다. 후술할 링크에서 사용합니다.
  • description: 한 줄 요약. **이것이 회상(recall)의 키(key)**가 됩니다. 여기가 생명입니다.
  • metadata.type: 4가지 분류 중 하나 (다음 섹션).

description의 품질에 따라 모든 것이 결정됩니다. 이것은 운용하면서 가장 뼈저리게 느낀 점이었습니다.

여기에 「실측 데이터가 없을 때 표의 셀은 빈칸」이라고 구체적으로 적혀 있으면, 보고서 관련 작업을 할 때 「아, 이거 관련 있겠는데」라며 불러올 수 있습니다. 반대로 여기가 「데이터 취급에 대하여」처럼 모호하면 불러오지 않습니다. 불러와지지 않는 메모리는 없는 것과 마찬가지입니다.

type은 4개로 압축했다

metadata.type은 4개뿐입니다. 늘리면 스스로 혼란스러워지기 때문에 일부러 제한했습니다.

type의미
user사용자가 누구인지. 프로필, 소속, 무엇을 하는 사람인지
feedback업무 진행 방식에 대한 지시나 정정. 이유를 포함하여 작성
project코드나 git 이력에서는 읽어낼 수 없는, 진행 중인 작업이나 제약 사항
reference외부 리소스에 대한 포인터. "그 자료는 여기"

feedback은 「이유를 포함하여」 작성하는 것이 중요하다고 생각합니다. 「수식은 Unicode로」라고만 하면 '왜?'가 빠집니다. 「$$...$$는 환경에서 렌더링되지 않으므로 Unicode로」까지 적습니다. 이유가 있으면 비슷하지만 다른 케이스에도 응용이 가능합니다. 아마도요. 이것은 체감상 그렇습니다.

project는 은근히 효과적입니다. 코드를 읽으면 알 수 있는 것은 쓰지 않는다는 것이 철칙이지만, 「이 건은 .docx로 납품한다」, 「구 폴더는 폐지됨」처럼 소스 어디에도 적혀 있지 않은 규칙이라는 게 있거든요. 그것을 두는 장소입니다.

메모리끼리 링크하기

본문에서는 다른 메모리로 [[other-name]] 형식을 통해 링크를 걸 수 있도록 했습니다. Obsidian에서 익숙한 바로 그것입니다.

리포트 생성 시에는 [[feedback-report-tool]]에 따라 /report 스킬을 사용한다.
문체 규칙은 [[feedback-report-writing]]을 참조한다.

여기서 의도적으로 하고 있는 것이 하나 있습니다.

아직 존재하지 않는 메모리에 링크를 걸어도 좋다.

[[feedback-report-writing]]

이라는 파일이 아직 없더라도, 링크만 먼저 걸어둡니다. 이것은 '언젠가 이것을 쓰겠다'라는 예약, 혹은 TODO가 됩니다. 나중에 '이 링크가 끊겨 있네, 내용을 써야겠다'라고 생각하게 됩니다.

게으르게 보이는 것 같지만, 써야 할 내용을 놓치는 일이 줄어들기 때문에 저는 이 방식을 좋아합니다.

MEMORY.md는 색인(Index)이지 본체가 아니다

이 부분이 가장 중요할지도 모릅니다.

MEMORY.md에는 1메모리 1행만 작성합니다. 형식은 다음과 같습니다.

- [제목](file.md) — 후크 (Hook)

실제 제 색인의 몇 줄을 그대로 가져오면 다음과 같은 느낌입니다 (고유명사는 범용화했습니다).

- [사용자 프로필](user_profile.md) — <org>의 학부 2학년. 반도체·국제 교류·프로그래밍 등으로 활동.
- [수식은 플레인 텍스트로 작성한다](feedback_math_notation.md) — LaTeX 표기법($$...$$)은 환경에서 렌더링되지 않으므로, 수식은 Unicode로 기술한다.
- [실험 데이터의 날조·변조 절대 금지](feedback_no_data_fabrication.md) — 실측 데이터가 없는 경우, 표의 셀은 빈칸으로 남겨둔다. 이론값 생성은 변조로 간주한다.

뒤의 '후크'는 요컨대 description(설명)의 축약 버전입니다. 이것만 읽고도 '지금 작업과 관련이 있는가?'를 판단할 수 있도록 작성합니다.

왜 색인과 본체를 나누는 걸까요?

매 세션마다 읽어들이는 것은 MEMORY.md뿐이기 때문입니다. 본체인 .md 파일은 평소에 읽히지 않습니다. 색인의 후크를 보고 '관련이 있을 것 같다'고 생각되는 것만 본체를 열러 갑니다. 만약 본체의 내용까지 전부 MEMORY.md에 적는다면, 매 세션마다 모든 사실을 컨텍스트(Context)에 쌓게 됩니다. 메모리가 20개, 30개로 늘어나면 이는 효과적이지 않습니다. 읽기 비용(Loading cost)이 커지고, 정말 필요한 정보가 희석됩니다.

처음에 CLAUDE.md에 모든 것을 다 넣었다가 실패했던 이유가 바로 이것이었습니다. 읽기 비용은 올라가는 반면, 정작 중요한 순간에 핵심 정보가 묻혀버립니다. 색인과 본체를 나누고 나서야 겨우 제대로 돌아가기 시작했습니다.

「기억해내는」 흐름

실제로 어떻게 회상(Recall)하는지, 그 흐름은 다음과 같습니다.

  • 세션 시작 시, MEMORY.md(색인)가 읽혀짐 - 각 행의 후크(=description)를 확인
  • 지금 하고 있는 작업과 관련이 있을 법한 메모리를 선택
  • 해당 메모리의 본체 파일만 열어서 읽음

전부를 읽지 않습니다. description을 보고 관련된 것만 끌어옵니다. 그래서 몇 번이고 강조하지만 description이 생명입니다.

사람이 책장의 책등(Spine)만 보고 '이거다' 하며 한 권을 뽑는 것. 그 감각으로 움직이기를 바라는 설계입니다.

메커니즘보다 운영 규칙에서 사고가 난다

솔직히 메커니즘보다 운영 규칙이 더 중요했습니다. 지키지 않으면 금방 지저분해집니다.

중복을 만들지 말고, 기존 것을 업데이트하라.

비슷한 사실이 나오면 새 파일을 추가하지 마세요. 원래 있던 파일을 수정하세요. 이걸 게을리하면 '거의 같은 내용의 메모리가 3개'가 되어, 어떤 것이 정답인지 알 수 없게 됩니다. 저도 해봤습니다. 지옥이었습니다.

틀린 것은 지워라.

오래된 사실, 정정된 사실은 남기지 말고 삭제합니다. '만약을 위해 보관해두자'라고 하면 색인이 죽은 메모리로 비대해집니다.

코드나 git 이력에서 알 수 있는 것은 저장하지 마라.

'이 함수는 이런 구현이다' 같은 것은 쓰지 않습니다. 읽어보면 알 수 있으니까요. 메모리 낭비입니다. 쓰는 것은 '코드를 읽어도 알 수 없는 것'뿐이어야 합니다.

상대 날짜는 절대 날짜로 변환하여 저장하라.

'다음 주까지'라거나 '지난주에 수정함' 같은 표현은 나중에 읽으면 의미가 변합니다. '2026-06-22까지'와 같이 절대 날짜로 고친 뒤 저장하세요. 사소해 보이지만 가장 실수하기 쉬운 부분입니다.

실물 하나를 통째로

추상적인 이야기만 하면 이미지가 잘 떠오르지 않으므로, memory/feedback_math_notation.md를 내용 그대로 보여드리겠습니다. 구조는 실제와 같으며, 고유명사만 범용화한 예시입니다.


name: feedback-math-notation
description: LaTeX 표기법($$...$$)은 환경에서 렌더링되지 않으므로, 수식은 Unicode와 플레인 텍스트 (Plain Text)로 작성한다.
...

frontmatter가 있고, 헤더(Heading)로 "무엇이 수정되었는가 / 어떻게 작성해야 하는가 / 왜"가 구분되어 있으며, 마지막에는 [[...]]를 통해 관련 메모리(Memory)로 연결되어 있습니다. [[feedback-report-tool]]은 실제 존재하는 메모리로의 링크입니다. [[feedback-report-writing]]은 방금 말한 "예약"의 예시입니다. 아직 내용이 부족하다면 나중에 보강할 것입니다.

인덱스(Index)인 MEMORY.md 측에는 이 파일에 대응하는 단 한 줄만 기재됩니다.

- [수식은 플레인 텍스트로 작성한다](feedback_math_notation.md) — LaTeX 표기법($$...$$)은 환경에서 렌더링되지 않으므로, 수식은 Unicode로 기술한다

이렇게 하면 수식이 포함된 작업을 할 때만 이 메모리가 인출(Retrieval)되는 흐름이 됩니다.

무엇이 좋았는가

가장 큰 점은, 매번 다시 설명할 필요가 없어졌다는 것입니다.

"수식은 Unicode로", "데이터를 날조하지 말 것"과 같은 지시를 매 세션(Session)마다 말할 필요가 없습니다. 이전에 이렇게 수정했다는 기억이 남습니다. 새로운 세션임에도 불구하고, 왠지 모르게 저의 습관을 이미 파악하고 있는 상태가 됩니다.

또 다른 부산물로는, 자신의 작업 규칙이 언어화되었다는 점입니다. 메모리에 기록하기 위해 "나는 왜 이것을 싫어했었지?"를 한 번 더 생각하게 되기 때문입니다. 이유를 포함하여 feedback을 작성하도록 강제하는 규칙이 여기서 효과를 발휘합니다.

솔직히 아직 다 채우지 못한 부분

벤치마크를 통해 몇 초가 빨라졌는지와 같은 측정은 하지 않았습니다. 체감상 "편해졌다"는 수준입니다. 그 부분은 솔직히 말씀드립니다.

메모리가 늘어났을 때 인덱스가 너무 길어지는 문제는 아직 발생하지 않았지만, 언젠가 닥칠 것 같다는 느낌이 듭니다. 지금은 20개 미만이라 인덱스도 짧습니다. 이것이 100개가 된다면 인덱스 자체를 분할하거나 타입(Type)별로 나누는 등 별도의 고안이 필요할 것입니다. 그때 어떻게 할지는 아직 확인되지 않았습니다.

description을 작성하는 방법 또한 정답을 알고 있는 것은 아닙니다. 구체적으로 적을수록 더 잘 인출된다는 것은 체감으로 파악했지만, 너무 구체적이면 오히려 범위가 좁아질 수도 있을 것 같아 보입니다. 그 적절한 수위는 아직 탐색 중입니다.

그럼에도 불구하고, "1파일 1사실 + 인덱스"라는 골격은 양이 늘어나도 무너지기 어려운 형태라고 생각합니다. 적어도 CLAUDE.md에 모든 것을 다 집어넣는 방식보다는 훨씬 잘 돌아갑니다.

이 기사는 구현부터 집필까지 Claude Code와 대화하며 작성했습니다. 학부 2학년이라 용어 사용이 미흡한 부분이 있을 수 있으니, 지적해 주시면 감사하겠습니다.

Discussion

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0