claude-memory-layer 1.0.11 → 1.0.13
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.
- package/AGENTS.md +60 -0
- package/README.md +166 -2
- package/bootstrap-kb/decisions/decisions.md +244 -0
- package/bootstrap-kb/glossary/glossary.md +46 -0
- package/bootstrap-kb/modules/.claude-plugin.md +22 -0
- package/bootstrap-kb/modules/agents.md.md +15 -0
- package/bootstrap-kb/modules/claude.md.md +15 -0
- package/bootstrap-kb/modules/context.md.md +15 -0
- package/bootstrap-kb/modules/docs.md +18 -0
- package/bootstrap-kb/modules/handoff.md.md +15 -0
- package/bootstrap-kb/modules/package-lock.json.md +15 -0
- package/bootstrap-kb/modules/package.json.md +15 -0
- package/bootstrap-kb/modules/plan.md.md +15 -0
- package/bootstrap-kb/modules/readme.md.md +15 -0
- package/bootstrap-kb/modules/scripts.md +26 -0
- package/bootstrap-kb/modules/spec.md.md +15 -0
- package/bootstrap-kb/modules/specs.md +20 -0
- package/bootstrap-kb/modules/src.md +51 -0
- package/bootstrap-kb/modules/tests.md +42 -0
- package/bootstrap-kb/modules/tsconfig.json.md +15 -0
- package/bootstrap-kb/modules/vitest.config.ts.md +15 -0
- package/bootstrap-kb/overview/overview.md +40 -0
- package/bootstrap-kb/sources/manifest.json +950 -0
- package/bootstrap-kb/sources/manifest.md +227 -0
- package/bootstrap-kb/timeline/timeline.md +57 -0
- package/d.sh +3 -0
- package/deploy.sh +3 -0
- package/dist/cli/index.js +2389 -286
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +1017 -132
- package/dist/core/index.js.map +4 -4
- package/dist/hooks/post-tool-use.js +1347 -202
- package/dist/hooks/post-tool-use.js.map +4 -4
- package/dist/hooks/session-end.js +1339 -194
- package/dist/hooks/session-end.js.map +4 -4
- package/dist/hooks/session-start.js +1343 -198
- package/dist/hooks/session-start.js.map +4 -4
- package/dist/hooks/stop.js +1351 -206
- package/dist/hooks/stop.js.map +4 -4
- package/dist/hooks/user-prompt-submit.js +1347 -202
- package/dist/hooks/user-prompt-submit.js.map +4 -4
- package/dist/server/api/index.js +1436 -211
- package/dist/server/api/index.js.map +4 -4
- package/dist/server/index.js +1445 -220
- package/dist/server/index.js.map +4 -4
- package/dist/services/memory-service.js +1345 -199
- package/dist/services/memory-service.js.map +4 -4
- package/dist/ui/app.js +69 -2
- package/dist/ui/index.html +8 -0
- package/docs/MCP_MEMORY_SERVICE_COMPARATIVE_REVIEW.md +271 -0
- package/docs/MEMU_ADOPTION.md +40 -0
- package/memory/.claude-plugin/commands/2026-02-25.md +263 -0
- package/memory/_index.md +405 -0
- package/memory/default/uncategorized/2026-02-25.md +4839 -0
- package/memory/specs/20260207-dashboard-upgrade/2026-02-25.md +142 -0
- package/memory/specs/citations-system/2026-02-25.md +1121 -0
- package/memory/specs/endless-mode/2026-02-25.md +1392 -0
- package/memory/specs/entity-edge-model/2026-02-25.md +1263 -0
- package/memory/specs/evidence-aligner-v2/2026-02-25.md +1028 -0
- package/memory/specs/mcp-desktop-integration/2026-02-25.md +1334 -0
- package/memory/specs/post-tool-use-hook/2026-02-25.md +1164 -0
- package/memory/specs/private-tags/2026-02-25.md +1057 -0
- package/memory/specs/progressive-disclosure/2026-02-25.md +1436 -0
- package/memory/specs/task-entity-system/2026-02-25.md +924 -0
- package/memory/specs/vector-outbox-v2/2026-02-25.md +1510 -0
- package/memory/specs/web-viewer-ui/2026-02-25.md +1709 -0
- package/package.json +2 -1
- package/scripts/build.ts +6 -0
- package/scripts/bump-patch-version.sh +18 -0
- package/src/cli/index.ts +281 -2
- package/src/core/consolidated-store.ts +63 -1
- package/src/core/consolidation-worker.ts +115 -6
- package/src/core/event-store.ts +14 -0
- package/src/core/index.ts +1 -0
- package/src/core/ingest-interceptor.ts +80 -0
- package/src/core/markdown-mirror.ts +70 -0
- package/src/core/md-mirror.ts +92 -0
- package/src/core/mongo-sync-config.ts +165 -0
- package/src/core/mongo-sync-worker.ts +381 -0
- package/src/core/retriever.ts +540 -150
- package/src/core/sqlite-event-store.ts +350 -1
- package/src/core/tag-taxonomy.ts +51 -0
- package/src/core/types.ts +28 -0
- package/src/server/api/health.ts +53 -0
- package/src/server/api/index.ts +3 -1
- package/src/server/api/stats.ts +46 -1
- package/src/services/bootstrap-organizer.ts +443 -0
- package/src/services/codex-session-history-importer.ts +474 -0
- package/src/services/memory-service.ts +373 -68
- package/src/services/session-history-importer.ts +53 -25
- package/src/ui/app.js +69 -2
- package/src/ui/index.html +8 -0
- package/tests/bootstrap-organizer.test.ts +111 -0
- package/tests/consolidation-worker.test.ts +75 -0
- package/tests/ingest-interceptor.test.ts +38 -0
- package/tests/markdown-mirror.test.ts +85 -0
- package/tests/md-mirror.test.ts +50 -0
- package/tests/retriever-fallback-chain.test.ts +223 -0
- package/tests/retriever-strategy-scope.test.ts +97 -0
- package/tests/retriever.memu-adoption.test.ts +122 -0
- package/tests/sqlite-event-store-replication.test.ts +92 -0
package/dist/ui/app.js
CHANGED
|
@@ -11,6 +11,7 @@ const state = {
|
|
|
11
11
|
sharedStats: null,
|
|
12
12
|
mostAccessed: null,
|
|
13
13
|
helpfulness: null,
|
|
14
|
+
retrievalTraces: null,
|
|
14
15
|
currentLevel: 'L0',
|
|
15
16
|
currentSort: 'recent',
|
|
16
17
|
currentView: 'overview',
|
|
@@ -235,17 +236,19 @@ async function refreshData() {
|
|
|
235
236
|
if(btn) btn.classList.add('loading');
|
|
236
237
|
|
|
237
238
|
try {
|
|
238
|
-
const [stats, shared, mostAccessed, helpfulness] = await Promise.all([
|
|
239
|
+
const [stats, shared, mostAccessed, helpfulness, retrievalTraces] = await Promise.all([
|
|
239
240
|
fetch(apiUrl(`${API_BASE}/stats`)).then(r => r.json()).catch(() => null),
|
|
240
241
|
fetch(apiUrl(`${API_BASE}/stats/shared`)).then(r => r.json()).catch(() => null),
|
|
241
242
|
fetch(apiUrl(`${API_BASE}/stats/most-accessed`, { limit: 10 })).then(r => r.json()).catch(() => null),
|
|
242
|
-
fetch(apiUrl(`${API_BASE}/stats/helpfulness`, { limit: 5 })).then(r => r.json()).catch(() => null)
|
|
243
|
+
fetch(apiUrl(`${API_BASE}/stats/helpfulness`, { limit: 5 })).then(r => r.json()).catch(() => null),
|
|
244
|
+
fetch(apiUrl(`${API_BASE}/stats/retrieval-traces`, { limit: 20 })).then(r => r.json()).catch(() => null)
|
|
243
245
|
]);
|
|
244
246
|
|
|
245
247
|
state.stats = stats;
|
|
246
248
|
state.sharedStats = shared;
|
|
247
249
|
state.mostAccessed = mostAccessed;
|
|
248
250
|
state.helpfulness = helpfulness;
|
|
251
|
+
state.retrievalTraces = retrievalTraces;
|
|
249
252
|
|
|
250
253
|
updateStatsUI();
|
|
251
254
|
updateSharedUI();
|
|
@@ -397,6 +400,7 @@ function updateMemoryUsageUI() {
|
|
|
397
400
|
updateGraduationBars();
|
|
398
401
|
updateHelpfulnessUI();
|
|
399
402
|
updateMostHelpfulList();
|
|
403
|
+
updateRetrievalTraceUI();
|
|
400
404
|
}
|
|
401
405
|
|
|
402
406
|
function updateGraduationBars() {
|
|
@@ -483,6 +487,69 @@ function updateMostHelpfulList() {
|
|
|
483
487
|
}).join('');
|
|
484
488
|
}
|
|
485
489
|
|
|
490
|
+
|
|
491
|
+
function updateRetrievalTraceUI() {
|
|
492
|
+
const summaryEl = document.getElementById('retrieval-trace-summary');
|
|
493
|
+
const listEl = document.getElementById('retrieval-trace-list');
|
|
494
|
+
if (!summaryEl || !listEl) return;
|
|
495
|
+
|
|
496
|
+
const payload = state.retrievalTraces;
|
|
497
|
+
const stats = payload?.stats;
|
|
498
|
+
const traces = payload?.traces || [];
|
|
499
|
+
|
|
500
|
+
if (!stats || !Number.isFinite(stats.totalQueries) || stats.totalQueries === 0) {
|
|
501
|
+
summaryEl.innerHTML = '<span style="color:var(--text-muted);">No retrieval traces yet.</span>';
|
|
502
|
+
listEl.innerHTML = '<div style="padding:12px; text-align:center; color:var(--text-muted); font-size:13px;">No query/context trace data</div>';
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const selectionRate = ((stats.selectionRate || 0) * 100).toFixed(1);
|
|
507
|
+
summaryEl.innerHTML = `
|
|
508
|
+
<div style="display:flex; gap:14px; flex-wrap:wrap; font-size:12px;">
|
|
509
|
+
<span><strong>${formatNumber(stats.totalQueries)}</strong> queries</span>
|
|
510
|
+
<span><strong>${Number(stats.avgCandidateCount || 0).toFixed(1)}</strong> avg candidates</span>
|
|
511
|
+
<span><strong>${Number(stats.avgSelectedCount || 0).toFixed(1)}</strong> avg selected</span>
|
|
512
|
+
<span><strong>${selectionRate}%</strong> selection rate</span>
|
|
513
|
+
</div>
|
|
514
|
+
`;
|
|
515
|
+
|
|
516
|
+
listEl.innerHTML = traces.slice(0, 8).map((t) => {
|
|
517
|
+
const ts = t.createdAt ? new Date(t.createdAt).toLocaleString() : '-';
|
|
518
|
+
const confidence = t.confidence || 'n/a';
|
|
519
|
+
const selected = Number(t.selectedCount || 0);
|
|
520
|
+
const candidates = Number(t.candidateCount || 0);
|
|
521
|
+
const selectedDetails = (t.selectedDetails || []).slice(0, 2);
|
|
522
|
+
const candidateDetails = (t.candidateDetails || []).slice(0, 3);
|
|
523
|
+
const selectedIdsHtml = selectedDetails.length > 0
|
|
524
|
+
? selectedDetails.map((d) => {
|
|
525
|
+
const breakdown = `score=${Number(d.score || 0).toFixed(3)} · s=${Number(d.semanticScore || 0).toFixed(3)} · l=${Number(d.lexicalScore || 0).toFixed(3)} · r=${Number(d.recencyScore || 0).toFixed(3)}`;
|
|
526
|
+
return `<span class="event-type-badge" style="cursor:pointer;" onclick="openDetailModal('${d.eventId}')" title="${escapeHtml(breakdown)}">${escapeHtml((d.eventId || '').slice(0, 8))}...</span>`;
|
|
527
|
+
}).join(' ')
|
|
528
|
+
: ((t.selectedEventIds || []).slice(0, 2).map((id) => `<span class="event-type-badge" style="cursor:pointer;" onclick="openDetailModal('${id}')">${escapeHtml((id || '').slice(0, 8))}...</span>`).join(' ') || '-');
|
|
529
|
+
|
|
530
|
+
const scoreBreakdownHtml = selectedDetails.length > 0
|
|
531
|
+
? selectedDetails.map((d) => `<div style="font-size:10px; color:var(--text-muted);">${escapeHtml((d.eventId || '').slice(0, 8))}... → score ${Number(d.score || 0).toFixed(3)} (s ${Number(d.semanticScore || 0).toFixed(3)}, l ${Number(d.lexicalScore || 0).toFixed(3)}, r ${Number(d.recencyScore || 0).toFixed(3)})</div>`).join('')
|
|
532
|
+
: '';
|
|
533
|
+
|
|
534
|
+
return `
|
|
535
|
+
<div class="shared-item" style="align-items:flex-start;">
|
|
536
|
+
<div class="shared-info" style="align-items:flex-start; flex-direction:column; gap:4px;">
|
|
537
|
+
<span style="font-size:12px; color:var(--text-secondary);"><strong>Q:</strong> ${escapeHtml((t.queryText || '').slice(0, 120))}</span>
|
|
538
|
+
<span style="font-size:11px; color:var(--text-muted);">${ts} · strategy=${escapeHtml(t.strategy || 'auto')} · conf=${escapeHtml(confidence)}</span>
|
|
539
|
+
<span style="font-size:11px; color:var(--text-muted);">selected IDs: ${selectedIdsHtml}</span>
|
|
540
|
+
<span style="font-size:11px; color:var(--text-muted);">candidates: ${candidateDetails.map((d) => `<span class=\"event-type-badge\" style=\"cursor:pointer;\" onclick=\"openDetailModal('${d.eventId}')\">${escapeHtml((d.eventId || '').slice(0, 8))}...</span>`).join(' ') || '-'}</span>
|
|
541
|
+
${scoreBreakdownHtml}
|
|
542
|
+
</div>
|
|
543
|
+
<div style="display:flex; flex-direction:column; align-items:flex-end; gap:2px; min-width:68px;">
|
|
544
|
+
<span style="font-size:13px; font-weight:600; color:var(--accent-primary);">${selected}/${candidates}</span>
|
|
545
|
+
<span style="font-size:10px; color:var(--text-muted);">sel/cand</span>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
`;
|
|
549
|
+
}).join('');
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
|
|
486
553
|
// --- Charts ---
|
|
487
554
|
|
|
488
555
|
async function initActivityChart() {
|
package/dist/ui/index.html
CHANGED
|
@@ -271,6 +271,14 @@
|
|
|
271
271
|
<div style="padding:12px; text-align:center; color:var(--text-muted); font-size:13px;">Loading...</div>
|
|
272
272
|
</div>
|
|
273
273
|
</div>
|
|
274
|
+
|
|
275
|
+
<div style="margin-top:20px;">
|
|
276
|
+
<div class="section-label">Retrieval Trace (1:1)</div>
|
|
277
|
+
<div id="retrieval-trace-summary" style="padding:8px 0; font-size:13px; color:var(--text-muted);">Loading...</div>
|
|
278
|
+
<div id="retrieval-trace-list" class="shared-list">
|
|
279
|
+
<div style="padding:12px; text-align:center; color:var(--text-muted); font-size:13px;">Loading...</div>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
274
282
|
</div>
|
|
275
283
|
|
|
276
284
|
</div>
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# mcp-memory-service 코드 리뷰 기반 개선 제안서
|
|
2
|
+
|
|
3
|
+
작성일: 2026-02-26
|
|
4
|
+
대상:
|
|
5
|
+
- 참고 레포: `~/workspace/mcp-memory-service` (commit `8d7e582`)
|
|
6
|
+
- 개선 대상: `~/workspace/claude-memory-layer`
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0) 결론 요약
|
|
11
|
+
|
|
12
|
+
`claude-memory-layer`는 이미 구조가 매우 좋고(프로젝트 해시 격리, scoped retrieval, outbox, endless mode, shared store 실험), **핵심 기능은 충분히 경쟁력 있음**.
|
|
13
|
+
|
|
14
|
+
다만 `mcp-memory-service`를 기준으로 봤을 때 실제 운영 관점에서 보강하면 체감이 큰 포인트는 아래 5가지:
|
|
15
|
+
|
|
16
|
+
1. **멀티-repo 스코프 강제 정책**(기본 격리 + 명시적 cross-repo)
|
|
17
|
+
2. **태그 taxonomy 표준화**(`proj:`, `agent:`, `topic:`, `q:` 등) + 자동 주입
|
|
18
|
+
3. **HTTP/SSE API 레이어**(운영/관측/통합성 증가)
|
|
19
|
+
4. **하이브리드 검색(BM25+Vector) 공식화** 및 점수 퓨전 표준화
|
|
20
|
+
5. **운영 안정성 레이어**(헬스체크, 백업/복구, 보존정책, 인증)
|
|
21
|
+
|
|
22
|
+
즉, 지금은 “강한 코어 엔진” 단계고, 다음 단계는 “**운영형 메모리 플랫폼**”으로 가는 게 맞음.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 1) 조사 방식
|
|
27
|
+
|
|
28
|
+
### 확인한 핵심 파일(참고 레포)
|
|
29
|
+
- `README.md`
|
|
30
|
+
- `docs/architecture.md`
|
|
31
|
+
- `docs/agents/README.md`
|
|
32
|
+
- `docs/mastery/configuration-guide.md`
|
|
33
|
+
- `src/mcp_memory_service/models/tag_taxonomy.py`
|
|
34
|
+
- `src/mcp_memory_service/web/api/memories.py`
|
|
35
|
+
- `src/mcp_memory_service/web/api/search.py`
|
|
36
|
+
|
|
37
|
+
### 확인한 핵심 파일(현재 레포)
|
|
38
|
+
- `README.md`
|
|
39
|
+
- `package.json`
|
|
40
|
+
- `src/services/memory-service.ts`
|
|
41
|
+
- `src/core/retriever.ts`
|
|
42
|
+
- `src/core/event-store.ts`
|
|
43
|
+
- `docs/OPERATIONS.md`
|
|
44
|
+
- `docs/MEMU_ADOPTION.md`
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 2) 현재 `claude-memory-layer` 강점 (유지해야 할 것)
|
|
49
|
+
|
|
50
|
+
1. **프로젝트 격리 설계가 이미 있음**
|
|
51
|
+
- `hashProjectPath()` + `~/.claude-code/memory/projects/{hash}`
|
|
52
|
+
- 세션 레지스트리로 session→project 매핑
|
|
53
|
+
|
|
54
|
+
2. **검색 전략 설계가 좋음**
|
|
55
|
+
- `fast/deep/auto`, fallback chain, scope filter, rerank, graph-hop
|
|
56
|
+
- 실전성 높은 토큰/정확도 트레이드오프
|
|
57
|
+
|
|
58
|
+
3. **쓰기 파이프라인 안정성 의식이 강함**
|
|
59
|
+
- SQLite primary, outbox, background worker
|
|
60
|
+
- hook 경량 모드(lightweightMode)
|
|
61
|
+
|
|
62
|
+
4. **고급 메모리 기능이 이미 구현/실험됨**
|
|
63
|
+
- graduation, endless mode, shared store, markdown mirror
|
|
64
|
+
|
|
65
|
+
=> 요약: 엔진 레벨은 이미 상당히 앞서 있음.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 3) `mcp-memory-service` 대비 갭 분석
|
|
70
|
+
|
|
71
|
+
### A. 멀티-repo 운영 규칙의 “정책 강제력”
|
|
72
|
+
|
|
73
|
+
- 현 상태: 프로젝트 해시 분리는 있으나, 교차 검색/주입 정책이 코드/문서에서 강하게 표준화되어 있지는 않음
|
|
74
|
+
- 참고 레포 포인트:
|
|
75
|
+
- `agent:` 태그 자동 주입(`X-Agent-ID`)
|
|
76
|
+
- 태그 namespace 체계 명시(`proj:`, `topic:`, `q:` ...)
|
|
77
|
+
|
|
78
|
+
**리스크**
|
|
79
|
+
- 여러 repo를 운용할수록 검색 누수(다른 repo 기억 주입) 가능성 증가
|
|
80
|
+
|
|
81
|
+
**개선안**
|
|
82
|
+
- 기본 policy: `same-project-only`
|
|
83
|
+
- cross-project는 explicit flag + 이유(required reason) 필요
|
|
84
|
+
- retrieval 요청 시 project_id 부재면 hard-fail(옵션)
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### B. 태그 체계 표준화 부족
|
|
89
|
+
|
|
90
|
+
- 현 상태: metadata/scope가 강하지만 태그 네임스페이스 규약은 상대적으로 약함
|
|
91
|
+
- 참고 레포 포인트:
|
|
92
|
+
- `TagTaxonomy`를 별도 모델로 정의하고 namespace 유효성 관리
|
|
93
|
+
|
|
94
|
+
**개선안**
|
|
95
|
+
- `src/core/tag-taxonomy.ts` 신설
|
|
96
|
+
- 표준 namespace:
|
|
97
|
+
- `proj:` repository identifier
|
|
98
|
+
- `agent:` 실행 주체
|
|
99
|
+
- `topic:` 주제
|
|
100
|
+
- `q:` 품질/신뢰 등급
|
|
101
|
+
- `t:` 시간/스프린트
|
|
102
|
+
- `sys:` 시스템 자동 태그
|
|
103
|
+
- ingest 시 최소 `proj:<hash>` 자동 부착
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### C. HTTP/SSE 운용 계층 부재(또는 약함)
|
|
108
|
+
|
|
109
|
+
- 현 상태: CLI/hooks 중심 구조가 강점이지만, 외부 오케스트레이터/다중 클라이언트 연동은 제한적
|
|
110
|
+
- 참고 레포 포인트:
|
|
111
|
+
- REST API + SSE + dashboard 연동
|
|
112
|
+
|
|
113
|
+
**개선안**
|
|
114
|
+
- 최소 API부터 시작:
|
|
115
|
+
- `POST /api/memories`
|
|
116
|
+
- `POST /api/memories/search`
|
|
117
|
+
- `GET /api/memories?project=...`
|
|
118
|
+
- `GET /api/health`
|
|
119
|
+
- SSE 이벤트:
|
|
120
|
+
- memory_stored
|
|
121
|
+
- memory_deleted
|
|
122
|
+
- search_completed
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### D. Hybrid search 점수 체계 공식화 필요
|
|
127
|
+
|
|
128
|
+
- 현 상태: fast/deep + rerank는 이미 훌륭함
|
|
129
|
+
- 부족한 점: “BM25 + Vector + Recency + Quality”를 운영상 조정 가능한 공식으로 고정 문서화한 수준은 약함
|
|
130
|
+
- 참고 레포 포인트:
|
|
131
|
+
- hybrid 검색을 제품 기능으로 명시
|
|
132
|
+
|
|
133
|
+
**개선안**
|
|
134
|
+
- `score = w_semantic*S + w_lexical*L + w_recency*R + w_quality*Q`
|
|
135
|
+
- env/config에서 가중치 조정 가능하게
|
|
136
|
+
- quality 점수 부재 시 graceful fallback
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### E. 운영/보안 레이어
|
|
141
|
+
|
|
142
|
+
- 현 상태: runbook/ops 스크립트 존재(좋음)
|
|
143
|
+
- 참고 레포 포인트:
|
|
144
|
+
- 인증, 헬스/환경 점검, 상세 config 가이드
|
|
145
|
+
|
|
146
|
+
**개선안**
|
|
147
|
+
- 최소 추가:
|
|
148
|
+
- `MEMORY_API_KEY` 인증(HTTP 도입 시)
|
|
149
|
+
- `/api/health` + 저장소 상태 + outbox backlog 노출
|
|
150
|
+
- 백업/복구 명령 표준화
|
|
151
|
+
- 보존정책(TTL, 중요도 기반 정리) 명문화
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 4) 우선순위 로드맵 (실행 순서)
|
|
156
|
+
|
|
157
|
+
## P0 (당장 효과 큼, 1~3일)
|
|
158
|
+
1. 멀티-repo 스코프 기본 정책 강제
|
|
159
|
+
2. `proj:` 자동 태깅
|
|
160
|
+
3. 검색 기본값 same-project-only
|
|
161
|
+
4. 교차 검색은 명시적 옵션 필요
|
|
162
|
+
|
|
163
|
+
## P1 (1~2주)
|
|
164
|
+
1. tag taxonomy 모듈화
|
|
165
|
+
2. hybrid scoring 공식화 + 설정화
|
|
166
|
+
3. health endpoint/metrics 정리
|
|
167
|
+
|
|
168
|
+
## P2 (2~4주)
|
|
169
|
+
1. HTTP API + SSE 추가
|
|
170
|
+
2. 인증(OAuth까지는 아니어도 API key)
|
|
171
|
+
3. 팀/멀티클라이언트 운영 문서화
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 5) 구체 구현 제안 (코드 레벨)
|
|
176
|
+
|
|
177
|
+
### 5.1 Retrieval 옵션 확장
|
|
178
|
+
`src/core/retriever.ts`에 아래 정책 필드 추가 권장:
|
|
179
|
+
|
|
180
|
+
- `projectScopeMode: 'strict' | 'prefer' | 'global'`
|
|
181
|
+
- `allowedProjectHashes?: string[]`
|
|
182
|
+
- `crossProjectReason?: string`
|
|
183
|
+
|
|
184
|
+
`strict`일 때 현재 프로젝트 hash 불일치 결과는 필터링.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### 5.2 자동 태깅 훅
|
|
189
|
+
`MemoryService.storeUserPrompt/storeAgentResponse/storeToolObservation`에서 metadata 병합 시:
|
|
190
|
+
|
|
191
|
+
- `scope.project.hash`
|
|
192
|
+
- `scope.project.path`
|
|
193
|
+
- `tags` 개념을 도입하면 `proj:${projectHash}` 자동 주입
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
### 5.3 정책 파일 도입
|
|
198
|
+
`claude-memory-layer/policies/memory-scope-policy.json` 예:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"defaultMode": "strict",
|
|
203
|
+
"allowCrossProject": false,
|
|
204
|
+
"requireReasonForCrossProject": true,
|
|
205
|
+
"alwaysIncludeTags": ["sys:auto", "proj:auto"]
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### 5.4 운영 API 최소셋
|
|
212
|
+
향후 `src/server`에 라우트 추가:
|
|
213
|
+
|
|
214
|
+
- `GET /api/health`
|
|
215
|
+
- db 연결 상태
|
|
216
|
+
- vector worker backlog
|
|
217
|
+
- failed outbox 개수
|
|
218
|
+
- `POST /api/memories/search`
|
|
219
|
+
- projectHash 필수(운영 모드에서)
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 6) 여러 repository 관리 관점 평가
|
|
224
|
+
|
|
225
|
+
질문의 핵심(“여러 repo 관리 용이?”)에 대해:
|
|
226
|
+
|
|
227
|
+
- `claude-memory-layer` 현재 구조는 **잠재적으로 매우 유리**
|
|
228
|
+
- 프로젝트 해시 분리 구조가 이미 있기 때문
|
|
229
|
+
- 하지만 운영 안정성은 “격리 정책 강제 + 표준 태깅 + API 관측”이 있어야 완성
|
|
230
|
+
|
|
231
|
+
즉, **아키텍처 방향은 맞고, 운영 레이어 보강이 필요**.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 7) 추천 최종 전략
|
|
236
|
+
|
|
237
|
+
`/Users/namsangboy/workspace/claude-memory-layer`를 계속 중심으로 가져가되:
|
|
238
|
+
|
|
239
|
+
1. P0/P1 개선 먼저 적용해서 “멀티-repo 안 섞이는 안정성” 확보
|
|
240
|
+
2. 그 다음 HTTP/SSE/API key 붙여서 외부 자동화/다중 클라이언트 지원
|
|
241
|
+
3. 마지막에 공유 지식(shared store) 룰을 엄격히(검증된 것만 승격)
|
|
242
|
+
|
|
243
|
+
이 순서가 리스크/효율 밸런스가 가장 좋음.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 8) 보너스: 바로 체크할 TODO
|
|
248
|
+
|
|
249
|
+
- [x] `projectScopeMode` 옵션 추가
|
|
250
|
+
- [x] 기본 검색 strict project filter 적용
|
|
251
|
+
- [x] `proj:<hash>` 자동 태깅
|
|
252
|
+
- [x] tag taxonomy 모듈 생성
|
|
253
|
+
- [x] health API에 outbox failed/pending 수치 노출 (`GET /api/health`)
|
|
254
|
+
- [ ] 문서에 cross-project 허용 조건 명시
|
|
255
|
+
|
|
256
|
+
### P1 적용 메모 (이번 반영)
|
|
257
|
+
|
|
258
|
+
- 태그 taxonomy 파일 추가: `src/core/tag-taxonomy.ts`
|
|
259
|
+
- namespace 유효성 검증(`sys:, q:, proj:, topic:, t:, user:, agent:`)
|
|
260
|
+
- tags 정규화(`normalizeTags`)로 ingest 시 품질 보정
|
|
261
|
+
- rerank 가중치 설정화
|
|
262
|
+
- 환경변수 지원:
|
|
263
|
+
- `MEMORY_RERANK_WEIGHT_SEMANTIC`
|
|
264
|
+
- `MEMORY_RERANK_WEIGHT_LEXICAL`
|
|
265
|
+
- `MEMORY_RERANK_WEIGHT_RECENCY`
|
|
266
|
+
- 3개가 모두 유효하면 정규화해서 고정값 사용
|
|
267
|
+
- 없으면 기존 adaptive/기본 동작 fallback
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
원하면 다음 단계로 health endpoint/운영 지표(outbox backlog, failed 카운트)까지 이어서 붙일 수 있음.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# memU Adoption Notes (claude-memory-layer)
|
|
2
|
+
|
|
3
|
+
이 프로젝트에 적용된 memU 장점 요약입니다.
|
|
4
|
+
|
|
5
|
+
## 1) Dual Retrieval Strategy
|
|
6
|
+
- `strategy: "fast" | "deep" | "auto"`
|
|
7
|
+
- `fast`: 키워드 기반(FTS/keyword) 우선 탐색으로 저지연 검색
|
|
8
|
+
- `deep`: 임베딩 + 벡터 검색 + 재정렬(키워드 오버랩 가중)로 정밀 검색
|
|
9
|
+
|
|
10
|
+
## 2) Scoped Retrieval Filters
|
|
11
|
+
`scope`로 검색 범위를 좁혀 정확도를 높입니다.
|
|
12
|
+
|
|
13
|
+
- `sessionId` / `sessionIdPrefix`
|
|
14
|
+
- `eventTypes`
|
|
15
|
+
- `canonicalKeyPrefix`
|
|
16
|
+
- `contentIncludes` (부분 문자열 OR)
|
|
17
|
+
- `metadata` (dot-path, 예: `scope.project.id`)
|
|
18
|
+
|
|
19
|
+
## 3) Hybrid Rerank Behavior
|
|
20
|
+
`rerankWithKeyword=true`일 때 semantic score에 키워드 오버랩/최근성 점수를 가중해 재정렬합니다.
|
|
21
|
+
|
|
22
|
+
## 4) Test Coverage
|
|
23
|
+
- `tests/retriever.memu-adoption.test.ts`
|
|
24
|
+
- metadata dot-path 스코프 필터
|
|
25
|
+
- fast 전략 키워드 경로
|
|
26
|
+
- `tests/retriever-strategy-scope.test.ts`
|
|
27
|
+
- fast/deep 전략 및 복합 스코프 필터
|
|
28
|
+
|
|
29
|
+
## Quick Example
|
|
30
|
+
```ts
|
|
31
|
+
await retriever.retrieve('브리핑', {
|
|
32
|
+
strategy: 'deep',
|
|
33
|
+
topK: 10,
|
|
34
|
+
scope: {
|
|
35
|
+
sessionIdPrefix: 'agent:main:',
|
|
36
|
+
canonicalKeyPrefix: 'pref/briefing',
|
|
37
|
+
metadata: { 'scope.project.id': 'alpha' }
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
```
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
|
|
2
|
+
## 2026-02-25T12:31:21.733Z | a551b032-ffdd-43e5-8f34-c42b12b091ce
|
|
3
|
+
- type: session_summary
|
|
4
|
+
- session: import:organized
|
|
5
|
+
# /memory-forget
|
|
6
|
+
|
|
7
|
+
Remove specific memories from storage.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/memory-forget <event-id>
|
|
13
|
+
/memory-forget --session <session-id>
|
|
14
|
+
/memory-forget --before <date>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Arguments
|
|
18
|
+
|
|
19
|
+
- `event-id`: Specific event ID to forget
|
|
20
|
+
- `--session <id>`: Forget all events from a session
|
|
21
|
+
- `--before <date>`: Forget events before a date (YYYY-MM-DD)
|
|
22
|
+
- `--confirm`: Skip confirmation prompt
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
/memory-forget abc123-def456
|
|
28
|
+
/memory-forget --session session_xyz --confirm
|
|
29
|
+
/memory-forget --before 2024-01-01
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Description
|
|
33
|
+
|
|
34
|
+
Removes memories from storage. This operation:
|
|
35
|
+
|
|
36
|
+
1. Marks events as deleted in EventStore (soft delete)
|
|
37
|
+
2. Removes corresponding vectors from LanceDB
|
|
38
|
+
3. Updates memory level statistics
|
|
39
|
+
|
|
40
|
+
⚠️ **Note**: Due to the append-only architecture, deleted events are marked but not physically removed from the event log. Vector embeddings are physically deleted.
|
|
41
|
+
|
|
42
|
+
## Implementation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
node dist/cli/index.js forget $ARGUMENTS
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 2026-02-25T12:31:21.738Z | ec065482-7832-4ec6-9fbf-584ca1d05d75
|
|
49
|
+
- type: session_summary
|
|
50
|
+
- session: import:organized
|
|
51
|
+
# /memory-history
|
|
52
|
+
|
|
53
|
+
View conversation history from memory.
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
/memory-history [options]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Options
|
|
62
|
+
|
|
63
|
+
- `--session <id>`: Show history for a specific session
|
|
64
|
+
- `--limit <n>`: Limit number of events (default: 20)
|
|
65
|
+
- `--type <type>`: Filter by event type (user_prompt, agent_response, session_summary)
|
|
66
|
+
|
|
67
|
+
## Examples
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
/memory-history
|
|
71
|
+
/memory-history --limit 50
|
|
72
|
+
/memory-history --session abc123
|
|
73
|
+
/memory-history --type user_prompt
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Description
|
|
77
|
+
|
|
78
|
+
Displays stored conversation events from memory. By default shows the most recent events across all sessions. Use filters to narrow down to specific sessions or event types.
|
|
79
|
+
|
|
80
|
+
## Implementation
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
node dist/cli/index.js history $ARGUMENTS
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 2026-02-25T12:31:21.740Z | 5be40880-b0f7-4aa3-9844-7190b1fa06cf
|
|
87
|
+
- type: session_summary
|
|
88
|
+
- session: import:organized
|
|
89
|
+
# /memory-import
|
|
90
|
+
|
|
91
|
+
Import existing Claude Code conversation history into memory.
|
|
92
|
+
|
|
93
|
+
## Usage
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
/memory-import [options]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Options
|
|
100
|
+
|
|
101
|
+
- `--project <path>`: Import from specific project path
|
|
102
|
+
- `--session <file>`: Import a specific session file (JSONL)
|
|
103
|
+
- `--all`: Import all sessions from all projects
|
|
104
|
+
- `--limit <n>`: Limit messages per session
|
|
105
|
+
- `--verbose`: Show detailed progress
|
|
106
|
+
|
|
107
|
+
## Examples
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
/memory-import
|
|
111
|
+
/memory-import --project /home/user/myproject
|
|
112
|
+
/memory-import --all
|
|
113
|
+
/memory-import --session ~/.claude/projects/xyz/abc123.jsonl
|
|
114
|
+
/memory-import --all --limit 100 --verbose
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Description
|
|
118
|
+
|
|
119
|
+
This command imports existing Claude Code conversation history from JSONL session files into the memory store. This allows the plugin to learn from your previous conversations and provide more relevant context in future sessions.
|
|
120
|
+
|
|
121
|
+
### What gets imported:
|
|
122
|
+
|
|
123
|
+
- **User prompts**: Your questions and requests
|
|
124
|
+
- **Agent responses**: Claude's responses (truncated to 5000 chars)
|
|
125
|
+
- **Session metadata**: Timestamps and session IDs
|
|
126
|
+
|
|
127
|
+
### Deduplication
|
|
128
|
+
|
|
129
|
+
The importer automatically skips duplicate messages based on content hash, so you can safely run import multiple times without creating duplicate memories.
|
|
130
|
+
|
|
131
|
+
### Session Files Location
|
|
132
|
+
|
|
133
|
+
Claude Code stores session history in:
|
|
134
|
+
```
|
|
135
|
+
~/.claude/projects/<project-hash>/<session-id>.jsonl
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Use `/memory-list` to see available sessions before importing.
|
|
139
|
+
|
|
140
|
+
## Implementation
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
node dist/cli/index.js import $ARGUMENTS
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 2026-02-25T12:31:21.743Z | 3d6ec7cb-b61d-4638-b767-a2d6a1e1b7bd
|
|
147
|
+
- type: session_summary
|
|
148
|
+
- session: import:organized
|
|
149
|
+
# /memory-list
|
|
150
|
+
|
|
151
|
+
List available Claude Code sessions that can be imported.
|
|
152
|
+
|
|
153
|
+
## Usage
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
/memory-list [options]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Options
|
|
160
|
+
|
|
161
|
+
- `--project <path>`: Filter sessions by project path
|
|
162
|
+
|
|
163
|
+
## Examples
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
/memory-list
|
|
167
|
+
/memory-list --project /home/user/myproject
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Description
|
|
171
|
+
|
|
172
|
+
Shows all available Claude Code session files that can be imported into memory. Each session displays:
|
|
173
|
+
|
|
174
|
+
- **Session ID**: Unique identifier for the session
|
|
175
|
+
- **Modified date**: When the session was last updated
|
|
176
|
+
- **File size**: Size of the session file
|
|
177
|
+
- **Path**: Full path to the JSONL file
|
|
178
|
+
|
|
179
|
+
Use this command to identify which sessions you want to import before running `/memory-import`.
|
|
180
|
+
|
|
181
|
+
## Implementation
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
node dist/cli/index.js list $ARGUMENTS
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## 2026-02-25T12:31:21.745Z | fd04fc38-ab42-4406-aadc-9d73fdbbb079
|
|
188
|
+
- type: session_summary
|
|
189
|
+
- session: import:organized
|
|
190
|
+
# /memory-search
|
|
191
|
+
|
|
192
|
+
Search through stored memories using semantic search.
|
|
193
|
+
|
|
194
|
+
## Usage
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
/memory-search <query>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Arguments
|
|
201
|
+
|
|
202
|
+
- `query`: The search query to find relevant memories
|
|
203
|
+
|
|
204
|
+
## Examples
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
/memory-search how to implement authentication
|
|
208
|
+
/memory-search React component patterns
|
|
209
|
+
/memory-search database optimization
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Description
|
|
213
|
+
|
|
214
|
+
This command searches through all stored conversation memories using semantic similarity. It returns the most relevant memories that match your query, along with their confidence scores.
|
|
215
|
+
|
|
216
|
+
The search uses AXIOMMIND weighted scoring:
|
|
217
|
+
- **High confidence** (≥0.92): Strong match, likely relevant
|
|
218
|
+
- **Suggested** (≥0.75): May be relevant, review recommended
|
|
219
|
+
- **None** (<0.75): No significant matches found
|
|
220
|
+
|
|
221
|
+
## Implementation
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
node dist/cli/index.js search "$ARGUMENTS"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 2026-02-25T12:31:21.746Z | dc8f7b26-d8dd-461f-9911-54b26b23343e
|
|
228
|
+
- type: session_summary
|
|
229
|
+
- session: import:organized
|
|
230
|
+
# /memory-stats
|
|
231
|
+
|
|
232
|
+
View memory storage statistics.
|
|
233
|
+
|
|
234
|
+
## Usage
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
/memory-stats
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Description
|
|
241
|
+
|
|
242
|
+
Displays statistics about stored memories including:
|
|
243
|
+
|
|
244
|
+
- Total number of events
|
|
245
|
+
- Number of vector embeddings
|
|
246
|
+
- Memory level distribution (L0-L4)
|
|
247
|
+
- Storage size information
|
|
248
|
+
|
|
249
|
+
## Memory Levels
|
|
250
|
+
|
|
251
|
+
The graduation pipeline moves memories through these levels:
|
|
252
|
+
|
|
253
|
+
- **L0**: Raw events (EventStore)
|
|
254
|
+
- **L1**: Structured JSON (patterns, summaries)
|
|
255
|
+
- **L2**: Type candidates (validated schemas)
|
|
256
|
+
- **L3**: Verified knowledge (cross-session validated)
|
|
257
|
+
- **L4**: Active/searchable (indexed, readily available)
|
|
258
|
+
|
|
259
|
+
## Implementation
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
node dist/cli/index.js stats
|
|
263
|
+
```
|