claude-memory-layer 1.0.11 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/AGENTS.md +60 -0
  2. package/README.md +166 -2
  3. package/bootstrap-kb/decisions/decisions.md +244 -0
  4. package/bootstrap-kb/glossary/glossary.md +46 -0
  5. package/bootstrap-kb/modules/.claude-plugin.md +22 -0
  6. package/bootstrap-kb/modules/agents.md.md +15 -0
  7. package/bootstrap-kb/modules/claude.md.md +15 -0
  8. package/bootstrap-kb/modules/context.md.md +15 -0
  9. package/bootstrap-kb/modules/docs.md +18 -0
  10. package/bootstrap-kb/modules/handoff.md.md +15 -0
  11. package/bootstrap-kb/modules/package-lock.json.md +15 -0
  12. package/bootstrap-kb/modules/package.json.md +15 -0
  13. package/bootstrap-kb/modules/plan.md.md +15 -0
  14. package/bootstrap-kb/modules/readme.md.md +15 -0
  15. package/bootstrap-kb/modules/scripts.md +26 -0
  16. package/bootstrap-kb/modules/spec.md.md +15 -0
  17. package/bootstrap-kb/modules/specs.md +20 -0
  18. package/bootstrap-kb/modules/src.md +51 -0
  19. package/bootstrap-kb/modules/tests.md +42 -0
  20. package/bootstrap-kb/modules/tsconfig.json.md +15 -0
  21. package/bootstrap-kb/modules/vitest.config.ts.md +15 -0
  22. package/bootstrap-kb/overview/overview.md +40 -0
  23. package/bootstrap-kb/sources/manifest.json +950 -0
  24. package/bootstrap-kb/sources/manifest.md +227 -0
  25. package/bootstrap-kb/timeline/timeline.md +57 -0
  26. package/d.sh +3 -0
  27. package/deploy.sh +3 -0
  28. package/dist/cli/index.js +2389 -286
  29. package/dist/cli/index.js.map +4 -4
  30. package/dist/core/index.js +1017 -132
  31. package/dist/core/index.js.map +4 -4
  32. package/dist/hooks/post-tool-use.js +1347 -202
  33. package/dist/hooks/post-tool-use.js.map +4 -4
  34. package/dist/hooks/session-end.js +1339 -194
  35. package/dist/hooks/session-end.js.map +4 -4
  36. package/dist/hooks/session-start.js +1343 -198
  37. package/dist/hooks/session-start.js.map +4 -4
  38. package/dist/hooks/stop.js +1351 -206
  39. package/dist/hooks/stop.js.map +4 -4
  40. package/dist/hooks/user-prompt-submit.js +1347 -202
  41. package/dist/hooks/user-prompt-submit.js.map +4 -4
  42. package/dist/server/api/index.js +1436 -211
  43. package/dist/server/api/index.js.map +4 -4
  44. package/dist/server/index.js +1445 -220
  45. package/dist/server/index.js.map +4 -4
  46. package/dist/services/memory-service.js +1345 -199
  47. package/dist/services/memory-service.js.map +4 -4
  48. package/dist/ui/app.js +69 -2
  49. package/dist/ui/index.html +8 -0
  50. package/docs/MCP_MEMORY_SERVICE_COMPARATIVE_REVIEW.md +271 -0
  51. package/docs/MEMU_ADOPTION.md +40 -0
  52. package/memory/.claude-plugin/commands/2026-02-25.md +263 -0
  53. package/memory/_index.md +405 -0
  54. package/memory/default/uncategorized/2026-02-25.md +4839 -0
  55. package/memory/specs/20260207-dashboard-upgrade/2026-02-25.md +142 -0
  56. package/memory/specs/citations-system/2026-02-25.md +1121 -0
  57. package/memory/specs/endless-mode/2026-02-25.md +1392 -0
  58. package/memory/specs/entity-edge-model/2026-02-25.md +1263 -0
  59. package/memory/specs/evidence-aligner-v2/2026-02-25.md +1028 -0
  60. package/memory/specs/mcp-desktop-integration/2026-02-25.md +1334 -0
  61. package/memory/specs/post-tool-use-hook/2026-02-25.md +1164 -0
  62. package/memory/specs/private-tags/2026-02-25.md +1057 -0
  63. package/memory/specs/progressive-disclosure/2026-02-25.md +1436 -0
  64. package/memory/specs/task-entity-system/2026-02-25.md +924 -0
  65. package/memory/specs/vector-outbox-v2/2026-02-25.md +1510 -0
  66. package/memory/specs/web-viewer-ui/2026-02-25.md +1709 -0
  67. package/package.json +2 -1
  68. package/scripts/build.ts +6 -0
  69. package/src/cli/index.ts +281 -2
  70. package/src/core/consolidated-store.ts +63 -1
  71. package/src/core/consolidation-worker.ts +115 -6
  72. package/src/core/event-store.ts +14 -0
  73. package/src/core/index.ts +1 -0
  74. package/src/core/ingest-interceptor.ts +80 -0
  75. package/src/core/markdown-mirror.ts +70 -0
  76. package/src/core/md-mirror.ts +92 -0
  77. package/src/core/mongo-sync-config.ts +165 -0
  78. package/src/core/mongo-sync-worker.ts +381 -0
  79. package/src/core/retriever.ts +540 -150
  80. package/src/core/sqlite-event-store.ts +350 -1
  81. package/src/core/tag-taxonomy.ts +51 -0
  82. package/src/core/types.ts +28 -0
  83. package/src/server/api/health.ts +53 -0
  84. package/src/server/api/index.ts +3 -1
  85. package/src/server/api/stats.ts +46 -1
  86. package/src/services/bootstrap-organizer.ts +443 -0
  87. package/src/services/codex-session-history-importer.ts +474 -0
  88. package/src/services/memory-service.ts +373 -68
  89. package/src/ui/app.js +69 -2
  90. package/src/ui/index.html +8 -0
  91. package/tests/bootstrap-organizer.test.ts +111 -0
  92. package/tests/consolidation-worker.test.ts +75 -0
  93. package/tests/ingest-interceptor.test.ts +38 -0
  94. package/tests/markdown-mirror.test.ts +85 -0
  95. package/tests/md-mirror.test.ts +50 -0
  96. package/tests/retriever-fallback-chain.test.ts +223 -0
  97. package/tests/retriever-strategy-scope.test.ts +97 -0
  98. package/tests/retriever.memu-adoption.test.ts +122 -0
  99. package/tests/sqlite-event-store-replication.test.ts +92 -0
