add tool prompting and doc updates for strict mode in edit/move, and sync_status tool

Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
phernandez
2025-06-04 23:46:48 -05:00
parent 602c55fe90
commit ae3eeb0cc1
5 changed files with 206 additions and 128 deletions
+18 -2
View File
@@ -80,19 +80,21 @@ read_note("memory://specs/search") # By memory URL
**Incremental editing** (v0.13.0):
```
edit_note(
identifier="Search Design",
identifier="Search Design", # Must be EXACT title/permalink (strict matching)
operation="append", # append, prepend, find_replace, replace_section
content="\n## New Section\nContent here..."
)
```
**⚠️ Important:** `edit_note` requires exact identifiers (no fuzzy matching). Use `search_notes()` first if uncertain.
**File organization** (v0.13.0):
```
move_note(
identifier="Old Note",
identifier="Old Note", # Must be EXACT title/permalink (strict matching)
destination="archive/old-note.md" # Folders created automatically
)
```
**⚠️ Important:** `move_note` requires exact identifiers (no fuzzy matching). Use `search_notes()` first if uncertain.
### Project Management (v0.13.0)
@@ -364,6 +366,20 @@ When creating relations:
- If information seems outdated, suggest `basic-memory sync`
- Use `recent_activity()` to check if content is current
**Strict Mode for Edit/Move Operations:**
- `edit_note()` and `move_note()` require **exact identifiers** (no fuzzy matching for safety)
- If identifier not found: use `search_notes()` first to find the exact title/permalink
- Error messages will guide you to find correct identifiers
- Example workflow:
```
# ❌ This might fail if identifier isn't exact
edit_note("Meeting Note", "append", "content")
# ✅ Safe approach: search first, then use exact result
results = search_notes("meeting")
edit_note("Meeting Notes 2024", "append", "content") # Use exact title from search
```
## Best Practices
1. **Proactively Record Context**
+1 -1
View File
@@ -185,7 +185,7 @@ async def edit_note(
edit_note("Meeting Notes", "append", "\\n- Follow up on action items") # exact title
edit_note("docs/meeting-notes", "append", "\\n- Follow up tasks") # exact permalink
edit_note("docs/Meeting Notes", "append", "\\n- Next steps") # exact folder/title
# If uncertain about identifier, search first:
# search_notes("meeting") # Find available notes
# edit_note("docs/meeting-notes-2025", "append", "content") # Use exact result
+3 -3
View File
@@ -232,13 +232,13 @@ async def move_note(
Examples:
# Move to new folder (exact title match)
move_note("My Note", "work/notes/my-note.md")
# Move by exact permalink
move_note("my-note-permalink", "archive/old-notes/my-note.md")
# Specify project with exact identifier
move_note("My Note", "archive/my-note.md", project="work-project")
# If uncertain about identifier, search first:
# search_notes("my note") # Find available notes
# move_note("docs/my-note-2025", "archive/my-note.md") # Use exact result
+4 -2
View File
@@ -26,9 +26,11 @@ class LinkResolver:
self.entity_repository = entity_repository
self.search_service = search_service
async def resolve_link(self, link_text: str, use_search: bool = True, strict: bool = False) -> Optional[Entity]:
async def resolve_link(
self, link_text: str, use_search: bool = True, strict: bool = False
) -> Optional[Entity]:
"""Resolve a markdown link to a permalink.
Args:
link_text: The link text to resolve
use_search: Whether to use search-based fuzzy matching as fallback
+180 -120
View File
@@ -33,51 +33,94 @@ build these connections!
## Core Tools Reference
```python
# Writing knowledge - THE MOST IMPORTANT TOOL!
response = await write_note(
title="Search Design", # Required: Note title
content="# Search Design\n...", # Required: Note content
folder="specs", # Optional: Folder to save in
tags=["search", "design"], # Optional: Tags for categorization
verbose=True # Optional: Get parsing details
**Writing knowledge - THE MOST IMPORTANT TOOL!**
```
write_note(
title="Search Design",
content="# Search Design\n\n## Overview\nSearch functionality design and implementation.\n\n## Observations\n- [requirement] Must support full-text search #search\n- [decision] Using vector embeddings for semantic search #technology\n\n## Relations\n- implements [[Search Requirements]]\n- part_of [[API Specification]]",
folder="specs",
tags=["search", "design"]
)
```
**Reading knowledge:**
```
read_note("Search Design") # By exact title
read_note("specs/search-design") # By permalink
read_note("memory://specs/search") # By memory URL
```
**Incremental editing (v0.13.0) - REQUIRES EXACT IDENTIFIERS:**
```
edit_note(
identifier="Search Design", # Must be EXACT title/permalink
operation="append",
content="\n## Implementation Notes\n- Added caching layer for performance"
)
# Reading knowledge
content = await read_note("Search Design") # By title
content = await read_note("specs/search-design") # By path
content = await read_note("memory://specs/search") # By memory URL
# Searching for knowledge
results = await search_notes(
query="authentication system", # Text to search for
page=1, # Optional: Pagination
page_size=10 # Optional: Results per page
edit_note(
identifier="API Documentation",
operation="replace_section",
section="## Authentication",
content="Updated authentication using JWT tokens with refresh capability."
)
```
# Building context from the knowledge graph
context = await build_context(
url="memory://specs/search", # Starting point
depth=2, # Optional: How many hops to follow
timeframe="1 month" # Optional: Recent timeframe
**File organization (v0.13.0) - REQUIRES EXACT IDENTIFIERS:**
```
move_note(
identifier="Old Meeting Notes", # Must be EXACT title/permalink
destination_path="archive/2024/meeting-notes.md"
)
```
# Checking recent changes
activity = await recent_activity(
type="all", # Optional: Entity types to include
depth=1, # Optional: Related items to include
timeframe="1 week" # Optional: Time window
**Searching for knowledge:**
```
search_notes(
query="authentication system",
page=1,
page_size=10
)
```
# Creating a knowledge visualization
canvas_result = await canvas(
nodes=[{"id": "note1", "label": "Search Design"}], # Nodes to display
edges=[{"from": "note1", "to": "note2"}], # Connections
title="Project Overview", # Canvas title
folder="diagrams" # Storage location
**Building context from the knowledge graph:**
```
build_context(
url="memory://specs/search",
depth=2,
timeframe="1 month"
)
```
**Checking recent changes:**
```
recent_activity(
timeframe="1 week",
depth=1
)
```
**Creating knowledge visualizations:**
```
canvas(
nodes=[
{"id": "search", "x": 100, "y": 100, "width": 200, "height": 100, "type": "text", "text": "Search Design"},
{"id": "api", "x": 400, "y": 100, "width": 200, "height": 100, "type": "text", "text": "API Specification"}
],
edges=[
{"id": "link1", "fromNode": "search", "toNode": "api"}
],
title="System Architecture",
folder="diagrams"
)
```
**Monitoring sync status:**
```
sync_status() # Check overall system status
sync_status(project="work-notes") # Check specific project status
```
## memory:// URLs Explained
Basic Memory uses a special URL format to reference entities in the knowledge graph:
@@ -259,45 +302,24 @@ When creating relations, you can:
1. Reference existing entities by their exact title
2. Create forward references to entities that don't exist yet
```python
# Example workflow for creating notes with effective relations
async def create_note_with_effective_relations():
# Search for existing entities to reference
search_results = await search_notes("travel")
existing_entities = [result.title for result in search_results.primary_results]
**Example workflow for creating notes with effective relations:**
# Check if specific entities exist
packing_tips_exists = "Packing Tips" in existing_entities
japan_travel_exists = "Japan Travel Guide" in existing_entities
1. **First, search for existing entities to reference:**
```
search_notes(query="travel")
```
# Prepare relations section - include both existing and forward references
relations_section = "## Relations\n"
2. **Check recent activity for current topics:**
```
recent_activity(timeframe="1 week")
```
# Existing reference - exact match to known entity
if packing_tips_exists:
relations_section += "- references [[Packing Tips]]\n"
else:
# Forward reference - will be linked when that entity is created later
relations_section += "- references [[Packing Tips]]\n"
3. **Create the note with both existing and forward references:**
```
write_note(
title="Tokyo Neighborhood Guide",
content="# Tokyo Neighborhood Guide
# Another possible reference
if japan_travel_exists:
relations_section += "- part_of [[Japan Travel Guide]]\n"
# You can also check recently modified notes to reference them
recent = await recent_activity(timeframe="1 week")
recent_titles = [item.title for item in recent.primary_results]
if "Transportation Options" in recent_titles:
relations_section += "- relates_to [[Transportation Options]]\n"
# Always include meaningful forward references, even if they don't exist yet
relations_section += "- located_in [[Tokyo]]\n"
relations_section += "- visited_during [[Spring 2023 Trip]]\n"
# Now create the note with both verified and forward relations
content = f"""# Tokyo Neighborhood Guide
## Overview
Details about different Tokyo neighborhoods and their unique characteristics.
@@ -307,65 +329,103 @@ Details about different Tokyo neighborhoods and their unique characteristics.
- [recommendation] Visit Shimokitazawa for vintage shopping #unique
- [tip] Get a Suica card for easy train travel #convenience
{relations_section}
"""
result = await write_note(
title="Tokyo Neighborhood Guide",
content=content,
verbose=True
)
# You can check which relations were resolved and which are forward references
if result and 'relations' in result:
resolved = [r['to_name'] for r in result['relations'] if r.get('target_id')]
forward_refs = [r['to_name'] for r in result['relations'] if not r.get('target_id')]
print(f"Resolved relations: {resolved}")
print(f"Forward references that will be resolved later: {forward_refs}")
## Relations
- references [[Packing Tips]] # Forward reference (will be linked when created)
- part_of [[Japan Travel Guide]] # Existing reference (if found in search)
- relates_to [[Transportation Options]] # Recent reference (if found in activity)
- located_in [[Tokyo]] # Forward reference
- visited_during [[Spring 2023 Trip]] # Forward reference",
folder="travel",
tags=["tokyo", "neighborhoods", "travel"]
)
```
**Key points:**
- Use exact titles from search results for existing entities: `[[Exact Title Found]]`
- Forward references are fine - they'll be linked automatically when target notes are created
- Check recent activity to reference currently active topics
- Use meaningful relation types: `part_of`, `located_in`, `visited_during` vs generic `relates_to`
## Error Handling
Common issues to watch for:
1. **Missing Content**
```python
try:
content = await read_note("Document")
except:
# Try search instead
results = await search_notes("Document")
if results and results.primary_results:
# Found something similar
content = await read_note(results.primary_results[0].permalink)
```
**1. Missing Content - Use Search as Fallback**
```
# If read_note fails, try search instead
search_notes(query="Document")
# Then use exact result from search:
read_note("Exact Document Title Found")
```
2. **Forward References (Unresolved Relations)**
```python
response = await write_note(..., verbose=True)
# Check for forward references (unresolved relations)
forward_refs = []
for relation in response.get('relations', []):
if not relation.get('target_id'):
forward_refs.append(relation.get('to_name'))
if forward_refs:
# This is a feature, not an error! Inform the user about forward references
print(f"Note created with forward references to: {forward_refs}")
print("These will be automatically linked when those notes are created.")
# Optionally suggest creating those entities now
print("Would you like me to create any of these notes now to complete the connections?")
```
**2. Strict Mode for Edit/Move Operations (v0.13.0)**
3. **Sync Issues**
```python
# If information seems outdated
activity = await recent_activity(timeframe="1 hour")
if not activity or not activity.primary_results:
print("It seems there haven't been recent updates. You might need to run 'basic-memory sync'.")
```
**This might fail if identifier isn't exact:**
```
edit_note(identifier="Meeting Note", operation="append", content="new content")
```
✅ **Safe approach - search first, then use exact result:**
```
# 1. Search first to find exact identifier
search_notes(query="meeting")
# 2. Use exact title from search results
edit_note(identifier="Meeting Notes 2024", operation="append", content="new content")
# Same pattern for move_note:
search_notes(query="old note")
move_note(identifier="Old Meeting Notes", destination_path="archive/old-notes.md")
```
**3. Forward References (Unresolved Relations)**
Forward references are a **feature, not an error!** Basic Memory automatically links them when target notes are created.
When you see unresolved relations in the response:
- Inform users: "I've created forward references that will be linked when you create those notes"
- Optionally suggest: "Would you like me to create any of these notes now to complete the connections?"
**4. Sync Issues**
If information seems outdated:
```
recent_activity(timeframe="1 hour")
```
If no recent activity shows, check sync status first:
```
sync_status()
```
If sync is pending or failed, suggest: "You might need to run `basic-memory sync`"
**5. Understanding Sync Status**
The `sync_status()` tool provides essential information about Basic Memory's operational state:
```
sync_status() # Check overall system readiness
sync_status(project="work-notes") # Check specific project context
```
**When to use sync_status:**
- At the start of conversations to verify system readiness
- When operations seem slow or fail unexpectedly
- Before working with large knowledge bases
- When switching between projects
- To provide users context about background processing
**What sync_status tells you:**
- **System Ready**: Whether all files are indexed and tools are operational
- **Active Processing**: Which projects are currently syncing with progress indicators
- **Project Status**: Individual project sync states (👁️ watching, ✅ completed, 🔄 syncing, ❌ failed, ⏳ pending)
- **Error Details**: Specific error messages for failed sync operations
- **Guidance**: Next steps when issues are detected
**Using sync_status effectively:**
- Check status if tools return unexpected results
- Use project parameter when working in multi-project setups
- Share status with users when explaining delays
- Monitor progress during initial setup or large imports
## Best Practices