Skip to content

Commit 093dab5

Browse files
phernandezphernandez
andauthored
feat: Add enhanced prompts and resources (#15)
## Summary - Add comprehensive documentation to all MCP prompt modules - Enhance search prompt with detailed contextual output formatting - Implement consistent logging and docstring patterns across prompt utilities - Fix type checking in prompt modules ## Prompts Added/Enhanced - `search.py`: New formatted output with relevance scores, excerpts, and next steps - `recent_activity.py`: Enhanced with better metadata handling and documentation - `continue_conversation.py`: Improved context management ## Resources Added/Enhanced - `ai_assistant_guide`: Resource with description to give to LLM to understand how to use the tools ## Technical improvements - Added detailed docstrings to all prompt modules explaining their purpose and usage - Enhanced the search prompt with rich contextual output that helps LLMs understand results - Created a consistent pattern for formatting output across prompts - Improved error handling in metadata extraction - Standardized import organization and naming conventions - Fixed various type checking issues across the codebase This PR is part of our ongoing effort to improve the MCP's interaction quality with LLMs, making the system more helpful and intuitive for AI assistants to navigate knowledge bases. 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: phernandez <phernandez@basicmachines.co>
1 parent 0d7b0b3 commit 093dab5

36 files changed

Lines changed: 1755 additions & 355 deletions

CLAUDE.md

Lines changed: 465 additions & 0 deletions
Large diffs are not rendered by default.

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ format:
2727
uv run ruff format .
2828

2929
# run inspector tool
30-
run-dev:
30+
run-inspector:
3131
uv run mcp dev src/basic_memory/mcp/main.py
3232

3333
# Build app installer
@@ -40,7 +40,7 @@ installer-win:
4040

4141

4242
update-deps:
43-
uv lock f--upgrade
43+
uv lock --upgrade
4444

4545
check: lint format type-check test
4646

data/ai_assistant_guide.md

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
# AI Assistant Guide
2+
3+
This guide explains how to use Basic Memory's tools effectively when working with users.
4+
It explains how to read, write, and navigate knowledge through the Model Context Protocol (MCP).
5+
6+
## Overview
7+
8+
Basic Memory allows users and LLMs to record context in local files using plain text Markdown formats to build a rich,
9+
organized knowledge base through natural conversations and simple tools.
10+
11+
- LLMs can read and write notes
12+
- Users can see content in real time
13+
- Simple Markdown formats are parsed to create a semantic knowledge graph
14+
- All data is local and stored in plain text files on the user's computer
15+
- Files can be updated externally and synced back to the knowledge base
16+
17+
## Core Tools
18+
19+
Basic Memory provides several tools through the MCP (Model Context Protocol) for LLMs:
20+
21+
```python
22+
# Writing knowledge
23+
response = await write_note(
24+
title="Search Design",
25+
content=content,
26+
folder="specs",
27+
tags=["search", "design"],
28+
verbose=True # Get parsing details
29+
)
30+
31+
# Reading knowledge
32+
content = await read_note("Search Design") # By title
33+
content = await read_note("specs/search") # By path
34+
content = await read_note("memory://specs/search") # By memory url
35+
36+
# Building context
37+
context = await build_context("memory://specs/search")
38+
39+
# Following relations
40+
impl = await build_context("memory://specs/search/implements/*")
41+
42+
# Checking changes
43+
activity = await recent_activity(timeframe="1 week")
44+
45+
# Creating a json canvas diagram
46+
activity = await canvas(...)
47+
48+
```
49+
50+
## Semantic Markup in Plain Text
51+
52+
Knowledge is encoded within standard markdown using semantic conventions that are both human-readable and
53+
machine-processable.
54+
55+
**Key aspects:**
56+
57+
- Files in the knowledge base are each an `Entity` within the system
58+
- Markdown files can contain semantic content through simple markup.
59+
- `Observations` as categorized list items
60+
- `Relations` as wiki-style links with types
61+
- Frontmatter for metadata
62+
- Minimal specialized syntax
63+
64+
**Examples:**
65+
66+
- Observation syntax: `- [category] Content text #tag1 #tag2 (optional context)`
67+
- Relation syntax: `- relation_type [[Entity]] (optional context)`
68+
- Inline relations through `[[Entity]]` Wiki Link style references
69+
70+
## Knowledge Graph Through Relations
71+
72+
Connections between documents create a knowledge graph without requiring a specialized database.
73+
74+
**Key aspects:**
75+
76+
- Relations create edges between document nodes
77+
- Relation types provide semantic meaning to connections
78+
- Navigation between knowledge via relation traversal
79+
- Emergent structure through use
80+
81+
**Examples:**
82+
83+
- `implements`, `extends`, `relates_to` relations
84+
- Following paths like `docs/search/implements/*`
85+
- Context building by walking the graph
86+
87+
## Understanding Users
88+
89+
Users will interact in patterns like:
90+
91+
1. Creating knowledge:
92+
```
93+
Human: "Let's write up what we discussed about search."
94+
95+
Response: I'll create a note capturing our discussion.
96+
```
97+
98+
AI Actions:
99+
100+
- record note via `write_note("...")`
101+
102+
1. Referencing existing knowledge:
103+
```
104+
Human: "Take a look at memory://specs/search"
105+
106+
Response: Let me build context from that and related documents.
107+
```
108+
109+
AI Actions:
110+
111+
- build context via `build_context("memory://specs/search")`
112+
- examine results
113+
- read content via `read_note()`
114+
115+
116+
2. Finding information:
117+
```
118+
Human: "What were our decisions about auth?"
119+
120+
Response: I'll search for relevant notes and build context.
121+
```
122+
123+
AI Actions:
124+
125+
- search via `search("auth")`
126+
- examine results
127+
- read content
128+
129+
## Key Things to Remember
130+
131+
3. **Files are Truth**
132+
- Everything lives in local files
133+
- Users control their files
134+
- Always check verbose output
135+
- The user can update files locally outside the LLM
136+
- Changes need to be synced by the user
137+
138+
4. **Building Context**
139+
- Start specific
140+
- Follow relations
141+
- Check recent changes
142+
- Build incrementally
143+
144+
5. **Writing Knowledge**
145+
- Using the same title + folder will overwrite a note
146+
- Use semantic markup
147+
- Create useful relations
148+
- Keep files organized
149+
150+
## Common Patterns
151+
152+
### Capturing Discussions
153+
154+
```python
155+
# Document a decision
156+
response = await write_note(
157+
title="Auth System Decision",
158+
folder="decisions",
159+
content="""# Auth System Decision
160+
161+
## Context
162+
Evaluated different auth approaches...
163+
164+
## Decision
165+
Selected JWT-based authentication because...
166+
167+
## Observations
168+
- [decision] Using JWT for auth #auth
169+
- [tech] Implementing with bcrypt #security
170+
171+
## Relations
172+
- affects [[Auth System]]
173+
- based_on [[Security Requirements]]
174+
"""
175+
)
176+
177+
```
178+
179+
### Building Understanding
180+
181+
```python
182+
async def explore_topic(topic):
183+
# Get main context
184+
context = await build_context(f"memory://{topic}")
185+
186+
# Find implementations
187+
impl = await build_context(
188+
f"memory://{topic}/implements/*"
189+
)
190+
191+
# Get recent changes
192+
activity = await recent_activity(timeframe="1 week")
193+
relevant = [r for r in activity.primary_results
194+
if topic in r.permalink]
195+
196+
# Build comprehensive view
197+
for result in relevant:
198+
details = await build_context(
199+
f"memory://{result.permalink}"
200+
)
201+
```
202+
203+
### Handling Files
204+
205+
```python
206+
# Check before writing
207+
try:
208+
existing = await read_note("Search Design")
209+
# Update existing
210+
await write_note(
211+
title="Search Design",
212+
content=updated_content,
213+
verbose=True
214+
)
215+
except:
216+
# Create new
217+
await write_note(
218+
title="Search Design",
219+
content=new_content,
220+
)
221+
```
222+
223+
## Error Handling
224+
225+
Common issues to watch for:
226+
227+
6. **Missing Content**
228+
```python
229+
try:
230+
content = await read_note("Document")
231+
except:
232+
# Try search
233+
results = await search({"text": "Document"})
234+
```
235+
236+
7. **Unresolved Relations**
237+
```python
238+
response = await write_note(..., verbose=True)
239+
for relation in response['relations']:
240+
if not relation['target']:
241+
# Relation didn't resolve
242+
# Might need sync
243+
# Or target doesn't exist
244+
```
245+
246+
8. **Pattern Matching**
247+
```python
248+
# If pattern fails, try:
249+
# - More specific path
250+
# - Direct lookup
251+
# - Search instead
252+
# - Recent activity
253+
```
254+
255+
## Best Practices
256+
257+
1. **Read and write Notes as needed**
258+
- Write notes to record context
259+
- See what was parsed
260+
- Check relations
261+
- Verify changes
262+
263+
2. **Build Context Carefully**
264+
- Start specific
265+
- Follow logical paths
266+
- Combine approaches
267+
- Stay relevant
268+
269+
3. **Write Clean Content**
270+
- Clear structure
271+
- Good organization
272+
- Useful relations
273+
- Regular cleanup
274+
275+
Built with ♥️ by Basic Machines

src/basic_memory/api/routers/memory_router.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,32 @@ async def to_graph_context(context, entity_repository: EntityRepository, page: i
2929
async def to_summary(item: SearchIndexRow | ContextResultRow):
3030
match item.type:
3131
case SearchItemType.ENTITY:
32-
assert item.title is not None
33-
assert item.created_at is not None
34-
3532
return EntitySummary(
36-
title=item.title,
33+
title=item.title, # pyright: ignore
3734
permalink=item.permalink,
3835
file_path=item.file_path,
3936
created_at=item.created_at,
4037
)
4138
case SearchItemType.OBSERVATION:
42-
assert item.category is not None
43-
assert item.content is not None
44-
assert item.permalink is not None
45-
4639
return ObservationSummary(
47-
category=item.category, content=item.content, permalink=item.permalink
40+
title=item.title, # pyright: ignore
41+
file_path=item.file_path,
42+
category=item.category, # pyright: ignore
43+
content=item.content, # pyright: ignore
44+
permalink=item.permalink, # pyright: ignore
45+
created_at=item.created_at,
4846
)
4947
case SearchItemType.RELATION:
50-
assert item.from_id is not None
51-
assert item.permalink is not None
52-
from_entity = await entity_repository.find_by_id(item.from_id)
53-
assert from_entity is not None
54-
assert from_entity.permalink is not None
55-
48+
from_entity = await entity_repository.find_by_id(item.from_id) # pyright: ignore
5649
to_entity = await entity_repository.find_by_id(item.to_id) if item.to_id else None
5750
return RelationSummary(
58-
permalink=item.permalink,
51+
title=item.title, # pyright: ignore
52+
file_path=item.file_path,
53+
permalink=item.permalink, # pyright: ignore
5954
relation_type=item.type,
60-
from_id=from_entity.permalink,
55+
from_id=from_entity.permalink, # pyright: ignore
6156
to_id=to_entity.permalink if to_entity else None,
57+
created_at=item.created_at,
6258
)
6359
case _: # pragma: no cover
6460
raise ValueError(f"Unexpected type: {item.type}")

src/basic_memory/api/routers/resource_router.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ async def get_resource_content(
9898
content = await file_service.read_entity_content(result)
9999
memory_url = normalize_memory_url(result.permalink)
100100
modified_date = result.updated_at.isoformat()
101-
assert result.checksum
102-
checksum = result.checksum[:8]
101+
checksum = result.checksum[:8] if result.checksum else ""
103102

104103
# Prepare the delimited content
105104
response_content = f"--- {memory_url} {modified_date} {checksum}\n"
@@ -192,7 +191,6 @@ async def write_resource(
192191
"updated_at": datetime.fromtimestamp(file_stats.st_mtime),
193192
},
194193
)
195-
assert entity is not None, "Entity should be returned after update"
196194
status_code = 200
197195
else:
198196
# Create a new entity model
@@ -209,7 +207,7 @@ async def write_resource(
209207
status_code = 201
210208

211209
# Index the file for search
212-
await search_service.index_entity(entity)
210+
await search_service.index_entity(entity) # pyright: ignore
213211

214212
# Return success response
215213
return JSONResponse(

src/basic_memory/cli/commands/sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def sync(
196196

197197
except Exception as e: # pragma: no cover
198198
if not isinstance(e, typer.Exit):
199-
logger.exception("Sync failed")
199+
logger.exception("Sync failed", e)
200200
typer.echo(f"Error during sync: {e}", err=True)
201201
raise typer.Exit(1)
202202
raise

0 commit comments

Comments
 (0)