claude-recall 0.22.0 → 0.22.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.
@@ -8,14 +8,14 @@ source: claude-recall
8
8
 
9
9
  # Preferences
10
10
 
11
- Auto-generated from 5 memories. Last updated: 2026-04-11.
11
+ Auto-generated from 5 memories. Last updated: 2026-04-14.
12
12
 
13
13
  ## Rules
14
14
 
15
- - Session test preference 1775902182248
16
- - Test preference 1775902182184-2
17
- - Test preference 1775902182184-1
18
- - Test preference 1775902182184-0
15
+ - Session test preference 1776172131422
16
+ - Test preference 1776172131359-2
17
+ - Test preference 1776172131359-1
18
+ - Test preference 1776172131359-0
19
19
  - Test memory content
20
20
 
21
21
  ---
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "topicId": "preferences",
3
- "sourceHash": "a383c0d6502023d06954eb49fcab8886dc5181d5e59666f6c74a381221e44f87",
3
+ "sourceHash": "37e19c67668ff4fdd21019d4837a36dc368138b8e4299bcff235fdaf84b5f028",
4
4
  "memoryCount": 5,
5
- "generatedAt": "2026-04-11T10:09:42.271Z",
5
+ "generatedAt": "2026-04-14T13:08:51.442Z",
6
6
  "memoryKeys": [
7
- "memory_1775902182249_x5rzzep7s",
8
- "memory_1775902182226_9uo2kaw57",
9
- "memory_1775902182211_pl5fzrb85",
10
- "memory_1775902182185_q6f9widp3",
11
- "memory_1775902182147_olowsptz3"
7
+ "memory_1776172131423_zdtbhf2vw",
8
+ "memory_1776172131396_d2s4cuyls",
9
+ "memory_1776172131378_1r9w9r7lq",
10
+ "memory_1776172131363_gqgkc4o6s",
11
+ "memory_1776172131318_dbwsryce8"
12
12
  ]
13
13
  }
package/README.md CHANGED
@@ -33,20 +33,33 @@ Your preferences, project structure, workflows, corrections, and coding style ar
33
33
 
34
34
  ### Install for Claude Code
35
35
 
36
+ #### First-time install
37
+
38
+ Run this **once** on your machine:
39
+
36
40
  ```bash
37
- # Install globally
38
41
  npm install -g claude-recall
42
+ ```
39
43
 
40
- # Set up hooks and skills in your project
41
- claude-recall setup --install
44
+ Then run these **in the project directory** where you want claude-recall active:
42
45
 
43
- # Register MCP server
46
+ ```bash
47
+ claude-recall setup --install
44
48
  claude mcp add claude-recall -- claude-recall mcp start
45
49
  ```
46
50
 
47
- Then restart your Claude Code session. For additional projects, only the last two commands are needed.
51
+ Restart Claude Code. **Verify**: ask *"Load my rules"* Claude should call `mcp__claude-recall__load_rules`.
52
+
53
+ #### Adding to another project
48
54
 
49
- **Verify:** Ask *"Load my rules"* Claude should call `mcp__claude-recall__load_rules`.
55
+ The global binary is already installed. Just `cd` into the new project and run the per-project commands:
56
+
57
+ ```bash
58
+ claude-recall setup --install
59
+ claude mcp add claude-recall -- claude-recall mcp start
60
+ ```
61
+
62
+ Restart Claude Code in that project.
50
63
 
51
64
  ### Install for Pi
52
65
 
@@ -64,36 +77,61 @@ Both agents use the same database (`~/.claude-recall/claude-recall.db`). Memorie
64
77
 
65
78
  ### Upgrading
66
79
 
80
+ #### If you use Claude Code
81
+
82
+ Run this **once** to update the global binary:
83
+
67
84
  ```bash
68
- # Claude Code — update binary + re-install hooks in each project
69
85
  npm install -g claude-recall
70
- claude-recall setup --install # run from each project directory
86
+ ```
87
+
88
+ Then run this **in each project directory** where you use claude-recall (the binary upgrade alone isn't enough — new releases sometimes add hook events that need to be registered in each project's `.claude/settings.json`):
71
89
 
