basic-memory 0.2.21__tar.gz → 0.4.0__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 (148) hide show
  1. {basic_memory-0.2.21 → basic_memory-0.4.0}/.gitignore +1 -0
  2. {basic_memory-0.2.21 → basic_memory-0.4.0}/CHANGELOG.md +38 -0
  3. {basic_memory-0.2.21 → basic_memory-0.4.0}/PKG-INFO +87 -1
  4. {basic_memory-0.2.21 → basic_memory-0.4.0}/README.md +86 -0
  5. {basic_memory-0.2.21 → basic_memory-0.4.0}/installer/installer.py +1 -0
  6. {basic_memory-0.2.21 → basic_memory-0.4.0}/installer/setup.py +8 -15
  7. {basic_memory-0.2.21 → basic_memory-0.4.0}/pyproject.toml +4 -2
  8. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/__init__.py +1 -1
  9. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/api/app.py +3 -24
  10. basic_memory-0.4.0/src/basic_memory/cli/app.py +20 -0
  11. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/commands/db.py +1 -1
  12. basic_memory-0.4.0/src/basic_memory/cli/commands/import_chatgpt.py +255 -0
  13. basic_memory-0.4.0/src/basic_memory/cli/commands/import_claude_conversations.py +211 -0
  14. basic_memory-0.4.0/src/basic_memory/cli/commands/import_claude_projects.py +195 -0
  15. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/commands/import_memory_json.py +8 -7
  16. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/commands/mcp.py +2 -2
  17. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/commands/status.py +5 -7
  18. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/commands/sync.py +44 -44
  19. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/main.py +10 -1
  20. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/db.py +21 -28
  21. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/async_client.py +1 -1
  22. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/tools/notes.py +4 -1
  23. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/sync/utils.py +1 -4
  24. basic_memory-0.4.0/tests/cli/test_import_chatgpt.py +276 -0
  25. basic_memory-0.4.0/tests/cli/test_import_claude_conversations.py +174 -0
  26. basic_memory-0.4.0/tests/cli/test_import_claude_projects.py +173 -0
  27. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/cli/test_import_memory_json.py +5 -5
  28. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/conftest.py +2 -5
  29. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/mcp/test_tool_notes.py +22 -0
  30. {basic_memory-0.2.21 → basic_memory-0.4.0}/uv.lock +1 -1
  31. basic_memory-0.2.21/src/basic_memory/cli/app.py +0 -3
  32. {basic_memory-0.2.21 → basic_memory-0.4.0}/.github/workflows/pr-title.yml +0 -0
  33. {basic_memory-0.2.21 → basic_memory-0.4.0}/.github/workflows/release.yml +0 -0
  34. {basic_memory-0.2.21 → basic_memory-0.4.0}/.github/workflows/test.yml +0 -0
  35. {basic_memory-0.2.21 → basic_memory-0.4.0}/.python-version +0 -0
  36. {basic_memory-0.2.21 → basic_memory-0.4.0}/CITATION.cff +0 -0
  37. {basic_memory-0.2.21 → basic_memory-0.4.0}/CODE_OF_CONDUCT.md +0 -0
  38. {basic_memory-0.2.21 → basic_memory-0.4.0}/CONTRIBUTING.md +0 -0
  39. {basic_memory-0.2.21 → basic_memory-0.4.0}/LICENSE +0 -0
  40. {basic_memory-0.2.21 → basic_memory-0.4.0}/Makefile +0 -0
  41. {basic_memory-0.2.21 → basic_memory-0.4.0}/alembic.ini +0 -0
  42. {basic_memory-0.2.21 → basic_memory-0.4.0}/basic-memory.md +0 -0
  43. {basic_memory-0.2.21 → basic_memory-0.4.0}/installer/Basic.icns +0 -0
  44. {basic_memory-0.2.21 → basic_memory-0.4.0}/installer/README.md +0 -0
  45. {basic_memory-0.2.21 → basic_memory-0.4.0}/installer/icon.svg +0 -0
  46. {basic_memory-0.2.21 → basic_memory-0.4.0}/installer/make_icons.sh +0 -0
  47. {basic_memory-0.2.21 → basic_memory-0.4.0}/memory.json +0 -0
  48. {basic_memory-0.2.21 → basic_memory-0.4.0}/scripts/install.sh +0 -0
  49. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/alembic/README +0 -0
  50. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/alembic/env.py +0 -0
  51. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/alembic/migrations.py +0 -0
  52. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/alembic/script.py.mako +0 -0
  53. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +0 -0
  54. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/api/__init__.py +0 -0
  55. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/api/routers/__init__.py +0 -0
  56. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/api/routers/knowledge_router.py +0 -0
  57. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/api/routers/memory_router.py +0 -0
  58. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/api/routers/resource_router.py +0 -0
  59. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/api/routers/search_router.py +0 -0
  60. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/__init__.py +0 -0
  61. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/cli/commands/__init__.py +0 -0
  62. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/config.py +0 -0
  63. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/deps.py +0 -0
  64. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/file_utils.py +0 -0
  65. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/markdown/__init__.py +0 -0
  66. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/markdown/entity_parser.py +0 -0
  67. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/markdown/markdown_processor.py +0 -0
  68. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/markdown/plugins.py +0 -0
  69. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/markdown/schemas.py +0 -0
  70. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/markdown/utils.py +0 -0
  71. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/__init__.py +0 -0
  72. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/server.py +0 -0
  73. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/tools/__init__.py +0 -0
  74. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/tools/knowledge.py +0 -0
  75. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/tools/memory.py +0 -0
  76. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/tools/search.py +0 -0
  77. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/mcp/tools/utils.py +0 -0
  78. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/models/__init__.py +0 -0
  79. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/models/base.py +0 -0
  80. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/models/knowledge.py +0 -0
  81. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/models/search.py +0 -0
  82. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/repository/__init__.py +0 -0
  83. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/repository/entity_repository.py +0 -0
  84. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/repository/observation_repository.py +0 -0
  85. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/repository/relation_repository.py +0 -0
  86. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/repository/repository.py +0 -0
  87. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/repository/search_repository.py +0 -0
  88. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/__init__.py +0 -0
  89. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/base.py +0 -0
  90. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/delete.py +0 -0
  91. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/discovery.py +0 -0
  92. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/memory.py +0 -0
  93. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/request.py +0 -0
  94. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/response.py +0 -0
  95. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/schemas/search.py +0 -0
  96. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/__init__.py +0 -0
  97. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/context_service.py +0 -0
  98. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/entity_service.py +0 -0
  99. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/exceptions.py +0 -0
  100. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/file_service.py +0 -0
  101. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/link_resolver.py +0 -0
  102. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/search_service.py +0 -0
  103. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/services/service.py +0 -0
  104. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/sync/__init__.py +0 -0
  105. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/sync/file_change_scanner.py +0 -0
  106. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/sync/sync_service.py +0 -0
  107. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/sync/watch_service.py +0 -0
  108. {basic_memory-0.2.21 → basic_memory-0.4.0}/src/basic_memory/utils.py +0 -0
  109. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/api/conftest.py +0 -0
  110. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/api/test_knowledge_router.py +0 -0
  111. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/api/test_memory_router.py +0 -0
  112. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/api/test_resource_router.py +0 -0
  113. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/api/test_search_router.py +0 -0
  114. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/cli/test_status.py +0 -0
  115. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/cli/test_sync.py +0 -0
  116. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/edit_file_test.py +0 -0
  117. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/__init__.py +0 -0
  118. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/test_entity_parser.py +0 -0
  119. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/test_markdown_plugins.py +0 -0
  120. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/test_markdown_processor.py +0 -0
  121. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/test_observation_edge_cases.py +0 -0
  122. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/test_parser_edge_cases.py +0 -0
  123. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/test_relation_edge_cases.py +0 -0
  124. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/markdown/test_task_detection.py +0 -0
  125. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/mcp/conftest.py +0 -0
  126. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/mcp/test_tool_get_entity.py +0 -0
  127. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/mcp/test_tool_knowledge.py +0 -0
  128. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/mcp/test_tool_memory.py +0 -0
  129. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/mcp/test_tool_search.py +0 -0
  130. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/mcp/test_tool_utils.py +0 -0
  131. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/repository/test_entity_repository.py +0 -0
  132. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/repository/test_observation_repository.py +0 -0
  133. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/repository/test_relation_repository.py +0 -0
  134. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/repository/test_repository.py +0 -0
  135. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/schemas/test_memory_url.py +0 -0
  136. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/schemas/test_schemas.py +0 -0
  137. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/schemas/test_search.py +0 -0
  138. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/services/test_context_service.py +0 -0
  139. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/services/test_entity_service.py +0 -0
  140. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/services/test_file_service.py +0 -0
  141. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/services/test_link_resolver.py +0 -0
  142. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/services/test_search_service.py +0 -0
  143. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/sync/test_file_change_scanner.py +0 -0
  144. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/sync/test_sync_service.py +0 -0
  145. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/sync/test_watch_service.py +0 -0
  146. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/test_basic_memory.py +0 -0
  147. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/utils/test_file_utils.py +0 -0
  148. {basic_memory-0.2.21 → basic_memory-0.4.0}/tests/utils/test_permalink_formatting.py +0 -0
