Claude Code 에이전트의 고질적인 문맥 누락 문제, Memtrace로 해결했습니다.
Your Claude Code agent is always working from stale context. I built it a fix it can rewind, replay, and stay ahead of every edit.
핵심 요약
Claude Code의 문맥 누락 문제를 해결하기 위해 코드 변경 사항을 실시간으로 추적하고 과거 상태를 복구하는 Memtrace를 개발했습니다.
- 문맥 누락 문제 — 에이전트가 이전 세션의 변경 사항을 기억하지 못해 불필요한 토큰을 낭비하고 잘못된 리팩토링을 수행함.
- 실시간 상태 추적 — 코드 변경 시 42ms 만에 증분 스냅샷을 생성하여 에이전트가 항상 최신 상태를 유지하도록 함.
- 코드 상태 복구 — bi-temporal 레이어를 통해 코드의 과거 상태를 기억하고 버그 발생 시점의 코드로 되돌려 분석 가능함.
- 하이브리드 검색 — BM25와 Jina-code 임베딩을 결합하여 코드 구조와 의미를 모두 이해하는 정밀한 검색을 구현함.
모든 긴 Claude Code 세션에는 동일한 숨겨진 실패 모드가 있습니다. 에이전트가 항상 오래된 문맥을 바탕으로 작업한다는 점입니다.
에이전트는 이미 보여준 인터페이스를 '상기시키기 위해' 세 번의 세션에 걸쳐 동일한 12개의 파일을 다시 읽습니다. getUserById를 호출하는 곳을 확인하지 않고 리팩토링합니다. 이전 버전이 왜 그렇게 되었는지에 대한 기억 없이 설정을 편집합니다. 이는 문맥 창의 문제가 아닙니다. 창은 괜찮습니다. 에이전트가 다시 쿼리할 수 있는 코드베이스의 지속적이고 시간에 민감한 표현이 없습니다. 그래서 추측하는 것입니다. 그리고 여러분은 매번 다시 읽을 때마다 토큰 비용을 지불합니다.
저는 바로 이 문제를 해결하기 위해 Memtrace를 만들었습니다.
다른 메모리 도구에는 없는 두 가지 기능이 있습니다:
(1) 항상 최신 상태. 여러분이 만드는 모든 편집은 코딩 에이전트가 적용한 변경 사항의 42ms 증분 스냅샷을 트리거합니다. 에이전트의 메모리는 한 세션 전의 것이 아닙니다. 리팩토링 후 에이전트는 여러분보다 먼저 영향 범위를 파악합니다. 즉, 방금 수정한 함수를 호출하는 모든 곳, 모든 테스트, 모든 소비자를 알고 있습니다. 에이전트는 getUserById를 본 지 30초 후에 "getUserById가 무엇을 반환하나요?"라고 묻는 것을 멈춥니다.
(2) 되감기 및 재생. 이것은 다른 누구도 가지고 있지 않은 부분입니다. 여러분의 코드베이스는 bi-temporal 방식으로 저장되므로 모든 변경 사항이 기억 가능한 에피소드가 됩니다. 에이전트가 회귀 버그를 디버깅할 때, 망가진 함수가 현재 상태에 어떻게 도달했는지 재생할 수 있습니다.
- 이전에 무엇이 작동했는지.
- 무엇이 언제 변경되었는지.
- 어떤 커밋이 버그를 도입했는지
"현재 상태에서 추측"하는 것이 아니라, 재생하는 것입니다.
두 가지를 모두 가능하게 하는 저의 아키텍처적 선택은 인덱싱 중 LLM 추론을 전혀 사용하지 않는 것입니다. Tree-sitter가 코드를 AST로 파싱하고, 그 AST가 구조적 표현이 됩니다. 컴파일러가 이미 알고 있는 것을 다시 파생시키기 위해 LLM에 비용을 지불할 필요가 없습니다.
검색은 하이브리드 방식입니다. 어휘 회상을 위한 Tantivy BM25("getUserById 찾기" 쿼리)와 HNSW에 인덱싱된 Jina-code 768차원 임베딩을 사용한 의미론적 회상("사용자를 인증하는 모든 것 찾기" 쿼리)을 사용합니다. 두 개의 순위 목록을 k=60에서 Reciprocal Rank Fusion으로 융합합니다. 하나의 신호만으로는 놓치지만, 함께하면 정확합니다. 여기서 임베딩 모델이 중요합니다. Jina-code는 일반적인 산문이 아닌 코드로 훈련되었기 때문에, 의미론적 측면에서 "auth"라는 단어에 대한 패턴 매칭이 아니라 "이것은 인증 핸들러이다"라는 것을 실제로 이해합니다.
bi-temporal 레이어가 되감기를 가능하게 합니다. 모든 노드와 엣지는 valid_time과 transaction_time을 가지므로 "월요일에 이 함수가 어떻게 생겼었나"는 git-blame 휴리스틱이 아닌 실제 쿼리가 됩니다. 또한 리팩토링 전에 에이전트에게 영향 범위를 제공하는 것도 바로 이것입니다. 타입이 지정된 엣지(CALLS, IMPORTS, IMPLEMENTS, EXTENDS, CONTAINS, TYPE_REFERENCES, INSTANTIATES)가 텍스트 시간이 아닌 그래프 시간을 통해 탐색됩니다.
속도가 중요한 이유는 신선함이 저렴해야 하기 때문입니다. 모든 편집 후 스냅샷을 찍는 것이 비싸다면, 모든 편집마다 그렇게 할 여유가 없습니다. 따라서 인덱싱 경로는 LLM 토큰이 아닌 I/O에 의해 병목 현상이 발생합니다.

