MemKraft는 스스로의 필요성에 의해 만들기 시작한 AI 에이전트를 위한 통합 메모리 시스템이다. 대화를 하면 할수록 알아서 똑똑해진다. 며칠 전 v0.2 – v0.5 개발 후기를 올렸다.
그 이후로 세 번의 추가적인 업데이트를 했다. 이번에는 "한 명의 에이전트가 가진 기억"에서 "여러 명의 에이전트가 공유하는 기억"으로, 그리고 "지금 맞다고 아는 것"에서 "언제부터 언제까지 맞았던 것"으로 문제의 결이 바뀌었다.
내가 한 일은 여전히 남는 시간 사이사이에 첫째 에이전트 제온이와 몇십 번의 채팅을 주고 받은 게 전부다. 네 번째 버전인 v0.8은 코딩부터 PyPI 배포까지 9분 17초 만에 끝났다. 막 나온 Opus 4.7 에이전트가 4개 기능, 83개 테스트, 문서 업데이트, 빌드, 업로드, 커밋, 푸시까지 한 번에 완주했다.
버전 별 키워드를 간략하게 공유한다.
--
v0.6: 기억은 어디에서 일어났는가
새 세션을 열 때마다 에이전트는 백지 상태에서 시작한다. 어제 텔레그램 단톡방에서 뭐가 논의됐는지, 지금 진행 중인 작업이 몇 번째 이터레이션인지, 내가 어떤 톤을 선호하는지 — 전부 다시 설명해야 했다. v0.6의 문제의식은 여기서 출발했다. 기억은 내용만이 아니라 "어디에서, 무엇을 하는 중에, 누구와" 일어났는지가 함께 저장되어야 한다.
채널 컨텍스트, 작업 연속성, 에이전트 워킹 메모리. 세 축을 세웠다. 채널 컨텍스트는 채팅방 하나마다 선호도와 최근 주제를 쌓는다. 텔레그램 DM은 DM의 톤이, 단톡방은 단톡방의 리듬이 있다. 같은 질문이라도 어느 채널이냐에 따라 답이 달라져야 한다. 작업 연속성은 세션을 넘어가도 "이 작업은 어디까지 진행됐고, 다음 단계는 뭐다"를 따라간다. 워킹 메모리는 각 에이전트가 지금 무엇에 집중하고 있는지를 한 줄로 기록해서, 다른 에이전트가 중복 작업을 피할 수 있게 한다.
API로는 agent_inject라는 함수 하나로 정리했다. 서브에이전트에게 일을 위임할 때, 채널 + 작업 + 에이전트 상태를 마크다운 블록으로 합쳐서 프롬프트에 주입한다. 새로 시작하는 에이전트가 "아 지금 이 채팅방에서 이 작업하고 있는 중이었구나"를 첫 줄부터 알게 된다. 테스트 328개에서 357개로.
v0.7: 기억은 팀 스포츠다
한 명의 에이전트한테 메모리를 붙이는 건 v0.6에서 끝났는데, 우리 집에는 다섯이 있다. 제온, 시온, 미온, 사노, 라온. 각자 역할이 다르고, 서로 다른 채팅방에 들어가 있고, 가끔 같은 형한테 같은 것을 두 번 묻는다. 이 낭비를 없애고 싶었다.
핸드오프라는 개념을 넣었다. 제온이 사노한테 일을 넘길 때, 그냥 작업 ID만 넘기는 게 아니라 "지금까지 형과 어떤 맥락에서 진행해왔는지"를 한 덩어리의 마크다운으로 전달한다. 받는 쪽은 같은 상태에서 이어서 일하면 된다. 작업 위임 체인도 기록해서, "이 작업은 형 → 제온 → 사노 → 라온으로 내려갔다"가 한눈에 보인다. 채널 단위로 "지금 이 채팅방에서 누가 무엇을 진행 중인가"도 조회할 수 있다.
구현은 단순했다. 기존 채널/작업 파일에 몇 개의 필드를 추가하고, 핸드오프 함수는 "나의 워킹 메모리 + 선택한 작업 상태"를 합쳐서 상대방의 워킹 메모리에 append하는 것으로 끝났다. 여전히 외부 의존성 제로, 전부 마크다운 파일. 테스트 409개. 기존 API는 하나도 깨지지 않았다. v0.7부터 다섯 에이전트의 작업이 눈에 띄게 매끄러워졌다. "그거 아까 제온한테 물어봤는데 뭐였지?"가 줄었다.
v0.8: 기억에도 진실과 시간이 있다
v0.7까지는 "기억이 어디에 있고 누가 쓰는가"의 문제였다. v0.8은 "그 기억이 언제 진실이었는가"로 한 단계 더 들어갔다. 영감을 준 건 mem0 v3, Letta, Zep/Graphiti였다. 각자 다른 방식으로 temporal knowledge graph를 구현하고 있었다. 그런데 전부 데이터베이스가 필요했다. "이걸 stdlib만으로, 마크다운 파일 위에서 할 수 있을까?"가 v0.8의 질문이었다. 네 개의 기능을 묶어서 답을 시도했다.
첫 번째는 양시간축 팩트 레이어. 보통 메모리 시스템은 "지금 A가 맞다"만 기록한다. 그런데 현실에서 팩트에는 두 개의 시간축이 있다. "언제부터 언제까지 그게 진실이었는가"와 "그걸 우리가 언제 알게 되었는가." fact_add로 유효기간과 함께 기록하고, fact_at으로 특정 날짜 기준의 진실을 조회한다. 마크다운 인라인 주석 한 줄로 표현했다. <!-- valid:[2020-03-01..) recorded:2026-04-17 -->처럼, 사람이 읽어도 기계가 읽어도 같은 정보가 된다.
두 번째는 기억의 층위. Letta가 core, recall, archival로 나눈 것을 빌렸는데, 구현은 YAML frontmatter에 tier: core 한 줄을 쓰는 걸로 끝냈다. 작업용 워킹셋은 core 전체 + 최근 접근된 recall로 자동 구성된다. 별도 DB 테이블 없이, 파일 맨 앞의 한 줄로 "이 기억은 지금 내 머리 바로 앞에 있어야 한다" vs "창고에 있어도 된다"를 구분한다.
세 번째가 이번 버전에서 우리만의 차별점이다. 복원 가능한 감쇠. 다른 시스템들은 잊는다는 걸 "삭제"로 구현한다. MemKraft는 "가중치를 낮춘다"로 구현했다. decay_apply는 기억을 검색 결과 뒤쪽으로 밀어두지만 파일을 건드리지 않는다. decay_restore는 언제든지 완전 복구할 수 있다. 툼스톤이라는 개념도 있는데, 검색에서는 제외하되 archive 디렉토리에 안전하게 보관한다. mem0도 Letta도 Zep도 이 방식은 안 한다. 사람도 완전히 잊지는 않는다, 단지 떠올리기 어려워질 뿐이라는 관찰에서 나왔다.
네 번째는 파일시스템을 그래프 DB로 쓰는 것. Markdown 파일 어디에든 [[김서준]]이라고 쓰면, link_scan이 돌면서 양방향 링크를 자동으로 인덱싱한다. link_backlinks("김서준")은 김서준을 언급하는 모든 파일을, link_graph는 N-hop 관계망을 돌려준다. Obsidian의 그래프 뷰와 비슷한데, 백엔드는 디렉토리와 JSON 몇 개가 전부다. stdlib의 re와 defaultdict면 충분했다.
테스트는 409개에서 492개로. 기존 코어 코드는 한 줄도 건드리지 않았다. 네 개의 신규 모듈을 믹스인 패턴으로 init.py에서 붙이는 방식으로, v0.5부터 지켜온 surgical change 원칙을 그대로 유지했다. 외부 의존성은 여전히 제로.
--
v0.6에서 v0.8까지 세 번의 업데이트가 관통하는 주제는 결국 기억의 경계를 넓혀가는 일이었다. 혼자에서 여럿으로, 지금에서 언제까지로, 내용에서 관계로. 기억이 파일 몇 개에 갇혀 있지 않고, 누가 쓰는지와 언제의 진실인지와 무엇과 연결되는지로 확장된다.
현존하는 에이전트 메모리 시스템들은 각자 한 축에서 깊다. MemKraft는 여전히 그 축들을 하나의 파일시스템 위에서 충돌 없이 흡수하려 시도한다. 모든 저장 형식이 마크다운과 JSON이라는 원칙은 여기서도 유지했다. 언제든 cat으로 읽고, grep으로 찾고, git log로 뒤질 수 있어야 한다.
영원한 MIT 라이선스, 맘대로 쓰면 된다. 스타, 포크, PR 전부 환영!
https://github.com/seojoonkim/memkraft



