basic-memory 0.12.0__tar.gz → 0.12.2__tar.gz

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.

Potentially problematic release.


This version of basic-memory might be problematic. Click here for more details.

Files changed (228) hide show
  1. {basic_memory-0.12.0 → basic_memory-0.12.2}/CHANGELOG.md +20 -0
  2. {basic_memory-0.12.0 → basic_memory-0.12.2}/PKG-INFO +3 -9
  3. {basic_memory-0.12.0 → basic_memory-0.12.2}/README.md +2 -8
  4. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/CLI Reference.md +16 -0
  5. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Getting Started with Basic Memory.md +9 -20
  6. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Knowledge Format.md +13 -1
  7. {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/installer.py +1 -1
  8. {basic_memory-0.12.0 → basic_memory-0.12.2}/pyproject.toml +1 -1
  9. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/__init__.py +1 -1
  10. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/app.py +3 -34
  11. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/app.py +13 -1
  12. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_memory_json.py +1 -1
  13. basic_memory-0.12.2/src/basic_memory/cli/commands/mcp.py +35 -0
  14. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/sync.py +8 -8
  15. basic_memory-0.12.2/src/basic_memory/cli/main.py +26 -0
  16. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/config.py +2 -2
  17. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/entity_parser.py +1 -1
  18. basic_memory-0.12.2/src/basic_memory/mcp/server.py +37 -0
  19. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/repository.py +0 -4
  20. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/file_service.py +1 -1
  21. basic_memory-0.12.2/src/basic_memory/services/initialization.py +143 -0
  22. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/sync/sync_service.py +75 -185
  23. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/sync/watch_service.py +49 -30
  24. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_resource_router.py +3 -3
  25. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_cli_tools.py +28 -0
  26. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_chatgpt.py +8 -7
  27. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_claude_conversations.py +5 -4
  28. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_claude_projects.py +5 -4
  29. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_import_memory_json.py +4 -3
  30. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/conftest.py +1 -1
  31. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_markdown_processor.py +5 -5
  32. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_canvas.py +4 -4
  33. basic_memory-0.12.2/tests/services/test_initialization.py +49 -0
  34. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_sync_service.py +36 -36
  35. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_sync_wikilink_issue.py +6 -5
  36. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_tmp_files.py +2 -2
  37. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_watch_service.py +6 -6
  38. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_file_utils.py +10 -10
  39. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_permalink_formatting.py +3 -2
  40. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_utf8_handling.py +2 -2
  41. {basic_memory-0.12.0 → basic_memory-0.12.2}/uv.lock +1 -1
  42. basic_memory-0.12.0/src/basic_memory/cli/commands/mcp.py +0 -33
  43. basic_memory-0.12.0/src/basic_memory/cli/main.py +0 -67
  44. basic_memory-0.12.0/src/basic_memory/mcp/server.py +0 -11
  45. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  46. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  47. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
  48. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  49. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/dependabot.yml +0 -0
  50. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/claude-code-actions.yml +0 -0
  51. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/pr-title.yml +0 -0
  52. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/release.yml +0 -0
  53. {basic_memory-0.12.0 → basic_memory-0.12.2}/.github/workflows/test.yml +0 -0
  54. {basic_memory-0.12.0 → basic_memory-0.12.2}/.gitignore +0 -0
  55. {basic_memory-0.12.0 → basic_memory-0.12.2}/.python-version +0 -0
  56. {basic_memory-0.12.0 → basic_memory-0.12.2}/CITATION.cff +0 -0
  57. {basic_memory-0.12.0 → basic_memory-0.12.2}/CLA.md +0 -0
  58. {basic_memory-0.12.0 → basic_memory-0.12.2}/CLAUDE.md +0 -0
  59. {basic_memory-0.12.0 → basic_memory-0.12.2}/CODE_OF_CONDUCT.md +0 -0
  60. {basic_memory-0.12.0 → basic_memory-0.12.2}/CONTRIBUTING.md +0 -0
  61. {basic_memory-0.12.0 → basic_memory-0.12.2}/Dockerfile +0 -0
  62. {basic_memory-0.12.0 → basic_memory-0.12.2}/LICENSE +0 -0
  63. {basic_memory-0.12.0 → basic_memory-0.12.2}/Makefile +0 -0
  64. {basic_memory-0.12.0 → basic_memory-0.12.2}/SECURITY.md +0 -0
  65. {basic_memory-0.12.0 → basic_memory-0.12.2}/basic-memory.md +0 -0
  66. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/AI Assistant Guide.md +0 -0
  67. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Canvas.md +0 -0
  68. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Obsidian Integration.md +0 -0
  69. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Technical Information.md +0 -0
  70. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/User Guide.md +0 -0
  71. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/Welcome to Basic memory.md +0 -0
  72. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/Canvas.png +0 -0
  73. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/Claude-Obsidian-Demo.mp4 +0 -0
  74. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/Prompt.png +0 -0
  75. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/disk-ai-logo-400x400.png +0 -0
  76. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/disk-ai-logo.png +0 -0
  77. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt 1.png +0 -0
  78. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt2.png +0 -0
  79. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt3.png +0 -0
  80. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/attachments/prompt4.png +0 -0
  81. {basic_memory-0.12.0 → basic_memory-0.12.2}/docs/publish.js +0 -0
  82. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Brewing Equipment.md +0 -0
  83. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Bean Origins.md +0 -0
  84. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Brewing Methods.md +0 -0
  85. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Flavor Map.md +0 -0
  86. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Coffee Knowledge Base.md +0 -0
  87. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Flavor Extraction.md +0 -0
  88. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Perfect Pour Over Coffee Method.canvas +0 -0
  89. {basic_memory-0.12.0 → basic_memory-0.12.2}/examples/Coffee Notes/Tasting Notes.md +0 -0
  90. {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/Basic.icns +0 -0
  91. {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/README.md +0 -0
  92. {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/icon.svg +0 -0
  93. {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/make_icons.sh +0 -0
  94. {basic_memory-0.12.0 → basic_memory-0.12.2}/installer/setup.py +0 -0
  95. {basic_memory-0.12.0 → basic_memory-0.12.2}/llms-install.md +0 -0
  96. {basic_memory-0.12.0 → basic_memory-0.12.2}/memory.json +0 -0
  97. {basic_memory-0.12.0 → basic_memory-0.12.2}/scripts/install.sh +0 -0
  98. {basic_memory-0.12.0 → basic_memory-0.12.2}/smithery.yaml +0 -0
  99. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/alembic.ini +0 -0
  100. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/env.py +0 -0
  101. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/migrations.py +0 -0
  102. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/script.py.mako +0 -0
  103. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +0 -0
  104. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py +0 -0
  105. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py +0 -0
  106. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +0 -0
  107. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/__init__.py +0 -0
  108. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/__init__.py +0 -0
  109. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/knowledge_router.py +0 -0
  110. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/memory_router.py +0 -0
  111. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/project_info_router.py +0 -0
  112. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/resource_router.py +0 -0
  113. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/api/routers/search_router.py +0 -0
  114. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/__init__.py +0 -0
  115. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/__init__.py +0 -0
  116. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/db.py +0 -0
  117. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_chatgpt.py +0 -0
  118. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_claude_conversations.py +0 -0
  119. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/import_claude_projects.py +0 -0
  120. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/project.py +0 -0
  121. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/status.py +0 -0
  122. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/cli/commands/tool.py +0 -0
  123. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/db.py +0 -0
  124. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/deps.py +0 -0
  125. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/file_utils.py +0 -0
  126. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/__init__.py +0 -0
  127. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/markdown_processor.py +0 -0
  128. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/plugins.py +0 -0
  129. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/schemas.py +0 -0
  130. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/markdown/utils.py +0 -0
  131. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/__init__.py +0 -0
  132. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/async_client.py +0 -0
  133. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/main.py +0 -0
  134. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/__init__.py +0 -0
  135. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/ai_assistant_guide.py +0 -0
  136. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/continue_conversation.py +0 -0
  137. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/recent_activity.py +0 -0
  138. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/search.py +0 -0
  139. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/prompts/utils.py +0 -0
  140. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/resources/ai_assistant_guide.md +0 -0
  141. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/__init__.py +0 -0
  142. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/build_context.py +0 -0
  143. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/canvas.py +0 -0
  144. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/delete_note.py +0 -0
  145. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/project_info.py +0 -0
  146. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/read_content.py +0 -0
  147. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/read_note.py +0 -0
  148. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/recent_activity.py +0 -0
  149. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/search.py +0 -0
  150. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/utils.py +0 -0
  151. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/mcp/tools/write_note.py +0 -0
  152. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/__init__.py +0 -0
  153. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/base.py +0 -0
  154. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/knowledge.py +0 -0
  155. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/models/search.py +0 -0
  156. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/__init__.py +0 -0
  157. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/entity_repository.py +0 -0
  158. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/observation_repository.py +0 -0
  159. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/project_info_repository.py +0 -0
  160. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/relation_repository.py +0 -0
  161. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/repository/search_repository.py +0 -0
  162. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/__init__.py +0 -0
  163. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/base.py +0 -0
  164. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/delete.py +0 -0
  165. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/memory.py +0 -0
  166. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/project_info.py +0 -0
  167. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/request.py +0 -0
  168. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/response.py +0 -0
  169. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/schemas/search.py +0 -0
  170. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/__init__.py +0 -0
  171. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/context_service.py +0 -0
  172. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/entity_service.py +0 -0
  173. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/exceptions.py +0 -0
  174. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/link_resolver.py +0 -0
  175. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/search_service.py +0 -0
  176. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/services/service.py +0 -0
  177. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/sync/__init__.py +0 -0
  178. {basic_memory-0.12.0 → basic_memory-0.12.2}/src/basic_memory/utils.py +0 -0
  179. {basic_memory-0.12.0 → basic_memory-0.12.2}/static/ai_assistant_guide.md +0 -0
  180. {basic_memory-0.12.0 → basic_memory-0.12.2}/static/json_canvas_spec_1_0.md +0 -0
  181. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/Non-MarkdownFileSupport.pdf +0 -0
  182. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/Screenshot.png +0 -0
  183. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/__init__.py +0 -0
  184. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/conftest.py +0 -0
  185. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_knowledge_router.py +0 -0
  186. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_memory_router.py +0 -0
  187. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_project_info_router.py +0 -0
  188. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/api/test_search_router.py +0 -0
  189. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/conftest.py +0 -0
  190. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_project_commands.py +0 -0
  191. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_project_info.py +0 -0
  192. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_status.py +0 -0
  193. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_sync.py +0 -0
  194. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/cli/test_version.py +0 -0
  195. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/edit_file_test.py +0 -0
  196. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/__init__.py +0 -0
  197. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_entity_parser.py +0 -0
  198. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_markdown_plugins.py +0 -0
  199. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_observation_edge_cases.py +0 -0
  200. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_parser_edge_cases.py +0 -0
  201. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_relation_edge_cases.py +0 -0
  202. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/markdown/test_task_detection.py +0 -0
  203. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/conftest.py +0 -0
  204. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_prompts.py +0 -0
  205. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_resources.py +0 -0
  206. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_memory.py +0 -0
  207. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_project_info.py +0 -0
  208. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_read_note.py +0 -0
  209. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_resource.py +0 -0
  210. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_search.py +0 -0
  211. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_utils.py +0 -0
  212. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/mcp/test_tool_write_note.py +0 -0
  213. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_entity_repository.py +0 -0
  214. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_observation_repository.py +0 -0
  215. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_relation_repository.py +0 -0
  216. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/repository/test_repository.py +0 -0
  217. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/schemas/test_memory_url.py +0 -0
  218. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/schemas/test_schemas.py +0 -0
  219. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/schemas/test_search.py +0 -0
  220. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_context_service.py +0 -0
  221. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_entity_service.py +0 -0
  222. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_file_service.py +0 -0
  223. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_link_resolver.py +0 -0
  224. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/services/test_search_service.py +0 -0
  225. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/sync/test_watch_service_edge_cases.py +0 -0
  226. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/test_basic_memory.py +0 -0
  227. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/test_config.py +0 -0
  228. {basic_memory-0.12.0 → basic_memory-0.12.2}/tests/utils/test_parse_tags.py +0 -0
@@ -1,6 +1,26 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v0.12.2 (2025-04-08)
5
+
6
+ ### Bug Fixes
7
+
8
+ - Utf8 for all file reads/write/open instead of default platform encoding
9
+ ([#91](https://github.com/basicmachines-co/basic-memory/pull/91),
10
+ [`2934176`](https://github.com/basicmachines-co/basic-memory/commit/29341763318408ea8f1e954a41046c4185f836c6))
11
+
12
+ Signed-off-by: phernandez <paul@basicmachines.co>
13
+
14
+
15
+ ## v0.12.1 (2025-04-07)
16
+
17
+ ### Bug Fixes
18
+
19
+ - Run migrations and sync when starting mcp
20
+ ([#88](https://github.com/basicmachines-co/basic-memory/pull/88),
21
+ [`78a3412`](https://github.com/basicmachines-co/basic-memory/commit/78a3412bcff83b46e78e26f8b9fce42ed9e05991))
22
+
23
+
4
24
  ## v0.12.0 (2025-04-06)
5
25
 
6
26
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-memory
3
- Version: 0.12.0
3
+ Version: 0.12.2
4
4
  Summary: Local-first knowledge management combining Zettelkasten with knowledge graphs
5
5
  Project-URL: Homepage, https://github.com/basicmachines-co/basic-memory
6
6
  Project-URL: Repository, https://github.com/basicmachines-co/basic-memory
@@ -187,7 +187,7 @@ The note embeds semantic content and links to other topics via simple Markdown f
187
187
 
188
188
  3. You see this file on your computer in real time in the current project directory (default `~/$HOME/basic-memory`).
189
189
 
190
- - Realtime sync can be enabled via running `basic-memory sync --watch`
190
+ - Realtime sync is enabled by default with the v0.12.0 version
191
191
 
192
192
  4. In a chat with the LLM, you can reference a topic:
193
193
 
@@ -378,13 +378,7 @@ config:
378
378
 
379
379
  2. Sync your knowledge:
380
380
 
381
- ```bash
382
- # One-time sync of local knowledge updates
383
- basic-memory sync
384
-
385
- # Run realtime sync process (recommended)
386
- basic-memory sync --watch
387
- ```
381
+ Basic Memory will sync the files in your project in real time if you make manual edits.
388
382
 
389
383
  3. In Claude Desktop, the LLM can now use these tools:
390
384
 
@@ -153,7 +153,7 @@ The note embeds semantic content and links to other topics via simple Markdown f
153
153
 
154
154
  3. You see this file on your computer in real time in the current project directory (default `~/$HOME/basic-memory`).
155
155
 
156
- - Realtime sync can be enabled via running `basic-memory sync --watch`
156
+ - Realtime sync is enabled by default with the v0.12.0 version
157
157
 
158
158
  4. In a chat with the LLM, you can reference a topic:
159
159
 
@@ -344,13 +344,7 @@ config:
344
344
 
345
345
  2. Sync your knowledge:
346
346
 
347
- ```bash
348
- # One-time sync of local knowledge updates
349
- basic-memory sync
350
-
351
- # Run realtime sync process (recommended)
352
- basic-memory sync --watch
353
- ```
347
+ Basic Memory will sync the files in your project in real time if you make manual edits.
354
348
 
355
349
  3. In Claude Desktop, the LLM can now use these tools:
356
350
 
@@ -29,6 +29,22 @@ Options:
29
29
  - `--watch`: Continuously monitor for changes
30
30
  - `--verbose`: Show detailed output
31
31
 
32
+ **Note**:
33
+
34
+ As of the v0.12.0 release syncing will occur in real time when the mcp process starts.
35
+ - The real time sync means that it is no longer necessary to run the `basic-memory sync --watch` process in a a terminal to sync changes to the db (so the AI can see them). This will be done automatically.
36
+
37
+ This behavior can be changed via the config. The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.
38
+
39
+ To change the properties, set the following values:
40
+ ```
41
+ ~/.basic-memory/config.json
42
+ {
43
+ "sync_changes": false,
44
+ }
45
+ ```
46
+
47
+ Thanks for using Basic Memory!
32
48
  ### import
33
49
 
34
50
  Imports external knowledge sources:
@@ -89,22 +89,11 @@ Replace `/absolute/path/to/uvx` with the actual path you found in Step 1.
89
89
 
90
90
  Close and reopen Claude Desktop for the changes to take effect.
91
91
 
92
- ### 3. Start the Sync Service
92
+ ### 3. Sync changes in real time
93
93
 
94
- > Note the sync service is optional. You can run it if you want your local change to be available in Claude Desktop
95
-
96
- Start the sync service to monitor your files for changes:
97
-
98
- ```bash
99
- # One-time sync
100
- basic-memory sync
101
-
102
- # For continuous monitoring (recommended)
103
- basic-memory sync --watch
104
- ```
105
-
106
- The `--watch` flag enables automatic detection of file changes, updating your knowledge in real time.
94
+ > **Note**: The service will sync changes from your project directory in real time so they available for the AI assistant.
107
95
 
96
+ To disable realtime sync, you can update the config. See [[CLI Reference#sync]].
108
97
  ### 4. Staying Updated
109
98
 
110
99
  To update Basic Memory when new versions are released:
@@ -145,8 +134,8 @@ If Claude cannot find Basic Memory tools:
145
134
  1. **Check absolute paths**: Ensure you're using complete absolute paths to uvx in the Claude Desktop configuration
146
135
  2. **Verify installation**: Run `basic-memory --version` in Terminal to confirm Basic Memory is installed
147
136
  3. **Restart applications**: Restart both Terminal and Claude Desktop after making configuration changes
148
- 4. **Check sync status**: Ensure `basic-memory sync --watch` is running
149
-
137
+ 4. **Check sync status**: You can view the sync status by running `basic-memory status
138
+ .
150
139
  #### Permission Issues
151
140
 
152
141
  If you encounter permission errors:
@@ -282,15 +271,15 @@ basic-memory import claude conversations
282
271
  basic-memory import chatgpt
283
272
  ```
284
273
 
285
- After importing, run `basic-memory sync` to index everything.
274
+ After importing, the changes will be synced. Initial syncs may take a few moments. You can see info about your project by running `basic-memrory project info`.
286
275
 
287
276
  ## Quick Tips
288
277
 
289
- - Keep `basic-memory sync --watch` running in a terminal window
278
+ - Basic Memory will sync changes from your project in real time.
290
279
  - Use special prompts (Continue Conversation, Recent Activity, Search) to start contextual discussions
291
280
  - Build connections between notes for a richer knowledge graph
292
- - Use direct memory:// URLs when you need precise context
293
- - Use git to version control your knowledge base
281
+ - Use direct `memory://` URLs with a permalink when you need precise context. See [[User Guide#Using memory // URLs]]
282
+ - Use git to version control your knowledge base (git integration is on the roadmap)
294
283
  - Review and edit AI-generated notes for accuracy
295
284
 
296
285
  ## Next Steps
@@ -144,7 +144,19 @@ permalink: auth-approaches-2024
144
144
  ---
145
145
  ```
146
146
 
147
- If not specified, one will be generated automatically from the title.
147
+ If not specified, one will be generated automatically from the title, if the note has has a frontmatter section.
148
+
149
+ By default a notes' permalink value will not change if the file is moved. It's a **stable** identifier :). But if you'd rather permalinks are always updated when a file moves, you can set the config setting in the global config.
150
+
151
+ The config file for Basic Memory is in the home directory under `.basic-memory/config.json`.
152
+
153
+ To change the behavior, set the following value:
154
+ ```
155
+ ~/.basic-memory/config.json
156
+ {
157
+ "update_permalinks_on_move": true
158
+ }
159
+ ```
148
160
 
149
161
  ### Using memory:// URLs
150
162
 
@@ -44,7 +44,7 @@ def update_claude_config():
44
44
 
45
45
  # Load existing config or create new
46
46
  if config_path.exists():
47
- config = json.loads(config_path.read_text())
47
+ config = json.loads(config_path.read_text(encoding="utf-8"))
48
48
  else:
49
49
  config = {"mcpServers": {}}
50
50
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "basic-memory"
3
- version = "0.12.0"
3
+ version = "0.12.2"
4
4
  description = "Local-first knowledge management combining Zettelkasten with knowledge graphs"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12.1"
@@ -1,3 +1,3 @@
1
1
  """basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
2
2
 
3
- __version__ = "0.12.0"
3
+ __version__ = "0.12.2"
@@ -1,6 +1,5 @@
1
1
  """FastAPI application for basic-memory knowledge graph API."""
2
2
 
3
- import asyncio
4
3
  from contextlib import asynccontextmanager
5
4
 
6
5
  from fastapi import FastAPI, HTTPException
@@ -10,44 +9,14 @@ from loguru import logger
10
9
  from basic_memory import db
11
10
  from basic_memory.api.routers import knowledge, memory, project_info, resource, search
12
11
  from basic_memory.config import config as project_config
13
- from basic_memory.config import config_manager
14
- from basic_memory.sync import SyncService, WatchService
15
-
16
-
17
- async def run_background_sync(sync_service: SyncService, watch_service: WatchService): # pragma: no cover
18
- logger.info(f"Starting watch service to sync file changes in dir: {project_config.home}")
19
- # full sync
20
- await sync_service.sync(project_config.home, show_progress=False)
21
-
22
- # watch changes
23
- await watch_service.run()
12
+ from basic_memory.services.initialization import initialize_app
24
13
 
25
14
 
26
15
  @asynccontextmanager
27
16
  async def lifespan(app: FastAPI): # pragma: no cover
28
17
  """Lifecycle manager for the FastAPI app."""
29
- await db.run_migrations(project_config)
30
-
31
- # app config
32
- basic_memory_config = config_manager.load_config()
33
- logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
34
- logger.info(f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}")
35
-
36
- watch_task = None
37
- if basic_memory_config.sync_changes:
38
- # import after migrations have run
39
- from basic_memory.cli.commands.sync import get_sync_service
40
-
41
- sync_service = await get_sync_service()
42
- watch_service = WatchService(
43
- sync_service=sync_service,
44
- file_service=sync_service.entity_service.file_service,
45
- config=project_config,
46
- )
47
- watch_task = asyncio.create_task(run_background_sync(sync_service, watch_service))
48
- else:
49
- logger.info("Sync changes disabled. Skipping watch service.")
50
-
18
+ # Initialize database and file sync services
19
+ watch_task = await initialize_app(project_config)
51
20
 
52
21
  # proceed with startup
53
22
  yield
@@ -7,8 +7,11 @@ def version_callback(value: bool) -> None:
7
7
  """Show version and exit."""
8
8
  if value: # pragma: no cover
9
9
  import basic_memory
10
+ from basic_memory.config import config
10
11
 
11
12
  typer.echo(f"Basic Memory version: {basic_memory.__version__}")
13
+ typer.echo(f"Current project: {config.project}")
14
+ typer.echo(f"Project path: {config.home}")
12
15
  raise typer.Exit()
13
16
 
14
17
 
@@ -17,11 +20,12 @@ app = typer.Typer(name="basic-memory")
17
20
 
18
21
  @app.callback()
19
22
  def app_callback(
23
+ ctx: typer.Context,
20
24
  project: Optional[str] = typer.Option(
21
25
  None,
22
26
  "--project",
23
27
  "-p",
24
- help="Specify which project to use",
28
+ help="Specify which project to use 1",
25
29
  envvar="BASIC_MEMORY_PROJECT",
26
30
  ),
27
31
  version: Optional[bool] = typer.Option(
@@ -34,6 +38,7 @@ def app_callback(
34
38
  ),
35
39
  ) -> None:
36
40
  """Basic Memory - Local-first personal knowledge management."""
41
+
37
42
  # We use the project option to set the BASIC_MEMORY_PROJECT environment variable
38
43
  # The config module will pick this up when loading
39
44
  if project: # pragma: no cover
@@ -53,6 +58,13 @@ def app_callback(
53
58
 
54
59
  config = new_config
55
60
 
61
+ # Run migrations for every command unless --version was specified
62
+ if not version and ctx.invoked_subcommand is not None:
63
+ from basic_memory.config import config
64
+ from basic_memory.services.initialization import ensure_initialize_database
65
+
66
+ ensure_initialize_database(config)
67
+
56
68
 
57
69
  # Register sub-command groups
58
70
  import_app = typer.Typer(help="Import data from various sources")
@@ -38,7 +38,7 @@ async def process_memory_json(
38
38
  read_task = progress.add_task("Reading memory.json...", total=None)
39
39
 
40
40
  # First pass - collect entities and relations
41
- with open(json_path) as f:
41
+ with open(json_path, encoding="utf-8") as f:
42
42
  lines = f.readlines()
43
43
  progress.update(read_task, total=len(lines))
44
44
 
@@ -0,0 +1,35 @@
1
+ """MCP server command."""
2
+
3
+ import basic_memory
4
+ from basic_memory.cli.app import app
5
+
6
+ # Import mcp instance
7
+ from basic_memory.mcp.server import mcp as mcp_server # pragma: no cover
8
+
9
+ # Import mcp tools to register them
10
+ import basic_memory.mcp.tools # noqa: F401 # pragma: no cover
11
+
12
+
13
+ @app.command()
14
+ def mcp(): # pragma: no cover
15
+ """Run the MCP server"""
16
+ from basic_memory.config import config
17
+ import asyncio
18
+ from basic_memory.services.initialization import initialize_database
19
+
20
+ # First, run just the database migrations synchronously
21
+ asyncio.run(initialize_database(config))
22
+
23
+ # Load config to check if sync is enabled
24
+ from basic_memory.config import config_manager
25
+
26
+ basic_memory_config = config_manager.load_config()
27
+
28
+ if basic_memory_config.sync_changes:
29
+ # For now, we'll just log that sync will be handled by the MCP server
30
+ from loguru import logger
31
+
32
+ logger.info("File sync will be handled by the MCP server")
33
+
34
+ # Start the MCP server
35
+ mcp_server.run()
@@ -179,14 +179,14 @@ async def run_sync(verbose: bool = False, watch: bool = False, console_status: b
179
179
  )
180
180
 
181
181
  # full sync - no progress bars in watch mode
182
- await sync_service.sync(config.home, show_progress=False)
182
+ await sync_service.sync(config.home)
183
183
 
184
184
  # watch changes
185
185
  await watch_service.run() # pragma: no cover
186
186
  else:
187
- # one time sync - use progress bars for better UX
187
+ # one time sync
188
188
  logger.info("Running one-time sync")
189
- knowledge_changes = await sync_service.sync(config.home, show_progress=True)
189
+ knowledge_changes = await sync_service.sync(config.home)
190
190
 
191
191
  # Log results
192
192
  duration_ms = int((time.time() - start_time) * 1000)
@@ -237,11 +237,11 @@ def sync(
237
237
  if not isinstance(e, typer.Exit):
238
238
  logger.exception(
239
239
  "Sync command failed",
240
- project=config.project,
241
- error=str(e),
242
- error_type=type(e).__name__,
243
- watch_mode=watch,
244
- directory=str(config.home),
240
+ f"project={config.project},"
241
+ f"error={str(e)},"
242
+ f"error_type={type(e).__name__},"
243
+ f"watch_mode={watch},"
244
+ f"directory={str(config.home)}",
245
245
  )
246
246
  typer.echo(f"Error during sync: {e}", err=True)
247
247
  raise typer.Exit(1)
@@ -0,0 +1,26 @@
1
+ """Main CLI entry point for basic-memory.""" # pragma: no cover
2
+
3
+ from basic_memory.cli.app import app # pragma: no cover
4
+
5
+ # Register commands
6
+ from basic_memory.cli.commands import ( # noqa: F401 # pragma: no cover
7
+ db,
8
+ import_chatgpt,
9
+ import_claude_conversations,
10
+ import_claude_projects,
11
+ import_memory_json,
12
+ mcp,
13
+ project,
14
+ status,
15
+ sync,
16
+ tool,
17
+ )
18
+ from basic_memory.config import config
19
+ from basic_memory.services.initialization import ensure_initialization
20
+
21
+ if __name__ == "__main__": # pragma: no cover
22
+ # Run initialization if we are starting as a module
23
+ ensure_initialization(config)
24
+
25
+ # start the app
26
+ app()
@@ -35,7 +35,7 @@ class ProjectConfig(BaseSettings):
35
35
 
36
36
  # Watch service configuration
37
37
  sync_delay: int = Field(
38
- default=500, description="Milliseconds to wait after changes before syncing", gt=0
38
+ default=1000, description="Milliseconds to wait after changes before syncing", gt=0
39
39
  )
40
40
 
41
41
  # update permalinks on move
@@ -274,7 +274,7 @@ def setup_basic_memory_logging(): # pragma: no cover
274
274
  console=False,
275
275
  )
276
276
 
277
- logger.info(f"Starting Basic Memory {basic_memory.__version__} (Project: {config.project})")
277
+ logger.info(f"Basic Memory {basic_memory.__version__} (Project: {config.project})")
278
278
  _LOGGING_SETUP = True
279
279
 
280
280
 
@@ -104,7 +104,7 @@ class EntityParser:
104
104
  absolute_path = self.base_path / path
105
105
 
106
106
  # Parse frontmatter and content using python-frontmatter
107
- file_content = absolute_path.read_text()
107
+ file_content = absolute_path.read_text(encoding="utf-8")
108
108
  return await self.parse_file_content(absolute_path, file_content)
109
109
 
110
110
  async def parse_file_content(self, absolute_path, file_content):
@@ -0,0 +1,37 @@
1
+ """Enhanced FastMCP server instance for Basic Memory."""
2
+
3
+ import asyncio
4
+ from contextlib import asynccontextmanager
5
+ from typing import AsyncIterator, Optional
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+ from mcp.server.fastmcp.utilities.logging import configure_logging as mcp_configure_logging
9
+ from dataclasses import dataclass
10
+
11
+ from basic_memory.config import config as project_config
12
+ from basic_memory.services.initialization import initialize_app
13
+
14
+ # mcp console logging
15
+ mcp_configure_logging(level="ERROR")
16
+
17
+
18
+ @dataclass
19
+ class AppContext:
20
+ watch_task: Optional[asyncio.Task]
21
+
22
+
23
+ @asynccontextmanager
24
+ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: # pragma: no cover
25
+ """Manage application lifecycle with type-safe context"""
26
+ # Initialize on startup
27
+ watch_task = await initialize_app(project_config)
28
+ try:
29
+ yield AppContext(watch_task=watch_task)
30
+ finally:
31
+ # Cleanup on shutdown
32
+ if watch_task:
33
+ watch_task.cancel()
34
+
35
+
36
+ # Create the shared server instance
37
+ mcp = FastMCP("Basic Memory", log_level="ERROR", lifespan=app_lifespan)
@@ -137,8 +137,6 @@ class Repository[T: Base]:
137
137
 
138
138
  async def find_one(self, query: Select[tuple[T]]) -> Optional[T]:
139
139
  """Execute a query and retrieve a single record."""
140
- logger.debug(f"Finding one {self.Model.__name__} with query: {query}")
141
-
142
140
  # add in load options
143
141
  query = query.options(*self.get_load_options())
144
142
  result = await self.execute_query(query)
@@ -270,11 +268,9 @@ class Repository[T: Base]:
270
268
  """Execute a query asynchronously."""
271
269
 
272
270
  query = query.options(*self.get_load_options()) if use_query_options else query
273
-
274
271
  logger.debug(f"Executing query: {query}")
275
272
  async with db.scoped_session(self.session_maker) as session:
276
273
  result = await session.execute(query)
277
- logger.debug("Query executed successfully")
278
274
  return result
279
275
 
280
276
  def get_load_options(self) -> List[LoaderOption]:
@@ -60,7 +60,7 @@ class FileService:
60
60
  Returns:
61
61
  Raw content string without metadata sections
62
62
  """
63
- logger.debug("Reading entity content", entity_id=entity.id, permalink=entity.permalink)
63
+ logger.debug(f"Reading entity content, entity_id={entity.id}, permalink={entity.permalink}")
64
64
 
65
65
  file_path = self.get_entity_path(entity)
66
66
  markdown = await self.markdown_processor.read_file(file_path)
@@ -0,0 +1,143 @@
1
+ """Shared initialization service for Basic Memory.
2
+
3
+ This module provides shared initialization functions used by both CLI and API
4
+ to ensure consistent application startup across all entry points.
5
+ """
6
+
7
+ import asyncio
8
+ from typing import Optional
9
+
10
+ from loguru import logger
11
+
12
+ from basic_memory import db
13
+ from basic_memory.config import ProjectConfig, config_manager
14
+ from basic_memory.sync import WatchService
15
+
16
+ # Import this inside functions to avoid circular imports
17
+ # from basic_memory.cli.commands.sync import get_sync_service
18
+
19
+
20
+ async def initialize_database(app_config: ProjectConfig) -> None:
21
+ """Run database migrations to ensure schema is up to date.
22
+
23
+ Args:
24
+ app_config: The Basic Memory project configuration
25
+ """
26
+ try:
27
+ logger.info("Running database migrations...")
28
+ await db.run_migrations(app_config)
29
+ logger.info("Migrations completed successfully")
30
+ except Exception as e:
31
+ logger.error(f"Error running migrations: {e}")
32
+ # Allow application to continue - it might still work
33
+ # depending on what the error was, and will fail with a
34
+ # more specific error if the database is actually unusable
35
+
36
+
37
+ async def initialize_file_sync(
38
+ app_config: ProjectConfig,
39
+ ) -> asyncio.Task:
40
+ """Initialize file synchronization services.
41
+
42
+ Args:
43
+ app_config: The Basic Memory project configuration
44
+
45
+ Returns:
46
+ Tuple of (sync_service, watch_service, watch_task) if sync is enabled,
47
+ or (None, None, None) if sync is disabled
48
+ """
49
+ # Load app configuration
50
+ # Import here to avoid circular imports
51
+ from basic_memory.cli.commands.sync import get_sync_service
52
+
53
+ # Initialize sync service
54
+ sync_service = await get_sync_service()
55
+
56
+ # Initialize watch service
57
+ watch_service = WatchService(
58
+ sync_service=sync_service,
59
+ file_service=sync_service.entity_service.file_service,
60
+ config=app_config,
61
+ quiet=True,
62
+ )
63
+
64
+ # Create the background task for running sync
65
+ async def run_background_sync(): # pragma: no cover
66
+ # Run initial full sync
67
+ await sync_service.sync(app_config.home)
68
+ logger.info("Sync completed successfully")
69
+
70
+ # Start background sync task
71
+ logger.info(f"Starting watch service to sync file changes in dir: {app_config.home}")
72
+
73
+ # Start watching for changes
74
+ await watch_service.run()
75
+
76
+ watch_task = asyncio.create_task(run_background_sync())
77
+ logger.info("Watch service started")
78
+ return watch_task
79
+
80
+
81
+ async def initialize_app(
82
+ app_config: ProjectConfig,
83
+ ) -> Optional[asyncio.Task]:
84
+ """Initialize the Basic Memory application.
85
+
86
+ This function handles all initialization steps needed for both API and shor lived CLI commands.
87
+ For long running commands like mcp, a
88
+ - Running database migrations
89
+ - Setting up file synchronization
90
+
91
+ Args:
92
+ app_config: The Basic Memory project configuration
93
+ """
94
+ # Initialize database first
95
+ await initialize_database(app_config)
96
+
97
+ basic_memory_config = config_manager.load_config()
98
+ logger.info(f"Sync changes enabled: {basic_memory_config.sync_changes}")
99
+ logger.info(
100
+ f"Update permalinks on move enabled: {basic_memory_config.update_permalinks_on_move}"
101
+ )
102
+ if not basic_memory_config.sync_changes: # pragma: no cover
103
+ logger.info("Sync changes disabled. Skipping watch service.")
104
+ return
105
+
106
+ # Initialize file sync services
107
+ return await initialize_file_sync(app_config)
108
+
109
+
110
+ def ensure_initialization(app_config: ProjectConfig) -> None:
111
+ """Ensure initialization runs in a synchronous context.
112
+
113
+ This is a wrapper for the async initialize_app function that can be
114
+ called from synchronous code like CLI entry points.
115
+
116
+ Args:
117
+ app_config: The Basic Memory project configuration
118
+ """
119
+ try:
120
+ asyncio.run(initialize_app(app_config))
121
+ except Exception as e:
122
+ logger.error(f"Error during initialization: {e}")
123
+ # Continue execution even if initialization fails
124
+ # The command might still work, or will fail with a
125
+ # more specific error message
126
+
127
+
128
+ def ensure_initialize_database(app_config: ProjectConfig) -> None:
129
+ """Ensure initialization runs in a synchronous context.
130
+
131
+ This is a wrapper for the async initialize_database function that can be
132
+ called from synchronous code like CLI entry points.
133
+
134
+ Args:
135
+ app_config: The Basic Memory project configuration
136
+ """
137
+ try:
138
+ asyncio.run(initialize_database(app_config))
139
+ except Exception as e:
140
+ logger.error(f"Error during initialization: {e}")
141
+ # Continue execution even if initialization fails
142
+ # The command might still work, or will fail with a
143
+ # more specific error message