@@ -42,3 +42,4 @@ ENV/
42
42
 
43
43
  # macOS
44
44
  .DS_Store
45
+ /.coverage.*
@@ -1,6 +1,33 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v0.4.0 (2025-02-16)
5
+
6
+ ### Features
7
+
8
+ - Import chatgpt conversation data ([#9](https://github.com/basicmachines-co/basic-memory/pull/9),
9
+ [`56f47d6`](https://github.com/basicmachines-co/basic-memory/commit/56f47d6812982437f207629e6ac9a82e0e56514e))
10
+
11
+ Co-authored-by: phernandez <phernandez@basicmachines.co>
12
+
13
+ - Import claude.ai data ([#8](https://github.com/basicmachines-co/basic-memory/pull/8),
14
+ [`a15c346`](https://github.com/basicmachines-co/basic-memory/commit/a15c346d5ebd44344b76bad877bb4d1073fcbc3b))
15
+
16
+ Import Claude.ai conversation and project data to basic-memory Markdown format.
17
+
18
+ ---------
19
+
20
+ Co-authored-by: phernandez <phernandez@basicmachines.co>
21
+
22
+
23
+ ## v0.3.0 (2025-02-15)
24
+
25
+ ### Bug Fixes
26
+
27
+ - Refactor db schema migrate handling
28
+ ([`ca632be`](https://github.com/basicmachines-co/basic-memory/commit/ca632beb6fed5881f4d8ba5ce698bb5bc681e6aa))
29
+
30
+
4
31
  ## v0.2.21 (2025-02-15)
5
32
 
6
33
  ### Bug Fixes
@@ -8,6 +35,17 @@
8
35
  - Fix osx installer github action
9
36
  ([`65ebe5d`](https://github.com/basicmachines-co/basic-memory/commit/65ebe5d19491e5ff047c459d799498ad5dd9cd1a))
10
37
 
38
+ - Handle memory:// url format in read_note tool
39
+ ([`e080373`](https://github.com/basicmachines-co/basic-memory/commit/e0803734e69eeb6c6d7432eea323c7a264cb8347))
40
+
41
+ - Remove create schema from init_db
42
+ ([`674dd1f`](https://github.com/basicmachines-co/basic-memory/commit/674dd1fd47be9e60ac17508476c62254991df288))
43
+
44
+ ### Features
45
+
46
+ - Set version in var, output version at startup
47
+ ([`a91da13`](https://github.com/basicmachines-co/basic-memory/commit/a91da1396710e62587df1284da00137d156fc05e))
48
+
11
49
 
12
50
  ## v0.2.20 (2025-02-14)
13
51
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-memory
3
- Version: 0.2.21
3
+ Version: 0.4.0
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
@@ -286,6 +286,92 @@ Basic Memory is built on some key ideas:
286
286
  - Simple text patterns can capture rich meaning
287
287
  - Local-first doesn't mean feature-poor
288
288
 
289
+ ## Importing data
290
+
291
+ Basic memory has cli commands to import data from several formats into Markdown files
292
+
293
+ ### Claude.ai
294
+
295
+ First, request an export of your data from your Claude account. The data will be emailed to you in several files,
296
+ including
297
+ `conversations.json` and `projects.json`.
298
+
299
+ Import Claude.ai conversation data
300
+
301
+ ```bash
302
+ basic-memory import claude conversations conversations.json
303
+ ```
304
+
305
+ The conversations will be turned into Markdown files and placed in the "conversations" folder by default (this can be
306
+ changed with the --folder arg).
307
+
308
+ Example:
309
+
310
+ ```bash
311
+ Importing chats from conversations.json...writing to .../basic-memory
312
+ Reading chat data... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
313
+ ╭────────────────────────────╮
314
+ │ Import complete! │
315
+ │ │
316
+ │ Imported 307 conversations │
317
+ │ Containing 7769 messages │
318
+ ╰────────────────────────────╯
319
+ ```
320
+
321
+ Next, you can run the `sync` command to import the data into basic-memory
322
+
323
+ ```bash
324
+ basic-memory sync
325
+ ```
326
+
327
+ You can also import project data from Claude.ai
328
+
329
+ ```bash
330
+ ➜ basic-memory import claude projects
331
+ Importing projects from projects.json...writing to .../basic-memory/projects
332
+ Reading project data... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
333
+ ╭────────────────────────────────╮
334
+ │ Import complete! │
335
+ │ │
336
+ │ Imported 101 project documents │
337
+ │ Imported 32 prompt templates │
338
+ ╰────────────────────────────────╯
339
+
340
+ Run 'basic-memory sync' to index the new files.
341
+ ```
342
+
343
+ ### Chat Gpt
344
+
345
+ ```bash
346
+ ➜ basic-memory import chatgpt
347
+ Importing chats from conversations.json...writing to .../basic-memory/conversations
348
+
349
+ Reading chat data... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
350
+ ╭────────────────────────────╮
351
+ │ Import complete! │
352
+ │ │
353
+ │ Imported 198 conversations │
354
+ │ Containing 11777 messages │
355
+ ╰────────────────────────────╯
356
+
357
+
358
+ ```
359
+
360
+ ### Memory json
361
+
362
+ ```bash
363
+ ➜ basic-memory import memory-json
364
+ Importing from memory.json...writing to .../basic-memory
365
+ Reading memory.json... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
366
+ Creating entities... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
367
+ ╭──────────────────────╮
368
+ │ Import complete! │
369
+ │ │
370
+ │ Created 126 entities │
371
+ │ Added 252 relations │
372
+ ╰──────────────────────╯
373
+ ```
374
+
289
375
  ## License
290
376
 
291
377
  AGPL-3.0
@@ -253,6 +253,92 @@ Basic Memory is built on some key ideas:
253
253
  - Simple text patterns can capture rich meaning
254
254
  - Local-first doesn't mean feature-poor
255
255
 
256
+ ## Importing data
257
+
258
+ Basic memory has cli commands to import data from several formats into Markdown files
259
+
260
+ ### Claude.ai
261
+
262
+ First, request an export of your data from your Claude account. The data will be emailed to you in several files,
263
+ including
264
+ `conversations.json` and `projects.json`.
265
+
266
+ Import Claude.ai conversation data
267
+
268
+ ```bash
269
+ basic-memory import claude conversations conversations.json
270
+ ```
271
+
272
+ The conversations will be turned into Markdown files and placed in the "conversations" folder by default (this can be
273
+ changed with the --folder arg).
274
+
275
+ Example:
276
+
277
+ ```bash
278
+ Importing chats from conversations.json...writing to .../basic-memory
279
+ Reading chat data... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
280
+ ╭────────────────────────────╮
281
+ │ Import complete! │
282
+ │ │
283
+ │ Imported 307 conversations │
284
+ │ Containing 7769 messages │
285
+ ╰────────────────────────────╯
286
+ ```
287
+
288
+ Next, you can run the `sync` command to import the data into basic-memory
289
+
290
+ ```bash
291
+ basic-memory sync
292
+ ```
293
+
294
+ You can also import project data from Claude.ai
295
+
296
+ ```bash
297
+ ➜ basic-memory import claude projects
298
+ Importing projects from projects.json...writing to .../basic-memory/projects
299
+ Reading project data... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
300
+ ╭────────────────────────────────╮
301
+ │ Import complete! │
302
+ │ │
303
+ │ Imported 101 project documents │
304
+ │ Imported 32 prompt templates │
305
+ ╰────────────────────────────────╯
306
+
307
+ Run 'basic-memory sync' to index the new files.
308
+ ```
309
+
310
+ ### Chat Gpt
311
+
312
+ ```bash
313
+ ➜ basic-memory import chatgpt
314
+ Importing chats from conversations.json...writing to .../basic-memory/conversations
315
+
316
+ Reading chat data... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
317
+ ╭────────────────────────────╮
318
+ │ Import complete! │
319
+ │ │
320
+ │ Imported 198 conversations │
321
+ │ Containing 11777 messages │
322
+ ╰────────────────────────────╯
323
+
324
+
325
+ ```
326
+
327
+ ### Memory json
328
+
329
+ ```bash
330
+ ➜ basic-memory import memory-json
331
+ Importing from memory.json...writing to .../basic-memory
332
+ Reading memory.json... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
333
+ Creating entities... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
334
+ ╭──────────────────────╮
335
+ │ Import complete! │
336
+ │ │
337
+ │ Created 126 entities │
338
+ │ Added 252 relations │
339
+ ╰──────────────────────╯
340
+ ```
341
+
256
342
  ## License
257
343
 
258
344
  AGPL-3.0
@@ -8,6 +8,7 @@ if sys.platform == "darwin":
8
8
  import tkinter as tk
9
9
  from tkinter import messagebox
10
10
 
11
+
11
12
  def ensure_uv_installed():
12
13
  """Check if uv is installed, install if not."""
13
14
  try:
@@ -4,31 +4,24 @@ import sys
4
4
  # Build options for all platforms
5
5
  build_exe_options = {
6
6
  "packages": ["json", "pathlib"],
7
- "excludes": [
8
- "unittest",
9
- "pydoc",
10
- "test"
11
- ],
7
+ "excludes": ["unittest", "pydoc", "test"],
12
8
  }
13
9
 
14
10
  # Platform-specific options
15
11
  if sys.platform == "win32":
16
12
  base = "Win32GUI" # Use GUI base for Windows
17
- build_exe_options.update({
18
- "include_msvcr": True,
19
- })
13
+ build_exe_options.update(
14
+ {
15
+ "include_msvcr": True,
16
+ }
17
+ )
20
18
  target_name = "Basic Memory Installer.exe"
21
19
  else: # darwin
22
20
  base = None # Don't use GUI base for macOS
23
21
  target_name = "Basic Memory Installer"
24
22
 
25
23
  executables = [
26
- Executable(
27
- script="installer.py",
28
- target_name=target_name,
29
- base=base,
30
- icon="Basic.icns"
31
- )
24
+ Executable(script="installer.py", target_name=target_name, base=base, icon="Basic.icns")
32
25
  ]
33
26
 
34
27
  setup(
@@ -41,7 +34,7 @@ setup(
41
34
  "bundle_name": "Basic Memory Installer",
42
35
  "iconfile": "Basic.icns",
43
36
  "codesign_identity": "-", # Force ad-hoc signing
44
- }
37
+ },
45
38
  },
46
39
  executables=executables,
47
40
  )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "basic-memory"
3
- version = "0.2.21"
3
+ version = "0.4.0"
4
4
  description = "Local-first knowledge management combining Zettelkasten with knowledge graphs"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12.1"
@@ -84,7 +84,9 @@ pythonVersion = "3.12"
84
84
 
85
85
 
86
86
  [tool.semantic_release]
87
- version_variable = "src/basic_memory/__init__.py:__version__"
87
+ version_variables = [
88
+ "src/basic_memory/__init__.py:__version__",
89
+ ]
88
90
  version_toml = [
89
91
  "pyproject.toml:project.version",
90
92
  ]
@@ -1,3 +1,3 @@
1
1
  """basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
2
2
 
3
- __version__ = "0.0.1"
3
+ __version__ = "0.4.0"
@@ -6,38 +6,17 @@ from fastapi import FastAPI, HTTPException
6
6
  from fastapi.exception_handlers import http_exception_handler
7
7
  from loguru import logger
8
8
 
9
+ import basic_memory
9
10
  from basic_memory import db
10
11
  from basic_memory.config import config as app_config
11
12
  from basic_memory.api.routers import knowledge, search, memory, resource
12
- from alembic import command
13
- from alembic.config import Config
14
-
15
- from basic_memory.db import DatabaseType
16
- from basic_memory.repository.search_repository import SearchRepository
17
-
18
-
19
- async def run_migrations(): # pragma: no cover
20
- """Run any pending alembic migrations."""
21
- logger.info("Running database migrations...")
22
- try:
23
- config = Config("alembic.ini")
24
- command.upgrade(config, "head")
25
- logger.info("Migrations completed successfully")
26
-
27
- _, session_maker = await db.get_or_create_db(
28
- app_config.database_path, DatabaseType.FILESYSTEM
29
- )
30
- await SearchRepository(session_maker).init_search_index()
31
- except Exception as e:
32
- logger.error(f"Error running migrations: {e}")
33
- raise
34
13
 
35
14
 
36
15
  @asynccontextmanager
37
16
  async def lifespan(app: FastAPI): # pragma: no cover
38
17
  """Lifecycle manager for the FastAPI app."""
39
- logger.info("Starting Basic Memory API")
40
- await run_migrations()
18
+ logger.info(f"Starting Basic Memory API {basic_memory.__version__}")
19
+ await db.run_migrations(app_config)
41
20
  yield
42
21
  logger.info("Shutting down Basic Memory API")
43
22
  await db.shutdown_db()
@@ -0,0 +1,20 @@
1
+ import asyncio
2
+
3
+ import typer
4
+
5
+ from basic_memory import db
6
+ from basic_memory.config import config
7
+ from basic_memory.utils import setup_logging
8
+
9
+ setup_logging(log_file=".basic-memory/basic-memory-cli.log") # pragma: no cover
10
+
11
+ asyncio.run(db.run_migrations(config))
12
+
13
+ app = typer.Typer(name="basic-memory")
14
+
15
+ import_app = typer.Typer()
16
+ app.add_typer(import_app, name="import")
17
+
18
+
19
+ claude_app = typer.Typer()
20
+ import_app.add_typer(claude_app, name="claude")
@@ -22,4 +22,4 @@ def reset(
22
22
  from basic_memory.cli.commands.sync import sync
23
23
 
24
24
  logger.info("Rebuilding search index from filesystem...")
25
- asyncio.run(sync()) # pyright: ignore
25
+ sync(watch=False) # pyright: ignore
@@ -0,0 +1,255 @@
1
+ """Import command for ChatGPT conversations."""
2
+
3
+ import asyncio
4
+ import json
5
+ from datetime import datetime
6
+ from pathlib import Path
7
+ from typing import Dict, Any, List, Annotated, Set, Optional
8
+
9
+ import typer
10
+ from loguru import logger
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
14
+
15
+ from basic_memory.cli.app import import_app
16
+ from basic_memory.config import config
17
+ from basic_memory.markdown import EntityParser, MarkdownProcessor
18
+ from basic_memory.markdown.schemas import EntityMarkdown, EntityFrontmatter
19
+
20
+ console = Console()
21
+
22
+
23
+ def clean_filename(text: str) -> str:
24
+ """Convert text to safe filename."""
25
+ clean = "".join(c if c.isalnum() else "-" for c in text.lower()).strip("-")
26
+ return clean
27
+
28
+
29
+ def format_timestamp(ts: float) -> str:
30
+ """Format Unix timestamp for display."""
31
+ dt = datetime.fromtimestamp(ts)
32
+ return dt.strftime("%Y-%m-%d %H:%M:%S")
33
+
34
+
35
+ def get_message_content(message: Dict[str, Any]) -> str:
36
+ """Extract clean message content."""
37
+ if not message or "content" not in message:
38
+ return "" # pragma: no cover
39
+
40
+ content = message["content"]
41
+ if content.get("content_type") == "text":
42
+ return "\n".join(content.get("parts", []))
43
+ elif content.get("content_type") == "code":
44
+ return f"```{content.get('language', '')}\n{content.get('text', '')}\n```"
45
+ return "" # pragma: no cover
46
+
47
+
48
+ def traverse_messages(
49
+ mapping: Dict[str, Any], root_id: Optional[str], seen: Set[str]
50
+ ) -> List[Dict[str, Any]]:
51
+ """Traverse message tree and return messages in order."""
52
+ messages = []
53
+ node = mapping.get(root_id) if root_id else None
54
+
55
+ while node:
56
+ if node["id"] not in seen and node.get("message"):
57
+ seen.add(node["id"])
58
+ messages.append(node["message"])
59
+
60
+ # Follow children
61
+ children = node.get("children", [])
62
+ for child_id in children:
63
+ child_msgs = traverse_messages(mapping, child_id, seen)
64
+ messages.extend(child_msgs)
65
+
66
+ break # Don't follow siblings
67
+
68
+ return messages
69
+
70
+
71
+ def format_chat_markdown(
72
+ title: str, mapping: Dict[str, Any], root_id: Optional[str], created_at: float, modified_at: float
73
+ ) -> str:
74
+ """Format chat as clean markdown."""
75
+
76
+ # Start with title
77
+ lines = [f"# {title}\n"]
78
+
79
+ # Traverse message tree
80
+ seen_msgs = set()
81
+ messages = traverse_messages(mapping, root_id, seen_msgs)
82
+
83
+ # Format each message
84
+ for msg in messages:
85
+ # Skip hidden messages
86
+ if msg.get("metadata", {}).get("is_visually_hidden_from_conversation"):
87
+ continue
88
+
89
+ # Get author and timestamp
90
+ author = msg["author"]["role"].title()
91
+ ts = format_timestamp(msg["create_time"]) if msg.get("create_time") else ""
92
+
93
+ # Add message header
94
+ lines.append(f"### {author} ({ts})")
95
+
96
+ # Add message content
97
+ content = get_message_content(msg)
98
+ if content:
99
+ lines.append(content)
100
+
101
+ # Add spacing
102
+ lines.append("")
103
+
104
+ return "\n".join(lines)
105
+
106
+
107
+ def format_chat_content(folder: str, conversation: Dict[str, Any]) -> EntityMarkdown:
108
+ """Convert chat conversation to Basic Memory entity."""
109
+
110
+ # Extract timestamps
111
+ created_at = conversation["create_time"]
112
+ modified_at = conversation["update_time"]
113
+
114
+ root_id = None
115
+ # Find root message
116
+ for node_id, node in conversation["mapping"].items():
117
+ if node.get("parent") is None:
118
+ root_id = node_id
119
+ break
120
+
121
+ # Generate permalink
122
+ date_prefix = datetime.fromtimestamp(created_at).strftime("%Y%m%d")
123
+ clean_title = clean_filename(conversation["title"])
124
+
125
+ # Format content
126
+ content = format_chat_markdown(
127
+ title=conversation["title"],
128
+ mapping=conversation["mapping"],
129
+ root_id=root_id,
130
+ created_at=created_at,
131
+ modified_at=modified_at,
132
+ )
133
+
134
+ # Create entity
135
+ entity = EntityMarkdown(
136
+ frontmatter=EntityFrontmatter(
137
+ metadata={
138
+ "type": "conversation",
139
+ "title": conversation["title"],
140
+ "created": format_timestamp(created_at),
141
+ "modified": format_timestamp(modified_at),
142
+ "permalink": f"{folder}/{date_prefix}-{clean_title}",
143
+ }
144
+ ),
145
+ content=content,
146
+ )
147
+
148
+ return entity
149
+
150
+
151
+ async def process_chatgpt_json(
152
+ json_path: Path, folder: str, markdown_processor: MarkdownProcessor
153
+ ) -> Dict[str, int]:
154
+ """Import conversations from ChatGPT JSON format."""
155
+
156
+ with Progress(
157
+ SpinnerColumn(),
158
+ TextColumn("[progress.description]{task.description}"),
159
+ BarColumn(),
160
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
161
+ console=console,
162
+ ) as progress:
163
+ read_task = progress.add_task("Reading chat data...", total=None)
164
+
165
+ # Read conversations
166
+ conversations = json.loads(json_path.read_text())
167
+ progress.update(read_task, total=len(conversations))
168
+
169
+ # Process each conversation
170
+ messages_imported = 0
171
+ chats_imported = 0
172
+
173
+ for chat in conversations:
174
+ # Convert to entity
175
+ entity = format_chat_content(folder, chat)
176
+
177
+ # Write file
178
+ file_path = config.home / f"{entity.frontmatter.metadata['permalink']}.md"
179
+ # logger.info(f"Writing file: {file_path.absolute()}")
180
+ await markdown_processor.write_file(file_path, entity)
181
+
182
+ # Count messages
183
+ msg_count = sum(
184
+ 1
185
+ for node in chat["mapping"].values()
186
+ if node.get("message")
187
+ and not node.get("message", {})
188
+ .get("metadata", {})
189
+ .get("is_visually_hidden_from_conversation")
190
+ )
191
+
192
+ chats_imported += 1
193
+ messages_imported += msg_count
194
+ progress.update(read_task, advance=1)
195
+
196
+ return {"conversations": chats_imported, "messages": messages_imported}
197
+
198
+
199
+ async def get_markdown_processor() -> MarkdownProcessor:
200
+ """Get MarkdownProcessor instance."""
201
+ entity_parser = EntityParser(config.home)
202
+ return MarkdownProcessor(entity_parser)
203
+
204
+
205
+ @import_app.command(name="chatgpt", help="Import conversations from ChatGPT JSON export.")
206
+ def import_chatgpt(
207
+ conversations_json: Annotated[
208
+ Path, typer.Option(..., help="Path to ChatGPT conversations.json file")
209
+ ] = Path("conversations.json"),
210
+ folder: Annotated[
211
+ str, typer.Option(help="The folder to place the files in.")
212
+ ] = "conversations",
213
+ ):
214
+ """Import chat conversations from ChatGPT JSON format.
215
+
216
+ This command will:
217
+ 1. Read the complex tree structure of messages
218
+ 2. Convert them to linear markdown conversations
219
+ 3. Save as clean, readable markdown files
220
+
221
+ After importing, run 'basic-memory sync' to index the new files.
222
+ """
223
+
224
+ try:
225
+ if conversations_json:
226
+ if not conversations_json.exists():
227
+ typer.echo(f"Error: File not found: {conversations_json}", err=True)
228
+ raise typer.Exit(1)
229
+
230
+ # Get markdown processor
231
+ markdown_processor = asyncio.run(get_markdown_processor())
232
+
233
+ # Process the file
234
+ base_path = config.home / folder
235
+ console.print(f"\nImporting chats from {conversations_json}...writing to {base_path}")
236
+ results = asyncio.run(
237
+ process_chatgpt_json(conversations_json, folder, markdown_processor)
238
+ )
239
+
240
+ # Show results
241
+ console.print(
242
+ Panel(
243
+ f"[green]Import complete![/green]\n\n"
244
+ f"Imported {results['conversations']} conversations\n"
245
+ f"Containing {results['messages']} messages",
246
+ expand=False,
247
+ )
248
+ )
249
+
250
+ console.print("\nRun 'basic-memory sync' to index the new files.")
251
+
252
+ except Exception as e:
253
+ logger.error("Import failed")
254
+ typer.echo(f"Error during import: {e}", err=True)
255
+ raise typer.Exit(1)