basic-memory 0.17.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- basic_memory/__init__.py +7 -0
- basic_memory/alembic/alembic.ini +119 -0
- basic_memory/alembic/env.py +185 -0
- basic_memory/alembic/migrations.py +24 -0
- basic_memory/alembic/script.py.mako +26 -0
- basic_memory/alembic/versions/314f1ea54dc4_add_postgres_full_text_search_support_.py +131 -0
- basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +93 -0
- basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +51 -0
- basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py +120 -0
- basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py +112 -0
- basic_memory/alembic/versions/9d9c1cb7d8f5_add_mtime_and_size_columns_to_entity_.py +49 -0
- basic_memory/alembic/versions/a1b2c3d4e5f6_fix_project_foreign_keys.py +49 -0
- basic_memory/alembic/versions/a2b3c4d5e6f7_add_search_index_entity_cascade.py +56 -0
- basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +44 -0
- basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +113 -0
- basic_memory/alembic/versions/e7e1f4367280_add_scan_watermark_tracking_to_project.py +37 -0
- basic_memory/alembic/versions/f8a9b2c3d4e5_add_pg_trgm_for_fuzzy_link_resolution.py +239 -0
- basic_memory/api/__init__.py +5 -0
- basic_memory/api/app.py +131 -0
- basic_memory/api/routers/__init__.py +11 -0
- basic_memory/api/routers/directory_router.py +84 -0
- basic_memory/api/routers/importer_router.py +152 -0
- basic_memory/api/routers/knowledge_router.py +318 -0
- basic_memory/api/routers/management_router.py +80 -0
- basic_memory/api/routers/memory_router.py +90 -0
- basic_memory/api/routers/project_router.py +448 -0
- basic_memory/api/routers/prompt_router.py +260 -0
- basic_memory/api/routers/resource_router.py +249 -0
- basic_memory/api/routers/search_router.py +36 -0
- basic_memory/api/routers/utils.py +169 -0
- basic_memory/api/template_loader.py +292 -0
- basic_memory/api/v2/__init__.py +35 -0
- basic_memory/api/v2/routers/__init__.py +21 -0
- basic_memory/api/v2/routers/directory_router.py +93 -0
- basic_memory/api/v2/routers/importer_router.py +182 -0
- basic_memory/api/v2/routers/knowledge_router.py +413 -0
- basic_memory/api/v2/routers/memory_router.py +130 -0
- basic_memory/api/v2/routers/project_router.py +342 -0
- basic_memory/api/v2/routers/prompt_router.py +270 -0
- basic_memory/api/v2/routers/resource_router.py +286 -0
- basic_memory/api/v2/routers/search_router.py +73 -0
- basic_memory/cli/__init__.py +1 -0
- basic_memory/cli/app.py +84 -0
- basic_memory/cli/auth.py +277 -0
- basic_memory/cli/commands/__init__.py +18 -0
- basic_memory/cli/commands/cloud/__init__.py +6 -0
- basic_memory/cli/commands/cloud/api_client.py +112 -0
- basic_memory/cli/commands/cloud/bisync_commands.py +110 -0
- basic_memory/cli/commands/cloud/cloud_utils.py +101 -0
- basic_memory/cli/commands/cloud/core_commands.py +195 -0
- basic_memory/cli/commands/cloud/rclone_commands.py +371 -0
- basic_memory/cli/commands/cloud/rclone_config.py +110 -0
- basic_memory/cli/commands/cloud/rclone_installer.py +263 -0
- basic_memory/cli/commands/cloud/upload.py +233 -0
- basic_memory/cli/commands/cloud/upload_command.py +124 -0
- basic_memory/cli/commands/command_utils.py +77 -0
- basic_memory/cli/commands/db.py +44 -0
- basic_memory/cli/commands/format.py +198 -0
- basic_memory/cli/commands/import_chatgpt.py +84 -0
- basic_memory/cli/commands/import_claude_conversations.py +87 -0
- basic_memory/cli/commands/import_claude_projects.py +86 -0
- basic_memory/cli/commands/import_memory_json.py +87 -0
- basic_memory/cli/commands/mcp.py +76 -0
- basic_memory/cli/commands/project.py +889 -0
- basic_memory/cli/commands/status.py +174 -0
- basic_memory/cli/commands/telemetry.py +81 -0
- basic_memory/cli/commands/tool.py +341 -0
- basic_memory/cli/main.py +28 -0
- basic_memory/config.py +616 -0
- basic_memory/db.py +394 -0
- basic_memory/deps.py +705 -0
- basic_memory/file_utils.py +478 -0
- basic_memory/ignore_utils.py +297 -0
- basic_memory/importers/__init__.py +27 -0
- basic_memory/importers/base.py +79 -0
- basic_memory/importers/chatgpt_importer.py +232 -0
- basic_memory/importers/claude_conversations_importer.py +180 -0
- basic_memory/importers/claude_projects_importer.py +148 -0
- basic_memory/importers/memory_json_importer.py +108 -0
- basic_memory/importers/utils.py +61 -0
- basic_memory/markdown/__init__.py +21 -0
- basic_memory/markdown/entity_parser.py +279 -0
- basic_memory/markdown/markdown_processor.py +160 -0
- basic_memory/markdown/plugins.py +242 -0
- basic_memory/markdown/schemas.py +70 -0
- basic_memory/markdown/utils.py +117 -0
- basic_memory/mcp/__init__.py +1 -0
- basic_memory/mcp/async_client.py +139 -0
- basic_memory/mcp/project_context.py +141 -0
- basic_memory/mcp/prompts/__init__.py +19 -0
- basic_memory/mcp/prompts/ai_assistant_guide.py +70 -0
- basic_memory/mcp/prompts/continue_conversation.py +62 -0
- basic_memory/mcp/prompts/recent_activity.py +188 -0
- basic_memory/mcp/prompts/search.py +57 -0
- basic_memory/mcp/prompts/utils.py +162 -0
- basic_memory/mcp/resources/ai_assistant_guide.md +283 -0
- basic_memory/mcp/resources/project_info.py +71 -0
- basic_memory/mcp/server.py +81 -0
- basic_memory/mcp/tools/__init__.py +48 -0
- basic_memory/mcp/tools/build_context.py +120 -0
- basic_memory/mcp/tools/canvas.py +152 -0
- basic_memory/mcp/tools/chatgpt_tools.py +190 -0
- basic_memory/mcp/tools/delete_note.py +242 -0
- basic_memory/mcp/tools/edit_note.py +324 -0
- basic_memory/mcp/tools/list_directory.py +168 -0
- basic_memory/mcp/tools/move_note.py +551 -0
- basic_memory/mcp/tools/project_management.py +201 -0
- basic_memory/mcp/tools/read_content.py +281 -0
- basic_memory/mcp/tools/read_note.py +267 -0
- basic_memory/mcp/tools/recent_activity.py +534 -0
- basic_memory/mcp/tools/search.py +385 -0
- basic_memory/mcp/tools/utils.py +540 -0
- basic_memory/mcp/tools/view_note.py +78 -0
- basic_memory/mcp/tools/write_note.py +230 -0
- basic_memory/models/__init__.py +15 -0
- basic_memory/models/base.py +10 -0
- basic_memory/models/knowledge.py +226 -0
- basic_memory/models/project.py +87 -0
- basic_memory/models/search.py +85 -0
- basic_memory/repository/__init__.py +11 -0
- basic_memory/repository/entity_repository.py +503 -0
- basic_memory/repository/observation_repository.py +73 -0
- basic_memory/repository/postgres_search_repository.py +379 -0
- basic_memory/repository/project_info_repository.py +10 -0
- basic_memory/repository/project_repository.py +128 -0
- basic_memory/repository/relation_repository.py +146 -0
- basic_memory/repository/repository.py +385 -0
- basic_memory/repository/search_index_row.py +95 -0
- basic_memory/repository/search_repository.py +94 -0
- basic_memory/repository/search_repository_base.py +241 -0
- basic_memory/repository/sqlite_search_repository.py +439 -0
- basic_memory/schemas/__init__.py +86 -0
- basic_memory/schemas/base.py +297 -0
- basic_memory/schemas/cloud.py +50 -0
- basic_memory/schemas/delete.py +37 -0
- basic_memory/schemas/directory.py +30 -0
- basic_memory/schemas/importer.py +35 -0
- basic_memory/schemas/memory.py +285 -0
- basic_memory/schemas/project_info.py +212 -0
- basic_memory/schemas/prompt.py +90 -0
- basic_memory/schemas/request.py +112 -0
- basic_memory/schemas/response.py +229 -0
- basic_memory/schemas/search.py +117 -0
- basic_memory/schemas/sync_report.py +72 -0
- basic_memory/schemas/v2/__init__.py +27 -0
- basic_memory/schemas/v2/entity.py +129 -0
- basic_memory/schemas/v2/resource.py +46 -0
- basic_memory/services/__init__.py +8 -0
- basic_memory/services/context_service.py +601 -0
- basic_memory/services/directory_service.py +308 -0
- basic_memory/services/entity_service.py +864 -0
- basic_memory/services/exceptions.py +37 -0
- basic_memory/services/file_service.py +541 -0
- basic_memory/services/initialization.py +216 -0
- basic_memory/services/link_resolver.py +121 -0
- basic_memory/services/project_service.py +880 -0
- basic_memory/services/search_service.py +404 -0
- basic_memory/services/service.py +15 -0
- basic_memory/sync/__init__.py +6 -0
- basic_memory/sync/background_sync.py +26 -0
- basic_memory/sync/sync_service.py +1259 -0
- basic_memory/sync/watch_service.py +510 -0
- basic_memory/telemetry.py +249 -0
- basic_memory/templates/prompts/continue_conversation.hbs +110 -0
- basic_memory/templates/prompts/search.hbs +101 -0
- basic_memory/utils.py +468 -0
- basic_memory-0.17.1.dist-info/METADATA +617 -0
- basic_memory-0.17.1.dist-info/RECORD +171 -0
- basic_memory-0.17.1.dist-info/WHEEL +4 -0
- basic_memory-0.17.1.dist-info/entry_points.txt +3 -0
- basic_memory-0.17.1.dist-info/licenses/LICENSE +661 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Recent activity prompts for Basic Memory MCP server.
|
|
2
|
+
|
|
3
|
+
These prompts help users see what has changed in their knowledge base recently.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Annotated, Optional
|
|
7
|
+
|
|
8
|
+
from loguru import logger
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
|
|
11
|
+
from basic_memory.mcp.prompts.utils import format_prompt_context, PromptContext, PromptContextItem
|
|
12
|
+
from basic_memory.mcp.server import mcp
|
|
13
|
+
from basic_memory.mcp.tools.recent_activity import recent_activity
|
|
14
|
+
from basic_memory.schemas.base import TimeFrame
|
|
15
|
+
from basic_memory.schemas.memory import GraphContext, ProjectActivitySummary
|
|
16
|
+
from basic_memory.schemas.search import SearchItemType
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@mcp.prompt(
|
|
20
|
+
name="recent_activity",
|
|
21
|
+
description="Get recent activity from a specific project or across all projects",
|
|
22
|
+
)
|
|
23
|
+
async def recent_activity_prompt(
|
|
24
|
+
timeframe: Annotated[
|
|
25
|
+
TimeFrame,
|
|
26
|
+
Field(description="How far back to look for activity (e.g. '1d', '1 week')"),
|
|
27
|
+
] = "7d",
|
|
28
|
+
project: Annotated[
|
|
29
|
+
Optional[str],
|
|
30
|
+
Field(
|
|
31
|
+
description="Specific project to get activity from (None for discovery across all projects)"
|
|
32
|
+
),
|
|
33
|
+
] = None,
|
|
34
|
+
) -> str:
|
|
35
|
+
"""Get recent activity from a specific project or across all projects.
|
|
36
|
+
|
|
37
|
+
This prompt helps you see what's changed recently in the knowledge base.
|
|
38
|
+
In discovery mode (project=None), it shows activity across all projects.
|
|
39
|
+
In project-specific mode, it shows detailed activity for one project.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
timeframe: How far back to look for activity (e.g. '1d', '1 week')
|
|
43
|
+
project: Specific project to get activity from (None for discovery across all projects)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Formatted summary of recent activity
|
|
47
|
+
"""
|
|
48
|
+
logger.info(f"Getting recent activity, timeframe: {timeframe}, project: {project}")
|
|
49
|
+
|
|
50
|
+
recent = await recent_activity.fn(
|
|
51
|
+
project=project, timeframe=timeframe, type=[SearchItemType.ENTITY]
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Extract primary results from the hierarchical structure
|
|
55
|
+
primary_results = []
|
|
56
|
+
related_results = []
|
|
57
|
+
|
|
58
|
+
if isinstance(recent, ProjectActivitySummary):
|
|
59
|
+
# Discovery mode - extract results from all projects
|
|
60
|
+
for _, project_activity in recent.projects.items():
|
|
61
|
+
if project_activity.activity.results:
|
|
62
|
+
# Take up to 2 primary results per project
|
|
63
|
+
for item in project_activity.activity.results[:2]:
|
|
64
|
+
primary_results.append(item.primary_result)
|
|
65
|
+
# Add up to 1 related result per primary item
|
|
66
|
+
if item.related_results:
|
|
67
|
+
related_results.extend(item.related_results[:1])
|
|
68
|
+
|
|
69
|
+
# Limit total results for readability
|
|
70
|
+
primary_results = primary_results[:8]
|
|
71
|
+
related_results = related_results[:6]
|
|
72
|
+
|
|
73
|
+
elif isinstance(recent, GraphContext):
|
|
74
|
+
# Project-specific mode - use existing logic
|
|
75
|
+
if recent.results:
|
|
76
|
+
# Take up to 5 primary results
|
|
77
|
+
for item in recent.results[:5]:
|
|
78
|
+
primary_results.append(item.primary_result)
|
|
79
|
+
# Add up to 2 related results per primary item
|
|
80
|
+
if item.related_results:
|
|
81
|
+
related_results.extend(item.related_results[:2])
|
|
82
|
+
|
|
83
|
+
# Set topic based on mode
|
|
84
|
+
if project:
|
|
85
|
+
topic = f"Recent Activity in {project} ({timeframe})"
|
|
86
|
+
else:
|
|
87
|
+
topic = f"Recent Activity Across All Projects ({timeframe})"
|
|
88
|
+
|
|
89
|
+
prompt_context = format_prompt_context(
|
|
90
|
+
PromptContext(
|
|
91
|
+
topic=topic,
|
|
92
|
+
timeframe=timeframe,
|
|
93
|
+
results=[
|
|
94
|
+
PromptContextItem(
|
|
95
|
+
primary_results=primary_results,
|
|
96
|
+
related_results=related_results[:10], # Limit total related results
|
|
97
|
+
)
|
|
98
|
+
],
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Add mode-specific suggestions
|
|
103
|
+
first_title = "Recent Topic"
|
|
104
|
+
if primary_results and len(primary_results) > 0:
|
|
105
|
+
first_title = primary_results[0].title
|
|
106
|
+
|
|
107
|
+
if project:
|
|
108
|
+
# Project-specific suggestions
|
|
109
|
+
capture_suggestions = f"""
|
|
110
|
+
## Opportunity to Capture Activity Summary
|
|
111
|
+
|
|
112
|
+
Consider creating a summary note of recent activity in {project}:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
await write_note(
|
|
116
|
+
"{project}",
|
|
117
|
+
title="Activity Summary {timeframe}",
|
|
118
|
+
content='''
|
|
119
|
+
# Activity Summary for {project} ({timeframe})
|
|
120
|
+
|
|
121
|
+
## Overview
|
|
122
|
+
[Summary of key changes and developments in this project over this period]
|
|
123
|
+
|
|
124
|
+
## Key Updates
|
|
125
|
+
[List main updates and their significance within this project]
|
|
126
|
+
|
|
127
|
+
## Observations
|
|
128
|
+
- [trend] [Observation about patterns in recent activity]
|
|
129
|
+
- [insight] [Connection between different activities]
|
|
130
|
+
|
|
131
|
+
## Relations
|
|
132
|
+
- summarizes [[{first_title}]]
|
|
133
|
+
- relates_to [[{project} Overview]]
|
|
134
|
+
''',
|
|
135
|
+
folder="summaries"
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Summarizing periodic activity helps create high-level insights and connections within the project.
|
|
140
|
+
"""
|
|
141
|
+
else:
|
|
142
|
+
# Discovery mode suggestions
|
|
143
|
+
project_count = len(recent.projects) if isinstance(recent, ProjectActivitySummary) else 0
|
|
144
|
+
most_active = (
|
|
145
|
+
getattr(recent.summary, "most_active_project", "Unknown")
|
|
146
|
+
if isinstance(recent, ProjectActivitySummary)
|
|
147
|
+
else "Unknown"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
capture_suggestions = f"""
|
|
151
|
+
## Cross-Project Activity Discovery
|
|
152
|
+
|
|
153
|
+
Found activity across {project_count} projects. Most active: **{most_active}**
|
|
154
|
+
|
|
155
|
+
Consider creating a cross-project summary:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
await write_note(
|
|
159
|
+
"{most_active if most_active != "Unknown" else "main"}",
|
|
160
|
+
title="Cross-Project Activity Summary {timeframe}",
|
|
161
|
+
content='''
|
|
162
|
+
# Cross-Project Activity Summary ({timeframe})
|
|
163
|
+
|
|
164
|
+
## Overview
|
|
165
|
+
Activity found across {project_count} projects, with {most_active} showing the most activity.
|
|
166
|
+
|
|
167
|
+
## Key Developments
|
|
168
|
+
[Summarize important changes across all projects]
|
|
169
|
+
|
|
170
|
+
## Project Insights
|
|
171
|
+
[Note patterns or connections between projects]
|
|
172
|
+
|
|
173
|
+
## Observations
|
|
174
|
+
- [trend] [Cross-project patterns observed]
|
|
175
|
+
- [insight] [Connections between different project activities]
|
|
176
|
+
|
|
177
|
+
## Relations
|
|
178
|
+
- summarizes [[{first_title}]]
|
|
179
|
+
- relates_to [[Project Portfolio Overview]]
|
|
180
|
+
''',
|
|
181
|
+
folder="summaries"
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Cross-project summaries help identify broader trends and project interconnections.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
return prompt_context + capture_suggestions
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Search prompts for Basic Memory MCP server.
|
|
2
|
+
|
|
3
|
+
These prompts help users search and explore their knowledge base.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Annotated, Optional
|
|
7
|
+
|
|
8
|
+
from loguru import logger
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
|
|
11
|
+
from basic_memory.config import get_project_config
|
|
12
|
+
from basic_memory.mcp.async_client import get_client
|
|
13
|
+
from basic_memory.mcp.server import mcp
|
|
14
|
+
from basic_memory.mcp.tools.utils import call_post
|
|
15
|
+
from basic_memory.schemas.base import TimeFrame
|
|
16
|
+
from basic_memory.schemas.prompt import SearchPromptRequest
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@mcp.prompt(
|
|
20
|
+
name="search_knowledge_base",
|
|
21
|
+
description="Search across all content in basic-memory",
|
|
22
|
+
)
|
|
23
|
+
async def search_prompt(
|
|
24
|
+
query: str,
|
|
25
|
+
timeframe: Annotated[
|
|
26
|
+
Optional[TimeFrame],
|
|
27
|
+
Field(description="How far back to search (e.g. '1d', '1 week')"),
|
|
28
|
+
] = None,
|
|
29
|
+
) -> str:
|
|
30
|
+
"""Search across all content in basic-memory.
|
|
31
|
+
|
|
32
|
+
This prompt helps search for content in the knowledge base and
|
|
33
|
+
provides helpful context about the results.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
query: The search text to look for
|
|
37
|
+
timeframe: Optional timeframe to limit results (e.g. '1d', '1 week')
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Formatted search results with context
|
|
41
|
+
"""
|
|
42
|
+
logger.info(f"Searching knowledge base, query: {query}, timeframe: {timeframe}")
|
|
43
|
+
|
|
44
|
+
async with get_client() as client:
|
|
45
|
+
# Create request model
|
|
46
|
+
request = SearchPromptRequest(query=query, timeframe=timeframe)
|
|
47
|
+
|
|
48
|
+
project_url = get_project_config().project_url
|
|
49
|
+
|
|
50
|
+
# Call the prompt API endpoint
|
|
51
|
+
response = await call_post(
|
|
52
|
+
client, f"{project_url}/prompt/search", json=request.model_dump(exclude_none=True)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Extract the rendered prompt from the response
|
|
56
|
+
result = response.json()
|
|
57
|
+
return result["prompt"]
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Utility functions for formatting prompt responses.
|
|
2
|
+
|
|
3
|
+
These utilities help format data from various tools into consistent,
|
|
4
|
+
user-friendly markdown summaries.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from textwrap import dedent
|
|
9
|
+
from typing import List
|
|
10
|
+
|
|
11
|
+
from basic_memory.schemas.base import TimeFrame
|
|
12
|
+
from basic_memory.schemas.memory import (
|
|
13
|
+
normalize_memory_url,
|
|
14
|
+
EntitySummary,
|
|
15
|
+
RelationSummary,
|
|
16
|
+
ObservationSummary,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class PromptContextItem:
|
|
22
|
+
primary_results: List[EntitySummary]
|
|
23
|
+
related_results: List[EntitySummary | RelationSummary | ObservationSummary]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class PromptContext:
|
|
28
|
+
timeframe: TimeFrame
|
|
29
|
+
topic: str
|
|
30
|
+
results: List[PromptContextItem]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def format_prompt_context(context: PromptContext) -> str:
|
|
34
|
+
"""Format continuation context into a helpful summary.
|
|
35
|
+
Returns:
|
|
36
|
+
Formatted continuation summary
|
|
37
|
+
"""
|
|
38
|
+
if not context.results: # pragma: no cover
|
|
39
|
+
return dedent(f"""
|
|
40
|
+
# Continuing conversation on: {context.topic}
|
|
41
|
+
|
|
42
|
+
This is a memory retrieval session.
|
|
43
|
+
The supplied query did not return any information specifically on this topic.
|
|
44
|
+
|
|
45
|
+
## Opportunity to Capture New Knowledge!
|
|
46
|
+
|
|
47
|
+
This is an excellent chance to start documenting this topic:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
await write_note(
|
|
51
|
+
title="{context.topic}",
|
|
52
|
+
content=f'''
|
|
53
|
+
# {context.topic}
|
|
54
|
+
|
|
55
|
+
## Overview
|
|
56
|
+
[Summary of what we know about {context.topic}]
|
|
57
|
+
|
|
58
|
+
## Key Points
|
|
59
|
+
[Main aspects or components of {context.topic}]
|
|
60
|
+
|
|
61
|
+
## Observations
|
|
62
|
+
- [category] [First important observation about {context.topic}]
|
|
63
|
+
- [category] [Second observation about {context.topic}]
|
|
64
|
+
|
|
65
|
+
## Relations
|
|
66
|
+
- relates_to [[Related Topic]]
|
|
67
|
+
- part_of [[Broader Context]]
|
|
68
|
+
'''
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Other Options
|
|
73
|
+
|
|
74
|
+
Please use the available basic-memory tools to gather relevant context before responding.
|
|
75
|
+
You can also:
|
|
76
|
+
- Try a different search term
|
|
77
|
+
- Check recent activity with `recent_activity(timeframe="1w")`
|
|
78
|
+
""")
|
|
79
|
+
|
|
80
|
+
# Start building our summary with header - add knowledge capture emphasis
|
|
81
|
+
summary = dedent(f"""
|
|
82
|
+
# Continuing conversation on: {context.topic}
|
|
83
|
+
|
|
84
|
+
This is a memory retrieval session.
|
|
85
|
+
|
|
86
|
+
Please use the available basic-memory tools to gather relevant context before responding.
|
|
87
|
+
Start by executing one of the suggested commands below to retrieve content.
|
|
88
|
+
|
|
89
|
+
Here's what I found from previous conversations:
|
|
90
|
+
|
|
91
|
+
> **Knowledge Capture Recommendation:** As you continue this conversation, actively look for opportunities to record new information, decisions, or insights that emerge. Use `write_note()` to document important context.
|
|
92
|
+
""")
|
|
93
|
+
|
|
94
|
+
# Track what we've added to avoid duplicates
|
|
95
|
+
added_permalinks = set()
|
|
96
|
+
sections = []
|
|
97
|
+
|
|
98
|
+
# Process each context
|
|
99
|
+
for context in context.results: # pyright: ignore
|
|
100
|
+
for primary in context.primary_results: # pyright: ignore
|
|
101
|
+
if primary.permalink not in added_permalinks:
|
|
102
|
+
primary_permalink = primary.permalink
|
|
103
|
+
|
|
104
|
+
added_permalinks.add(primary_permalink)
|
|
105
|
+
|
|
106
|
+
# Use permalink if available, otherwise use file_path
|
|
107
|
+
if primary_permalink:
|
|
108
|
+
memory_url = normalize_memory_url(primary_permalink)
|
|
109
|
+
read_command = f'read_note("{primary_permalink}")'
|
|
110
|
+
else:
|
|
111
|
+
memory_url = f"file://{primary.file_path}"
|
|
112
|
+
read_command = f'read_file("{primary.file_path}")'
|
|
113
|
+
|
|
114
|
+
section = dedent(f"""
|
|
115
|
+
--- {memory_url}
|
|
116
|
+
|
|
117
|
+
## {primary.title}
|
|
118
|
+
- **Type**: {primary.type}
|
|
119
|
+
""")
|
|
120
|
+
|
|
121
|
+
# Add creation date
|
|
122
|
+
section += f"- **Created**: {primary.created_at.strftime('%Y-%m-%d %H:%M')}\n"
|
|
123
|
+
|
|
124
|
+
# Add content snippet
|
|
125
|
+
if hasattr(primary, "content") and primary.content: # pyright: ignore
|
|
126
|
+
content = primary.content or "" # pyright: ignore
|
|
127
|
+
if content:
|
|
128
|
+
section += f"\n**Excerpt**:\n{content}\n"
|
|
129
|
+
|
|
130
|
+
section += dedent(f"""
|
|
131
|
+
|
|
132
|
+
You can read this document with: `{read_command}`
|
|
133
|
+
""")
|
|
134
|
+
sections.append(section)
|
|
135
|
+
|
|
136
|
+
if context.related_results: # pyright: ignore
|
|
137
|
+
section += dedent( # pyright: ignore
|
|
138
|
+
"""
|
|
139
|
+
## Related Context
|
|
140
|
+
"""
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
for related in context.related_results: # pyright: ignore
|
|
144
|
+
section_content = dedent(f"""
|
|
145
|
+
- type: **{related.type}**
|
|
146
|
+
- title: {related.title}
|
|
147
|
+
""")
|
|
148
|
+
if related.permalink: # pragma: no cover
|
|
149
|
+
section_content += (
|
|
150
|
+
f'You can view this document with: `read_note("{related.permalink}")`'
|
|
151
|
+
)
|
|
152
|
+
else: # pragma: no cover
|
|
153
|
+
section_content += (
|
|
154
|
+
f'You can view this file with: `read_file("{related.file_path}")`'
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
section += section_content
|
|
158
|
+
sections.append(section)
|
|
159
|
+
|
|
160
|
+
# Add all sections
|
|
161
|
+
summary += "\n".join(sections)
|
|
162
|
+
return summary
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# AI Assistant Guide for Basic Memory
|
|
2
|
+
|
|
3
|
+
Quick reference for using Basic Memory tools effectively through MCP.
|
|
4
|
+
|
|
5
|
+
**For comprehensive coverage**: See the [Extended AI Assistant Guide](https://github.com/basicmachines-co/basic-memory/blob/main/docs/ai-assistant-guide-extended.md) with detailed examples, advanced patterns, and self-contained sections.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Basic Memory creates a semantic knowledge graph from markdown files. Focus on building rich connections between notes.
|
|
10
|
+
|
|
11
|
+
- **Local-First**: Plain text files on user's computer
|
|
12
|
+
- **Persistent**: Knowledge survives across sessions
|
|
13
|
+
- **Semantic**: Observations and relations create a knowledge graph
|
|
14
|
+
|
|
15
|
+
**Your role**: You're helping humans build enduring knowledge they'll own forever. The semantic graph (observations, relations, context) helps you provide better assistance by understanding connections and maintaining continuity. Think: lasting insights worth keeping, not disposable chat logs.
|
|
16
|
+
|
|
17
|
+
## Project Management
|
|
18
|
+
|
|
19
|
+
All tools require explicit project specification.
|
|
20
|
+
|
|
21
|
+
**Three-tier resolution:**
|
|
22
|
+
1. CLI constraint: `--project name` (highest priority)
|
|
23
|
+
2. Explicit parameter: `project="name"` in tool calls
|
|
24
|
+
3. Default mode: `default_project_mode=true` in config (fallback)
|
|
25
|
+
|
|
26
|
+
### Quick Setup Check
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
# Discover projects
|
|
30
|
+
projects = await list_memory_projects()
|
|
31
|
+
|
|
32
|
+
# Check if default_project_mode enabled
|
|
33
|
+
# If yes: project parameter optional
|
|
34
|
+
# If no: project parameter required
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Default Project Mode
|
|
38
|
+
|
|
39
|
+
When `default_project_mode=true`:
|
|
40
|
+
```python
|
|
41
|
+
# These are equivalent:
|
|
42
|
+
await write_note("Note", "Content", "folder")
|
|
43
|
+
await write_note("Note", "Content", "folder", project="main")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
When `default_project_mode=false` (default):
|
|
47
|
+
```python
|
|
48
|
+
# Project required:
|
|
49
|
+
await write_note("Note", "Content", "folder", project="main") # ✓
|
|
50
|
+
await write_note("Note", "Content", "folder") # ✗ Error
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Core Tools
|
|
54
|
+
|
|
55
|
+
### Writing Knowledge
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
await write_note(
|
|
59
|
+
title="Topic",
|
|
60
|
+
content="# Topic\n## Observations\n- [category] fact\n## Relations\n- relates_to [[Other]]",
|
|
61
|
+
folder="notes",
|
|
62
|
+
project="main" # Required unless default_project_mode=true
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Reading Knowledge
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# By identifier
|
|
70
|
+
content = await read_note("Topic", project="main")
|
|
71
|
+
|
|
72
|
+
# By memory:// URL
|
|
73
|
+
content = await read_note("memory://folder/topic", project="main")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Searching
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
results = await search_notes(
|
|
80
|
+
query="authentication",
|
|
81
|
+
project="main",
|
|
82
|
+
page_size=10
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Building Context
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
context = await build_context(
|
|
90
|
+
url="memory://specs/auth",
|
|
91
|
+
project="main",
|
|
92
|
+
depth=2,
|
|
93
|
+
timeframe="1 week"
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Knowledge Graph Essentials
|
|
98
|
+
|
|
99
|
+
### Observations
|
|
100
|
+
|
|
101
|
+
Categorized facts with optional tags:
|
|
102
|
+
```markdown
|
|
103
|
+
- [decision] Use JWT for authentication #security
|
|
104
|
+
- [technique] Hash passwords with bcrypt #best-practice
|
|
105
|
+
- [requirement] Support OAuth 2.0 providers
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Relations
|
|
109
|
+
|
|
110
|
+
Directional links between entities:
|
|
111
|
+
```markdown
|
|
112
|
+
- implements [[Authentication Spec]]
|
|
113
|
+
- requires [[User Database]]
|
|
114
|
+
- extends [[Base Security Model]]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Common relation types:** `relates_to`, `implements`, `requires`, `extends`, `part_of`, `contrasts_with`
|
|
118
|
+
|
|
119
|
+
### Forward References
|
|
120
|
+
|
|
121
|
+
Reference entities that don't exist yet:
|
|
122
|
+
```python
|
|
123
|
+
# Create note with forward reference
|
|
124
|
+
await write_note(
|
|
125
|
+
title="Login Flow",
|
|
126
|
+
content="## Relations\n- requires [[OAuth Provider]]", # Doesn't exist yet
|
|
127
|
+
folder="auth",
|
|
128
|
+
project="main"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Later, create referenced entity
|
|
132
|
+
await write_note(
|
|
133
|
+
title="OAuth Provider",
|
|
134
|
+
content="# OAuth Provider\n...",
|
|
135
|
+
folder="auth",
|
|
136
|
+
project="main"
|
|
137
|
+
)
|
|
138
|
+
# → Relation automatically resolved
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Best Practices
|
|
142
|
+
|
|
143
|
+
### 1. Project Management
|
|
144
|
+
|
|
145
|
+
**Single-project users:**
|
|
146
|
+
- Enable `default_project_mode=true`
|
|
147
|
+
- Simpler tool calls
|
|
148
|
+
|
|
149
|
+
**Multi-project users:**
|
|
150
|
+
- Keep `default_project_mode=false`
|
|
151
|
+
- Always specify project explicitly
|
|
152
|
+
|
|
153
|
+
**Discovery:**
|
|
154
|
+
```python
|
|
155
|
+
# Start with discovery
|
|
156
|
+
projects = await list_memory_projects()
|
|
157
|
+
|
|
158
|
+
# Cross-project activity (no project param = all projects)
|
|
159
|
+
activity = await recent_activity()
|
|
160
|
+
|
|
161
|
+
# Or specific project
|
|
162
|
+
activity = await recent_activity(project="main")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 2. Building Rich Graphs
|
|
166
|
+
|
|
167
|
+
**Always include:**
|
|
168
|
+
- 3-5 observations per note
|
|
169
|
+
- 2-3 relations per note
|
|
170
|
+
- Meaningful categories and relation types
|
|
171
|
+
|
|
172
|
+
**Search before creating:**
|
|
173
|
+
```python
|
|
174
|
+
# Find existing entities to reference
|
|
175
|
+
results = await search_notes(query="authentication", project="main")
|
|
176
|
+
# Use exact titles in [[WikiLinks]]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 3. Writing Effective Notes
|
|
180
|
+
|
|
181
|
+
**Structure:**
|
|
182
|
+
```markdown
|
|
183
|
+
# Title
|
|
184
|
+
|
|
185
|
+
## Context
|
|
186
|
+
Background information
|
|
187
|
+
|
|
188
|
+
## Observations
|
|
189
|
+
- [category] Fact with #tags
|
|
190
|
+
- [category] Another fact
|
|
191
|
+
|
|
192
|
+
## Relations
|
|
193
|
+
- relation_type [[Exact Entity Title]]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Categories:** `[idea]`, `[decision]`, `[fact]`, `[technique]`, `[requirement]`
|
|
197
|
+
|
|
198
|
+
### 4. Error Handling
|
|
199
|
+
|
|
200
|
+
**Missing project:**
|
|
201
|
+
```python
|
|
202
|
+
try:
|
|
203
|
+
await search_notes(query="test") # Missing project parameter - will error
|
|
204
|
+
except:
|
|
205
|
+
# Show available projects
|
|
206
|
+
projects = await list_memory_projects()
|
|
207
|
+
# Then retry with project
|
|
208
|
+
results = await search_notes(query="test", project=projects[0].name)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Forward references:**
|
|
212
|
+
```python
|
|
213
|
+
# Check response for unresolved relations
|
|
214
|
+
response = await write_note(
|
|
215
|
+
title="New Topic",
|
|
216
|
+
content="## Relations\n- relates_to [[Future Topic]]",
|
|
217
|
+
folder="notes",
|
|
218
|
+
project="main"
|
|
219
|
+
)
|
|
220
|
+
# Forward refs will resolve when target created
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 5. Recording Context
|
|
224
|
+
|
|
225
|
+
**Ask permission:**
|
|
226
|
+
> "Would you like me to save our discussion about [topic] to Basic Memory?"
|
|
227
|
+
|
|
228
|
+
**Confirm when done:**
|
|
229
|
+
> "I've saved our discussion to Basic Memory."
|
|
230
|
+
|
|
231
|
+
**What to record:**
|
|
232
|
+
- Decisions and rationales
|
|
233
|
+
- Important discoveries
|
|
234
|
+
- Action items and plans
|
|
235
|
+
- Connected topics
|
|
236
|
+
|
|
237
|
+
## Common Patterns
|
|
238
|
+
|
|
239
|
+
### Capture Decision
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
await write_note(
|
|
243
|
+
title="DB Choice",
|
|
244
|
+
content="""# DB Choice\n## Decision\nUse PostgreSQL\n## Observations\n- [requirement] ACID compliance #reliability\n- [decision] PostgreSQL over MySQL\n## Relations\n- implements [[Data Architecture]]""",
|
|
245
|
+
folder="decisions",
|
|
246
|
+
project="main"
|
|
247
|
+
)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Link Topics & Build Context
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
# Link bidirectionally
|
|
254
|
+
await write_note(title="API Auth", content="## Relations\n- part_of [[API Design]]", folder="api", project="main")
|
|
255
|
+
await edit_note(identifier="API Design", operation="append", content="\n- includes [[API Auth]]", project="main")
|
|
256
|
+
|
|
257
|
+
# Search and build context
|
|
258
|
+
results = await search_notes(query="authentication", project="main")
|
|
259
|
+
context = await build_context(url=f"memory://{results[0].permalink}", project="main", depth=2)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Tool Quick Reference
|
|
263
|
+
|
|
264
|
+
| Tool | Purpose | Key Params |
|
|
265
|
+
|------|---------|------------|
|
|
266
|
+
| `write_note` | Create/update | title, content, folder, project |
|
|
267
|
+
| `read_note` | Read content | identifier, project |
|
|
268
|
+
| `edit_note` | Modify existing | identifier, operation, content, project |
|
|
269
|
+
| `search_notes` | Find notes | query, project |
|
|
270
|
+
| `build_context` | Graph traversal | url, depth, project |
|
|
271
|
+
| `recent_activity` | Recent changes | timeframe, project |
|
|
272
|
+
| `list_memory_projects` | Show projects | (none) |
|
|
273
|
+
|
|
274
|
+
## memory:// URL Format
|
|
275
|
+
|
|
276
|
+
- `memory://title` - By title
|
|
277
|
+
- `memory://folder/title` - By folder + title
|
|
278
|
+
- `memory://permalink` - By permalink
|
|
279
|
+
- `memory://folder/*` - All in folder
|
|
280
|
+
|
|
281
|
+
For full documentation: https://docs.basicmemory.com
|
|
282
|
+
|
|
283
|
+
Built with ♥️ by Basic Machines
|