Hermes Agent, Agent Memory Layer

7,511 단어·16 분·원문(.md)

대상: hermes-agent(NousResearch) 네이티브 메모리 + oh-my-hermes(OMH)가 얹는 확장 레이어 기준일: 2026-08-01


0. 왜 메모리를 "층"으로 나누나요? #

에이전트가 기억해야 하는 정보는 성격이 전부 다릅니다. "이 사람은 존댓말을 선호한다"는 사실은 매 턴 프롬프트에 있어야 쓸모가 있고, "3주 전 목요일에 Redis 커넥션 풀 이슈를 이렇게 고쳤다"는 사실은 그 얘기가 나올 때만 필요합니다. 앞의 것을 창고에 넣으면 영영 안 꺼내지고, 뒤의 것을 프롬프트에 넣으면 컨텍스트가 며칠 만에 터집니다.

그래서 축을 두 개 잡습니다.

  • 상주성(residency): 항상 프롬프트에 있는가, 요청할 때만 읽는가
  • 변동성(volatility): 거의 안 바뀌는가, 매 턴 쌓이는가

이 두 축을 따라 4단계로 자른 것이 L0 ~ L3입니다. 위쪽(L0)은 작고 안 바뀌고 항상 켜져 있으며, 아래로 갈수록 커지고 자주 바뀌고 필요할 때만 꺼냅니다.


1. 전체 그림은 어떻게 생겼나요? #

