claude-memory-layer 1.0.0

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 (127) hide show
  1. package/.claude-plugin/commands/memory-forget.md +42 -0
  2. package/.claude-plugin/commands/memory-history.md +34 -0
  3. package/.claude-plugin/commands/memory-import.md +56 -0
  4. package/.claude-plugin/commands/memory-list.md +37 -0
  5. package/.claude-plugin/commands/memory-search.md +36 -0
  6. package/.claude-plugin/commands/memory-stats.md +34 -0
  7. package/.claude-plugin/hooks.json +59 -0
  8. package/.claude-plugin/plugin.json +24 -0
  9. package/.history/package_20260201112328.json +45 -0
  10. package/.history/package_20260201113602.json +45 -0
  11. package/.history/package_20260201113713.json +45 -0
  12. package/.history/package_20260201114110.json +45 -0
  13. package/Memo.txt +558 -0
  14. package/README.md +520 -0
  15. package/context.md +636 -0
  16. package/dist/.claude-plugin/commands/memory-forget.md +42 -0
  17. package/dist/.claude-plugin/commands/memory-history.md +34 -0
  18. package/dist/.claude-plugin/commands/memory-import.md +56 -0
  19. package/dist/.claude-plugin/commands/memory-list.md +37 -0
  20. package/dist/.claude-plugin/commands/memory-search.md +36 -0
  21. package/dist/.claude-plugin/commands/memory-stats.md +34 -0
  22. package/dist/.claude-plugin/hooks.json +59 -0
  23. package/dist/.claude-plugin/plugin.json +24 -0
  24. package/dist/cli/index.js +3539 -0
  25. package/dist/cli/index.js.map +7 -0
  26. package/dist/core/index.js +4408 -0
  27. package/dist/core/index.js.map +7 -0
  28. package/dist/hooks/session-end.js +2971 -0
  29. package/dist/hooks/session-end.js.map +7 -0
  30. package/dist/hooks/session-start.js +2969 -0
  31. package/dist/hooks/session-start.js.map +7 -0
  32. package/dist/hooks/stop.js +3123 -0
  33. package/dist/hooks/stop.js.map +7 -0
  34. package/dist/hooks/user-prompt-submit.js +2960 -0
  35. package/dist/hooks/user-prompt-submit.js.map +7 -0
  36. package/dist/services/memory-service.js +2931 -0
  37. package/dist/services/memory-service.js.map +7 -0
  38. package/package.json +45 -0
  39. package/plan.md +1642 -0
  40. package/scripts/build.ts +102 -0
  41. package/spec.md +624 -0
  42. package/specs/citations-system/context.md +243 -0
  43. package/specs/citations-system/plan.md +495 -0
  44. package/specs/citations-system/spec.md +371 -0
  45. package/specs/endless-mode/context.md +305 -0
  46. package/specs/endless-mode/plan.md +620 -0
  47. package/specs/endless-mode/spec.md +455 -0
  48. package/specs/entity-edge-model/context.md +401 -0
  49. package/specs/entity-edge-model/plan.md +459 -0
  50. package/specs/entity-edge-model/spec.md +391 -0
  51. package/specs/evidence-aligner-v2/context.md +401 -0
  52. package/specs/evidence-aligner-v2/plan.md +303 -0
  53. package/specs/evidence-aligner-v2/spec.md +312 -0
  54. package/specs/mcp-desktop-integration/context.md +278 -0
  55. package/specs/mcp-desktop-integration/plan.md +550 -0
  56. package/specs/mcp-desktop-integration/spec.md +494 -0
  57. package/specs/post-tool-use-hook/context.md +319 -0
  58. package/specs/post-tool-use-hook/plan.md +469 -0
  59. package/specs/post-tool-use-hook/spec.md +364 -0
  60. package/specs/private-tags/context.md +288 -0
  61. package/specs/private-tags/plan.md +412 -0
  62. package/specs/private-tags/spec.md +345 -0
  63. package/specs/progressive-disclosure/context.md +346 -0
  64. package/specs/progressive-disclosure/plan.md +663 -0
  65. package/specs/progressive-disclosure/spec.md +415 -0
  66. package/specs/task-entity-system/context.md +297 -0
  67. package/specs/task-entity-system/plan.md +301 -0
  68. package/specs/task-entity-system/spec.md +314 -0
  69. package/specs/vector-outbox-v2/context.md +470 -0
  70. package/specs/vector-outbox-v2/plan.md +562 -0
  71. package/specs/vector-outbox-v2/spec.md +466 -0
  72. package/specs/web-viewer-ui/context.md +384 -0
  73. package/specs/web-viewer-ui/plan.md +797 -0
  74. package/specs/web-viewer-ui/spec.md +516 -0
  75. package/src/cli/index.ts +570 -0
  76. package/src/core/canonical-key.ts +186 -0
  77. package/src/core/citation-generator.ts +63 -0
  78. package/src/core/consolidated-store.ts +279 -0
  79. package/src/core/consolidation-worker.ts +384 -0
  80. package/src/core/context-formatter.ts +276 -0
  81. package/src/core/continuity-manager.ts +336 -0
  82. package/src/core/edge-repo.ts +324 -0
  83. package/src/core/embedder.ts +124 -0
  84. package/src/core/entity-repo.ts +342 -0
  85. package/src/core/event-store.ts +672 -0
  86. package/src/core/evidence-aligner.ts +635 -0
  87. package/src/core/graduation.ts +365 -0
  88. package/src/core/index.ts +32 -0
  89. package/src/core/matcher.ts +210 -0
  90. package/src/core/metadata-extractor.ts +203 -0
  91. package/src/core/privacy/filter.ts +179 -0
  92. package/src/core/privacy/index.ts +20 -0
  93. package/src/core/privacy/tag-parser.ts +145 -0
  94. package/src/core/progressive-retriever.ts +415 -0
  95. package/src/core/retriever.ts +235 -0
  96. package/src/core/task/blocker-resolver.ts +325 -0
  97. package/src/core/task/index.ts +9 -0
  98. package/src/core/task/task-matcher.ts +238 -0
  99. package/src/core/task/task-projector.ts +345 -0
  100. package/src/core/task/task-resolver.ts +414 -0
  101. package/src/core/types.ts +841 -0
  102. package/src/core/vector-outbox.ts +295 -0
  103. package/src/core/vector-store.ts +182 -0
  104. package/src/core/vector-worker.ts +488 -0
  105. package/src/core/working-set-store.ts +244 -0
  106. package/src/hooks/post-tool-use.ts +127 -0
  107. package/src/hooks/session-end.ts +78 -0
  108. package/src/hooks/session-start.ts +57 -0
  109. package/src/hooks/stop.ts +78 -0
  110. package/src/hooks/user-prompt-submit.ts +54 -0
  111. package/src/mcp/handlers.ts +212 -0
  112. package/src/mcp/index.ts +47 -0
  113. package/src/mcp/tools.ts +78 -0
  114. package/src/server/api/citations.ts +101 -0
  115. package/src/server/api/events.ts +101 -0
  116. package/src/server/api/index.ts +18 -0
  117. package/src/server/api/search.ts +98 -0
  118. package/src/server/api/sessions.ts +111 -0
  119. package/src/server/api/stats.ts +97 -0
  120. package/src/server/index.ts +91 -0
  121. package/src/services/memory-service.ts +626 -0
  122. package/src/services/session-history-importer.ts +367 -0
  123. package/tests/canonical-key.test.ts +101 -0
  124. package/tests/evidence-aligner.test.ts +152 -0
  125. package/tests/matcher.test.ts +112 -0
  126. package/tsconfig.json +24 -0
  127. package/vitest.config.ts +15 -0
