feat: rename search tool to search_notes (#66)

Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
Paul Hernandez
2025-03-28 19:11:35 -05:00
committed by GitHub
parent 0743ade5fc
commit b27827671d
15 changed files with 53 additions and 52 deletions
+2 -2
View File
@@ -107,7 +107,7 @@ See the [README.md](README.md) file for a project overview.
1d", "1 week")
**Search & Discovery:**
- `search(query, page, page_size)` - Full-text search across all content with filtering options
- `search_notes(query, page, page_size)` - Full-text search across all content with filtering options
**Visualization:**
- `canvas(nodes, edges, title, folder)` - Generate Obsidian canvas files for knowledge graph visualization
@@ -115,7 +115,7 @@ See the [README.md](README.md) file for a project overview.
- MCP Prompts for better AI interaction:
- `ai_assistant_guide()` - Guidance on effectively using Basic Memory tools for AI assistants
- `continue_conversation(topic, timeframe)` - Continue previous conversations with relevant historical context
- `search(query, after_date)` - Search with detailed, formatted results for better context understanding
- `search_notes(query, after_date)` - Search with detailed, formatted results for better context understanding
- `recent_activity(timeframe)` - View recently changed items with formatted output
- `json_canvas_spec()` - Full JSON Canvas specification for Obsidian visualization
+3 -2
View File
@@ -285,7 +285,8 @@ for OS X):
}
```
If you want to use a specific project (see [Multiple Projects](docs/User%20Guide.md#multiple-projects)), update your Claude Desktop
If you want to use a specific project (see [Multiple Projects](docs/User%20Guide.md#multiple-projects)), update your
Claude Desktop
config:
```json
@@ -320,7 +321,7 @@ basic-memory sync --watch
write_note(title, content, folder, tags) - Create or update notes
read_note(identifier, page, page_size) - Read notes by title or permalink
build_context(url, depth, timeframe) - Navigate knowledge graph via memory:// URLs
search(query, page, page_size) - Search across your knowledge base
search_notes(query, page, page_size) - Search across your knowledge base
recent_activity(type, depth, timeframe) - Find recently updated information
canvas(nodes, edges, title, folder) - Generate knowledge visualizations
```
+5 -5
View File
@@ -53,7 +53,7 @@ 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(
results = await search_notes(
query="authentication system", # Text to search for
page=1, # Optional: Pagination
page_size=10 # Optional: Results per page
@@ -154,7 +154,7 @@ Users will interact with Basic Memory in patterns like:
Human: "What were our decisions about auth?"
You: Let me find that information for you.
[Use search() to find relevant notes]
[Use search_notes() to find relevant notes]
[Then build_context() to understand connections]
```
@@ -251,7 +251,7 @@ When creating relations, you can:
# 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("travel")
search_results = await search_notes("travel")
existing_entities = [result.title for result in search_results.primary_results]
# Check if specific entities exist
@@ -323,7 +323,7 @@ Common issues to watch for:
content = await read_note("Document")
except:
# Try search instead
results = await search("Document")
results = await search_notes("Document")
if results and results.primary_results:
# Found something similar
content = await read_note(results.primary_results[0].permalink)
@@ -369,7 +369,7 @@ Common issues to watch for:
- **Create deliberate relations**: Connect each note to at least 2-3 related entities
- **Use existing entities**: Before creating a new relation, search for existing entities
- **Verify wikilinks**: When referencing `[[Entity]]`, use exact titles of existing notes
- **Check accuracy**: Use `search()` or `recent_activity()` to confirm entity titles
- **Check accuracy**: Use `search_notes()` or `recent_activity()` to confirm entity titles
- **Use precise relation types**: Choose specific relation types that convey meaning (e.g., "implements" instead of "relates_to")
- **Consider bidirectional relations**: When appropriate, create inverse relations in both entities
+1 -1
View File
@@ -196,7 +196,7 @@ flowchart TD
end
BMCP <-->|"write_note() read_note()"| KnowledgeFiles
BMCP <-->|"search() build_context()"| KnowledgeIndex
BMCP <-->|"search_notes() build_context()"| KnowledgeIndex
KnowledgeFiles <-.->|Sync Process| KnowledgeIndex
KnowledgeFiles <-->|Direct Editing| Editors((Text Editors & Git))
+3 -3
View File
@@ -12,7 +12,7 @@ from basic_memory.cli.app import app
from basic_memory.mcp.tools import build_context as mcp_build_context
from basic_memory.mcp.tools import read_note as mcp_read_note
from basic_memory.mcp.tools import recent_activity as mcp_recent_activity
from basic_memory.mcp.tools import search as mcp_search
from basic_memory.mcp.tools import search_notes as mcp_search
from basic_memory.mcp.tools import write_note as mcp_write_note
# Import prompts
@@ -180,8 +180,8 @@ def recent_activity(
raise
@tool_app.command()
def search(
@tool_app.command("search-notes")
def search_notes(
query: str,
permalink: Annotated[bool, typer.Option("--permalink", help="Search permalink values")] = False,
title: Annotated[bool, typer.Option("--title", help="Search title values")] = False,
@@ -14,7 +14,7 @@ from basic_memory.mcp.prompts.utils import format_prompt_context, PromptContext,
from basic_memory.mcp.server import mcp
from basic_memory.mcp.tools.build_context import build_context
from basic_memory.mcp.tools.recent_activity import recent_activity
from basic_memory.mcp.tools.search import search
from basic_memory.mcp.tools.search import search_notes
from basic_memory.schemas.base import TimeFrame
from basic_memory.schemas.memory import GraphContext
from basic_memory.schemas.search import SearchQuery, SearchItemType
@@ -47,7 +47,7 @@ async def continue_conversation(
# If topic provided, search for it
if topic:
search_results = await search(
search_results = await search_notes(
SearchQuery(text=topic, after_date=timeframe, types=[SearchItemType.ENTITY])
)
@@ -93,7 +93,7 @@ async def continue_conversation(
## Next Steps
You can:
- Explore more with: `search({{"text": "{topic}"}})`
- Explore more with: `search_notes({{"text": "{topic}"}})`
- See what's changed: `recent_activity(timeframe="{timeframe or "7d"}")`
- **Record new learnings or decisions from this conversation:** `write_note(title="[Create a meaningful title]", content="[Content with observations and relations]")`
+4 -4
View File
@@ -10,7 +10,7 @@ from loguru import logger
from pydantic import Field
from basic_memory.mcp.server import mcp
from basic_memory.mcp.tools.search import search as search_tool
from basic_memory.mcp.tools.search import search_notes as search_tool
from basic_memory.schemas.base import TimeFrame
from basic_memory.schemas.search import SearchQuery, SearchResponse
@@ -144,9 +144,9 @@ def format_search_results(
## Next Steps
You can:
- Refine your search: `search("{query} AND additional_term")`
- Exclude terms: `search("{query} NOT exclude_term")`
- View more results: `search("{query}", after_date=None)`
- Refine your search: `search_notes("{query} AND additional_term")`
- Exclude terms: `search_notes("{query} NOT exclude_term")`
- View more results: `search_notes("{query}", after_date=None)`
- Check recent activity: `recent_activity()`
## Synthesize and Capture Knowledge
@@ -49,7 +49,7 @@ 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(
results = await search_notes(
query="authentication system", # Text to search for
page=1, # Optional: Pagination
page_size=10 # Optional: Results per page
@@ -154,7 +154,7 @@ Users will interact with Basic Memory in patterns like:
Human: "What were our decisions about auth?"
You: Let me find that information for you.
[Use search() to find relevant notes]
[Use search_notes() to find relevant notes]
[Then build_context() to understand connections]
```
@@ -263,7 +263,7 @@ When creating relations, you can:
# 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("travel")
search_results = await search_notes("travel")
existing_entities = [result.title for result in search_results.primary_results]
# Check if specific entities exist
@@ -335,7 +335,7 @@ Common issues to watch for:
content = await read_note("Document")
except:
# Try search instead
results = await search("Document")
results = await search_notes("Document")
if results and results.primary_results:
# Found something similar
content = await read_note(results.primary_results[0].permalink)
@@ -381,7 +381,7 @@ Common issues to watch for:
- **Create deliberate relations**: Connect each note to at least 2-3 related entities
- **Use existing entities**: Before creating a new relation, search for existing entities
- **Verify wikilinks**: When referencing `[[Entity]]`, use exact titles of existing notes
- **Check accuracy**: Use `search()` or `recent_activity()` to confirm entity titles
- **Check accuracy**: Use `search_notes()` or `recent_activity()` to confirm entity titles
- **Use precise relation types**: Choose specific relation types that convey meaning (e.g., "implements" instead
of "relates_to")
- **Consider bidirectional relations**: When appropriate, create inverse relations in both entities
+2 -2
View File
@@ -12,7 +12,7 @@ from basic_memory.mcp.tools.build_context import build_context
from basic_memory.mcp.tools.recent_activity import recent_activity
from basic_memory.mcp.tools.read_note import read_note
from basic_memory.mcp.tools.write_note import write_note
from basic_memory.mcp.tools.search import search
from basic_memory.mcp.tools.search import search_notes
from basic_memory.mcp.tools.canvas import canvas
__all__ = [
@@ -22,6 +22,6 @@ __all__ = [
"read_content",
"read_note",
"recent_activity",
"search",
"search_notes",
"write_note",
]
+3 -3
View File
@@ -6,7 +6,7 @@ from loguru import logger
from basic_memory.mcp.async_client import client
from basic_memory.mcp.server import mcp
from basic_memory.mcp.tools.search import search
from basic_memory.mcp.tools.search import search_notes
from basic_memory.mcp.tools.utils import call_get
from basic_memory.schemas.memory import memory_url_path
from basic_memory.schemas.search import SearchQuery
@@ -63,7 +63,7 @@ async def read_note(identifier: str, page: int = 1, page_size: int = 10) -> str:
# Fallback 1: Try title search via API
logger.info(f"Search title for: {identifier}")
title_results = await search(SearchQuery(title=identifier))
title_results = await search_notes(SearchQuery(title=identifier))
if title_results and title_results.results:
result = title_results.results[0] # Get the first/best match
@@ -87,7 +87,7 @@ async def read_note(identifier: str, page: int = 1, page_size: int = 10) -> str:
# Fallback 2: Text search as a last resort
logger.info(f"Title search failed, trying text search for: {identifier}")
text_results = await search(SearchQuery(text=identifier))
text_results = await search_notes(SearchQuery(text=identifier))
# We didn't find a direct match, construct a helpful error message
if not text_results or not text_results.results:
+9 -9
View File
@@ -11,7 +11,7 @@ from basic_memory.mcp.async_client import client
@mcp.tool(
description="Search across all content in the knowledge base.",
)
async def search(query: SearchQuery, page: int = 1, page_size: int = 10) -> SearchResponse:
async def search_notes(query: SearchQuery, page: int = 1, page_size: int = 10) -> SearchResponse:
"""Search across all content in the knowledge base.
This tool searches the knowledge base using full-text search, pattern matching,
@@ -36,34 +36,34 @@ async def search(query: SearchQuery, page: int = 1, page_size: int = 10) -> Sear
Examples:
# Basic text search
results = await search(SearchQuery(text="project planning"))
results = await search_notes(SearchQuery(text="project planning"))
# Boolean AND search (both terms must be present)
results = await search(SearchQuery(text="project AND planning"))
results = await search_notes(SearchQuery(text="project AND planning"))
# Boolean OR search (either term can be present)
results = await search(SearchQuery(text="project OR meeting"))
results = await search_notes(SearchQuery(text="project OR meeting"))
# Boolean NOT search (exclude terms)
results = await search(SearchQuery(text="project NOT meeting"))
results = await search_notes(SearchQuery(text="project NOT meeting"))
# Boolean search with grouping
results = await search(SearchQuery(text="(project OR planning) AND notes"))
results = await search_notes(SearchQuery(text="(project OR planning) AND notes"))
# Search with type filter
results = await search(SearchQuery(
results = await search_notes(SearchQuery(
text="meeting notes",
types=["entity"],
))
# Search for recent content
results = await search(SearchQuery(
results = await search_notes(SearchQuery(
text="bug report",
after_date="1 week"
))
# Pattern matching on permalinks
results = await search(SearchQuery(
results = await search_notes(SearchQuery(
permalink_match="docs/meeting-*"
))
"""
+5 -5
View File
@@ -49,7 +49,7 @@ 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(
results = await search_notes(
query="authentication system", # Text to search for
page=1, # Optional: Pagination
page_size=10 # Optional: Results per page
@@ -154,7 +154,7 @@ Users will interact with Basic Memory in patterns like:
Human: "What were our decisions about auth?"
You: Let me find that information for you.
[Use search() to find relevant notes]
[Use search_notes() to find relevant notes]
[Then build_context() to understand connections]
```
@@ -263,7 +263,7 @@ When creating relations, you can:
# 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("travel")
search_results = await search_notes("travel")
existing_entities = [result.title for result in search_results.primary_results]
# Check if specific entities exist
@@ -335,7 +335,7 @@ Common issues to watch for:
content = await read_note("Document")
except:
# Try search instead
results = await search("Document")
results = await search_notes("Document")
if results and results.primary_results:
# Found something similar
content = await read_note(results.primary_results[0].permalink)
@@ -381,7 +381,7 @@ Common issues to watch for:
- **Create deliberate relations**: Connect each note to at least 2-3 related entities
- **Use existing entities**: Before creating a new relation, search for existing entities
- **Verify wikilinks**: When referencing `[[Entity]]`, use exact titles of existing notes
- **Check accuracy**: Use `search()` or `recent_activity()` to confirm entity titles
- **Check accuracy**: Use `search_notes()` or `recent_activity()` to confirm entity titles
- **Use precise relation types**: Choose specific relation types that convey meaning (e.g., "implements" instead
of "relates_to")
- **Consider bidirectional relations**: When appropriate, create inverse relations in both entities
+2 -2
View File
@@ -211,7 +211,7 @@ def test_search_basic(cli_env, setup_test_note):
"""Test basic search command."""
result = runner.invoke(
tool_app,
["search", "test observation"],
["search-notes", "test observation"],
)
assert result.exit_code == 0
@@ -235,7 +235,7 @@ def test_search_permalink(cli_env, setup_test_note):
result = runner.invoke(
tool_app,
["search", permalink, "--permalink"],
["search-notes", permalink, "--permalink"],
)
assert result.exit_code == 0
+1 -1
View File
@@ -26,7 +26,7 @@ async def mock_call_get():
@pytest_asyncio.fixture
async def mock_search():
"""Mock for search tool."""
with patch("basic_memory.mcp.tools.read_note.search") as mock:
with patch("basic_memory.mcp.tools.read_note.search_notes") as mock:
# Default to empty results
mock.return_value = SearchResponse(results=[], current_page=1, page_size=1)
yield mock
+5 -5
View File
@@ -4,7 +4,7 @@ import pytest
from datetime import datetime, timedelta
from basic_memory.mcp.tools import write_note
from basic_memory.mcp.tools.search import search
from basic_memory.mcp.tools.search import search_notes
from basic_memory.schemas.search import SearchQuery, SearchItemType
@@ -22,7 +22,7 @@ async def test_search_basic(client):
# Search for it
query = SearchQuery(text="searchable")
response = await search(query)
response = await search_notes(query)
# Verify results
assert len(response.results) > 0
@@ -43,7 +43,7 @@ async def test_search_pagination(client):
# Search for it
query = SearchQuery(text="searchable")
response = await search(query, page=1, page_size=1)
response = await search_notes(query, page=1, page_size=1)
# Verify results
assert len(response.results) == 1
@@ -62,7 +62,7 @@ async def test_search_with_type_filter(client):
# Search with type filter
query = SearchQuery(text="type", types=[SearchItemType.ENTITY])
response = await search(query)
response = await search_notes(query)
# Verify all results are entities
assert all(r.type == "entity" for r in response.results)
@@ -81,7 +81,7 @@ async def test_search_with_date_filter(client):
# Search with date filter
one_hour_ago = datetime.now() - timedelta(hours=1)
query = SearchQuery(text="recent", after_date=one_hour_ago)
response = await search(query)
response = await search_notes(query)
# Verify we get results within timeframe
assert len(response.results) > 0