이름소유자저장 매체크기프롬프트 상주쓰기 주체
L0soul / persona사람 (관례상)설정 파일아주 작음항상사람만
L1MEMORY.md + USER.md에이전트 (큐레이션)Markdown 2개하드캡 (기본 2200자 / 1375자)항상 (세션 시작 시 스냅샷)에이전트
L2memory blocks (OMH)OMH + 리뷰어.omh/memory/*.json블록별 상한, 2티어라벨만 상주, 본문은 온디맨드OMH 캡처 → 사람 승인
L3session store런타임SQLite FTS5 (~/.hermes/state.db)무제한없음자동 (원본 로그)

렌더 파이프라인은 매 턴 이런 모양이 됩니다.

[L0 soul]  ─┐
[L1 core]  ─┼→ 시스템 프롬프트 (총 6000자 예산 안에서 렌더)
[L2 라벨목록] ┘        ↑
                  넘치면 overflow 표시 (무음 절단 금지)

[L2 블록 본문] ← 라벨 보고 필요할 때 read
[L3 세션 원본] ← session_search 질의 또는 provider prefetch

핵심은 예산이 프롬프트 쪽에만 걸린다는 점입니다. L3는 아무리 커져도 프롬프트 비용이 0이고, L1은 1KB만 커져도 매 턴 비용이 붙습니다.


2. 알바생 비유 #

카페에 새 알바생(에이전트)이 들어왔다고 생각해 보겠습니다.

L0 — 첫날 사장님이 정해준 가게 성격 "우리는 조용한 동네 카페고, 손님한테 먼저 말 걸지 않습니다." 알바생이 바꿀 수 없고, 근무 내내 머리에 깔려 있습니다. 사장님(사람)만 고칩니다.

L1 — 계산대 옆에 코팅해서 붙여둔 A4 한 장 "에스프레소 머신 2번 그룹헤드 압력 이상함", "단골 김 선생님은 얼음 적게". 눈만 들면 보이고, 매 손님 응대에 자동으로 반영됩니다. 대신 A4 한 장을 넘길 수 없습니다. 꽉 찼는데 새 메모를 붙이려 하면, 오래된 걸 몰래 지우는 대신 "자리 없음, 정리부터 하세요"라고 거절합니다. 그리고 이 A4는 출근할 때 사진을 찍어 머리에 넣는 방식이라, 근무 중에 새로 적은 메모는 파일에는 남지만 오늘 머릿속 사진에는 안 들어옵니다. 다음 출근 때 반영됩니다.

L2 — 라벨 붙은 서랍장 서랍 겉면에 "원두 발주 절차", "포스기 오류 대응", "지난달 매장 정책 변경"이라고 라벨만 보입니다. 알바생은 서랍 목록은 항상 알고 있고, 필요할 때 해당 서랍만 엽니다. 서랍 하나에 넣을 수 있는 양도 정해져 있습니다. 새로 알게 된 내용은 일단 "미확인 함"에 들어가고, 점장이 확인해야 정식 서랍으로 옮겨집니다.

L3 — 창고에 쌓인 영수증·근무일지 박스 전부 버리는 게 없습니다. 다만 통째로 읽는 건 불가능해서, "6월에 우유 납품 지연" 같은 키워드로 검색해서 해당 장만 꺼내 봅니다.

이 비유에서 자연스럽게 나오는 규칙이 실제 설계 규칙과 그대로 맞물립니다.

  • A4를 서랍 대신 쓰면 정확도가 떨어집니다. → L1을 작업 일지로 쓰면 안 됩니다
  • 창고 영수증을 A4에 옮겨 적기엔 유실된 내용들이 많을 수 있습니다. → L3 원본은 L1으로 승격되지 않습니다
  • 서랍 라벨이 부실하면 알맞는 서랍을 열 수 없습니다. → L2는 라벨 품질이 성능입니다 (recall 성능 중요)

3. L0 — soul / persona #

무엇인가요. 에이전트의 정체성, 말투, 역할 경계, 넘지 말아야 할 선. Hermes에서는 페르소나/시스템 지시 영역에 해당합니다.

왜 따로 두나요. 이 층이 에이전트 자기 자신에 의해 수정 가능하면, 긴 세션을 돌면서 정체성이 서서히 드리프트합니다. 그래서 OMH 스택에서는 "human owned by convention" — 규약상 사람만 손대는 층으로 못 박습니다. 코드로 막는 게 아니라 운영 규약으로 막는다는 점이 중요합니다.

엔지니어링 포인트.

  • 거의 안 바뀌므로 프롬프트 캐시 프리픽스의 맨 앞에 두기 좋습니다.
  • 서브에이전트에게도 동일하게 복사됩니다.
  • 크기는 수백 토큰 수준으로 유지합니다. 여기가 커지면 아래 세 층 전체의 예산이 깎입니다.

4. L1 — MEMORY.md + USER.md (코어 메모리) #

무엇인가요. Hermes 네이티브 큐레이션 메모리입니다. 프로필별 $HERMES_HOME/memories/ 아래에 마크다운 파일 두 개로 존재합니다.

  • MEMORY.md — 에이전트 노트: 환경 사실, 프로젝트 관례, 툴 특이사항, 안정된 교훈. 기본 상한 2200자 (약 800토큰)
  • USER.md — 사용자 프로필: 선호, 커뮤니케이션 방식. 기본 상한 1375자 (약 500토큰)

설정은 ~/.hermes/config.yaml에서 조정합니다.

memory:
  memory_enabled: true
  user_profile_enabled: true
  memory_char_limit: 2200
  user_char_limit: 1375
  write_approval: false   # true면 쓰기 시 승인 요구

동작 특성 (여기가 중요합니다).

  1. frozen snapshot 주입. 세션 시작 시점에 시스템 프롬프트에 통째로 박힙니다. 세션 중간에 쓴 내용은 디스크에 즉시 저장되지만, 활성 프롬프트는 다음 세션 또는 프롬프트 재빌드 전까지 그대로입니다. 이 성질 덕분에 프롬프트 프리픽스가 세션 내내 고정되고, 프롬프트 캐싱이 걸립니다.
  2. read 액션이 없습니다. 메모리 툴은 add / replace / remove만 지원합니다. 이미 프롬프트에 있으니 읽을 이유가 없습니다.
  3. 하드캡 초과 시 자동 압축 대신 쓰기 거부. OMH 스택이 강조하는 지점입니다. 자동 요약은 조용히 정보를 태우고, 어떤 문장이 사라졌는지 아무도 모릅니다. 거부하면 사람이나 상위 워크플로가 "정리"라는 명시적 행동을 하게 됩니다.
  4. 엔트리 구분자는 § 이고, 디스크에 쓰기 전 _scan_memory_content가 프롬프트 인젝션·역할 탈취·유출 패턴을 strict 스코프로 검사합니다.

여기 넣으면 안 되는 것. 진행 중 작업 상태, 티켓 번호, 임시 결정, 로그. L1은 작업 일지가 되는 순간 망가집니다.


5. L2 — memory blocks (OMH가 추가하는 층) #

무엇인가요. 라벨이 달린 블록 단위의 리뷰된 장기 컨텍스트입니다. Hermes 네이티브에는 없고 OMH가 채워 넣는 자리입니다.

구조 (OMH 프로젝트 메모리 기준).

.omh/memory/
  candidates/*.json   # 캡처됐지만 아직 리뷰 전
  records/*.json      # 승인된 정식 레코드
  reviews/*.json      # 승인/거절 결정 기록
  index.json          # 로컬 파일 인벤토리

레코드 타입은 다섯 가지로 고정되어 있습니다.

타입의미예시
fact변하지 않는 사실"이 레포는 Python 3.11+ 대상"
decision내려진 결정과 그 이유"인증은 세션 쿠키로 간다, JWT 폐기"
lesson실패에서 얻은 교훈"이 마이그레이션은 인덱스 먼저 만들어야 안 죽음"
procedure재현 가능한 절차"워크플로 계약 변경 후 unittest discovery 실행"
episode특정 사건"8/1 배포 롤백 건" — 기본 TTL 짧음

두 티어. 블록은 두 단계로 나뉩니다. 항상 렌더되는 티어와, 라벨만 노출하고 본문은 온디맨드로 읽는 티어입니다. 매 턴 6000자 예산 안에서 렌더되고, 예산을 넘기면 overflow가 명시적으로 표시됩니다. 조용히 잘리는 경우가 없습니다.

안전 규칙. 캡처는 원본 텍스트를 저장하지 않습니다. 해시, 길이, 타입화된 요약, 리뷰 메타데이터만 남깁니다. 로컬 안전 분류기가 다음을 차단하거나 리뷰 대상으로 강제합니다.

  • credential처럼 보이는 문자열
  • 원시 로그와 트레이스백
  • 전체 대화 트랜스크립트
  • 수명이 짧은 PR·커밋 식별자
  • 임시 작업 진행 상황
  • 비정상적으로 긴 원문

차단된 후보는 승인 자체가 불가능합니다. 안전하고 경계가 잡힌 요약으로 다시 캡처하거나 거절해야 합니다.

정책 모드. omh setupproject_memory_policy/v1.omh/setup-profile.json에 기록합니다.

omh setup --memory-mode review-first   # 기본값: 캡처 후 리뷰 통과해야 recall
omh setup --memory-mode auto-safe      # 안전 검사 통과분은 자동 승인, 위험분만 리뷰
omh setup --memory-mode off            # 자동 캡처·recall 비활성

CLI 흐름.

omh memory capture --type procedure --tag tests "워크플로 계약 변경 후 unittest discovery 실행"
omh memory review
omh memory approve cand_1234 --approved-by user
omh memory reject  cand_1234 --reason "임시 작업 진행 상황"
omh memory recall  --executor codex "workflow docs verification"
omh memory status

6. L3 — session store (FTS5) #

무엇인가요. 모든 CLI·메신저 세션이 SQLite(~/.hermes/state.db)에 원본 그대로 저장되고, FTS5 전문 인덱스가 붙습니다. messages_ftsmessages_fts_trigram 두 인덱스를 사용합니다.

한글을 쓴다면 여기를 확인해야 합니다. FTS5는 기본적으로 공백으로 단어를 나눕니다. 한국어·중국어·일본어는 그렇지 않기 때문에, Hermes는 native/fts5_cjk/에 네이티브 CJK 토크나이저 확장을 두고 messages_fts가 이를 쓰도록 합니다. 이 확장이 로드되지 않으면 한글 세션 검색이 조용히 빈 결과를 돌려줍니다. 자체 L3를 만들 때 가장 먼저 확인할 항목입니다.

접근 방법. session_search 툴이 세 가지 호출 형태를 가집니다.

  • discovery — 키워드로 어느 세션에 있었는지 찾기
  • scroll — 찾은 세션 안에서 앞뒤로 이동 (session_id + around_message_id)
  • browse — 세션 훑기

검색 결과는 DB의 실제 메시지를 그대로 돌려줍니다. LLM 요약도, 절단도 없습니다.

한계를 알고 써야 합니다. FTS5는 토큰 일치 기반입니다. 과거 세션에 "authentication microservice uses Redis"라고 적혀 있을 때 "auth 서비스에 대해 뭐라고 했었지?"로 질의하면 안 걸릴 수 있습니다. 의미 기반 회수가 필요하면 L2 블록이나 외부 벡터 provider가 그 간극을 메워야 합니다.

또 하나, 에이전트가 검색을 호출하기로 결정해야 합니다. 이 판단 부담을 줄이려고 OMH는 memory-provider seam에 붙어서 prefetch로 recall이 먼저 도착하게 만듭니다. 에이전트가 "찾아봐야겠다"고 생각하지 않아도 관련 컨텍스트가 이미 와 있는 구조입니다.


7. 용어 정리 #

용어
core memory항상 프롬프트에 상주하는 소량 메모리. 여기서는 L1
frozen snapshot세션 시작 시 고정 주입되어 세션 내내 안 바뀌는 프롬프트 조각
prompt caching프롬프트 앞부분이 동일할 때 재계산을 생략하는 최적화. L0/L1이 안 흔들려야 걸립니다
residency상주 여부. 항상 프롬프트에 있는가, 요청 시 읽는가
memory provider seamHermes가 외부 메모리 구현체를 끼우도록 열어둔 확장 지점 (agent/memory_provider.py, MemoryManager가 오케스트레이션, 동시에 1개만 활성)
prefetch에이전트가 요청하기 전에 응답 직전 단계에서 관련 메모리를 미리 당겨오는 것
consolidation아래층의 여러 항목을 위층의 요약 한 덩어리로 승격시키는 과정
eviction예산 초과 시 항목을 밀어내는 것
compaction컨텍스트가 찼을 때 대화 이력을 요약해 줄이는 런타임 동작
TTL / staleness레코드의 유효 기한과 신선도 메타데이터. 만료분은 recall에서 제외
source priority같은 주제에 여러 출처가 있을 때 어느 쪽을 믿을지의 순위
prepared ≠ observed준비된 컨텍스트와 실제로 관측된 실행 증거를 절대 섞지 않는 원칙
recall pack코딩 핸드오프에 붙는 압축된 메모리 묶음 (memory_recall_pack/v1)
context pack충돌 없는 메타데이터 전용 컨텍스트 (handoff_context_pack/v1)

8. "L0~L3"이라는 라벨의 혼선 #

같은 생태계 안에서 L 번호가 세 가지 다른 의미로 쓰이고 있습니다. 문서를 읽을 때 반드시 구분해야 합니다.

(A) 상주성 계층 — 이 노트가 다루는 것 L0 페르소나 → L1 코어 → L2 블록 → L3 세션 원본.
번호가 커질수록 양이 많아지고 상주성이 낮아집니다.

(B) 해상도 계층 — OpenViking 방식 한 항목을 세 해상도로 저장합니다. L0은 한 문장 요약(약 50100토큰), L1은 핵심 정보와 사용 시나리오(약 5002k토큰), L2는 원문 전체입니다. 에이전트가 L0부터 읽고 필요할 때만 위로 올라갑니다. 공개된 벤치마크 기준 전체 컨텍스트를 매 턴 로드하는 방식 대비 80~90% 토큰 절감을 주장합니다.
번호가 커질수록 같은 항목이 더 자세해집니다.

(C) 추상화 사다리 — TencentDB Agent Memory 방식 L0 원시 대화 → (N턴마다 LLM 추출) L1 원자적 사실 → (50개마다 합성) L2 시나리오 → L3 페르소나.
번호가 커질수록 더 추상적입니다. (A)와 방향이 정반대입니다.

세 스킴 모두 "L0~L3"이라고 부르므로, 설계 문서를 쓸 때는 축 이름을 함께 적어두는 편이 안전합니다. 예: L2 (residency tier), L1 (resolution tier).


9. 대표 스택 #

레이어별 구현 후보

이 스택의 구현같은 자리를 채우는 다른 선택지
L0설정 파일 기반 페르소나시스템 프롬프트 템플릿, Letta의 persona 블록
L1Markdown 2파일 + 문자 상한Letta/MemGPT core memory 블록, CLAUDE.md 계열 프로젝트 지침 파일
L2OMH .omh/memory/ JSON 레코드Mem0, Zep/Graphiti(시간 지식그래프), Cognee, Letta archival memory, ByteRover(Markdown 지식트리)
L3SQLite FTS5pgvector/Postgres, Qdrant·Weaviate·LanceDB, BM25+벡터 하이브리드 + 리랭커

Hermes 생태계의 외부 provider들 (2026년 4월 기준 8종) OpenViking(viking:// 스킴, L0/L1/L2 티어 로딩, AGPL, 자체 호스팅), Mem0(플랫폼/셀프호스트/OSS 3모드), Hindsight(LongMemEval 94.6%, PostgreSQL 로컬), Honcho(사용자 모델링), Holographic(순수 SQLite, HRR 대수 질의), RetainDB(벡터+BM25+리랭킹), ByteRover, agentmemory 등.
동시에 활성화되는 외부 provider는 한 개입니다. 빌트인 L1은 그와 무관하게 계속 동작하며, 외부 provider는 더해지는 층입니다.

OMH의 현재 백엔드 입장 v1 정책은 local_json을 현재 백엔드로 명시하고, Mem0·Graphiti·Cognee·Letta 등을 옵션 어댑터로 붙일 수 있는 확장 이음새로만 남겨두었습니다. 의존성·프라이버시·패키징 경계가 명시적일 때만 추가한다는 조건이 붙어 있습니다.


10. 층끼리 어떻게 상호작용시켜야 하나요? #

10-1. 읽기 경로 (매 턴) #

턴 시작
 ├ L0 렌더 (고정)
 ├ L1 렌더 (세션 시작 스냅샷, 세션 내 불변)
 ├ L2 라벨 목록 렌더 + 상시 티어 블록 렌더
 │    └ 6000자 예산 초과분 → overflow 마킹
 ├ provider prefetch → 관련 L2/L3 후보를 미리 당김
 └ 모델 판단으로 L2 블록 read / L3 session_search

설계 원칙 세 개.

  1. 위층일수록 좁고 조용하게. L1에 뭘 넣을지 고민된다면 넣지 않는 쪽이 대체로 맞습니다.
  2. 라벨이 인터페이스입니다. L2 블록의 라벨만 보고 열지 말지를 결정하므로, 라벨은 "제목"이 아니라 "언제 열어야 하는지"를 담아야 합니다. 배포절차 보다 배포 롤백 시 확인할 순서가 좋습니다.
  3. overflow는 반드시 보이게. 잘렸다는 사실이 숨겨지면 에이전트가 불완전한 정보를 완전한 정보로 착각합니다.

10-2. 쓰기 경로 (승격) #

L3 원본 로그
  │ (턴 카운트 도달 또는 compaction 관측 시 consolidation)
  ↓
L2 candidate  ──안전 분류기──→ 차단 / 리뷰 필요 / 통과
  │ (사람 또는 auto-safe 정책이 승인)
  ↓
L2 record (타입 + TTL + staleness)
  │ (반복 참조되고 프로젝트 전역에 해당하면)
  ↓
L1 (사람이 명시적으로 옮김, 자리 확보 후)

승격 트리거를 시간으로 잡지 마세요. OMH 스택은 consolidation을 턴 카운트 또는 관측된 compaction 이벤트에 걸어둡니다. compaction이 일어난다는 것은 곧 원본이 사라진다는 뜻이므로, 그 직전이 승격의 마지막 기회입니다. 10시간짜리 장기 루프에서 초반 결정이 후반에 소실되는 문제는 정확히 이 지점의 설계 문제입니다. 초반 decision 레코드가 compaction 전에 L2로 올라가 있으면, 후반 턴에서 라벨을 보고 다시 읽을 수 있습니다.

10-3. 퇴출 (eviction) #

oldest-first를 쓰지 않습니다. 오래된 항목이 덜 중요하다는 보장이 없고, 프로젝트 초기의 아키텍처 결정은 가장 오래됐으면서 가장 오래 유효합니다.

대신 증명 가능한 중복(provable redundancy) 만 퇴출 근거로 인정합니다. 즉 "이 항목의 내용이 다른 항목에 완전히 포함된다"를 보일 수 있을 때만 지웁니다. 이 규칙 때문에 엔트리에 순서 판정용 타임스탬프를 두지 않습니다.

TTL은 별개 축입니다. episode 타입처럼 태생적으로 수명이 짧은 레코드에는 TTL이 붙고, 만료되면 recall 대상에서 빠집니다. "오래돼서 지운다"와 "수명이 정해져 있어서 만료된다"는 다른 규칙이므로 구현에서 분리해 두는 편이 좋습니다.

10-4. 충돌 해소 (source priority) #

충돌 검토는 별도 표면으로 스키마화되어 있습니다. "지금 기억하고 있는 게 아직 유효한가"를 사용자가 파일을 직접 열어 보지 않고 카드로 확인할 수 있게 하려는 설계입니다.

스키마용도
memory_snapshot/v1래퍼가 제공하거나 OMH가 로컬에서 찾은 컨텍스트 소스
memory_inspection/v1소스 인벤토리, 충돌 탐지, 리뷰 항목, 프리뷰
memory_review_card/v1래퍼가 렌더하는 리뷰 UI (status_card/v1과 분리)
memory_update_batch/v1사용자가 승인한 keep / forget / update / scope 결정
handoff_context_pack/v1실행자 핸드오프에 붙는 충돌 없는 메타데이터 전용 컨텍스트

같은 주제에 여러 출처가 있으면 OMH는 아래 순서로 신뢰합니다.

  1. run-ledger 아티팩트의 런타임 증거
  2. 래퍼 세션 상태
  3. 런타임 상태 인덱스
  4. 타깃 토폴로지
  5. 셋업 프로파일
  6. 승인된 OMH 메모리
  7. 위키 / 노트
  8. 카탈로그 힌트
  9. 래퍼 스냅샷 후보

상위 출처가 하위 출처의 오래된 가정을 차단할 수 있습니다. 그리고 충돌이 남아 있으면 핸드오프에 컨텍스트를 붙이지 않고 context_pack_blocked를 충돌 목록과 함께 기록합니다. 오래된 컨텍스트가 실행자 프롬프트에 섞여 들어가 가짜 증거가 되는 경로를 막는 장치입니다.

10-5. 멀티 에이전트에서의 쓰기 권한 #

서브에이전트는 읽되 쓰지 않습니다. 병렬 서브에이전트가 각자 L1/L2에 쓰기 시작하면 순서 없는 병합, 상호 모순, 그리고 한 서브에이전트의 국소적 착각이 전역 사실로 굳는 문제가 동시에 발생합니다. 쓰기는 오케스트레이터 한 곳으로 모읍니다.

10-6. prepared ≠ observed #

메모리에 "이렇게 하기로 했다"가 있는 것과 "실제로 그렇게 실행됐다"는 완전히 다른 사실입니다. OMH는 모든 리뷰·recall 페이로드에 이것이 준비된 컨텍스트일 뿐이며 실행·리뷰·CI·머지·Hermes 내부 메모리의 증거가 아니라고 명시합니다.

메모리 시스템을 만들 때 이 구분을 스키마 레벨에서 강제하지 않으면, 몇 주 뒤에 에이전트가 자기가 계획했던 일을 완료된 일로 보고하기 시작합니다.


11. 설계 시 결정해야 하는 항목 (체크리스트) #

  • L1 상한을 몇 자로 잡을 것인가, 초과 시 거부인가 압축인가
  • L2 블록 하나의 상한과 상시 티어 / 온디맨드 티어의 분할 기준
  • 매 턴 렌더 예산 총액 (여기서는 6000자)
  • consolidation 트리거: 턴 카운트 임계값, compaction 관측 훅
  • eviction 근거: 중복 증명 방식 (해시 포함 관계? 의미 유사도 임계값?)
  • TTL 기본값: 타입별로 다르게 줄 것인가
  • 승인 정책: review-first / auto-safe / off 중 기본값
  • 안전 분류기가 막을 패턴 목록
  • source priority 순서와 충돌 시 차단 정책
  • 서브에이전트 쓰기 권한 (기본은 금지)
  • L3 회수가 키워드 전용인가, 의미 검색을 붙일 것인가

12. 흔한 실패 모드 #

증상원인대응
며칠 뒤 L1이 잡동사니로 가득진행 상황을 L1에 씀타입 강제 (fact/decision/lesson/procedure), 진행 상황은 캡처 단계에서 차단
오래 돌린 루프 후반에 초반 결정과 모순되는 수정compaction으로 초반 결정 소실compaction 관측을 consolidation 트리거로 등록, 초반 decision을 L2로 승격
메모리에 다 있는데 에이전트가 안 씀L2 라벨이 부실하거나 회수 호출 판단 실패라벨을 "언제 열어야 하는지"로 재작성, prefetch로 판단 부담 제거
과거 얘기가 검색이 안 됨FTS5 토큰 불일치동의어 확장, L2 요약에 검색용 키워드 포함, 의미 검색 provider 병행
에이전트가 계획을 완료로 보고prepared / observed 미분리스키마 레벨에서 분리, 핸드오프에 증거 경계 명시
프롬프트 캐시가 안 걸림상위 층이 매 턴 흔들림L1을 세션 시작 스냅샷으로 고정, 세션 중 쓰기는 디스크에만 반영
승인 안 된 컨텍스트가 실행자 프롬프트로 유출충돌 검사 없이 팩 부착blocked_by_conflicts가 비었을 때만 부착, 아니면 context_pack_blocked

13. 참고 #

AI/hermes_memory.md