Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit ea782bc

Browse files
committed
docs(skills): update memory-recall skill examples
- Update example scripts for current API - Improve search-optimization reference docs
1 parent 8fa61d5 commit ea782bc

4 files changed

Lines changed: 114 additions & 65 deletions

File tree

skills/memory-recall/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ from git_notes_memory import get_recall_service
5454
recall = get_recall_service()
5555
results = recall.search(
5656
query='''$EXTRACTED_CONCEPTS''',
57-
limit=5,
58-
threshold=0.7 # Only high-relevance results
57+
k=5,
58+
min_similarity=0.7 # Only high-relevance results
5959
)
6060
6161
for r in results:
62-
print(f'{r.namespace}: {r.title or r.content[:50]} (score: {r.score:.2f})')
62+
print(f'{r.namespace}: {r.summary} (score: {r.score:.2f})')
6363
"
6464
```
6565

skills/memory-recall/examples/auto-recall.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def auto_recall(
106106
results = recall.search(
107107
query=query,
108108
namespace=namespace,
109-
limit=limit * 2 # Get more, then filter by threshold
109+
k=limit * 2 # Get more, then filter by threshold
110110
)
111111

112112
# Step 4: Filter by threshold
@@ -128,8 +128,7 @@ def format_results(recall_result: dict) -> str:
128128
lines = [f"**Relevant Memories Found** ({len(recall_result['results'])} matches)\n"]
129129

130130
for i, r in enumerate(recall_result['results'], 1):
131-
summary = r.title or r.content[:50]
132-
lines.append(f"{i}. **{r.namespace.title()}** ({r.score:.2f}): {summary}")
131+
lines.append(f"{i}. **{r.namespace.title()}** ({r.score:.2f}): {r.summary}")
133132

134133
lines.append("\n_Use `/memory:recall` for details or `/memory:search` for custom queries._")
135134

skills/memory-recall/examples/filtered-search.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def search_by_namespace(
4444
return recall.search(
4545
query=query,
4646
namespace=namespace,
47-
limit=limit
47+
k=limit
4848
)
4949

5050

@@ -88,7 +88,7 @@ def search_with_filters(
8888
# Multi-namespace search
8989
all_results = []
9090
for ns in filters.namespaces:
91-
results = recall.search(query=query, namespace=ns, limit=limit)
91+
results = recall.search(query=query, namespace=ns, k=limit)
9292
all_results.extend(results)
9393
# Sort by score and deduplicate
9494
seen_ids = set()
@@ -101,10 +101,10 @@ def search_with_filters(
101101
results = recall.search(
102102
query=query,
103103
namespace=filters.namespace,
104-
limit=limit * 2 # Get more for filtering
104+
k=limit * 2 # Get more for filtering
105105
)
106106
else:
107-
results = recall.search(query=query, limit=limit * 2)
107+
results = recall.search(query=query, k=limit * 2)
108108

109109
# Apply additional filters
110110
filtered = []
@@ -113,11 +113,10 @@ def search_with_filters(
113113
if r.score < filters.min_score:
114114
continue
115115

116-
# Date filters
117-
created = datetime.fromisoformat(r.created_at)
118-
if filters.since and created < filters.since:
116+
# Date filters (timestamp is already a datetime object)
117+
if filters.since and r.timestamp < filters.since:
119118
continue
120-
if filters.until and created > filters.until:
119+
if filters.until and r.timestamp > filters.until:
121120
continue
122121

123122
# Tag filter
@@ -184,7 +183,7 @@ def cross_namespace_search(
184183
results = recall.search(
185184
query=query,
186185
namespace=ns,
187-
limit=limit_per_namespace
186+
k=limit_per_namespace
188187
)
189188
if results:
190189
results_by_namespace[ns] = results
@@ -201,8 +200,7 @@ def format_cross_namespace_results(results: dict) -> str:
201200
for namespace, memories in results.items():
202201
lines.append(f"\n### {namespace.title()} ({len(memories)} found)")
203202
for i, m in enumerate(memories, 1):
204-
summary = m.title or m.content[:50]
205-
lines.append(f" {i}. {summary} ({m.score:.2f})")
203+
lines.append(f" {i}. {m.summary} ({m.score:.2f})")
206204

207205
return '\n'.join(lines)
208206

@@ -213,13 +211,13 @@ def format_cross_namespace_results(results: dict) -> str:
213211
print("=== Decision Search ===")
214212
decisions = search_decisions("database")
215213
for d in decisions:
216-
print(f" - {d.title}: {d.score:.2f}")
214+
print(f" - {d.summary}: {d.score:.2f}")
217215

218216
# Example 2: Search with date filter
219217
print("\n=== Recent Learnings (7 days) ===")
220218
recent = search_recent("error handling", days=7, namespace='learnings')
221219
for r in recent:
222-
print(f" - {r.title}: {r.created_at[:10]}")
220+
print(f" - {r.summary}: {r.timestamp.strftime('%Y-%m-%d')}")
223221

224222
# Example 3: Cross-namespace search
225223
print("\n=== Cross-Namespace: Authentication ===")
@@ -234,4 +232,4 @@ def format_cross_namespace_results(results: dict) -> str:
234232
print("\n=== Tagged: API + Security ===")
235233
tagged = search_by_tags(['api', 'security'], limit=5)
236234
for t in tagged:
237-
print(f" - {t.namespace}: {t.title}")
235+
print(f" - {t.namespace}: {t.summary}")

skills/memory-recall/references/search-optimization.md

Lines changed: 97 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,30 @@
22

33
Advanced techniques for optimizing memory recall queries.
44

5-
## Query Expansion
5+
## Semantic vs Text Search
66

7-
Improve recall by expanding queries with related terms:
7+
The library provides two search modes:
88

99
```python
1010
from git_notes_memory import get_recall_service
11-
from git_notes_memory.search import get_optimizer
1211

