GEODE의 기억은 다섯 계층으로 나뉩니다. 위로 갈수록 안정적이고 아래로 갈수록 구체적입니다. 매 호출 전에 core/memory/context.py의 ContextAssembler가 다섯 계층을 병합해 LLM에 넣을 단일 요약을 만듭니다.
다섯 계층
| Tier | 이름 | 소스 |
|---|---|---|
| 0 | Identity | SOUL.md |
| 0.5 | User Profile | core/memory/user_profile.py (FileBasedUserProfile) |
| 1 | Organization | core/memory/organization.py (MonoLakeOrganizationMemory) |
| 2 | Project | core/memory/project.py (ProjectMemory) |
| 3 | Session | SessionStorePort (core/memory/port.py) |
병합 순서가 곧 override 규칙입니다. 같은 내용이 충돌하면 아래 계층(더 구체적인 쪽)이 위 계층을 덮습니다. 프로젝트 기억이 조직 기억을, 세션 기억이 프로젝트 기억을 이깁니다.
예산 인식 압축
요약은 max_chars 예산 아래로 맞춰집니다. 계층별 비례 배분은 SOUL 10%, Organization 25%, Project 25%이고 Session이 나머지를 가져갑니다. 세션 내용은 최신 항목부터 남은 예산에 채워 넣으므로, 예산이 모자라면 가장 오래된 대화부터 떨어져 나갑니다.
/recall: 저장 기억 풀
계층 병합과 별도로, 이름 붙여 저장하는 영속 기억 풀이 있습니다. 슬래시 명령 /recall(핸들러 core/cli/commands/recall.py)로 목록, 조회, 저장을 합니다.
| 구성요소 | 동작 |
|---|---|
| Writer | core/memory/recall_writer.py의 write_recall_entry가 frontmatter 달린 마크다운을 ~/.geode/memory/recall/에 씁니다 (GEODE_MEMORY_RECALL_DIR env로 위치 변경 가능) |
| Reader | 로더가 ~/.geode/memory/recall/*.md를 키워드 겹침과 최근성으로 랭킹해 <memory-recall> 블록으로 시스템 프롬프트 앞에 붙입니다 |
| 비자동 | 세션 종료 시 자동 저장하지 않습니다. 노이즈와 비용을 막기 위한 의도적 결정으로, 저장은 항상 명시적입니다 |
세션 저장소
| 구현 | 코드 | 용도 |
|---|---|---|
| InMemorySessionStore | core/memory/session.py | dict + TTL, 선택적 파일 영속화 |
| SessionManager (SQLite) | core/memory/session_manager.py | 프로젝트별 sessions.db (~/.geode/projects/ 아래) |
| Episodic | core/memory/episodic.py | append-only ~/.geode/memory/episodes.jsonl |
sessions.db에는 트랜스크립트 외에 context_artifacts도 있습니다. dreaming 서비스가 턴 경로 밖에서 합성해 되쓰는 dream 레코드로, 조립 상세는 컨텍스트 조립에서 다룹니다.
기억 수명주기: 증거 기반 소멸
프로젝트 기억은 시간이 아니라 증거로 정리됩니다. geode memory-lifecycle(core/cli/commands/memory_lifecycle.py)는 두 가지를 합니다. (1) 소멸 — resolution.guard_test가 아직 트리에 존재하는 항목은 .geode/memory/_archive/로 아카이빙하고(주입에서 제외), 가드 테스트가 사라진 항목은 다시 떠오릅니다(WARNING). 시간 기반 소멸은 없습니다. (2) 승격 제안 — dreaming이 남긴 context_artifacts(dream)와 활성 항목을 클러스터링해, 서로 다른 세션 3개 이상에 걸친 클러스터를 .geode/memory/_proposals/ 아래 HITL 제안 파일로 씁니다. 규칙은 블라스트 반경이 크므로 절대 자동 기록하지 않습니다. 기본은 dry-run이고, --apply가 파일을 옮기고 제안을 쓰며 MEMORY_PROMOTION_PROPOSED 훅을 발화합니다.
sessions.jsonl: 런 메트릭
자기개선 루프의 매 런은 토큰, 비용, 재시도, 검증 카운터를 행 하나로 남깁니다. core/observability/session_metrics.py의 SessionMetrics.to_session_row()가 행을 만들고, core/self_improving/train.py가 런 단위로 메트릭을 시드해 세션 인덱스에 합칩니다. 파일 위치는 core/self_improving/ledger.py의 SESSIONS_INDEX_PATH가 SoT입니다.
실패 모드
| 증상 | 원인 | 해법 |
|---|---|---|
| 저장했다고 생각한 기억이 다음 세션에 없음 | 세션 계층은 휘발성이고 recall 풀은 자동 저장되지 않음 | /recall save <name>으로 명시적으로 저장합니다 |
| 오래된 대화 내용이 요약에서 사라짐 | 세션 예산을 최신 항목부터 채우는 압축 규칙 | 정상 동작입니다. 중요한 결론은 recall 풀이나 프로젝트 기억으로 승격합니다 |
| 조직 규칙과 프로젝트 규칙이 충돌 | 계층 override가 의도된 동작 | 아래 계층이 이깁니다. 전역으로 강제할 내용은 위 계층에만 둡니다 |