package/context.md ADDED
@@ -0,0 +1,636 @@
1
+ # Context: Claude Code Memory Plugin
2
+
3
+ ## 1. 프로젝트 배경
4
+
5
+ 이 문서는 Claude Code용 Memory Plugin 개발을 위한 배경 연구와 참조 자료를 정리합니다.
6
+
7
+ ### 1.1 목표
8
+
9
+ 사용자가 Claude Code를 사용할수록 더 똑똑해지는 Agent를 만들기 위한 플러그인 개발:
10
+ - 사용자 prompt와 agent 응답을 지속적으로 기억
11
+ - 새로운 prompt 입력 시 관련된 과거 기억을 검색하여 컨텍스트로 활용
12
+ - 시간이 지남에 따라 개인화된 경험 제공
13
+
14
+ ---
15
+
16
+ ## 2. Claude Code Plugin System 분석
17
+
18
+ ### 2.1 플러그인 구조
19
+
20
+ ```
21
+ plugin-name/
22
+ ├── .claude-plugin/
23
+ │ └── plugin.json # 플러그인 메타데이터 (필수)
24
+ ├── commands/ # 슬래시 명령어 (선택)
25
+ ├── agents/ # 전문화된 에이전트 (선택)
26
+ ├── skills/ # 에이전트 스킬 (선택)
27
+ ├── hooks/ # 이벤트 핸들러 (선택)
28
+ ├── .mcp.json # MCP 서버 구성 (선택)
29
+ └── README.md # 문서
30
+ ```
31
+
32
+ ### 2.2 사용 가능한 Hook 이벤트
33
+
34
+ | Hook Event | 용도 | Memory Plugin 활용 |
35
+ |------------|------|-------------------|
36
+ | `SessionStart` | 세션 시작 시 실행 | 이전 세션 기억 로드 |
37
+ | `SessionEnd` | 세션 종료 시 실행 | 현재 세션 기억 저장 |
38
+ | `UserPromptSubmit` | 사용자 입력 시 실행 | 관련 기억 검색 및 주입 |
39
+ | `PreToolUse` | 도구 실행 전 | 도구별 과거 사용 패턴 제공 |
40
+ | `PostToolUse` | 도구 실행 후 | 도구 결과 기억 |
41
+ | `Stop` | Agent 응답 완료 시 | 전체 대화 기억 저장 |
42
+ | `PreCompact` | 컨텍스트 압축 전 | 중요 기억 보존 |
43
+
44
+ ### 2.3 Hook Input/Output 형식
45
+
46
+ ```json
47
+ // UserPromptSubmit hook input
48
+ {
49
+ "session_id": "...",
50
+ "prompt": "사용자가 입력한 텍스트",
51
+ "timestamp": "..."
52
+ }
53
+
54
+ // Hook은 stdout으로 결과 반환
55
+ // - 빈 출력: 변경 없음
56
+ // - JSON 출력: 컨텍스트 주입 또는 수정
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 3. AI Memory System 연구
62
+
63
+ ### 3.1 Memory의 종류
64
+
65
+ | 유형 | 설명 | 지속성 |
66
+ |------|------|--------|
67
+ | **Short-term Memory** | 현재 대화 컨텍스트 | 세션 내 |
68
+ | **Long-term Memory** | 사용자 선호도, 과거 인사이트 | 영구적 |
69
+ | **Episodic Memory** | 구체적인 대화/이벤트 기억 | 영구적 |
70
+ | **Semantic Memory** | 추출된 지식과 관계 | 영구적 |
71
+
72
+ ### 3.2 주요 Memory 솔루션 비교
73
+
74
+ | 솔루션 | 특징 | 장점 |
75
+ |--------|------|------|
76
+ | **Mem0** | Y Combinator 투자, 그래프 기반 | 복잡한 관계 표현 |
77
+ | **LangChain Memory** | 프레임워크 내장 | 쉬운 통합 |
78
+ | **Zep/Graphiti** | 시간적 지식 그래프 | 시계열 추적 |
79
+ | **AWS AgentCore Memory** | 비동기 파이프라인 | 확장성 |
80
+ | **Google Vertex Memory Bank** | 유사도 검색 | 엔터프라이즈 |
81
+
82
+ ### 3.3 Memory vs RAG
83
+
84
+ - **RAG**: 외부 문서에서 정보 검색 (stateless)
85
+ - **Memory**: 과거 상호작용에서 컨텍스트 검색 (stateful)
86
+ - **이 플러그인**: Memory 중심 + 선택적 RAG 통합
87
+
88
+ ---
89
+
90
+ ## 4. AXIOMMIND Memory System 참조
91
+
92
+ Gist에서 제공된 AXIOMMIND 시스템의 핵심 개념:
93
+
94
+ ### 4.1 아키텍처 레이어
95
+
96
+ ```
97
+ ┌─────────────────────────────────────────────────────────┐
98
+ │ L0 EventStore (Single Source of Truth) │
99
+ │ - Append-only events table │
100
+ │ - Event deduplication via dedupe_key │
101
+ │ - Projection offset tracking │
102
+ └─────────────────────────────────────────────────────────┘
103
+
104
+ ┌─────────────────────────────────────────────────────────┐
105
+ │ Extraction/Sorting Layer (LLM Processing) │
106
+ │ - LLM extracts structured JSON from raw input │
107
+ │ - Evidence alignment and validation │
108
+ └─────────────────────────────────────────────────────────┘
109
+
110
+ ┌─────────────────────────────────────────────────────────┐
111
+ │ Derived Stores (Rebuildable from Events) │
112
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
113
+ │ │ DuckDB │ │ LanceDB │ │ Relational │ │
114
+ │ │ (FTS/SQL) │ │ (Vectors) │ │ Views │ │
115
+ │ └─────────────┘ └─────────────┘ └─────────────┘ │
116
+ └─────────────────────────────────────────────────────────┘
117
+ ```
118
+
119
+ ### 4.2 핵심 원칙
120
+
121
+ - **Append-only EventStore**: 모든 변경 추적, 파생 저장소에서 언제든 재구성 가능
122
+ - **Canonical Key 정규화**: 동일 개념의 여러 표현을 단일 키로 통합
123
+ - **단일 진실 공급원(SoT)**: events 테이블만 영구 저장, 나머지는 파생
124
+ - **멱등성 보장**: `dedupe_key`로 중복 이벤트 차단
125
+
126
+ ### 4.3 Canonical Key 정규화 (핵심 알고리즘)
127
+
128
+ ```python
129
+ # canonical_key.py - 결정론적 키 생성
130
+ def make_canonical_key(title: str, project: str = None) -> str:
131
+ """
132
+ 동일한 제목은 항상 동일한 키를 생성
133
+
134
+ 정규화 단계:
135
+ 1. NFKC 유니코드 정규화
136
+ 2. 소문자 변환
137
+ 3. 구두점 제거
138
+ 4. 연속 공백 정리
139
+ 5. (선택) 프로젝트/도메인 컨텍스트 추가
140
+ 6. 긴 키는 MD5 체크섬으로 truncate
141
+ """
142
+ import unicodedata
143
+ import re
144
+ import hashlib
145
+
146
+ # Step 1-4: 정규화
147
+ normalized = unicodedata.normalize('NFKC', title)
148
+ normalized = normalized.lower()
149
+ normalized = re.sub(r'[^\w\s]', '', normalized)
150
+ normalized = re.sub(r'\s+', ' ', normalized).strip()
151
+
152
+ # Step 5: 컨텍스트 추가
153
+ if project:
154
+ key = f"{project}::{normalized}"
155
+ else:
156
+ key = normalized
157
+
158
+ # Step 6: 긴 키 처리
159
+ MAX_KEY_LENGTH = 200
160
+ if len(key) > MAX_KEY_LENGTH:
161
+ hash_suffix = hashlib.md5(key.encode()).hexdigest()[:8]
162
+ key = key[:MAX_KEY_LENGTH - 9] + "_" + hash_suffix
163
+
164
+ return key
165
+ ```
166
+
167
+ **Memory Plugin 적용**:
168
+ - 사용자 prompt의 canonical key로 중복 질문 감지
169
+ - 유사한 질문들을 그룹화하여 패턴 추출
170
+
171
+ ### 4.4 Matching Thresholds (엄격한 매칭 기준)
172
+
173
+ ```python
174
+ # task_matcher.py - 매칭 임계값
175
+ MATCH_THRESHOLDS = {
176
+ "min_combined_score": 0.92, # 최소 결합 점수
177
+ "min_gap": 0.03, # 1위와 2위 간 최소 점수 차이
178
+ "suggestion_threshold": 0.75, # 제안 모드 임계값
179
+ }
180
+
181
+ def calculate_weighted_score(result: SearchResult) -> float:
182
+ """
183
+ 가중치 점수 계산 (stage, status, recency)
184
+ """
185
+ weights = {
186
+ "semantic_similarity": 0.4, # 벡터 유사도
187
+ "fts_score": 0.25, # 전문 검색 점수
188
+ "recency_bonus": 0.2, # 최신성 가산점
189
+ "status_weight": 0.15, # 상태별 가중치
190
+ }
191
+
192
+ score = (
193
+ result.vector_score * weights["semantic_similarity"] +
194
+ result.fts_score * weights["fts_score"] +
195
+ result.recency_score * weights["recency_bonus"] +
196
+ result.status_score * weights["status_weight"]
197
+ )
198
+ return score
199
+
200
+ def match_with_confidence(query: str, candidates: list) -> MatchResult:
201
+ """
202
+ 엄격한 매칭: top-1이 확실히 우세할 때만 확정
203
+ """
204
+ if len(candidates) == 0:
205
+ return MatchResult(match=None, confidence="none")
206
+
207
+ top = candidates[0]
208
+
209
+ if top.score < MATCH_THRESHOLDS["suggestion_threshold"]:
210
+ return MatchResult(match=None, confidence="none")
211
+
212
+ if top.score >= MATCH_THRESHOLDS["min_combined_score"]:
213
+ if len(candidates) == 1:
214
+ return MatchResult(match=top, confidence="high")
215
+
216
+ gap = top.score - candidates[1].score
217
+ if gap >= MATCH_THRESHOLDS["min_gap"]:
218
+ return MatchResult(match=top, confidence="high")
219
+
220
+ # 점수가 높지만 확실하지 않음 → 제안 모드
221
+ return MatchResult(match=top, confidence="suggested")
222
+ ```
223
+
224
+ **Memory Plugin 적용**:
225
+ - 관련 기억 검색 시 엄격한 임계값 적용
226
+ - 애매한 매칭은 "suggested" 상태로 표시
227
+
228
+ ### 4.5 Single-Writer Pattern (벡터 동시성 제어)
229
+
230
+ ```python
231
+ # vector_worker.py - Outbox 패턴으로 동시성 제어
232
+
233
+ """
234
+ LanceDB는 동시 쓰기에 취약하므로 Single-Writer 패턴 사용:
235
+ 1. 이벤트 저장 시 embedding_outbox 테이블에 작업 추가
236
+ 2. 별도 워커가 outbox를 순차적으로 처리
237
+ 3. 처리 완료 시 outbox에서 삭제
238
+ """
239
+
240
+ # DuckDB의 outbox 테이블
241
+ CREATE TABLE embedding_outbox (
242
+ id UUID PRIMARY KEY,
243
+ event_id UUID NOT NULL,
244
+ content TEXT NOT NULL,
245
+ status VARCHAR DEFAULT 'pending', -- 'pending' | 'processing' | 'done'
246
+ created_at TIMESTAMP DEFAULT NOW(),
247
+ processed_at TIMESTAMP
248
+ );
249
+
250
+ # Python 워커 (단일 프로세스)
251
+ class VectorWorker:
252
+ def __init__(self, db: DuckDB, lance: LanceDB, embedder: Embedder):
253
+ self.db = db
254
+ self.lance = lance
255
+ self.embedder = embedder
256
+
257
+ async def process_outbox(self, batch_size: int = 32):
258
+ """
259
+ Outbox에서 pending 항목을 가져와 순차 처리
260
+ """
261
+ # 1. Pending 항목 가져오기 (락 획득)
262
+ pending = self.db.execute("""
263
+ UPDATE embedding_outbox
264
+ SET status = 'processing'
265
+ WHERE id IN (
266
+ SELECT id FROM embedding_outbox
267
+ WHERE status = 'pending'
268
+ ORDER BY created_at
269
+ LIMIT ?
270
+ )
271
+ RETURNING *
272
+ """, [batch_size])
273
+
274
+ if not pending:
275
+ return
276
+
277
+ # 2. 배치 임베딩 생성
278
+ contents = [p.content for p in pending]
279
+ vectors = await self.embedder.embed_batch(contents)
280
+
281
+ # 3. LanceDB에 저장 (단일 쓰기)
282
+ records = [
283
+ {"event_id": p.event_id, "content": p.content, "vector": v}
284
+ for p, v in zip(pending, vectors)
285
+ ]
286
+ self.lance.add(records)
287
+
288
+ # 4. Outbox 정리
289
+ ids = [p.id for p in pending]
290
+ self.db.execute("""
291
+ DELETE FROM embedding_outbox WHERE id = ANY(?)
292
+ """, [ids])
293
+ ```
294
+
295
+ **Memory Plugin 적용**:
296
+ - 대화 저장 시 즉시 반환, 임베딩은 비동기 처리
297
+ - 동시성 문제 없이 안정적인 벡터 인덱싱
298
+
299
+ ### 4.6 Blocker/Condition 분류 전략
300
+
301
+ ```python
302
+ # task_resolver.py - 애매한 참조 처리
303
+
304
+ """
305
+ Blocker 분류 전략:
306
+ 1. Artifact: URL, Jira, GitHub 이슈 등 명확한 참조
307
+ 2. Task: 엄격한 매칭만 허용 (score >= 0.92)
308
+ 3. Condition: 애매한 참조 흡수 (나중에 해결 가능)
309
+ """
310
+
311
+ class BlockerType(Enum):
312
+ ARTIFACT = "artifact" # 명확한 외부 참조
313
+ TASK = "task" # 확정된 작업 참조
314
+ CONDITION = "condition" # 애매한 조건/참조
315
+
316
+ def classify_blocker(reference: str, match_result: MatchResult) -> BlockerType:
317
+ # URL, 이슈 번호 등은 Artifact
318
+ if is_artifact_reference(reference):
319
+ return BlockerType.ARTIFACT
320
+
321
+ # 높은 신뢰도 매칭은 Task
322
+ if match_result.confidence == "high":
323
+ return BlockerType.TASK
324
+
325
+ # 나머지는 Condition으로 흡수
326
+ return BlockerType.CONDITION
327
+
328
+ # Condition은 나중에 실제 Task로 해결될 수 있음
329
+ # resolves_to edge로 연결
330
+ ```
331
+
332
+ **Memory Plugin 적용**:
333
+ - 불완전한 컨텍스트도 일단 저장
334
+ - 나중에 추가 정보로 보강 가능
335
+
336
+ ### 4.7 Query Patterns (효과적인 뷰 활용)
337
+
338
+ ```sql
339
+ -- v_task_blockers_effective: Condition 해결을 반영한 최종 blocker 뷰
340
+ CREATE VIEW v_memory_context_effective AS
341
+ SELECT
342
+ m.id,
343
+ m.session_id,
344
+ m.content,
345
+ m.event_type,
346
+ m.timestamp,
347
+ -- Condition이 해결된 경우 실제 참조로 대체
348
+ COALESCE(r.resolved_content, m.content) as effective_content,
349
+ COALESCE(r.resolved_id, m.id) as effective_id
350
+ FROM memories m
351
+ LEFT JOIN memory_resolutions r ON m.id = r.condition_id
352
+ WHERE r.resolution_type IS NULL OR r.resolution_type = 'confirmed';
353
+
354
+ -- 4가지 주요 쿼리 패턴
355
+ -- 1. 확정된 관련 기억
356
+ SELECT * FROM v_memory_context_effective
357
+ WHERE semantic_score >= 0.92;
358
+
359
+ -- 2. 제안 상태의 기억 (확인 대기)
360
+ SELECT * FROM memories
361
+ WHERE match_confidence = 'suggested';
362
+
363
+ -- 3. 자동 플레이스홀더 감지
364
+ SELECT * FROM memories
365
+ WHERE auto_placeholder = true;
366
+
367
+ -- 4. 해결된 조건 매핑
368
+ SELECT condition_id, resolved_to_id
369
+ FROM memory_resolutions
370
+ WHERE resolution_type = 'confirmed';
371
+ ```
372
+
373
+ ### 4.8 Placeholder 자동 생성
374
+
375
+ ```python
376
+ # 정보가 불완전할 때 플레이스홀더 생성
377
+ def create_placeholder_if_needed(event: MemoryEvent) -> Optional[Placeholder]:
378
+ """
379
+ 컨텍스트가 불완전하면 자동 플레이스홀더 생성
380
+ - auto_placeholder=true 플래그 설정
381
+ - 나중에 추가 정보로 해결 가능
382
+ """
383
+ if is_incomplete_context(event):
384
+ return Placeholder(
385
+ id=generate_uuid(),
386
+ event_id=event.id,
387
+ placeholder_type="unknown_context",
388
+ auto_placeholder=True,
389
+ created_at=datetime.now()
390
+ )
391
+ return None
392
+ ```
393
+
394
+ ### 4.9 주요 모듈 요약
395
+
396
+ | 모듈 | 역할 | Memory Plugin 대응 |
397
+ |------|------|-------------------|
398
+ | `canonical_key.py` | 결정론적 키 정규화 | `normalizer.ts` |
399
+ | `event_store.py` | append-only 이벤트 저장 | `event-store.ts` |
400
+ | `task_matcher.py` | 가중치 기반 매칭 | `matcher.ts` |
401
+ | `task_resolver.py` | 상태 전이 검증 | `resolver.ts` |
402
+ | `projector_task.py` | 이벤트→엔티티 투영 | `projector.ts` |
403
+ | `vector_worker.py` | 단일 쓰기 임베딩 | `vector-worker.ts` |
404
+
405
+ ### 4.10 Memory Graduation Pipeline (L0 → L4)
406
+
407
+ AXIOMMIND의 핵심 개념인 **다단계 메모리 승격 파이프라인**:
408
+
409
+ ```
410
+ ┌─────────────────────────────────────────────────────────────────┐
411
+ │ Memory Graduation Pipeline │
412
+ ├─────────────────────────────────────────────────────────────────┤
413
+ │ │
414
+ │ L0: EventStore (Raw) │
415
+ │ ├── 원본 채팅 로그, 프롬프트/응답 │
416
+ │ ├── Append-only, 불변 │
417
+ │ └── dedupe_key로 멱등성 보장 │
418
+ │ ↓ │
419
+ │ L1: Structured JSON │
420
+ │ ├── LLM이 추출한 구조화된 데이터 │
421
+ │ ├── 엔티티, 관계, 인사이트 │
422
+ │ └── EvidenceAligner로 증거 스팬 정렬 │
423
+ │ ↓ │
424
+ │ L2: Idris Candidates (검증 대상) │
425
+ │ ├── 타입 안전한 표현으로 변환 │
426
+ │ ├── 의존적 타입으로 불변식 검증 │
427
+ │ └── idris_generator.py가 생성 │
428
+ │ ↓ │
429
+ │ L3: Verified Knowledge │
430
+ │ ├── Idris 타입체커 통과 │
431
+ │ ├── 모순 없음 확인 │
432
+ │ └── 신뢰도 높은 지식 │
433
+ │ ↓ │
434
+ │ L4: Active Memory (검색 가능) │
435
+ │ ├── 벡터 인덱싱 완료 │
436
+ │ ├── 실시간 검색 가능 │
437
+ │ └── 컨텍스트 주입에 사용 │
438
+ │ │
439
+ └─────────────────────────────────────────────────────────────────┘
440
+ ```
441
+
442
+ **Memory Plugin 적용**:
443
+ - L0: 모든 대화를 `events` 테이블에 저장
444
+ - L1: 주기적으로 인사이트 추출 (LLM 기반)
445
+ - L2: TypeScript 강타입으로 검증 (Idris2 개념 적용)
446
+ - L3: 테스트 통과한 검증된 지식
447
+ - L4: LanceDB에 인덱싱되어 검색 가능한 상태
448
+
449
+ ### 4.11 AXIOMMIND 7가지 필수 원칙
450
+
451
+ | # | 원칙 | 설명 | Memory Plugin 적용 |
452
+ |---|------|------|-------------------|
453
+ | 1 | **진실의 원천(SoT)은 이벤트 로그** | 파생 테이블은 언제든 재구성 가능 | `events` 테이블만 영구 저장 |
454
+ | 2 | **추가전용 구조** | events에 UPDATE/DELETE 금지 | `append()` 메서드만 제공 |
455
+ | 3 | **멱등성 보장** | `dedupe_key`로 중복 제어 | content_hash + session_id |
456
+ | 4 | **증거 범위는 파이프라인이 확정** | LLM은 인용문만, aligner가 스팬 계산 | `EvidenceAligner` 모듈 |
457
+ | 5 | **Task는 엔티티** | 세션마다 새 항목 아닌 기존 업데이트 | `canonical_key`로 동일성 판단 |
458
+ | 6 | **벡터 저장소 정합성** | DuckDB → outbox → LanceDB 단방향 | Single-Writer Pattern |
459
+ | 7 | **DuckDB JSON 사용** | JSONB 제거, 표준 JSON만 | `metadata JSON` 컬럼 |
460
+
461
+ ```typescript
462
+ // 원칙 적용 예시: EventStore 인터페이스
463
+ interface EventStoreInterface {
464
+ // 원칙 2: 추가전용 - append만 허용
465
+ append(event: MemoryEvent): Promise<AppendResult>;
466
+
467
+ // 조회는 자유롭게
468
+ getBySession(sessionId: string): Promise<MemoryEvent[]>;
469
+ getRecent(limit: number): Promise<MemoryEvent[]>;
470
+
471
+ // 원칙 2 위반: UPDATE/DELETE 메서드 없음
472
+ // update(): ❌ 금지
473
+ // delete(): ❌ 금지
474
+ }
475
+ ```
476
+
477
+ ### 4.12 Evidence Aligner (증거 정렬기)
478
+
479
+ ```python
480
+ # evidence_aligner.py - LLM 인용문을 정확한 스팬으로 변환
481
+
482
+ class EvidenceAligner:
483
+ """
484
+ 원칙 4: LLM은 인용문만 제공, aligner가 정확한 스팬 계산
485
+
486
+ LLM이 추출한 대략적인 인용문을 원본 텍스트에서
487
+ 정확한 (start, end) 위치로 변환
488
+ """
489
+
490
+ def align(
491
+ self,
492
+ source_text: str,
493
+ llm_quote: str,
494
+ fuzzy_threshold: float = 0.85
495
+ ) -> Optional[EvidenceSpan]:
496
+ """
497
+ 1. 정확한 매칭 시도
498
+ 2. 실패 시 fuzzy matching (Levenshtein)
499
+ 3. 임계값 미달 시 None 반환
500
+ """
501
+ # 정확한 매칭
502
+ exact_pos = source_text.find(llm_quote)
503
+ if exact_pos >= 0:
504
+ return EvidenceSpan(
505
+ start=exact_pos,
506
+ end=exact_pos + len(llm_quote),
507
+ confidence=1.0,
508
+ match_type="exact"
509
+ )
510
+
511
+ # Fuzzy 매칭
512
+ best_match = self._fuzzy_search(source_text, llm_quote)
513
+ if best_match and best_match.score >= fuzzy_threshold:
514
+ return EvidenceSpan(
515
+ start=best_match.start,
516
+ end=best_match.end,
517
+ confidence=best_match.score,
518
+ match_type="fuzzy"
519
+ )
520
+
521
+ return None
522
+
523
+ def _fuzzy_search(self, text: str, query: str) -> Optional[FuzzyMatch]:
524
+ # 슬라이딩 윈도우 + Levenshtein 거리
525
+ ...
526
+ ```
527
+
528
+ **Memory Plugin 적용**:
529
+ - 사용자가 "이전에 rate limiting 얘기했잖아"라고 하면
530
+ - LLM이 대략적인 인용문 추출
531
+ - EvidenceAligner가 정확한 원본 위치 찾기
532
+ - 해당 컨텍스트를 정확히 주입
533
+
534
+ ### 5.1 Vector Database: LanceDB
535
+
536
+ 선택 이유:
537
+ - **Embedded 모드**: SQLite처럼 서버 없이 로컬 실행
538
+ - **Apache Arrow 기반**: 빠른 디스크 접근
539
+ - **다중 모달 지원**: 텍스트, 이미지, 오디오 임베딩
540
+ - **DuckDB 호환**: SQL 쿼리 가능
541
+
542
+ ```python
543
+ import lancedb
544
+
545
+ db = lancedb.connect("~/.claude-memory")
546
+ table = db.create_table("conversations", data)
547
+ results = table.search(query_embedding).limit(10).to_list()
548
+ ```
549
+
550
+ ### 5.2 관계형 저장소: DuckDB
551
+
552
+ 선택 이유:
553
+ - **임베디드**: 파일 기반, 서버 불필요
554
+ - **분석 최적화**: OLAP 워크로드에 적합
555
+ - **SQL 지원**: 친숙한 쿼리 언어
556
+ - **Lance 포맷 호환**: LanceDB와 통합
557
+
558
+ ### 5.3 Embedding Model
559
+
560
+ 옵션:
561
+ 1. **OpenAI text-embedding-3-small**: 고품질, API 비용
562
+ 2. **sentence-transformers**: 로컬 실행, 무료
563
+ 3. **Ollama embeddings**: 로컬 LLM 활용
564
+
565
+ 권장: sentence-transformers (로컬 우선) + OpenAI fallback
566
+
567
+ ---
568
+
569
+ ## 6. Idris2 활용 고려사항
570
+
571
+ ### 6.1 Idris2 개요
572
+
573
+ - **의존적 타입 시스템**: 타입 수준에서 프로그램 검증
574
+ - **Type-Driven Development**: 타입이 프로그램 설계를 가이드
575
+ - **Quantitative Type Theory (QTT)**: 선형 타입 지원
576
+
577
+ ### 6.2 적용 가능 영역
578
+
579
+ 1. **타입 안전한 이벤트 스키마**
580
+ ```idris
581
+ data MemoryEvent : Type where
582
+ UserPrompt : (sessionId : String) -> (content : String) -> MemoryEvent
583
+ AgentResponse : (sessionId : String) -> (content : String) -> MemoryEvent
584
+ ```
585
+
586
+ 2. **불변성 보장**
587
+ - Append-only EventStore의 불변성을 타입 수준에서 강제
588
+
589
+ 3. **정확성 증명**
590
+ - 중복 제거 로직의 정확성 검증
591
+ - 검색 알고리즘의 속성 증명
592
+
593
+ ### 6.3 실용적 접근
594
+
595
+ Idris2를 직접 사용하기보다 **개념적 영감**으로 활용:
596
+ - TypeScript의 강타입 시스템 적극 활용
597
+ - Zod/io-ts로 런타임 타입 검증
598
+ - 불변 데이터 구조 (Immutable.js 또는 순수 함수형 패턴)
599
+
600
+ ---
601
+
602
+ ## 7. 참조 링크
603
+
604
+ ### Claude Code Plugin 개발
605
+ - [Create plugins - Claude Code Docs](https://code.claude.com/docs/en/plugins)
606
+ - [Claude Code Plugins README](https://github.com/anthropics/claude-code/blob/main/plugins/README.md)
607
+ - [Hook Development SKILL](https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/hook-development/SKILL.md)
608
+ - [Claude Code Plugins Complete Guide](https://jangwook.net/en/blog/en/claude-code-plugins-complete-guide/)
609
+
610
+ ### AI Memory Systems
611
+ - [Mem0: Building Production-Ready AI Agents](https://arxiv.org/pdf/2504.19413)
612
+ - [AWS AgentCore Long-term Memory](https://aws.amazon.com/blogs/machine-learning/building-smarter-ai-agents-agentcore-long-term-memory-deep-dive/)
613
+ - [Google Vertex AI Memory Bank](https://docs.cloud.google.com/agent-builder/agent-engine/memory-bank/overview)
614
+ - [LangChain Conversational Memory](https://www.pinecone.io/learn/series/langchain/langchain-conversational-memory/)
615
+
616
+ ### Vector Databases
617
+ - [LanceDB](https://lancedb.com/)
618
+ - [Lance Format on GitHub](https://github.com/lance-format/lance)
619
+
620
+ ### Idris2
621
+ - [Idris2 Official Site](https://www.idris-lang.org/)
622
+ - [Idris 2: Quantitative Type Theory in Practice](https://arxiv.org/abs/2104.00480)
623
+ - [Idris2 GitHub](https://github.com/idris-lang/Idris2)
624
+
625
+ ---
626
+
627
+ ## 8. 용어 정의
628
+
629
+ | 용어 | 정의 |
630
+ |------|------|
631
+ | **Memory** | 과거 대화에서 추출/저장된 정보 |
632
+ | **Embedding** | 텍스트를 벡터로 변환한 표현 |
633
+ | **Semantic Search** | 의미 기반 유사도 검색 |
634
+ | **EventStore** | 모든 이벤트를 시간순으로 저장하는 append-only 저장소 |
635
+ | **Hook** | 특정 이벤트 발생 시 실행되는 스크립트 |
636
+ | **MCP** | Model Context Protocol - Claude와 외부 도구 연결 |
@@ -0,0 +1,42 @@
1
+ # /memory-forget
2
+
3
+ Remove specific memories from storage.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ /memory-forget <event-id>
9
+ /memory-forget --session <session-id>
10
+ /memory-forget --before <date>
11
+ ```
12
+
13
+ ## Arguments
14
+
15
+ - `event-id`: Specific event ID to forget
16
+ - `--session <id>`: Forget all events from a session
17
+ - `--before <date>`: Forget events before a date (YYYY-MM-DD)
18
+ - `--confirm`: Skip confirmation prompt
19
+
20
+ ## Examples
21
+
22
+ ```
23
+ /memory-forget abc123-def456
24
+ /memory-forget --session session_xyz --confirm
25
+ /memory-forget --before 2024-01-01
26
+ ```
27
+
28
+ ## Description
29
+
30
+ Removes memories from storage. This operation:
31
+
32
+ 1. Marks events as deleted in EventStore (soft delete)
33
+ 2. Removes corresponding vectors from LanceDB
34
+ 3. Updates memory level statistics
35
+
36
+ ⚠️ **Note**: Due to the append-only architecture, deleted events are marked but not physically removed from the event log. Vector embeddings are physically deleted.
37
+
38
+ ## Implementation
39
+
40
+ ```bash
41
+ node dist/cli/index.js forget $ARGUMENTS
42
+ ```