claude-recall 0.8.21 → 0.8.23

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.
File without changes
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ User Prompt Reminder Hook for Claude Recall.
4
+
5
+ Injects a visible reminder into Claude's context on every user prompt,
6
+ encouraging memory search before responding.
7
+
8
+ This hook outputs to stdout (exit 0) which Claude sees in its context.
9
+
10
+ Exit codes:
11
+ - 0: Always allow (non-blocking, but reminder is visible)
12
+ """
13
+ import json
14
+ import sys
15
+
16
+
17
+ def extract_keywords(prompt: str) -> str:
18
+ """Extract meaningful keywords from prompt for suggested search."""
19
+ # Common words to filter out
20
+ stop_words = {
21
+ 'a', 'an', 'the', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
22
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
23
+ 'should', 'may', 'might', 'must', 'can', 'to', 'of', 'in', 'for',
24
+ 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'through', 'during',
25
+ 'before', 'after', 'above', 'below', 'between', 'under', 'again',
26
+ 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why',
27
+ 'how', 'all', 'each', 'few', 'more', 'most', 'other', 'some', 'such',
28
+ 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very',
29
+ 's', 't', 'just', 'don', 'now', 'i', 'me', 'my', 'we', 'you', 'your',
30
+ 'it', 'its', 'this', 'that', 'these', 'those', 'what', 'which', 'who',
31
+ 'please', 'help', 'want', 'need', 'like', 'make', 'get', 'let', 'put'
32
+ }
33
+
34
+ # Extract words, filter stop words, take first 4 meaningful words
35
+ words = prompt.lower().split()
36
+ keywords = [w.strip('.,!?;:\'"()[]{}') for w in words if w.lower() not in stop_words]
37
+ keywords = [w for w in keywords if len(w) > 2] # Filter short words
38
+
39
+ return ' '.join(keywords[:4]) if keywords else 'preferences patterns'
40
+
41
+
42
+ def main():
43
+ try:
44
+ hook_data = json.load(sys.stdin)
45
+ prompt = hook_data.get('prompt', '') or hook_data.get('content', '') or ''
46
+
47
+ # Skip if prompt is very short (likely a typo or continuation)
48
+ if len(prompt.strip()) < 5:
49
+ sys.exit(0)
50
+
51
+ # Extract keywords for suggested search
52
+ keywords = extract_keywords(prompt)
53
+
54
+ # Output reminder (Claude will see this)
55
+ reminder = f"""<user-prompt-submit-hook>
56
+ šŸ” Search memories before responding: mcp__claude-recall__search("{keywords}")
57
+ </user-prompt-submit-hook>"""
58
+
59
+ print(reminder)
60
+ sys.exit(0)
61
+
62
+ except json.JSONDecodeError:
63
+ sys.exit(0)
64
+ except Exception:
65
+ sys.exit(0)
66
+
67
+
68
+ if __name__ == '__main__':
69
+ main()
@@ -27,6 +27,10 @@
27
27
  "UserPromptSubmit": [
28
28
  {
29
29
  "hooks": [
30
+ {
31
+ "type": "command",
32
+ "command": "python3 /home/ebiarao/repos-wsl/personal-projects/claude-recall/.claude/hooks/user_prompt_reminder.py"
33
+ },
30
34
  {
31
35
  "type": "command",
32
36
  "command": "python3 /home/ebiarao/repos-wsl/personal-projects/claude-recall/.claude/hooks/pubnub_prompt_hook.py"
@@ -34,5 +38,6 @@
34
38
  ]
35
39
  }
36
40
  ]
37
- }
38
- }
41
+ },
42
+ "hooksVersion": "0.8.23"
43
+ }
package/README.md CHANGED
@@ -9,7 +9,7 @@ Your preferences, project structure, workflows, corrections, and coding style ar
9
9
 
10
10
  > **TL;DR**
11
11
  > Claude Recall stores and searches your past preferences and project knowledge.
12
- > Install it → restart Claude Code → Claude automatically uses memory before writing or editing files.
12
+ > Install it → restart Claude Code → Claude is reminded to search memory on every turn.
13
13
 
14
14
  ---
15
15
 
@@ -151,12 +151,11 @@ Switch projects → Claude switches memory.
151
151
  Claude Recall integrates tightly via:
152
152
 
153
153
  * MCP server (search, store, evolve)
154
- * pre-action hooks
155
- * planning hooks
156
- * post-action hooks
154
+ * UserPromptSubmit hooks (reminder on every turn)
155
+ * PreToolUse hooks (enforce search before Write/Edit)
157
156
  * PubNub event subscriber (Memory Agent)
158
157
 
159
- Claude automatically searches memory before writing or editing files.
158
+ Claude sees a memory search reminder on every conversation turn, with suggested keywords extracted from your prompt.
160
159
 
161
160
  ---
162
161
 
@@ -186,59 +185,52 @@ npx claude-recall --version
186
185
  npx claude-recall setup
187
186
  ```
188
187
 
189
- ### Upgrade (existing users)
190
-
191
- npm doesn't run postinstall on version upgrades, so hooks/skills won't update automatically.
188
+ ### Upgrade
192
189
 
193
190
  ```bash
194
- # Option 1: Uninstall and reinstall (recommended)
195
- npm uninstall claude-recall && npm install claude-recall@latest
196
-
197
- # Option 2: Manually install hooks/skills after upgrade
198
191
  npm install claude-recall@latest
199
- npx claude-recall setup --install
192
+ npx claude-recall repair
200
193
  ```
201
194
 
195
+ This updates the package and repairs hooks/skills to the latest version.
196
+
202
197
  ---
203
198
 
204
199
  ### Activate
205
200
 
206
201
  ```bash
207
- # Add to your MCP config (if not already):
202
+ # Register MCP server:
208
203
  claude mcp add claude-recall -- npx -y claude-recall@latest mcp start
209
204
 
210
- # Already registered? Remove and re-add:
211
- claude mcp remove claude-recall
212
- claude mcp add claude-recall -- npx -y claude-recall@latest mcp start
213
-
214
- # Then restart your terminal or session
205
+ # Restart your terminal or Claude Code session
215
206
  ```
216
207
 
217
- ### Stop old instance
208
+ Already registered? Remove first: `claude mcp remove claude-recall`
218
209
 
219
- If an old MCP server is already running:
210
+ ---
220
211
 
221
- ```bash
222
- npx -y claude-recall@latest mcp stop
223
- ```
212
+ ### Automatic Capture (Optional)
224
213
 
225
- Then restart your session - it will automatically start the latest version.
214
+ For automatic preference/pattern capture from conversations, start the Memory Agent:
226
215
 
227
- ---
216
+ ```bash
217
+ npx claude-recall agent start
218
+ ```
228
219
 
229
- ### Verify it's working
220
+ The Memory Agent:
221
+ - Listens to conversation events via PubNub
222
+ - Extracts preferences ("I prefer TypeScript", "always use Jest")
223
+ - Stores learnings automatically
230
224
 
231
- In Claude Code:
225
+ Without the agent, you can still manually store memories via MCP tools.
232
226
 
233
- > "Search my memories."
227
+ ---
234
228
 
235
- Claude should call:
229
+ ### Verify
236
230
 
237
- ```
238
- mcp__claude-recall__search
239
- ```
231
+ In Claude Code, ask: *"Search my memories"*
240
232
 
241
- If results appear → You're ready.
233
+ Claude should call `mcp__claude-recall__search`. If it works → you're ready.
242
234
 
243
235
  ---
244
236
 
@@ -567,7 +567,7 @@ async function main() {
567
567
  }
568
568
  }
569
569
  // Install hooks and skills to current project
570
- function installHooksAndSkills() {
570
+ function installHooksAndSkills(force = false) {
571
571
  const cwd = process.cwd();
572
572
  const projectName = path.basename(cwd);
573
573
  console.log('\nšŸ“¦ Installing Claude Recall hooks and skills...\n');
@@ -589,7 +589,8 @@ async function main() {
589
589
  'mcp_tool_tracker.py',
590
590
  'pre_tool_search_enforcer.py',
591
591
  'pubnub_pre_tool_hook.py',
592
- 'pubnub_prompt_hook.py'
592
+ 'pubnub_prompt_hook.py',
593
+ 'user_prompt_reminder.py'
593
594
  ];
594
595
  let hooksInstalled = 0;
595
596
  for (const script of hookScripts) {
@@ -614,9 +615,13 @@ async function main() {
614
615
  const settingsContent = fs.readFileSync(settingsPath, 'utf8');
615
616
  settings = JSON.parse(settingsContent);
616
617
  }
617
- // Add hook configuration if not already present
618
- // Use ABSOLUTE paths so hooks work from any subdirectory
619
- if (!settings.hooks) {
618
+ // Version-based hook configuration
619
+ // Update hooks if: no hooks, older version, or force flag
620
+ const CURRENT_HOOKS_VERSION = '0.8.23';
621
+ const needsUpdate = force || !settings.hooks || settings.hooksVersion !== CURRENT_HOOKS_VERSION;
622
+ if (needsUpdate) {
623
+ // Use ABSOLUTE paths so hooks work from any subdirectory
624
+ settings.hooksVersion = CURRENT_HOOKS_VERSION;
620
625
  settings.hooks = {
621
626
  PreToolUse: [
622
627
  {
@@ -647,6 +652,10 @@ async function main() {
647
652
  UserPromptSubmit: [
648
653
  {
649
654
  hooks: [
655
+ {
656
+ type: "command",
657
+ command: `python3 ${path.join(hooksDir, 'user_prompt_reminder.py')}`
658
+ },
650
659
  {
651
660
  type: "command",
652
661
  command: `python3 ${path.join(hooksDir, 'pubnub_prompt_hook.py')}`
@@ -660,9 +669,12 @@ async function main() {
660
669
  console.log(' → PreToolUse (mcp__claude-recall__*): Tracks search calls');
661
670
  console.log(' → PreToolUse (Write|Edit): Enforces memory search first');
662
671
  console.log(' → UserPromptSubmit: Captures prompts for preference extraction');
672
+ if (force) {
673
+ console.log(' → Force flag: overwrote existing configuration');
674
+ }
663
675
  }
664
676
  else {
665
- console.log('ā„¹ļø Hooks already configured in .claude/settings.json (skipped)');
677
+ console.log(`ā„¹ļø Hooks already at version ${CURRENT_HOOKS_VERSION} (skipped)`);
666
678
  }
667
679
  // Copy skills directory
668
680
  if (fs.existsSync(packageSkillsDir)) {
@@ -712,9 +724,10 @@ async function main() {
712
724
  // Repair command - simple alias for setup --install
713
725
  program
714
726
  .command('repair')
715
- .description('Repair broken or missing hooks and skills (same as setup --install)')
716
- .action(() => {
717
- installHooksAndSkills();
727
+ .description('Repair broken or missing hooks and skills')
728
+ .option('--force', 'Force overwrite existing hook configuration')
729
+ .action((options) => {
730
+ installHooksAndSkills(options.force || false);
718
731
  process.exit(0);
719
732
  });
720
733
  // Check hooks function
@@ -117,8 +117,9 @@ class AgentCommands {
117
117
  console.log(chalk_1.default.gray(`šŸ’” Use ${chalk_1.default.cyan('npx claude-recall agent logs')} to view logs`));
118
118
  console.log(chalk_1.default.gray(`šŸ’” Use ${chalk_1.default.cyan('npx claude-recall agent status')} to check status`));
119
119
  console.log();
120
- // Wait a bit to ensure startup
121
- await new Promise((resolve) => setTimeout(resolve, 1000));
120
+ // Wait a bit to ensure startup, then exit cleanly
121
+ await new Promise((resolve) => setTimeout(resolve, 500));
122
+ process.exit(0);
122
123
  }
123
124
  /**
124
125
  * Stop the memory agent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-recall",
3
- "version": "0.8.21",
3
+ "version": "0.8.23",
4
4
  "description": "Persistent memory for Claude Code with fire-and-forget PubNub architecture, automatic capture, failure learning, and project scoping via MCP server",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -138,7 +138,8 @@ try {
138
138
  'mcp_tool_tracker.py',
139
139
  'pre_tool_search_enforcer.py',
140
140
  'pubnub_pre_tool_hook.py',
141
- 'pubnub_prompt_hook.py'
141
+ 'pubnub_prompt_hook.py',
142
+ 'user_prompt_reminder.py'
142
143
  ];
143
144
 
144
145
  for (const script of hookScripts) {
@@ -163,9 +164,14 @@ try {
163
164
  settings = JSON.parse(settingsContent);
164
165
  }
165
166
 
166
- // Add hook configuration if not already present
167
- // Use ABSOLUTE paths so hooks work from any subdirectory
168
- if (!settings.hooks) {
167
+ // Version-based hook configuration
168
+ // Update hooks if: no hooks, or older version
169
+ const CURRENT_HOOKS_VERSION = '0.8.23';
170
+ const needsUpdate = !settings.hooks || settings.hooksVersion !== CURRENT_HOOKS_VERSION;
171
+
172
+ if (needsUpdate) {
173
+ // Use ABSOLUTE paths so hooks work from any subdirectory
174
+ settings.hooksVersion = CURRENT_HOOKS_VERSION;
169
175
  settings.hooks = {
170
176
  PreToolUse: [
171
177
  {
@@ -196,6 +202,10 @@ try {
196
202
  UserPromptSubmit: [
197
203
  {
198
204
  hooks: [
205
+ {
206
+ type: "command",
207
+ command: `python3 ${path.join(hooksDir, 'user_prompt_reminder.py')}`
208
+ },
199
209
  {
200
210
  type: "command",
201
211
  command: `python3 ${path.join(hooksDir, 'pubnub_prompt_hook.py')}`
@@ -210,6 +220,11 @@ try {
210
220
  console.log(' → PreToolUse (mcp__claude-recall__*): Tracks search calls');
211
221
  console.log(' → PreToolUse (Write|Edit): Enforces memory search first');
212
222
  console.log(' → UserPromptSubmit: Captures prompts for preference extraction');
223
+ if (settings.hooksVersion) {
224
+ console.log(` → Updated from previous version to ${CURRENT_HOOKS_VERSION}`);
225
+ }
226
+ } else {
227
+ console.log(`ā„¹ļø Hooks already at version ${CURRENT_HOOKS_VERSION} (skipped)`);
213
228
  }
214
229
 
215
230
  // Copy skills directory (packageSkillsDir defined above)