1312
recall = get_recall_service()
14-
optimizer = get_optimizer()
1513

16-
# Original query
17-
query = "database connection"
14+
# Semantic search (vector similarity) - best for conceptual queries
15+
results = recall.search("authentication flow", k=10)
1816

19-
# Expanded with related terms
20-
expanded = optimizer.expand_query(query)
21-
# Result: "database connection pool timeout postgres sql"
22-
23-
results = recall.search(expanded, limit=10)
17+
# Text search (FTS5 keyword matching) - best for exact terms
18+
results = recall.search_text("JWT token", limit=10)
2419
```
2520

26-
## Hybrid Search Strategy
27-
28-
Combine semantic and keyword search for best results:
29-
30-
```python
31-
from git_notes_memory.search import get_optimizer
32-
33-
optimizer = get_optimizer()
34-
35-
# Hybrid search combines:
36-
# 1. Vector similarity (semantic meaning)
37-
# 2. BM25 keyword matching (exact terms)
38-
# 3. Recency weighting (newer memories preferred)
39-
40-
results = optimizer.search(
41-
query="authentication JWT tokens",
42-
semantic_weight=0.6, # 60% semantic
43-
keyword_weight=0.3, # 30% keyword
44-
recency_weight=0.1, # 10% recency
45-
limit=10
46-
)
47-
```
21+
| Mode | Method | Best For |
22+
|------|--------|----------|
23+
| Semantic | `search()` | Conceptual queries, finding related ideas |
24+
| Text | `search_text()` | Exact terms, specific identifiers |
4825

4926
## Threshold Tuning
5027

51-
Adjust relevance thresholds based on context:
28+
Adjust relevance thresholds based on context using `min_similarity`:
5229

5330
| Scenario | Threshold | Rationale |
5431
|----------|-----------|-----------|
@@ -58,6 +35,20 @@ Adjust relevance thresholds based on context:
5835
| Troubleshooting | 0.55 | Include related issues |
5936

6037
```python
38+
# High precision for direct questions
39+
results = recall.search(
40+
query="why did we choose PostgreSQL",
41+
k=5,
42+
min_similarity=0.8
43+
)
44+
45+
# Broader search for exploration
46+
results = recall.search(
47+
query="database",
48+
k=10,
49+
min_similarity=0.5
50+
)
51+
6152
# Dynamic threshold based on query type
6253
def get_threshold(query_type):
6354
thresholds = {
@@ -77,22 +68,57 @@ Target specific memory types for faster, more relevant results:
7768
# For decision inquiries
7869
results = recall.search(
7970
query="why redis",
80-
namespace="decisions",
81-
limit=5
71+
k=5,
72+
namespace="decisions"
8273
)
8374

8475
# For troubleshooting
8576
results = recall.search(
8677
query="timeout error",
87-
namespace="learnings",
88-
limit=10
78+
k=10,
79+
namespace="learnings"
8980
)
9081

91-
# Multi-namespace search
82+
# For spec-specific context
9283
results = recall.search(
93-
query="database",
84+
query="authentication",
85+
k=10,
86+
namespace="decisions",
87+
spec="my-project"
88+
)
89+
```
90+
91+
## Multi-Namespace Search
92+
93+
To search across multiple namespaces, query each and merge results:
94+
95+
```python
96+
def search_multiple_namespaces(query, namespaces, k_per_ns=5):
97+
"""Search across multiple namespaces, merging results."""
98+
all_results = []
99+
100+
for ns in namespaces:
101+
results = recall.search(query=query, namespace=ns, k=k_per_ns)
102+
all_results.extend(results)
103+
104+
# Sort by score (lower distance = better)
105+
all_results.sort(key=lambda r: r.distance)
106+
107+
# Deduplicate by ID
108+
seen = set()
109+
unique = []
110+
for r in all_results:
111+
if r.id not in seen:
112+
seen.add(r.id)
113+
unique.append(r)
114+
115+
return unique
116+
117+
# Example: search decisions and patterns together
118+
results = search_multiple_namespaces(
119+
"database",
94120
namespaces=["decisions", "patterns"],
95-
limit=10
121+
k_per_ns=5
96122
)
97123
```
98124

@@ -110,7 +136,7 @@ def format_for_context(memories, max_chars=500):
110136
content = content[:max_chars] + "..."
111137
formatted.append({
112138
'type': m.namespace,
113-
'summary': m.title or content[:50],
139+
'summary': m.summary,
114140
'score': m.score,
115141
'content': content
116142
})
@@ -125,9 +151,10 @@ Cache frequent queries for faster recall:
125151
from functools import lru_cache
126152

127153
@lru_cache(maxsize=100)
128-
def cached_search(query, namespace=None, limit=5):
154+
def cached_search(query, namespace=None, k=5):
129155
recall = get_recall_service()
130-
return recall.search(query, namespace=namespace, limit=limit)
156+
# Convert results to tuple for hashability
157+
return tuple(recall.search(query, namespace=namespace, k=k))
131158

132159
# Clear cache when new memories added
133160
def on_memory_captured():
@@ -142,6 +169,7 @@ Monitor search performance:
142169
import time
143170

144171
def timed_search(query, **kwargs):
172+
recall = get_recall_service()
145173
start = time.time()
146174
results = recall.search(query, **kwargs)
147175
duration = time.time() - start
@@ -157,7 +185,31 @@ def timed_search(query, **kwargs):
157185
## Best Practices
158186

159187
1. **Start specific, then broaden**: Begin with focused queries, expand if no results
160-
2. **Use namespace hints**: When query implies a type (e.g., "why" decisions)
188+
2. **Use namespace hints**: When query implies a type (e.g., "why" -> decisions)
161189
3. **Limit results**: Surface 3-5 highly relevant memories, not all matches
162190
4. **Cache common queries**: Project-specific terms are queried repeatedly
163191
5. **Monitor relevance**: Track which recalled memories users actually reference
192+
6. **Use appropriate search mode**: Semantic for concepts, text for exact matches
193+
7. **Combine with hydration**: Use `recall_context()` for search + hydration in one call
194+
195+
## Convenience Methods
196+
197+
The RecallService provides convenience methods for common patterns:
198+
199+
```python
200+
# Search and hydrate in one call
201+
from git_notes_memory.models import HydrationLevel
202+
203+
hydrated = recall.recall_context(
204+
query="error handling",
205+
k=5,
206+
hydration_level=HydrationLevel.FULL
207+
)
208+
209+
# Find similar memories
210+
memory = recall.get("decisions:abc123:0")
211+
similar = recall.recall_similar(memory, k=3)
212+
213+
# List recent memories
214+
recent = recall.list_recent(limit=10, namespace="learnings")
215+
```

0 commit comments

Comments
 (0)