72
- # Pi — must include the npm: prefix (matches the install command)
90
+ ```bash
91
+ claude-recall setup --install
92
+ ```
93
+
94
+ Restart Claude Code so the new MCP server starts (or run `claude-recall mcp restart` from the project directory to keep the current session running).
95
+
96
+ **Verify**: `claude-recall --version` shows the new version, and asking *"Load my rules"* in Claude Code triggers `mcp__claude-recall__load_rules`.
97
+
98
+ #### If you use Pi
99
+
100
+ Run this **once** — the `npm:` prefix is required (it matches the original install command):
101
+
102
+ ```bash
73
103
  pi update npm:claude-recall
74
104
  ```
75
105
 
76
- The MCP server picks up the new version automatically. `setup --install` is needed to update hooks in `.claude/settings.json` (new hook events may have been added).
106
+ Restart Pi to load the updated extension.
107
+
108
+ **Verify**: `pi list` shows the new `claude-recall` version, and asking *"Load my rules"* in Pi triggers `recall_load_rules`.
109
+
110
+ #### If you use both
111
+
112
+ Both upgrades are independent — run the Claude Code section AND the Pi section. Both agents share the same `~/.claude-recall/claude-recall.db`, so memories captured in either are visible to the other.
77
113
 
78
114
  ---
79
115
 
80
116
  ## What to Expect
81
117
 
82
- Once installed, Claude Recall works automatically in the background:
118
+ Once installed, Claude Recall works automatically in the background. Each row below is tagged with the runtime it applies to so you can skip what doesn't apply to you.
83
119
 
