mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
feat: rename search tool to search_notes (#66)
Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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]")`
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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-*"
|
||||
))
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user