claude-recall 0.7.0 → 0.7.2
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/.claude/CLAUDE.md +133 -0
- package/README.md +149 -0
- package/dist/cli/claude-recall-cli.js +69 -7
- package/dist/mcp/memory-capture-middleware.js +7 -6
- package/dist/mcp/tools/memory-tools.js +23 -6
- package/dist/memory/schema.sql +3 -1
- package/dist/memory/storage.js +6 -5
- package/dist/services/config.js +6 -1
- package/dist/services/memory.js +36 -2
- package/package.json +2 -2
package/.claude/CLAUDE.md
CHANGED
|
@@ -84,6 +84,58 @@ Claude Recall provides these MCP tools (access via `mcp__claude-recall__*`):
|
|
|
84
84
|
- **`mcp__claude-recall__get_stats`**: View memory statistics
|
|
85
85
|
- **`mcp__claude-recall__clear_context`**: Clear session context
|
|
86
86
|
|
|
87
|
+
## Intelligence & Evolution (v0.7.0+)
|
|
88
|
+
|
|
89
|
+
### Automatic Failure Learning
|
|
90
|
+
|
|
91
|
+
Claude Recall now **automatically captures failures with counterfactual reasoning**:
|
|
92
|
+
- **What failed**: The approach or action that didn't work
|
|
93
|
+
- **Why it failed**: Root cause analysis (file not found, permission denied, etc.)
|
|
94
|
+
- **What should be done instead**: Counterfactual suggestion (the right approach)
|
|
95
|
+
- **Preventative checks**: Steps to prevent the failure from recurring
|
|
96
|
+
|
|
97
|
+
**No manual storage needed** - failures are auto-detected from:
|
|
98
|
+
- Error messages and exceptions
|
|
99
|
+
- User corrections ("That didn't work", "Failed", "Error")
|
|
100
|
+
|
|
101
|
+
### Sophistication Tracking
|
|
102
|
+
|
|
103
|
+
Every memory is **automatically classified by sophistication level**:
|
|
104
|
+
- **L1 Procedural**: Basic tool use, simple actions
|
|
105
|
+
- **L2 Self-Reflection**: Error checking, corrections, learning from failures
|
|
106
|
+
- **L3 Adaptive**: Systematic workflows, devops patterns
|
|
107
|
+
- **L4 Compositional**: Multi-constraint reasoning, complex decision-making
|
|
108
|
+
|
|
109
|
+
View your agent's evolution: `npx claude-recall evolution`
|
|
110
|
+
|
|
111
|
+
### New CLI Commands (v0.7.0+)
|
|
112
|
+
|
|
113
|
+
**View memory evolution metrics:**
|
|
114
|
+
```bash
|
|
115
|
+
npx claude-recall evolution # Last 30 days
|
|
116
|
+
npx claude-recall evolution --days 60 # Last 60 days
|
|
117
|
+
npx claude-recall evolution --project my-app # Filter by project
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Shows:
|
|
121
|
+
- Progression score (0-100)
|
|
122
|
+
- Sophistication breakdown (L1-L4 percentages)
|
|
123
|
+
- Confidence trends (improving/stable/declining)
|
|
124
|
+
- Failure rate trends (improving/stable/worsening)
|
|
125
|
+
|
|
126
|
+
**View failure memories with counterfactual learning:**
|
|
127
|
+
```bash
|
|
128
|
+
npx claude-recall failures # Last 10 failures
|
|
129
|
+
npx claude-recall failures --limit 20 # Show 20 most recent
|
|
130
|
+
npx claude-recall failures --project my-app # Filter by project
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Shows:
|
|
134
|
+
- What failed and why
|
|
135
|
+
- What should have been done instead
|
|
136
|
+
- Preventative checks to avoid recurrence
|
|
137
|
+
- Alternative approaches to consider
|
|
138
|
+
|
|
87
139
|
## Memory Types
|
|
88
140
|
|
|
89
141
|
Memories are categorized by type (sorted by priority):
|
|
@@ -181,6 +233,87 @@ Confirm: "✓ Stored preference"
|
|
|
181
233
|
5. **Use broad search terms**: Include task type + language + preferences + success/failure/correction
|
|
182
234
|
6. **Close the loop**: Pre-action search → Execute → Post-action outcome storage
|
|
183
235
|
|
|
236
|
+
## Project Scoping (v0.7.2+)
|
|
237
|
+
|
|
238
|
+
Claude Recall now supports **project-specific memory isolation** to keep universal preferences separate from project-specific information.
|
|
239
|
+
|
|
240
|
+
### Three Memory Scopes
|
|
241
|
+
|
|
242
|
+
1. **Universal** (`scope='universal'`): Available in all projects
|
|
243
|
+
- User says: "Remember everywhere: I prefer TypeScript with strict mode"
|
|
244
|
+
- Stored as universal memory, accessible from any project
|
|
245
|
+
|
|
246
|
+
2. **Project** (`scope='project'`): Only available in current project
|
|
247
|
+
- User says: "For this project, we use PostgreSQL"
|
|
248
|
+
- Stored with project_id, only accessible from this project
|
|
249
|
+
|
|
250
|
+
3. **Unscoped** (`scope=null`, default): Available everywhere (backward compatible)
|
|
251
|
+
- User says: "I prefer Jest for testing"
|
|
252
|
+
- Stored without scope, works like v0.7.1 and earlier
|
|
253
|
+
|
|
254
|
+
### Auto-Detection
|
|
255
|
+
|
|
256
|
+
When storing memories, the system automatically detects scope from user language:
|
|
257
|
+
|
|
258
|
+
**Universal indicators**:
|
|
259
|
+
- "remember everywhere"
|
|
260
|
+
- "for all projects"
|
|
261
|
+
- "globally"
|
|
262
|
+
- "always use"
|
|
263
|
+
|
|
264
|
+
**Project indicators**:
|
|
265
|
+
- "for this project"
|
|
266
|
+
- "project-specific"
|
|
267
|
+
- "only here"
|
|
268
|
+
- "in this project"
|
|
269
|
+
|
|
270
|
+
**Default**: If no indicator, memory is unscoped (available everywhere)
|
|
271
|
+
|
|
272
|
+
### How Search Works
|
|
273
|
+
|
|
274
|
+
**Default behavior** (project + universal):
|
|
275
|
+
```
|
|
276
|
+
mcp__claude-recall__search("database")
|
|
277
|
+
```
|
|
278
|
+
Returns: Current project memories + universal memories + unscoped memories
|
|
279
|
+
|
|
280
|
+
**Global search** (all projects):
|
|
281
|
+
```
|
|
282
|
+
mcp__claude-recall__search("database", filters: { globalSearch: true })
|
|
283
|
+
```
|
|
284
|
+
Returns: All memories from all projects
|
|
285
|
+
|
|
286
|
+
### CLI Usage
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# Current project stats
|
|
290
|
+
npx claude-recall stats
|
|
291
|
+
|
|
292
|
+
# Global stats (all projects)
|
|
293
|
+
npx claude-recall stats --global
|
|
294
|
+
|
|
295
|
+
# Search current project
|
|
296
|
+
npx claude-recall search "database"
|
|
297
|
+
|
|
298
|
+
# Search specific project
|
|
299
|
+
npx claude-recall search "database" --project my-app
|
|
300
|
+
|
|
301
|
+
# Search all projects
|
|
302
|
+
npx claude-recall search "database" --global
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Use Cases
|
|
306
|
+
|
|
307
|
+
**Universal memories**: Preferences that apply across all your work
|
|
308
|
+
- Coding style: "Always use TypeScript with strict mode"
|
|
309
|
+
- Tools: "Prefer Jest for testing"
|
|
310
|
+
- Conventions: "Name files with kebab-case"
|
|
311
|
+
|
|
312
|
+
**Project memories**: Project-specific details
|
|
313
|
+
- Database: "This project uses PostgreSQL"
|
|
314
|
+
- API: "Base URL is https://api.example.com"
|
|
315
|
+
- Build: "Run npm run build:prod for production"
|
|
316
|
+
|
|
184
317
|
## Advanced: Optional Context-Manager Agent
|
|
185
318
|
|
|
186
319
|
For complex multi-step research, a `context-manager` agent is available at `.claude/agents/context-manager.md`.
|
package/README.md
CHANGED
|
@@ -28,6 +28,13 @@ Every time you start a new conversation with Claude, you're starting from scratc
|
|
|
28
28
|
- **Optional agent** - Advanced context-manager agent available for complex workflows
|
|
29
29
|
- **Correction priority** - User corrections given highest priority (never repeat mistakes)
|
|
30
30
|
|
|
31
|
+
### 🧠 Intelligence & Evolution (v0.7.0+)
|
|
32
|
+
- **Sophistication tracking** - Measures agent progression from basic tool use to compositional reasoning
|
|
33
|
+
- **Failure learning** - Captures what failed, why it failed, and what should be done instead (counterfactual reasoning)
|
|
34
|
+
- **Evolution metrics** - View progression score, confidence trends, and failure rates over time
|
|
35
|
+
- **Structured memories** - Rich Title/Description/Content format for better human readability
|
|
36
|
+
- **Automatic classification** - Memories auto-classified by sophistication level (L1-L4)
|
|
37
|
+
|
|
31
38
|
### 🔒 Privacy & Security First
|
|
32
39
|
- **100% Local** - All memories stored locally in SQLite (~/.claude-recall/)
|
|
33
40
|
- **No cloud sync** - Your data never leaves your machine
|
|
@@ -386,6 +393,148 @@ claude-recall clear --force # Clear everything
|
|
|
386
393
|
claude-recall capture user-prompt '{"content":"your message here"}'
|
|
387
394
|
```
|
|
388
395
|
|
|
396
|
+
### Intelligence & Evolution Commands (v0.7.0+)
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# View memory evolution and sophistication metrics
|
|
400
|
+
claude-recall evolution
|
|
401
|
+
claude-recall evolution --days 60 # Analyze last 60 days
|
|
402
|
+
claude-recall evolution --project my-app # Filter by project
|
|
403
|
+
|
|
404
|
+
# View failure memories with counterfactual learning
|
|
405
|
+
claude-recall failures
|
|
406
|
+
claude-recall failures --limit 20 # Show 20 most recent
|
|
407
|
+
claude-recall failures --project my-app # Filter by project
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Example `evolution` output:**
|
|
411
|
+
```
|
|
412
|
+
📈 Memory Evolution
|
|
413
|
+
|
|
414
|
+
Analysis Period: Last 30 days
|
|
415
|
+
Total Memories: 145
|
|
416
|
+
Progression Score: 67/100
|
|
417
|
+
|
|
418
|
+
Sophistication Breakdown:
|
|
419
|
+
Procedural (L1): 45 ( 31.0%)
|
|
420
|
+
Self-Reflection (L2): 38 ( 26.2%)
|
|
421
|
+
Adaptive (L3): 52 ( 35.9%)
|
|
422
|
+
Compositional (L4): 10 ( 6.9%)
|
|
423
|
+
|
|
424
|
+
Average Confidence: 0.78 ↗
|
|
425
|
+
Failure Rate: 12.4% ↘
|
|
426
|
+
|
|
427
|
+
○ Agent developing adaptive patterns
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Example `failures` output:**
|
|
431
|
+
```
|
|
432
|
+
❌ Failure Memories (Counterfactual Learning)
|
|
433
|
+
|
|
434
|
+
1. Avoid: Reading file without existence check
|
|
435
|
+
What Failed: Attempted to read config.json directly
|
|
436
|
+
Why Failed: File does not exist at expected location
|
|
437
|
+
Should Do: Verify file path exists before reading. Use fs.existsSync()
|
|
438
|
+
Preventative Checks:
|
|
439
|
+
- Verify file exists before reading (fs.existsSync)
|
|
440
|
+
- Handle ENOENT errors gracefully
|
|
441
|
+
|
|
442
|
+
2. Avoid: Session-based authentication
|
|
443
|
+
What Failed: Session-based auth implementation
|
|
444
|
+
Why Failed: User reported: Doesn't scale across multiple servers
|
|
445
|
+
Should Do: Use JWT tokens instead
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Sophistication Levels:**
|
|
449
|
+
- **L1 Procedural**: Basic tool use, simple actions
|
|
450
|
+
- **L2 Self-Reflection**: Error checking, corrections, learning from failures
|
|
451
|
+
- **L3 Adaptive**: Systematic workflows, devops patterns
|
|
452
|
+
- **L4 Compositional**: Multi-constraint reasoning, complex decision-making
|
|
453
|
+
|
|
454
|
+
## Project Scoping (v0.7.2+)
|
|
455
|
+
|
|
456
|
+
Claude Recall now supports **project-specific memory isolation** while keeping universal preferences available everywhere.
|
|
457
|
+
|
|
458
|
+
### How It Works
|
|
459
|
+
|
|
460
|
+
- **Single global database**: `~/.claude-recall/claude-recall.db`
|
|
461
|
+
- **Three memory scopes**:
|
|
462
|
+
- **Universal**: Available in all projects (coding preferences, tools)
|
|
463
|
+
- **Project**: Only available in the specific project
|
|
464
|
+
- **Unscoped** (default): Available everywhere (backward compatible)
|
|
465
|
+
- **Project ID**: Automatically detected from directory name
|
|
466
|
+
|
|
467
|
+
### Storing Memories
|
|
468
|
+
|
|
469
|
+
**Universal memories** (available everywhere):
|
|
470
|
+
```
|
|
471
|
+
User: "Remember everywhere: I prefer TypeScript with strict mode"
|
|
472
|
+
Claude: [Stores with scope='universal']
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**Project-specific memories**:
|
|
476
|
+
```
|
|
477
|
+
User: "For this project, we use SQLite for the database"
|
|
478
|
+
Claude: [Stores with scope='project', project_id='my-app']
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Default** (unscoped, works like before):
|
|
482
|
+
```
|
|
483
|
+
User: "I prefer Jest for testing"
|
|
484
|
+
Claude: [Stores with scope=null, available everywhere]
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Searching with Scopes
|
|
488
|
+
|
|
489
|
+
**Default** (current project + universal):
|
|
490
|
+
```bash
|
|
491
|
+
npx claude-recall search "database"
|
|
492
|
+
# Returns: Current project memories + universal memories + unscoped
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
**Specific project**:
|
|
496
|
+
```bash
|
|
497
|
+
npx claude-recall search "database" --project my-app
|
|
498
|
+
# Returns: my-app memories + universal memories + unscoped
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**All projects**:
|
|
502
|
+
```bash
|
|
503
|
+
npx claude-recall search "database" --global
|
|
504
|
+
# Returns: All memories from all projects
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Stats with Scopes
|
|
508
|
+
|
|
509
|
+
**Current project**:
|
|
510
|
+
```bash
|
|
511
|
+
npx claude-recall stats
|
|
512
|
+
# Shows: Memories for current project (claude-recall) + universal + unscoped
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**All projects**:
|
|
516
|
+
```bash
|
|
517
|
+
npx claude-recall stats --global
|
|
518
|
+
# Shows: All memories across all projects
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Use Cases
|
|
522
|
+
|
|
523
|
+
**Universal memories** (scope='universal'):
|
|
524
|
+
- Coding style preferences: "Always use TypeScript with strict mode"
|
|
525
|
+
- Tool preferences: "Prefer Jest for testing"
|
|
526
|
+
- File naming conventions: "Name markdown files with lowercase-dash-case"
|
|
527
|
+
|
|
528
|
+
**Project-specific memories** (scope='project'):
|
|
529
|
+
- Database choice: "This project uses PostgreSQL"
|
|
530
|
+
- API endpoints: "API base URL is https://api.example.com"
|
|
531
|
+
- Build commands: "Run npm run build:prod for production"
|
|
532
|
+
|
|
533
|
+
**Unscoped memories** (scope=null, default):
|
|
534
|
+
- Backward compatible
|
|
535
|
+
- Works like v0.7.1 and earlier
|
|
536
|
+
- Available everywhere unless you explicitly scope them
|
|
537
|
+
|
|
389
538
|
## Memory Management
|
|
390
539
|
|
|
391
540
|
Claude Recall automatically manages memory to prevent unlimited database growth, with user notifications:
|
|
@@ -67,13 +67,28 @@ class ClaudeRecallCLI {
|
|
|
67
67
|
/**
|
|
68
68
|
* Show memory statistics
|
|
69
69
|
*/
|
|
70
|
-
showStats() {
|
|
71
|
-
|
|
70
|
+
showStats(options) {
|
|
71
|
+
let stats;
|
|
72
72
|
const configService = config_1.ConfigService.getInstance();
|
|
73
73
|
const config = configService.getConfig();
|
|
74
74
|
const maxMemories = config.database.compaction?.maxMemories || 10000;
|
|
75
|
+
if (options?.global) {
|
|
76
|
+
// Show stats for all memories
|
|
77
|
+
stats = this.memoryService.getStats();
|
|
78
|
+
console.log('\n📊 Claude Recall Statistics (All Projects)\n');
|
|
79
|
+
}
|
|
80
|
+
else if (options?.project) {
|
|
81
|
+
// Show stats for specific project + universal
|
|
82
|
+
stats = this.getProjectStats(options.project);
|
|
83
|
+
console.log(`\n📊 Claude Recall Statistics (Project: ${options.project})\n`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Show stats for current project + universal
|
|
87
|
+
const projectId = configService.getProjectId();
|
|
88
|
+
stats = this.getProjectStats(projectId);
|
|
89
|
+
console.log(`\n📊 Claude Recall Statistics (Project: ${projectId})\n`);
|
|
90
|
+
}
|
|
75
91
|
const usagePercent = (stats.total / maxMemories) * 100;
|
|
76
|
-
console.log('\n📊 Claude Recall Statistics\n');
|
|
77
92
|
console.log(`Total Memories: ${stats.total}/${maxMemories} (${usagePercent.toFixed(1)}%)`);
|
|
78
93
|
// Simple status indicator
|
|
79
94
|
if (usagePercent >= 90) {
|
|
@@ -95,6 +110,24 @@ class ClaudeRecallCLI {
|
|
|
95
110
|
console.log('\n');
|
|
96
111
|
this.logger.info('CLI', 'Stats displayed', stats);
|
|
97
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Get stats for a specific project (includes universal and unscoped memories)
|
|
115
|
+
*/
|
|
116
|
+
getProjectStats(projectId) {
|
|
117
|
+
const allMemories = this.memoryService.search('');
|
|
118
|
+
const projectMemories = allMemories.filter(m => m.project_id === projectId ||
|
|
119
|
+
m.scope === 'universal' ||
|
|
120
|
+
m.project_id === null);
|
|
121
|
+
// Calculate byType breakdown
|
|
122
|
+
const byType = {};
|
|
123
|
+
for (const mem of projectMemories) {
|
|
124
|
+
byType[mem.type] = (byType[mem.type] || 0) + 1;
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
total: projectMemories.length,
|
|
128
|
+
byType
|
|
129
|
+
};
|
|
130
|
+
}
|
|
98
131
|
/**
|
|
99
132
|
* Show skills evolution breakdown
|
|
100
133
|
*/
|
|
@@ -254,7 +287,27 @@ class ClaudeRecallCLI {
|
|
|
254
287
|
*/
|
|
255
288
|
search(query, options) {
|
|
256
289
|
const limit = options.limit || 10;
|
|
257
|
-
|
|
290
|
+
// Determine search scope
|
|
291
|
+
let results;
|
|
292
|
+
if (options.global) {
|
|
293
|
+
// Global search: all memories
|
|
294
|
+
results = this.memoryService.search(query);
|
|
295
|
+
}
|
|
296
|
+
else if (options.project) {
|
|
297
|
+
// Project-specific search: project + universal
|
|
298
|
+
results = this.memoryService.findRelevant({
|
|
299
|
+
query,
|
|
300
|
+
projectId: options.project
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
// Default: current project + universal
|
|
305
|
+
const config = config_1.ConfigService.getInstance();
|
|
306
|
+
results = this.memoryService.findRelevant({
|
|
307
|
+
query,
|
|
308
|
+
projectId: config.getProjectId()
|
|
309
|
+
});
|
|
310
|
+
}
|
|
258
311
|
const topResults = results.slice(0, limit);
|
|
259
312
|
if (options.json) {
|
|
260
313
|
// Format for hook consumption - include relevance_score field
|
|
@@ -566,11 +619,15 @@ async function main() {
|
|
|
566
619
|
.description('Search memories by query')
|
|
567
620
|
.option('-l, --limit <number>', 'Maximum results to show', '10')
|
|
568
621
|
.option('--json', 'Output as JSON')
|
|
622
|
+
.option('--project <id>', 'Filter by project ID (includes universal memories)')
|
|
623
|
+
.option('--global', 'Search all projects and memories')
|
|
569
624
|
.action((query, options) => {
|
|
570
625
|
const cli = new ClaudeRecallCLI(program.opts());
|
|
571
626
|
cli.search(query, {
|
|
572
627
|
limit: parseInt(options.limit),
|
|
573
|
-
json: options.json
|
|
628
|
+
json: options.json,
|
|
629
|
+
project: options.project,
|
|
630
|
+
global: options.global
|
|
574
631
|
});
|
|
575
632
|
process.exit(0);
|
|
576
633
|
});
|
|
@@ -578,9 +635,14 @@ async function main() {
|
|
|
578
635
|
program
|
|
579
636
|
.command('stats')
|
|
580
637
|
.description('Show memory statistics')
|
|
581
|
-
.
|
|
638
|
+
.option('--project <id>', 'Filter by project ID')
|
|
639
|
+
.option('--global', 'Show all memories across all projects')
|
|
640
|
+
.action((options) => {
|
|
582
641
|
const cli = new ClaudeRecallCLI(program.opts());
|
|
583
|
-
cli.showStats(
|
|
642
|
+
cli.showStats({
|
|
643
|
+
project: options.project,
|
|
644
|
+
global: options.global
|
|
645
|
+
});
|
|
584
646
|
process.exit(0);
|
|
585
647
|
});
|
|
586
648
|
// Evolution command
|
|
@@ -190,10 +190,10 @@ class MemoryCaptureMiddleware {
|
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
|
-
// PRIORITY 1: Check for explicit "remember" commands
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
for (const match of
|
|
193
|
+
// PRIORITY 1: Check for explicit "remember" or "recall" commands
|
|
194
|
+
const explicitMemoryRegex = /(?:remember|Remember|recall|Recall)\s+(?:that\s+)?(.+?)(?:[.!?]|$)/gi;
|
|
195
|
+
const explicitMemoryMatches = content.matchAll(explicitMemoryRegex);
|
|
196
|
+
for (const match of explicitMemoryMatches) {
|
|
197
197
|
const memoryContent = match[1].trim();
|
|
198
198
|
if (memoryContent) {
|
|
199
199
|
memories.push({
|
|
@@ -201,7 +201,7 @@ class MemoryCaptureMiddleware {
|
|
|
201
201
|
content: memoryContent,
|
|
202
202
|
data: {
|
|
203
203
|
raw: memoryContent,
|
|
204
|
-
source: '
|
|
204
|
+
source: 'explicit_memory_command',
|
|
205
205
|
confidence: 1.0
|
|
206
206
|
},
|
|
207
207
|
confidence: 1.0, // Always highest confidence
|
|
@@ -230,7 +230,8 @@ class MemoryCaptureMiddleware {
|
|
|
230
230
|
const matches = content.matchAll(regex);
|
|
231
231
|
for (const match of matches) {
|
|
232
232
|
// Skip if this was already captured as explicit memory
|
|
233
|
-
|
|
233
|
+
const lower = match[0].toLowerCase();
|
|
234
|
+
if (lower.includes('remember') || lower.includes('recall'))
|
|
234
235
|
continue;
|
|
235
236
|
memories.push({
|
|
236
237
|
type: pattern.type,
|
|
@@ -86,6 +86,11 @@ class MemoryTools {
|
|
|
86
86
|
metadata: {
|
|
87
87
|
type: 'object',
|
|
88
88
|
description: 'Optional metadata for the memory'
|
|
89
|
+
},
|
|
90
|
+
scope: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
enum: ['universal', 'project'],
|
|
93
|
+
description: 'Memory scope: "universal" (available in all projects) or "project" (current project only). Default: unscoped (available everywhere for backward compatibility)'
|
|
89
94
|
}
|
|
90
95
|
},
|
|
91
96
|
required: ['content']
|
|
@@ -139,7 +144,11 @@ class MemoryTools {
|
|
|
139
144
|
},
|
|
140
145
|
projectId: {
|
|
141
146
|
type: 'string',
|
|
142
|
-
description: 'Filter by project ID'
|
|
147
|
+
description: 'Filter by project ID (includes universal memories)'
|
|
148
|
+
},
|
|
149
|
+
globalSearch: {
|
|
150
|
+
type: 'boolean',
|
|
151
|
+
description: 'Search all projects (ignores projectId filter)'
|
|
143
152
|
}
|
|
144
153
|
}
|
|
145
154
|
},
|
|
@@ -264,7 +273,7 @@ class MemoryTools {
|
|
|
264
273
|
}
|
|
265
274
|
async handleStoreMemory(input, context) {
|
|
266
275
|
try {
|
|
267
|
-
const { content, metadata } = input;
|
|
276
|
+
const { content, metadata, scope } = input;
|
|
268
277
|
if (!content || typeof content !== 'string') {
|
|
269
278
|
throw new Error('Content is required and must be a string');
|
|
270
279
|
}
|
|
@@ -280,8 +289,9 @@ class MemoryTools {
|
|
|
280
289
|
type: 'conversation',
|
|
281
290
|
context: {
|
|
282
291
|
sessionId: context.sessionId,
|
|
283
|
-
projectId: context.projectId,
|
|
284
|
-
timestamp: context.timestamp
|
|
292
|
+
projectId: scope === 'project' ? context.projectId : undefined,
|
|
293
|
+
timestamp: context.timestamp,
|
|
294
|
+
scope: scope || null
|
|
285
295
|
}
|
|
286
296
|
});
|
|
287
297
|
this.logger.info('MemoryTools', 'Memory stored successfully', {
|
|
@@ -379,8 +389,15 @@ class MemoryTools {
|
|
|
379
389
|
if (filters.type && result.type !== filters.type) {
|
|
380
390
|
return false;
|
|
381
391
|
}
|
|
382
|
-
|
|
383
|
-
|
|
392
|
+
// Global search: include all memories
|
|
393
|
+
if (filters.globalSearch) {
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
// Project-scoped search: include project + universal + unscoped memories
|
|
397
|
+
if (filters.projectId) {
|
|
398
|
+
return result.project_id === filters.projectId ||
|
|
399
|
+
result.scope === 'universal' ||
|
|
400
|
+
result.project_id === null;
|
|
384
401
|
}
|
|
385
402
|
return true;
|
|
386
403
|
});
|
package/dist/memory/schema.sql
CHANGED
|
@@ -14,10 +14,12 @@ CREATE TABLE IF NOT EXISTS memories (
|
|
|
14
14
|
superseded_by TEXT,
|
|
15
15
|
superseded_at INTEGER,
|
|
16
16
|
confidence_score REAL,
|
|
17
|
-
sophistication_level INTEGER DEFAULT 1
|
|
17
|
+
sophistication_level INTEGER DEFAULT 1,
|
|
18
|
+
scope TEXT CHECK(scope IN ('universal', 'project', NULL))
|
|
18
19
|
);
|
|
19
20
|
|
|
20
21
|
CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project_id);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_memories_scope_project ON memories(scope, project_id);
|
|
21
23
|
CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
|
|
22
24
|
CREATE INDEX IF NOT EXISTS idx_memories_timestamp ON memories(timestamp);
|
|
23
25
|
CREATE INDEX IF NOT EXISTS idx_memories_preference_key ON memories(preference_key, is_active);
|
package/dist/memory/storage.js
CHANGED
|
@@ -82,10 +82,10 @@ class MemoryStorage {
|
|
|
82
82
|
const stmt = this.db.prepare(`
|
|
83
83
|
INSERT OR REPLACE INTO memories
|
|
84
84
|
(key, value, type, project_id, file_path, timestamp, relevance_score, access_count,
|
|
85
|
-
preference_key, is_active, superseded_by, superseded_at, confidence_score, sophistication_level)
|
|
86
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
85
|
+
preference_key, is_active, superseded_by, superseded_at, confidence_score, sophistication_level, scope)
|
|
86
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
87
87
|
`);
|
|
88
|
-
stmt.run(memory.key, JSON.stringify(memory.value), memory.type, memory.project_id || null, memory.file_path || null, memory.timestamp || Date.now(), memory.relevance_score || 1.0, memory.access_count || 0, memory.preference_key || null, memory.is_active !== undefined ? (memory.is_active ? 1 : 0) : 1, memory.superseded_by || null, memory.superseded_at || null, memory.confidence_score || null, memory.sophistication_level || 1);
|
|
88
|
+
stmt.run(memory.key, JSON.stringify(memory.value), memory.type, memory.project_id || null, memory.file_path || null, memory.timestamp || Date.now(), memory.relevance_score || 1.0, memory.access_count || 0, memory.preference_key || null, memory.is_active !== undefined ? (memory.is_active ? 1 : 0) : 1, memory.superseded_by || null, memory.superseded_at || null, memory.confidence_score || null, memory.sophistication_level || 1, memory.scope || null);
|
|
89
89
|
// Force a WAL checkpoint to ensure the data is written to the main database file
|
|
90
90
|
// This ensures that other processes (like CLI) can see the changes immediately
|
|
91
91
|
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
@@ -133,8 +133,9 @@ class MemoryStorage {
|
|
|
133
133
|
let query = 'SELECT * FROM memories WHERE 1=1';
|
|
134
134
|
const params = [];
|
|
135
135
|
if (context.project_id) {
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
// Include project-specific OR universal OR unscoped (NULL) memories
|
|
137
|
+
query += ' AND (project_id = ? OR scope = ? OR project_id IS NULL)';
|
|
138
|
+
params.push(context.project_id, 'universal');
|
|
138
139
|
}
|
|
139
140
|
if (context.file_path) {
|
|
140
141
|
query += ' AND file_path = ?';
|
package/dist/services/config.js
CHANGED
|
@@ -144,7 +144,12 @@ class ConfigService {
|
|
|
144
144
|
return path.join(this.config.logging.directory, logName);
|
|
145
145
|
}
|
|
146
146
|
getProjectId() {
|
|
147
|
-
|
|
147
|
+
if (this.config.project.id) {
|
|
148
|
+
return this.config.project.id;
|
|
149
|
+
}
|
|
150
|
+
// Use directory name (basename) instead of full path
|
|
151
|
+
const rootDir = this.config.project.rootDir;
|
|
152
|
+
return path.basename(rootDir);
|
|
148
153
|
}
|
|
149
154
|
updateConfig(updates) {
|
|
150
155
|
this.config = this.mergeConfig(this.config, updates);
|
package/dist/services/memory.js
CHANGED
|
@@ -35,14 +35,17 @@ class MemoryService {
|
|
|
35
35
|
const percent = ((stats.total / maxMemories) * 100).toFixed(0);
|
|
36
36
|
console.log(`⚠️ Memory usage at ${percent}% (${stats.total}/${maxMemories})`);
|
|
37
37
|
}
|
|
38
|
+
// Detect scope (v0.8.0)
|
|
39
|
+
const scope = this.detectScope(request);
|
|
38
40
|
const memory = {
|
|
39
41
|
key: request.key,
|
|
40
42
|
value: request.value,
|
|
41
43
|
type: request.type,
|
|
42
|
-
project_id: request.context?.projectId || this.config.getProjectId(),
|
|
44
|
+
project_id: scope === 'universal' ? undefined : (request.context?.projectId || this.config.getProjectId()),
|
|
43
45
|
file_path: request.context?.filePath,
|
|
44
46
|
timestamp: request.context?.timestamp || Date.now(),
|
|
45
|
-
relevance_score: request.relevanceScore || 1.0
|
|
47
|
+
relevance_score: request.relevanceScore || 1.0,
|
|
48
|
+
scope: scope
|
|
46
49
|
};
|
|
47
50
|
// Auto-classify sophistication level (v0.7.0)
|
|
48
51
|
memory.sophistication_level = this.evolution.classifySophistication(memory);
|
|
@@ -354,6 +357,37 @@ class MemoryService {
|
|
|
354
357
|
return false;
|
|
355
358
|
}
|
|
356
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Detect memory scope from request (v0.8.0)
|
|
362
|
+
* @private
|
|
363
|
+
*/
|
|
364
|
+
detectScope(request) {
|
|
365
|
+
// Check explicit scope in context
|
|
366
|
+
if (request.context?.scope) {
|
|
367
|
+
return request.context.scope;
|
|
368
|
+
}
|
|
369
|
+
// Extract content for analysis
|
|
370
|
+
const content = typeof request.value === 'string'
|
|
371
|
+
? request.value
|
|
372
|
+
: JSON.stringify(request.value);
|
|
373
|
+
const lowerContent = content.toLowerCase();
|
|
374
|
+
// Explicit user indicators for universal scope
|
|
375
|
+
if (lowerContent.includes('remember everywhere') ||
|
|
376
|
+
lowerContent.includes('for all projects') ||
|
|
377
|
+
lowerContent.includes('globally') ||
|
|
378
|
+
lowerContent.includes('always use')) {
|
|
379
|
+
return 'universal';
|
|
380
|
+
}
|
|
381
|
+
// Explicit user indicators for project scope
|
|
382
|
+
if (lowerContent.includes('for this project') ||
|
|
383
|
+
lowerContent.includes('project-specific') ||
|
|
384
|
+
lowerContent.includes('only here') ||
|
|
385
|
+
lowerContent.includes('in this project')) {
|
|
386
|
+
return 'project';
|
|
387
|
+
}
|
|
388
|
+
// Default: unscoped (null) for backward compatibility
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
357
391
|
/**
|
|
358
392
|
* Close database connection
|
|
359
393
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-recall",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "Persistent memory for Claude Code with automatic capture, failure learning,
|
|
3
|
+
"version": "0.7.2",
|
|
4
|
+
"description": "Persistent memory for Claude Code with automatic capture, failure learning, sophistication tracking, and project scoping via MCP server",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"claude-recall": "dist/cli/claude-recall-cli.js"
|