84
- 1. **Session start** active rules are loaded before the first action. In Claude Code, this happens via the `search_enforcer` hook; in Pi, rules are injected into the system prompt automatically
85
- 2. **As you work** — every prompt is classified for corrections and preferences. Natural statements like *"we use tabs here"* or *"no, put tests in `__tests__/`"* are detected and stored
86
- 3. **Tool outcomes** results from all tools (Bash, Edit, Write, and more) are captured. Failures are stored as memories; Bash failures are paired with successful fixes
87
- 4. **End of session** session episodes are created, candidate lessons extracted from failures, and a promotion cycle graduates validated patterns into active rules. A session extraction pass sends the last 50 transcript entries to Haiku to identify cause-and-effect patterns: what failed, why, and what fixed it
88
- 5. **Reask detection** — frustration signals ("still broken", "that didn't work") are recorded as outcome events
89
- 6. **Before context compression** aggressive memory sweep captures important context before the window shrinks
90
- 7. **After context compression** (Claude Code only) rules are automatically re-injected into context so they're not lost when the window shrinks
91
- 8. **Sub-agent recall** (Claude Code only) when sub-agents are spawned, active rules are injected into their context automatically. Sub-agent outcomes (completed/failed/killed) are captured as events
92
- 9. **Rules sync** (Claude Code only) top 30 rules are exported as typed `.md` files to Claude Code's native memory directory
93
- 10. **Auto-checkpoint on session exit** when a session ends (Pi shutdown or Claude Code's `SessionEnd` for `clear`/`prompt_input_exit`/`logout`), the most recent task is extracted via Haiku into a structured `{completed, remaining, blockers}` checkpoint and saved for the next session. Critical for Pi (which has no `--resume` flag); a useful safety net for Claude Code users who exit without resuming. Conservative quality gate refuses to save when the LLM detects the task was already complete — manual checkpoints are never clobbered with garbage
94
- 11. **Just-in-time rule injection (JITRI)** before each tool call (Claude Code) or each agent turn (Pi), the most relevant active rules are searched against `tool_name + tool_input + recent prompt` and injected as a `<system-reminder>` block immediately adjacent to the action. This closes the rule-loading gap: rules are no longer just loaded once at session start (where attention decays as context grows) — they're surfaced at the moment of decision. Each injection is recorded in `rule_injection_events` and resolved with the tool outcome via PostToolUse, replacing the broken citation-detection regex with direct measurement of "was the relevant rule present when the action happened?"
120
+ | When | What happens | CC | Pi |
121
+ |---|---|:-:|:-:|
122
+ | **Session start** | Active rules are loaded before the first action and injected into the agent's context | | |
123
+ | **As you work** | Every prompt is classified for corrections and preferences. Natural statements like *"we use tabs here"* are detected and stored | | |
124
+ | **Before each tool call / agent turn** | **Just-in-time rule injection** relevant rules are surfaced as a `<system-reminder>` block adjacent to the action so the agent sees them at the moment of decision (not 50,000 tokens upstream). Per-tool-call in CC; per-turn in Pi | ✓ | ✓ |
125
+ | **Tool outcomes** | Tool results (Bash, Edit, Write, etc.) are captured. Failures are stored; Bash failures are paired with their successful fixes | ✓ | ✓ |
126
+ | **Reask detection** | Frustration signals (*"still broken"*, *"that didn't work"*) are recorded as outcome events | | |
127
+ | **Before context compression** | Aggressive memory sweep captures important context before the window shrinks | | |
128
+ | **After context compression** | Rules are automatically re-injected into the new context so they're not lost | | |
129
+ | **Sub-agent spawned** | Active rules are injected into the sub-agent's context. Sub-agent outcomes (completed/failed/killed) are captured | | |
130
+ | **Rules sync** | Top 30 rules are exported as typed `.md` files to Claude Code's native memory directory | | |
131
+ | **Session exit** | **Auto-checkpoint** — the most recent task is extracted into a `{completed, remaining, blockers}` snapshot and saved for the next session. Critical for Pi (no `--resume` flag); safety net for CC users who exit without resuming | ✓ | ✓ |
132
+ | **End of session** | Session episodes are created, candidate lessons are extracted from failures, and validated patterns are promoted into active rules | ✓ | ✓ |
95
133
 
96
- Classification uses Claude Haiku (via `ANTHROPIC_API_KEY`) with silent regex fallback. No configuration needed.
134
+ Classification and checkpoint extraction use Claude Haiku (via `ANTHROPIC_API_KEY`) with silent regex fallback. No configuration needed.
97
135
 
98
136
  **Next session:** `load_rules` returns everything captured previously — the agent applies your preferences without being told twice.
99
137
 
@@ -121,24 +159,35 @@ Claude Recall provides four memory tools backed by a local SQLite database with
121
159
 
122
160
  ### Skills
123
161
 
124
- Claude Recall uses skill files to teach agents when and how to use memory tools:
162
+ Claude Recall uses skill files to teach agents when and how to use memory tools.
163
+
164
+ **Claude Code** uses Anthropic's [Agent Skills](https://agentskills.io/) open standard:
125
165
 
126
- - **Claude Code** — uses Anthropic's [Agent Skills](https://agentskills.io/) open standard. A core skill (`.claude/skills/memory-management/SKILL.md`) guides memory behavior with progressive disclosure. Auto-generated skills (`.claude/skills/auto-*/`) crystallize from accumulated memories. See Anthropic's [blog post](https://claude.com/blog/equipping-agents-for-the-real-world-with-agent-skills) for more.
127
- - **Pi**ships a `skills/memory-management.md` skill loaded via Pi's package manifest
166
+ - `.claude/skills/memory-management/SKILL.md` — core skill, guides memory behavior
167
+ - `.claude/skills/auto-*/`auto-generated, crystallized from accumulated memories
168
+
169
+ See Anthropic's [Agent Skills blog post](https://claude.com/blog/equipping-agents-for-the-real-world-with-agent-skills) for the standard.
170
+
171
+ **Pi** ships a single `skills/memory-management.md` loaded via Pi's package manifest. No setup needed.
128
172
 
129
173
  ### Outcome-Aware Learning
130
174
 
131
- Claude Recall tracks what happens *after* the agent acts — not just what was said. The outcome processing pipeline:
175
+ Claude Recall tracks what happens *after* the agent acts — not just what was said. The pipeline:
132
176
 
133
177
  ```
134
178
  action → outcome event → episode → candidate lesson → promotion → active rule
179
+
180
+ JIT-injected before next action
181
+
182
+ PostToolUse resolves outcome per rule
135
183
  ```
136
184
 
137
185
  - **Outcome events** capture results from all tool types (Bash, Edit, Write, MCP), test outcomes, user corrections, and reask signals
138
186
  - **Episodes** summarize entire sessions with outcome type, severity, and confidence
139
187
  - **Candidate lessons** are extracted from failure patterns — deduplicated by Jaccard similarity
140
- - **Promotion engine** graduates lessons into active rules after 2+ observations (or immediately for high-severity failures), and demotes never-helpful memories
141
- - **Outcome-aware retrieval** boosts memories with evidence, penalizes stale/unhelpful ones
188
+ - **Promotion engine** graduates lessons into active rules after 2+ observations (or immediately for high-severity failures)
189
+ - **Just-in-time rule injection (v0.22.0+)** active rules are surfaced as a `<system-reminder>` block adjacent to each tool call (Claude Code) or each agent turn (Pi). Each injection is recorded in `rule_injection_events` and resolved with the tool's success/failure outcome by the PostToolUse hook. **This is the meter that measures rule effectiveness in practice.** It replaces the older citation-detection regex (which empirically returned 0 citations across thousands of opportunities — agents don't reliably write `(applied from memory: …)` markers, so the meter never had data to work with).
190
+ - **Per-rule effectiveness data** accumulates over time in `rule_injection_events`. Future releases will use it to deboost rules that are repeatedly injected without correlating to successful tool calls, and to auto-promote rules that are repeatedly injected before failures. As of v0.22.0 the data is being collected; ranking is not yet feeding back from it.
142
191
 
143
192
  ---
144
193
 
@@ -204,17 +253,22 @@ Agents can also save/load checkpoints via MCP tools (`mcp__claude-recall__save_c
204
253
 
205
254
  Manual `checkpoint save` is the explicit path. **Auto-checkpoint** is the safety net: when a session ends, the most recent task is extracted into a checkpoint automatically so the next session can resume.
206
255
 
207
- - **Pi** fires from the `session_shutdown` event handler. In-process synchronous call, runs as part of the existing session-end pipeline. **Critical for Pi: there is no `pi --resume` equivalent, so without this, restarting Pi loses all session context.**
208
- - **Claude Code** — fires from the `SessionEnd` hook for voluntary exit reasons (`clear`, `prompt_input_exit`, `logout`). Spawns a detached background worker (fork+unref) so it stays well within Claude Code's tight 1.5s `SessionEnd` timeout. Skips `bypass_permissions_disabled` and `other` reasons (those are system-driven, not user intent). Useful for users who exit and start fresh instead of using `claude --resume`.
256
+ **When it fires:**
257
+
258
+ - **Pi** — every `session_shutdown` event. **This is the only way to recover context in Pi: there is no `pi --resume` equivalent.**
259
+ - **Claude Code** — voluntary `SessionEnd` reasons (`clear`, `prompt_input_exit`, `logout`). Skips `bypass_permissions_disabled` and `other` (system-driven exits, not user intent). Useful if you exit and start fresh instead of using `claude --resume`.
260
+
261
+ **Behavior (both runtimes):**
209
262
 
210
- Both runtimes share the same Haiku-backed extraction (`extractCheckpointWithLLM`) and the same quality gate:
263
+ - Uses Haiku to extract `{completed, remaining, blockers}` from the most recent task in the transcript
264
+ - **Quality gate**: refuses to save if the LLM detects the task was already complete (e.g., agent said "Done.", user said "thanks"). **Manual checkpoints are never overwritten with garbage** — an empty checkpoint is far better than a fabricated one
265
+ - **Tagged**: auto-saved checkpoints include `[auto-saved on <pi|cc> session exit at <iso-timestamp>]` in their notes field
266
+ - **Requires `ANTHROPIC_API_KEY`**. Without it, no auto-checkpoint is saved and manual `checkpoint save` still works
211
267
 
212
- - **Quality gate**: refuses to save if the LLM returns an empty or trivially-short `remaining` field. The model is prompted to detect completion signals (assistant said "Done.", user said "thanks", no follow-up question) and return empty `remaining` when the task is finished. **An empty checkpoint is far better than a fabricated one** — manual checkpoints are never overwritten with garbage.
213
- - **Notes tag**: auto-saved checkpoints include `[auto-saved on <pi|cc> session exit at <iso-timestamp>]` in the notes field, so you can tell auto from manual via `checkpoint load`.
214
- - **Requires `ANTHROPIC_API_KEY`**. Without it, `extractCheckpointWithLLM` returns `null` (graceful fallback) and no auto-checkpoint is saved. Manual `checkpoint save` still works.
215
- - **Disable**: remove the `SessionEnd` block from `.claude/settings.json` (Claude Code) or, for Pi, no per-project disable flag exists yet — open an issue if you need one.
268
+ **Disable:**
216
269
 
217
- The auto-checkpoint never clobbers a useful manual checkpoint because of the quality gate. If the LLM doesn't see clear unfinished work, it returns empty and the gate refuses the save. Manual checkpoints stay sticky until you explicitly save over them.
270
+ - **Claude Code**: remove the `SessionEnd` block from `.claude/settings.json`
271
+ - **Pi**: no per-project disable flag yet — [open an issue](https://github.com/raoulbia-ai/claude-recall/issues) if you need one
218
272
 
219
273
  ### Troubleshooting
220
274
 
@@ -274,6 +274,10 @@ class MemoryTools {
274
274
  ? metadata.type
275
275
  : 'preference';
276
276
  const key = `memory_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
277
+ const preferenceKey = typeof metadata?.preference_key === 'string' && metadata.preference_key.length > 0
278
+ ? metadata.preference_key
279
+ : undefined;
280
+ const isOverride = metadata?.isOverride === true;
277
281
  this.memoryService.store({
278
282
  key,
279
283
  value: {
@@ -288,8 +292,17 @@ class MemoryTools {
288
292
  projectId: scope === 'project' ? context.projectId : undefined,
289
293
  timestamp: context.timestamp,
290
294
  scope: scope || null
291
- }
295
+ },
296
+ preferenceKey,
297
+ isOverride
292
298
  });
299
+ // If this store overrides an existing rule, mark previous active rules with
300
+ // the same preference_key as superseded and surface their keys so the agent
301
+ // knows to ignore the stale text sitting higher up in its context.
302
+ let supersededKeys = [];
303
+ if (isOverride && preferenceKey) {
304
+ supersededKeys = this.memoryService.supersedeByPreferenceKey(preferenceKey, key, { sessionId: context.sessionId, projectId: context.projectId, timestamp: context.timestamp });
305
+ }
293
306
  this.logger.info('MemoryTools', 'Memory stored successfully', {
294
307
  key,
295
308
  type: detectedType,
@@ -320,6 +333,10 @@ class MemoryTools {
320
333
  activeRule: `Stored as active rule:\n- ${content}`,
321
334
  type: detectedType,
322
335
  _directive: 'Apply this rule immediately. No need to call load_rules again.',
336
+ ...(supersededKeys.length > 0 && {
337
+ supersededKeys,
338
+ _supersessionNotice: `Superseded ${supersededKeys.length} prior rule(s) for preference_key="${preferenceKey}". Ignore any earlier text from these rules still in your context: ${supersededKeys.join(', ')}`
339
+ }),
323
340
  ...(skillResults.length > 0 && {
324
341
  _skillsGenerated: skillResults
325
342
  .filter(r => r.action === 'created' || r.action === 'updated')
@@ -383,11 +400,21 @@ class MemoryTools {
383
400
  return `- ${val}`;
384
401
  }).join('\n'));
385
402
  }
386
- // Add compliance section for rules loaded frequently but never cited
403
+ // Add compliance section for rules loaded frequently but never cited.
404
+ // Cap at top 10 by load_count so load_rules stays slim — this diagnostic
405
+ // list was previously unbounded and could dominate the payload.
406
+ const RULE_HEALTH_CAP = 10;
387
407
  const compliance = this.memoryService.getComplianceReport(projectId || context.projectId);
388
- const lowCompliance = compliance.rules.filter(r => r.load_count >= 5 && r.cite_count === 0);
408
+ const allLowCompliance = compliance.rules.filter(r => r.load_count >= 5 && r.cite_count === 0);
409
+ const lowCompliance = [...allLowCompliance]
410
+ .sort((a, b) => (b.load_count || 0) - (a.load_count || 0))
411
+ .slice(0, RULE_HEALTH_CAP);
412
+ const hiddenCount = allLowCompliance.length - lowCompliance.length;
389
413
  if (lowCompliance.length > 0) {
390
- sections.push('## Rule Health\nThese rules are loaded frequently but never cited — consider rewording or removing:\n' +
414
+ const heading = hiddenCount > 0
415
+ ? `## Rule Health (top ${RULE_HEALTH_CAP} of ${allLowCompliance.length})\nThese rules are loaded frequently but never cited — consider rewording or removing. ${hiddenCount} more hidden; run \`npx claude-recall outcomes\` to see all.`
416
+ : '## Rule Health\nThese rules are loaded frequently but never cited — consider rewording or removing:';
417
+ sections.push(heading + '\n' +
391
418
  lowCompliance.map(r => {
392
419
  let val;
393
420
  if (typeof r.value === 'string') {
@@ -562,6 +562,23 @@ class MemoryStorage {
562
562
  const stmt = this.db.prepare(`UPDATE memories SET ${setClause} WHERE key = ?`);
563
563
  stmt.run(...values, key);
564
564
  }
565
+ /**
566
+ * Get active memories (any type) that share the given preference_key.
567
+ * Used by store_memory's override path — a user can override a rule of any
568
+ * type (devops, correction, preference) as long as it was stored with a
569
+ * preference_key.
570
+ */
571
+ getActiveByPreferenceKeyAnyType(preferenceKey, projectId) {
572
+ let query = 'SELECT * FROM memories WHERE preference_key = ? AND is_active = 1';
573
+ const params = [preferenceKey];
574
+ if (projectId) {
575
+ query += ' AND (project_id = ? OR project_id IS NULL)';
576
+ params.push(projectId);
577
+ }
578
+ query += ' ORDER BY timestamp DESC';
579
+ const rows = this.db.prepare(query).all(...params);
580
+ return rows.map(row => this.rowToMemory(row));
581
+ }
565
582
  /**
566
583
  * Get preferences by preference key
567
584
  */
@@ -43,7 +43,9 @@ class MemoryService {
43
43
  file_path: request.context?.filePath,
44
44
  timestamp: request.context?.timestamp || Date.now(),
45
45
  relevance_score: request.relevanceScore || 1.0,
46
- scope: scope
46
+ scope: scope,
47
+ preference_key: request.preferenceKey,
48
+ is_active: true
47
49
  };
48
50
  this.storage.save(memory);
49
51
  this.logger.logMemoryOperation('STORE', {
@@ -303,6 +305,30 @@ class MemoryService {
303
305
  throw error;
304
306
  }
305
307
  }
308
+ /**
309
+ * Mark all currently-active memories with the given preference_key as superseded by newKey.
310
+ * Returns the list of superseded keys so callers can surface them to the agent — this
311
+ * closes the "I stored an override but the old rule is still in my context" gap.
312
+ */
313
+ supersedeByPreferenceKey(preferenceKey, newKey, context) {
314
+ if (!preferenceKey || !newKey)
315
+ return [];
316
+ const superseded = [];
317
+ try {
318
+ const pid = context.projectId || this.config.getProjectId();
319
+ const existing = this.storage.getActiveByPreferenceKeyAnyType(preferenceKey, pid);
320
+ for (const prev of existing) {
321
+ if (prev.key !== newKey) {
322
+ this.storage.markSuperseded(prev.key, newKey);
323
+ superseded.push(prev.key);
324
+ }
325
+ }
326
+ }
327
+ catch (error) {
328
+ this.logger.logServiceError('MemoryService', 'supersedeByPreferenceKey', error, { preferenceKey, newKey });
329
+ }
330
+ return superseded;
331
+ }
306
332
  /**
307
333
  * Mark existing preferences as superseded
308
334
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-recall",
3
- "version": "0.22.0",
3
+ "version": "0.22.2",
4
4
  "description": "Persistent memory for Claude Code and Pi with native Skills integration, automatic capture, failure learning, and project scoping",
5
5
  "main": "dist/index.js",
6
6
  "bin": {