@@ -0,0 +1,4839 @@
1
+
2
+ ## 2026-02-25T12:31:21.747Z | b9246a1c-4968-424a-aee5-d4c62a2d1346
3
+ - type: session_summary
4
+ - session: import:organized
5
+ # Codex / AI Agent Instructions
6
+
7
+ 이 저장소는 **Claude Code용 메모리 플러그인 + CLI + 로컬 대시보드 서버**입니다.
8
+ Codex(또는 다른 코딩 에이전트)가 작업할 때 아래 규칙을 우선으로 따르세요.
9
+
10
+ ## Quick Commands
11
+
12
+ ```bash
13
+ npm install
14
+ npm run build
15
+
16
+ # 웹 대시보드(로컬)
17
+ node dist/server/index.js
18
+ # 또는
19
+ npx claude-memory-layer dashboard
20
+ ```
21
+
22
+ ## Key Entry Points
23
+
24
+ - `scripts/build.ts`: esbuild 기반 빌드. `dist/` 생성 + `.claude-plugin/` 및 `src/ui` 복사
25
+ - `src/cli/index.ts`: CLI 엔트리포인트 (`bin`: `claude-memory-layer`)
26
+ - `src/server/index.ts`: 대시보드/REST API 서버 (기본 포트 `37777`)
27
+ - `src/server/api/chat.ts`: **외부 `claude` CLI**를 `spawn('claude', ...)`로 호출 (환경에 따라 미설치일 수 있음)
28
+
29
+ ## Local Side-Effects (주의)
30
+
31
+ - `claude-memory-layer install` / `uninstall` 은 **사용자 머신의** `~/.claude/settings.json` 을 수정합니다.
32
+ - 자동 실행/테스트 목적으로 임의 실행하지 말고, 사용자가 명시적으로 요청할 때만 실행하세요.
33
+ - 훅/CLI/서버는 기본적으로 `~/.claude-code/memory` 아래에 데이터를 읽고/씁니다.
34
+ - 메모리 스토리지를 삭제/초기화하는 동작은 요청 없이는 하지 마세요.
35
+
36
+ ## Common Pitfall: Self-dependency (반복 발생)
37
+
38
+ `package.json`의 `dependencies`에 **자기 자신**을 추가하면 설치가 꼬입니다.
39
+
40
+ - 금지 예: `"claude-memory-layer": "^1.0.x"`
41
+ - 진단: `npm list claude-memory-layer` 결과가 `(empty)` 여야 정상
42
+ - 복구:
43
+
44
+ ```bash
45
+ rm package-lock.json && rm -rf node_modules
46
+ npm install
47
+ npm list claude-memory-layer
48
+ ```
49
+
50
+ ## Release / Publish Workflow
51
+
52
+ 1. Self-dependency 확인: `npm list claude-memory-layer` → `(empty)`
53
+ 2. 버전 업데이트: `npm version patch` 또는 `package.json` 수정
54
+ 3. 빌드: `npm run build`
55
+ 4. 배포: `npm publish --otp=<code>`
56
+ 5. 확인: `npm view claude-memory-layer versions`
57
+
58
+ ## Dev Notes
59
+
60
+ - Node.js: `>=18` (ESM 프로젝트)
61
+ - 스토리지: **SQLite(WAL) 기반**으로 훅(쓰기) + 서버(읽기) 동시 동작을 전제로 함
62
+ - 테스트/정적분석 스크립트는 존재하지만, 현재 시점에서 전부 “항상 green”을 보장하지 않을 수 있으니
63
+ 변경 전후로 실제 실행 결과를 확인하고 진행하세요.
64
+
65
+
66
+ ## 2026-02-25T12:31:21.748Z | ac708211-cc0a-4817-aa7d-372f6ec29338
67
+ - type: session_summary
68
+ - session: import:organized
69
+ # Code Memory - Project Instructions
70
+
71
+ ## Common Mistakes to Avoid
72
+
73
+ ### ⚠️ Self-dependency in package.json (반복 발생 주의!)
74
+ - **절대로** package.json의 dependencies에 자기 자신의 패키지를 추가하지 말 것
75
+ - 예: `"claude-memory-layer": "^1.0.x"` 같은 순환 의존성 금지
76
+ - npm list 시 이상한 중첩 구조가 보이면 self-dependency 의심할 것
77
+
78
+ #### 원인
79
+ - `package-lock.json`에 self-dependency가 저장되면, `npm install` 시 package.json에 복원됨
80
+ - 한번 잘못 들어가면 lock 파일 때문에 계속 복원되는 악순환 발생
81
+
82
+ #### 해결 방법
83
+ ```bash
84
+ # 1. package.json에서 self-dependency 제거
85
+ # 2. lock 파일과 node_modules 삭제
86
+ rm package-lock.json && rm -rf node_modules
87
+ # 3. 새로 설치
88
+ npm install
89
+ # 4. 확인 (empty가 나와야 정상)
90
+ npm list claude-memory-layer
91
+ ```
92
+
93
+ ## npm Publish Workflow
94
+ 1. Self-dependency 확인: `npm list claude-memory-layer` → `(empty)` 확인
95
+ 2. 버전 업데이트: package.json 직접 수정 또는 `npm version patch`
96
+ 3. 빌드: `npm run build`
97
+ 4. 배포: `npm publish --otp=<코드>`
98
+ 5. 확인: `npm view claude-memory-layer versions`
99
+
100
+ ## 2026-02-25T12:31:21.749Z | f509ff1e-5ec2-4749-83c7-f96eedd933e8
101
+ - type: session_summary
102
+ - session: import:organized
103
+ # Claude Memory Layer - 작업 핸드오프 문서
104
+
105
+ ## 현재 상태
106
+ **날짜**: 2026-02-01
107
+ **상태**: SQLite WAL 마이그레이션 완료 ✅
108
+
109
+ ## 문제 해결 완료
110
+
111
+ ### 기존 문제
112
+ - DuckDB 다중 프로세스 동시 접근 충돌
113
+ - 웹 대시보드 (localhost:37777)에서 500 에러
114
+ - 훅과 서버 동시 실행 불가
115
+
116
+ ### 해결책: 2-tier 스토리지 아키텍처
117
+ ```
118
+ Hooks (쓰기) ──▶ SQLite (WAL) ◀── Server (읽기)
119
+
120
+ └── 동시 접근 가능 ✅
121
+ ```
122
+
123
+ ## 구현된 변경사항
124
+
125
+ ### 새 파일
126
+ 1. **`src/core/sqlite-wrapper.ts`** - SQLite WAL 모드 래퍼
127
+ 2. **`src/core/sqlite-event-store.ts`** - SQLite 기반 EventStore
128
+ 3. **`src/core/sync-worker.ts`** - SQLite→DuckDB 동기화 워커 (미래 분석용)
129
+
130
+ ### 수정된 파일
131
+ 1. **`src/services/memory-service.ts`** - 이중 스토어 아키텍처 통합
132
+ - `sqliteStore`: Primary store (항상 사용)
133
+ - `analyticsStore`: DuckDB (옵션, 분석용)
134
+ - `analyticsEnabled` 옵션 추가
135
+
136
+ 2. **`src/core/index.ts`** - 새 모듈 export
137
+
138
+ 3. **`scripts/build.ts`** - better-sqlite3 external 추가
139
+
140
+ 4. **`package.json`** - better-sqlite3 의존성 추가
141
+
142
+ ## 테스트 결과
143
+ ```bash
144
+ # 서버 실행 중 훅 테스트
145
+ $ node dist/server/index.js &
146
+ $ echo '{"session_id":"test","prompt":"test","cwd":"/tmp"}' | node dist/hooks/user-prompt-submit.js
147
+ {"context":""} # 성공!
148
+
149
+ # 동시 실행 테스트 (5개 훅 병렬)
150
+ All hooks completed ✅
151
+ eventCount: 7
152
+ ```
153
+
154
+ ## 아키텍처 결정
155
+
156
+ ### Primary Store: SQLite (WAL 모드)
157
+ - 훅에서 직접 쓰기
158
+ - 서버에서 직접 읽기
159
+ - WAL 모드: 다중 리더 + 단일 라이터 지원
160
+ - 락 충돌 없음
161
+
162
+ ### Analytics Store: DuckDB (옵션, 미래용)
163
+ - 복잡한 분석 쿼리용
164
+ - 배치 동기화 (SyncWorker)
165
+ - 현재는 비활성화
166
+
167
+ ## 빌드 및 실행
168
+
169
+ ```bash
170
+ # 빌드
171
+ npm run build
172
+
173
+ # 서버 시작
174
+ node dist/server/index.js
175
+
176
+ # 훅 테스트 (서버 실행 중에도 가능!)
177
+ echo '{"session_id":"test","prompt":"test","cwd":"/tmp"}' | node dist/hooks/user-prompt-submit.js
178
+
179
+ # 대시보드
180
+ open http://localhost:37777
181
+ ```
182
+
183
+ ## 향후 작업 (선택사항)
184
+
185
+ 1. **DuckDB 분석 기능 활성화**
186
+ - SyncWorker로 SQLite→DuckDB 동기화
187
+ - 복잡한 통계/분석 쿼리에 DuckDB 사용
188
+
189
+ 2. **Shared Store SQLite 마이그레이션**
190
+ - 현재: 훅에서 비활성화
191
+ - 향후: SQLite 기반으로 전환
192
+
193
+ 3. **마이그레이션 도구**
194
+ - 기존 DuckDB 데이터를 SQLite로 마이그레이션
195
+
196
+ ## 2026-02-25T12:31:21.750Z | 51d82e23-a7ef-4b51-92d0-1d5d33f1b606
197
+ - type: session_summary
198
+ - session: import:organized
199
+ # Claude Memory Layer
200
+
201
+ Claude Code 플러그인으로, 대화 내용을 기억하여 사용할수록 똑똑해지는 AI 어시스턴트를 만듭니다.
202
+
203
+ ## 개요
204
+
205
+ Claude Memory Layer는 Claude Code에서 사용자와 AI 간의 모든 대화를 저장하고, 새로운 질문을 할 때 관련된 과거 대화를 자동으로 검색하여 컨텍스트로 제공합니다. 이를 통해:
206
+
207
+ - **연속성 있는 대화**: 이전 세션에서 논의한 내용을 기억
208
+ - **프로젝트 맥락 이해**: 프로젝트별로 축적된 지식 활용
209
+ - **개인화된 응답**: 사용자의 선호도와 패턴 학습
210
+
211
+ ## Features
212
+
213
+ ### Core Features
214
+
215
+ - **Conversation Memory**: 사용자 프롬프트와 AI 응답 저장
216
+ - **Semantic Search**: 벡터 임베딩을 통한 의미 기반 검색
217
+ - **AXIOMMIND Architecture**: 7가지 원칙 기반 안정적 메모리 관리
218
+ - **Memory Graduation**: L0→L4 단계별 메모리 승격
219
+ - **Evidence Alignment**: 응답이 실제 기억에 기반했는지 검증
220
+ - **History Import**: 기존 Claude Code 세션 기록 임포트
221
+
222
+ ### Advanced Features
223
+
224
+ - **Citations System**: 메모리 출처 추적 (`[mem:abc123]` 형식)으로 검색 결과의 원본 확인 가능
225
+ - **Endless Mode**: 세션 경계 없는 연속적 메모리 스트림, Biomimetic Memory Architecture 기반
226
+ - **Entity-Edge Model**: entries/entities/edges 3-layer 모델로 데이터 관계 명시적 모델링
227
+ - **Evidence Aligner V2**: Quote 기반 3단계 정렬 (exact → normalized → fuzzy)
228
+ - **MCP Desktop Integration**: Claude Desktop용 MCP 서버로 CLI와 동일한 메모리 공유
229
+ - **PostToolUse Hook**: 도구 실행 결과 (Read, Write, Bash 등) 캡처 및 저장
230
+ - **Private Tags**: `<private>` 태그로 민감 정보를 명시적으로 제외
231
+ - **Progressive Disclosure**: 3-Layer 검색 (인덱스 → 타임라인 → 상세)으로 토큰 효율화
232
+ - **memU-inspired Retrieval**: fast/deep 전략 + 스코프 필터(session prefix, canonical key prefix, metadata path)
233
+ - **Append-only Markdown Mirror**: 저장 이벤트를 `memory/<namespace>/<category...>/YYYY-MM-DD.md`에도 동기 append (기본값: `namespace=default`, `category=uncategorized`, 경로 세그먼트 sanitize)
234
+ - `memory/_index.md` 인덱스를 자동 갱신
235
+ - **Task Entity System**: Task를 Entity로 승격하여 세션 간 상태 추적
236
+ - **Vector Outbox V2**: Transactional Outbox 패턴으로 DuckDB-LanceDB 정합성 보장
237
+ - **Web Viewer UI**: localhost:37777 대시보드로 실시간 메모리 모니터링
238
+
239
+ ## 설치 방법
240
+
241
+ ### 1. 의존성 설치
242
+
243
+ ```bash
244
+ cd claude-memory-layer
245
+ npm install
246
+ ```
247
+
248
+ ### 2. 빌드
249
+
250
+ ```bash
251
+ npm run build
252
+ ```
253
+
254
+ ### 3. Claude Code에 플러그인 등록
255
+
256
+ 빌드된 플러그인을 Claude Code 설정에 추가합니다:
257
+
258
+ ```bash
259
+ # Claude Code 설정 디렉토리에 플러그인 복사
260
+ cp -r dist/.claude-plugin ~/.claude/plugins/claude-memory-layer/
261
+ ```
262
+
263
+ ## 사용 방법
264
+
265
+ ### 자동 동작 (Hooks)
266
+
267
+ 플러그인은 Claude Code 세션에 자동으로 연결되어 동작합니다:
268
+
269
+ | Hook | 동작 |
270
+ |------|------|
271
+ | **SessionStart** | 세션 시작 시 프로젝트 관련 컨텍스트 로드 |
272
+ | **UserPromptSubmit** | 프롬프트 입력 시 관련 기억 검색 및 저장 |
273
+ | **Stop** | AI 응답 완료 시 응답 내용 저장 |
274
+ | **SessionEnd** | 세션 종료 시 요약 생성 및 저장 |
275
+
276
+ ### Slash 명령어
277
+
278
+ Claude Code 내에서 사용할 수 있는 명령어:
279
+
280
+ ```bash
281
+ # 메모리 검색 - 관련 기억 찾기
282
+ /memory-search "authentication 구현 방법"
283
+
284
+ # 대화 기록 보기
285
+ /memory-history
286
+ /memory-history --limit 50
287
+ /memory-history --session <session-id>
288
+
289
+ # 통계 확인
290
+ /memory-stats
291
+
292
+ # 기존 대화 기록 임포트
293
+ /memory-import # 현재 프로젝트
294
+ /memory-import --all # 모든 프로젝트
295
+ /memory-import --project /path/to/project # 특정 프로젝트
296
+
297
+ # 임포트 가능한 세션 목록
298
+ /memory-list
299
+
300
+ # 메모리 삭제
301
+ /memory-forget --session <id> --confirm
302
+ ```
303
+
304
+ ### 기존 메모리 정리 Import (구조화)
305
+
306
+ 레거시 markdown 메모리를 읽어서 구조화 경로로 재저장(import)할 수 있습니다.
307
+
308
+ ```bash
309
+ # 미리보기(실제 저장 없음)
310
+ claude-memory-layer organize-import /path/to/legacy-memory --dry-run
311
+
312
+ # 실제 import
313
+ claude-memory-layer organize-import /path/to/legacy-memory --project /path/to/project
314
+
315
+ # 일부만 import
316
+ claude-memory-layer organize-import /path/to/legacy-memory --limit 100
317
+
318
+ # source에 markdown이 없으면 자동 bootstrap(코드+git 분석)
319
+ claude-memory-layer organize-import /path/to/empty-dir --project /path/to/project
320
+
321
+ # bootstrap 강제 실행
322
+ claude-memory-layer organize-import /path/to/memory --force-bootstrap --repo /path/to/project
323
+
324
+ # 자동 bootstrap 비활성화
325
+ claude-memory-layer organize-import /path/to/empty-dir --no-bootstrap-if-empty
326
+
327
+ # markdown이 없는 초기 상태면 bootstrap 생성 + import
328
+ claude-memory-layer organize-import /path/to/empty-dir --bootstrap --repo /path/to/codebase
329
+
330
+ # bootstrap 강제 재생성 (기존 markdown 있어도)
331
+ claude-memory-layer organize-import /path/to/legacy-memory --force-bootstrap --repo /path/to/codebase --out /path/to/legacy-memory/bootstrap-kb
332
+
333
+ # 증분 bootstrap (기본값): 이전 manifest를 기준으로 변경분 중심 업데이트
334
+ claude-memory-layer organize-import /path/to/legacy-memory --bootstrap --repo /path/to/codebase --incremental
335
+
336
+ # 전체 재생성 bootstrap
337
+ claude-memory-layer organize-import /path/to/legacy-memory --bootstrap --repo /path/to/codebase --no-incremental
338
+ ```
339
+
340
+ ### CLI 명령어
341
+
342
+ 터미널에서 직접 사용:
343
+
344
+ ```bash
345
+ # 메모리 검색
346
+ npx claude-memory-layer search "React 컴포넌트 패턴"
347
+ npx claude-memory-layer search "API 에러 처리" --top-k 10
348
+
349
+ # 대화 기록 조회
350
+ npx claude-memory-layer history
351
+ npx claude-memory-layer history --limit 50 --type user_prompt
352
+
353
+ # 통계 확인
354
+ npx claude-memory-layer stats
355
+
356
+ # 기존 세션 임포트
357
+ npx claude-memory-layer import # 현재 프로젝트
358
+ npx claude-memory-layer import --all # 모든 프로젝트
359
+ npx claude-memory-layer import --all --verbose # 상세 로그
360
+
361
+ # 임포트 가능한 세션 목록
362
+ npx claude-memory-layer list
363
+ npx claude-memory-layer list --project /path/to/project
364
+
365
+ # 임베딩 수동 처리
366
+ npx claude-memory-layer process
367
+
368
+ # MongoDB 동기화 (옵션, 멀티 서버 협업)
369
+ # - 여러 서버에서 같은 프로젝트를 개발할 때, 각 서버의 로컬 SQLite(events.sqlite) 이벤트를
370
+ # 하나의 MongoDB로 모아 push/pull 동기화할 수 있습니다.
371
+ # - 동일 프로젝트는 반드시 같은 project key로 실행해야 합니다.
372
+ export CLAUDE_MEMORY_MONGO_URI="mongodb://USER:PASSWORD@HOST:PORT/"
373
+ export CLAUDE_MEMORY_MONGO_DB="claude_memory_layer"
374
+ export CLAUDE_MEMORY_MONGO_PROJECT="my-project"
375
+
376
+ # 1회 동기화 (push+pull)
377
+ npx claude-memory-layer mongo-sync
378
+
379
+ # 지속 동기화 (주기적으로 push+pull)
380
+ npx claude-memory-layer mongo-sync --watch --interval 30000
381
+ ```
382
+
383
+ ### memU-inspired Retrieval 사용 예시
384
+
385
+ 아래 예시는 SDK/서비스 레벨에서 `retrieveMemories()` 호출 시 적용되는 옵션입니다.
386
+
387
+ ```ts
388
+ import { getMemoryServiceForProject } from './src/services/memory-service.js';
389
+
390
+ const memory = getMemoryServiceForProject('/path/to/project');
391
+
392
+ // 1) Fast: 키워드 기반 빠른 검색
393
+ const fast = await memory.retrieveMemories('브리핑 포맷', {
394
+ strategy: 'fast',
395
+ topK: 5,
396
+ minScore: 0.6
397
+ });
398
+
399
+ // 2) Deep: 벡터 검색 + 키워드 오버랩 재정렬
400
+ const deep = await memory.retrieveMemories('브리핑 포맷', {
401
+ strategy: 'deep',
402
+ topK: 10,
403
+ rerankWithKeyword: true
404
+ });
405
+
406
+ // 3) Scoped filter: 세션/타입/계층형 메타데이터로 범위 제한
407
+ const scoped = await memory.retrieveMemories('아침 브리핑', {
408
+ strategy: 'deep',
409
+ scope: {
410
+ sessionIdPrefix: 'agent:main:',
411
+ eventTypes: ['user_prompt', 'agent_response'],
412
+ canonicalKeyPrefix: 'pref/briefing',
413
+ contentIncludes: ['아침'],
414
+ metadata: {
415
+ 'scope.project.id': 'alpha'
416
+ }
417
+ }
418
+ });
419
+ ```
420
+
421
+ 팁:
422
+ - `strategy: 'auto'`는 기본적으로 `deep` 경로를 사용합니다.
423
+ - 저지연 응답이 중요하면 `fast`, 정확도 우선이면 `deep`를 권장합니다.
424
+
425
+ ## Privacy 기능
426
+
427
+ ### Private Tags
428
+
429
+ 민감한 정보를 메모리에서 제외하려면 `<private>` 태그를 사용합니다:
430
+
431
+ ```markdown
432
+ 이 부분은 저장됩니다.
433
+
434
+ <private>
435
+ API_KEY=sk-xxxx
436
+ SECRET_TOKEN=abc123
437
+ 이 내용은 메모리에 저장되지 않습니다.
438
+ </private>
439
+
440
+ 이 부분도 저장됩니다.
441
+ ```
442
+
443
+ 저장 결과:
444
+ ```
445
+ 이 부분은 저장됩니다.
446
+ [PRIVATE]
447
+ 이 부분도 저장됩니다.
448
+ ```
449
+
450
+ ### 자동 필터링
451
+
452
+ 다음 패턴은 자동으로 마스킹됩니다:
453
+ - `password`, `api_key`, `secret`, `token`
454
+ - Bearer 토큰
455
+ - Private Key 블록
456
+
457
+ ## Citations (인용 시스템)
458
+
459
+ 검색 결과에는 인용 ID가 포함됩니다:
460
+
461
+ ```
462
+ 🔍 Search Results:
463
+
464
+ #1 [mem:a7Bc3x] (score: 0.94)
465
+ "DuckDB를 사용하여 이벤트 소싱 패턴을..."
466
+ 📅 2026-01-30 | 🔗 Session abc123
467
+ ```
468
+
469
+ 원본 확인:
470
+ ```bash
471
+ claude-memory-layer show mem:a7Bc3x
472
+ ```
473
+
474
+ ## Endless Mode
475
+
476
+ 세션 경계 없이 연속적인 메모리 스트림을 유지합니다:
477
+
478
+ ```bash
479
+ # Endless Mode 활성화
480
+ claude-memory-layer config set mode endless
481
+
482
+ # 상태 확인
483
+ claude-memory-layer status
484
+
485
+ # 출력 예시:
486
+ # Mode: Endless
487
+ # Working Set: 47 events (last 18 hours)
488
+ # Continuity Score: 0.85 (seamless)
489
+ # Consolidated: 23 memories
490
+ ```
491
+
492
+ ### 모드 비교
493
+
494
+ | 기존 세션 모드 | Endless Mode |
495
+ |---------------|-------------|
496
+ | 명확한 시작/끝 | 연속적 스트림 |
497
+ | 세션별 요약 | 점진적 통합 |
498
+ | 재시작 시 빈 상태 | 이전 컨텍스트 유지 |
499
+
500
+ ## MCP Desktop Integration
501
+
502
+ Claude Desktop에서 메모리 검색을 사용하려면:
503
+
504
+ ```bash
505
+ # MCP 서버 설치
506
+ claude-memory-layer mcp install
507
+
508
+ # 또는 수동 설정: ~/Library/Application Support/Claude/claude_desktop_config.json
509
+ {
510
+ "mcpServers": {
511
+ "claude-memory-layer": {
512
+ "command": "npx",
513
+ "args": ["claude-memory-layer-mcp"]
514
+ }
515
+ }
516
+ }
517
+ ```
518
+
519
+ ### 제공되는 MCP 도구
520
+
521
+ | 도구 | 설명 |
522
+ |------|------|
523
+ | `mem-search` | 메모리 검색 |
524
+ | `mem-timeline` | 타임라인 조회 |
525
+ | `mem-details` | 상세 정보 조회 |
526
+ | `mem-stats` | 통계 조회 |
527
+
528
+ ## Web Viewer
529
+
530
+ 브라우저에서 메모리 대시보드를 확인할 수 있습니다:
531
+
532
+ ```bash
533
+ # 웹 서버 시작
534
+ claude-memory-layer dashboard
535
+
536
+ # 브라우저에서 접속
537
+ # http://localhost:37777
538
+ ```
539
+
540
+ ### 주요 기능
541
+ - 실시간 이벤트 스트림
542
+ - 세션/프로젝트별 탐색
543
+ - 벡터 검색 인터페이스
544
+ - 저장소 통계 대시보드
545
+ - Outbox 상태 모니터링
546
+
547
+ ## 기존 대화 기록 임포트
548
+
549
+ 이미 Claude Code를 사용해왔다면, 기존 대화 기록을 임포트하여 바로 활용할 수 있습니다:
550
+
551
+ ```bash
552
+ # 1. 먼저 임포트 가능한 세션 확인
553
+ npx claude-memory-layer list
554
+
555
+ # 2. 현재 프로젝트의 모든 세션 임포트
556
+ npx claude-memory-layer import
557
+
558
+ # 3. 또는 모든 프로젝트의 세션 임포트
559
+ npx claude-memory-layer import --all --verbose
560
+ ```
561
+
562
+ ### 임포트 결과 예시
563
+
564
+ ```
565
+ 📥 Importing all sessions from all projects
566
+
567
+ ⏳ Processing embeddings...
568
+
569
+ ✅ Import Complete
570
+
571
+ Sessions processed: 15
572
+ Total messages: 342
573
+ Imported prompts: 156
574
+ Imported responses: 186
575
+ Skipped duplicates: 0
576
+ Embeddings processed: 342
577
+ ```
578
+
579
+ ### 중복 처리
580
+
581
+ 임포트는 콘텐츠 해시 기반으로 중복을 자동 감지합니다. 여러 번 실행해도 같은 내용이 중복 저장되지 않습니다.
582
+
583
+ ## 동작 원리
584
+
585
+ ### 1. 메모리 저장
586
+
587
+ ```
588
+ 사용자 프롬프트 입력
589
+
590
+ EventStore에 저장 (DuckDB, append-only)
591
+
592
+ Outbox에 임베딩 요청 등록
593
+
594
+ Vector Worker가 임베딩 생성
595
+
596
+ VectorStore에 저장 (LanceDB)
597
+ ```
598
+
599
+ ### 2. 메모리 검색
600
+
601
+ ```
602
+ 새 프롬프트 입력
603
+
604
+ 임베딩 생성
605
+
606
+ VectorStore에서 유사 벡터 검색
607
+
608
+ AXIOMMIND Matcher로 신뢰도 계산
609
+
610
+ 컨텍스트로 Claude에 제공
611
+ ```
612
+
613
+ ### 3. 메모리 승격 (Graduation)
614
+
615
+ 자주 참조되는 메모리는 더 높은 레벨로 승격됩니다:
616
+
617
+ | Level | 이름 | 설명 | 승격 조건 |
618
+ |-------|------|------|-----------|
619
+ | L0 | EventStore | 원본 이벤트 | 기본 저장 |
620
+ | L1 | Structured | 구조화된 패턴 | 3회 이상 접근 |
621
+ | L2 | Candidates | 검증된 스키마 | 5회 이상, 다중 세션 참조 |
622
+ | L3 | Verified | 교차 검증됨 | 높은 신뢰도 |
623
+ | L4 | Active | 활성 지식 | 10회 이상, 3개 이상 세션 |
624
+
625
+ ## 매칭 신뢰도
626
+
627
+ 검색 결과는 신뢰도에 따라 분류됩니다:
628
+
629
+ | 신뢰도 | 점수 | Gap | 동작 |
630
+ |--------|------|-----|------|
631
+ | **High** | ≥0.92 | ≥0.03 | 자동으로 컨텍스트에 포함 |
632
+ | **Suggested** | ≥0.75 | <0.03 | 대안 제시 |
633
+ | **None** | <0.75 | - | 매칭 없음 |
634
+
635
+ ## Architecture
636
+
637
+ ### System Overview
638
+
639
+ ```
640
+ ┌─────────────────────────────────────────────────────────────┐
641
+ │ Claude Code Hooks │
642
+ │ SessionStart │ UserPromptSubmit │ Stop │ PostToolUse │ End │
643
+ └──────────────────────────┬──────────────────────────────────┘
644
+
645
+
646
+ ┌─────────────────────────────────────────────────────────────┐
647
+ │ Memory Service │
648
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
649
+ │ │ Retriever │ │ Matcher │ │ Graduation │ │
650
+ │ │ Progressive│ │ Evidence │ │ L0 → L4 │ │
651
+ │ └─────────────┘ └─────────────┘ └─────────────┘ │
652
+ └──────────────────────────┬──────────────────────────────────┘
653
+
654
+ ┌──────────────────┴──────────────────┐
655
+ ▼ ▼
656
+ ┌───────────────┐ ┌───────────────┐
657
+ │ EventStore │ ──── Outbox ────▶ │ VectorStore │
658
+ │ (DuckDB) │ (V2 Pattern) │ (LanceDB) │
659
+ └───────────────┘ └───────────────┘
660
+ ```
661
+
662
+ ### Entity-Edge Model (3-Layer)
663
+
664
+ ```
665
+ ┌─────────────────────────────────────────────────────────────┐
666
+ │ edges │
667
+ │ ┌──────────┐ evidence_of ┌──────────┐ │
668
+ │ │ Entry │ ─────────────────▶│ Entity │ │
669
+ │ │ (Fact, │ │ (Task, │ │
670
+ │ │ Decision)│ │ Artifact)│ │
671
+ │ └──────────┘ └──────────┘ │
672
+ │ │ │ │
673
+ │ │ derived_from │ blocked_by │
674
+ │ ▼ ▼ │
675
+ │ ┌──────────┐ ┌──────────┐ │
676
+ │ │ Entry │ │ Entity │ │
677
+ │ └──────────┘ └──────────┘ │
678
+ └─────────────────────────────────────────────────────────────┘
679
+ ```
680
+
681
+ ### Progressive Disclosure (토큰 효율화)
682
+
683
+ ```
684
+ Layer 1: Search Index (~50-100 tokens/result)
685
+ │ { id, summary, score }
686
+
687
+ └──▶ Layer 2: Timeline Context (~200 tokens)
688
+ │ 시간순 전후 맥락
689
+
690
+ └──▶ Layer 3: Full Details (~500-1000 tokens)
691
+ 선택된 항목만 전체 로드
692
+ ```
693
+
694
+ ### MCP Integration
695
+
696
+ ```
697
+ ┌─────────────────────┐ ┌─────────────────────┐
698
+ │ Claude Desktop │◀────────│ claude-memory-layer │
699
+ │ (MCP Client) │ stdio │ (MCP Server) │
700
+ └─────────────────────┘ └──────────┬──────────┘
701
+
702
+
703
+ ┌─────────────────────┐
704
+ │ Shared Storage │
705
+ │ ~/.claude-code/ │
706
+ └─────────────────────┘
707
+ ```
708
+
709
+ ## AXIOMMIND 7 원칙
710
+
711
+ 1. **Single Source of Truth**: DuckDB EventStore가 유일한 진실의 원천
712
+ 2. **Append-Only**: 이벤트는 수정/삭제 없이 추가만
713
+ 3. **Idempotency**: dedupe_key로 중복 이벤트 감지
714
+ 4. **Evidence Alignment**: 주장이 실제 소스에 기반했는지 검증
715
+ 5. **Entity-Based Tasks**: canonical_key로 일관된 엔티티 식별
716
+ 6. **Vector Store Consistency**: DuckDB → LanceDB 단방향 흐름
717
+ 7. **Standard JSON**: 모든 데이터는 이식 가능한 JSON 형식
718
+
719
+ ## 저장 위치
720
+
721
+ 메모리는 기본적으로 다음 위치에 저장됩니다:
722
+
723
+ ```
724
+ ~/.claude-code/memory/
725
+ ├── events.duckdb # 이벤트 저장소
726
+ └── vectors/ # 벡터 임베딩
727
+ ```
728
+
729
+ Claude Code 세션 기록 위치:
730
+
731
+ ```
732
+ ~/.claude/projects/<project-hash>/<session-id>.jsonl
733
+ ```
734
+
735
+ ## 개발
736
+
737
+ ```bash
738
+ # 의존성 설치
739
+ npm install
740
+
741
+ # 빌드
742
+ npm run build
743
+
744
+ # 테스트
745
+ npm test
746
+
747
+ # 타입 체크
748
+ npm run typecheck
749
+
750
+ # 개발 모드 실행
751
+ npm run dev
752
+ ```
753
+
754
+ ## 기술 스택
755
+
756
+ - **DuckDB**: 이벤트 저장소 (append-only SQL)
757
+ - **LanceDB**: 벡터 저장소 (고성능 벡터 검색)
758
+ - **@xenova/transformers**: 로컬 임베딩 생성
759
+ - **Zod**: 런타임 타입 검증
760
+ - **Commander**: CLI 인터페이스
761
+ - **TypeScript**: 타입 안전한 코드
762
+ - **Bun**: HTTP 서버 (Web Viewer)
763
+ - **Hono**: 경량 라우터
764
+ - **MCP SDK**: Claude Desktop 통합
765
+
766
+ ## Specification Documents
767
+
768
+ 상세 설계 문서는 `specs/` 디렉토리에서 확인할 수 있습니다:
769
+
770
+ | 문서 | 설명 |
771
+ |------|------|
772
+ | [citations-system](specs/citations-system/spec.md) | 메모리 인용 시스템 |
773
+ | [endless-mode](specs/endless-mode/spec.md) | 연속 세션 모드 |
774
+ | [entity-edge-model](specs/entity-edge-model/spec.md) | 3-Layer 데이터 모델 |
775
+ | [evidence-aligner-v2](specs/evidence-aligner-v2/spec.md) | 증거 정렬 시스템 |
776
+ | [mcp-desktop-integration](specs/mcp-desktop-integration/spec.md) | MCP 서버 통합 |
777
+ | [post-tool-use-hook](specs/post-tool-use-hook/spec.md) | 도구 사용 기록 |
778
+ | [private-tags](specs/private-tags/spec.md) | 프라이버시 태그 |
779
+ | [progressive-disclosure](specs/progressive-disclosure/spec.md) | 토큰 효율화 검색 |
780
+ | [task-entity-system](specs/task-entity-system/spec.md) | Task Entity 관리 |
781
+ | [vector-outbox-v2](specs/vector-outbox-v2/spec.md) | Transactional Outbox |
782
+ | [web-viewer-ui](specs/web-viewer-ui/spec.md) | 웹 대시보드 |
783
+
784
+ ## Roadmap
785
+
786
+ ### Phase 1: Core (완료)
787
+ - [x] Event Store (DuckDB)
788
+ - [x] Vector Store (LanceDB)
789
+ - [x] Memory Graduation (L0→L4)
790
+ - [x] Evidence Alignment
791
+ - [x] History Import
792
+
793
+ ### Phase 2: Advanced Features (진행 중)
794
+ - [ ] Citations System
795
+ - [ ] Endless Mode
796
+ - [ ] Entity-Edge Model
797
+ - [ ] Evidence Aligner V2
798
+ - [ ] Private Tags
799
+
800
+ ### Phase 3: Integration
801
+ - [ ] MCP Desktop Integration
802
+ - [ ] Web Viewer UI
803
+ - [ ] PostToolUse Hook
804
+ - [ ] Progressive Disclosure
805
+
806
+ ### Phase 4: Optimization
807
+ - [ ] Vector Outbox V2
808
+ - [ ] Task Entity System
809
+ - [ ] Performance Tuning
810
+
811
+ ## License
812
+
813
+ MIT
814
+
815
+ ## 2026-02-25T12:31:21.752Z | 4b1b77d6-27a5-4d41-8a7b-f4d6890d71ae
816
+ - type: session_summary
817
+ - session: import:organized
818
+ # Context: Claude Code Memory Plugin
819
+
820
+ ## 1. 프로젝트 배경
821
+
822
+ 이 문서는 Claude Code용 Memory Plugin 개발을 위한 배경 연구와 참조 자료를 정리합니다.
823
+
824
+ ### 1.1 목표
825
+
826
+ 사용자가 Claude Code를 사용할수록 더 똑똑해지는 Agent를 만들기 위한 플러그인 개발:
827
+ - 사용자 prompt와 agent 응답을 지속적으로 기억
828
+ - 새로운 prompt 입력 시 관련된 과거 기억을 검색하여 컨텍스트로 활용
829
+ - 시간이 지남에 따라 개인화된 경험 제공
830
+
831
+ ---
832
+
833
+ ## 2. Claude Code Plugin System 분석
834
+
835
+ ### 2.1 플러그인 구조
836
+
837
+ ```
838
+ plugin-name/
839
+ ├── .claude-plugin/
840
+ │ └── plugin.json # 플러그인 메타데이터 (필수)
841
+ ├── commands/ # 슬래시 명령어 (선택)
842
+ ├── agents/ # 전문화된 에이전트 (선택)
843
+ ├── skills/ # 에이전트 스킬 (선택)
844
+ ├── hooks/ # 이벤트 핸들러 (선택)
845
+ ├── .mcp.json # MCP 서버 구성 (선택)
846
+ └── README.md # 문서
847
+ ```
848
+
849
+ ### 2.2 사용 가능한 Hook 이벤트
850
+
851
+ | Hook Event | 용도 | Memory Plugin 활용 |
852
+ |------------|------|-------------------|
853
+ | `SessionStart` | 세션 시작 시 실행 | 이전 세션 기억 로드 |
854
+ | `SessionEnd` | 세션 종료 시 실행 | 현재 세션 기억 저장 |
855
+ | `UserPromptSubmit` | 사용자 입력 시 실행 | 관련 기억 검색 및 주입 |
856
+ | `PreToolUse` | 도구 실행 전 | 도구별 과거 사용 패턴 제공 |
857
+ | `PostToolUse` | 도구 실행 후 | 도구 결과 기억 |
858
+ | `Stop` | Agent 응답 완료 시 | 전체 대화 기억 저장 |
859
+ | `PreCompact` | 컨텍스트 압축 전 | 중요 기억 보존 |
860
+
861
+ ### 2.3 Hook Input/Output 형식
862
+
863
+ ```json
864
+ // UserPromptSubmit hook input
865
+ {
866
+ "session_id": "...",
867
+ "prompt": "사용자가 입력한 텍스트",
868
+ "timestamp": "..."
869
+ }
870
+
871
+ // Hook은 stdout으로 결과 반환
872
+ // - 빈 출력: 변경 없음
873
+ // - JSON 출력: 컨텍스트 주입 또는 수정
874
+ ```
875
+
876
+ ---
877
+
878
+ ## 3. AI Memory System 연구
879
+
880
+ ### 3.1 Memory의 종류
881
+
882
+ | 유형 | 설명 | 지속성 |
883
+ |------|------|--------|
884
+ | **Short-term Memory** | 현재 대화 컨텍스트 | 세션 내 |
885
+ | **Long-term Memory** | 사용자 선호도, 과거 인사이트 | 영구적 |
886
+ | **Episodic Memory** | 구체적인 대화/이벤트 기억 | 영구적 |
887
+ | **Semantic Memory** | 추출된 지식과 관계 | 영구적 |
888
+
889
+ ### 3.2 주요 Memory 솔루션 비교
890
+
891
+ | 솔루션 | 특징 | 장점 |
892
+ |--------|------|------|
893
+ | **Mem0** | Y Combinator 투자, 그래프 기반 | 복잡한 관계 표현 |
894
+ | **LangChain Memory** | 프레임워크 내장 | 쉬운 통합 |
895
+ | **Zep/Graphiti** | 시간적 지식 그래프 | 시계열 추적 |
896
+ | **AWS AgentCore Memory** | 비동기 파이프라인 | 확장성 |
897
+ | **Google Vertex Memory Bank** | 유사도 검색 | 엔터프라이즈 |
898
+
899
+ ### 3.3 Memory vs RAG
900
+
901
+ - **RAG**: 외부 문서에서 정보 검색 (stateless)
902
+ - **Memory**: 과거 상호작용에서 컨텍스트 검색 (stateful)
903
+ - **이 플러그인**: Memory 중심 + 선택적 RAG 통합
904
+
905
+ ---
906
+
907
+ ## 4. AXIOMMIND Memory System 참조
908
+
909
+ Gist에서 제공된 AXIOMMIND 시스템의 핵심 개념:
910
+
911
+ ### 4.1 아키텍처 레이어
912
+
913
+ ```
914
+ ┌─────────────────────────────────────────────────────────┐
915
+ │ L0 EventStore (Single Source of Truth) │
916
+ │ - Append-only events table │
917
+ │ - Event deduplication via dedupe_key │
918
+ │ - Projection offset tracking │
919
+ └─────────────────────────────────────────────────────────┘
920
+
921
+ ┌─────────────────────────────────────────────────────────┐
922
+ │ Extraction/Sorting Layer (LLM Processing) │
923
+ │ - LLM extracts structured JSON from raw input │
924
+ │ - Evidence alignment and validation │
925
+ └─────────────────────────────────────────────────────────┘
926
+
927
+ ┌─────────────────────────────────────────────────────────┐
928
+ │ Derived Stores (Rebuildable from Events) │
929
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
930
+ │ │ DuckDB │ │ LanceDB │ │ Relational │ │
931
+ │ │ (FTS/SQL) │ │ (Vectors) │ │ Views │ │
932
+ │ └─────────────┘ └─────────────┘ └─────────────┘ │
933
+ └─────────────────────────────────────────────────────────┘
934
+ ```
935
+
936
+ ### 4.2 핵심 원칙
937
+
938
+ - **Append-only EventStore**: 모든 변경 추적, 파생 저장소에서 언제든 재구성 가능
939
+ - **Canonical Key 정규화**: 동일 개념의 여러 표현을 단일 키로 통합
940
+ - **단일 진실 공급원(SoT)**: events 테이블만 영구 저장, 나머지는 파생
941
+ - **멱등성 보장**: `dedupe_key`로 중복 이벤트 차단
942
+
943
+ ### 4.3 Canonical Key 정규화 (핵심 알고리즘)
944
+
945
+ ```python
946
+ # canonical_key.py - 결정론적 키 생성
947
+ def make_canonical_key(title: str, project: str = None) -> str:
948
+ """
949
+ 동일한 제목은 항상 동일한 키를 생성
950
+
951
+ 정규화 단계:
952
+ 1. NFKC 유니코드 정규화
953
+ 2. 소문자 변환
954
+ 3. 구두점 제거
955
+ 4. 연속 공백 정리
956
+ 5. (선택) 프로젝트/도메인 컨텍스트 추가
957
+ 6. 긴 키는 MD5 체크섬으로 truncate
958
+ """
959
+ import unicodedata
960
+ import re
961
+ import hashlib
962
+
963
+ # Step 1-4: 정규화
964
+ normalized = unicodedata.normalize('NFKC', title)
965
+ normalized = normalized.lower()
966
+ normalized = re.sub(r'[^\w\s]', '', normalized)
967
+ normalized = re.sub(r'\s+', ' ', normalized).strip()
968
+
969
+ # Step 5: 컨텍스트 추가
970
+ if project:
971
+ key = f"{project}::{normalized}"
972
+ else:
973
+ key = normalized
974
+
975
+ # Step 6: 긴 키 처리
976
+ MAX_KEY_LENGTH = 200
977
+ if len(key) > MAX_KEY_LENGTH:
978
+ hash_suffix = hashlib.md5(key.encode()).hexdigest()[:8]
979
+ key = key[:MAX_KEY_LENGTH - 9] + "_" + hash_suffix
980
+
981
+ return key
982
+ ```
983
+
984
+ **Memory Plugin 적용**:
985
+ - 사용자 prompt의 canonical key로 중복 질문 감지
986
+ - 유사한 질문들을 그룹화하여 패턴 추출
987
+
988
+ ### 4.4 Matching Thresholds (엄격한 매칭 기준)
989
+
990
+ ```python
991
+ # task_matcher.py - 매칭 임계값
992
+ MATCH_THRESHOLDS = {
993
+ "min_combined_score": 0.92, # 최소 결합 점수
994
+ "min_gap": 0.03, # 1위와 2위 간 최소 점수 차이
995
+ "suggestion_threshold": 0.75, # 제안 모드 임계값
996
+ }
997
+
998
+ def calculate_weighted_score(result: SearchResult) -> float:
999
+ """
1000
+ 가중치 점수 계산 (stage, status, recency)
1001
+ """
1002
+ weights = {
1003
+ "semantic_similarity": 0.4, # 벡터 유사도
1004
+ "fts_score": 0.25, # 전문 검색 점수
1005
+ "recency_bonus": 0.2, # 최신성 가산점
1006
+ "status_weight": 0.15, # 상태별 가중치
1007
+ }
1008
+
1009
+ score = (
1010
+ result.vector_score * weights["semantic_similarity"] +
1011
+ result.fts_score * weights["fts_score"] +
1012
+ result.recency_score * weights["recency_bonus"] +
1013
+ result.status_score * weights["status_weight"]
1014
+ )
1015
+ return score
1016
+
1017
+ def match_with_confidence(query: str, candidates: list) -> MatchResult:
1018
+ """
1019
+ 엄격한 매칭: top-1이 확실히 우세할 때만 확정
1020
+ """
1021
+ if len(candidates) == 0:
1022
+ return MatchResult(match=None, confidence="none")
1023
+
1024
+ top = candidates[0]
1025
+
1026
+ if top.score < MATCH_THRESHOLDS["suggestion_threshold"]:
1027
+ return MatchResult(match=None, confidence="none")
1028
+
1029
+ if top.score >= MATCH_THRESHOLDS["min_combined_score"]:
1030
+ if len(candidates) == 1:
1031
+ return MatchResult(match=top, confidence="high")
1032
+
1033
+ gap = top.score - candidates[1].score
1034
+ if gap >= MATCH_THRESHOLDS["min_gap"]:
1035
+ return MatchResult(match=top, confidence="high")
1036
+
1037
+ # 점수가 높지만 확실하지 않음 → 제안 모드
1038
+ return MatchResult(match=top, confidence="suggested")
1039
+ ```
1040
+
1041
+ **Memory Plugin 적용**:
1042
+ - 관련 기억 검색 시 엄격한 임계값 적용
1043
+ - 애매한 매칭은 "suggested" 상태로 표시
1044
+
1045
+ ### 4.5 Single-Writer Pattern (벡터 동시성 제어)
1046
+
1047
+ ```python
1048
+ # vector_worker.py - Outbox 패턴으로 동시성 제어
1049
+
1050
+ """
1051
+ LanceDB는 동시 쓰기에 취약하므로 Single-Writer 패턴 사용:
1052
+ 1. 이벤트 저장 시 embedding_outbox 테이블에 작업 추가
1053
+ 2. 별도 워커가 outbox를 순차적으로 처리
1054
+ 3. 처리 완료 시 outbox에서 삭제
1055
+ """
1056
+
1057
+ # DuckDB의 outbox 테이블
1058
+ CREATE TABLE embedding_outbox (
1059
+ id UUID PRIMARY KEY,
1060
+ event_id UUID NOT NULL,
1061
+ content TEXT NOT NULL,
1062
+ status VARCHAR DEFAULT 'pending', -- 'pending' | 'processing' | 'done'
1063
+ created_at TIMESTAMP DEFAULT NOW(),
1064
+ processed_at TIMESTAMP
1065
+ );
1066
+
1067
+ # Python 워커 (단일 프로세스)
1068
+ class VectorWorker:
1069
+ def __init__(self, db: DuckDB, lance: LanceDB, embedder: Embedder):
1070
+ self.db = db
1071
+ self.lance = lance
1072
+ self.embedder = embedder
1073
+
1074
+ async def process_outbox(self, batch_size: int = 32):
1075
+ """
1076
+ Outbox에서 pending 항목을 가져와 순차 처리
1077
+ """
1078
+ # 1. Pending 항목 가져오기 (락 획득)
1079
+ pending = self.db.execute("""
1080
+ UPDATE embedding_outbox
1081
+ SET status = 'processing'
1082
+ WHERE id IN (
1083
+ SELECT id FROM embedding_outbox
1084
+ WHERE status = 'pending'
1085
+ ORDER BY created_at
1086
+ LIMIT ?
1087
+ )
1088
+ RETURNING *
1089
+ """, [batch_size])
1090
+
1091
+ if not pending:
1092
+ return
1093
+
1094
+ # 2. 배치 임베딩 생성
1095
+ contents = [p.content for p in pending]
1096
+ vectors = await self.embedder.embed_batch(contents)
1097
+
1098
+ # 3. LanceDB에 저장 (단일 쓰기)
1099
+ records = [
1100
+ {"event_id": p.event_id, "content": p.content, "vector": v}
1101
+ for p, v in zip(pending, vectors)
1102
+ ]
1103
+ self.lance.add(records)
1104
+
1105
+ # 4. Outbox 정리
1106
+ ids = [p.id for p in pending]
1107
+ self.db.execute("""
1108
+ DELETE FROM embedding_outbox WHERE id = ANY(?)
1109
+ """, [ids])
1110
+ ```
1111
+
1112
+ **Memory Plugin 적용**:
1113
+ - 대화 저장 시 즉시 반환, 임베딩은 비동기 처리
1114
+ - 동시성 문제 없이 안정적인 벡터 인덱싱
1115
+
1116
+ ### 4.6 Blocker/Condition 분류 전략
1117
+
1118
+ ```python
1119
+ # task_resolver.py - 애매한 참조 처리
1120
+
1121
+ """
1122
+ Blocker 분류 전략:
1123
+ 1. Artifact: URL, Jira, GitHub 이슈 등 명확한 참조
1124
+ 2. Task: 엄격한 매칭만 허용 (score >= 0.92)
1125
+ 3. Condition: 애매한 참조 흡수 (나중에 해결 가능)
1126
+ """
1127
+
1128
+ class BlockerType(Enum):
1129
+ ARTIFACT = "artifact" # 명확한 외부 참조
1130
+ TASK = "task" # 확정된 작업 참조
1131
+ CONDITION = "condition" # 애매한 조건/참조
1132
+
1133
+ def classify_blocker(reference: str, match_result: MatchResult) -> BlockerType:
1134
+ # URL, 이슈 번호 등은 Artifact
1135
+ if is_artifact_reference(reference):
1136
+ return BlockerType.ARTIFACT
1137
+
1138
+ # 높은 신뢰도 매칭은 Task
1139
+ if match_result.confidence == "high":
1140
+ return BlockerType.TASK
1141
+
1142
+ # 나머지는 Condition으로 흡수
1143
+ return BlockerType.CONDITION
1144
+
1145
+ # Condition은 나중에 실제 Task로 해결될 수 있음
1146
+ # resolves_to edge로 연결
1147
+ ```
1148
+
1149
+ **Memory Plugin 적용**:
1150
+ - 불완전한 컨텍스트도 일단 저장
1151
+ - 나중에 추가 정보로 보강 가능
1152
+
1153
+ ### 4.7 Query Patterns (효과적인 뷰 활용)
1154
+
1155
+ ```sql
1156
+ -- v_task_blockers_effective: Condition 해결을 반영한 최종 blocker 뷰
1157
+ CREATE VIEW v_memory_context_effective AS
1158
+ SELECT
1159
+ m.id,
1160
+ m.session_id,
1161
+ m.content,
1162
+ m.event_type,
1163
+ m.timestamp,
1164
+ -- Condition이 해결된 경우 실제 참조로 대체
1165
+ COALESCE(r.resolved_content, m.content) as effective_content,
1166
+ COALESCE(r.resolved_id, m.id) as effective_id
1167
+ FROM memories m
1168
+ LEFT JOIN memory_resolutions r ON m.id = r.condition_id
1169
+ WHERE r.resolution_type IS NULL OR r.resolution_type = 'confirmed';
1170
+
1171
+ -- 4가지 주요 쿼리 패턴
1172
+ -- 1. 확정된 관련 기억
1173
+ SELECT * FROM v_memory_context_effective
1174
+ WHERE semantic_score >= 0.92;
1175
+
1176
+ -- 2. 제안 상태의 기억 (확인 대기)
1177
+ SELECT * FROM memories
1178
+ WHERE match_confidence = 'suggested';
1179
+
1180
+ -- 3. 자동 플레이스홀더 감지
1181
+ SELECT * FROM memories
1182
+ WHERE auto_placeholder = true;
1183
+
1184
+ -- 4. 해결된 조건 매핑
1185
+ SELECT condition_id, resolved_to_id
1186
+ FROM memory_resolutions
1187
+ WHERE resolution_type = 'confirmed';
1188
+ ```
1189
+
1190
+ ### 4.8 Placeholder 자동 생성
1191
+
1192
+ ```python
1193
+ # 정보가 불완전할 때 플레이스홀더 생성
1194
+ def create_placeholder_if_needed(event: MemoryEvent) -> Optional[Placeholder]:
1195
+ """
1196
+ 컨텍스트가 불완전하면 자동 플레이스홀더 생성
1197
+ - auto_placeholder=true 플래그 설정
1198
+ - 나중에 추가 정보로 해결 가능
1199
+ """
1200
+ if is_incomplete_context(event):
1201
+ return Placeholder(
1202
+ id=generate_uuid(),
1203
+ event_id=event.id,
1204
+ placeholder_type="unknown_context",
1205
+ auto_placeholder=True,
1206
+ created_at=datetime.now()
1207
+ )
1208
+ return None
1209
+ ```
1210
+
1211
+ ### 4.9 주요 모듈 요약
1212
+
1213
+ | 모듈 | 역할 | Memory Plugin 대응 |
1214
+ |------|------|-------------------|
1215
+ | `canonical_key.py` | 결정론적 키 정규화 | `normalizer.ts` |
1216
+ | `event_store.py` | append-only 이벤트 저장 | `event-store.ts` |
1217
+ | `task_matcher.py` | 가중치 기반 매칭 | `matcher.ts` |
1218
+ | `task_resolver.py` | 상태 전이 검증 | `resolver.ts` |
1219
+ | `projector_task.py` | 이벤트→엔티티 투영 | `projector.ts` |
1220
+ | `vector_worker.py` | 단일 쓰기 임베딩 | `vector-worker.ts` |
1221
+
1222
+ ### 4.10 Memory Graduation Pipeline (L0 → L4)
1223
+
1224
+ AXIOMMIND의 핵심 개념인 **다단계 메모리 승격 파이프라인**:
1225
+
1226
+ ```
1227
+ ┌─────────────────────────────────────────────────────────────────┐
1228
+ │ Memory Graduation Pipeline │
1229
+ ├─────────────────────────────────────────────────────────────────┤
1230
+ │ │
1231
+ │ L0: EventStore (Raw) │
1232
+ │ ├── 원본 채팅 로그, 프롬프트/응답 │
1233
+ │ ├── Append-only, 불변 │
1234
+ │ └── dedupe_key로 멱등성 보장 │
1235
+ │ ↓ │
1236
+ │ L1: Structured JSON │
1237
+ │ ├── LLM이 추출한 구조화된 데이터 │
1238
+ │ ├── 엔티티, 관계, 인사이트 │
1239
+ │ └── EvidenceAligner로 증거 스팬 정렬 │
1240
+ │ ↓ │
1241
+ │ L2: Idris Candidates (검증 대상) │
1242
+ │ ├── 타입 안전한 표현으로 변환 │
1243
+ │ ├── 의존적 타입으로 불변식 검증 │
1244
+ │ └── idris_generator.py가 생성 │
1245
+ │ ↓ │
1246
+ │ L3: Verified Knowledge │
1247
+ │ ├── Idris 타입체커 통과 │
1248
+ │ ├── 모순 없음 확인 │
1249
+ │ └── 신뢰도 높은 지식 │
1250
+ │ ↓ │
1251
+ │ L4: Active Memory (검색 가능) │
1252
+ │ ├── 벡터 인덱싱 완료 │
1253
+ │ ├── 실시간 검색 가능 │
1254
+ │ └── 컨텍스트 주입에 사용 │
1255
+ │ │
1256
+ └─────────────────────────────────────────────────────────────────┘
1257
+ ```
1258
+
1259
+ **Memory Plugin 적용**:
1260
+ - L0: 모든 대화를 `events` 테이블에 저장
1261
+ - L1: 주기적으로 인사이트 추출 (LLM 기반)
1262
+ - L2: TypeScript 강타입으로 검증 (Idris2 개념 적용)
1263
+ - L3: 테스트 통과한 검증된 지식
1264
+ - L4: LanceDB에 인덱싱되어 검색 가능한 상태
1265
+
1266
+ ### 4.11 AXIOMMIND 7가지 필수 원칙
1267
+
1268
+ | # | 원칙 | 설명 | Memory Plugin 적용 |
1269
+ |---|------|------|-------------------|
1270
+ | 1 | **진실의 원천(SoT)은 이벤트 로그** | 파생 테이블은 언제든 재구성 가능 | `events` 테이블만 영구 저장 |
1271
+ | 2 | **추가전용 구조** | events에 UPDATE/DELETE 금지 | `append()` 메서드만 제공 |
1272
+ | 3 | **멱등성 보장** | `dedupe_key`로 중복 제어 | content_hash + session_id |
1273
+ | 4 | **증거 범위는 파이프라인이 확정** | LLM은 인용문만, aligner가 스팬 계산 | `EvidenceAligner` 모듈 |
1274
+ | 5 | **Task는 엔티티** | 세션마다 새 항목 아닌 기존 업데이트 | `canonical_key`로 동일성 판단 |
1275
+ | 6 | **벡터 저장소 정합성** | DuckDB → outbox → LanceDB 단방향 | Single-Writer Pattern |
1276
+ | 7 | **DuckDB JSON 사용** | JSONB 제거, 표준 JSON만 | `metadata JSON` 컬럼 |
1277
+
1278
+ ```typescript
1279
+ // 원칙 적용 예시: EventStore 인터페이스
1280
+ interface EventStoreInterface {
1281
+ // 원칙 2: 추가전용 - append만 허용
1282
+ append(event: MemoryEvent): Promise<AppendResult>;
1283
+
1284
+ // 조회는 자유롭게
1285
+ getBySession(sessionId: string): Promise<MemoryEvent[]>;
1286
+ getRecent(limit: number): Promise<MemoryEvent[]>;
1287
+
1288
+ // 원칙 2 위반: UPDATE/DELETE 메서드 없음
1289
+ // update(): ❌ 금지
1290
+ // delete(): ❌ 금지
1291
+ }
1292
+ ```
1293
+
1294
+ ### 4.12 Evidence Aligner (증거 정렬기)
1295
+
1296
+ ```python
1297
+ # evidence_aligner.py - LLM 인용문을 정확한 스팬으로 변환
1298
+
1299
+ class EvidenceAligner:
1300
+ """
1301
+ 원칙 4: LLM은 인용문만 제공, aligner가 정확한 스팬 계산
1302
+
1303
+ LLM이 추출한 대략적인 인용문을 원본 텍스트에서
1304
+ 정확한 (start, end) 위치로 변환
1305
+ """
1306
+
1307
+ def align(
1308
+ self,
1309
+ source_text: str,
1310
+ llm_quote: str,
1311
+ fuzzy_threshold: float = 0.85
1312
+ ) -> Optional[EvidenceSpan]:
1313
+ """
1314
+ 1. 정확한 매칭 시도
1315
+ 2. 실패 시 fuzzy matching (Levenshtein)
1316
+ 3. 임계값 미달 시 None 반환
1317
+ """
1318
+ # 정확한 매칭
1319
+ exact_pos = source_text.find(llm_quote)
1320
+ if exact_pos >= 0:
1321
+ return EvidenceSpan(
1322
+ start=exact_pos,
1323
+ end=exact_pos + len(llm_quote),
1324
+ confidence=1.0,
1325
+ match_type="exact"
1326
+ )
1327
+
1328
+ # Fuzzy 매칭
1329
+ best_match = self._fuzzy_search(source_text, llm_quote)
1330
+ if best_match and best_match.score >= fuzzy_threshold:
1331
+ return EvidenceSpan(
1332
+ start=best_match.start,
1333
+ end=best_match.end,
1334
+ confidence=best_match.score,
1335
+ match_type="fuzzy"
1336
+ )
1337
+
1338
+ return None
1339
+
1340
+ def _fuzzy_search(self, text: str, query: str) -> Optional[FuzzyMatch]:
1341
+ # 슬라이딩 윈도우 + Levenshtein 거리
1342
+ ...
1343
+ ```
1344
+
1345
+ **Memory Plugin 적용**:
1346
+ - 사용자가 "이전에 rate limiting 얘기했잖아"라고 하면
1347
+ - LLM이 대략적인 인용문 추출
1348
+ - EvidenceAligner가 정확한 원본 위치 찾기
1349
+ - 해당 컨텍스트를 정확히 주입
1350
+
1351
+ ### 5.1 Vector Database: LanceDB
1352
+
1353
+ 선택 이유:
1354
+ - **Embedded 모드**: SQLite처럼 서버 없이 로컬 실행
1355
+ - **Apache Arrow 기반**: 빠른 디스크 접근
1356
+ - **다중 모달 지원**: 텍스트, 이미지, 오디오 임베딩
1357
+ - **DuckDB 호환**: SQL 쿼리 가능
1358
+
1359
+ ```python
1360
+ import lancedb
1361
+
1362
+ db = lancedb.connect("~/.claude-memory")
1363
+ table = db.create_table("conversations", data)
1364
+ results = table.search(query_embedding).limit(10).to_list()
1365
+ ```
1366
+
1367
+ ### 5.2 관계형 저장소: DuckDB
1368
+
1369
+ 선택 이유:
1370
+ - **임베디드**: 파일 기반, 서버 불필요
1371
+ - **분석 최적화**: OLAP 워크로드에 적합
1372
+ - **SQL 지원**: 친숙한 쿼리 언어
1373
+ - **Lance 포맷 호환**: LanceDB와 통합
1374
+
1375
+ ### 5.3 Embedding Model
1376
+
1377
+ 옵션:
1378
+ 1. **OpenAI text-embedding-3-small**: 고품질, API 비용
1379
+ 2. **sentence-transformers**: 로컬 실행, 무료
1380
+ 3. **Ollama embeddings**: 로컬 LLM 활용
1381
+
1382
+ 권장: sentence-transformers (로컬 우선) + OpenAI fallback
1383
+
1384
+ ---
1385
+
1386
+ ## 6. Idris2 활용 고려사항
1387
+
1388
+ ### 6.1 Idris2 개요
1389
+
1390
+ - **의존적 타입 시스템**: 타입 수준에서 프로그램 검증
1391
+ - **Type-Driven Development**: 타입이 프로그램 설계를 가이드
1392
+ - **Quantitative Type Theory (QTT)**: 선형 타입 지원
1393
+
1394
+ ### 6.2 적용 가능 영역
1395
+
1396
+ 1. **타입 안전한 이벤트 스키마**
1397
+ ```idris
1398
+ data MemoryEvent : Type where
1399
+ UserPrompt : (sessionId : String) -> (content : String) -> MemoryEvent
1400
+ AgentResponse : (sessionId : String) -> (content : String) -> MemoryEvent
1401
+ ```
1402
+
1403
+ 2. **불변성 보장**
1404
+ - Append-only EventStore의 불변성을 타입 수준에서 강제
1405
+
1406
+ 3. **정확성 증명**
1407
+ - 중복 제거 로직의 정확성 검증
1408
+ - 검색 알고리즘의 속성 증명
1409
+
1410
+ ### 6.3 실용적 접근
1411
+
1412
+ Idris2를 직접 사용하기보다 **개념적 영감**으로 활용:
1413
+ - TypeScript의 강타입 시스템 적극 활용
1414
+ - Zod/io-ts로 런타임 타입 검증
1415
+ - 불변 데이터 구조 (Immutable.js 또는 순수 함수형 패턴)
1416
+
1417
+ ---
1418
+
1419
+ ## 7. 참조 링크
1420
+
1421
+ ### Claude Code Plugin 개발
1422
+ - [Create plugins - Claude Code Docs](https://code.claude.com/docs/en/plugins)
1423
+ - [Claude Code Plugins README](https://github.com/anthropics/claude-code/blob/main/plugins/README.md)
1424
+ - [Hook Development SKILL](https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/hook-development/SKILL.md)
1425
+ - [Claude Code Plugins Complete Guide](https://jangwook.net/en/blog/en/claude-code-plugins-complete-guide/)
1426
+
1427
+ ### AI Memory Systems
1428
+ - [Mem0: Building Production-Ready AI Agents](https://arxiv.org/pdf/2504.19413)
1429
+ - [AWS AgentCore Long-term Memory](https://aws.amazon.com/blogs/machine-learning/building-smarter-ai-agents-agentcore-long-term-memory-deep-dive/)
1430
+ - [Google Vertex AI Memory Bank](https://docs.cloud.google.com/agent-builder/agent-engine/memory-bank/overview)
1431
+ - [LangChain Conversational Memory](https://www.pinecone.io/learn/series/langchain/langchain-conversational-memory/)
1432
+
1433
+ ### Vector Databases
1434
+ - [LanceDB](https://lancedb.com/)
1435
+ - [Lance Format on GitHub](https://github.com/lance-format/lance)
1436
+
1437
+ ### Idris2
1438
+ - [Idris2 Official Site](https://www.idris-lang.org/)
1439
+ - [Idris 2: Quantitative Type Theory in Practice](https://arxiv.org/abs/2104.00480)
1440
+ - [Idris2 GitHub](https://github.com/idris-lang/Idris2)
1441
+
1442
+ ---
1443
+
1444
+ ## 8. 용어 정의
1445
+
1446
+ | 용어 | 정의 |
1447
+ |------|------|
1448
+ | **Memory** | 과거 대화에서 추출/저장된 정보 |
1449
+ | **Embedding** | 텍스트를 벡터로 변환한 표현 |
1450
+ | **Semantic Search** | 의미 기반 유사도 검색 |
1451
+ | **EventStore** | 모든 이벤트를 시간순으로 저장하는 append-only 저장소 |
1452
+ | **Hook** | 특정 이벤트 발생 시 실행되는 스크립트 |
1453
+ | **MCP** | Model Context Protocol - Claude와 외부 도구 연결 |
1454
+
1455
+ ## 2026-02-25T12:31:21.755Z | 235651b6-564e-4b06-8fa5-48a5e946455a
1456
+ - type: session_summary
1457
+ - session: import:organized
1458
+ # memU Adoption Notes (claude-memory-layer)
1459
+
1460
+ 이 프로젝트에 적용된 memU 장점 요약입니다.
1461
+
1462
+ ## 1) Dual Retrieval Strategy
1463
+ - `strategy: "fast" | "deep" | "auto"`
1464
+ - `fast`: 키워드 기반(FTS/keyword) 우선 탐색으로 저지연 검색
1465
+ - `deep`: 임베딩 + 벡터 검색 + 재정렬(키워드 오버랩 가중)로 정밀 검색
1466
+
1467
+ ## 2) Scoped Retrieval Filters
1468
+ `scope`로 검색 범위를 좁혀 정확도를 높입니다.
1469
+
1470
+ - `sessionId` / `sessionIdPrefix`
1471
+ - `eventTypes`
1472
+ - `canonicalKeyPrefix`
1473
+ - `contentIncludes` (부분 문자열 OR)
1474
+ - `metadata` (dot-path, 예: `scope.project.id`)
1475
+
1476
+ ## 3) Hybrid Rerank Behavior
1477
+ `rerankWithKeyword=true`일 때 semantic score에 키워드 오버랩/최근성 점수를 가중해 재정렬합니다.
1478
+
1479
+ ## 4) Test Coverage
1480
+ - `tests/retriever.memu-adoption.test.ts`
1481
+ - metadata dot-path 스코프 필터
1482
+ - fast 전략 키워드 경로
1483
+ - `tests/retriever-strategy-scope.test.ts`
1484
+ - fast/deep 전략 및 복합 스코프 필터
1485
+
1486
+ ## Quick Example
1487
+ ```ts
1488
+ await retriever.retrieve('브리핑', {
1489
+ strategy: 'deep',
1490
+ topK: 10,
1491
+ scope: {
1492
+ sessionIdPrefix: 'agent:main:',
1493
+ canonicalKeyPrefix: 'pref/briefing',
1494
+ metadata: { 'scope.project.id': 'alpha' }
1495
+ }
1496
+ });
1497
+ ```
1498
+
1499
+ ## 2026-02-25T12:31:21.756Z | 50c73261-3d2b-490d-ad69-3a4c68cff7c9
1500
+ - type: session_summary
1501
+ - session: import:organized
1502
+ # Operations Runbook
1503
+
1504
+ ## Health scripts
1505
+
1506
+ - `npm run ops:sync-gap:report`
1507
+ - `npm run ops:sync-gap:fix`
1508
+ - `npm run ops:sync-gap:heal`
1509
+ - `npm run ops:review:resolve`
1510
+ - `npm run ops:heartbeat`
1511
+
1512
+ ## Status policy
1513
+
1514
+ - `ok`: no failed outbox items and no un-leveled events after heal
1515
+ - `needs-attention`: failed outbox remains or level sync still broken
1516
+
1517
+ ## Notes
1518
+
1519
+ These scripts are best-effort operational automation for Claude memory DB (`~/.claude-code/memory/events.sqlite`).
1520
+
1521
+ ## 2026-02-25T12:31:26.190Z | 6813c625-f6f1-44bf-8758-088cf3ba1434
1522
+ - type: session_summary
1523
+ - session: import:organized
1524
+ # Implementation Plan: Claude Code Memory Plugin
1525
+
1526
+ ## 1. 개발 단계 개요
1527
+
1528
+ AXIOMMIND 파이프라인 구현 단계에 맞춰 구성:
1529
+
1530
+ ```
1531
+ ┌─────────────────────────────────────────────────────────────────┐
1532
+ │ P0: 필수 품질 (Must Have) │
1533
+ │ ├── EventStore (append-only, dedupe) │
1534
+ │ ├── EvidenceAligner (증거 스팬 정렬) │
1535
+ │ ├── Task Entity System (canonical_key) │
1536
+ │ ├── Vector Outbox (single-writer) │
1537
+ │ ├── Basic Hooks (SessionStart, Stop) │
1538
+ │ └── CLI 기본 명령어 │
1539
+ ├─────────────────────────────────────────────────────────────────┤
1540
+ │ P1: 운영 (Operations) │
1541
+ │ ├── build_runs 테이블 (파이프라인 실행 추적) │
1542
+ │ ├── conflict_ledger (충돌 기록) │
1543
+ │ ├── decision_ledger (의사결정 기록) │
1544
+ │ ├── 메트릭 스켈레톤 │
1545
+ │ └── 에러 복구 메커니즘 │
1546
+ ├─────────────────────────────────────────────────────────────────┤
1547
+ │ P2: 검색 (Retrieval) │
1548
+ │ ├── 하이브리드 검색 (Vector + FTS) │
1549
+ │ ├── 골드셋 평가 시스템 │
1550
+ │ ├── 인사이트 추출 (LLM 기반) │
1551
+ │ └── L2→L3→L4 승격 파이프라인 │
1552
+ └─────────────────────────────────────────────────────────────────┘
1553
+ ```
1554
+
1555
+ ### 구현 Phase 매핑
1556
+
1557
+ | AXIOMMIND | 플러그인 Phase | 핵심 산출물 |
1558
+ |-----------|---------------|-------------|
1559
+ | **P0** | Phase 0-1 | EventStore, VectorWorker, 기본 Hook |
1560
+ | **P0** | Phase 2-3 | Embedder, Retriever, Hook 통합 |
1561
+ | **P1** | Phase 4 | CLI, 운영 도구, 메트릭 |
1562
+ | **P2** | Phase 5 | 하이브리드 검색, 평가, 최적화 |
1563
+
1564
+ ```
1565
+ Phase 0: 프로젝트 설정
1566
+
1567
+ Phase 1: Core Storage Layer (P0 - EventStore, Outbox)
1568
+
1569
+ Phase 2: Embedding & Retrieval (P0 - Vector, Matcher)
1570
+
1571
+ Phase 3: Hook Integration (P0 - 기본 동작)
1572
+
1573
+ Phase 4: Commands & CLI (P1 - 운영)
1574
+
1575
+ Phase 5: Testing & Polish (P2 - 검색 최적화)
1576
+ ```
1577
+
1578
+ ---
1579
+
1580
+ ## Phase 0: 프로젝트 설정
1581
+
1582
+ ### 0.1 디렉토리 구조 생성
1583
+
1584
+ ```
1585
+ code-memory/
1586
+ ├── .claude-plugin/
1587
+ │ └── plugin.json # 플러그인 메타데이터
1588
+ ├── commands/
1589
+ │ ├── search.md # /code-memory:search
1590
+ │ ├── history.md # /code-memory:history
1591
+ │ ├── insights.md # /code-memory:insights
1592
+ │ ├── forget.md # /code-memory:forget
1593
+ │ └── stats.md # /code-memory:stats
1594
+ ├── hooks/
1595
+ │ └── hooks.json # Hook 설정
1596
+ ├── src/
1597
+ │ ├── cli/
1598
+ │ │ ├── index.ts # CLI 엔트리포인트
1599
+ │ │ ├── commands/
1600
+ │ │ │ ├── session-start.ts
1601
+ │ │ │ ├── session-end.ts
1602
+ │ │ │ ├── search.ts
1603
+ │ │ │ ├── save.ts
1604
+ │ │ │ └── init.ts
1605
+ │ │ └── utils.ts
1606
+ │ ├── core/
1607
+ │ │ ├── canonical-key.ts # 정규화된 키 생성 (AXIOMMIND)
1608
+ │ │ ├── event-store.ts # DuckDB 이벤트 저장소
1609
+ │ │ ├── vector-store.ts # LanceDB 벡터 저장소
1610
+ │ │ ├── vector-worker.ts # Single-writer 패턴 워커 (AXIOMMIND)
1611
+ │ │ ├── embedder.ts # 임베딩 생성
1612
+ │ │ ├── matcher.ts # 가중치 기반 매칭 (AXIOMMIND)
1613
+ │ │ ├── evidence-aligner.ts # 증거 스팬 정렬 (AXIOMMIND 원칙4)
1614
+ │ │ ├── retriever.ts # 기억 검색
1615
+ │ │ ├── projector.ts # 이벤트→엔티티 투영 (AXIOMMIND)
1616
+ │ │ ├── graduation.ts # L0→L4 승격 파이프라인 (AXIOMMIND)
1617
+ │ │ └── types.ts # 타입 정의
1618
+ │ ├── hooks/
1619
+ │ │ ├── session-start.ts
1620
+ │ │ ├── user-prompt-submit.ts
1621
+ │ │ ├── stop.ts
1622
+ │ │ └── session-end.ts
1623
+ │ └── index.ts
1624
+ ├── tests/
1625
+ │ ├── event-store.test.ts
1626
+ │ ├── vector-store.test.ts
1627
+ │ ├── retriever.test.ts
1628
+ │ └── integration.test.ts
1629
+ ├── scripts/
1630
+ │ └── build.ts
1631
+ ├── package.json
1632
+ ├── tsconfig.json
1633
+ ├── vitest.config.ts
1634
+ ├── README.md
1635
+ ├── spec.md
1636
+ ├── plan.md
1637
+ └── context.md
1638
+ ```
1639
+
1640
+ ### 0.2 초기 설정 작업
1641
+
1642
+ ```bash
1643
+ # 1. package.json 생성
1644
+ npm init -y
1645
+
1646
+ # 2. TypeScript 및 핵심 의존성 설치
1647
+ npm install -D typescript @types/node tsx esbuild vitest
1648
+
1649
+ # 3. 런타임 의존성
1650
+ npm install zod commander duckdb lancedb
1651
+
1652
+ # 4. 임베딩 (선택)
1653
+ npm install @xenova/transformers # 또는 Python sentence-transformers
1654
+ ```
1655
+
1656
+ ### 0.3 TypeScript 설정
1657
+
1658
+ ```json
1659
+ // tsconfig.json
1660
+ {
1661
+ "compilerOptions": {
1662
+ "target": "ES2022",
1663
+ "module": "ESNext",
1664
+ "moduleResolution": "bundler",
1665
+ "strict": true,
1666
+ "esModuleInterop": true,
1667
+ "skipLibCheck": true,
1668
+ "outDir": "dist",
1669
+ "rootDir": "src",
1670
+ "declaration": true,
1671
+ "resolveJsonModule": true
1672
+ },
1673
+ "include": ["src/**/*"],
1674
+ "exclude": ["node_modules", "dist", "tests"]
1675
+ }
1676
+ ```
1677
+
1678
+ ---
1679
+
1680
+ ## Phase 1: Core Storage Layer
1681
+
1682
+ ### 1.1 타입 정의 (src/core/types.ts)
1683
+
1684
+ ```typescript
1685
+ // Idris2 영감: 완전하고 불변한 타입 정의
1686
+
1687
+ import { z } from 'zod';
1688
+
1689
+ // 이벤트 타입 스키마
1690
+ export const EventTypeSchema = z.enum([
1691
+ 'user_prompt',
1692
+ 'agent_response',
1693
+ 'session_summary'
1694
+ ]);
1695
+ export type EventType = z.infer<typeof EventTypeSchema>;
1696
+
1697
+ // 메모리 이벤트 스키마
1698
+ export const MemoryEventSchema = z.object({
1699
+ id: z.string().uuid(),
1700
+ eventType: EventTypeSchema,
1701
+ sessionId: z.string(),
1702
+ timestamp: z.date(),
1703
+ content: z.string(),
1704
+ contentHash: z.string(),
1705
+ metadata: z.record(z.unknown()).optional()
1706
+ });
1707
+ export type MemoryEvent = z.infer<typeof MemoryEventSchema>;
1708
+
1709
+ // 세션 스키마
1710
+ export const SessionSchema = z.object({
1711
+ id: z.string(),
1712
+ startedAt: z.date(),
1713
+ endedAt: z.date().optional(),
1714
+ projectPath: z.string().optional(),
1715
+ summary: z.string().optional(),
1716
+ tags: z.array(z.string()).optional()
1717
+ });
1718
+ export type Session = z.infer<typeof SessionSchema>;
1719
+
1720
+ // 검색 결과
1721
+ export const MemoryMatchSchema = z.object({
1722
+ event: MemoryEventSchema,
1723
+ score: z.number().min(0).max(1),
1724
+ relevanceReason: z.string().optional()
1725
+ });
1726
+ export type MemoryMatch = z.infer<typeof MemoryMatchSchema>;
1727
+
1728
+ // 설정 스키마
1729
+ export const ConfigSchema = z.object({
1730
+ storage: z.object({
1731
+ path: z.string().default('~/.claude-code/memory'),
1732
+ maxSizeMB: z.number().default(500)
1733
+ }),
1734
+ embedding: z.object({
1735
+ provider: z.enum(['local', 'openai']).default('local'),
1736
+ model: z.string().default('all-MiniLM-L6-v2'),
1737
+ batchSize: z.number().default(32)
1738
+ }),
1739
+ retrieval: z.object({
1740
+ topK: z.number().default(5),
1741
+ minScore: z.number().default(0.7),
1742
+ maxTokens: z.number().default(2000)
1743
+ })
1744
+ });
1745
+ export type Config = z.infer<typeof ConfigSchema>;
1746
+
1747
+ // AXIOMMIND: Matching 결과 타입
1748
+ export const MatchConfidenceSchema = z.enum(['high', 'suggested', 'none']);
1749
+ export type MatchConfidence = z.infer<typeof MatchConfidenceSchema>;
1750
+
1751
+ export const MatchResultSchema = z.object({
1752
+ match: MemoryMatchSchema.nullable(),
1753
+ confidence: MatchConfidenceSchema,
1754
+ gap: z.number().optional(),
1755
+ alternatives: z.array(MemoryMatchSchema).optional()
1756
+ });
1757
+ export type MatchResult = z.infer<typeof MatchResultSchema>;
1758
+
1759
+ // AXIOMMIND: Matching Thresholds
1760
+ export const MATCH_THRESHOLDS = {
1761
+ minCombinedScore: 0.92,
1762
+ minGap: 0.03,
1763
+ suggestionThreshold: 0.75
1764
+ } as const;
1765
+ ```
1766
+
1767
+ ### 1.2 Canonical Key 구현 (src/core/canonical-key.ts) - AXIOMMIND
1768
+
1769
+ ```typescript
1770
+ /**
1771
+ * AXIOMMIND canonical_key.py 포팅
1772
+ * 동일한 제목은 항상 동일한 키를 생성하는 결정론적 정규화
1773
+ */
1774
+
1775
+ import { createHash } from 'crypto';
1776
+
1777
+ const MAX_KEY_LENGTH = 200;
1778
+
1779
+ /**
1780
+ * 텍스트를 정규화된 canonical key로 변환
1781
+ *
1782
+ * 정규화 단계:
1783
+ * 1. NFKC 유니코드 정규화
1784
+ * 2. 소문자 변환
1785
+ * 3. 구두점 제거
1786
+ * 4. 연속 공백 정리
1787
+ * 5. 컨텍스트 추가 (선택)
1788
+ * 6. 긴 키 truncate + MD5
1789
+ */
1790
+ export function makeCanonicalKey(
1791
+ title: string,
1792
+ context?: { project?: string; sessionId?: string }
1793
+ ): string {
1794
+ // Step 1: NFKC 정규화
1795
+ let normalized = title.normalize('NFKC');
1796
+
1797
+ // Step 2: 소문자 변환
1798
+ normalized = normalized.toLowerCase();
1799
+
1800
+ // Step 3: 구두점 제거 (유니코드 호환)
1801
+ normalized = normalized.replace(/[^\p{L}\p{N}\s]/gu, '');
1802
+
1803
+ // Step 4: 연속 공백 정리
1804
+ normalized = normalized.replace(/\s+/g, ' ').trim();
1805
+
1806
+ // Step 5: 컨텍스트 추가
1807
+ let key = normalized;
1808
+ if (context?.project) {
1809
+ key = `${context.project}::${key}`;
1810
+ }
1811
+
1812
+ // Step 6: 긴 키 처리
1813
+ if (key.length > MAX_KEY_LENGTH) {
1814
+ const hashSuffix = createHash('md5').update(key).digest('hex').slice(0, 8);
1815
+ key = key.slice(0, MAX_KEY_LENGTH - 9) + '_' + hashSuffix;
1816
+ }
1817
+
1818
+ return key;
1819
+ }
1820
+
1821
+ /**
1822
+ * 두 텍스트가 동일한 canonical key를 가지는지 확인
1823
+ */
1824
+ export function isSameCanonicalKey(a: string, b: string): boolean {
1825
+ return makeCanonicalKey(a) === makeCanonicalKey(b);
1826
+ }
1827
+
1828
+ /**
1829
+ * Dedupe key 생성 (content + session으로 유일성 보장)
1830
+ */
1831
+ export function makeDedupeKey(content: string, sessionId: string): string {
1832
+ const contentHash = createHash('sha256').update(content).digest('hex');
1833
+ return `${sessionId}:${contentHash}`;
1834
+ }
1835
+ ```
1836
+
1837
+ ### 1.3 Event Store 구현 (src/core/event-store.ts)
1838
+
1839
+ ```typescript
1840
+ // AXIOMMIND 스타일: append-only, 멱등성, 단일 진실 공급원
1841
+
1842
+ import { Database } from 'duckdb';
1843
+ import { createHash } from 'crypto';
1844
+ import { MemoryEvent, EventType } from './types';
1845
+
1846
+ export class EventStore {
1847
+ private db: Database;
1848
+
1849
+ constructor(dbPath: string) {
1850
+ this.db = new Database(dbPath);
1851
+ this.initialize();
1852
+ }
1853
+
1854
+ private initialize(): void {
1855
+ // 이벤트 테이블 (불변, append-only)
1856
+ this.db.run(`
1857
+ CREATE TABLE IF NOT EXISTS events (
1858
+ id VARCHAR PRIMARY KEY,
1859
+ event_type VARCHAR NOT NULL,
1860
+ session_id VARCHAR NOT NULL,
1861
+ timestamp TIMESTAMP NOT NULL,
1862
+ content TEXT NOT NULL,
1863
+ metadata JSON,
1864
+ content_hash VARCHAR UNIQUE
1865
+ )
1866
+ `);
1867
+
1868
+ // 중복 방지 테이블
1869
+ this.db.run(`
1870
+ CREATE TABLE IF NOT EXISTS event_dedup (
1871
+ content_hash VARCHAR PRIMARY KEY,
1872
+ event_id VARCHAR NOT NULL
1873
+ )
1874
+ `);
1875
+
1876
+ // 세션 테이블
1877
+ this.db.run(`
1878
+ CREATE TABLE IF NOT EXISTS sessions (
1879
+ id VARCHAR PRIMARY KEY,
1880
+ started_at TIMESTAMP NOT NULL,
1881
+ ended_at TIMESTAMP,
1882
+ project_path VARCHAR,
1883
+ summary TEXT
1884
+ )
1885
+ `);
1886
+ }
1887
+
1888
+ // 멱등성 보장 저장
1889
+ async append(event: Omit<MemoryEvent, 'id' | 'contentHash'>): Promise<{
1890
+ success: boolean;
1891
+ eventId?: string;
1892
+ isDuplicate?: boolean;
1893
+ }> {
1894
+ const contentHash = this.hashContent(event.content);
1895
+
1896
+ // 중복 확인
1897
+ const existing = this.db.prepare(`
1898
+ SELECT event_id FROM event_dedup WHERE content_hash = ?
1899
+ `).get(contentHash);
1900
+
1901
+ if (existing) {
1902
+ return { success: true, eventId: existing.event_id, isDuplicate: true };
1903
+ }
1904
+
1905
+ const id = crypto.randomUUID();
1906
+
1907
+ this.db.run(`
1908
+ INSERT INTO events (id, event_type, session_id, timestamp, content, metadata, content_hash)
1909
+ VALUES (?, ?, ?, ?, ?, ?, ?)
1910
+ `, [id, event.eventType, event.sessionId, event.timestamp, event.content,
1911
+ JSON.stringify(event.metadata), contentHash]);
1912
+
1913
+ this.db.run(`
1914
+ INSERT INTO event_dedup (content_hash, event_id) VALUES (?, ?)
1915
+ `, [contentHash, id]);
1916
+
1917
+ return { success: true, eventId: id, isDuplicate: false };
1918
+ }
1919
+
1920
+ private hashContent(content: string): string {
1921
+ return createHash('sha256').update(content).digest('hex');
1922
+ }
1923
+
1924
+ // 세션별 이벤트 조회
1925
+ async getSessionEvents(sessionId: string): Promise<MemoryEvent[]> {
1926
+ return this.db.prepare(`
1927
+ SELECT * FROM events WHERE session_id = ? ORDER BY timestamp ASC
1928
+ `).all(sessionId);
1929
+ }
1930
+
1931
+ // 최근 이벤트 조회
1932
+ async getRecentEvents(limit: number = 100): Promise<MemoryEvent[]> {
1933
+ return this.db.prepare(`
1934
+ SELECT * FROM events ORDER BY timestamp DESC LIMIT ?
1935
+ `).all(limit);
1936
+ }
1937
+ }
1938
+ ```
1939
+
1940
+ ### 1.3 Vector Store 구현 (src/core/vector-store.ts)
1941
+
1942
+ ```typescript
1943
+ import * as lancedb from 'lancedb';
1944
+
1945
+ export class VectorStore {
1946
+ private db: lancedb.Connection;
1947
+ private table: lancedb.Table | null = null;
1948
+
1949
+ constructor(private dbPath: string) {}
1950
+
1951
+ async initialize(): Promise<void> {
1952
+ this.db = await lancedb.connect(this.dbPath);
1953
+
1954
+ // 테이블이 없으면 생성 (첫 데이터 삽입 시)
1955
+ try {
1956
+ this.table = await this.db.openTable('conversations');
1957
+ } catch {
1958
+ // 테이블이 없으면 나중에 생성
1959
+ this.table = null;
1960
+ }
1961
+ }
1962
+
1963
+ async upsert(data: {
1964
+ id: string;
1965
+ eventId: string;
1966
+ sessionId: string;
1967
+ eventType: string;
1968
+ content: string;
1969
+ vector: number[];
1970
+ timestamp: string;
1971
+ metadata?: Record<string, unknown>;
1972
+ }): Promise<void> {
1973
+ if (!this.table) {
1974
+ // 첫 데이터로 테이블 생성
1975
+ this.table = await this.db.createTable('conversations', [data]);
1976
+ return;
1977
+ }
1978
+
1979
+ await this.table.add([data]);
1980
+ }
1981
+
1982
+ async search(queryVector: number[], options: {
1983
+ limit?: number;
1984
+ minScore?: number;
1985
+ filter?: string;
1986
+ } = {}): Promise<Array<{
1987
+ id: string;
1988
+ eventId: string;
1989
+ content: string;
1990
+ score: number;
1991
+ }>> {
1992
+ if (!this.table) {
1993
+ return [];
1994
+ }
1995
+
1996
+ const { limit = 5, minScore = 0.7 } = options;
1997
+
1998
+ const results = await this.table
1999
+ .search(queryVector)
2000
+ .limit(limit)
2001
+ .execute();
2002
+
2003
+ return results
2004
+ .filter(r => r._distance <= (1 - minScore)) // distance to score
2005
+ .map(r => ({
2006
+ id: r.id,
2007
+ eventId: r.eventId,
2008
+ content: r.content,
2009
+ score: 1 - r._distance
2010
+ }));
2011
+ }
2012
+
2013
+ async delete(eventId: string): Promise<void> {
2014
+ if (!this.table) return;
2015
+ await this.table.delete(`eventId = "${eventId}"`);
2016
+ }
2017
+ }
2018
+ ```
2019
+
2020
+ ### 1.4 Vector Worker 구현 (src/core/vector-worker.ts) - AXIOMMIND Single-Writer
2021
+
2022
+ ```typescript
2023
+ /**
2024
+ * AXIOMMIND vector_worker.py 포팅
2025
+ * Single-Writer 패턴으로 LanceDB 동시성 문제 해결
2026
+ *
2027
+ * 원리:
2028
+ * 1. 이벤트 저장 시 embedding_outbox에 작업 추가 (빠름)
2029
+ * 2. 별도 워커가 outbox를 순차적으로 처리 (단일 쓰기)
2030
+ * 3. 처리 완료 시 outbox에서 삭제
2031
+ */
2032
+
2033
+ import { Database } from 'duckdb';
2034
+ import { VectorStore } from './vector-store';
2035
+ import { Embedder } from './embedder';
2036
+
2037
+ interface OutboxItem {
2038
+ id: string;
2039
+ eventId: string;
2040
+ content: string;
2041
+ status: 'pending' | 'processing' | 'done' | 'failed';
2042
+ retryCount: number;
2043
+ createdAt: Date;
2044
+ }
2045
+
2046
+ export class VectorWorker {
2047
+ private isRunning = false;
2048
+ private pollInterval = 1000; // 1초
2049
+
2050
+ constructor(
2051
+ private db: Database,
2052
+ private vectorStore: VectorStore,
2053
+ private embedder: Embedder
2054
+ ) {}
2055
+
2056
+ /**
2057
+ * Outbox에 임베딩 작업 추가 (빠른 반환)
2058
+ */
2059
+ async enqueue(eventId: string, content: string): Promise<string> {
2060
+ const id = crypto.randomUUID();
2061
+
2062
+ this.db.run(`
2063
+ INSERT INTO embedding_outbox (id, event_id, content, status, retry_count, created_at)
2064
+ VALUES (?, ?, ?, 'pending', 0, NOW())
2065
+ `, [id, eventId, content]);
2066
+
2067
+ return id;
2068
+ }
2069
+
2070
+ /**
2071
+ * 워커 시작 (백그라운드에서 실행)
2072
+ */
2073
+ async start(): Promise<void> {
2074
+ if (this.isRunning) return;
2075
+ this.isRunning = true;
2076
+
2077
+ while (this.isRunning) {
2078
+ await this.processOutbox();
2079
+ await this.sleep(this.pollInterval);
2080
+ }
2081
+ }
2082
+
2083
+ /**
2084
+ * 워커 중지
2085
+ */
2086
+ stop(): void {
2087
+ this.isRunning = false;
2088
+ }
2089
+
2090
+ /**
2091
+ * Outbox 처리 (핵심 로직)
2092
+ */
2093
+ private async processOutbox(batchSize: number = 32): Promise<number> {
2094
+ // 1. Pending 항목 가져오기 + 락 획득 (atomic update)
2095
+ const pending = this.db.prepare(`
2096
+ UPDATE embedding_outbox
2097
+ SET status = 'processing'
2098
+ WHERE id IN (
2099
+ SELECT id FROM embedding_outbox
2100
+ WHERE status = 'pending'
2101
+ ORDER BY created_at
2102
+ LIMIT ?
2103
+ )
2104
+ RETURNING *
2105
+ `).all(batchSize) as OutboxItem[];
2106
+
2107
+ if (pending.length === 0) {
2108
+ return 0;
2109
+ }
2110
+
2111
+ try {
2112
+ // 2. 배치 임베딩 생성
2113
+ const contents = pending.map(p => p.content);
2114
+ const vectors = await this.embedder.embedBatch(contents);
2115
+
2116
+ // 3. LanceDB에 저장 (단일 쓰기 - 동시성 안전)
2117
+ for (let i = 0; i < pending.length; i++) {
2118
+ const item = pending[i];
2119
+ await this.vectorStore.upsert({
2120
+ id: crypto.randomUUID(),
2121
+ eventId: item.eventId,
2122
+ sessionId: '', // 필요시 조회
2123
+ eventType: '',
2124
+ content: item.content.slice(0, 1000), // 미리보기용
2125
+ vector: vectors[i],
2126
+ timestamp: new Date().toISOString()
2127
+ });
2128
+ }
2129
+
2130
+ // 4. 성공한 항목 삭제
2131
+ const ids = pending.map(p => `'${p.id}'`).join(',');
2132
+ this.db.run(`DELETE FROM embedding_outbox WHERE id IN (${ids})`);
2133
+
2134
+ return pending.length;
2135
+
2136
+ } catch (error) {
2137
+ // 5. 실패 시 retry_count 증가
2138
+ const ids = pending.map(p => `'${p.id}'`).join(',');
2139
+ this.db.run(`
2140
+ UPDATE embedding_outbox
2141
+ SET status = CASE WHEN retry_count >= 3 THEN 'failed' ELSE 'pending' END,
2142
+ retry_count = retry_count + 1,
2143
+ error_message = ?
2144
+ WHERE id IN (${ids})
2145
+ `, [String(error)]);
2146
+
2147
+ return 0;
2148
+ }
2149
+ }
2150
+
2151
+ private sleep(ms: number): Promise<void> {
2152
+ return new Promise(resolve => setTimeout(resolve, ms));
2153
+ }
2154
+ }
2155
+ ```
2156
+
2157
+ ### 1.5 Matcher 구현 (src/core/matcher.ts) - AXIOMMIND Weighted Scoring
2158
+
2159
+ ```typescript
2160
+ /**
2161
+ * AXIOMMIND task_matcher.py 포팅
2162
+ * 가중치 기반 스코어링 + 엄격한 매칭 임계값
2163
+ */
2164
+
2165
+ import { MemoryMatch, MatchResult, MATCH_THRESHOLDS } from './types';
2166
+
2167
+ interface ScoringWeights {
2168
+ semanticSimilarity: number;
2169
+ ftsScore: number;
2170
+ recencyBonus: number;
2171
+ statusWeight: number;
2172
+ }
2173
+
2174
+ const DEFAULT_WEIGHTS: ScoringWeights = {
2175
+ semanticSimilarity: 0.4,
2176
+ ftsScore: 0.25,
2177
+ recencyBonus: 0.2,
2178
+ statusWeight: 0.15
2179
+ };
2180
+
2181
+ interface RawSearchResult {
2182
+ id: string;
2183
+ eventId: string;
2184
+ content: string;
2185
+ vectorScore: number; // 벡터 유사도 (0-1)
2186
+ ftsScore?: number; // 전문 검색 점수 (0-1)
2187
+ timestamp: Date;
2188
+ eventType: string;
2189
+ }
2190
+
2191
+ /**
2192
+ * 가중치 결합 점수 계산
2193
+ */
2194
+ export function calculateWeightedScore(
2195
+ result: RawSearchResult,
2196
+ weights: ScoringWeights = DEFAULT_WEIGHTS
2197
+ ): number {
2198
+ // 최신성 가산점 (30일 이내 = 1.0, 이후 감소)
2199
+ const daysSince = (Date.now() - result.timestamp.getTime()) / (1000 * 60 * 60 * 24);
2200
+ const recencyScore = Math.max(0, 1 - daysSince / 30);
2201
+
2202
+ // 상태별 가중치 (agent_response > user_prompt)
2203
+ const statusScore = result.eventType === 'agent_response' ? 1.0 : 0.8;
2204
+
2205
+ const score =
2206
+ result.vectorScore * weights.semanticSimilarity +
2207
+ (result.ftsScore ?? 0) * weights.ftsScore +
2208
+ recencyScore * weights.recencyBonus +
2209
+ statusScore * weights.statusWeight;
2210
+
2211
+ return Math.min(1, Math.max(0, score)); // 0-1 범위로 클램프
2212
+ }
2213
+
2214
+ /**
2215
+ * 엄격한 매칭: top-1이 확실히 우세할 때만 확정
2216
+ *
2217
+ * AXIOMMIND 규칙:
2218
+ * - combined score >= 0.92 AND gap >= 0.03 → 'high' (확정)
2219
+ * - 0.75 <= score < 0.92 → 'suggested' (제안)
2220
+ * - score < 0.75 → 'none' (매칭 없음)
2221
+ */
2222
+ export function matchWithConfidence(
2223
+ candidates: MemoryMatch[]
2224
+ ): MatchResult {
2225
+ if (candidates.length === 0) {
2226
+ return { match: null, confidence: 'none' };
2227
+ }
2228
+
2229
+ // 점수순 정렬
2230
+ const sorted = [...candidates].sort((a, b) => b.score - a.score);
2231
+ const top = sorted[0];
2232
+
2233
+ // 임계값 미달
2234
+ if (top.score < MATCH_THRESHOLDS.suggestionThreshold) {
2235
+ return { match: null, confidence: 'none' };
2236
+ }
2237
+
2238
+ // 확정 매칭 체크
2239
+ if (top.score >= MATCH_THRESHOLDS.minCombinedScore) {
2240
+ // 단일 후보
2241
+ if (sorted.length === 1) {
2242
+ return { match: top, confidence: 'high' };
2243
+ }
2244
+
2245
+ // 2위와의 gap 체크
2246
+ const gap = top.score - sorted[1].score;
2247
+ if (gap >= MATCH_THRESHOLDS.minGap) {
2248
+ return { match: top, confidence: 'high', gap };
2249
+ }
2250
+ }
2251
+
2252
+ // 제안 모드 (확실하지 않음)
2253
+ return {
2254
+ match: top,
2255
+ confidence: 'suggested',
2256
+ gap: sorted.length > 1 ? top.score - sorted[1].score : undefined,
2257
+ alternatives: sorted.slice(1, 4) // 상위 3개 대안
2258
+ };
2259
+ }
2260
+
2261
+ /**
2262
+ * 검색 결과를 MemoryMatch로 변환
2263
+ */
2264
+ export function toMemoryMatch(
2265
+ result: RawSearchResult,
2266
+ weights?: ScoringWeights
2267
+ ): MemoryMatch {
2268
+ const score = calculateWeightedScore(result, weights);
2269
+
2270
+ return {
2271
+ event: {
2272
+ id: result.eventId,
2273
+ eventType: result.eventType as any,
2274
+ sessionId: '',
2275
+ timestamp: result.timestamp,
2276
+ content: result.content,
2277
+ contentHash: ''
2278
+ },
2279
+ score,
2280
+ relevanceReason: `Weighted score: ${(score * 100).toFixed(1)}% ` +
2281
+ `(vector: ${(result.vectorScore * 100).toFixed(0)}%)`
2282
+ };
2283
+ }
2284
+ ```
2285
+
2286
+ ### 1.6 Evidence Aligner 구현 (src/core/evidence-aligner.ts) - AXIOMMIND 원칙4
2287
+
2288
+ ```typescript
2289
+ /**
2290
+ * AXIOMMIND 원칙 4: 증거 범위는 파이프라인이 확정
2291
+ *
2292
+ * LLM이 추출한 대략적인 인용문을 원본 텍스트에서
2293
+ * 정확한 (start, end) 위치로 변환
2294
+ */
2295
+
2296
+ interface EvidenceSpan {
2297
+ start: number;
2298
+ end: number;
2299
+ confidence: number;
2300
+ matchType: 'exact' | 'fuzzy' | 'none';
2301
+ originalQuote: string;
2302
+ alignedText: string;
2303
+ }
2304
+
2305
+ interface FuzzyMatch {
2306
+ start: number;
2307
+ end: number;
2308
+ score: number;
2309
+ text: string;
2310
+ }
2311
+
2312
+ export class EvidenceAligner {
2313
+ private fuzzyThreshold: number;
2314
+
2315
+ constructor(fuzzyThreshold: number = 0.85) {
2316
+ this.fuzzyThreshold = fuzzyThreshold;
2317
+ }
2318
+
2319
+ /**
2320
+ * LLM 인용문을 원본 텍스트에서 정확한 스팬으로 변환
2321
+ */
2322
+ align(sourceText: string, llmQuote: string): EvidenceSpan | null {
2323
+ // 1. 정확한 매칭 시도
2324
+ const exactPos = sourceText.indexOf(llmQuote);
2325
+ if (exactPos >= 0) {
2326
+ return {
2327
+ start: exactPos,
2328
+ end: exactPos + llmQuote.length,
2329
+ confidence: 1.0,
2330
+ matchType: 'exact',
2331
+ originalQuote: llmQuote,
2332
+ alignedText: llmQuote
2333
+ };
2334
+ }
2335
+
2336
+ // 2. 정규화 후 매칭 (공백, 대소문자 무시)
2337
+ const normalizedMatch = this.normalizedSearch(sourceText, llmQuote);
2338
+ if (normalizedMatch && normalizedMatch.score >= 0.95) {
2339
+ return {
2340
+ start: normalizedMatch.start,
2341
+ end: normalizedMatch.end,
2342
+ confidence: normalizedMatch.score,
2343
+ matchType: 'exact',
2344
+ originalQuote: llmQuote,
2345
+ alignedText: normalizedMatch.text
2346
+ };
2347
+ }
2348
+
2349
+ // 3. Fuzzy 매칭 (Levenshtein 거리)
2350
+ const fuzzyMatch = this.fuzzySearch(sourceText, llmQuote);
2351
+ if (fuzzyMatch && fuzzyMatch.score >= this.fuzzyThreshold) {
2352
+ return {
2353
+ start: fuzzyMatch.start,
2354
+ end: fuzzyMatch.end,
2355
+ confidence: fuzzyMatch.score,
2356
+ matchType: 'fuzzy',
2357
+ originalQuote: llmQuote,
2358
+ alignedText: fuzzyMatch.text
2359
+ };
2360
+ }
2361
+
2362
+ // 4. 매칭 실패
2363
+ return null;
2364
+ }
2365
+
2366
+ /**
2367
+ * 정규화된 검색 (공백/대소문자 무시)
2368
+ */
2369
+ private normalizedSearch(text: string, query: string): FuzzyMatch | null {
2370
+ const normalize = (s: string) => s.toLowerCase().replace(/\s+/g, ' ').trim();
2371
+ const normalizedText = normalize(text);
2372
+ const normalizedQuery = normalize(query);
2373
+
2374
+ const pos = normalizedText.indexOf(normalizedQuery);
2375
+ if (pos < 0) return null;
2376
+
2377
+ // 원본 텍스트에서 실제 위치 찾기
2378
+ let originalStart = 0;
2379
+ let normalizedPos = 0;
2380
+ for (let i = 0; i < text.length && normalizedPos < pos; i++) {
2381
+ if (!/\s/.test(text[i]) || (i > 0 && !/\s/.test(text[i-1]))) {
2382
+ normalizedPos++;
2383
+ }
2384
+ originalStart = i + 1;
2385
+ }
2386
+
2387
+ return {
2388
+ start: originalStart,
2389
+ end: originalStart + query.length,
2390
+ score: 0.98,
2391
+ text: text.slice(originalStart, originalStart + query.length)
2392
+ };
2393
+ }
2394
+
2395
+ /**
2396
+ * Fuzzy 검색 (슬라이딩 윈도우 + Levenshtein)
2397
+ */
2398
+ private fuzzySearch(text: string, query: string): FuzzyMatch | null {
2399
+ const windowSize = Math.min(query.length * 1.5, text.length);
2400
+ let bestMatch: FuzzyMatch | null = null;
2401
+
2402
+ for (let i = 0; i <= text.length - query.length; i++) {
2403
+ const window = text.slice(i, i + Math.ceil(windowSize));
2404
+ const score = this.similarity(window.slice(0, query.length), query);
2405
+
2406
+ if (!bestMatch || score > bestMatch.score) {
2407
+ bestMatch = {
2408
+ start: i,
2409
+ end: i + query.length,
2410
+ score,
2411
+ text: window.slice(0, query.length)
2412
+ };
2413
+ }
2414
+ }
2415
+
2416
+ return bestMatch;
2417
+ }
2418
+
2419
+ /**
2420
+ * Levenshtein 기반 유사도 (0-1)
2421
+ */
2422
+ private similarity(a: string, b: string): number {
2423
+ const distance = this.levenshteinDistance(a.toLowerCase(), b.toLowerCase());
2424
+ const maxLen = Math.max(a.length, b.length);
2425
+ return maxLen === 0 ? 1 : 1 - distance / maxLen;
2426
+ }
2427
+
2428
+ private levenshteinDistance(a: string, b: string): number {
2429
+ const matrix: number[][] = [];
2430
+ for (let i = 0; i <= b.length; i++) {
2431
+ matrix[i] = [i];
2432
+ }
2433
+ for (let j = 0; j <= a.length; j++) {
2434
+ matrix[0][j] = j;
2435
+ }
2436
+ for (let i = 1; i <= b.length; i++) {
2437
+ for (let j = 1; j <= a.length; j++) {
2438
+ const cost = a[j - 1] === b[i - 1] ? 0 : 1;
2439
+ matrix[i][j] = Math.min(
2440
+ matrix[i - 1][j] + 1,
2441
+ matrix[i][j - 1] + 1,
2442
+ matrix[i - 1][j - 1] + cost
2443
+ );
2444
+ }
2445
+ }
2446
+ return matrix[b.length][a.length];
2447
+ }
2448
+ }
2449
+ ```
2450
+
2451
+ ### 1.7 Graduation Pipeline 구현 (src/core/graduation.ts) - AXIOMMIND L0→L4
2452
+
2453
+ ```typescript
2454
+ /**
2455
+ * AXIOMMIND Memory Graduation Pipeline
2456
+ * L0(Raw) → L1(Structured) → L2(Candidates) → L3(Verified) → L4(Active)
2457
+ */
2458
+
2459
+ import { EventStore } from './event-store';
2460
+ import { VectorStore } from './vector-store';
2461
+ import { VectorWorker } from './vector-worker';
2462
+ import { MemoryEvent } from './types';
2463
+
2464
+ type MemoryLevel = 'L0' | 'L1' | 'L2' | 'L3' | 'L4';
2465
+
2466
+ interface GraduationResult {
2467
+ eventId: string;
2468
+ fromLevel: MemoryLevel;
2469
+ toLevel: MemoryLevel;
2470
+ success: boolean;
2471
+ reason?: string;
2472
+ }
2473
+
2474
+ interface LevelStatus {
2475
+ level: MemoryLevel;
2476
+ count: number;
2477
+ lastUpdated: Date | null;
2478
+ }
2479
+
2480
+ export class GraduationPipeline {
2481
+ constructor(
2482
+ private eventStore: EventStore,
2483
+ private vectorStore: VectorStore,
2484
+ private vectorWorker: VectorWorker
2485
+ ) {}
2486
+
2487
+ /**
2488
+ * L0 → L1: 원본 이벤트에서 구조화된 데이터 추출
2489
+ * (LLM 기반 추출은 별도 서비스에서 처리)
2490
+ */
2491
+ async promoteToL1(eventId: string): Promise<GraduationResult> {
2492
+ // L1 승격은 LLM 추출 완료 후 마킹
2493
+ // 여기서는 메타데이터만 업데이트
2494
+ return {
2495
+ eventId,
2496
+ fromLevel: 'L0',
2497
+ toLevel: 'L1',
2498
+ success: true
2499
+ };
2500
+ }
2501
+
2502
+ /**
2503
+ * L1 → L2: 타입 검증 대상으로 승격
2504
+ * TypeScript 타입 체크 통과 여부 확인
2505
+ */
2506
+ async promoteToL2(eventId: string, structuredData: unknown): Promise<GraduationResult> {
2507
+ try {
2508
+ // Zod 스키마로 검증
2509
+ // const validated = SomeSchema.parse(structuredData);
2510
+
2511
+ return {
2512
+ eventId,
2513
+ fromLevel: 'L1',
2514
+ toLevel: 'L2',
2515
+ success: true
2516
+ };
2517
+ } catch (error) {
2518
+ return {
2519
+ eventId,
2520
+ fromLevel: 'L1',
2521
+ toLevel: 'L2',
2522
+ success: false,
2523
+ reason: `Validation failed: ${error}`
2524
+ };
2525
+ }
2526
+ }
2527
+
2528
+ /**
2529
+ * L2 → L3: 검증 완료 (모순 없음 확인)
2530
+ */
2531
+ async promoteToL3(eventId: string): Promise<GraduationResult> {
2532
+ // 기존 지식과의 모순 체크
2533
+ // 중복 체크
2534
+ // 신뢰도 계산
2535
+
2536
+ return {
2537
+ eventId,
2538
+ fromLevel: 'L2',
2539
+ toLevel: 'L3',
2540
+ success: true
2541
+ };
2542
+ }
2543
+
2544
+ /**
2545
+ * L3 → L4: 검색 가능 상태로 승격 (벡터 인덱싱)
2546
+ */
2547
+ async promoteToL4(eventId: string, content: string): Promise<GraduationResult> {
2548
+ try {
2549
+ // VectorWorker의 outbox에 추가 (비동기 인덱싱)
2550
+ await this.vectorWorker.enqueue(eventId, content);
2551
+
2552
+ return {
2553
+ eventId,
2554
+ fromLevel: 'L3',
2555
+ toLevel: 'L4',
2556
+ success: true
2557
+ };
2558
+ } catch (error) {
2559
+ return {
2560
+ eventId,
2561
+ fromLevel: 'L3',
2562
+ toLevel: 'L4',
2563
+ success: false,
2564
+ reason: `Indexing failed: ${error}`
2565
+ };
2566
+ }
2567
+ }
2568
+
2569
+ /**
2570
+ * 전체 파이프라인 실행 (L0 → L4)
2571
+ */
2572
+ async graduateFull(event: MemoryEvent): Promise<GraduationResult[]> {
2573
+ const results: GraduationResult[] = [];
2574
+
2575
+ // L0 → L1 (구조화)
2576
+ const l1Result = await this.promoteToL1(event.id);
2577
+ results.push(l1Result);
2578
+ if (!l1Result.success) return results;
2579
+
2580
+ // L1 → L2 (타입 검증)
2581
+ const l2Result = await this.promoteToL2(event.id, event);
2582
+ results.push(l2Result);
2583
+ if (!l2Result.success) return results;
2584
+
2585
+ // L2 → L3 (모순 체크)
2586
+ const l3Result = await this.promoteToL3(event.id);
2587
+ results.push(l3Result);
2588
+ if (!l3Result.success) return results;
2589
+
2590
+ // L3 → L4 (인덱싱)
2591
+ const l4Result = await this.promoteToL4(event.id, event.content);
2592
+ results.push(l4Result);
2593
+
2594
+ return results;
2595
+ }
2596
+
2597
+ /**
2598
+ * 각 레벨별 통계 조회
2599
+ */
2600
+ async getLevelStats(): Promise<LevelStatus[]> {
2601
+ // 실제 구현에서는 DB 쿼리
2602
+ return [
2603
+ { level: 'L0', count: 0, lastUpdated: null },
2604
+ { level: 'L1', count: 0, lastUpdated: null },
2605
+ { level: 'L2', count: 0, lastUpdated: null },
2606
+ { level: 'L3', count: 0, lastUpdated: null },
2607
+ { level: 'L4', count: 0, lastUpdated: null }
2608
+ ];
2609
+ }
2610
+ }
2611
+ ```
2612
+
2613
+ ---
2614
+
2615
+ ## Phase 2: Embedding & Retrieval
2616
+
2617
+ ### 2.1 Embedder 구현 (src/core/embedder.ts)
2618
+
2619
+ ```typescript
2620
+ import { pipeline, Pipeline } from '@xenova/transformers';
2621
+
2622
+ export class Embedder {
2623
+ private model: Pipeline | null = null;
2624
+ private modelName: string;
2625
+
2626
+ constructor(modelName: string = 'Xenova/all-MiniLM-L6-v2') {
2627
+ this.modelName = modelName;
2628
+ }
2629
+
2630
+ async initialize(): Promise<void> {
2631
+ this.model = await pipeline('feature-extraction', this.modelName);
2632
+ }
2633
+
2634
+ async embed(text: string): Promise<number[]> {
2635
+ if (!this.model) {
2636
+ await this.initialize();
2637
+ }
2638
+
2639
+ const result = await this.model!(text, {
2640
+ pooling: 'mean',
2641
+ normalize: true
2642
+ });
2643
+
2644
+ return Array.from(result.data);
2645
+ }
2646
+
2647
+ async embedBatch(texts: string[]): Promise<number[][]> {
2648
+ return Promise.all(texts.map(t => this.embed(t)));
2649
+ }
2650
+ }
2651
+ ```
2652
+
2653
+ ### 2.2 Retriever 구현 (src/core/retriever.ts)
2654
+
2655
+ ```typescript
2656
+ import { Embedder } from './embedder';
2657
+ import { VectorStore } from './vector-store';
2658
+ import { EventStore } from './event-store';
2659
+ import { MemoryMatch, Config } from './types';
2660
+
2661
+ export class Retriever {
2662
+ constructor(
2663
+ private embedder: Embedder,
2664
+ private vectorStore: VectorStore,
2665
+ private eventStore: EventStore,
2666
+ private config: Config
2667
+ ) {}
2668
+
2669
+ async search(query: string): Promise<MemoryMatch[]> {
2670
+ // 1. 쿼리 임베딩
2671
+ const queryVector = await this.embedder.embed(query);
2672
+
2673
+ // 2. 벡터 검색
2674
+ const vectorResults = await this.vectorStore.search(queryVector, {
2675
+ limit: this.config.retrieval.topK,
2676
+ minScore: this.config.retrieval.minScore
2677
+ });
2678
+
2679
+ // 3. 이벤트 정보 보강
2680
+ const matches: MemoryMatch[] = [];
2681
+
2682
+ for (const result of vectorResults) {
2683
+ // 원본 이벤트 조회
2684
+ const events = await this.eventStore.getSessionEvents(result.eventId);
2685
+ const event = events.find(e => e.id === result.eventId);
2686
+
2687
+ if (event) {
2688
+ matches.push({
2689
+ event,
2690
+ score: result.score,
2691
+ relevanceReason: `Semantic similarity: ${(result.score * 100).toFixed(1)}%`
2692
+ });
2693
+ }
2694
+ }
2695
+
2696
+ return matches;
2697
+ }
2698
+
2699
+ // 컨텍스트 포맷팅
2700
+ formatContext(matches: MemoryMatch[]): string {
2701
+ if (matches.length === 0) {
2702
+ return '';
2703
+ }
2704
+
2705
+ const lines = ['## Relevant Memories\n'];
2706
+
2707
+ for (const match of matches) {
2708
+ const date = new Date(match.event.timestamp).toLocaleDateString();
2709
+ lines.push(`### ${match.event.eventType} (${date})`);
2710
+ lines.push(`> ${match.event.content.slice(0, 500)}...`);
2711
+ lines.push(`_Relevance: ${(match.score * 100).toFixed(0)}%_\n`);
2712
+ }
2713
+
2714
+ return lines.join('\n');
2715
+ }
2716
+ }
2717
+ ```
2718
+
2719
+ ---
2720
+
2721
+ ## Phase 3: Hook Integration
2722
+
2723
+ ### 3.1 hooks.json 설정
2724
+
2725
+ ```json
2726
+ {
2727
+ "hooks": {
2728
+ "SessionStart": [
2729
+ {
2730
+ "type": "command",
2731
+ "command": "npx code-memory session-start",
2732
+ "timeout": 5000
2733
+ }
2734
+ ],
2735
+ "UserPromptSubmit": [
2736
+ {
2737
+ "type": "command",
2738
+ "command": "npx code-memory search --stdin",
2739
+ "timeout": 3000
2740
+ }
2741
+ ],
2742
+ "Stop": [
2743
+ {
2744
+ "type": "command",
2745
+ "command": "npx code-memory save --stdin",
2746
+ "timeout": 5000
2747
+ }
2748
+ ],
2749
+ "SessionEnd": [
2750
+ {
2751
+ "type": "command",
2752
+ "command": "npx code-memory session-end --stdin",
2753
+ "timeout": 10000
2754
+ }
2755
+ ]
2756
+ }
2757
+ }
2758
+ ```
2759
+
2760
+ ### 3.2 UserPromptSubmit Hook (src/hooks/user-prompt-submit.ts)
2761
+
2762
+ ```typescript
2763
+ import { Retriever } from '../core/retriever';
2764
+ import { loadServices } from '../core/services';
2765
+
2766
+ export async function handleUserPromptSubmit(input: {
2767
+ session_id: string;
2768
+ prompt: string;
2769
+ }): Promise<{ context?: string }> {
2770
+ const { retriever } = await loadServices();
2771
+
2772
+ // 관련 기억 검색
2773
+ const matches = await retriever.search(input.prompt);
2774
+
2775
+ if (matches.length === 0) {
2776
+ return {};
2777
+ }
2778
+
2779
+ // 컨텍스트 포맷팅
2780
+ const context = retriever.formatContext(matches);
2781
+
2782
+ return { context };
2783
+ }
2784
+
2785
+ // CLI 엔트리포인트
2786
+ if (process.stdin.isTTY === false) {
2787
+ let data = '';
2788
+ process.stdin.on('data', chunk => data += chunk);
2789
+ process.stdin.on('end', async () => {
2790
+ const input = JSON.parse(data);
2791
+ const result = await handleUserPromptSubmit(input);
2792
+ console.log(JSON.stringify(result));
2793
+ });
2794
+ }
2795
+ ```
2796
+
2797
+ ### 3.3 Stop Hook (src/hooks/stop.ts)
2798
+
2799
+ ```typescript
2800
+ import { EventStore } from '../core/event-store';
2801
+ import { VectorStore } from '../core/vector-store';
2802
+ import { Embedder } from '../core/embedder';
2803
+ import { loadServices } from '../core/services';
2804
+
2805
+ export async function handleStop(input: {
2806
+ session_id: string;
2807
+ messages: Array<{ role: string; content: string }>;
2808
+ }): Promise<void> {
2809
+ const { eventStore, vectorStore, embedder } = await loadServices();
2810
+
2811
+ // 마지막 user-assistant 쌍 저장
2812
+ const messages = input.messages.slice(-2);
2813
+
2814
+ for (const msg of messages) {
2815
+ const eventType = msg.role === 'user' ? 'user_prompt' : 'agent_response';
2816
+
2817
+ // 1. 이벤트 저장
2818
+ const result = await eventStore.append({
2819
+ eventType,
2820
+ sessionId: input.session_id,
2821
+ timestamp: new Date(),
2822
+ content: msg.content,
2823
+ metadata: {}
2824
+ });
2825
+
2826
+ // 2. 임베딩 생성 및 벡터 저장 (중복 아닌 경우)
2827
+ if (result.success && !result.isDuplicate) {
2828
+ const vector = await embedder.embed(msg.content);
2829
+
2830
+ await vectorStore.upsert({
2831
+ id: crypto.randomUUID(),
2832
+ eventId: result.eventId!,
2833
+ sessionId: input.session_id,
2834
+ eventType,
2835
+ content: msg.content.slice(0, 1000), // 미리보기용
2836
+ vector,
2837
+ timestamp: new Date().toISOString()
2838
+ });
2839
+ }
2840
+ }
2841
+ }
2842
+ ```
2843
+
2844
+ ---
2845
+
2846
+ ## Phase 4: Commands & CLI
2847
+
2848
+ ### 4.1 Search Command (commands/search.md)
2849
+
2850
+ ```markdown
2851
+ ---
2852
+ description: Search through your conversation memory
2853
+ ---
2854
+
2855
+ # Memory Search
2856
+
2857
+ Search for relevant memories based on your query.
2858
+
2859
+ ## Usage
2860
+
2861
+ The user wants to search their conversation memory for: "$ARGUMENTS"
2862
+
2863
+ Search the memory database and return the most relevant past conversations, code snippets, and insights related to the query.
2864
+
2865
+ Display the results in a clear format showing:
2866
+ 1. The date of the memory
2867
+ 2. A brief excerpt of the content
2868
+ 3. The relevance score
2869
+
2870
+ If no relevant memories are found, inform the user and suggest they can build up their memory by having more conversations.
2871
+ ```
2872
+
2873
+ ### 4.2 CLI Entry Point (src/cli/index.ts)
2874
+
2875
+ ```typescript
2876
+ import { Command } from 'commander';
2877
+ import { handleSessionStart } from './commands/session-start';
2878
+ import { handleSearch } from './commands/search';
2879
+ import { handleSave } from './commands/save';
2880
+ import { handleSessionEnd } from './commands/session-end';
2881
+ import { handleInit } from './commands/init';
2882
+
2883
+ const program = new Command();
2884
+
2885
+ program
2886
+ .name('code-memory')
2887
+ .description('Claude Code Memory Plugin CLI')
2888
+ .version('1.0.0');
2889
+
2890
+ program
2891
+ .command('init')
2892
+ .description('Initialize the memory database')
2893
+ .action(handleInit);
2894
+
2895
+ program
2896
+ .command('session-start')
2897
+ .description('Handle session start')
2898
+ .option('--session-id <id>', 'Session ID')
2899
+ .option('--cwd <path>', 'Current working directory')
2900
+ .action(handleSessionStart);
2901
+
2902
+ program
2903
+ .command('search')
2904
+ .description('Search memories')
2905
+ .option('--query <text>', 'Search query')
2906
+ .option('--stdin', 'Read from stdin')
2907
+ .option('--limit <n>', 'Max results', '5')
2908
+ .action(handleSearch);
2909
+
2910
+ program
2911
+ .command('save')
2912
+ .description('Save conversation')
2913
+ .option('--stdin', 'Read from stdin')
2914
+ .action(handleSave);
2915
+
2916
+ program
2917
+ .command('session-end')
2918
+ .description('Handle session end')
2919
+ .option('--stdin', 'Read from stdin')
2920
+ .action(handleSessionEnd);
2921
+
2922
+ program.parse();
2923
+ ```
2924
+
2925
+ ---
2926
+
2927
+ ## Phase 5: Testing & Polish
2928
+
2929
+ ### 5.1 테스트 케이스 (tests/event-store.test.ts)
2930
+
2931
+ ```typescript
2932
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2933
+ import { EventStore } from '../src/core/event-store';
2934
+ import { unlink } from 'fs/promises';
2935
+
2936
+ describe('EventStore', () => {
2937
+ let store: EventStore;
2938
+ const testDbPath = './test-events.db';
2939
+
2940
+ beforeEach(() => {
2941
+ store = new EventStore(testDbPath);
2942
+ });
2943
+
2944
+ afterEach(async () => {
2945
+ await unlink(testDbPath).catch(() => {});
2946
+ });
2947
+
2948
+ it('should append events with deduplication', async () => {
2949
+ const event = {
2950
+ eventType: 'user_prompt' as const,
2951
+ sessionId: 'test-session',
2952
+ timestamp: new Date(),
2953
+ content: 'Hello, how are you?',
2954
+ metadata: {}
2955
+ };
2956
+
2957
+ // 첫 번째 저장
2958
+ const result1 = await store.append(event);
2959
+ expect(result1.success).toBe(true);
2960
+ expect(result1.isDuplicate).toBe(false);
2961
+
2962
+ // 중복 저장 시도
2963
+ const result2 = await store.append(event);
2964
+ expect(result2.success).toBe(true);
2965
+ expect(result2.isDuplicate).toBe(true);
2966
+ expect(result2.eventId).toBe(result1.eventId);
2967
+ });
2968
+
2969
+ it('should retrieve events by session', async () => {
2970
+ const sessionId = 'test-session';
2971
+
2972
+ await store.append({
2973
+ eventType: 'user_prompt',
2974
+ sessionId,
2975
+ timestamp: new Date(),
2976
+ content: 'First message',
2977
+ metadata: {}
2978
+ });
2979
+
2980
+ await store.append({
2981
+ eventType: 'agent_response',
2982
+ sessionId,
2983
+ timestamp: new Date(),
2984
+ content: 'First response',
2985
+ metadata: {}
2986
+ });
2987
+
2988
+ const events = await store.getSessionEvents(sessionId);
2989
+ expect(events.length).toBe(2);
2990
+ });
2991
+ });
2992
+ ```
2993
+
2994
+ ### 5.2 통합 테스트 (tests/integration.test.ts)
2995
+
2996
+ ```typescript
2997
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2998
+ import { EventStore } from '../src/core/event-store';
2999
+ import { VectorStore } from '../src/core/vector-store';
3000
+ import { Embedder } from '../src/core/embedder';
3001
+ import { Retriever } from '../src/core/retriever';
3002
+
3003
+ describe('Integration: Memory Retrieval', () => {
3004
+ let eventStore: EventStore;
3005
+ let vectorStore: VectorStore;
3006
+ let embedder: Embedder;
3007
+ let retriever: Retriever;
3008
+
3009
+ beforeAll(async () => {
3010
+ eventStore = new EventStore('./test-integration.db');
3011
+ vectorStore = new VectorStore('./test-integration-vectors');
3012
+ embedder = new Embedder();
3013
+
3014
+ await vectorStore.initialize();
3015
+ await embedder.initialize();
3016
+
3017
+ retriever = new Retriever(eventStore, vectorStore, embedder, {
3018
+ retrieval: { topK: 5, minScore: 0.5, maxTokens: 2000 }
3019
+ });
3020
+
3021
+ // 테스트 데이터 삽입
3022
+ const testData = [
3023
+ { content: 'How to implement rate limiting in Express?', type: 'user_prompt' },
3024
+ { content: 'You can use express-rate-limit middleware...', type: 'agent_response' },
3025
+ { content: 'How to add authentication to my API?', type: 'user_prompt' },
3026
+ { content: 'Use Passport.js or JWT for authentication...', type: 'agent_response' }
3027
+ ];
3028
+
3029
+ for (const data of testData) {
3030
+ const result = await eventStore.append({
3031
+ eventType: data.type as any,
3032
+ sessionId: 'test-session',
3033
+ timestamp: new Date(),
3034
+ content: data.content,
3035
+ metadata: {}
3036
+ });
3037
+
3038
+ const vector = await embedder.embed(data.content);
3039
+ await vectorStore.upsert({
3040
+ id: crypto.randomUUID(),
3041
+ eventId: result.eventId!,
3042
+ sessionId: 'test-session',
3043
+ eventType: data.type,
3044
+ content: data.content,
3045
+ vector,
3046
+ timestamp: new Date().toISOString()
3047
+ });
3048
+ }
3049
+ });
3050
+
3051
+ it('should find relevant memories', async () => {
3052
+ const matches = await retriever.search('rate limiting');
3053
+
3054
+ expect(matches.length).toBeGreaterThan(0);
3055
+ expect(matches[0].event.content).toContain('rate limiting');
3056
+ });
3057
+
3058
+ it('should format context correctly', () => {
3059
+ const matches = [
3060
+ {
3061
+ event: {
3062
+ id: '1',
3063
+ eventType: 'user_prompt',
3064
+ sessionId: 'test',
3065
+ timestamp: new Date(),
3066
+ content: 'Test content',
3067
+ contentHash: 'hash'
3068
+ },
3069
+ score: 0.95,
3070
+ relevanceReason: 'High similarity'
3071
+ }
3072
+ ];
3073
+
3074
+ const context = retriever.formatContext(matches);
3075
+ expect(context).toContain('Relevant Memories');
3076
+ expect(context).toContain('Test content');
3077
+ });
3078
+ });
3079
+ ```
3080
+
3081
+ ### 5.3 빌드 스크립트 (scripts/build.ts)
3082
+
3083
+ ```typescript
3084
+ import * as esbuild from 'esbuild';
3085
+
3086
+ async function build() {
3087
+ // CLI 빌드
3088
+ await esbuild.build({
3089
+ entryPoints: ['src/cli/index.ts'],
3090
+ bundle: true,
3091
+ platform: 'node',
3092
+ target: 'node18',
3093
+ outfile: 'dist/cli.js',
3094
+ external: ['duckdb', 'lancedb', '@xenova/transformers']
3095
+ });
3096
+
3097
+ console.log('Build complete!');
3098
+ }
3099
+
3100
+ build().catch(console.error);
3101
+ ```
3102
+
3103
+ ---
3104
+
3105
+ ## 마일스톤 체크리스트
3106
+
3107
+ ### Phase 0: 프로젝트 설정
3108
+ - [ ] 디렉토리 구조 생성
3109
+ - [ ] package.json 초기화
3110
+ - [ ] 의존성 설치
3111
+ - [ ] TypeScript 설정
3112
+ - [ ] plugin.json 생성
3113
+
3114
+ ### Phase 1: Core Storage Layer
3115
+ - [ ] types.ts - Zod 스키마 정의
3116
+ - [ ] event-store.ts - DuckDB 연동
3117
+ - [ ] vector-store.ts - LanceDB 연동
3118
+ - [ ] 단위 테스트
3119
+
3120
+ ### Phase 2: Embedding & Retrieval
3121
+ - [ ] embedder.ts - 로컬 임베딩
3122
+ - [ ] retriever.ts - 검색 로직
3123
+ - [ ] 컨텍스트 포맷터
3124
+ - [ ] 단위 테스트
3125
+
3126
+ ### Phase 3: Hook Integration
3127
+ - [ ] hooks.json 설정
3128
+ - [ ] session-start hook
3129
+ - [ ] user-prompt-submit hook
3130
+ - [ ] stop hook
3131
+ - [ ] session-end hook
3132
+
3133
+ ### Phase 4: Commands & CLI
3134
+ - [ ] CLI 엔트리포인트
3135
+ - [ ] search 명령어
3136
+ - [ ] history 명령어
3137
+ - [ ] forget 명령어
3138
+ - [ ] stats 명령어
3139
+
3140
+ ### Phase 5: Testing & Polish
3141
+ - [ ] 통합 테스트
3142
+ - [ ] README.md
3143
+ - [ ] 에러 처리 개선
3144
+ - [ ] 성능 최적화
3145
+ - [ ] 첫 릴리스 준비
3146
+
3147
+ ---
3148
+
3149
+ ## 리스크 및 대응
3150
+
3151
+ | 리스크 | 영향 | 대응 |
3152
+ |--------|------|------|
3153
+ | 임베딩 모델 로드 시간 | 세션 시작 지연 | 모델 캐싱, 지연 로드 |
3154
+ | 대용량 대화 처리 | 메모리 부족 | 스트리밍, 배치 처리 |
3155
+ | DuckDB/LanceDB 호환성 | 설치 실패 | fallback 구현, 순수 JS 대안 |
3156
+ | Hook 타임아웃 | 기능 미작동 | 비동기 처리, 캐싱 |
3157
+
3158
+ ---
3159
+
3160
+ ## 다음 단계
3161
+
3162
+ 1. **Phase 0 완료 후**: 기본 플러그인 구조 동작 확인
3163
+ 2. **Phase 1-2 완료 후**: 기억 저장/검색 기능 데모
3164
+ 3. **Phase 3-4 완료 후**: 실제 Claude Code에서 테스트
3165
+ 4. **Phase 5 완료 후**: 커뮤니티 마켓플레이스 등록
3166
+
3167
+ ## 2026-02-25T12:31:26.199Z | 5808e4d1-65b8-46d8-8745-b6208eafa711
3168
+ - type: session_summary
3169
+ - session: import:organized
3170
+ # Specification: Claude Code Memory Plugin
3171
+
3172
+ ## 1. 개요
3173
+
3174
+ ### 1.1 플러그인 정보
3175
+
3176
+ | 항목 | 값 |
3177
+ |------|-----|
3178
+ | **이름** | `code-memory` |
3179
+ | **버전** | `1.0.0` |
3180
+ | **설명** | 대화 기억을 통해 사용자 맞춤형 경험을 제공하는 Claude Code 플러그인 |
3181
+ | **핵심 가치** | "사용할수록 똑똑해지는 Agent" |
3182
+
3183
+ ### 1.2 핵심 기능
3184
+
3185
+ 1. **대화 기억 저장**: 모든 사용자 prompt와 agent 응답을 영구 저장
3186
+ 2. **지능형 검색**: 새로운 prompt와 관련된 과거 기억을 의미 기반 검색
3187
+ 3. **컨텍스트 주입**: 관련 기억을 현재 대화에 자동 주입
3188
+ 4. **학습 및 진화**: 패턴 인식을 통한 개인화
3189
+
3190
+ ---
3191
+
3192
+ ## 2. 아키텍처
3193
+
3194
+ ### 2.1 시스템 구조
3195
+
3196
+ ```
3197
+ ┌─────────────────────────────────────────────────────────────┐
3198
+ │ Claude Code Session │
3199
+ └─────────────────────────────────────────────────────────────┘
3200
+ │ │ │
3201
+ ▼ ▼ ▼
3202
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
3203
+ │ SessionStart│ │UserPrompt │ │ Stop/ │
3204
+ │ Hook │ │Submit Hook │ │ SessionEnd │
3205
+ └─────────────┘ └─────────────┘ └─────────────┘
3206
+ │ │ │
3207
+ ▼ ▼ ▼
3208
+ ┌─────────────────────────────────────────────────────────────┐
3209
+ │ Memory Service (Core) │
3210
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
3211
+ │ │ Ingester │ │ Embedder │ │ Retriever│ │ Ranker │ │
3212
+ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
3213
+ └─────────────────────────────────────────────────────────────┘
3214
+ │ │ │
3215
+ ▼ ▼ ▼
3216
+ ┌─────────────────────────────────────────────────────────────┐
3217
+ │ Storage Layer │
3218
+ │ ┌───────────────────┐ ┌───────────────────┐ │
3219
+ │ │ LanceDB │ │ DuckDB │ │
3220
+ │ │ (Vector Store) │ │ (Event Store) │ │
3221
+ │ └───────────────────┘ └───────────────────┘ │
3222
+ └─────────────────────────────────────────────────────────────┘
3223
+ ```
3224
+
3225
+ ### 2.2 데이터 흐름
3226
+
3227
+ ```
3228
+ 1. [SessionStart]
3229
+ → 이전 세션 요약 로드
3230
+ → 사용자 선호도/패턴 로드
3231
+
3232
+ 2. [UserPromptSubmit]
3233
+ → 현재 prompt 임베딩 생성
3234
+ → 관련 기억 검색 (top-k)
3235
+ → 기억을 시스템 프롬프트로 주입
3236
+
3237
+ 3. [Stop/AgentResponse]
3238
+ → 전체 대화 쌍 (prompt + response) 저장
3239
+ → 비동기 임베딩 생성 및 인덱싱
3240
+
3241
+ 4. [SessionEnd]
3242
+ → 세션 요약 생성 및 저장
3243
+ → 장기 기억으로 통합
3244
+ ```
3245
+
3246
+ ### 2.3 Memory Graduation Pipeline (L0 → L4)
3247
+
3248
+ AXIOMMIND 기반 다단계 메모리 승격 구조:
3249
+
3250
+ | 레벨 | 이름 | 설명 | 저장소 | 상태 |
3251
+ |------|------|------|--------|------|
3252
+ | **L0** | EventStore | 원본 대화 로그 (불변) | DuckDB `events` | 즉시 저장 |
3253
+ | **L1** | Structured | LLM 추출 구조화 데이터 | DuckDB `insights` | 비동기 처리 |
3254
+ | **L2** | Candidates | 타입 검증 대상 | TypeScript 검증 | 배치 처리 |
3255
+ | **L3** | Verified | 검증 완료 지식 | DuckDB `verified_knowledge` | 검증 후 |
3256
+ | **L4** | Active | 검색 가능 메모리 | LanceDB | 인덱싱 후 |
3257
+
3258
+ ```
3259
+ User Prompt → L0 (즉시) → L1 (비동기) → L2 (배치) → L3 (검증) → L4 (검색 가능)
3260
+ ↑ ↓
3261
+ └──────────── 검색 시 L4에서 조회 ─────────────┘
3262
+ ```
3263
+
3264
+ ### 2.4 AXIOMMIND 7가지 필수 원칙
3265
+
3266
+ 본 플러그인은 다음 원칙을 준수합니다:
3267
+
3268
+ | # | 원칙 | 구현 |
3269
+ |---|------|------|
3270
+ | 1 | 진실의 원천은 이벤트 로그 | `events` 테이블에서 모든 파생 데이터 재구성 가능 |
3271
+ | 2 | 추가전용 구조 | `EventStore.append()` 만 제공, UPDATE/DELETE 없음 |
3272
+ | 3 | 멱등성 보장 | `dedupe_key = session_id + content_hash` |
3273
+ | 4 | 증거 범위는 파이프라인이 확정 | `EvidenceAligner`가 정확한 스팬 계산 |
3274
+ | 5 | Task는 엔티티 | `canonical_key`로 동일 개념 통합 |
3275
+ | 6 | 벡터 저장소 정합성 | DuckDB → outbox → LanceDB 단방향 |
3276
+ | 7 | DuckDB JSON 사용 | JSONB 대신 표준 JSON |
3277
+
3278
+ ---
3279
+
3280
+ ## 3. 데이터 모델
3281
+
3282
+ ### 3.1 Event Schema (DuckDB) - AXIOMMIND 스타일
3283
+
3284
+ ```sql
3285
+ -- ============================================================
3286
+ -- L0 EventStore: Single Source of Truth (불변, append-only)
3287
+ -- ============================================================
3288
+
3289
+ CREATE TABLE events (
3290
+ id UUID PRIMARY KEY,
3291
+ event_type VARCHAR NOT NULL, -- 'user_prompt' | 'agent_response' | 'session_summary'
3292
+ session_id VARCHAR NOT NULL,
3293
+ timestamp TIMESTAMP NOT NULL,
3294
+ content TEXT NOT NULL,
3295
+ canonical_key VARCHAR NOT NULL, -- 정규화된 키 (NFKC, lowercase, no punctuation)
3296
+ metadata JSON,
3297
+ dedupe_key VARCHAR UNIQUE -- 멱등성 보장 (content_hash + session_id)
3298
+ );
3299
+
3300
+ -- 중복 방지 테이블 (event_dedup)
3301
+ CREATE TABLE event_dedup (
3302
+ dedupe_key VARCHAR PRIMARY KEY,
3303
+ event_id UUID NOT NULL REFERENCES events(id),
3304
+ created_at TIMESTAMP DEFAULT NOW()
3305
+ );
3306
+
3307
+ -- Projection offset 추적 (증분 처리용)
3308
+ CREATE TABLE projection_offsets (
3309
+ projection_name VARCHAR PRIMARY KEY,
3310
+ last_event_id UUID,
3311
+ last_timestamp TIMESTAMP,
3312
+ updated_at TIMESTAMP DEFAULT NOW()
3313
+ );
3314
+
3315
+ -- ============================================================
3316
+ -- 세션 메타데이터
3317
+ -- ============================================================
3318
+
3319
+ CREATE TABLE sessions (
3320
+ id VARCHAR PRIMARY KEY,
3321
+ started_at TIMESTAMP NOT NULL,
3322
+ ended_at TIMESTAMP,
3323
+ project_path VARCHAR,
3324
+ summary TEXT,
3325
+ tags JSON
3326
+ );
3327
+
3328
+ -- ============================================================
3329
+ -- 추출된 인사이트 (파생 데이터, 재구성 가능)
3330
+ -- ============================================================
3331
+
3332
+ CREATE TABLE insights (
3333
+ id UUID PRIMARY KEY,
3334
+ insight_type VARCHAR NOT NULL, -- 'preference' | 'pattern' | 'expertise'
3335
+ content TEXT NOT NULL,
3336
+ canonical_key VARCHAR NOT NULL, -- 정규화된 키
3337
+ confidence FLOAT,
3338
+ source_events JSON, -- 원본 이벤트 ID 목록
3339
+ created_at TIMESTAMP,
3340
+ last_updated TIMESTAMP
3341
+ );
3342
+
3343
+ -- ============================================================
3344
+ -- Embedding Outbox (Single-Writer Pattern)
3345
+ -- ============================================================
3346
+
3347
+ CREATE TABLE embedding_outbox (
3348
+ id UUID PRIMARY KEY,
3349
+ event_id UUID NOT NULL REFERENCES events(id),
3350
+ content TEXT NOT NULL,
3351
+ status VARCHAR DEFAULT 'pending', -- 'pending' | 'processing' | 'done' | 'failed'
3352
+ retry_count INT DEFAULT 0,
3353
+ created_at TIMESTAMP DEFAULT NOW(),
3354
+ processed_at TIMESTAMP,
3355
+ error_message TEXT
3356
+ );
3357
+
3358
+ -- ============================================================
3359
+ -- Memory Resolutions (Condition → Task 해결)
3360
+ -- ============================================================
3361
+
3362
+ CREATE TABLE memory_resolutions (
3363
+ id UUID PRIMARY KEY,
3364
+ condition_id UUID NOT NULL, -- 원본 조건/참조
3365
+ resolved_to_id UUID, -- 해결된 대상
3366
+ resolution_type VARCHAR, -- 'confirmed' | 'rejected' | 'pending'
3367
+ confidence FLOAT,
3368
+ resolved_at TIMESTAMP
3369
+ );
3370
+
3371
+ -- ============================================================
3372
+ -- Effective View (Condition 해결 반영)
3373
+ -- ============================================================
3374
+
3375
+ CREATE VIEW v_memory_context_effective AS
3376
+ SELECT
3377
+ e.id,
3378
+ e.session_id,
3379
+ e.content,
3380
+ e.canonical_key,
3381
+ e.event_type,
3382
+ e.timestamp,
3383
+ COALESCE(r.resolved_to_id, e.id) as effective_id,
3384
+ CASE
3385
+ WHEN r.resolution_type = 'confirmed' THEN 'resolved'
3386
+ WHEN r.resolution_type = 'pending' THEN 'pending'
3387
+ ELSE 'direct'
3388
+ END as resolution_status
3389
+ FROM events e
3390
+ LEFT JOIN memory_resolutions r ON e.id = r.condition_id;
3391
+ ```
3392
+
3393
+ ### 3.2 Vector Schema (LanceDB)
3394
+
3395
+ ```python
3396
+ # 대화 임베딩 테이블
3397
+ conversations_schema = {
3398
+ "id": str, # UUID
3399
+ "event_id": str, # events 테이블 참조
3400
+ "session_id": str,
3401
+ "event_type": str, # 'user_prompt' | 'agent_response'
3402
+ "content": str, # 원본 텍스트 (검색 결과 표시용)
3403
+ "vector": list[float], # 임베딩 벡터 (384 또는 1536 차원)
3404
+ "timestamp": str,
3405
+ "metadata": dict # 추가 메타데이터
3406
+ }
3407
+
3408
+ # 인사이트 임베딩 테이블
3409
+ insights_schema = {
3410
+ "id": str,
3411
+ "insight_id": str, # insights 테이블 참조
3412
+ "content": str,
3413
+ "vector": list[float],
3414
+ "insight_type": str,
3415
+ "confidence": float
3416
+ }
3417
+ ```
3418
+
3419
+ ### 3.3 TypeScript 타입 정의 (Idris2 영감)
3420
+
3421
+ ```typescript
3422
+ // 불변성과 타입 안전성을 강조한 설계
3423
+
3424
+ // 이벤트 타입 (Union Type으로 완전성 보장)
3425
+ type EventType = 'user_prompt' | 'agent_response' | 'session_summary';
3426
+
3427
+ // 이벤트 구조 (Readonly로 불변성 강제)
3428
+ interface MemoryEvent {
3429
+ readonly id: string;
3430
+ readonly eventType: EventType;
3431
+ readonly sessionId: string;
3432
+ readonly timestamp: Date;
3433
+ readonly content: string;
3434
+ readonly contentHash: string;
3435
+ readonly metadata: Readonly<Record<string, unknown>>;
3436
+ }
3437
+
3438
+ // 검색 결과 (신뢰도 점수 포함)
3439
+ interface MemoryMatch {
3440
+ readonly event: MemoryEvent;
3441
+ readonly score: number; // 0.0 ~ 1.0
3442
+ readonly relevanceReason: string;
3443
+ }
3444
+
3445
+ // 컨텍스트 주입 결과
3446
+ interface ContextInjection {
3447
+ readonly memories: ReadonlyArray<MemoryMatch>;
3448
+ readonly systemPromptAddition: string;
3449
+ readonly totalTokensUsed: number;
3450
+ }
3451
+
3452
+ // 저장 결과 (성공/실패 명시적 표현)
3453
+ type SaveResult =
3454
+ | { success: true; eventId: string }
3455
+ | { success: false; error: string; isDuplicate: boolean };
3456
+ ```
3457
+
3458
+ ---
3459
+
3460
+ ## 4. Hook 명세
3461
+
3462
+ ### 4.1 SessionStart Hook
3463
+
3464
+ **목적**: 세션 시작 시 관련 컨텍스트 로드
3465
+
3466
+ ```json
3467
+ {
3468
+ "hooks": {
3469
+ "SessionStart": [
3470
+ {
3471
+ "type": "command",
3472
+ "command": "code-memory session-start",
3473
+ "timeout": 5000
3474
+ }
3475
+ ]
3476
+ }
3477
+ }
3478
+ ```
3479
+
3480
+ **입력**:
3481
+ ```json
3482
+ {
3483
+ "session_id": "sess_abc123",
3484
+ "cwd": "/path/to/project"
3485
+ }
3486
+ ```
3487
+
3488
+ **출력**:
3489
+ ```json
3490
+ {
3491
+ "context": "## Previous Session Context\n- Last worked on: API authentication\n- User preference: Prefers TypeScript\n- Recent patterns: Uses Zod for validation"
3492
+ }
3493
+ ```
3494
+
3495
+ ### 4.2 UserPromptSubmit Hook
3496
+
3497
+ **목적**: 사용자 입력 시 관련 기억 검색 및 주입
3498
+
3499
+ ```json
3500
+ {
3501
+ "hooks": {
3502
+ "UserPromptSubmit": [
3503
+ {
3504
+ "type": "command",
3505
+ "command": "code-memory search",
3506
+ "timeout": 3000
3507
+ }
3508
+ ]
3509
+ }
3510
+ }
3511
+ ```
3512
+
3513
+ **입력**:
3514
+ ```json
3515
+ {
3516
+ "session_id": "sess_abc123",
3517
+ "prompt": "How do I add rate limiting to the API?"
3518
+ }
3519
+ ```
3520
+
3521
+ **출력**:
3522
+ ```json
3523
+ {
3524
+ "context": "## Relevant Memories\n\n### Previous Discussion (2 weeks ago)\nYou implemented rate limiting for the /users endpoint using express-rate-limit...\n\n### Your Preferences\n- Prefers middleware-based solutions\n- Uses Redis for distributed rate limiting"
3525
+ }
3526
+ ```
3527
+
3528
+ ### 4.3 Stop Hook
3529
+
3530
+ **목적**: Agent 응답 완료 시 대화 저장
3531
+
3532
+ ```json
3533
+ {
3534
+ "hooks": {
3535
+ "Stop": [
3536
+ {
3537
+ "type": "command",
3538
+ "command": "code-memory save",
3539
+ "timeout": 5000
3540
+ }
3541
+ ]
3542
+ }
3543
+ }
3544
+ ```
3545
+
3546
+ **입력**:
3547
+ ```json
3548
+ {
3549
+ "session_id": "sess_abc123",
3550
+ "stop_reason": "end_turn",
3551
+ "messages": [
3552
+ {"role": "user", "content": "..."},
3553
+ {"role": "assistant", "content": "..."}
3554
+ ]
3555
+ }
3556
+ ```
3557
+
3558
+ ### 4.4 SessionEnd Hook
3559
+
3560
+ **목적**: 세션 종료 시 요약 저장
3561
+
3562
+ ```json
3563
+ {
3564
+ "hooks": {
3565
+ "SessionEnd": [
3566
+ {
3567
+ "type": "command",
3568
+ "command": "code-memory session-end",
3569
+ "timeout": 10000
3570
+ }
3571
+ ]
3572
+ }
3573
+ }
3574
+ ```
3575
+
3576
+ ---
3577
+
3578
+ ## 5. 명령어 인터페이스
3579
+
3580
+ ### 5.1 슬래시 명령어
3581
+
3582
+ | 명령어 | 설명 | 예시 |
3583
+ |--------|------|------|
3584
+ | `/code-memory:search` | 기억 수동 검색 | `/code-memory:search rate limiting` |
3585
+ | `/code-memory:history` | 최근 대화 이력 | `/code-memory:history 10` |
3586
+ | `/code-memory:insights` | 추출된 인사이트 보기 | `/code-memory:insights` |
3587
+ | `/code-memory:forget` | 특정 기억 삭제 | `/code-memory:forget <id>` |
3588
+ | `/code-memory:export` | 기억 내보내기 | `/code-memory:export json` |
3589
+ | `/code-memory:stats` | 통계 보기 | `/code-memory:stats` |
3590
+
3591
+ ### 5.2 CLI 명령어 (Hook에서 호출)
3592
+
3593
+ ```bash
3594
+ # 세션 시작
3595
+ code-memory session-start --session-id <id> --cwd <path>
3596
+
3597
+ # 기억 검색
3598
+ code-memory search --query <text> --limit 5 --threshold 0.7
3599
+
3600
+ # 대화 저장
3601
+ code-memory save --stdin # JSON 입력 수신
3602
+
3603
+ # 세션 종료
3604
+ code-memory session-end --session-id <id>
3605
+
3606
+ # 데이터베이스 초기화
3607
+ code-memory init
3608
+
3609
+ # 임베딩 재생성
3610
+ code-memory reindex
3611
+ ```
3612
+
3613
+ ---
3614
+
3615
+ ## 6. 설정
3616
+
3617
+ ### 6.1 plugin.json
3618
+
3619
+ ```json
3620
+ {
3621
+ "name": "code-memory",
3622
+ "description": "Learn from conversations to provide personalized assistance",
3623
+ "version": "1.0.0",
3624
+ "author": {
3625
+ "name": "Buzzni"
3626
+ },
3627
+ "homepage": "https://github.com/buzzni/code-memory",
3628
+ "repository": {
3629
+ "type": "git",
3630
+ "url": "https://github.com/buzzni/code-memory.git"
3631
+ },
3632
+ "license": "MIT",
3633
+ "engines": {
3634
+ "claude-code": ">=1.0.33"
3635
+ },
3636
+ "keywords": ["memory", "learning", "personalization", "context"]
3637
+ }
3638
+ ```
3639
+
3640
+ ### 6.2 사용자 설정 (config.json)
3641
+
3642
+ ```json
3643
+ {
3644
+ "storage": {
3645
+ "path": "~/.claude-code/memory",
3646
+ "maxSizeMB": 500
3647
+ },
3648
+ "embedding": {
3649
+ "provider": "local", // "local" | "openai"
3650
+ "model": "all-MiniLM-L6-v2", // local 모델
3651
+ "openaiModel": "text-embedding-3-small",
3652
+ "batchSize": 32
3653
+ },
3654
+ "retrieval": {
3655
+ "topK": 5,
3656
+ "minScore": 0.7,
3657
+ "maxTokens": 2000 // 주입할 최대 토큰 수
3658
+ },
3659
+ "matching": {
3660
+ "minCombinedScore": 0.92, // 확정 매칭 최소 점수 (AXIOMMIND)
3661
+ "minGap": 0.03, // 1위-2위 간 최소 점수 차이
3662
+ "suggestionThreshold": 0.75, // 제안 모드 임계값
3663
+ "weights": {
3664
+ "semanticSimilarity": 0.4, // 벡터 유사도 가중치
3665
+ "ftsScore": 0.25, // 전문 검색 가중치
3666
+ "recencyBonus": 0.2, // 최신성 가산점
3667
+ "statusWeight": 0.15 // 상태별 가중치
3668
+ }
3669
+ },
3670
+ "privacy": {
3671
+ "excludePatterns": [ // 저장 제외 패턴
3672
+ "password",
3673
+ "secret",
3674
+ "api_key"
3675
+ ],
3676
+ "anonymize": false
3677
+ },
3678
+ "features": {
3679
+ "autoSave": true,
3680
+ "sessionSummary": true,
3681
+ "insightExtraction": true,
3682
+ "crossProjectLearning": false, // 프로젝트 간 학습
3683
+ "singleWriterMode": true // Outbox 패턴 사용 (권장)
3684
+ }
3685
+ }
3686
+ ```
3687
+
3688
+ ### 6.3 Matching Thresholds (AXIOMMIND 기반)
3689
+
3690
+ 검색 결과의 신뢰도를 3단계로 분류:
3691
+
3692
+ | 신뢰도 | 조건 | 동작 |
3693
+ |--------|------|------|
3694
+ | **high** | score ≥ 0.92 AND gap ≥ 0.03 | 확정 매칭, 자동 컨텍스트 주입 |
3695
+ | **suggested** | 0.75 ≤ score < 0.92 | 제안 모드, 사용자 확인 권장 |
3696
+ | **none** | score < 0.75 | 매칭 없음 |
3697
+
3698
+ ```typescript
3699
+ // Matching 결과 타입
3700
+ interface MatchResult {
3701
+ readonly match: MemoryMatch | null;
3702
+ readonly confidence: 'high' | 'suggested' | 'none';
3703
+ readonly gap?: number; // top-1과 top-2 간 점수 차이
3704
+ readonly alternatives?: ReadonlyArray<MemoryMatch>; // suggested일 때 대안들
3705
+ }
3706
+ ```
3707
+
3708
+ ---
3709
+
3710
+ ## 7. 보안 및 프라이버시
3711
+
3712
+ ### 7.1 데이터 보호
3713
+
3714
+ 1. **로컬 저장**: 모든 데이터는 사용자 로컬에만 저장
3715
+ 2. **민감 정보 필터링**: password, secret, api_key 등 자동 제외
3716
+ 3. **선택적 익명화**: 개인 식별 정보 마스킹 옵션
3717
+
3718
+ ### 7.2 데이터 삭제
3719
+
3720
+ ```bash
3721
+ # 특정 기억 삭제
3722
+ code-memory forget --id <event_id>
3723
+
3724
+ # 세션 전체 삭제
3725
+ code-memory forget --session <session_id>
3726
+
3727
+ # 기간별 삭제
3728
+ code-memory forget --before "2024-01-01"
3729
+
3730
+ # 전체 초기화
3731
+ code-memory reset --confirm
3732
+ ```
3733
+
3734
+ ---
3735
+
3736
+ ## 8. 성능 요구사항
3737
+
3738
+ | 항목 | 목표 | 비고 |
3739
+ |------|------|------|
3740
+ | **검색 지연** | < 500ms | 10만 건 기준 |
3741
+ | **저장 지연** | < 100ms | 비동기 처리 |
3742
+ | **메모리 사용** | < 200MB | 실행 시 |
3743
+ | **디스크 사용** | < 500MB | 기본 제한 |
3744
+ | **시작 시간** | < 2s | 세션 시작 |
3745
+
3746
+ ---
3747
+
3748
+ ## 9. 의존성
3749
+
3750
+ ### 9.1 런타임 의존성
3751
+
3752
+ | 패키지 | 버전 | 용도 |
3753
+ |--------|------|------|
3754
+ | `lancedb` | ^0.5.0 | 벡터 저장소 |
3755
+ | `duckdb` | ^0.10.0 | 이벤트 저장소 |
3756
+ | `sentence-transformers` | ^2.2.0 | 로컬 임베딩 (Python) |
3757
+ | `@xenova/transformers` | ^2.15.0 | 로컬 임베딩 (JS) |
3758
+ | `zod` | ^3.22.0 | 스키마 검증 |
3759
+ | `commander` | ^12.0.0 | CLI 파싱 |
3760
+
3761
+ ### 9.2 개발 의존성
3762
+
3763
+ | 패키지 | 버전 | 용도 |
3764
+ |--------|------|------|
3765
+ | `typescript` | ^5.4.0 | 타입 시스템 |
3766
+ | `vitest` | ^1.4.0 | 테스트 |
3767
+ | `tsx` | ^4.7.0 | TS 실행 |
3768
+ | `esbuild` | ^0.20.0 | 빌드 |
3769
+
3770
+ ---
3771
+
3772
+ ## 10. 향후 확장
3773
+
3774
+ ### Phase 2 (v1.1.0)
3775
+ - [ ] 그래프 기반 관계 저장 (Neo4j/Graphiti)
3776
+ - [ ] 멀티 프로젝트 학습
3777
+ - [ ] 팀 기억 공유 (암호화)
3778
+
3779
+ ### Phase 3 (v2.0.0)
3780
+ - [ ] 자동 인사이트 추출 (LLM 기반)
3781
+ - [ ] 코드 스니펫 특화 기억
3782
+ - [ ] IDE 통합 (VSCode extension)
3783
+
3784
+ ---
3785
+
3786
+ ## 11. 성공 지표
3787
+
3788
+ | 지표 | 측정 방법 | 목표 |
3789
+ |------|----------|------|
3790
+ | **관련성** | 사용자 피드백 | 80%+ 유용 |
3791
+ | **속도** | 응답 지연 | < 500ms |
3792
+ | **채택률** | 활성 사용자 | 1000+ |
3793
+ | **재사용률** | 기억 활용 빈도 | 50%+ 세션 |
3794
+
3795
+ ## 2026-02-25T12:44:49.770Z | c15348b2-9c17-4b7f-abd6-06abcf83c7fa
3796
+ - type: session_summary
3797
+ - session: import:organized
3798
+ # Decisions (extracted)
3799
+
3800
+ - confidence: high
3801
+
3802
+ ## 2026-01-31 | feat: implement complete code-memory plugin
3803
+ - status: active (inferred)
3804
+ - source: commit:111f400e73f0568b192a5b1b37a88622fd44d648
3805
+ - author: Claude
3806
+ - changedFiles: 31
3807
+ - confidence: mid
3808
+
3809
+ ## 2026-01-31 | feat: add session history import functionality
3810
+ - status: active (inferred)
3811
+ - source: commit:22b1c43d9b9f095cd2a210f529ca8bee5a1100c5
3812
+ - author: Claude
3813
+ - changedFiles: 5
3814
+ - confidence: mid
3815
+
3816
+ ## 2026-02-01 | docs: Update README with comprehensive feature documentation (#3)
3817
+ - status: active (inferred)
3818
+ - source: commit:3662dfae8381fdf35923b115f58c362e091c474a
3819
+ - author: justinbuzzni
3820
+ - changedFiles: 1
3821
+ - confidence: mid
3822
+
3823
+ ## 2026-02-01 | feat: Add cross-project shared troubleshooting store
3824
+ - status: active (inferred)
3825
+ - source: commit:d04e562b5b011e0f07cdea0664db823f0caca5d0
3826
+ - author: justinbuzzni
3827
+ - changedFiles: 9
3828
+ - confidence: mid
3829
+
3830
+ ## 2026-02-01 | refactor: Extract DuckDB wrapper for consistent async API
3831
+ - status: active (inferred)
3832
+ - source: commit:65b0f64da3fd2c4b0b758b89f9d0f22301df23a7
3833
+ - author: justinbuzzni
3834
+ - changedFiles: 19
3835
+ - confidence: mid
3836
+
3837
+ ## 2026-02-01 | feat: Add web dashboard for memory visualization
3838
+ - status: active (inferred)
3839
+ - source: commit:665cf11bb9a01f1bcba51ec49f53382e95cd7e32
3840
+ - author: justinbuzzni
3841
+ - changedFiles: 5
3842
+ - confidence: mid
3843
+
3844
+ ## 2026-02-01 | refactor: Rename project from code-memory to claude-memory-layer
3845
+ - status: active (inferred)
3846
+ - source: commit:f35da2b92704d7d1b5655edac3516c64a829eeef
3847
+ - author: justinbuzzni
3848
+ - changedFiles: 7
3849
+ - confidence: mid
3850
+
3851
+ ## 2026-02-01 | feat: Migrate primary store from DuckDB to SQLite (WAL mode)
3852
+ - status: active (inferred)
3853
+ - source: commit:be36be70f69d42d2373ac26e6c0b8e8b53ca0340
3854
+ - author: justinbuzzni
3855
+ - changedFiles: 8
3856
+ - confidence: mid
3857
+
3858
+ ## 2026-02-01 | feat: Enhance dashboard, CLI, and memory graduation system
3859
+ - status: active (inferred)
3860
+ - source: commit:babfd15284754bc3dbb698fcc4c81efcf53fcd85
3861
+ - author: justinbuzzni
3862
+ - changedFiles: 13
3863
+ - confidence: mid
3864
+
3865
+ ## 2026-02-07 | feat: Add memory helpfulness tracking and dashboard sort controls
3866
+ - status: active (inferred)
3867
+ - source: commit:794640023652fc38b010e1ab46ca6a9a504a09e8
3868
+ - author: justinbuzzni
3869
+ - changedFiles: 9
3870
+ - confidence: mid
3871
+
3872
+ ## 2026-02-08 | feat: Add interactive dashboard with modals, navigation, and detail views
3873
+ - status: active (inferred)
3874
+ - source: commit:20c37b2cdffd271eaf04df9d2e87e5f23a4f853e
3875
+ - author: justinbuzzni
3876
+ - changedFiles: 5
3877
+ - confidence: mid
3878
+
3879
+ ## 2026-02-08 | fix: Align hooks with actual Claude Code input format and use lightweight service
3880
+ - status: active (inferred)
3881
+ - source: commit:a1d93af414821eb92d74cd02abb748849366ebfb
3882
+ - author: justinbuzzni
3883
+ - changedFiles: 4
3884
+ - confidence: mid
3885
+
3886
+ ## 2026-02-08 | feat: Add real-time progress display for import command
3887
+ - status: active (inferred)
3888
+ - source: commit:fd8f38af7cecf7d31a32a5aba9b1902178f986b1
3889
+ - author: justinbuzzni
3890
+ - changedFiles: 2
3891
+ - confidence: mid
3892
+
3893
+ ## 2026-02-08 | feat: Add turn-based event grouping, force reimport, and session registry support
3894
+ - status: active (inferred)
3895
+ - source: commit:938ec34bdf5fe1e4c43274424497ca081d62023a
3896
+ - author: justinbuzzni
3897
+ - changedFiles: 9
3898
+ - confidence: mid
3899
+
3900
+ ## 2026-02-08 | feat: Add per-project dashboard with project selector and turns API
3901
+ - status: active (inferred)
3902
+ - source: commit:af18cee5277324c78a9e1bca5873bc86ee5b2719
3903
+ - author: justinbuzzni
3904
+ - changedFiles: 12
3905
+ - confidence: mid
3906
+
3907
+ ## 2026-02-08 | fix: Handle vector store table race condition and auto-create SQLite directories
3908
+ - status: active (inferred)
3909
+ - source: commit:5b7401917611b50ee49e38bdf080983d1c763d5e
3910
+ - author: justinbuzzni
3911
+ - changedFiles: 2
3912
+ - confidence: mid
3913
+
3914
+ ## 2026-02-08 | feat: Add Ask Memory chat service to dashboard
3915
+ - status: active (inferred)
3916
+ - source: commit:a7b260f0ceeff6d768fefb675e6425f5b4717d7e
3917
+ - author: justinbuzzni
3918
+ - changedFiles: 5
3919
+ - confidence: mid
3920
+
3921
+ ## 2026-02-08 | feat: Widen chat panel and add conversation history with localStorage
3922
+ - status: active (inferred)
3923
+ - source: commit:15547d41e952350d095dfe3c01b2afa749638532
3924
+ - author: justinbuzzni
3925
+ - changedFiles: 3
3926
+ - confidence: mid
3927
+
3928
+ ## 2026-02-08 | fix: Knowledge Graph shows data even when no memories have been accessed
3929
+ - status: active (inferred)
3930
+ - source: commit:78b0956610eb7d22c28a821c67e10e6e9996c5be
3931
+ - author: justinbuzzni
3932
+ - changedFiles: 2
3933
+ - confidence: mid
3934
+
3935
+ ## 2026-02-20 | feat(ops): add heartbeat orchestrator and sync-gap auto-heal scripts
3936
+ - status: active (inferred)
3937
+ - source: commit:d56d22ba3271c1d51ea8bbaddb21f5f3d0a79d49
3938
+ - author: namsangboy
3939
+ - changedFiles: 7
3940
+ - confidence: mid
3941
+
3942
+ ## 2026-02-09 | feat: optional MongoDB sync for project events
3943
+ - status: active (inferred)
3944
+ - source: commit:11d3092e372836f784a760fc0b4269fd44e9159f
3945
+ - author: Justin
3946
+ - changedFiles: 9
3947
+ - confidence: mid
3948
+
3949
+ ## 2026-02-22 | feat: add Codex session history importer, MongoDB sync config, and AGENTS.md
3950
+ - status: active (inferred)
3951
+ - source: commit:4855172b8f92fff0c148c106de4e10c494d2bb09
3952
+ - author: Justin
3953
+ - changedFiles: 4
3954
+ - confidence: mid
3955
+
3956
+ ## 2026-02-24 | feat(memory): adopt memU-style scoped retrieval and staged ingest hooks
3957
+ - status: active (inferred)
3958
+ - source: commit:d278200d0f0666616a8556f2f25f9758b3ab9afd
3959
+ - author: justinbuzzni
3960
+ - changedFiles: 6
3961
+ - confidence: mid
3962
+
3963
+ ## 2026-02-24 | feat(memory): add append-only markdown mirror for categorized event archives
3964
+ - status: active (inferred)
3965
+ - source: commit:917ad7fc97a1c2de68637dfbe4b4cdd51776ec30
3966
+ - author: justinbuzzni
3967
+ - changedFiles: 4
3968
+ - confidence: mid
3969
+
3970
+ ## 2026-02-24 | feat: append-only markdown mirror in sqlite ingest flow
3971
+ - status: active (inferred)
3972
+ - source: commit:72250046152e851ed70476a8704ca38ca633ffab
3973
+ - author: justinbuzzni
3974
+ - changedFiles: 3
3975
+ - confidence: mid
3976
+
3977
+ ## 2026-02-24 | feat(memory): auto-refresh markdown mirror index
3978
+ - status: active (inferred)
3979
+ - source: commit:3a34d45a594affb034d6e416e3a29b6d2dcc20a5
3980
+ - author: justinbuzzni
3981
+ - changedFiles: 3
3982
+ - confidence: mid
3983
+
3984
+ ## 2026-02-24 | feat(cli): add organize-import command for structured markdown memory import
3985
+ - status: active (inferred)
3986
+ - source: commit:fe9ef67e5acabb81885a3c752a5b8525f80856a5
3987
+ - author: justinbuzzni
3988
+ - changedFiles: 3
3989
+ - confidence: mid
3990
+
3991
+ ## 2026-02-24 | feat(retrieval): add auto fallback chain fast→deep→scope-expand→summary
3992
+ - status: active (inferred)
3993
+ - source: commit:0dceb2d914e67e10d140848340f30e6fd07c4f67
3994
+ - author: justinbuzzni
3995
+ - changedFiles: 2
3996
+ - confidence: mid
3997
+
3998
+ ## 2026-02-24 | feat(ranking): add helpfulness-driven adaptive rerank weights v1
3999
+ - status: active (inferred)
4000
+ - source: commit:7de02967a1d59aea3e04ef1239585b93828c503a
4001
+ - author: justinbuzzni
4002
+ - changedFiles: 3
4003
+ - confidence: mid
4004
+
4005
+ ## 2026-02-24 | feat(retrieval): add ttl/decay ranking policy v1
4006
+ - status: active (inferred)
4007
+ - source: commit:46f2cfa2d99f0c8fb3a48709a97f62800f01d4fe
4008
+ - author: justinbuzzni
4009
+ - changedFiles: 2
4010
+ - confidence: mid
4011
+
4012
+ ## 2026-02-24 | feat(retrieval): add intent-rewrite deep retrieval merge flow
4013
+ - status: active (inferred)
4014
+ - source: commit:5fd950beee4d02f00b0c93be668a2e114ce9b257
4015
+ - author: justinbuzzni
4016
+ - changedFiles: 3
4017
+ - confidence: mid
4018
+
4019
+ ## 2026-02-24 | feat(retrieval): add graph-hop expansion with hop penalty
4020
+ - status: active (inferred)
4021
+ - source: commit:d1dfe03f881d1a76ecd9a916cbf04c3ff2a4bf7e
4022
+ - author: justinbuzzni
4023
+ - changedFiles: 2
4024
+ - confidence: mid
4025
+
4026
+ ## 2026-02-24 | feat(consolidation): add hierarchical summary→rule automation with report
4027
+ - status: active (inferred)
4028
+ - source: commit:7c84b5eacff733d8cb692eb9d47b7297a0872e43
4029
+ - author: justinbuzzni
4030
+ - changedFiles: 6
4031
+ - confidence: mid
4032
+
4033
+ ## 2026-02-25 | Feat/organize import bootstrap kb (#10)
4034
+ - status: active (inferred)
4035
+ - source: commit:db38c7e606a59478c03bac7e5bb5951954ca0813
4036
+ - author: justinbuzzni
4037
+ - changedFiles: 4
4038
+ - confidence: mid
4039
+
4040
+ ## Sources
4041
+ - source: git-log:since=180 days ago;max=1000
4042
+
4043
+ ## 2026-02-25T12:44:49.793Z | ad99702b-0e3a-4054-ab3c-27d4d1c83850
4044
+ - type: session_summary
4045
+ - session: import:organized
4046
+ # Glossary (auto-extracted)
4047
+
4048
+ - confidence: mid
4049
+
4050
+ - context
4051
+ - spec
4052
+ - plan
4053
+ - memory
4054
+ - store
4055
+ - sync
4056
+ - worker
4057
+ - retriever
4058
+ - event
4059
+ - mirror
4060
+ - session
4061
+ - shared
4062
+ - vector
4063
+ - gap
4064
+ - history
4065
+ - matcher
4066
+ - sqlite
4067
+ - task
4068
+ - aligner
4069
+ - auto
4070
+ - bootstrap
4071
+ - canonical
4072
+ - config
4073
+ - consolidation
4074
+ - evidence
4075
+ - graduation
4076
+ - importer
4077
+ - ingest
4078
+ - interceptor
4079
+ - key
4080
+ - markdown
4081
+ - mongo
4082
+ - organizer
4083
+ - package
4084
+ - repo
4085
+ - resolver
4086
+ - search
4087
+ - stats
4088
+ - wrapper
4089
+
4090
+ ## Sources
4091
+ - source: repo-scan:/home/walter/workspace/opensource/claude-memory-layer
4092
+
4093
+ ## 2026-02-25T12:44:49.802Z | df87a07f-4efe-4925-829a-2dd51fb27014
4094
+ - type: session_summary
4095
+ - session: import:organized
4096
+ # Module: .claude-plugin
4097
+
4098
+ - responsibility: inferred from top-level path `.claude-plugin/`
4099
+ - files: 8
4100
+ - languages: Markdown, JSON
4101
+ - confidence: high
4102
+
4103
+ ## Entry Candidates
4104
+ - none detected
4105
+
4106
+ ## Related Commits (recent sample)
4107
+ - 2026-01-31 111f400e feat: implement complete code-memory plugin
4108
+ - 2026-01-31 22b1c43d feat: add session history import functionality
4109
+ - 2026-02-01 504ec3dd docs: Add citations and endless mode specification documents (#2)
4110
+ - 2026-02-01 f35da2b9 refactor: Rename project from code-memory to claude-memory-layer
4111
+
4112
+ ## Sources
4113
+ - source: repo-path:.claude-plugin/**
4114
+ - source: commit:111f400e73f0568b192a5b1b37a88622fd44d648
4115
+ - source: commit:22b1c43d9b9f095cd2a210f529ca8bee5a1100c5
4116
+ - source: commit:504ec3ddd7f451fabf2cf01e073fc96e65ae124e
4117
+ - source: commit:f35da2b92704d7d1b5655edac3516c64a829eeef
4118
+
4119
+ ## 2026-02-25T12:44:49.817Z | 7a188e68-aab0-4d23-ae8c-b904d850224f
4120
+ - type: session_summary
4121
+ - session: import:organized
4122
+ # Module: AGENTS.md
4123
+
4124
+ - responsibility: inferred from top-level path `AGENTS.md/`
4125
+ - files: 1
4126
+ - languages: Markdown
4127
+ - confidence: low
4128
+
4129
+ ## Entry Candidates
4130
+ - none detected
4131
+
4132
+ ## Related Commits (recent sample)
4133
+ - none in selected range
4134
+
4135
+ ## Sources
4136
+ - source: repo-path:AGENTS.md/**
4137
+
4138
+ ## 2026-02-25T12:44:49.826Z | 9f2abb09-0094-4864-b1d1-8481675491bd
4139
+ - type: session_summary
4140
+ - session: import:organized
4141
+ # Module: CLAUDE.md
4142
+
4143
+ - responsibility: inferred from top-level path `CLAUDE.md/`
4144
+ - files: 1
4145
+ - languages: Markdown
4146
+ - confidence: low
4147
+
4148
+ ## Entry Candidates
4149
+ - none detected
4150
+
4151
+ ## Related Commits (recent sample)
4152
+ - none in selected range
4153
+
4154
+ ## Sources
4155
+ - source: repo-path:CLAUDE.md/**
4156
+
4157
+ ## 2026-02-25T12:44:49.834Z | a410152a-449c-4f76-b5e9-5bbecacd4370
4158
+ - type: session_summary
4159
+ - session: import:organized
4160
+ # Module: context.md
4161
+
4162
+ - responsibility: inferred from top-level path `context.md/`
4163
+ - files: 1
4164
+ - languages: Markdown
4165
+ - confidence: low
4166
+
4167
+ ## Entry Candidates
4168
+ - none detected
4169
+
4170
+ ## Related Commits (recent sample)
4171
+ - none in selected range
4172
+
4173
+ ## Sources
4174
+ - source: repo-path:context.md/**
4175
+
4176
+ ## 2026-02-25T12:44:49.841Z | 7b9b955f-89a4-4b90-a75f-35a50e59b14d
4177
+ - type: session_summary
4178
+ - session: import:organized
4179
+ # Module: docs
4180
+
4181
+ - responsibility: inferred from top-level path `docs/`
4182
+ - files: 2
4183
+ - languages: Markdown
4184
+ - confidence: mid
4185
+
4186
+ ## Entry Candidates
4187
+ - none detected
4188
+
4189
+ ## Related Commits (recent sample)
4190
+ - 2026-02-20 d56d22ba feat(ops): add heartbeat orchestrator and sync-gap auto-heal scripts
4191
+ - 2026-02-24 4447e64f docs(memory): document memU-inspired retrieval strategies and scoped filters
4192
+
4193
+ ## Sources
4194
+ - source: repo-path:docs/**
4195
+ - source: commit:d56d22ba3271c1d51ea8bbaddb21f5f3d0a79d49
4196
+ - source: commit:4447e64fa00065bfb364d38c597ad87484770891
4197
+
4198
+ ## 2026-02-25T12:44:49.849Z | 39062a82-1fd5-47ba-850c-36adb9aaad2a
4199
+ - type: session_summary
4200
+ - session: import:organized
4201
+ # Module: HANDOFF.md
4202
+
4203
+ - responsibility: inferred from top-level path `HANDOFF.md/`
4204
+ - files: 1
4205
+ - languages: Markdown
4206
+ - confidence: low
4207
+
4208
+ ## Entry Candidates
4209
+ - none detected
4210
+
4211
+ ## Related Commits (recent sample)
4212
+ - none in selected range
4213
+
4214
+ ## Sources
4215
+ - source: repo-path:HANDOFF.md/**
4216
+
4217
+ ## 2026-02-25T12:44:49.856Z | ede06b47-7e54-4a2b-8e59-0d87fec83fa5
4218
+ - type: session_summary
4219
+ - session: import:organized
4220
+ # Module: package-lock.json
4221
+
4222
+ - responsibility: inferred from top-level path `package-lock.json/`
4223
+ - files: 1
4224
+ - languages: JSON
4225
+ - confidence: low
4226
+
4227
+ ## Entry Candidates
4228
+ - none detected
4229
+
4230
+ ## Related Commits (recent sample)
4231
+ - none in selected range
4232
+
4233
+ ## Sources
4234
+ - source: repo-path:package-lock.json/**
4235
+
4236
+ ## 2026-02-25T12:44:49.863Z | ccfcd6c5-95fb-4a1c-9708-d518cad72a84
4237
+ - type: session_summary
4238
+ - session: import:organized
4239
+ # Module: package.json
4240
+
4241
+ - responsibility: inferred from top-level path `package.json/`
4242
+ - files: 1
4243
+ - languages: JSON
4244
+ - confidence: low
4245
+
4246
+ ## Entry Candidates
4247
+ - none detected
4248
+
4249
+ ## Related Commits (recent sample)
4250
+ - none in selected range
4251
+
4252
+ ## Sources
4253
+ - source: repo-path:package.json/**
4254
+
4255
+ ## 2026-02-25T12:44:49.869Z | 698bcbda-e8a5-47c8-8b97-4cffebd4c1d6
4256
+ - type: session_summary
4257
+ - session: import:organized
4258
+ # Module: plan.md
4259
+
4260
+ - responsibility: inferred from top-level path `plan.md/`
4261
+ - files: 1
4262
+ - languages: Markdown
4263
+ - confidence: low
4264
+
4265
+ ## Entry Candidates
4266
+ - none detected
4267
+
4268
+ ## Related Commits (recent sample)
4269
+ - none in selected range
4270
+
4271
+ ## Sources
4272
+ - source: repo-path:plan.md/**
4273
+
4274
+ ## 2026-02-25T12:44:49.876Z | 3c641407-4507-4025-a30a-1ba8bc3ba6a9
4275
+ - type: session_summary
4276
+ - session: import:organized
4277
+ # Module: README.md
4278
+
4279
+ - responsibility: inferred from top-level path `README.md/`
4280
+ - files: 1
4281
+ - languages: Markdown
4282
+ - confidence: low
4283
+
4284
+ ## Entry Candidates
4285
+ - none detected
4286
+
4287
+ ## Related Commits (recent sample)
4288
+ - none in selected range
4289
+
4290
+ ## Sources
4291
+ - source: repo-path:README.md/**
4292
+
4293
+ ## 2026-02-25T12:44:49.883Z | f948c223-8747-48a2-aacb-eb3c0f4d7ef1
4294
+ - type: session_summary
4295
+ - session: import:organized
4296
+ # Module: scripts
4297
+
4298
+ - responsibility: inferred from top-level path `scripts/`
4299
+ - files: 6
4300
+ - languages: JavaScript, Shell, TypeScript
4301
+ - confidence: high
4302
+
4303
+ ## Entry Candidates
4304
+ - none detected
4305
+
4306
+ ## Related Commits (recent sample)
4307
+ - 2026-01-31 111f400e feat: implement complete code-memory plugin
4308
+ - 2026-02-01 665cf11b feat: Add web dashboard for memory visualization
4309
+ - 2026-02-01 f35da2b9 refactor: Rename project from code-memory to claude-memory-layer
4310
+ - 2026-02-01 be36be70 feat: Migrate primary store from DuckDB to SQLite (WAL mode)
4311
+ - 2026-02-20 d56d22ba feat(ops): add heartbeat orchestrator and sync-gap auto-heal scripts
4312
+ - 2026-02-09 11d3092e feat: optional MongoDB sync for project events
4313
+
4314
+ ## Sources
4315
+ - source: repo-path:scripts/**
4316
+ - source: commit:111f400e73f0568b192a5b1b37a88622fd44d648
4317
+ - source: commit:665cf11bb9a01f1bcba51ec49f53382e95cd7e32
4318
+ - source: commit:f35da2b92704d7d1b5655edac3516c64a829eeef
4319
+ - source: commit:be36be70f69d42d2373ac26e6c0b8e8b53ca0340
4320
+ - source: commit:d56d22ba3271c1d51ea8bbaddb21f5f3d0a79d49
4321
+ - source: commit:11d3092e372836f784a760fc0b4269fd44e9159f
4322
+
4323
+ ## 2026-02-25T12:44:49.889Z | 2da127d3-7fff-44bb-85aa-3858635b10e1
4324
+ - type: session_summary
4325
+ - session: import:organized
4326
+ # Module: spec.md
4327
+
4328
+ - responsibility: inferred from top-level path `spec.md/`
4329
+ - files: 1
4330
+ - languages: Markdown
4331
+ - confidence: low
4332
+
4333
+ ## Entry Candidates
4334
+ - none detected
4335
+
4336
+ ## Related Commits (recent sample)
4337
+ - none in selected range
4338
+
4339
+ ## Sources
4340
+ - source: repo-path:spec.md/**
4341
+
4342
+ ## 2026-02-25T12:44:49.896Z | c7f1b00c-61ee-4621-a012-4cb83d80fd99
4343
+ - type: session_summary
4344
+ - session: import:organized
4345
+ # Module: specs
4346
+
4347
+ - responsibility: inferred from top-level path `specs/`
4348
+ - files: 35
4349
+ - languages: Markdown
4350
+ - confidence: high
4351
+
4352
+ ## Entry Candidates
4353
+ - none detected
4354
+
4355
+ ## Related Commits (recent sample)
4356
+ - 2026-02-01 4bbbc717 Merge pull request #1 from buzzni/claude/idris2-memory-storage-JLk7J
4357
+ - 2026-02-01 504ec3dd docs: Add citations and endless mode specification documents (#2)
4358
+ - 2026-02-08 20c37b2c feat: Add interactive dashboard with modals, navigation, and detail views
4359
+
4360
+ ## Sources
4361
+ - source: repo-path:specs/**
4362
+ - source: commit:4bbbc7174f920434cfc67ee02746a9b9824ec101
4363
+ - source: commit:504ec3ddd7f451fabf2cf01e073fc96e65ae124e
4364
+ - source: commit:20c37b2cdffd271eaf04df9d2e87e5f23a4f853e
4365
+
4366
+ ## 2026-02-25T12:44:49.902Z | 8315c023-3a7a-451d-82de-1629672658c6
4367
+ - type: session_summary
4368
+ - session: import:organized
4369
+ # Module: src
4370
+
4371
+ - responsibility: inferred from top-level path `src/`
4372
+ - files: 70
4373
+ - languages: TypeScript, JavaScript
4374
+ - confidence: high
4375
+
4376
+ ## Entry Candidates
4377
+ - src/cli/index.ts
4378
+ - src/core/index.ts
4379
+ - src/core/privacy/index.ts
4380
+ - src/core/task/index.ts
4381
+ - src/mcp/index.ts
4382
+ - src/server/api/index.ts
4383
+ - src/server/index.ts
4384
+ - src/ui/app.js
4385
+
4386
+ ## Related Commits (recent sample)
4387
+ - 2026-01-31 111f400e feat: implement complete code-memory plugin
4388
+ - 2026-01-31 22b1c43d feat: add session history import functionality
4389
+ - 2026-02-01 4bbbc717 Merge pull request #1 from buzzni/claude/idris2-memory-storage-JLk7J
4390
+ - 2026-02-01 504ec3dd docs: Add citations and endless mode specification documents (#2)
4391
+ - 2026-02-01 d04e562b feat: Add cross-project shared troubleshooting store
4392
+ - 2026-02-01 65b0f64d refactor: Extract DuckDB wrapper for consistent async API
4393
+ - 2026-02-01 665cf11b feat: Add web dashboard for memory visualization
4394
+ - 2026-02-01 f35da2b9 refactor: Rename project from code-memory to claude-memory-layer
4395
+ - 2026-02-01 be36be70 feat: Migrate primary store from DuckDB to SQLite (WAL mode)
4396
+ - 2026-02-01 babfd152 feat: Enhance dashboard, CLI, and memory graduation system
4397
+ - 2026-02-02 543643e7 perf: Add fast keyword search and optimize hook performance
4398
+ - 2026-02-07 79464002 feat: Add memory helpfulness tracking and dashboard sort controls
4399
+ - 2026-02-08 20c37b2c feat: Add interactive dashboard with modals, navigation, and detail views
4400
+ - 2026-02-08 a1d93af4 fix: Align hooks with actual Claude Code input format and use lightweight service
4401
+ - 2026-02-08 fd8f38af feat: Add real-time progress display for import command
4402
+
4403
+ ## Sources
4404
+ - source: repo-path:src/**
4405
+ - source: commit:111f400e73f0568b192a5b1b37a88622fd44d648
4406
+ - source: commit:22b1c43d9b9f095cd2a210f529ca8bee5a1100c5
4407
+ - source: commit:4bbbc7174f920434cfc67ee02746a9b9824ec101
4408
+ - source: commit:504ec3ddd7f451fabf2cf01e073fc96e65ae124e
4409
+ - source: commit:d04e562b5b011e0f07cdea0664db823f0caca5d0
4410
+ - source: commit:65b0f64da3fd2c4b0b758b89f9d0f22301df23a7
4411
+ - source: commit:665cf11bb9a01f1bcba51ec49f53382e95cd7e32
4412
+ - source: commit:f35da2b92704d7d1b5655edac3516c64a829eeef
4413
+ - source: commit:be36be70f69d42d2373ac26e6c0b8e8b53ca0340
4414
+ - source: commit:babfd15284754bc3dbb698fcc4c81efcf53fcd85
4415
+ - source: commit:543643e7a9f1d4a94f3216c2369d0212a51ff32d
4416
+ - source: commit:794640023652fc38b010e1ab46ca6a9a504a09e8
4417
+ - source: commit:20c37b2cdffd271eaf04df9d2e87e5f23a4f853e
4418
+ - source: commit:a1d93af414821eb92d74cd02abb748849366ebfb
4419
+ - source: commit:fd8f38af7cecf7d31a32a5aba9b1902178f986b1
4420
+
4421
+ ## 2026-02-25T12:44:49.909Z | c2836359-ecb1-4c15-86ab-42163c79b489
4422
+ - type: session_summary
4423
+ - session: import:organized
4424
+ # Module: tests
4425
+
4426
+ - responsibility: inferred from top-level path `tests/`
4427
+ - files: 12
4428
+ - languages: TypeScript
4429
+ - confidence: high
4430
+
4431
+ ## Entry Candidates
4432
+ - none detected
4433
+
4434
+ ## Related Commits (recent sample)
4435
+ - 2026-01-31 111f400e feat: implement complete code-memory plugin
4436
+ - 2026-02-09 11d3092e feat: optional MongoDB sync for project events
4437
+ - 2026-02-24 d278200d feat(memory): adopt memU-style scoped retrieval and staged ingest hooks
4438
+ - 2026-02-24 917ad7fc feat(memory): add append-only markdown mirror for categorized event archives
4439
+ - 2026-02-24 72250046 feat: append-only markdown mirror in sqlite ingest flow
4440
+ - 2026-02-24 3a34d45a feat(memory): auto-refresh markdown mirror index
4441
+ - 2026-02-24 df15146c chore(memory): normalize markdown mirror default category to uncategorized
4442
+ - 2026-02-24 0dceb2d9 feat(retrieval): add auto fallback chain fast→deep→scope-expand→summary
4443
+ - 2026-02-24 7de02967 feat(ranking): add helpfulness-driven adaptive rerank weights v1
4444
+ - 2026-02-24 46f2cfa2 feat(retrieval): add ttl/decay ranking policy v1
4445
+ - 2026-02-24 5fd950be feat(retrieval): add intent-rewrite deep retrieval merge flow
4446
+ - 2026-02-24 d1dfe03f feat(retrieval): add graph-hop expansion with hop penalty
4447
+ - 2026-02-24 7c84b5ea feat(consolidation): add hierarchical summary→rule automation with report
4448
+ - 2026-02-25 db38c7e6 Feat/organize import bootstrap kb (#10)
4449
+
4450
+ ## Sources
4451
+ - source: repo-path:tests/**
4452
+ - source: commit:111f400e73f0568b192a5b1b37a88622fd44d648
4453
+ - source: commit:11d3092e372836f784a760fc0b4269fd44e9159f
4454
+ - source: commit:d278200d0f0666616a8556f2f25f9758b3ab9afd
4455
+ - source: commit:917ad7fc97a1c2de68637dfbe4b4cdd51776ec30
4456
+ - source: commit:72250046152e851ed70476a8704ca38ca633ffab
4457
+ - source: commit:3a34d45a594affb034d6e416e3a29b6d2dcc20a5
4458
+ - source: commit:df15146c2a8c3e389c1a2b8d6fcfb4a33f7a772d
4459
+ - source: commit:0dceb2d914e67e10d140848340f30e6fd07c4f67
4460
+ - source: commit:7de02967a1d59aea3e04ef1239585b93828c503a
4461
+ - source: commit:46f2cfa2d99f0c8fb3a48709a97f62800f01d4fe
4462
+ - source: commit:5fd950beee4d02f00b0c93be668a2e114ce9b257
4463
+ - source: commit:d1dfe03f881d1a76ecd9a916cbf04c3ff2a4bf7e
4464
+ - source: commit:7c84b5eacff733d8cb692eb9d47b7297a0872e43
4465
+ - source: commit:db38c7e606a59478c03bac7e5bb5951954ca0813
4466
+
4467
+ ## 2026-02-25T12:44:49.916Z | 5b4e83de-4ba2-4475-9b94-47f66c4571d4
4468
+ - type: session_summary
4469
+ - session: import:organized
4470
+ # Module: tsconfig.json
4471
+
4472
+ - responsibility: inferred from top-level path `tsconfig.json/`
4473
+ - files: 1
4474
+ - languages: JSON
4475
+ - confidence: low
4476
+
4477
+ ## Entry Candidates
4478
+ - none detected
4479
+
4480
+ ## Related Commits (recent sample)
4481
+ - none in selected range
4482
+
4483
+ ## Sources
4484
+ - source: repo-path:tsconfig.json/**
4485
+
4486
+ ## 2026-02-25T12:44:49.923Z | baf71944-cc8e-411f-96d2-a861944fe5c4
4487
+ - type: session_summary
4488
+ - session: import:organized
4489
+ # Module: vitest.config.ts
4490
+
4491
+ - responsibility: inferred from top-level path `vitest.config.ts/`
4492
+ - files: 1
4493
+ - languages: TypeScript
4494
+ - confidence: low
4495
+
4496
+ ## Entry Candidates
4497
+ - none detected
4498
+
4499
+ ## Related Commits (recent sample)
4500
+ - none in selected range
4501
+
4502
+ ## Sources
4503
+ - source: repo-path:vitest.config.ts/**
4504
+
4505
+ ## 2026-02-25T12:44:49.931Z | b68be7e7-e001-42ca-be4e-d5c07a37bf0d
4506
+ - type: session_summary
4507
+ - session: import:organized
4508
+ # Codebase Overview
4509
+
4510
+ - generatedAt: 2026-02-25T12:44:49.677Z
4511
+ - deterministicPipeline: true
4512
+ - repo: /home/walter/workspace/opensource/claude-memory-layer
4513
+ - filesAnalyzed: 150
4514
+ - commitsAnalyzed: 47
4515
+ - confidence: high
4516
+
4517
+ ## Directory / Module Map
4518
+ - src: 70 files (TypeScript, JavaScript)
4519
+ - specs: 35 files (Markdown)
4520
+ - tests: 12 files (TypeScript)
4521
+ - .claude-plugin: 8 files (Markdown, JSON)
4522
+ - scripts: 6 files (JavaScript, Shell, TypeScript)
4523
+ - .omc: 4 files (JSON)
4524
+ - docs: 2 files (Markdown)
4525
+ - AGENTS.md: 1 files (Markdown)
4526
+ - CLAUDE.md: 1 files (Markdown)
4527
+ - context.md: 1 files (Markdown)
4528
+ - d.sh: 1 files (Shell)
4529
+ - deploy.sh: 1 files (Shell)
4530
+ - HANDOFF.md: 1 files (Markdown)
4531
+ - package-lock.json: 1 files (JSON)
4532
+ - package.json: 1 files (JSON)
4533
+ - plan.md: 1 files (Markdown)
4534
+ - README.md: 1 files (Markdown)
4535
+ - spec.md: 1 files (Markdown)
4536
+ - tsconfig.json: 1 files (JSON)
4537
+ - vitest.config.ts: 1 files (TypeScript)
4538
+
4539
+ ## Fact
4540
+ - Generated from deterministic file scan and git history parsing.
4541
+
4542
+ ## Inference
4543
+ - Module responsibilities should be reviewed by maintainers for nuanced boundaries.
4544
+
4545
+ ## Sources
4546
+ - source: repo-scan:/home/walter/workspace/opensource/claude-memory-layer
4547
+ - source: git-log:since=180 days ago;max=1000
4548
+
4549
+ ## 2026-02-25T12:44:49.939Z | a238e1a3-f03a-415a-b90c-ed2c563c2db2
4550
+ - type: session_summary
4551
+ - session: import:organized
4552
+ # Sources Manifest
4553
+
4554
+ - deterministicPipeline: true
4555
+ - mode: incremental
4556
+ - sourceCount: 197
4557
+
4558
+ ## Outputs
4559
+ - decisions/decisions.md
4560
+ - glossary/glossary.md
4561
+ - modules/.claude-plugin.md
4562
+ - modules/agents.md.md
4563
+ - modules/claude.md.md
4564
+ - modules/context.md.md
4565
+ - modules/docs.md
4566
+ - modules/handoff.md.md
4567
+ - modules/package-lock.json.md
4568
+ - modules/package.json.md
4569
+ - modules/plan.md.md
4570
+ - modules/readme.md.md
4571
+ - modules/scripts.md
4572
+ - modules/spec.md.md
4573
+ - modules/specs.md
4574
+ - modules/src.md
4575
+ - modules/tests.md
4576
+ - modules/tsconfig.json.md
4577
+ - modules/vitest.config.ts.md
4578
+ - overview/overview.md
4579
+ - timeline/timeline.md
4580
+
4581
+ ## Sources (sample)
4582
+ - file:.claude-plugin/commands/memory-forget.md
4583
+ - file:.claude-plugin/commands/memory-history.md
4584
+ - file:.claude-plugin/commands/memory-import.md
4585
+ - file:.claude-plugin/commands/memory-list.md
4586
+ - file:.claude-plugin/commands/memory-search.md
4587
+ - file:.claude-plugin/commands/memory-stats.md
4588
+ - file:.claude-plugin/hooks.json
4589
+ - file:.claude-plugin/plugin.json
4590
+ - file:.omc/project-memory.json
4591
+ - file:.omc/sessions/9d7106b0-883c-4ad7-b7be-39de88a483e5.json
4592
+ - file:.omc/sessions/dccdf47f-f9ef-4621-a49d-f333667baf0a.json
4593
+ - file:.omc/state/subagent-tracking.json
4594
+ - file:AGENTS.md
4595
+ - file:CLAUDE.md
4596
+ - file:HANDOFF.md
4597
+ - file:README.md
4598
+ - file:context.md
4599
+ - file:d.sh
4600
+ - file:deploy.sh
4601
+ - file:docs/MEMU_ADOPTION.md
4602
+ - file:docs/OPERATIONS.md
4603
+ - file:package-lock.json
4604
+ - file:package.json
4605
+ - file:plan.md
4606
+ - file:scripts/build.ts
4607
+ - file:scripts/fix-sync-gap.js
4608
+ - file:scripts/heartbeat-memory-orchestrator.sh
4609
+ - file:scripts/report-sync-gap.js
4610
+ - file:scripts/review-queue-auto-resolve.js
4611
+ - file:scripts/sync-gap-auto-heal.sh
4612
+ - file:spec.md
4613
+ - file:specs/20260207-dashboard-upgrade/context.md
4614
+ - file:specs/20260207-dashboard-upgrade/spec.md
4615
+ - file:specs/citations-system/context.md
4616
+ - file:specs/citations-system/plan.md
4617
+ - file:specs/citations-system/spec.md
4618
+ - file:specs/endless-mode/context.md
4619
+ - file:specs/endless-mode/plan.md
4620
+ - file:specs/endless-mode/spec.md
4621
+ - file:specs/entity-edge-model/context.md
4622
+ - file:specs/entity-edge-model/plan.md
4623
+ - file:specs/entity-edge-model/spec.md
4624
+ - file:specs/evidence-aligner-v2/context.md
4625
+ - file:specs/evidence-aligner-v2/plan.md
4626
+ - file:specs/evidence-aligner-v2/spec.md
4627
+ - file:specs/mcp-desktop-integration/context.md
4628
+ - file:specs/mcp-desktop-integration/plan.md
4629
+ - file:specs/mcp-desktop-integration/spec.md
4630
+ - file:specs/post-tool-use-hook/context.md
4631
+ - file:specs/post-tool-use-hook/plan.md
4632
+ - file:specs/post-tool-use-hook/spec.md
4633
+ - file:specs/private-tags/context.md
4634
+ - file:specs/private-tags/plan.md
4635
+ - file:specs/private-tags/spec.md
4636
+ - file:specs/progressive-disclosure/context.md
4637
+ - file:specs/progressive-disclosure/plan.md
4638
+ - file:specs/progressive-disclosure/spec.md
4639
+ - file:specs/task-entity-system/context.md
4640
+ - file:specs/task-entity-system/plan.md
4641
+ - file:specs/task-entity-system/spec.md
4642
+ - file:specs/vector-outbox-v2/context.md
4643
+ - file:specs/vector-outbox-v2/plan.md
4644
+ - file:specs/vector-outbox-v2/spec.md
4645
+ - file:specs/web-viewer-ui/context.md
4646
+ - file:specs/web-viewer-ui/plan.md
4647
+ - file:specs/web-viewer-ui/spec.md
4648
+ - file:src/cli/index.ts
4649
+ - file:src/core/canonical-key.ts
4650
+ - file:src/core/citation-generator.ts
4651
+ - file:src/core/consolidated-store.ts
4652
+ - file:src/core/consolidation-worker.ts
4653
+ - file:src/core/context-formatter.ts
4654
+ - file:src/core/continuity-manager.ts
4655
+ - file:src/core/db-wrapper.ts
4656
+ - file:src/core/edge-repo.ts
4657
+ - file:src/core/embedder.ts
4658
+ - file:src/core/entity-repo.ts
4659
+ - file:src/core/event-store.ts
4660
+ - file:src/core/evidence-aligner.ts
4661
+ - file:src/core/graduation-worker.ts
4662
+ - file:src/core/graduation.ts
4663
+ - file:src/core/index.ts
4664
+ - file:src/core/ingest-interceptor.ts
4665
+ - file:src/core/markdown-mirror.ts
4666
+ - file:src/core/matcher.ts
4667
+ - file:src/core/md-mirror.ts
4668
+ - file:src/core/metadata-extractor.ts
4669
+ - file:src/core/mongo-sync-config.ts
4670
+ - file:src/core/mongo-sync-worker.ts
4671
+ - file:src/core/privacy/filter.ts
4672
+ - file:src/core/privacy/index.ts
4673
+ - file:src/core/privacy/tag-parser.ts
4674
+ - file:src/core/progressive-retriever.ts
4675
+ - file:src/core/retriever.ts
4676
+ - file:src/core/shared-event-store.ts
4677
+ - file:src/core/shared-promoter.ts
4678
+ - file:src/core/shared-store.ts
4679
+ - file:src/core/shared-vector-store.ts
4680
+ - file:src/core/sqlite-event-store.ts
4681
+ - file:src/core/sqlite-wrapper.ts
4682
+ - file:src/core/sync-worker.ts
4683
+ - file:src/core/task/blocker-resolver.ts
4684
+ - file:src/core/task/index.ts
4685
+ - file:src/core/task/task-matcher.ts
4686
+ - file:src/core/task/task-projector.ts
4687
+ - file:src/core/task/task-resolver.ts
4688
+ - file:src/core/turn-state.ts
4689
+ - file:src/core/types.ts
4690
+ - file:src/core/vector-outbox.ts
4691
+ - file:src/core/vector-store.ts
4692
+ - file:src/core/vector-worker.ts
4693
+ - file:src/core/working-set-store.ts
4694
+ - file:src/hooks/post-tool-use.ts
4695
+ - file:src/hooks/session-end.ts
4696
+ - file:src/hooks/session-start.ts
4697
+ - file:src/hooks/stop.ts
4698
+ - file:src/hooks/user-prompt-submit.ts
4699
+ - file:src/mcp/handlers.ts
4700
+ - file:src/mcp/index.ts
4701
+ - file:src/mcp/tools.ts
4702
+ - file:src/server/api/chat.ts
4703
+ - file:src/server/api/citations.ts
4704
+ - file:src/server/api/events.ts
4705
+ - file:src/server/api/index.ts
4706
+ - file:src/server/api/projects.ts
4707
+ - file:src/server/api/search.ts
4708
+ - file:src/server/api/sessions.ts
4709
+ - file:src/server/api/stats.ts
4710
+ - file:src/server/api/turns.ts
4711
+ - file:src/server/api/utils.ts
4712
+ - file:src/server/index.ts
4713
+ - file:src/services/bootstrap-organizer.ts
4714
+ - file:src/services/codex-session-history-importer.ts
4715
+ - file:src/services/memory-service.ts
4716
+ - file:src/services/session-history-importer.ts
4717
+ - file:src/ui/app.js
4718
+ - file:tests/bootstrap-organizer.test.ts
4719
+ - file:tests/canonical-key.test.ts
4720
+ - file:tests/consolidation-worker.test.ts
4721
+ - file:tests/evidence-aligner.test.ts
4722
+ - file:tests/ingest-interceptor.test.ts
4723
+ - file:tests/markdown-mirror.test.ts
4724
+ - file:tests/matcher.test.ts
4725
+ - file:tests/md-mirror.test.ts
4726
+ - file:tests/retriever-fallback-chain.test.ts
4727
+ - file:tests/retriever-strategy-scope.test.ts
4728
+ - file:tests/retriever.memu-adoption.test.ts
4729
+ - file:tests/sqlite-event-store-replication.test.ts
4730
+ - file:tsconfig.json
4731
+ - file:vitest.config.ts
4732
+ - commit:09a27030ac03dc003fc725ce1fd360a53ca3159f
4733
+ - commit:e0fb3078d786dd6f6a4cd8fac87e547668c04466
4734
+ - commit:83614efe2baf9ca3223508daecfff2e55fbf092e
4735
+ - commit:111f400e73f0568b192a5b1b37a88622fd44d648
4736
+ - commit:22b1c43d9b9f095cd2a210f529ca8bee5a1100c5
4737
+ - commit:ead5da9868336e6bb0696fd5ee236bc32c327079
4738
+ - commit:03ce3f8393e52df24f86ffc10756d3974204c373
4739
+ - commit:4bbbc7174f920434cfc67ee02746a9b9824ec101
4740
+ - commit:504ec3ddd7f451fabf2cf01e073fc96e65ae124e
4741
+ - commit:3662dfae8381fdf35923b115f58c362e091c474a
4742
+ - commit:d04e562b5b011e0f07cdea0664db823f0caca5d0
4743
+ - commit:65b0f64da3fd2c4b0b758b89f9d0f22301df23a7
4744
+ - commit:665cf11bb9a01f1bcba51ec49f53382e95cd7e32
4745
+ - commit:f35da2b92704d7d1b5655edac3516c64a829eeef
4746
+ - commit:d4f1f16858e2bf2436f12e4141fedbecf3a75851
4747
+ - commit:be36be70f69d42d2373ac26e6c0b8e8b53ca0340
4748
+ - commit:babfd15284754bc3dbb698fcc4c81efcf53fcd85
4749
+ - commit:543643e7a9f1d4a94f3216c2369d0212a51ff32d
4750
+ - commit:a8a8b4edb28a04c1d07abd6e67625f6b68b67b55
4751
+ - commit:794640023652fc38b010e1ab46ca6a9a504a09e8
4752
+ - commit:20c37b2cdffd271eaf04df9d2e87e5f23a4f853e
4753
+ - commit:a1d93af414821eb92d74cd02abb748849366ebfb
4754
+ - commit:fd8f38af7cecf7d31a32a5aba9b1902178f986b1
4755
+ - commit:938ec34bdf5fe1e4c43274424497ca081d62023a
4756
+ - commit:af18cee5277324c78a9e1bca5873bc86ee5b2719
4757
+ - commit:5b7401917611b50ee49e38bdf080983d1c763d5e
4758
+ - commit:a7b260f0ceeff6d768fefb675e6425f5b4717d7e
4759
+ - commit:15547d41e952350d095dfe3c01b2afa749638532
4760
+ - commit:78b0956610eb7d22c28a821c67e10e6e9996c5be
4761
+ - commit:d56d22ba3271c1d51ea8bbaddb21f5f3d0a79d49
4762
+ - commit:11d3092e372836f784a760fc0b4269fd44e9159f
4763
+ - commit:4855172b8f92fff0c148c106de4e10c494d2bb09
4764
+ - commit:d278200d0f0666616a8556f2f25f9758b3ab9afd
4765
+ - commit:4447e64fa00065bfb364d38c597ad87484770891
4766
+ - commit:e25f03a7680d82532d10620d3495ac6dc2b67a46
4767
+ - commit:917ad7fc97a1c2de68637dfbe4b4cdd51776ec30
4768
+ - commit:72250046152e851ed70476a8704ca38ca633ffab
4769
+ - commit:3a34d45a594affb034d6e416e3a29b6d2dcc20a5
4770
+ - commit:df15146c2a8c3e389c1a2b8d6fcfb4a33f7a772d
4771
+ - commit:fe9ef67e5acabb81885a3c752a5b8525f80856a5
4772
+ - commit:0dceb2d914e67e10d140848340f30e6fd07c4f67
4773
+ - commit:7de02967a1d59aea3e04ef1239585b93828c503a
4774
+ - commit:46f2cfa2d99f0c8fb3a48709a97f62800f01d4fe
4775
+ - commit:5fd950beee4d02f00b0c93be668a2e114ce9b257
4776
+ - commit:d1dfe03f881d1a76ecd9a916cbf04c3ff2a4bf7e
4777
+ - commit:7c84b5eacff733d8cb692eb9d47b7297a0872e43
4778
+ - commit:db38c7e606a59478c03bac7e5bb5951954ca0813
4779
+
4780
+ ## 2026-02-25T12:44:49.946Z | 244d330a-f728-4c93-bcfc-93c4096cd3b5
4781
+ - type: session_summary
4782
+ - session: import:organized
4783
+ # Timeline
4784
+
4785
+ - confidence: mid
4786
+
4787
+ ## 2026-01
4788
+ - 2026-01-31 09a27030 docs: add specification documents for code-memory plugin
4789
+ - 2026-01-31 e0fb3078 docs: enhance AXIOMMIND integration in specification documents
4790
+ - 2026-01-31 83614efe docs: add Memory Graduation Pipeline and 7 AXIOMMIND principles
4791
+ - 2026-01-31 111f400e feat: implement complete code-memory plugin
4792
+ - 2026-01-31 22b1c43d feat: add session history import functionality
4793
+ - 2026-01-31 ead5da98 docs: update README with detailed Korean documentation
4794
+ - 2026-01-31 03ce3f83 Add implementation guide for AxiomMind Memory Pipeline
4795
+
4796
+ ## 2026-02
4797
+ - 2026-02-01 4bbbc717 Merge pull request #1 from buzzni/claude/idris2-memory-storage-JLk7J
4798
+ - 2026-02-01 504ec3dd docs: Add citations and endless mode specification documents (#2)
4799
+ - 2026-02-01 3662dfae docs: Update README with comprehensive feature documentation (#3)
4800
+ - 2026-02-01 d04e562b feat: Add cross-project shared troubleshooting store
4801
+ - 2026-02-01 65b0f64d refactor: Extract DuckDB wrapper for consistent async API
4802
+ - 2026-02-01 665cf11b feat: Add web dashboard for memory visualization
4803
+ - 2026-02-01 f35da2b9 refactor: Rename project from code-memory to claude-memory-layer
4804
+ - 2026-02-01 d4f1f168 docs: Update README for claude-memory-layer rename
4805
+ - 2026-02-01 be36be70 feat: Migrate primary store from DuckDB to SQLite (WAL mode)
4806
+ - 2026-02-01 babfd152 feat: Enhance dashboard, CLI, and memory graduation system
4807
+ - 2026-02-02 543643e7 perf: Add fast keyword search and optimize hook performance
4808
+ - 2026-02-06 a8a8b4ed chore: Bump version to 1.0.10 and add project configuration
4809
+ - 2026-02-07 79464002 feat: Add memory helpfulness tracking and dashboard sort controls
4810
+ - 2026-02-08 20c37b2c feat: Add interactive dashboard with modals, navigation, and detail views
4811
+ - 2026-02-08 a1d93af4 fix: Align hooks with actual Claude Code input format and use lightweight service
4812
+ - 2026-02-08 fd8f38af feat: Add real-time progress display for import command
4813
+ - 2026-02-08 938ec34b feat: Add turn-based event grouping, force reimport, and session registry support
4814
+ - 2026-02-08 af18cee5 feat: Add per-project dashboard with project selector and turns API
4815
+ - 2026-02-08 5b740191 fix: Handle vector store table race condition and auto-create SQLite directories
4816
+ - 2026-02-08 a7b260f0 feat: Add Ask Memory chat service to dashboard
4817
+ - 2026-02-08 15547d41 feat: Widen chat panel and add conversation history with localStorage
4818
+ - 2026-02-08 78b09566 fix: Knowledge Graph shows data even when no memories have been accessed
4819
+ - 2026-02-20 d56d22ba feat(ops): add heartbeat orchestrator and sync-gap auto-heal scripts
4820
+ - 2026-02-09 11d3092e feat: optional MongoDB sync for project events
4821
+ - 2026-02-22 4855172b feat: add Codex session history importer, MongoDB sync config, and AGENTS.md
4822
+ - 2026-02-24 d278200d feat(memory): adopt memU-style scoped retrieval and staged ingest hooks
4823
+ - 2026-02-24 4447e64f docs(memory): document memU-inspired retrieval strategies and scoped filters
4824
+ - 2026-02-24 e25f03a7 docs(readme): add practical examples for memU-inspired retrieval options
4825
+ - 2026-02-24 917ad7fc feat(memory): add append-only markdown mirror for categorized event archives
4826
+ - 2026-02-24 72250046 feat: append-only markdown mirror in sqlite ingest flow
4827
+ - 2026-02-24 3a34d45a feat(memory): auto-refresh markdown mirror index
4828
+ - 2026-02-24 df15146c chore(memory): normalize markdown mirror default category to uncategorized
4829
+ - 2026-02-24 fe9ef67e feat(cli): add organize-import command for structured markdown memory import
4830
+ - 2026-02-24 0dceb2d9 feat(retrieval): add auto fallback chain fast→deep→scope-expand→summary
4831
+ - 2026-02-24 7de02967 feat(ranking): add helpfulness-driven adaptive rerank weights v1
4832
+ - 2026-02-24 46f2cfa2 feat(retrieval): add ttl/decay ranking policy v1
4833
+ - 2026-02-24 5fd950be feat(retrieval): add intent-rewrite deep retrieval merge flow
4834
+ - 2026-02-24 d1dfe03f feat(retrieval): add graph-hop expansion with hop penalty
4835
+ - 2026-02-24 7c84b5ea feat(consolidation): add hierarchical summary→rule automation with report
4836
+ - 2026-02-25 db38c7e6 Feat/organize import bootstrap kb (#10)
4837
+
4838
+ ## Sources
4839
+ - source: git-log:since=180 days ago;max=1000