Compare commits

..

317 Commits

Author SHA1 Message Date
Joe P 73cade27ab chore: update version to 0.14.4 for v0.14.4 release 2025-09-04 14:03:09 -06:00
Joe P 7e024a8674 fix: resolve linting errors for release preparation
- Replace bare except clauses with Exception in legal_file_inventory.py
- Remove unused variables in test files
- Prepare codebase for v0.14.4 release
2025-09-04 14:01:06 -06:00
Drew Cain 22f7bfa398 fix: Update YAML frontmatter tag formatting for Obsidian compatibility (#280)
Signed-off-by: Drew Cain <groksrc@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-09-04 09:57:45 -05:00
jope-bm cd7cee650f fix: complete project management special character support (#272) (#279)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-29 10:57:13 -06:00
Paul Hernandez 105bcaa025 feat: implement non-root Docker container to fix file ownership issues (#277)
Signed-off-by: Drew Cain <groksrc@gmail.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Drew Cain <groksrc@gmail.com>
2025-08-28 22:15:14 -05:00
Brandon Mayes 74e12eb782 fix: Sanitize filenames and allow optional kebab case (#260)
Signed-off-by: Brandon Mayes <5610870+bdmayes@users.noreply.github.com>
2025-08-27 19:29:01 -04:00
Drew Cain 7a8b08d11e fix: Windows test failures and add Windows CI support (#273)
Signed-off-by: Drew Cain <groksrc@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-25 08:58:24 -05:00
manuelbliemel 9aa40246a8 Addressed issues when running basic-memory on the Windows platform (#252)
Signed-off-by: Manuel Bliemel <manuel.bliemel@gmail.com>
2025-08-24 19:12:40 -07:00
jope-bm 7aff836c57 fix: Add ISO datetime serialization to MCP schema models (#270)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-23 07:23:07 -06:00
jope-bm 285e96baea fix: Fix observation parsing to exclude markdown and wiki links (#269)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-22 20:16:05 -06:00
jope-bm 2cd2a62f30 fix: Ensure all datetime operations return timezone-aware objects (#268)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-22 13:43:55 -06:00
jope-bm f3d8d8d617 fix: Use discriminated unions for MCP schema validation in build_context (#266)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
2025-08-22 09:36:32 -06:00
jope-bm 9743fcd13e fix: Respect BASIC_MEMORY_LOG_LEVEL and BASIC_MEMORY_CONSOLE_LOGGING environment variables (#264)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-22 07:58:19 -06:00
phernandez 65d1984a53 Update CLA.md to include copyright and license info
Signed-off-by: phernandez <paul@basicmachines.co>
2025-08-21 18:21:24 -05:00
jope-bm b814d40ab1 fix: Add project isolation to ContextService.find_related() method (#261) (#262)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-20 20:07:04 -06:00
Paul Hernandez 2438094914 fix: handle vim atomic write DELETE events without ADD (#249)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Joe P <joe@basicmemory.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-20 14:36:43 -05:00
jope-bm 5d74d7407c fix: Enable string-to-integer conversion for build_context depth parameter (#259)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-20 11:22:14 -06:00
jope-bm b6aeb3217c fix: Add missing foreign key constraints for project removal (#254) (#258)
Signed-off-by: Joe P <joe@basicmemory.com>
Signed-off-by: joe@basicmemory.com
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-20 08:49:07 -06:00
jope-bm 08ee7e1201 fix: Critical search index bug - prevent note disappearing on edit (#257)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
2025-08-19 15:41:27 -06:00
phernandez 63ae9ee0e4 docs: Re-implement external documentation improvements
- Fix typo: 'enviroment' -> 'environment' in CLAUDE.md
- Update HTTP links to HTTPS in README.md
- Add comprehensive VS Code integration instructions
- Maintain correct internal link references

All improvements re-implemented by Basic Machines team for clean IP ownership.
2025-08-08 15:31:04 -05:00
phernandez 0e78751d34 revert: Remove external documentation changes for clean IP
Reverting changes by:
- Ikko Eltociear Ashimine (typo fix)
- Jason Noble (HTTPS links)
- Matias Forbord (link fix)
- Marc Baiza (VS Code instructions)

Will be re-implemented by Basic Machines team for clean IP ownership.
2025-08-08 15:26:29 -05:00
phernandez 59eae34dee fix: Update function name in error messages to use correct search_notes
Corrects error message templates to reference the actual search_notes function name for consistency.
2025-08-08 15:25:33 -05:00
phernandez b1e55e169e revert: Remove external function name fix for clean IP
Original contribution by Amadeusz Wieczorek will be re-implemented by Basic Machines team.
2025-08-08 15:24:58 -05:00
phernandez 173bff35c1 feat: Add Chinese character support to permalink generation
Preserves non-ASCII characters like Chinese in permalinks while maintaining
backward compatibility with ASCII-only processing. This re-implements
functionality that was contributed externally, now with Basic Machines authorship.
2025-08-08 15:24:23 -05:00
phernandez 629c8e47c9 revert: Remove external Chinese character fix for clean IP
Original contribution by andyxinweiminicloud will be re-implemented by Basic Machines team for clean IP ownership.
2025-08-08 15:23:28 -05:00
phernandez 9e4b8bca8f Add legal inventory documentation for IP analysis 2025-08-08 15:16:39 -05:00
Drew Cain b0cc559426 chore: update version to 0.14.3 for v0.14.3 release 2025-08-01 22:06:53 -05:00
Drew Cain 7460a938df fix: make case sensitivity test platform-aware
- Add platform detection to handle case-insensitive file systems
- Test now passes on macOS and Windows while maintaining Linux behavior
- Fixes test failure on case-insensitive file systems
2025-08-01 22:02:53 -05:00
Drew Cain 43fa5762a8 ruff checks
Signed-off-by: Drew Cain <groksrc@gmail.com>
2025-08-01 21:50:18 -05:00
Paul Hernandez fb1350b294 fix: enhance character conflict detection and error handling for sync operations (#201)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-08-01 21:35:56 -05:00
Paul Hernandez 7585a29c96 fix: replace recursive _traverse_messages with iterative approach to handle deep conversation threads (#235)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-08-01 21:34:11 -05:00
Drew Cain 752c78c379 chore: minor cleanup (#228)
Signed-off-by: Drew Cain <groksrc@gmail.com>
2025-07-31 21:32:56 -05:00
jope-bm a4a3b1b689 fix: handle missing 'name' key in memory JSON import (#241)
Signed-off-by: Joe P <joe@basicmemory.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
2025-07-28 14:52:15 -06:00
jope-bm 6361574a20 fix: basic memory home env var not respected when project path is changed. (#239)
Signed-off-by: Joe P <joe@basicmemory.com>
2025-07-28 14:50:47 -06:00
jope-bm 24a1d6195d fix: path traversal security vulnerability in mcp tools (#223)
Signed-off-by: Joe P <joe@basicmemory.com>
2025-07-15 09:05:11 -06:00
jope-bm a0cf62375d docs: improve virtual environment setup instructions (#222)
Co-authored-by: Claude <noreply@anthropic.com>
2025-07-10 10:18:43 -06:00
Paul Hernandez 473f70c949 chore: Cloud auth (#213)
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: Claude <noreply@anthropic.com>
2025-07-07 21:08:25 -05:00
phernandez 2c29dcc2b2 chore: update version to 0.14.2 for v0.14.2 release 2025-07-03 17:30:40 -05:00
phernandez 448210e552 docs: add v0.14.2 changelog entry
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-03 17:23:54 -05:00
Drew Cain 3621bb7b4d fix: MCP Error with MCP-Hub #204 (#212)
Signed-off-by: Drew Cain <groksrc@gmail.com>
2025-07-03 16:57:43 -05:00
Drew Cain f80ac0ee72 fix: replace deprecated datetime.utcnow() with timezone-aware alternatives and suppress SQLAlchemy warnings (#211)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2025-07-03 16:57:30 -05:00
Drew Cain 23ddf1918c chore: update version to 0.14.1 for v0.14.1 release 2025-07-01 22:08:25 -05:00
Drew Cain 2aca19aa05 chore: apply ruff formatting 2025-07-01 22:05:17 -05:00
Drew Cain 827f7cf3e3 fix: constrain fastmcp version to prevent breaking changes (#203)
Signed-off-by: Drew Cain <groksrc@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-07-01 22:01:59 -05:00
Drew Cain bd4f55158b fix: Problems with MCP #190 (#202)
Signed-off-by: Drew Cain <groksrc@gmail.com>
2025-07-01 10:50:44 -05:00
Drew Cain 5360005122 feat: Add to cursor button (#200)
Signed-off-by: Drew Cain <groksrc@gmail.com>
2025-07-01 09:17:48 -05:00
Drew Cain 39f811f8b5 Update README.md
Added Homebrew instructions to README.md

Signed-off-by: Drew Cain <groksrc@users.noreply.github.com>
2025-06-26 21:51:14 -05:00
phernandez 8e69c8b533 chore: update version to 0.14.0 for v0.14.0 release 2025-06-26 16:18:10 -05:00
phernandez 627a5c3c22 docs: add comprehensive v0.14.0 changelog entry
Add detailed changelog for v0.14.0 release including:
- Docker Container Registry migration to GitHub Container Registry
- Enhanced search documentation with comprehensive syntax examples
- Cross-project file management with intelligent boundary detection
- 8 major bug fixes with issue numbers and commit links
- Technical improvements and infrastructure enhancements
- Migration guide and installation instructions

Covers all changes since v0.13.7 with proper categorization and
user-facing descriptions for better release communication.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-26 16:15:11 -05:00
phernandez cd88945b22 remove v0.13.0 from changelog
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-26 16:11:05 -05:00
phernandez cd8e372f0a fix: add test coverage for optional permalink in EntityResponse schema
- Add comprehensive test for None permalink validation in EntityResponse
- Ensures schema properly handles markdown files without explicit permalinks
- Addresses GitHub issue #170 validation errors during edit operations
- Test validates that permalink=None doesn't cause ValidationError

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-26 15:58:49 -05:00
Paul Hernandez a589f8b894 feat: enhance search_notes tool documentation with comprehensive syntax examples (#186)
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-26 15:51:58 -05:00
Paul Hernandez c2f4b632cf fix: preserve permalink when editing notes without frontmatter permalink (#184)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-06-26 15:35:31 -05:00
phernandez 46d102cef1 update tests for search_repository
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-26 14:30:10 -05:00
phernandez 8e4dc026ce chore: update version to 0.14.0b1 for v0.14.0b1 beta release 2025-06-26 14:08:32 -05:00
phernandez 7af8e198c2 style: fix linting errors in test assertions
Replace equality comparisons to False with 'not' for better style.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-26 14:06:51 -05:00
Paul Hernandez 12b51522bc fix: implement project-specific sync status checks for MCP tools (#183)
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-26 13:54:26 -05:00
Paul Hernandez ac9e148bcc test: add more tests for search_repository (#181)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-26 13:45:07 -05:00
Paul Hernandez 546e3cd8db fix: handle Boolean search syntax with hyphenated terms (#180)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-26 12:41:32 -05:00
phernandez de4737cc22 fix: correct typo and update changelog command template
- Fix typo: <versuib> → <version>
- Update version examples to v0.14.0 format
- Improve template formatting clarity

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 11:09:32 -05:00
phernandez 77eefeb252 update test-live.md regression suite
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-26 10:25:48 -05:00
phernandez e5923a0378 allow web_search in claude github action
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-26 09:29:23 -05:00
phernandez 1bf348259b fix formatting on files
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-25 22:32:05 -05:00
phernandez 224e4bf9e4 fixes #164 revove log level from mcp_server.run()
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-25 22:31:47 -05:00
Drew Cain 9f1db23c78 fix: respect BASIC_MEMORY_HOME environment variable in Docker containers (#174)
Signed-off-by: Drew Cain <groksrc@gmail.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2025-06-25 21:40:30 -05:00
Paul Hernandez db5ef7d35c feat: enhance move_note tool with cross-project detection and guidance (#161)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-06-25 12:57:59 -05:00
Paul Hernandez f50650763d fix: ensure permalinks are generated for entities with null permalinks during move operations (#162)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-06-25 12:57:44 -05:00
Drew Cain 8a065c32f4 fix: handle None from_entity in Context API RelationSummary (#166)
Signed-off-by: Drew Cain <groksrc@gmail.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2025-06-25 12:57:31 -05:00
Drew Cain 2a3adc109a fix: scope entity queries by project_id in upsert_entity method (#168)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2025-06-24 00:02:18 -05:00
Drew Cain a52ce1c860 fix: only update Homebrew on stable releases
Signed-off-by: Drew Cain <groksrc@gmail.com>
2025-06-21 08:12:23 -05:00
phernandez 616c1f0710 feat: switch from Docker Hub to GitHub Container Registry
🏴 Fighting the power! No more $15/month Docker Hub fees.

- Use ghcr.io/basicmachines-co/basic-memory for container images
- Native GitHub integration with GITHUB_TOKEN (no external secrets)
- Update all documentation and examples to use GHCR
- Remove Docker Hub description update step (not needed for GHCR)
- Completely free solution for public repositories

Docker users can now:
docker pull ghcr.io/basicmachines-co/basic-memory:latest
2025-06-20 15:57:49 -05:00
Paul Hernandez 74847cc380 feat: implement Docker CI workflow for automated image publishing (#159)
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-20 15:42:55 -05:00
phernandez d3b6c85184 docs: add v0.13.8 changelog entry
Documents recent fixes and features including:
- Docker container support with volume mounting
- #151: Reset command project configuration fix
- #148: MCP/CLI project state consistency fix
- FastMCP compatibility improvements
- Comprehensive integration testing

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-19 22:13:32 -05:00
Paul Hernandez af44941d5a fix: reset command now clears project configuration (#152)
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-19 21:55:50 -05:00
Paul Hernandez 35e4f73ae8 fix: resolve project state inconsistency between MCP and CLI (#149)
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-06-19 21:24:51 -05:00
Drew Cain 7be001ca68 fix: fastmcp deprecation warning (#150)
Signed-off-by: Drew Cain <groksrc@gmail.com>
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
Co-authored-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-06-19 19:59:17 -05:00
Paul Hernandez 3269a2f33a feat: add Docker container support with volume mounting (#131)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: phernandez <phernandez@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-19 19:57:30 -05:00
Drew Cain b8191d090f chore: update version to 0.13.7 for v0.13.7 release 2025-06-18 22:32:53 -05:00
Drew Cain 2ce8a8e4b0 feat: Automatically update Homebrew
Signed-off-by: Drew Cain <groksrc@users.noreply.github.com>
2025-06-18 22:00:02 -05:00
Drew Cain f8099cd004 feat: Automatically update Homebrew (#147)
Signed-off-by: Drew Cain <groksrc@users.noreply.github.com>
2025-06-18 21:54:49 -05:00
phernandez 688e0b0971 chore: update version to 0.13.6 for v0.13.6 release 2025-06-18 17:58:56 -05:00
phernandez ed09ea4ec7 docs: add git sign-off reminder to CLAUDE.md
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-18 17:56:24 -05:00
phernandez c85d9f74d7 docs: add v0.13.6 changelog entry
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-18 17:55:21 -05:00
Paul Hernandez 84d2aaf641 fix: eliminate redundant database migration initialization (#146)
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-18 17:32:20 -05:00
Paul Hernandez 7789864493 fix: add entity_type parameter to write_note MCP tool (#145)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-18 17:10:15 -05:00
Drew Cain c6215fd819 fix: UNIQUE constraint failed: entity.permalink issue #139 (#140)
Signed-off-by: Drew Cain <groksrc@users.noreply.github.com>
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: phernandez <paul@basicmachines.co>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-18 15:03:11 -05:00
Drew Cain b4c26a6133 fix: correct spelling error "Chose" to "Choose" in continue_conversation prompt (#141)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
2025-06-17 22:15:14 -05:00
phernandez 3fdce683d7 Update README with new website and community links
- Add new main website: https://basicmemory.com
- Add Discord community: https://discord.gg/tyvKNccgqN
- Add YouTube channel: https://www.youtube.com/@basicmachines-co
- Reorganize links section for better clarity

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-15 10:37:24 -05:00
phernandez 782cb2df28 update README.md and CLAUDE.md docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-12 14:24:37 -05:00
phernandez 56c875f137 chore: update version to 0.13.5 for v0.13.5 release 2025-06-11 22:02:56 -05:00
phernandez 5049de7e2d docs: add changelog entry for v0.13.5
- Renamed create_project to create_memory_project for namespace isolation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 22:01:10 -05:00
phernandez 49011768f7 fix: rename create_project to create_memory_project for namespace isolation
Continue the namespace isolation effort by renaming the create_project tool
to create_memory_project to avoid conflicts with other MCP servers.

Changes:
- Renamed @mcp.tool() decorator from 'create_project' to 'create_memory_project'
- Updated all test references to use the new tool name
- Tool functionality remains identical, only the name changed
- Part of broader effort to ensure Basic Memory tools have unique namespaced names

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 21:58:40 -05:00
phernandez bc3557f000 chore: update version to 0.13.4 for v0.13.4 release 2025-06-11 21:41:06 -05:00
phernandez 611f5cd305 docs: add changelog entry for v0.13.4
- Renamed list_projects to list_memory_projects for namespace isolation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 21:39:20 -05:00
phernandez 4ea392d284 fix: rename list_projects to list_memory_projects to avoid naming conflicts
The tool name 'list_projects' was too generic and could conflict with other MCP servers.
Renamed to 'list_memory_projects' for better specificity and namespace isolation.

Changes:
- Renamed @mcp.tool() decorator from 'list_projects' to 'list_memory_projects'
- Updated all test references to use the new tool name
- Tool functionality remains identical, only the name changed

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 21:37:48 -05:00
phernandez d491757980 docs: add changelog entries for v0.13.2 and v0.13.3
- v0.13.2: automated release management system with version control
- v0.13.3: case-insensitive project switching bug fixes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 19:33:48 -05:00
phernandez 7a69ca2c36 chore: update version to 0.13.3 for v0.13.3 release 2025-06-11 19:29:04 -05:00
phernandez 70a6ce3411 fix: resolve case-insensitive project switching issues
This commit fixes the persistent case-insensitive project switching bug
where switching to projects with different case variations would succeed
but subsequent operations would fail.

Key changes:
- Enhanced config manager with case-insensitive project lookup using permalinks
- Updated project management tools to handle both name and permalink matching
- Fixed API URL construction to use permalinks consistently
- Added comprehensive test coverage for case-insensitive operations
- Updated project service to support permalink-based lookups

The fix ensures that users can switch to projects using any case variation
(e.g., "personal", "Personal", "PERSONAL") and all subsequent operations
work correctly with the canonical project name.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 19:26:27 -05:00
phernandez 5b69fd65cd fix: resolve case-insensitive project switching database lookup issue
Fix project switching bug where case-insensitive matching worked but
caused database lookup failures for subsequent operations.

**Problem:**
- switch_project('personal') succeeded (case-insensitive matching)
- get_current_project() failed with 'Project personal not found'
- Session stored user input case instead of canonical database name

**Solution:**
- Find project by permalink (case-insensitive) in switch_project
- Store canonical project name from database in session
- Use canonical name for all API calls and responses

**Test Coverage:**
- Added comprehensive case-insensitive project switching tests
- Added tests for case preservation in project listings
- Added tests for session state consistency after case switching
- Added error handling tests for non-existent projects

**Files Changed:**
- src/basic_memory/mcp/tools/project_management.py: Fixed switch_project logic
- test-int/mcp/test_project_management_integration.py: Added test coverage

**Test Cases Now Passing:**
-  switch_project('personal') → finds 'Personal' project
-  get_current_project() → works with canonical name
-  Project summary shows stats correctly
-  Case-insensitive matching for all case variations
-  Error handling for non-existent projects

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 18:19:17 -05:00
phernandez 85a178a6b8 chore: update version to 0.13.2 for v0.13.2 release 2025-06-11 17:09:57 -05:00
phernandez e4b32d7bc9 feat: add automated release management system
- Add version management in __init__.py
- Add justfile targets for release and beta automation
- Create Claude command documentation for /release and /beta
- Implement comprehensive quality checks and validation
- Support automated version updates and git tagging

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 17:06:23 -05:00
phernandez 9590b934cf Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-06-11 16:55:48 -05:00
phernandez 735f239f9b chore: update CHANGELOG.md for v0.13.1 release
Add changelog entry for v0.13.1 patch release documenting:
- Fixed CLI project management commands (#129)
- Resolved case sensitivity issues in project switching (#127)
- API endpoint standardization and improved error handling
- Consistent project name handling using permalinks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 16:14:04 -05:00
Paul Hernandez 3ee30e1f36 fix: project cli commands and case sensitivity when switching projects (#130)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-11 16:09:53 -05:00
phernandez ac401ea254 chore: prepare for v0.13.0 release by removing release notes file
The release notes content has been integrated into CHANGELOG.md.
Removing the standalone RELEASE_NOTES_v0.13.0.md file as it's no longer needed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-11 08:36:30 -05:00
phernandez fb2fd62ed9 fix: resolve type error and prepare for v0.13.0b6 release
- Add type ignore comment for MCP prompt function call
- Function works correctly at runtime despite false positive type error
- All quality checks now passing
2025-06-09 15:38:59 -05:00
phernandez 126d1655e6 fix: simplify versioning for release workflow
- Use static API version 'v0' instead of dynamic package version
- Remove version verification step in release workflow
- Dynamic versioning handled by uv-dynamic-versioning at build time
2025-06-09 15:25:20 -05:00
phernandez 2abf626c46 fix: resolve unused variable lint warnings in tests
- Remove unused variables in test mock functions
- Clean up test code per ruff linting rules
2025-06-09 15:15:05 -05:00
phernandez ba8e3d112d chore: update dependencies for beta release
- fastmcp 2.7.0 -> 2.7.1
- automated dependency updates
2025-06-09 00:48:48 -05:00
phernandez 7108a7baf1 fix: resolve sync race conditions and search errors
- Add IntegrityError handling in entity_service.create_entity_from_markdown for file_path/permalink constraint violations
- Add IntegrityError handling in sync_service.sync_regular_file for concurrent sync race conditions
- Fix FTS "unknown special query" error when searching for wildcard "*" patterns
- Add comprehensive test coverage for race condition edge cases and error handling
- Gracefully handle concurrent sync processes with fallback to update operations

Fixes sync errors from beta testing including:
- "UNIQUE constraint failed: entity.file_path"
- "UNIQUE constraint failed: entity.permalink"
- "unknown special query" FTS errors

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-08 15:20:27 -05:00
phernandez 35884ef3a7 fix: update MCP tool/prompt/resource calls to use .fn attribute
FastMCP library changes now require calling decorated functions via the .fn attribute:
- Tools: @mcp.tool() functions return FunctionTool, call with tool.fn()
- Prompts: @mcp.prompt() functions return FunctionPrompt, call with prompt.fn()
- Resources: @mcp.resource() functions return FunctionResource, call with resource.fn()

Updated core files:
- view_note.py: read_note() → read_note.fn()
- read_note.py: search_notes() → search_notes.fn() (2 locations)
- tool.py: 6 MCP tool calls updated to use .fn
- recent_activity.py: recent_activity() → recent_activity.fn()
- project.py: project_info() → project_info.fn() with type ignore

Updated 100+ test files systematically to use .fn attribute and fixed mock targets.

All 869 tests now pass. Fixes view_note tool error in Claude Desktop.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-08 11:52:23 -05:00
phernandez 040be05a81 fix: normalize project names in config during startup
- Fix case sensitivity bug where config had "Personal" but database expected "personal"
- Add project name normalization in synchronize_projects() to use generate_permalink()
- Update config file with normalized names and log changes for user visibility
- Use proper permalink generation instead of hardcoded name.lower().replace()
- Add comprehensive tests for project name normalization scenarios

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-08 09:28:57 -05:00
phernandez c141d7d1e6 chore: update version to 0.13.0b5 for release 2025-06-05 17:08:07 -05:00
phernandez b73aeb5ed8 feat: add view_note tool for formatted artifacts
- Implement view_note tool for better note readability in Claude Desktop
- Display notes as formatted markdown artifacts with special instructions
- Extract titles from frontmatter or headings automatically
- Add comprehensive test suite with 100% coverage
- Include view_note in live testing plan and release notes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-05 16:57:11 -05:00
phernandez 9a0e0bd82d add view_note tool
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-05 16:30:09 -05:00
phernandez 117fa44ecf fix project info stats tests
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-05 15:51:11 -05:00
phernandez 69d7610d47 test coverage 100%
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-05 13:07:20 -05:00
phernandez f608cd13f1 add justfile instead of Makefile, add ignores to test coverage
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-05 12:26:31 -05:00
phernandez 2162ad57fe all tests passing
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-05 11:13:40 -05:00
phernandez dd6ca80716 fix link_resolver tests
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-04 23:57:01 -05:00
phernandez ae3eeb0cc1 add tool prompting and doc updates for strict mode in edit/move, and sync_status tool
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-04 23:46:48 -05:00
phernandez 602c55fe90 only allow edit_note, move_note using strict identifier match
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-04 23:37:29 -05:00
phernandez 91bfe2dc92 add sync status tool
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-04 22:24:10 -05:00
phernandez a3cae1064d add background migration task and status tool/prompt
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-04 16:52:12 -05:00
phernandez c5c70cb0f4 improve validation for memory:// urls, add examples to build_context
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-04 00:16:33 -05:00
phernandez 80ec860a1c remove coverage files
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-03 23:14:07 -05:00
phernandez f64d5b2152 improve error messages for tools
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-03 23:12:59 -05:00
phernandez 69a625acd1 fix search escape issues, and empty forward reference resolving for entities
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-03 18:09:41 -05:00
phernandez 53c29a37ca fix: resolve FTS5 search syntax errors with special characters
Enhances search term preparation to handle special characters gracefully while preserving functionality:

- Improves FTS5 query preparation with targeted special character handling
- Preserves boolean operators (AND, OR, NOT) without modification
- Quotes problematic characters that cause syntax errors
- Maintains wildcard patterns for legitimate use cases
- Adds comprehensive error handling with graceful fallback

Includes extensive test coverage:
- 10 new test cases for various search scenarios
- Programming terms (C++, function(), email@domain.com) now searchable
- Malformed syntax handled without crashes
- Boolean and wildcard functionality preserved

Fixes search crashes when users enter queries containing special characters.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 16:45:13 -05:00
phernandez d8c13bf1d3 fix project table unique constraint bug
Signed-off-by: phernandez <paul@basicmachines.co>
2025-06-03 14:23:15 -05:00
phernandez 3f70f5ed42 feat: add /project:test-live command for comprehensive real-world testing
Implements live testing suite that:
- Uses installed Basic Memory version via MCP
- Follows TESTING.md methodology systematically
- Records all observations in Basic Memory notes
- Tests all 5 phases: core, features, edge cases, workflows, stress
- Creates dedicated test project for isolation
- Documents bugs with reproduction steps
- Tracks performance metrics and UX insights
- Validates v0.13.0 features in real usage scenarios

This enables 'Basic Memory testing itself' - comprehensive integration
testing that creates living documentation of test results.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 09:40:52 -05:00
phernandez 569a3de80b feat: add comprehensive custom Claude Code slash commands
Adds custom slash commands for streamlined development workflow:

Release Management (/project:release:*):
- beta - Create beta releases with automated quality checks
- release - Create stable releases with comprehensive validation
- release-check - Pre-flight validation without making changes
- changelog - Generate changelog entries from commits

Development (/project:*):
- test-coverage - Run tests with detailed coverage analysis
- lint-fix - Comprehensive code quality fixes with auto-repair
- check-health - Project health assessment and metrics

Commands are organized in .claude/commands/ directory following Claude Code
conventions and provide structured automation for common development tasks.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 09:24:03 -05:00
phernandez ac08a8d024 fix: update FastMCP initialization for API changes
- Remove deprecated auth_server_provider parameter
- Use auth parameter correctly with OAuthProvider instead of AuthSettings
- Fixes type error after dependency updates

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 09:08:17 -05:00
phernandez c13d4b1511 chore: update dependencies via make update-deps
- Updated authlib and other dependencies to latest versions
- Includes setuptools import fix for runtime compatibility

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 08:53:56 -05:00
phernandez 5b85d33a99 fix: remove unused setuptools import causing runtime error
Fixes ModuleNotFoundError when basic-memory is installed in environments
without setuptools (common with uv tool installs)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 08:52:30 -05:00
phernandez e2bd3142dc docs: remove working documentation files
Clean up development docs before v0.13.0 beta release

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 08:45:37 -05:00
phernandez 40b7de9168 docs: add comprehensive v0.13.0 changelog entry
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-03 08:43:54 -05:00
phernandez 455a280707 Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-06-03 08:31:42 -05:00
Paul Hernandez 634486107b feat: v0.13.0 pre (#122)
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-03 01:00:40 -05:00
phernandez 23d34289fd Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-05-28 14:46:45 -05:00
Paul Hernandez 5ec4087f7c feat: Add Claude Code GitHub Workflow (#120)
Co-authored-by: Claude <noreply@anthropic.com>
2025-05-28 14:45:33 -05:00
phernandez 71941c35dd Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-05-25 10:07:54 -05:00
bm-claudeai 020957cd76 feat: Multi-project support, OAuth authentication, and major improvements (#119)
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: phernandez <paul@basicmachines.co>
Co-authored-by: Claude <noreply@anthropic.com>
2025-05-25 10:07:34 -05:00
phernandez b3af6aa685 Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-04-17 11:12:18 -05:00
semantic-release 9437a5f83b chore(release): 0.12.3 [skip ci] 2025-04-17 16:04:31 +00:00
phernandez 3c1cc346df fix: modify recent_activity args to be strings instead of enums
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-17 10:56:46 -05:00
phernandez 81616ab42e update CLAUDE.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-17 10:56:46 -05:00
phernandez 321471f29d update CLAUDE.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-17 10:17:47 -05:00
phernandez 73ea91fe0d fix: add extra logic for permalink generation with mixed Latin unicode and Chinese characters
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-17 10:00:40 -05:00
andyxinweiminicloud 03d4e97b90 Fix: preserve Chinese characters in permalinks 2025-04-17 09:03:35 -05:00
Paul Hernandez 98622a7a47 Update README.md
fix example json for passing --project arg

Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-04-16 07:50:12 -05:00
Amadeusz Wieczorek 54dfa08aba Update name of function search_notes in error output (#92)
Signed-off-by: Amadeusz Wieczorek <git@amadeusw.com>
2025-04-14 11:06:15 -05:00
semantic-release 9433065a57 chore(release): 0.12.2 [skip ci] 2025-04-08 16:27:42 +00:00
Paul Hernandez 2934176331 fix: utf8 for all file reads/write/open instead of default platform encoding (#91)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-08 10:55:01 -05:00
semantic-release ac89eb47cb chore(release): 0.12.1 [skip ci] 2025-04-07 22:47:23 +00:00
Paul Hernandez 78a3412bcf fix: run migrations and sync when starting mcp (#88) 2025-04-07 17:45:26 -05:00
Paul Hernandez fa314b5d2b Update README.md
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-04-06 20:29:00 -05:00
Paul Hernandez d2ac62a27c Update README.md
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-04-06 20:25:06 -05:00
semantic-release 7ce7a29f35 chore(release): 0.12.0 [skip ci] 2025-04-06 23:44:17 +00:00
Paul Hernandez 3f4d9e4d87 fix: write_note preserves frontmatter fields in content (#84) 2025-04-06 18:39:51 -05:00
Paul Hernandez 00c8633cfc feat: add watch to mcp process (#83) 2025-04-06 18:33:10 -05:00
Paul Hernandez 617e60bda4 feat: permalink enhancements (#82)
- Avoiding "useless permalink values" for files without metadata
- Enable permalinks to be updated on move via config setting
2025-04-06 14:54:59 -05:00
github-actions[bot] 6c19c9edf5 fix: [BUG] # character accumulation in markdown frontmatter tags prop (#79) 2025-04-05 23:07:53 -05:00
github-actions[bot] 9bff1f732e fix: [BUG] write_note Tool Fails to Update Existing Files in Some Situations. (#80) 2025-04-05 22:31:40 -05:00
Paul Hernandez 248214cb11 fix: set default mcp log level to ERROR (#81) 2025-04-05 22:27:29 -05:00
Jason Noble 40ea28b0bf docs: Updated basicmachines.co links to be https (#69) 2025-04-05 22:22:37 -05:00
Marc Baiza 43cbb7b38c docs: Add VS Code instructions to README (#76) 2025-04-05 22:18:56 -05:00
github-actions[bot] 7930ddb291 fix: [BUG] Some notes never exit "modified" status (#77) 2025-04-05 22:03:38 -05:00
phernandez 1844e58210 Add pull_request_target trigger to test workflow with explanatory comment 2025-04-05 20:30:05 -05:00
phernandez 7fbb5ebfc5 Update claude-code-github-action to v0.11.0 with backtick handling fix 2025-04-05 20:04:18 -05:00
phernandez 0e5a465b10 add claude-output to .gitignore
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-05 19:45:07 -05:00
github-actions[bot] 9d581cee13 fix: [BUG] Cursor has errors calling search tool (#78) 2025-04-05 19:12:23 -05:00
phernandez f58852954b Update to claude-code-github-action v0.10.0 to check comment author for org membership 2025-04-05 12:54:33 -05:00
phernandez edd426b99f Update to claude-code-github-action v0.9.0 with organization membership check fix 2025-04-05 12:42:35 -05:00
phernandez 6b4a421315 Update to claude-code-github-action v0.8.0 with PERSONAL_ACCESS_TOKEN support 2025-04-05 12:13:05 -05:00
phernandez 4632405446 Fix claude-code-actions.yml to use v0.7.0 of basicmachines-co action 2025-04-05 12:01:04 -05:00
phernandez 3a6d5ff58d update claude code actions
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-04 23:31:08 -05:00
phernandez 03de85ec32 add claude code github action workflow
Signed-off-by: phernandez <paul@basicmachines.co>
2025-04-04 21:20:40 -05:00
phernandez 084c91ecce update basic-memory dep version
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-30 17:46:44 -05:00
semantic-release 3d45227b72 chore(release): 0.11.0 [skip ci] 2025-03-29 00:19:46 +00:00
Paul Hernandez 069c0a21c6 feat: add bm command alias for basic-memory (#67)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-28 19:12:25 -05:00
Paul Hernandez b27827671d feat: rename search tool to search_notes (#66)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-28 19:11:35 -05:00
Paul Hernandez 0743ade5fc fix: just delete db for reset db instead of using migrations. (#65)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-28 19:11:11 -05:00
Paul Hernandez f1c95709cb fix: make logs for each process - mcp, sync, cli (#64)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-28 19:10:43 -05:00
Matias Forbord 3c68b7d5dd docs: Update broken "Multiple Projects" link in README.md (#55) 2025-03-26 14:31:51 -05:00
semantic-release 3d0077990f chore(release): 0.10.1 [skip ci] 2025-03-25 18:12:28 +00:00
phernandez 731b502d36 docs: add help docs to mcp cli tools
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-25 13:01:11 -05:00
phernandez 2a881b1425 refactor: move project stats into projct subcommand
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-25 12:50:11 -05:00
phernandez 681af5d450 chore: remove duplicate code in entity_service.py from bad merge
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-25 12:27:37 -05:00
phernandez b35037eb86 fix broken merge
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-24 23:18:22 -05:00
phernandez b667bca5a2 fix test coverage and type checks
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-24 22:46:47 -05:00
phernandez e716946b44 fix: preserve custom frontmatter fields when updating notes
Fixes #36 by modifying entity_service.update_entity() to read existing
frontmatter from files before updating them. Custom metadata fields
such as Status, Priority, and Version are now preserved when notes
are updated through the write_note MCP tool.

Added test case that verifies this behavior by creating a note with
custom frontmatter and then updating it.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-24 22:46:47 -05:00
phernandez 46c4fd2164 fix: make set_default_project also activate project for current session to fix #37
This change makes the 'basic-memory project default <name>' command both:
1. Set the default project for future invocations (persistent change)
2. Activate the project for the current session (immediate change)

Added tests to verify this behavior, which resolves issue #37 where the
project name and path weren't changing properly when the default project
was changed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-24 22:46:47 -05:00
phernandez 9c791259a0 \fix: improve tags handling in write_note tool to fix #38\n\nThis change makes the write_note tool more flexible with tag inputs by:\n1. Adding a parse_tags helper function to handle various input formats\n2. Removing explicit type annotation from the write_note signature\n3. Adding documentation on how to pass tags from external MCP clients\n4. Adding a test that reproduces the issue from bug report #38\n\nThe issue occurred in external MCP clients like Cursor where the tags\nparameter was causing type mismatch errors.\n\n\ud83e\udd16 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-24 22:46:47 -05:00
phernandez cc2cae72c1 fix: move ai_assistant_guide.md into package resources to fix #39
This change relocates the AI assistant guide from the static directory
into the package resources directory, ensuring it gets properly included
in the distribution package and is accessible when installed via pip/uv.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-24 22:46:47 -05:00
phernandez 0a1fdd8f15 update docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-24 22:46:47 -05:00
phernandez 78f234b180 fix: preserve custom frontmatter fields when updating notes
Fixes #36 by modifying entity_service.update_entity() to read existing
frontmatter from files before updating them. Custom metadata fields
such as Status, Priority, and Version are now preserved when notes
are updated through the write_note MCP tool.

Added test case that verifies this behavior by creating a note with
custom frontmatter and then updating it.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-24 19:50:38 -05:00
phernandez cbe72be10a fix: make set_default_project also activate project for current session to fix #37
This change makes the 'basic-memory project default <name>' command both:
1. Set the default project for future invocations (persistent change)
2. Activate the project for the current session (immediate change)

Added tests to verify this behavior, which resolves issue #37 where the
project name and path weren't changing properly when the default project
was changed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-24 18:56:51 -05:00
phernandez 0ade6b0603 \fix: improve tags handling in write_note tool to fix #38\n\nThis change makes the write_note tool more flexible with tag inputs by:\n1. Adding a parse_tags helper function to handle various input formats\n2. Removing explicit type annotation from the write_note signature\n3. Adding documentation on how to pass tags from external MCP clients\n4. Adding a test that reproduces the issue from bug report #38\n\nThe issue occurred in external MCP clients like Cursor where the tags\nparameter was causing type mismatch errors.\n\n\ud83e\udd16 Generated with [Claude Code](https://claude.ai/code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\ 2025-03-24 18:30:21 -05:00
phernandez 390ff9d31c fix: move ai_assistant_guide.md into package resources to fix #39
This change relocates the AI assistant guide from the static directory
into the package resources directory, ensuring it gets properly included
in the distribution package and is accessible when installed via pip/uv.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-24 17:34:47 -05:00
phernandez 3ed74b4a4d update docs 2025-03-24 17:28:30 -05:00
Ikko Eltociear Ashimine dfaf0fea9c docs: update CLAUDE.md (#33)
fix spelling in CLAUDE.md: enviroment -> environment
Signed-off-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
2025-03-24 13:15:12 -05:00
phernandez b26afa927f docs: add mcp badge, update cli reference, llms-install.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-16 14:09:08 -05:00
phernandez 3806943f8c add star history to README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-16 11:24:08 -05:00
phernandez 3bffb2e190 Add updated getting started docs and utf8 test
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 16:52:17 -05:00
semantic-release 9fe34dcddf chore(release): 0.10.0 [skip ci] 2025-03-15 20:49:20 +00:00
Paul Hernandez eb5e4ec6bd fix: improve utf-8 support for file reading/writing (#32)
fixes #29

Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 15:43:37 -05:00
Paul Hernandez 6b110b28dd fix: don't sync *.tmp files on watch (#31)
Fixes #30

Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 15:43:28 -05:00
phernandez 88d193e0aa Edig content in README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 11:46:53 -05:00
phernandez fa9175f049 Remove redundant info in README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 11:45:28 -05:00
phernandez 7c787a413c Simpify README.md, ONTRIBUTING.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 11:31:18 -05:00
Paul Hernandez 0fa1adf3b5 Update README.md
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-03-15 11:17:29 -05:00
phernandez cbe488fbd2 remove .obsidian dir in docs, try to fix video
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 11:00:27 -05:00
Paul Hernandez 99ff8f60c2 Update README.md
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-03-15 10:57:59 -05:00
phernandez 06ee2852a0 try to fix video in README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 10:53:08 -05:00
phernandez 939bab1a24 fix demo link in README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 10:48:58 -05:00
phernandez 67736487fb update README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 10:43:41 -05:00
phernandez 2ac620f98b Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-03-15 10:40:16 -05:00
phernandez 4cbda7a9d4 update docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-15 10:40:09 -05:00
Paul Hernandez 3070ade69a Create dependabot.yml
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-03-15 10:34:53 -05:00
Paul Hernandez 9af913da4f docs: add glama badge. Fix typos in README.md (#28)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-13 13:24:39 -05:00
Paul Hernandez 7b7bec9557 Create SECURITY.md
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2025-03-12 15:51:23 -05:00
bm-claudeai fea2f40d1b docs: Update CLAUDE.md with GitHub integration capabilities (#25)
This PR updates the CLAUDE.md file to document the GitHub integration
capabilities that enable Claude to participate directly in the
development workflow.
2025-03-11 16:32:30 -05:00
bm-claudeai eb1e7b6088 feat: Add Smithery integration for easier installation (#24)
This PR adds support for deploying Basic Memory on the Smithery platform.

Signed-off-by: bm-claudeai <claude@basicmachines.co>
2025-03-11 16:21:51 -05:00
phernandez 9203730ba7 update README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-11 14:04:01 -05:00
phernandez 1a473c02e9 remove cool asii art from README.md
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-11 14:00:37 -05:00
phernandez b6f5d8a545 update getting started docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-11 13:35:33 -05:00
phernandez addeeb1e7f update user docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-11 13:30:00 -05:00
phernandez 85f9099b0a update docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-08 11:53:24 -06:00
phernandez 82b6f3d60e update user guide docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-08 11:51:17 -06:00
semantic-release 8a7432949b chore(release): 0.9.0 [skip ci] 2025-03-07 20:54:32 +00:00
Paul Hernandez 6a4bd54646 chore: Pre beta prep (#20)
fix: drop search_index table on db reindex 
fix: ai_resource_guide.md path
chore: remove logfire
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-07 14:31:35 -06:00
phernandez da97353cfc fix: ai_resource_guide.md path
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-07 14:25:24 -06:00
phernandez 2e9d673e54 fix: ai_resource_guide.md path
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-07 14:24:48 -06:00
phernandez c4732a47b3 fix: ai_resource_guide.md path 2025-03-07 14:19:27 -06:00
phernandez 2d5176e800 add user guide docs
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-07 14:11:06 -06:00
phernandez 9bb8a020c3 chore: remove logfire
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-06 13:06:48 -06:00
phernandez 31cca6f913 fix: drop search_index table on db reindex
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-06 12:51:25 -06:00
Paul Hernandez d2bd75a949 feat: add project_info tool (#19)
Signed-off-by: phernandez <paul@basicmachines.co>
2025-03-05 23:44:28 -06:00
Paul Hernandez 90d5754180 feat: Implement boolean search (#18) 2025-03-05 20:57:12 -06:00
Paul Hernandez e6496df595 feat: Beta work (#17)
feat: Add multiple projects support 
feat: enhanced read_note for when initial result is not found
fix: merge frontmatter when updating note
fix: handle directory removed on sync watch
2025-03-05 18:46:04 -06:00
phernandez 41868fd34c Add contributing docs and github workflows 2025-03-01 15:46:51 -06:00
phernandez a3072702b9 add CLA.md 2025-03-01 14:13:09 -06:00
phernandez 182ec78355 docs: update README.md and CLAUDE.md 2025-03-01 13:43:09 -06:00
Paul Hernandez f8078cdd46 Fix: Beta testing fixes (#16)
Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-28 20:23:53 -06:00
semantic-release 4bcbeacdd2 chore(release): 0.8.0 [skip ci] 2025-02-28 02:50:27 +00:00
Paul Hernandez 093dab5f03 feat: Add enhanced prompts and resources (#15)
## Summary
- Add comprehensive documentation to all MCP prompt modules
- Enhance search prompt with detailed contextual output formatting
- Implement consistent logging and docstring patterns across prompt
utilities
- Fix type checking in prompt modules

## Prompts Added/Enhanced
- `search.py`: New formatted output with relevance scores, excerpts, and
next steps
- `recent_activity.py`: Enhanced with better metadata handling and
documentation
- `continue_conversation.py`: Improved context management

## Resources Added/Enhanced
- `ai_assistant_guide`: Resource with description to give to LLM to
understand how to use the tools

## Technical improvements
- Added detailed docstrings to all prompt modules explaining their
purpose and usage
- Enhanced the search prompt with rich contextual output that helps LLMs
understand results
- Created a consistent pattern for formatting output across prompts
- Improved error handling in metadata extraction
- Standardized import organization and naming conventions
- Fixed various type checking issues across the codebase

This PR is part of our ongoing effort to improve the MCP's interaction
quality with LLMs, making the system more helpful and intuitive for AI
assistants to navigate knowledge bases.

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-27 20:48:56 -06:00
Paul Hernandez 0d7b0b3d7e feat: Add new canvas tool to create json canvas files in obsidian. (#14)
Add new `canvas` tool to create json canvas files in obsidian.

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-25 21:21:05 -06:00
phernandez 93cc6379eb chore: formatting 2025-02-24 22:18:27 -06:00
Paul Hernandez 37a01b806d feat: Incremental sync on watch (#13)
- incremental sync on watch
- sync non-markdown files in knowledge base
- experimental `read_resource` tool for reading non-markdown files in raw form (pdf, image)
2025-02-24 22:13:15 -06:00
phernandez a573f78317 try to optimize image size for mcp tool response 2025-02-23 17:30:47 -06:00
phernandez ab36e7e560 return optimized image from read_resource tool - tweaks 2025-02-23 16:54:07 -06:00
phernandez 959b278687 return optimized image from read_resource tool 2025-02-23 16:50:00 -06:00
phernandez 04b387c742 add more logging for image response 2025-02-23 16:38:20 -06:00
phernandez 0c59fd5e83 handle image response in tools WIP 2025-02-23 16:14:06 -06:00
phernandez 2ed920aa50 add resource tool to read binary files 2025-02-23 15:34:41 -06:00
phernandez bd20185492 read img/pdf via tool 2025-02-23 13:51:47 -06:00
phernandez f731a23e49 fix sync and status cli 2025-02-22 17:16:33 -06:00
phernandez 07a9415451 add alembic migration for relation_to_name uniqueness 2025-02-22 15:05:40 -06:00
phernandez 20d0375ffa sync non-markdown files 2025-02-22 14:50:40 -06:00
phernandez eb4a55a5e7 code cleanup 2025-02-21 22:11:54 -06:00
phernandez 51b4eb32c5 fix tests 2025-02-21 21:40:28 -06:00
phernandez 74adae506e fix tests 2025-02-21 21:36:39 -06:00
phernandez 94394f0bfe new sync service implementation 2025-02-21 19:10:23 -06:00
phernandez 9e3f71cb87 file sync WIP 2025-02-20 22:29:40 -06:00
phernandez f4b703e57f chore: refactor logging setup 2025-02-19 20:22:01 -06:00
semantic-release 6b8cefcd45 chore(release): 0.7.0 [skip ci] 2025-02-19 14:27:20 +00:00
phernandez 57984aa912 chore: fix tests 2025-02-18 23:48:22 -06:00
phernandez f5a7541da1 feat: add cli commands for mcp tools 2025-02-18 23:23:09 -06:00
phernandez bc9ca0744f fix: search query pagination params 2025-02-18 21:29:11 -06:00
phernandez 2c8ed1737d chore: remove unused tests 2025-02-18 20:45:47 -06:00
phernandez 02f8e86692 feat: add pagination to read_notes 2025-02-18 20:42:19 -06:00
phernandez 0123544556 feat: add pagination to build_context and recent_activity 2025-02-18 20:22:35 -06:00
phernandez 00d23a5ee1 fix: add logfire spans to cli 2025-02-18 19:56:20 -06:00
phernandez 812136c8c2 fix: add logfire spans to cli 2025-02-18 19:08:46 -06:00
phernandez 3e8e3e8961 fix: add logfire instrumentation to tools 2025-02-18 18:52:09 -06:00
phernandez 8544bb7966 Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-02-18 16:19:20 -06:00
phernandez 66b57e682f chore: re-add sync status console on watch 2025-02-18 16:19:14 -06:00
semantic-release 58a1296111 chore(release): 0.6.0 [skip ci] 2025-02-18 22:09:14 +00:00
Paul Hernandez 6da143898b feat: configure logfire telemetry (#12)
Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-18 15:53:38 -06:00
semantic-release a6b46908b1 chore(release): 0.5.0 [skip ci] 2025-02-18 05:34:50 +00:00
Paul Hernandez 0689e7a730 feat: return semantic info in markdown after write_note (#11)
Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-17 23:33:11 -06:00
semantic-release 16466e9269 chore(release): 0.4.3 [skip ci] 2025-02-18 00:49:28 +00:00
Paul Hernandez 39bd5ca08f fix: Re do enhanced read note format (#10)
Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-17 18:47:59 -06:00
semantic-release 4a1f5452c4 chore(release): 0.4.2 [skip ci] 2025-02-17 03:54:57 +00:00
phernandez 9c9960e2ca Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-02-16 21:49:51 -06:00
phernandez 30cd74ec95 fix: more alembic fixes 2025-02-16 21:49:41 -06:00
semantic-release 132c5671d8 chore(release): 0.4.1 [skip ci] 2025-02-17 03:29:36 +00:00
phernandez 71de8acfd0 fix: fix alemic config 2025-02-16 21:22:22 -06:00
phernandez 50469d691b Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-02-16 21:13:44 -06:00
phernandez 85e620c72b rejigger alembic files 2025-02-16 21:13:29 -06:00
semantic-release 493e0902b6 chore(release): 0.4.0 [skip ci] 2025-02-16 19:49:15 +00:00
Paul Hernandez 56f47d6812 feat: import chatgpt conversation data (#9)
Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-16 13:47:16 -06:00
Paul Hernandez a15c346d5e feat: Import claude.ai data (#8)
Import Claude.ai conversation and project data to basic-memory Markdown
format.

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>
2025-02-16 12:47:41 -06:00
semantic-release c06cf19e62 chore(release): 0.3.0 [skip ci] 2025-02-15 20:43:17 +00:00
phernandez 41f5b1667b format code 2025-02-15 14:38:19 -06:00
phernandez ca632beb6f fix: refactor db schema migrate handling 2025-02-15 14:36:12 -06:00
phernandez a491c2b7d4 Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-02-15 12:36:20 -06:00
phernandez 674dd1fd47 fix: remove create schema from init_db 2025-02-15 12:36:08 -06:00
phernandez a91da13967 feat: set version in var, output version at startup 2025-02-15 12:26:48 -06:00
phernandez e0803734e6 fix: handle memory:// url format in read_note tool 2025-02-15 12:00:03 -06:00
semantic-release 8a5a970ba9 chore(release): 0.2.21 [skip ci] 2025-02-15 00:13:30 +00:00
phernandez 65ebe5d194 fix: fix osx installer github action 2025-02-14 18:11:44 -06:00
phernandez 8370a06b6c re-add xattr 2025-02-14 17:55:23 -06:00
phernandez 3270e6d82b upload build artifacts 2025-02-14 17:49:35 -06:00
phernandez c05d363a99 comment out xattr 2025-02-14 17:44:46 -06:00
phernandez 3f9c68ed85 set codesign_identity 2025-02-14 17:40:30 -06:00
phernandez a8ffe051ea install dev deps 2025-02-14 17:29:54 -06:00
phernandez 2c74434e99 install librrsvg 2025-02-14 17:22:50 -06:00
phernandez bea3d6c889 wtf setup python 2025-02-14 17:20:23 -06:00
phernandez 14539010b1 wtf 2025-02-14 17:16:10 -06:00
phernandez a19287c967 add installer build step back in 2025-02-14 17:09:22 -06:00
phernandez 64430b850e installer debug 2025-02-14 16:54:37 -06:00
phernandez 10b2e91e34 Merge branch 'main' of github.com:basicmachines-co/basic-memory 2025-02-14 16:14:50 -06:00
phernandez 1989db15fa debug release installer app 2025-02-14 16:14:30 -06:00
semantic-release 17f0517917 chore(release): 0.2.20 [skip ci] 2025-02-14 05:40:17 +00:00
phernandez 8de84c0221 fix: fix installer artifact 2025-02-13 23:38:47 -06:00
296 changed files with 66217 additions and 6104 deletions
+95
View File
@@ -0,0 +1,95 @@
# /beta - Create Beta Release
Create a new beta release using the automated justfile target with quality checks and tagging.
## Usage
```
/beta <version>
```
**Parameters:**
- `version` (required): Beta version like `v0.13.2b1` or `v0.13.2rc1`
## Implementation
You are an expert release manager for the Basic Memory project. When the user runs `/beta`, execute the following steps:
### Step 1: Pre-flight Validation
1. Verify version format matches `v\d+\.\d+\.\d+(b\d+|rc\d+)` pattern
2. Check current git status for uncommitted changes
3. Verify we're on the `main` branch
4. Confirm no existing tag with this version
### Step 2: Use Justfile Automation
Execute the automated beta release process:
```bash
just beta <version>
```
The justfile target handles:
- ✅ Beta version format validation (supports b1, b2, rc1, etc.)
- ✅ Git status and branch checks
- ✅ Quality checks (`just check` - lint, format, type-check, tests)
- ✅ Version update in `src/basic_memory/__init__.py`
- ✅ Automatic commit with proper message
- ✅ Tag creation and pushing to GitHub
- ✅ Beta release workflow trigger
### Step 3: Monitor Beta Release
1. Check GitHub Actions workflow starts successfully
2. Monitor workflow at: https://github.com/basicmachines-co/basic-memory/actions
3. Verify PyPI pre-release publication
4. Test beta installation: `uv tool install basic-memory --pre`
### Step 4: Beta Testing Instructions
Provide users with beta testing instructions:
```bash
# Install/upgrade to beta
uv tool install basic-memory --pre
# Or upgrade existing installation
uv tool upgrade basic-memory --prerelease=allow
```
## Version Guidelines
- **First beta**: `v0.13.2b1`
- **Subsequent betas**: `v0.13.2b2`, `v0.13.2b3`, etc.
- **Release candidates**: `v0.13.2rc1`, `v0.13.2rc2`, etc.
- **Final release**: `v0.13.2` (use `/release` command)
## Error Handling
- If `just beta` fails, examine the error output for specific issues
- If quality checks fail, fix issues and retry
- If version format is invalid, correct and retry
- If tag already exists, increment version number
## Success Output
```
✅ Beta Release v0.13.2b1 Created Successfully!
🏷️ Tag: v0.13.2b1
🚀 GitHub Actions: Running
📦 PyPI: Will be available in ~5 minutes as pre-release
Install/test with:
uv tool install basic-memory --pre
Monitor release: https://github.com/basicmachines-co/basic-memory/actions
```
## Beta Testing Workflow
1. **Create beta**: Use `/beta v0.13.2b1`
2. **Test features**: Install and validate new functionality
3. **Fix issues**: Address bugs found during testing
4. **Iterate**: Create `v0.13.2b2` if needed
5. **Release candidate**: Create `v0.13.2rc1` when stable
6. **Final release**: Use `/release v0.13.2` when ready
## Context
- Beta releases are pre-releases for testing new features
- Automatically published to PyPI with pre-release flag
- Uses the automated justfile target for consistency
- Version is automatically updated in `__init__.py`
- Ideal for validating changes before stable release
- Supports both beta (b1, b2) and release candidate (rc1, rc2) versions
+160
View File
@@ -0,0 +1,160 @@
# /changelog - Generate or Update Changelog Entry
Analyze commits and generate formatted changelog entry for a version.
## Usage
```
/changelog <version> [type]
```
**Parameters:**
- `version` (required): Version like `v0.14.0` or `v0.14.0b1`
- `type` (optional): `beta`, `rc`, or `stable` (default: `stable`)
## Implementation
You are an expert technical writer for the Basic Memory project. When the user runs `/changelog`, execute the following steps:
### Step 1: Version Analysis
1. **Determine Commit Range**
```bash
# Find last release tag
git tag -l "v*" --sort=-version:refname | grep -v "b\|rc" | head -1
# Get commits since last release
git log --oneline ${last_tag}..HEAD
```
2. **Parse Conventional Commits**
- Extract feat: (features)
- Extract fix: (bug fixes)
- Extract BREAKING CHANGE: (breaking changes)
- Extract chore:, docs:, test: (other improvements)
### Step 2: Categorize Changes
1. **Features (feat:)**
- New MCP tools
- New CLI commands
- New API endpoints
- Major functionality additions
2. **Bug Fixes (fix:)**
- User-facing bug fixes
- Critical issues resolved
- Performance improvements
- Security fixes
3. **Technical Improvements**
- Test coverage improvements
- Code quality enhancements
- Dependency updates
- Documentation updates
4. **Breaking Changes**
- API changes
- Configuration changes
- Behavior changes
- Migration requirements
### Step 3: Generate Changelog Entry
Create formatted entry following existing CHANGELOG.md style:
Example:
```markdown
## <version> (<date>)
### Features
- **Multi-Project Management System** - Switch between projects instantly during conversations
([`993e88a`](https://github.com/basicmachines-co/basic-memory/commit/993e88a))
- Instant project switching with session context
- Project-specific operations and isolation
- Project discovery and management tools
- **Advanced Note Editing** - Incremental editing with append, prepend, find/replace, and section operations
([`6fc3904`](https://github.com/basicmachines-co/basic-memory/commit/6fc3904))
- `edit_note` tool with multiple operation types
- Smart frontmatter-aware editing
- Validation and error handling
### Bug Fixes
- **#118**: Fix YAML tag formatting to follow standard specification
([`2dc7e27`](https://github.com/basicmachines-co/basic-memory/commit/2dc7e27))
- **#110**: Make --project flag work consistently across CLI commands
([`02dd91a`](https://github.com/basicmachines-co/basic-memory/commit/02dd91a))
### Technical Improvements
- **Comprehensive Testing** - 100% test coverage with integration testing
([`468a22f`](https://github.com/basicmachines-co/basic-memory/commit/468a22f))
- MCP integration test suite
- End-to-end testing framework
- Performance and edge case validation
### Breaking Changes
- **Database Migration**: Automatic migration from per-project to unified database.
Data will be re-index from the filesystem, resulting in no data loss.
- **Configuration Changes**: Projects now synced between config.json and database
- **Full Backward Compatibility**: All existing setups continue to work seamlessly
```
### Step 4: Integration
1. **Update CHANGELOG.md**
- Insert new entry at top
- Maintain consistent formatting
- Include commit links and issue references
2. **Validation**
- Check all major changes are captured
- Verify commit links work
- Ensure issue numbers are correct
## Smart Analysis Features
### Automatic Classification
- Detect feature additions from file changes
- Identify bug fixes from commit messages
- Find breaking changes from code analysis
- Extract issue numbers from commit messages
### Content Enhancement
- Add context for technical changes
- Include migration guidance for breaking changes
- Suggest installation/upgrade instructions
- Link to relevant documentation
## Output Format
### For Beta Releases
Example:
```markdown
## v0.13.0b4 (2025-06-03)
### Beta Changes Since v0.13.0b3
- Fix FastMCP API compatibility issues
- Update dependencies to latest versions
- Resolve setuptools import error
### Installation
```bash
uv tool install basic-memory --prerelease=allow
```
### Known Issues
- [List any known issues for beta testing]
```
### For Stable Releases
Full changelog with complete feature list, organized by impact and category.
## Context
- Follows existing CHANGELOG.md format and style
- Uses conventional commit standards
- Includes GitHub commit links for traceability
- Focuses on user-facing changes and value
- Maintains consistency with previous entries
+131
View File
@@ -0,0 +1,131 @@
# /release-check - Pre-flight Release Validation
Comprehensive pre-flight check for release readiness without making any changes.
## Usage
```
/release-check [version]
```
**Parameters:**
- `version` (optional): Version to validate like `v0.13.0`. If not provided, determines from context.
## Implementation
You are an expert QA engineer for the Basic Memory project. When the user runs `/release-check`, execute the following validation steps:
### Step 1: Environment Validation
1. **Git Status Check**
- Verify working directory is clean
- Confirm on `main` branch
- Check if ahead/behind origin
2. **Version Validation**
- Validate version format if provided
- Check for existing tags with same version
- Verify version increments properly from last release
### Step 2: Code Quality Gates
1. **Test Suite Validation**
```bash
just test
```
- All tests must pass
- Check test coverage (target: 95%+)
- Validate no skipped critical tests
2. **Code Quality Checks**
```bash
just lint
just type-check
```
- No linting errors
- No type checking errors
- Code formatting is consistent
### Step 3: Documentation Validation
1. **Changelog Check**
- CHANGELOG.md contains entry for target version
- Entry includes all major features and fixes
- Breaking changes are documented
2. **Documentation Currency**
- README.md reflects current functionality
- CLI reference is up to date
- MCP tools are documented
### Step 4: Dependency Validation
1. **Security Scan**
- No known vulnerabilities in dependencies
- All dependencies are at appropriate versions
- No conflicting dependency versions
2. **Build Validation**
- Package builds successfully
- All required files are included
- No missing dependencies
### Step 5: Issue Tracking Validation
1. **GitHub Issues Check**
- No critical open issues blocking release
- All milestone issues are resolved
- High-priority bugs are fixed
2. **Testing Coverage**
- Integration tests pass
- MCP tool tests pass
- Cross-platform compatibility verified
## Report Format
Generate a comprehensive report:
```
🔍 Release Readiness Check for v0.13.0
✅ PASSED CHECKS:
├── Git status clean
├── On main branch
├── All tests passing (744/744)
├── Test coverage: 98.2%
├── Type checking passed
├── Linting passed
├── CHANGELOG.md updated
└── No critical issues open
⚠️ WARNINGS:
├── 2 medium-priority issues still open
└── Documentation could be updated
❌ BLOCKING ISSUES:
└── None found
🎯 RELEASE READINESS: ✅ READY
Recommended next steps:
1. Address warnings if desired
2. Run `/release v0.13.0` when ready
```
## Validation Criteria
### Must Pass (Blocking)
- [ ] All tests pass
- [ ] No type errors
- [ ] No linting errors
- [ ] Working directory clean
- [ ] On main branch
- [ ] CHANGELOG.md has version entry
- [ ] No critical open issues
### Should Pass (Warnings)
- [ ] Test coverage >95%
- [ ] No medium-priority open issues
- [ ] Documentation up to date
- [ ] No dependency vulnerabilities
## Context
- This is a read-only validation - makes no changes
- Provides confidence before running actual release
- Helps identify issues early in release process
- Can be run multiple times safely
+92
View File
@@ -0,0 +1,92 @@
# /release - Create Stable Release
Create a stable release using the automated justfile target with comprehensive validation.
## Usage
```
/release <version>
```
**Parameters:**
- `version` (required): Release version like `v0.13.2`
## Implementation
You are an expert release manager for the Basic Memory project. When the user runs `/release`, execute the following steps:
### Step 1: Pre-flight Validation
1. Verify version format matches `v\d+\.\d+\.\d+` pattern
2. Check current git status for uncommitted changes
3. Verify we're on the `main` branch
4. Confirm no existing tag with this version
#### Documentation Validation
1. **Changelog Check**
- CHANGELOG.md contains entry for target version
- Entry includes all major features and fixes
- Breaking changes are documented
### Step 2: Use Justfile Automation
Execute the automated release process:
```bash
just release <version>
```
The justfile target handles:
- ✅ Version format validation
- ✅ Git status and branch checks
- ✅ Quality checks (`just check` - lint, format, type-check, tests)
- ✅ Version update in `src/basic_memory/__init__.py`
- ✅ Automatic commit with proper message
- ✅ Tag creation and pushing to GitHub
- ✅ Release workflow trigger
### Step 3: Monitor Release Process
1. Check that GitHub Actions workflow starts successfully
2. Monitor workflow completion at: https://github.com/basicmachines-co/basic-memory/actions
3. Verify PyPI publication
4. Test installation: `uv tool install basic-memory`
### Step 4: Post-Release Validation
1. Verify GitHub release is created automatically
2. Check PyPI publication
3. Validate release assets
4. Update any post-release documentation
## Pre-conditions Check
Before starting, verify:
- [ ] All beta testing is complete
- [ ] Critical bugs are fixed
- [ ] Breaking changes are documented
- [ ] CHANGELOG.md is updated (if needed)
- [ ] Version number follows semantic versioning
## Error Handling
- If `just release` fails, examine the error output for specific issues
- If quality checks fail, fix issues and retry
- If changelog entry missing, update CHANGELOG.md and commit before retrying
- If GitHub Actions fail, check workflow logs for debugging
## Success Output
```
🎉 Stable Release v0.13.2 Created Successfully!
🏷️ Tag: v0.13.2
📋 GitHub Release: https://github.com/basicmachines-co/basic-memory/releases/tag/v0.13.2
📦 PyPI: https://pypi.org/project/basic-memory/0.13.2/
🚀 GitHub Actions: Completed
Install with:
uv tool install basic-memory
Users can now upgrade:
uv tool upgrade basic-memory
```
## Context
- This creates production releases used by end users
- Must pass all quality gates before proceeding
- Uses the automated justfile target for consistency
- Version is automatically updated in `__init__.py`
- Triggers automated GitHub release with changelog
- Leverages uv-dynamic-versioning for package version management
+595
View File
@@ -0,0 +1,595 @@
# /project:test-live - Live Basic Memory Testing Suite
Execute comprehensive real-world testing of Basic Memory using the installed version.
All test results are recorded as notes in a dedicated test project.
## Usage
```
/project:test-live [phase]
```
**Parameters:**
- `phase` (optional): Specific test phase to run (`recent`, `core`, `features`, `edge`, `workflows`, `stress`, or `all`)
- `recent` - Focus on recent changes and new features (recommended for regular testing)
- `core` - Essential tools only (Tier 1: write_note, read_note, search_notes, edit_note, list_projects, switch_project)
- `features` - Core + important workflows (Tier 1 + Tier 2)
- `all` - Comprehensive testing of all tools and scenarios
## Implementation
You are an expert QA engineer conducting live testing of Basic Memory.
When the user runs `/project:test-live`, execute comprehensive test plan:
## Tool Testing Priority
### **Tier 1: Critical Core (Always Test)**
1. **write_note** - Foundation of all knowledge creation
2. **read_note** - Primary knowledge retrieval mechanism
3. **search_notes** - Essential for finding information
4. **edit_note** - Core content modification capability
5. **list_memory_projects** - Project discovery and status
6. **switch_project** - Context switching for multi-project workflows
### **Tier 2: Important Workflows (Usually Test)**
7. **recent_activity** - Understanding what's changed
8. **build_context** - Conversation continuity via memory:// URLs
9. **create_memory_project** - Essential for project setup
10. **move_note** - Knowledge organization
11. **sync_status** - Understanding system state
### **Tier 3: Enhanced Functionality (Sometimes Test)**
12. **view_note** - Claude Desktop artifact display
13. **read_content** - Raw content access
14. **delete_note** - Content removal
15. **list_directory** - File system exploration
16. **set_default_project** - Configuration
17. **delete_project** - Administrative cleanup
### **Tier 4: Specialized (Rarely Test)**
18. **canvas** - Obsidian visualization (specialized use case)
19. **MCP Prompts** - Enhanced UX tools (ai_assistant_guide, continue_conversation)
### Pre-Test Setup
1. **Environment Verification**
- Verify basic-memory is installed and accessible via MCP
- Check version and confirm it's the expected release
- Test MCP connection and tool availability
2. **Recent Changes Analysis** (if phase includes 'recent' or 'all')
- Run `git log --oneline -20` to examine recent commits
- Identify new features, bug fixes, and enhancements
- Generate targeted test scenarios for recent changes
- Prioritize regression testing for recently fixed issues
3. **Test Project Creation**
Run the bash `date` command to get the current date/time.
```
Create project: "basic-memory-testing-[timestamp]"
Location: ~/basic-memory-testing-[timestamp]
Purpose: Record all test observations and results
```
Make sure to switch to the newly created project with the `switch_project()` tool.
4. **Baseline Documentation**
Create initial test session note with:
- Test environment details
- Version being tested
- Recent changes identified (if applicable)
- Test objectives and scope
- Start timestamp
### Phase 0: Recent Changes Validation (if 'recent' or 'all' phase)
Based on recent commit analysis, create targeted test scenarios:
**Recent Changes Test Protocol:**
1. **Feature Addition Tests** - For each new feature identified:
- Test basic functionality
- Test integration with existing tools
- Verify documentation accuracy
- Test edge cases and error handling
2. **Bug Fix Regression Tests** - For each recent fix:
- Recreate the original problem scenario
- Verify the fix works as expected
- Test related functionality isn't broken
- Document the verification in test notes
3. **Performance/Enhancement Validation** - For optimizations:
- Establish baseline timing
- Compare with expected improvements
- Test under various load conditions
- Document performance observations
**Example Recent Changes (Update based on actual git log):**
- Watch Service Restart (#156): Test project creation → file modification → automatic restart
- Cross-Project Moves (#161): Test move_note with cross-project detection
- Docker Environment Support (#174): Test BASIC_MEMORY_HOME behavior
- MCP Server Logging (#164): Verify log level configurations
### Phase 1: Core Functionality Validation (Tier 1 Tools)
Test essential MCP tools that form the foundation of Basic Memory:
**1. write_note Tests (Critical):**
- ✅ Basic note creation with frontmatter
- ✅ Special characters and Unicode in titles
- ✅ Various content types (lists, headings, code blocks)
- ✅ Empty notes and minimal content edge cases
- ⚠️ Error handling for invalid parameters
**2. read_note Tests (Critical):**
- ✅ Read by title, permalink, memory:// URLs
- ✅ Non-existent notes (error handling)
- ✅ Notes with complex markdown formatting
- ⚠️ Performance with large notes (>10MB)
**3. search_notes Tests (Critical):**
- ✅ Simple text queries across content
- ✅ Tag-based searches with multiple tags
- ✅ Boolean operators (AND, OR, NOT)
- ✅ Empty/no results scenarios
- ⚠️ Performance with 100+ notes
**4. edit_note Tests (Critical):**
- ✅ Append operations preserving frontmatter
- ✅ Prepend operations
- ✅ Find/replace with validation
- ✅ Section replacement under headers
- ⚠️ Error scenarios (invalid operations)
**5. list_memory_projects Tests (Critical):**
- ✅ Display all projects with status indicators
- ✅ Current and default project identification
- ✅ Empty project list handling
- ✅ Project metadata accuracy
**6. switch_project Tests (Critical):**
- ✅ Switch between existing projects
- ✅ Context preservation during switch
- ⚠️ Invalid project name handling
- ✅ Confirmation of successful switch
### Phase 2: Important Workflows (Tier 2 Tools)
**7. recent_activity Tests (Important):**
- ✅ Various timeframes ("today", "1 week", "1d")
- ✅ Type filtering capabilities
- ✅ Empty project scenarios
- ⚠️ Performance with many recent changes
**8. build_context Tests (Important):**
- ✅ Different depth levels (1, 2, 3+)
- ✅ Various timeframes for context
- ✅ memory:// URL navigation
- ⚠️ Performance with complex relation graphs
**9. create_memory_project Tests (Important):**
- ✅ Create projects dynamically
- ✅ Set default during creation
- ✅ Path validation and creation
- ⚠️ Invalid paths and names
- ✅ Integration with existing projects
**10. move_note Tests (Important):**
- ✅ Move within same project
- ✅ Cross-project moves with detection (#161)
- ✅ Automatic folder creation
- ✅ Database consistency validation
- ⚠️ Special characters in paths
**11. sync_status Tests (Important):**
- ✅ Background operation monitoring
- ✅ File synchronization status
- ✅ Project sync state reporting
- ⚠️ Error state handling
### Phase 3: Enhanced Functionality (Tier 3 Tools)
**12. view_note Tests (Enhanced):**
- ✅ Claude Desktop artifact display
- ✅ Title extraction from frontmatter
- ✅ Unicode and emoji content rendering
- ⚠️ Error handling for non-existent notes
**13. read_content Tests (Enhanced):**
- ✅ Raw file content access
- ✅ Binary file handling
- ✅ Image file reading
- ⚠️ Large file performance
**14. delete_note Tests (Enhanced):**
- ✅ Single note deletion
- ✅ Database consistency after deletion
- ⚠️ Non-existent note handling
- ✅ Confirmation of successful deletion
**15. list_directory Tests (Enhanced):**
- ✅ Directory content listing
- ✅ Depth control and filtering
- ✅ File name globbing
- ⚠️ Empty directory handling
**16. set_default_project Tests (Enhanced):**
- ✅ Change default project
- ✅ Configuration persistence
- ⚠️ Invalid project handling
**17. delete_project Tests (Enhanced):**
- ✅ Project removal from config
- ✅ Database cleanup
- ⚠️ Default project protection
- ⚠️ Non-existent project handling
### Phase 4: Edge Case Exploration
**Boundary Testing:**
- Very long titles and content (stress limits)
- Empty projects and notes
- Unicode, emojis, special symbols
- Deeply nested folder structures
- Circular relations and self-references
- Maximum relation depths
**Error Scenarios:**
- Invalid memory:// URLs
- Missing files referenced in database
- Invalid project names and paths
- Malformed note structures
- Concurrent operation conflicts
**Performance Testing:**
- Create 100+ notes rapidly
- Complex search queries
- Deep relation chains (5+ levels)
- Rapid successive operations
- Memory usage monitoring
### Phase 5: Real-World Workflow Scenarios
**Meeting Notes Pipeline:**
1. Create meeting notes with action items
2. Extract action items using edit_note
3. Build relations to project documents
4. Update progress incrementally
5. Search and track completion
**Research Knowledge Building:**
1. Create research topic hierarchy
2. Build complex relation networks
3. Add incremental findings over time
4. Search for connections and patterns
5. Reorganize as knowledge evolves
**Multi-Project Workflow:**
1. Technical documentation project
2. Personal recipe collection project
3. Learning/course notes project
4. Switch contexts during conversation
5. Cross-reference related concepts
**Content Evolution:**
1. Start with basic notes
2. Enhance with relations and observations
3. Reorganize file structure using moves
4. Update content with edit operations
5. Validate knowledge graph integrity
### Phase 6: Specialized Tools Testing (Tier 4)
**18. canvas Tests (Specialized):**
- ✅ JSON Canvas generation
- ✅ Node and edge creation
- ✅ Obsidian compatibility
- ⚠️ Complex graph handling
**19. MCP Prompts Tests (Specialized):**
- ✅ ai_assistant_guide output
- ✅ continue_conversation functionality
- ✅ Formatted search results
- ✅ Enhanced activity reports
### Phase 7: Integration & File Watching Tests
**File System Integration:**
- ✅ Watch service behavior with file changes
- ✅ Project creation → watch restart (#156)
- ✅ Multi-project synchronization
- ⚠️ MCP→API→DB→File stack validation
**Real Integration Testing:**
- ✅ End-to-end file watching vs manual operations
- ✅ Cross-session persistence
- ✅ Database consistency across operations
- ⚠️ Performance under real file system changes
### Phase 8: Creative Stress Testing
**Creative Exploration:**
- Rapid project creation/switching patterns
- Unusual but valid markdown structures
- Creative observation categories
- Novel relation types and patterns
- Unexpected tool combinations
**Stress Scenarios:**
- Bulk operations (many notes quickly)
- Complex nested moves and edits
- Deep context building
- Complex boolean search expressions
- Resource constraint testing
## Test Execution Guidelines
### Quick Testing (core/features phases)
- Focus on Tier 1 tools (core) or Tier 1+2 (features)
- Test essential functionality and common edge cases
- Record critical issues immediately
- Complete in 15-20 minutes
### Comprehensive Testing (all phase)
- Cover all tiers systematically
- Include specialized tools and stress testing
- Document performance baselines
- Complete in 45-60 minutes
### Recent Changes Focus (recent phase)
- Analyze git log for recent commits
- Generate targeted test scenarios
- Focus on regression testing for fixes
- Validate new features thoroughly
## Test Observation Format
Record ALL observations immediately as Basic Memory notes:
```markdown
---
title: Test Session [Phase] YYYY-MM-DD HH:MM
tags: [testing, v0.13.0, live-testing, [phase]]
permalink: test-session-[phase]-[timestamp]
---
# Test Session [Phase] - [Date/Time]
## Environment
- Basic Memory version: [version]
- MCP connection: [status]
- Test project: [name]
- Phase focus: [description]
## Test Results
### ✅ Successful Operations
- [timestamp] ✅ write_note: Created note with emoji title 📝 #tier1 #functionality
- [timestamp] ✅ search_notes: Boolean query returned 23 results in 0.4s #tier1 #performance
- [timestamp] ✅ edit_note: Append operation preserved frontmatter #tier1 #reliability
### ⚠️ Issues Discovered
- [timestamp] ⚠️ move_note: Slow with deep folder paths (2.1s) #tier2 #performance
- [timestamp] 🚨 search_notes: Unicode query returned unexpected results #tier1 #bug #critical
- [timestamp] ⚠️ build_context: Context lost for memory:// URLs #tier2 #issue
### 🚀 Enhancements Identified
- edit_note could benefit from preview mode #ux-improvement
- search_notes needs fuzzy matching for typos #feature-idea
- move_note could auto-suggest folder creation #usability
### 📊 Performance Metrics
- Average write_note time: 0.3s
- Search with 100+ notes: 0.6s
- Project switch overhead: 0.1s
- Memory usage: [observed levels]
## Relations
- tests [[Basic Memory v0.13.0]]
- part_of [[Live Testing Suite]]
- found_issues [[Bug Report: Unicode Search]]
- discovered [[Performance Optimization Opportunities]]
```
## Quality Assessment Areas
**User Experience & Usability:**
- Tool instruction clarity and examples
- Error message actionability
- Response time acceptability
- Tool consistency and discoverability
- Learning curve and intuitiveness
**System Behavior:**
- Context preservation across operations
- memory:// URL navigation reliability
- Multi-step workflow cohesion
- Edge case graceful handling
- Recovery from user errors
**Documentation Alignment:**
- Tool output clarity and helpfulness
- Behavior vs. documentation accuracy
- Example validity and usefulness
- Real-world vs. documented workflows
**Mental Model Validation:**
- Natural user expectation alignment
- Surprising behavior identification
- Mistake recovery ease
- Knowledge graph concept naturalness
**Performance & Reliability:**
- Operation completion times
- Consistency across sessions
- Scaling behavior with growth
- Unexpected slowness identification
## Error Documentation Protocol
For each error discovered:
1. **Immediate Recording**
- Create dedicated error note
- Include exact reproduction steps
- Capture error messages verbatim
- Note system state when error occurred
2. **Error Note Format**
```markdown
---
title: Bug Report - [Short Description]
tags: [bug, testing, v0.13.0, [severity]]
---
# Bug Report: [Description]
## Reproduction Steps
1. [Exact steps to reproduce]
2. [Include all parameters used]
3. [Note any special conditions]
## Expected Behavior
[What should have happened]
## Actual Behavior
[What actually happened]
## Error Messages
```
[Exact error text]
```
## Environment
- Version: [version]
- Project: [name]
- Timestamp: [when]
## Severity
- [ ] Critical (blocks major functionality)
- [ ] High (impacts user experience)
- [ ] Medium (workaround available)
- [ ] Low (minor inconvenience)
## Relations
- discovered_during [[Test Session [Phase]]]
- affects [[Feature Name]]
```
## Success Metrics Tracking
**Quantitative Measures:**
- Test scenario completion rate
- Bug discovery count with severity
- Performance benchmark establishment
- Tool coverage completeness
**Qualitative Measures:**
- Conversation flow naturalness
- Knowledge graph quality
- User experience insights
- System reliability assessment
## Test Execution Flow
1. **Setup Phase** (5 minutes)
- Verify environment and create test project
- Record baseline system state
- Establish performance benchmarks
2. **Core Testing** (15-20 minutes per phase)
- Execute test scenarios systematically
- Record observations immediately
- Note timestamps for performance tracking
- Explore variations when interesting behaviors occur
3. **Documentation** (5 minutes per phase)
- Create phase summary note
- Link related test observations
- Update running issues list
- Record enhancement ideas
4. **Analysis Phase** (10 minutes)
- Review all observations across phases
- Identify patterns and trends
- Create comprehensive summary report
- Generate development recommendations
## Testing Success Criteria
### Core Testing (Tier 1) - Must Pass
- All 6 critical tools function correctly
- No critical bugs in essential workflows
- Acceptable performance for basic operations
- Error handling works as expected
### Feature Testing (Tier 1+2) - Should Pass
- All 11 core + important tools function
- Workflow scenarios complete successfully
- Performance meets baseline expectations
- Integration points work correctly
### Comprehensive Testing (All Tiers) - Complete Coverage
- All tools tested across all scenarios
- Edge cases and stress testing completed
- Performance baselines established
- Full documentation of issues and enhancements
## Expected Outcomes
**System Validation:**
- Feature verification prioritized by tier importance
- Recent changes validated for regression
- Performance baseline establishment
- Bug identification with severity assessment
**Knowledge Base Creation:**
- Prioritized testing documentation
- Real usage examples for user guides
- Recent changes validation records
- Performance insights for optimization
**Development Insights:**
- Tier-based bug priority list
- Recent changes impact assessment
- Enhancement ideas from real usage
- User experience improvement areas
## Post-Test Deliverables
1. **Test Summary Note**
- Overall results and findings
- Critical issues requiring immediate attention
- Enhancement opportunities discovered
- System readiness assessment
2. **Bug Report Collection**
- All discovered issues with reproduction steps
- Severity and impact assessments
- Suggested fixes where applicable
3. **Performance Baseline**
- Timing data for all operations
- Scaling behavior observations
- Resource usage patterns
4. **UX Improvement Recommendations**
- Usability enhancement suggestions
- Documentation improvement areas
- Tool design optimization ideas
5. **Updated TESTING.md**
- Incorporate new test scenarios discovered
- Update based on real execution experience
- Add performance benchmarks and targets
## Context
- Uses real installed basic-memory version
- Tests complete MCP→API→DB→File stack
- Creates living documentation in Basic Memory itself
- Follows integration over isolation philosophy
- Prioritizes testing by tool importance and usage frequency
- Adapts to recent development changes dynamically
- Focuses on real usage patterns over checklist validation
- Generates actionable insights prioritized by impact
+60
View File
@@ -0,0 +1,60 @@
# Git files
.git/
.gitignore
.gitattributes
# Development files
.vscode/
.idea/
*.swp
*.swo
*~
# Testing files
tests/
test-int/
.pytest_cache/
.coverage
htmlcov/
# Build artifacts
build/
dist/
*.egg-info/
__pycache__/
*.pyc
*.pyo
*.pyd
.Python
# Virtual environments (uv creates these during build)
.venv/
venv/
.env
# CI/CD files
.github/
# Documentation (keep README.md and pyproject.toml)
docs/
CHANGELOG.md
CLAUDE.md
CONTRIBUTING.md
# Example files not needed for runtime
examples/
# Local development files
.basic-memory/
*.db
*.sqlite3
# OS files
.DS_Store
Thumbs.db
# Temporary files
tmp/
temp/
*.tmp
*.log
+38
View File
@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve Basic Memory
title: '[BUG] '
labels: bug
assignees: ''
---
## Bug Description
A clear and concise description of what the bug is.
## Steps To Reproduce
Steps to reproduce the behavior:
1. Install version '...'
2. Run command '...'
3. Use tool/feature '...'
4. See error
## Expected Behavior
A clear and concise description of what you expected to happen.
## Actual Behavior
What actually happened, including error messages and output.
## Environment
- OS: [e.g. macOS 14.2, Ubuntu 22.04]
- Python version: [e.g. 3.12.1]
- Basic Memory version: [e.g. 0.1.0]
- Installation method: [e.g. pip, uv, source]
- Claude Desktop version (if applicable):
## Additional Context
- Configuration files (if relevant)
- Logs or screenshots
- Any special configuration or environment variables
## Possible Solution
If you have any ideas on what might be causing the issue or how to fix it, please share them here.
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Basic Memory Discussions
url: https://github.com/basicmachines-co/basic-memory/discussions
about: For questions, ideas, or more open-ended discussions
- name: Documentation
url: https://github.com/basicmachines-co/basic-memory#readme
about: Please check the documentation first before reporting an issue
+19
View File
@@ -0,0 +1,19 @@
---
name: Documentation improvement
about: Suggest improvements or report issues with documentation
title: '[DOCS] '
labels: documentation
assignees: ''
---
## Documentation Issue
Describe what's missing, unclear, or incorrect in the current documentation.
## Location
Where is the problematic documentation? (URL, file path, or section)
## Suggested Improvement
How would you improve this documentation? Please be as specific as possible.
## Additional Context
Any additional information or screenshots that might help explain the issue or improvement.
+28
View File
@@ -0,0 +1,28 @@
---
name: Feature request
about: Suggest an idea for Basic Memory
title: '[FEATURE] '
labels: enhancement
assignees: ''
---
## Feature Description
A clear and concise description of the feature you'd like to see implemented.
## Problem This Feature Solves
Describe the problem or limitation you're experiencing that this feature would address.
## Proposed Solution
Describe how you envision this feature working. Include:
- User workflow
- Interface design (if applicable)
- Technical approach (if you have ideas)
## Alternative Solutions
Have you considered any alternative solutions or workarounds?
## Additional Context
Add any other context, screenshots, or examples about the feature request here.
## Impact
How would this feature benefit you and other users of Basic Memory?
+12
View File
@@ -0,0 +1,12 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
+114
View File
@@ -0,0 +1,114 @@
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
steps:
- name: Check user permissions
id: check_membership
uses: actions/github-script@v7
with:
script: |
let actor;
if (context.eventName === 'issue_comment') {
actor = context.payload.comment.user.login;
} else if (context.eventName === 'pull_request_review_comment') {
actor = context.payload.comment.user.login;
} else if (context.eventName === 'pull_request_review') {
actor = context.payload.review.user.login;
} else if (context.eventName === 'issues') {
actor = context.payload.issue.user.login;
}
console.log(`Checking permissions for user: ${actor}`);
// List of explicitly allowed users (organization members)
const allowedUsers = [
'phernandez',
'groksrc',
'nellins',
'bm-claudeai'
];
if (allowedUsers.includes(actor)) {
console.log(`User ${actor} is in the allowed list`);
core.setOutput('is_member', true);
return;
}
// Fallback: Check if user has repository permissions
try {
const collaboration = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: actor
});
const permission = collaboration.data.permission;
console.log(`User ${actor} has permission level: ${permission}`);
// Allow if user has push access or higher (write, maintain, admin)
const allowed = ['write', 'maintain', 'admin'].includes(permission);
core.setOutput('is_member', allowed);
if (!allowed) {
core.notice(`User ${actor} does not have sufficient repository permissions (has: ${permission})`);
}
} catch (error) {
console.log(`Error checking permissions: ${error.message}`);
// Final fallback: Check if user is a public member of the organization
try {
const membership = await github.rest.orgs.getMembershipForUser({
org: 'basicmachines-co',
username: actor
});
const allowed = membership.data.state === 'active';
core.setOutput('is_member', allowed);
if (!allowed) {
core.notice(`User ${actor} is not a public member of basicmachines-co organization`);
}
} catch (membershipError) {
console.log(`Error checking organization membership: ${membershipError.message}`);
core.setOutput('is_member', false);
core.notice(`User ${actor} does not have access to this repository`);
}
}
- name: Checkout repository
if: steps.check_membership.outputs.is_member == 'true'
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code
if: steps.check_membership.outputs.is_member == 'true'
id: claude
uses: anthropics/claude-code-action@beta
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
allowed_tools: Bash(uv run pytest),Bash(uv run ruff check . --fix),Bash(uv run ruff format .),Bash(uv run pyright),Bash(just test),Bash(just lint),Bash(just format),Bash(just type-check),Bash(just check),Read,Write,Edit,MultiEdit,Glob,Grep,LS, mcp__web_search
+53
View File
@@ -0,0 +1,53 @@
name: Dev Release
on:
push:
branches: [main]
workflow_dispatch: # Allow manual triggering
jobs:
dev-release:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
run: |
pip install uv
- name: Install dependencies and build
run: |
uv venv
uv sync
uv build
- name: Check if this is a dev version
id: check_version
run: |
VERSION=$(uv run python -c "import basic_memory; print(basic_memory.__version__)")
echo "version=$VERSION" >> $GITHUB_OUTPUT
if [[ "$VERSION" == *"dev"* ]]; then
echo "is_dev=true" >> $GITHUB_OUTPUT
echo "Dev version detected: $VERSION"
else
echo "is_dev=false" >> $GITHUB_OUTPUT
echo "Release version detected: $VERSION, skipping dev release"
fi
- name: Publish dev version to PyPI
if: steps.check_version.outputs.is_dev == 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_TOKEN }}
skip-existing: true # Don't fail if version already exists
+61
View File
@@ -0,0 +1,61 @@
name: Docker Image CI
on:
push:
tags:
- 'v*' # Trigger on version tags like v1.0.0, v0.13.0, etc.
workflow_dispatch: # Allow manual triggering for testing
env:
REGISTRY: ghcr.io
IMAGE_NAME: basicmachines-co/basic-memory
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+54 -87
View File
@@ -1,118 +1,85 @@
name: Release
on:
workflow_dispatch:
inputs:
version_type:
description: 'Type of version bump (major, minor, patch)'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
push:
tags:
- 'v*' # Trigger on version tags like v1.0.0, v0.13.0, etc.
jobs:
release:
runs-on: ubuntu-latest
concurrency: release
permissions:
id-token: write
contents: write
outputs:
released: ${{ steps.release.outputs.released }}
tag: ${{ steps.release.outputs.tag }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Python Semantic Release
id: release
uses: python-semantic-release/python-semantic-release@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
if: steps.release.outputs.released == 'true'
with:
password: ${{ secrets.PYPI_TOKEN }}
- name: Publish to GitHub Release Assets
uses: python-semantic-release/publish-action@v9.8.9
if: steps.release.outputs.released == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.release.outputs.tag }}
build-macos:
needs: release
if: needs.release.outputs.released == 'true'
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.release.outputs.tag }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
python-version: "3.12"
- name: Install uv
run: |
pip install uv
- name: Create virtual env
- name: Install dependencies and build
run: |
uv venv
uv sync
uv build
- name: Install dependencies
- name: Verify build succeeded
run: |
uv pip install -e .[dev]
# Verify that build artifacts exist
ls -la dist/
echo "Build completed successfully"
- name: Install librsvg
run: brew install librsvg
- name: Create icon
run: |
cd installer
chmod +x make_icons.sh
./make_icons.sh
- name: Build macOS installer
run: |
# Debug info
echo "Environment Info:"
uv pip list
python --version
which uv
which python
ls -la $(dirname $(which python))
echo "PYTHONPATH=$PYTHONPATH"
# Build
make installer-mac
#xattr -dr com.apple.quarantine "installer/build/Basic Memory Installer.app"
- name: Inspect build
run: |
echo "Build structure:"
ls -la installer/build/Basic\ Memory\ Installer.app/Contents/MacOS/
# - name: Zip macOS installer
# run: |
# cd installer/build
# zip -ry "Basic-Memory-Installer-${{ needs.release.outputs.tag }}.zip" "Basic Memory Installer.app"
- name: Upload macOS installer
uses: softprops/action-gh-release@v1
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
#files: installer/build/Basic-Memory-Installer-${{ needs.release.outputs.tag }}.zip
files: installer/build/Basic\ Memory\ Installer.app
tag_name: ${{ needs.release.outputs.tag }}
files: |
dist/*.whl
dist/*.tar.gz
generate_release_notes: true
tag_name: ${{ github.ref_name }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_TOKEN }}
homebrew:
name: Update Homebrew Formula
needs: release
runs-on: ubuntu-latest
# Only run for stable releases (not dev, beta, or rc versions)
if: ${{ !contains(github.ref_name, 'dev') && !contains(github.ref_name, 'b') && !contains(github.ref_name, 'rc') }}
permissions:
contents: write
actions: read
steps:
- name: Update Homebrew formula
uses: mislav/bump-homebrew-formula-action@v3
with:
# Formula name in homebrew-basic-memory repo
formula-name: basic-memory
# The tap repository
homebrew-tap: basicmachines-co/homebrew-basic-memory
# Base branch of the tap repository
base-branch: main
# Download URL will be automatically constructed from the tag
download-url: https://github.com/basicmachines-co/basic-memory/archive/refs/tags/${{ github.ref_name }}.tar.gz
# Commit message for the formula update
commit-message: |
{{formulaName}} {{version}}
Created by https://github.com/basicmachines-co/basic-memory/actions/runs/${{ github.run_id }}
env:
# Personal Access Token with repo scope for homebrew-basic-memory repo
COMMITTER_TOKEN: ${{ secrets.HOMEBREW_TOKEN }}
+22 -3
View File
@@ -5,14 +5,21 @@ on:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# pull_request_target runs on the BASE of the PR, not the merge result.
# It has write permissions and access to secrets.
# It's useful for PRs from forks or automated PRs but requires careful use for security reasons.
# See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
pull_request_target:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: [ "3.12" ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
@@ -29,6 +36,18 @@ jobs:
run: |
pip install uv
- name: Install just (Linux/macOS)
if: runner.os != 'Windows'
run: |
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin
- name: Install just (Windows)
if: runner.os == 'Windows'
run: |
# Install just using Chocolatey (pre-installed on GitHub Actions Windows runners)
choco install just --yes
shell: pwsh
- name: Create virtual env
run: |
uv venv
@@ -39,9 +58,9 @@ jobs:
- name: Run type checks
run: |
uv run make type-check
just type-check
- name: Run tests
run: |
uv pip install pytest pytest-cov
uv run make test
just test
+11
View File
@@ -42,3 +42,14 @@ ENV/
# macOS
.DS_Store
.coverage.*
# obsidian docs:
/docs/.obsidian/
/examples/.obsidian/
/examples/.basic-memory/
# claude action
claude-output
**/.claude/settings.local.json
+1126 -1
View File
File diff suppressed because it is too large Load Diff
+71
View File
@@ -0,0 +1,71 @@
# Contributor License Agreement
## Copyright Assignment and License Grant
By signing this Contributor License Agreement ("Agreement"), you accept and agree to the following terms and conditions
for your present and future Contributions submitted
to Basic Machines LLC. Except for the license granted herein to Basic Machines LLC and recipients of software
distributed by Basic Machines LLC, you reserve all right,
title, and interest in and to your Contributions.
### 1. Definitions
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this
Agreement with Basic Machines LLC.
"Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work,
that is intentionally submitted by You to Basic
Machines LLC for inclusion in, or documentation of, any of the products owned or managed by Basic Machines LLC (the "
Work").
### 2. Grant of Copyright License
Subject to the terms and conditions of this Agreement, You hereby grant to Basic Machines LLC and to recipients of
software distributed by Basic Machines LLC a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Work, and to permit persons to whom the Work is furnished to do so.
### 3. Assignment of Copyright
You hereby assign to Basic Machines LLC all right, title, and interest worldwide in all Copyright covering your
Contributions. Basic Machines LLC may license the
Contributions under any license terms, including copyleft, permissive, commercial, or proprietary licenses.
### 4. Grant of Patent License
Subject to the terms and conditions of this Agreement, You hereby grant to Basic Machines LLC and to recipients of
software distributed by Basic Machines LLC a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to
make, have made, use, offer to sell, sell, import, and
otherwise transfer the Work.
### 5. Developer Certificate of Origin
By making a Contribution to this project, You certify that:
(a) The Contribution was created in whole or in part by You and You have the right to submit it under this Agreement; or
(b) The Contribution is based upon previous work that, to the best of Your knowledge, is covered under an appropriate
open source license and You have the right under that
license to submit that work with modifications, whether created in whole or in part by You, under this Agreement; or
(c) The Contribution was provided directly to You by some other person who certified (a), (b) or (c) and You have not
modified it.
(d) You understand and agree that this project and the Contribution are public and that a record of the Contribution (
including all personal information You submit with
it, including Your sign-off) is maintained indefinitely and may be redistributed consistent with this project or the
open source license(s) involved.
### 6. Representations
You represent that you are legally entitled to grant the above license and assignment. If your employer(s) has rights to
intellectual property that you create that
includes your Contributions, you represent that you have received permission to make Contributions on behalf of that
employer, or that your employer has waived such rights
for your Contributions to Basic Machines LLC.
---
This Agreement is effective as of the date you first submit a Contribution to Basic Machines LLC.
+171
View File
@@ -0,0 +1,171 @@
# CLAUDE.md - Basic Memory Project Guide
## Project Overview
Basic Memory is a local-first knowledge management system built on the Model Context Protocol (MCP). It enables
bidirectional communication between LLMs (like Claude) and markdown files, creating a personal knowledge graph that can
be traversed using links between documents.
## CODEBASE DEVELOPMENT
### Project information
See the [README.md](README.md) file for a project overview.
### Build and Test Commands
- Install: `make install` or `pip install -e ".[dev]"`
- Run tests: `uv run pytest -p pytest_mock -v` or `make test`
- Single test: `pytest tests/path/to/test_file.py::test_function_name`
- Lint: `make lint` or `ruff check . --fix`
- Type check: `make type-check` or `uv run pyright`
- Format: `make format` or `uv run ruff format .`
- Run all code checks: `make check` (runs lint, format, type-check, test)
- Create db migration: `make migration m="Your migration message"`
- Run development MCP Inspector: `make run-inspector`
### Code Style Guidelines
- Line length: 100 characters max
- Python 3.12+ with full type annotations
- Format with ruff (consistent styling)
- Import order: standard lib, third-party, local imports
- Naming: snake_case for functions/variables, PascalCase for classes
- Prefer async patterns with SQLAlchemy 2.0
- Use Pydantic v2 for data validation and schemas
- CLI uses Typer for command structure
- API uses FastAPI for endpoints
- Follow the repository pattern for data access
- Tools communicate to api routers via the httpx ASGI client (in process)
### Codebase Architecture
- `/alembic` - Alembic db migrations
- `/api` - FastAPI implementation of REST endpoints
- `/cli` - Typer command-line interface
- `/markdown` - Markdown parsing and processing
- `/mcp` - Model Context Protocol server implementation
- `/models` - SQLAlchemy ORM models
- `/repository` - Data access layer
- `/schemas` - Pydantic models for validation
- `/services` - Business logic layer
- `/sync` - File synchronization services
### Development Notes
- MCP tools are defined in src/basic_memory/mcp/tools/
- MCP prompts are defined in src/basic_memory/mcp/prompts/
- MCP tools should be atomic, composable operations
- Use `textwrap.dedent()` for multi-line string formatting in prompts and tools
- MCP Prompts are used to invoke tools and format content with instructions for an LLM
- Schema changes require Alembic migrations
- SQLite is used for indexing and full text search, files are source of truth
- Testing uses pytest with asyncio support (strict mode)
- Test database uses in-memory SQLite
- Avoid creating mocks in tests in most circumstances.
- Each test runs in a standalone environment with in memory SQLite and tmp_file directory
## BASIC MEMORY PRODUCT USAGE
### Knowledge Structure
- Entity: Any concept, document, or idea represented as a markdown file
- Observation: A categorized fact about an entity (`- [category] content`)
- Relation: A directional link between entities (`- relation_type [[Target]]`)
- Frontmatter: YAML metadata at the top of markdown files
- Knowledge representation follows precise markdown format:
- Observations with [category] prefixes
- Relations with WikiLinks [[Entity]]
- Frontmatter with metadata
### Basic Memory Commands
- Sync knowledge: `basic-memory sync` or `basic-memory sync --watch`
- Import from Claude: `basic-memory import claude conversations`
- Import from ChatGPT: `basic-memory import chatgpt`
- Import from Memory JSON: `basic-memory import memory-json`
- Check sync status: `basic-memory status`
- Tool access: `basic-memory tools` (provides CLI access to MCP tools)
- Guide: `basic-memory tools basic-memory-guide`
- Continue: `basic-memory tools continue-conversation --topic="search"`
### MCP Capabilities
- Basic Memory exposes these MCP tools to LLMs:
**Content Management:**
- `write_note(title, content, folder, tags)` - Create/update markdown notes with semantic observations and relations
- `read_note(identifier, page, page_size)` - Read notes by title, permalink, or memory:// URL with knowledge graph
awareness
- `read_file(path)` - Read raw file content (text, images, binaries) without knowledge graph processing
**Knowledge Graph Navigation:**
- `build_context(url, depth, timeframe)` - Navigate the knowledge graph via memory:// URLs for conversation
continuity
- `recent_activity(type, depth, timeframe)` - Get recently updated information with specified timeframe (e.g., "
1d", "1 week")
**Search & Discovery:**
- `search(query, page, page_size)` - Full-text search across all content with filtering options
**Visualization:**
- `canvas(nodes, edges, title, folder)` - Generate Obsidian canvas files for knowledge graph visualization
- MCP Prompts for better AI interaction:
- `ai_assistant_guide()` - Guidance on effectively using Basic Memory tools for AI assistants
- `continue_conversation(topic, timeframe)` - Continue previous conversations with relevant historical context
- `search(query, after_date)` - Search with detailed, formatted results for better context understanding
- `recent_activity(timeframe)` - View recently changed items with formatted output
- `json_canvas_spec()` - Full JSON Canvas specification for Obsidian visualization
## AI-Human Collaborative Development
Basic Memory emerged from and enables a new kind of development process that combines human and AI capabilities. Instead
of using AI just for code generation, we've developed a true collaborative workflow:
1. AI (LLM) writes initial implementation based on specifications and context
2. Human reviews, runs tests, and commits code with any necessary adjustments
3. Knowledge persists across conversations using Basic Memory's knowledge graph
4. Development continues seamlessly across different AI sessions with consistent context
5. Results improve through iterative collaboration and shared understanding
This approach has allowed us to tackle more complex challenges and build a more robust system than either humans or AI
could achieve independently.
## GitHub Integration
Basic Memory has taken AI-Human collaboration to the next level by integrating Claude directly into the development workflow through GitHub:
### GitHub MCP Tools
Using the GitHub Model Context Protocol server, Claude can now:
- **Repository Management**:
- View repository files and structure
- Read file contents
- Create new branches
- Create and update files
- **Issue Management**:
- Create new issues
- Comment on existing issues
- Close and update issues
- Search across issues
- **Pull Request Workflow**:
- Create pull requests
- Review code changes
- Add comments to PRs
This integration enables Claude to participate as a full team member in the development process, not just as a code generation tool. Claude's GitHub account ([bm-claudeai](https://github.com/bm-claudeai)) is a member of the Basic Machines organization with direct contributor access to the codebase.
### Collaborative Development Process
With GitHub integration, the development workflow includes:
1. **Direct code review** - Claude can analyze PRs and provide detailed feedback
2. **Contribution tracking** - All of Claude's contributions are properly attributed in the Git history
3. **Branch management** - Claude can create feature branches for implementations
4. **Documentation maintenance** - Claude can keep documentation updated as the code evolves
This level of integration represents a new paradigm in AI-human collaboration, where the AI assistant becomes a full-fledged team member rather than just a tool for generating code snippets.
+195 -8
View File
@@ -1,17 +1,204 @@
# Contributing to Basic Memory
Thank you for considering contributing to Basic Memory! Your help is greatly appreciated to improve this project.
Thank you for considering contributing to Basic Memory! This document outlines the process for contributing to the
project and how to get started as a developer.
## How to Contribute
## Getting Started
1. **Fork the Repo**: Fork the repository and clone your copy.
1. **Create a Branch**: Create a new branch for your feature or fix.
1. **Test Your Changes**: Ensure tests pass locally and include new tests when necessary to ensure 100& test coverage.
1. **Format Your Code**: Run `make format` to ensure code is formatted appropriately.
4. **Submit a PR**: Submit a pull request with a detailed description of your changes.
### Development Environment
Thank You!
1. **Clone the Repository**:
```bash
git clone https://github.com/basicmachines-co/basic-memory.git
cd basic-memory
```
2. **Install Dependencies**:
```bash
# Using just (recommended)
just install
# Or using uv
uv install -e ".[dev]"
# Or using pip
pip install -e ".[dev]"
```
> **Note**: Basic Memory uses [just](https://just.systems) as a modern command runner. Install with `brew install just` or `cargo install just`.
3. **Activate the Virtual Environment**
```bash
source .venv/bin/activate
```
4. **Run the Tests**:
```bash
# Run all tests
just test
# or
uv run pytest -p pytest_mock -v
# Run a specific test
pytest tests/path/to/test_file.py::test_function_name
```
### Development Workflow
1. **Fork the Repo**: Fork the repository on GitHub and clone your copy.
2. **Create a Branch**: Create a new branch for your feature or fix.
```bash
git checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-you-are-fixing
```
3. **Make Your Changes**: Implement your changes with appropriate test coverage.
4. **Check Code Quality**:
```bash
# Run all checks at once
just check
# Or run individual checks
just lint # Run linting
just format # Format code
just type-check # Type checking
```
5. **Test Your Changes**: Ensure all tests pass locally and maintain 100% test coverage.
```bash
just test
```
6. **Submit a PR**: Submit a pull request with a detailed description of your changes.
## LLM-Assisted Development
This project is designed for collaborative development between humans and LLMs (Large Language Models):
1. **CLAUDE.md**: The repository includes a `CLAUDE.md` file that serves as a project guide for both humans and LLMs.
This file contains:
- Key project information and architectural overview
- Development commands and workflows
- Code style guidelines
- Documentation standards
2. **AI-Human Collaborative Workflow**:
- We encourage using LLMs like Claude for code generation, reviews, and documentation
- When possible, save context in markdown files that can be referenced later
- This enables seamless knowledge transfer between different development sessions
- Claude can help with implementation details while you focus on architecture and design
3. **Adding to CLAUDE.md**:
- If you discover useful project information or common commands, consider adding them to CLAUDE.md
- This helps all contributors (human and AI) maintain consistent knowledge of the project
## Pull Request Process
1. **Create a Pull Request**: Open a PR against the `main` branch with a clear title and description.
2. **Sign the Developer Certificate of Origin (DCO)**: All contributions require signing our DCO, which certifies that
you have the right to submit your contributions. This will be automatically checked by our CLA assistant when you
create a PR.
3. **PR Description**: Include:
- What the PR changes
- Why the change is needed
- How you tested the changes
- Any related issues (use "Fixes #123" to automatically close issues)
4. **Code Review**: Wait for code review and address any feedback.
5. **CI Checks**: Ensure all CI checks pass.
6. **Merge**: Once approved, a maintainer will merge your PR.
## Developer Certificate of Origin
By contributing to this project, you agree to the [Developer Certificate of Origin (DCO)](CLA.md). This means you
certify that:
- You have the right to submit your contributions
- You're not knowingly submitting code with patent or copyright issues
- Your contributions are provided under the project's license (AGPL-3.0)
This is a lightweight alternative to a Contributor License Agreement and helps ensure that all contributions can be
properly incorporated into the project and potentially used in commercial applications.
### Signing Your Commits
Sign your commit:
**Using the `-s` or `--signoff` flag**:
```bash
git commit -s -m "Your commit message"
```
This adds a `Signed-off-by` line to your commit message, certifying that you adhere to the DCO.
The sign-off certifies that you have the right to submit your contribution under the project's license and verifies your
agreement to the DCO.
## Code Style Guidelines
- **Python Version**: Python 3.12+ with full type annotations
- **Line Length**: 100 characters maximum
- **Formatting**: Use ruff for consistent styling
- **Import Order**: Standard lib, third-party, local imports
- **Naming**: Use snake_case for functions/variables, PascalCase for classes
- **Documentation**: Add docstrings to public functions, classes, and methods
- **Type Annotations**: Use type hints for all functions and methods
## Testing Guidelines
- **Coverage Target**: We aim for 100% test coverage for all code
- **Test Framework**: Use pytest for unit and integration tests
- **Mocking**: Use pytest-mock for mocking dependencies only when necessary
- **Edge Cases**: Test both normal operation and edge cases
- **Database Testing**: Use in-memory SQLite for testing database operations
- **Fixtures**: Use async pytest fixtures for setup and teardown
## Release Process
Basic Memory uses automatic versioning based on git tags with `uv-dynamic-versioning`. Here's how releases work:
### Version Management
- **Development versions**: Automatically generated from git commits (e.g., `0.12.4.dev26+468a22f`)
- **Beta releases**: Created by tagging with beta suffixes (e.g., `git tag v0.13.0b1`)
- **Stable releases**: Created by tagging with version numbers (e.g., `git tag v0.13.0`)
### Release Workflows
#### Development Builds
- Automatically published to PyPI on every commit to `main`
- Version format: `0.12.4.dev26+468a22f` (base version + dev + commit count + hash)
- Users install with: `pip install basic-memory --pre --force-reinstall`
#### Beta Releases
1. Create and push a beta tag: `git tag v0.13.0b1 && git push origin v0.13.0b1`
2. GitHub Actions automatically builds and publishes to PyPI
3. Users install with: `pip install basic-memory --pre`
#### Stable Releases
1. Create and push a version tag: `git tag v0.13.0 && git push origin v0.13.0`
2. GitHub Actions automatically:
- Builds the package with version `0.13.0`
- Creates GitHub release with auto-generated notes
- Publishes to PyPI
3. Users install with: `pip install basic-memory`
### For Contributors
- No manual version bumping required
- Versions are automatically derived from git tags
- Focus on code changes, not version management
## Creating Issues
If you're planning to work on something, please create an issue first to discuss the approach. Include:
- A clear title and description
- Steps to reproduce if reporting a bug
- Expected behavior vs. actual behavior
- Any relevant logs or screenshots
- Your proposed solution, if you have one
## Code of Conduct
All contributors must follow the [Code of Conduct](CODE_OF_CONDUCT.md).
## Thank You!
Your contributions help make Basic Memory better. We appreciate your time and effort!
+45
View File
@@ -0,0 +1,45 @@
FROM python:3.12-slim-bookworm
# Build arguments for user ID and group ID (defaults to 1000)
ARG UID=1000
ARG GID=1000
# Copy uv from official image
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# Set environment variables
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# Create a group and user with the provided UID/GID
# Check if the GID already exists, if not create appgroup
RUN (getent group ${GID} || groupadd --gid ${GID} appgroup) && \
useradd --uid ${UID} --gid ${GID} --create-home --shell /bin/bash appuser
# Copy the project into the image
ADD . /app
# Sync the project into a new environment, asserting the lockfile is up to date
WORKDIR /app
RUN uv sync --locked
# Create necessary directories and set ownership
RUN mkdir -p /app/data /app/.basic-memory && \
chown -R appuser:${GID} /app
# Set default data directory and add venv to PATH
ENV BASIC_MEMORY_HOME=/app/data \
PATH="/app/.venv/bin:$PATH"
# Switch to the non-root user
USER appuser
# Expose port
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD basic-memory --version || exit 1
# Use the basic-memory entrypoint to run the MCP server with default SSE transport
CMD ["basic-memory", "mcp", "--transport", "sse", "--host", "0.0.0.0", "--port", "8000"]
+250
View File
@@ -0,0 +1,250 @@
# Legal File Inventory Guide
## Overview
This guide documents the comprehensive file inventory script created for Basic Memory's legal documentation needs, including copyright assignments and company agreement exhibits.
## Repository Analysis Summary
### Repository Structure
- **Primary Language**: Python (3,958 files)
- **License**: GNU Affero General Public License v3.0
- **Total Contributors**: 12 identified contributors
- **Main Contributors**:
- `phernandez@basicmachines.co` / `paul@basicmachines.co` (Paul Hernandez) - 700+ commits
- `groksrc@gmail.com` / `groksrc@users.noreply.github.com` (Drew Cain) - 18+ commits
- Various AI bots and automated systems
### File Type Distribution
Based on the analysis, the repository contains:
| Extension | Count | Purpose |
|-----------|-------|---------|
| `.py` | 3,958 | Python source code |
| `.pyi` | 4,536 | Python type stubs (dependencies) |
| `.pyc` | 1,435 | Compiled Python (excluded from inventory) |
| `.md` | 34 | Documentation files |
| `.toml` | 179 | Configuration files |
| `.html` | 119 | Coverage reports and documentation |
| `.txt` | 127 | Various text files |
### Contributors by Email Domain
**Basic Machines Contributors:**
- `phernandez@basicmachines.co` - 547 commits (Primary maintainer)
- `paul@basicmachines.co` / `paulmh@gmail.com` - 170 commits (Paul Hernandez)
- `claude@basicmachines.co` - 3 commits (AI assistant)
**External Contributors:**
- `groksrc@gmail.com` / `groksrc@users.noreply.github.com` - 18 commits (Drew Cain)
- Various one-time contributors (1-2 commits each)
**Automated Systems:**
- GitHub Actions, semantic-release, and other bots
## Legal Inventory Script Features
### What It Includes
**Source Files:**
- All Python source code (`.py` files)
- Configuration files (`.toml`, `.yaml`, `.json`, etc.)
- Documentation (`.md`, `.rst`, `.txt`)
- Build and deployment scripts
- Database migrations and SQL files
- Legal and license files
**Metadata for Each File:**
- File path, size, and creation/modification dates
- Git history (creation date, last modified, commit count)
- Contributors and their line contributions
- Primary author identification
- File categorization
- SHA-256 hash for integrity verification
### What It Excludes
**Generated/Build Artifacts:**
- `__pycache__/` and `.pyc` files
- Build directories (`build/`, `dist/`, `htmlcov/`)
- Coverage reports and cache files
**Dependencies:**
- Virtual environment files (`.venv/`, `venv/`)
- Third-party packages (`site-packages/`, `*.dist-info/`)
- Lock files (`uv.lock`, `package-lock.json`)
**IDE/Editor Files:**
- `.idea/`, `.vscode/`, `.DS_Store`
- Temporary and swap files
**Version Control:**
- `.git/` directory contents
- Git configuration files
## Usage Instructions
### Basic Usage
```bash
# Generate CSV inventory (default)
python3 legal_file_inventory.py
# Generate Markdown report
python3 legal_file_inventory.py --format markdown --output legal_report.md
# Generate JSON with full metadata
python3 legal_file_inventory.py --format json --output legal_data.json
# Specify different repository path
python3 legal_file_inventory.py --repo-path /path/to/repo --output inventory.csv
```
### Command Line Options
- `--output`, `-o`: Output file path (default: `basic_memory_legal_inventory.csv`)
- `--format`, `-f`: Output format - `csv`, `json`, or `markdown` (default: `csv`)
- `--repo-path`, `-r`: Repository path (default: current directory)
### Output Formats
**CSV Format:**
- Suitable for spreadsheet applications
- Contains all metadata fields
- Contributors stored as JSON string in separate column
**JSON Format:**
- Complete structured data
- Includes summary statistics and detailed file information
- Best for programmatic processing
**Markdown Format:**
- Human-readable report
- Summary statistics and contributor rankings
- Detailed table of all files
## Legal Documentation Applications
### Copyright Assignment Use Cases
1. **Contributor Identification**: The script identifies all contributors to each file based on git blame analysis
2. **Primary Author Recognition**: Determines the primary author of each file (contributor with most lines)
3. **Contribution Metrics**: Provides line counts and commit counts per contributor
4. **File Categorization**: Groups files by purpose (source code, documentation, configuration, etc.)
### Company Agreement Exhibits
The inventory provides comprehensive documentation of:
1. **Intellectual Property Scope**: All source code files and their origins
2. **Contributor Tracking**: Complete list of all individuals who have contributed code
3. **File Integrity**: SHA-256 hashes for verification of file contents
4. **Historical Documentation**: Git creation dates and modification history
### Due Diligence Documentation
The script generates data suitable for:
1. **Legal Review**: Comprehensive file listing with contributor information
2. **IP Audit**: Identification of all copyright holders
3. **License Compliance**: Verification of file ownership and licensing
4. **Asset Documentation**: Complete inventory of company code assets
## Integration with Legal Processes
### Recommended Workflow
1. **Generate Inventory**: Run the script to create current file inventory
2. **Legal Review**: Have legal counsel review the contributor list and file categorization
3. **Copyright Assignment**: Use contributor data to ensure proper copyright assignments
4. **Document Attachment**: Include inventory as exhibit in company agreements
5. **Regular Updates**: Re-run inventory for significant releases or legal milestones
### Key Legal Considerations
**AGPL-3.0 License:**
- All files are under AGPL-3.0 unless otherwise specified
- Contributors retain copyright but license under AGPL-3.0 terms
- Company needs proper copyright assignments for proprietary licensing
**Contributor Rights:**
- External contributors may retain rights to their contributions
- Proper contributor license agreements (CLAs) should be in place
- AI-generated content may have different legal status
**File Categories for Legal Review:**
- **Source Code**: Core IP, requires copyright assignment
- **Configuration**: May contain proprietary deployment information
- **Documentation**: Usually less sensitive but may contain trade secrets
- **Legal/License**: Critical for compliance verification
## Maintenance and Updates
### When to Regenerate Inventory
- Before major releases
- During legal document preparation
- After significant contributor additions
- For annual compliance reviews
- During acquisition or investment processes
### Validation Steps
1. Verify contributor email mapping is accurate
2. Check that file categorization makes sense
3. Ensure excluded files are appropriate
4. Review contributor counts against expectations
5. Validate file hashes for integrity
## Technical Implementation Notes
### Git Integration
- Uses `git blame --line-porcelain` for detailed contributor analysis
- Tracks file history with `git log --follow`
- Handles renamed files and complex git histories
### Performance Considerations
- Scans repository incrementally to handle large codebases
- Excludes binary dependencies to reduce processing time
- Caches git operations where possible
### Error Handling
- Gracefully handles files not in git
- Continues processing if individual files fail
- Provides detailed error reporting
## Security and Privacy
### Data Sensitivity
- Contains contributor names and email addresses
- May reveal internal file structure and organization
- Should be treated as confidential legal documentation
### Recommended Handling
- Limit access to legal and executive team
- Store in secure, access-controlled systems
- Consider redacting contributor emails for external sharing
- Regular cleanup of generated inventory files
## Troubleshooting
### Common Issues
**Git Not Available:**
- Ensure git is installed and repository is initialized
- Check that the script is run from within the repository
**Permission Errors:**
- Ensure read access to all repository files
- Check write permissions for output directory
**Large Repository Performance:**
- Consider running on subsets of files for very large repositories
- Use `--repo-path` to target specific subdirectories
**Contributor Mapping Issues:**
- Git usernames may not match real identities
- Consider post-processing to normalize contributor names
- Review .mailmap files for git identity consolidation
This comprehensive legal file inventory system provides the foundation for proper intellectual property documentation and legal compliance for the Basic Memory project.
-42
View File
@@ -1,42 +0,0 @@
.PHONY: install test lint clean format type-check installer-mac installer-win
install:
pip install -e ".[dev]"
test:
pytest -p pytest_mock -v
lint:
ruff check . --fix
type-check:
uv run pyright
clean:
find . -type f -name '*.pyc' -delete
find . -type d -name '__pycache__' -exec rm -r {} +
rm -rf installer/build/
rm -rf installer/dist/
rm -f rw.*.dmg
rm -rf dist
rm -rf installer/build
rm -rf installer/dist
rm -f .coverage.*
format:
uv run ruff format .
# run inspector tool
run-dev:
uv run mcp dev src/basic_memory/mcp/main.py
# Build app installer
installer-mac:
cd installer && uv run python setup.py bdist_mac
installer-win:
cd installer && uv run python setup.py bdist_win32
update-deps:
uv lock f--upgrade
+360 -222
View File
@@ -1,258 +1,396 @@
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![PyPI version](https://badge.fury.io/py/basic-memory.svg)](https://badge.fury.io/py/basic-memory)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![Tests](https://github.com/basicmachines-co/basic-memory/workflows/Tests/badge.svg)](https://github.com/basicmachines-co/basic-memory/actions)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
![](https://badge.mcpx.dev?type=server 'MCP Server')
![](https://badge.mcpx.dev?type=dev 'MCP Dev')
[![smithery badge](https://smithery.ai/badge/@basicmachines-co/basic-memory)](https://smithery.ai/server/@basicmachines-co/basic-memory)
# Basic Memory
Basic Memory lets you build persistent knowledge through natural conversations with Large Language Models (LLMs) like
Claude, while keeping everything in simple markdown files on your computer. It uses the Model Context Protocol (MCP) to
Claude, while keeping everything in simple Markdown files on your computer. It uses the Model Context Protocol (MCP) to
enable any compatible LLM to read and write to your local knowledge base.
## What is Basic Memory?
- Website: https://basicmachines.co
- Documentation: https://memory.basicmachines.co
Most people use LLMs like calculators - paste in some text, expect to get an answer back, repeat. Each conversation
starts fresh,
and any knowledge or context is lost. Some try to work around this by:
## Pick up your conversation right where you left off
- Saving chat histories (but they're hard to reference)
- Copying and pasting previous conversations (messy and repetitive)
- Using RAG systems to query documents (complex and often cloud-based)
- AI assistants can load context from local files in a new conversation
- Notes are saved locally as Markdown files in real time
- No project knowledge or special prompting required
Basic Memory takes a different approach by letting both humans and LLMs read and write knowledge naturally using
standard markdown files. This means:
https://github.com/user-attachments/assets/a55d8238-8dd0-454a-be4c-8860dbbd0ddc
- Your knowledge stays in files you control
- Both you and the LLM can read and write notes
- Context persists across conversations
- Context stays local and user controlled
## How It Works in Practice
Let's say you're working on a new project and want to capture design decisions. Here's how it works:
1. Start by chatting normally:
```markdown
We need to design a new auth system, some key features:
- local first, don't delegate users to third party system
- support multiple platforms via jwt
- want to keep it simple but secure
```
... continue conversation.
2. Ask Claude to help structure this knowledge:
```
"Lets write a note about the auth system design."
```
Claude creates a new markdown file on your system (which you can see instantly in Obsidian or your editor):
```markdown
---
title: Auth System Design
permalink: auth-system-design
tags
- design
- auth
---
# Auth System Design
## Observations
- [requirement] Local-first authentication without third party delegation
- [tech] JWT-based auth for cross-platform support
- [principle] Balance simplicity with security
## Relations
- implements [[Security Requirements]]
- relates_to [[Platform Support]]
- referenced_by [[JWT Implementation]]
```
The note embeds semantic content (Observations) and links to other topics (Relations) via simple markdown formatting.
3. You can edit this file directly in your editor in real time:
```markdown
# Auth System Design
## Observations
- [requirement] Local-first authentication without third party delegation
- [tech] JWT-based auth for cross-platform support
- [principle] Balance simplicity with security
- [decision] Will use bcrypt for password hashing # Added by you
## Relations
- implements [[Security Requirements]]
- relates_to [[Platform Support]]
- referenced_by [[JWT Implementation]]
- blocks [[User Service]] # Added by you
```
4. In a new chat with Claude, you can reference this knowledge:
```
"Claude, look at memory://auth-system-design for context about our auth system"
```
Claude can now build rich context from the knowledge graph. For example:
```
Following relation 'implements [[Security Requirements]]':
- Found authentication best practices
- OWASP guidelines for JWT
- Rate limiting requirements
Following relation 'relates_to [[Platform Support]]':
- Mobile auth requirements
- Browser security considerations
- JWT storage strategies
```
Each related document can lead to more context, building a rich semantic understanding of your knowledge base. All of
this context comes from standard markdown files that both humans and LLMs can read and write.
Everything stays in local markdown files that you can:
- Edit in any text editor
- Version via git
- Back up normally
- Share when you want to
## Technical Implementation
Under the hood, Basic Memory:
1. Stores everything in markdown files
2. Uses a SQLite database just for searching and indexing
3. Extracts semantic meaning from simple markdown patterns
4. Maintains a local knowledge graph from file content
The file format is just markdown with some simple markup:
Frontmatter
- title
- type
- permalink
- optional metadata
Observations
- facts about a topic
```markdown
- [category] content #tag (optional context)
```
Relations
- links to other topics
```markdown
- relation_type [[WikiLink]] (optional context)
```
Example:
```markdown
---
title: Note tile
type: note
permalink: unique/stable/id # Added automatically
tags
- tag1
- tag2
---
# Note Title
Regular markdown content...
## Observations
- [category] Structured knowledge #tag (optional context)
- [idea] Another observation
## Relations
- links_to [[Other Note]]
- implements [[Some Spec]]
```
Basic Memory will parse the markdown and derive the semantic relationships in the content. When you run
`basic-memory sync`:
1. New and changed files are detected
2. Markdown patterns become semantic knowledge:
- `[tech]` becomes a categorized observation
- `[[WikiLink]]` creates a relation in the knowledge graph
- Tags and metadata are indexed for search
3. A SQLite database maintains these relationships for fast querying
4. Claude and other MCP-compatible LLMs can access this knowledge via memory:// URLs
This creates a two-way flow where:
- Humans write and edit markdown files
- LLMs read and write through the MCP protocol
- Sync keeps everything consistent
- All knowledge stays in local files.
## Using with Claude
Basic Memory works with the Claude desktop app (https://claude.ai/):
1. Install Basic Memory locally:
## Quick Start
```bash
# Install with uv (recommended)
uv tool install basic-memory
# Configure Claude Desktop (edit ~/Library/Application Support/Claude/claude_desktop_config.json)
# Add this to your config:
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": [
"basic-memory"
"basic-memory",
"mcp"
]
}
}
}
# Now in Claude Desktop, you can:
# - Write notes with "Create a note about coffee brewing methods"
# - Read notes with "What do I know about pour over coffee?"
# - Search with "Find information about Ethiopian beans"
```
You can view shared context via files in `~/basic-memory` (default directory location).
### Alternative Installation via Smithery
You can use [Smithery](https://smithery.ai/server/@basicmachines-co/basic-memory) to automatically configure Basic
Memory for Claude Desktop:
```bash
npx -y @smithery/cli install @basicmachines-co/basic-memory --client claude
```
This installs and configures Basic Memory without requiring manual edits to the Claude Desktop configuration file. The
Smithery server hosts the MCP server component, while your data remains stored locally as Markdown files.
### Glama.ai
<a href="https://glama.ai/mcp/servers/o90kttu9ym">
<img width="380" height="200" src="https://glama.ai/mcp/servers/o90kttu9ym/badge" alt="basic-memory MCP server" />
</a>
## Why Basic Memory?
Most LLM interactions are ephemeral - you ask a question, get an answer, and everything is forgotten. Each conversation
starts fresh, without the context or knowledge from previous ones. Current workarounds have limitations:
- Chat histories capture conversations but aren't structured knowledge
- RAG systems can query documents but don't let LLMs write back
- Vector databases require complex setups and often live in the cloud
- Knowledge graphs typically need specialized tools to maintain
Basic Memory addresses these problems with a simple approach: structured Markdown files that both humans and LLMs can
read
and write to. The key advantages:
- **Local-first:** All knowledge stays in files you control
- **Bi-directional:** Both you and the LLM read and write to the same files
- **Structured yet simple:** Uses familiar Markdown with semantic patterns
- **Traversable knowledge graph:** LLMs can follow links between topics
- **Standard formats:** Works with existing editors like Obsidian
- **Lightweight infrastructure:** Just local files indexed in a local SQLite database
With Basic Memory, you can:
- Have conversations that build on previous knowledge
- Create structured notes during natural conversations
- Have conversations with LLMs that remember what you've discussed before
- Navigate your knowledge graph semantically
- Keep everything local and under your control
- Use familiar tools like Obsidian to view and edit notes
- Build a personal knowledge base that grows over time
## How It Works in Practice
Let's say you're exploring coffee brewing methods and want to capture your knowledge. Here's how it works:
1. Start by chatting normally:
```
I've been experimenting with different coffee brewing methods. Key things I've learned:
- Pour over gives more clarity in flavor than French press
- Water temperature is critical - around 205°F seems best
- Freshly ground beans make a huge difference
```
... continue conversation.
2. Ask the LLM to help structure this knowledge:
```
"Let's write a note about coffee brewing methods."
```
LLM creates a new Markdown file on your system (which you can see instantly in Obsidian or your editor):
```markdown
---
title: Coffee Brewing Methods
permalink: coffee-brewing-methods
tags:
- coffee
- brewing
---
# Coffee Brewing Methods
## Observations
- [method] Pour over provides more clarity and highlights subtle flavors
- [technique] Water temperature at 205°F (96°C) extracts optimal compounds
- [principle] Freshly ground beans preserve aromatics and flavor
## Relations
- relates_to [[Coffee Bean Origins]]
- requires [[Proper Grinding Technique]]
- affects [[Flavor Extraction]]
```
The note embeds semantic content and links to other topics via simple Markdown formatting.
3. You see this file on your computer in real time in the current project directory (default `~/$HOME/basic-memory`).
- Realtime sync can be enabled via running `basic-memory sync --watch`
4. In a chat with the LLM, you can reference a topic:
```
Look at `coffee-brewing-methods` for context about pour over coffee
```
The LLM can now build rich context from the knowledge graph. For example:
```
Following relation 'relates_to [[Coffee Bean Origins]]':
- Found information about Ethiopian Yirgacheffe
- Notes on Colombian beans' nutty profile
- Altitude effects on bean characteristics
Following relation 'requires [[Proper Grinding Technique]]':
- Burr vs. blade grinder comparisons
- Grind size recommendations for different methods
- Impact of consistent particle size on extraction
```
Each related document can lead to more context, building a rich semantic understanding of your knowledge base.
This creates a two-way flow where:
- Humans write and edit Markdown files
- LLMs read and write through the MCP protocol
- Sync keeps everything consistent
- All knowledge stays in local files.
## Technical Implementation
Under the hood, Basic Memory:
1. Stores everything in Markdown files
2. Uses a SQLite database for searching and indexing
3. Extracts semantic meaning from simple Markdown patterns
- Files become `Entity` objects
- Each `Entity` can have `Observations`, or facts associated with it
- `Relations` connect entities together to form the knowledge graph
4. Maintains the local knowledge graph derived from the files
5. Provides bidirectional synchronization between files and the knowledge graph
6. Implements the Model Context Protocol (MCP) for AI integration
7. Exposes tools that let AI assistants traverse and manipulate the knowledge graph
8. Uses memory:// URLs to reference entities across tools and conversations
The file format is just Markdown with some simple markup:
Each Markdown file has:
### Frontmatter
```markdown
title: <Entity title>
type: <The type of Entity> (e.g. note)
permalink: <a uri slug>
- <optional metadata> (such as tags)
```
### Observations
Observations are facts about a topic.
They can be added by creating a Markdown list with a special format that can reference a `category`, `tags` using a
"#" character, and an optional `context`.
Observation Markdown format:
```markdown
- [category] content #tag (optional context)
```
Examples of observations:
```markdown
- [method] Pour over extracts more floral notes than French press
- [tip] Grind size should be medium-fine for pour over #brewing
- [preference] Ethiopian beans have bright, fruity flavors (especially from Yirgacheffe)
- [fact] Lighter roasts generally contain more caffeine than dark roasts
- [experiment] Tried 1:15 coffee-to-water ratio with good results
- [resource] James Hoffman's V60 technique on YouTube is excellent
- [question] Does water temperature affect extraction of different compounds differently?
- [note] My favorite local shop uses a 30-second bloom time
```
### Relations
Relations are links to other topics. They define how entities connect in the knowledge graph.
Markdown format:
```markdown
- relation_type [[WikiLink]] (optional context)
```
Examples of relations:
```markdown
- pairs_well_with [[Chocolate Desserts]]
- grown_in [[Ethiopia]]
- contrasts_with [[Tea Brewing Methods]]
- requires [[Burr Grinder]]
- improves_with [[Fresh Beans]]
- relates_to [[Morning Routine]]
- inspired_by [[Japanese Coffee Culture]]
- documented_in [[Coffee Journal]]
```
## Using with VS Code
Add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing `Ctrl + Shift + P` and typing `Preferences: Open User Settings (JSON)`.
```json
{
"mcp": {
"servers": {
"basic-memory": {
"command": "uvx",
"args": ["basic-memory", "mcp"]
}
}
}
}
```
2. Add to Claude Desktop:
Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace. This will allow you to share the configuration with others.
```
Basic Memory is available with these tools:
- write_note() for creating/updating notes
- read_note() for loading notes
- build_context() to load notes via memory:// URLs
- recent_activity() to find recently updated information
- search() to search infomation in the knowledge base
```json
{
"servers": {
"basic-memory": {
"command": "uvx",
"args": ["basic-memory", "mcp"]
}
}
}
```
3. Install via uv
You can use Basic Memory with VS Code to easily retrieve and store information while coding.
## Using with Claude Desktop
Basic Memory is built using the MCP (Model Context Protocol) and works with the Claude desktop app (https://claude.ai/):
1. Configure Claude Desktop to use Basic Memory:
Edit your MCP configuration file (usually located at `~/Library/Application Support/Claude/claude_desktop_config.json`
for OS X):
```json
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": [
"basic-memory",
"mcp"
]
}
}
}
```
If you want to use a specific project (see [Multiple Projects](#multiple-projects) below), update your Claude Desktop
config:
```json
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": [
"basic-memory",
"mcp",
"--project",
"your-project-name"
]
}
}
}
```
2. Sync your knowledge:
```bash
uv add basic-memory
# sync local knowledge updates
# One-time sync of local knowledge updates
basic-memory sync
# run realtime sync process
# Run realtime sync process (recommended)
basic-memory sync --watch
```
## Design Philosophy
3. In Claude Desktop, the LLM can now use these tools:
Basic Memory is built on some key ideas:
```
write_note(title, content, folder, tags) - Create or update notes
read_note(identifier, page, page_size) - Read notes by title or permalink
build_context(url, depth, timeframe) - Navigate knowledge graph via memory:// URLs
search(query, page, page_size) - Search across your knowledge base
recent_activity(type, depth, timeframe) - Find recently updated information
canvas(nodes, edges, title, folder) - Generate knowledge visualizations
```
- Your knowledge should stay in files you control
- Both humans and AI should use natural formats
- Simple text patterns can capture rich meaning
- Local-first doesn't mean feature-poor
5. Example prompts to try:
```
"Create a note about our project architecture decisions"
"Find information about JWT authentication in my notes"
"Create a canvas visualization of my project components"
"Read my notes on the authentication system"
"What have I been working on in the past week?"
```
## Futher info
See the [Documentation](https://memory.basicmachines.co/) for more info, including:
- [Complete User Guide](https://memory.basicmachines.co/docs/user-guide)
- [CLI tools](https://memory.basicmachines.co/docs/cli-reference)
- [Managing multiple Projects](https://memory.basicmachines.co/docs/cli-reference#project)
- [Importing data from OpenAI/Claude Projects](https://memory.basicmachines.co/docs/cli-reference#import)
## License
AGPL-3.0
AGPL-3.0
Contributions are welcome. See the [Contributing](CONTRIBUTING.md) guide for info about setting up the project locally
and submitting PRs.
## Star History
<a href="https://www.star-history.com/#basicmachines-co/basic-memory&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=basicmachines-co/basic-memory&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=basicmachines-co/basic-memory&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=basicmachines-co/basic-memory&type=Date" />
</picture>
</a>
Built with ♥️ by Basic Machines
+13
View File
@@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 0.x.x | :white_check_mark: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
If you find a vulnerability, please contact hello@basicmachines.co
-1419
View File
File diff suppressed because it is too large Load Diff
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""
Create CSV exhibits for individual contributors
"""
import json
import csv
from pathlib import Path
def create_csv_exhibits():
"""Create CSV Exhibit A files for each contributor."""
# Read the JSON inventory
inventory_files = list(Path("legal_inventory_main").glob("*.json"))
if not inventory_files:
print("Error: No JSON inventory files found")
return
inventory_file = inventory_files[0] # Use the most recent one
print(f"Using inventory file: {inventory_file}")
with open(inventory_file, 'r') as f:
data = json.load(f)
files = data['files']
# Create output directory
output_dir = Path("legal_exhibits")
output_dir.mkdir(exist_ok=True)
# Contributors we need exhibits for
target_contributors = {
'jope-bm': 'joe_exhibit_a.csv',
'Drew Cain': 'drew_cain_exhibit_a.csv'
}
print("Creating CSV exhibits for contributors...")
for contributor_key, filename in target_contributors.items():
# Find files for this contributor
contributor_files = []
for file_info in files:
# Check if this contributor is listed in the file's contributors
for contrib in file_info.get('contributors', []):
if contributor_key in contrib['name']:
contributor_files.append(file_info)
break
if not contributor_files:
print(f"No files found for {contributor_key}")
continue
# Sort files by path
contributor_files.sort(key=lambda x: x['path'])
# Create CSV file
csv_file = output_dir / filename
with open(csv_file, 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = [
'file_path', 'file_name', 'category', 'size_bytes',
'modified_date', 'primary_author', 'all_contributors', 'sha256_hash'
]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for file_info in contributor_files:
contributors_list = '; '.join([c['name'] for c in file_info['contributors']])
writer.writerow({
'file_path': file_info['path'],
'file_name': file_info['name'],
'category': file_info['category'],
'size_bytes': file_info['size_bytes'],
'modified_date': file_info['modified_time'][:10],
'primary_author': file_info['primary_author'],
'all_contributors': contributors_list,
'sha256_hash': file_info['sha256_hash']
})
print(f"Created CSV exhibit for {contributor_key}: {csv_file}")
print(f" - {len(contributor_files)} files")
print(f" - {sum(f['size_bytes'] for f in contributor_files):,} bytes")
if __name__ == '__main__':
create_csv_exhibits()
+208
View File
@@ -0,0 +1,208 @@
#!/usr/bin/env python3
"""
Create individual Exhibit A files for copyright assignments
"""
import json
from pathlib import Path
from datetime import datetime
def create_individual_exhibits():
"""Create individual Exhibit A files for each contributor."""
# Read the JSON inventory
inventory_file = Path("legal_inventory_main/basic_memory_inventory_20250730_101521.json")
if not inventory_file.exists():
print(f"Error: {inventory_file} not found")
return
with open(inventory_file, 'r') as f:
data = json.load(f)
files = data['files']
# Create output directory
output_dir = Path("legal_exhibits")
output_dir.mkdir(exist_ok=True)
# Contributors we need exhibits for (based on copyright assignments)
target_contributors = {
'jope-bm': 'Joseph "Joe" [Last Name]', # Need to get his full name
'Drew Cain': 'Drew Cain'
}
print("Creating individual contributor exhibits...")
for contributor_key, full_name in target_contributors.items():
# Find files for this contributor
contributor_files = []
for file_info in files:
# Check if this contributor is listed in the file's contributors
for contrib in file_info.get('contributors', []):
if contributor_key in contrib['name']:
contributor_files.append(file_info)
break
if not contributor_files:
print(f"No files found for {contributor_key}")
continue
# Sort files by path
contributor_files.sort(key=lambda x: x['path'])
# Create exhibit markdown
exhibit_content = f"""# Exhibit A - Assigned Works
## Copyright Assignment: {full_name} to Basic Memory LLC
**Date:** [To be filled]
**Assignor:** {full_name}
**Assignee:** Basic Memory LLC
## Summary
- **Total Files:** {len(contributor_files)}
- **Total Size:** {sum(f['size_bytes'] for f in contributor_files):,} bytes
- **Categories:** {', '.join(set(f['category'] for f in contributor_files))}
## Detailed File List
"""
# Group by category
categories = {}
for file_info in contributor_files:
category = file_info['category']
if category not in categories:
categories[category] = []
categories[category].append(file_info)
# Add files by category
for category, category_files in sorted(categories.items()):
exhibit_content += f"### {category.replace('_', ' ').title()}\n\n"
for file_info in category_files:
exhibit_content += f"**{file_info['path']}**\n"
exhibit_content += f"- Size: {file_info['size_bytes']:,} bytes\n"
exhibit_content += f"- Modified: {file_info['modified_time'][:10]}\n"
exhibit_content += f"- Primary Author: {file_info['primary_author']}\n"
# Show all contributors for this file
if len(file_info['contributors']) > 1:
contributors_list = ', '.join([c['name'] for c in file_info['contributors']])
exhibit_content += f"- All Contributors: {contributors_list}\n"
exhibit_content += f"- SHA-256: `{file_info['sha256_hash']}`\n\n"
# Add verification section
exhibit_content += f"""
## Verification
This exhibit lists all files in the Basic Memory repository where {full_name} is identified as a contributor based on git commit history analysis.
**Analysis Date:** {datetime.now().strftime('%Y-%m-%d')}
**Repository State:** Basic Memory main branch
**Method:** Git history analysis via `git log --follow` for each file
## Legal Representation
{full_name} hereby represents and warrants that they are the author of the contributions listed above and have the right to assign copyright in these works to Basic Memory LLC.
---
*This exhibit is attached to and forms part of the Copyright Assignment Agreement between {full_name} and Basic Memory LLC.*
"""
# Write exhibit file
safe_name = contributor_key.replace(' ', '_').replace('-', '_').lower()
exhibit_file = output_dir / f"exhibit_a_{safe_name}.md"
with open(exhibit_file, 'w') as f:
f.write(exhibit_content)
print(f"Created exhibit for {full_name}: {exhibit_file}")
print(f" - {len(contributor_files)} files")
print(f" - {sum(f['size_bytes'] for f in contributor_files):,} bytes")
# Create overall summary exhibit (for Paul's assignment to Basic Machines LLC)
create_overall_summary_exhibit(data, output_dir)
def create_overall_summary_exhibit(data, output_dir):
"""Create overall summary exhibit for Company Agreement."""
files = data['files']
summary = data['summary']
contributors = data['contributors']
summary_content = f"""# Basic Memory Repository - Complete IP Inventory
## For Basic Memory LLC Company Agreement
**Analysis Date:** {summary['scan_date'][:10]}
**Repository:** {summary['repository_path']}
## Executive Summary
- **Total Files:** {summary['total_files']:,}
- **Total Size:** {summary['total_size_bytes']:,} bytes
- **Contributors:** {summary['contributor_count']}
- **Primary Author:** Paul Hernandez ({len(contributors.get('Paul Hernandez', {}).get('files', []))} files)
## File Categories
"""
for category, count in sorted(summary['categories'].items()):
summary_content += f"- **{category.replace('_', ' ').title()}:** {count} files\n"
summary_content += """
## Contributor Summary
"""
for contrib in summary['top_contributors']:
summary_content += f"- **{contrib['name']}** ({contrib['email']}): {contrib['file_count']} files, {contrib['commit_count']} commits\n"
summary_content += """
## Legal Significance
This inventory represents the complete codebase of Basic Memory as licensed from Basic Machines LLC to Basic Memory LLC under the copyright license agreement dated [DATE].
### IP Rights Chain
1. **Paul Hernandez** → Basic Machines LLC (copyright assignment)
2. **Basic Machines LLC** → Basic Memory LLC (15% royalty license)
3. **Co-founders** → Basic Memory LLC (direct copyright assignments)
### Due Diligence Documentation
This comprehensive file inventory serves as:
- **Company Agreement Exhibit:** Original codebase licensed to Basic Memory LLC
- **Acquisition Documentation:** Complete IP inventory for due diligence
- **Copyright Verification:** Establishes chain of title for all repository contents
## Repository Contents by Category
"""
# Add sample files by category (first 10 in each category)
for category in sorted(summary['categories'].keys()):
category_files = [f for f in files if f['category'] == category][:10]
if category_files:
summary_content += f"### {category.replace('_', ' ').title()} (Sample)\n\n"
for file_info in category_files:
summary_content += f"- `{file_info['path']}` ({file_info['size_bytes']:,} bytes)\n"
if len([f for f in files if f['category'] == category]) > 10:
remaining = len([f for f in files if f['category'] == category]) - 10
summary_content += f"- *... and {remaining} more files*\n"
summary_content += "\n"
summary_content += f"""
---
*This inventory was generated automatically from git repository analysis and represents the complete intellectual property foundation of Basic Memory as of {summary['scan_date'][:10]}.*
"""
# Write summary file
summary_file = output_dir / "basic_memory_complete_inventory.md"
with open(summary_file, 'w') as f:
f.write(summary_content)
print(f"Created complete inventory summary: {summary_file}")
if __name__ == '__main__':
create_individual_exhibits()
+83
View File
@@ -0,0 +1,83 @@
# Docker Compose configuration for Basic Memory
# See docs/Docker.md for detailed setup instructions
version: '3.8'
services:
basic-memory:
# Use pre-built image (recommended for most users)
image: ghcr.io/basicmachines-co/basic-memory:latest
# Uncomment to build locally instead:
# build: .
container_name: basic-memory-server
# Volume mounts for knowledge directories and persistent data
volumes:
# Persistent storage for configuration and database
- basic-memory-config:/root/.basic-memory:rw
# Mount your knowledge directory (required)
# Change './knowledge' to your actual Obsidian vault or knowledge directory
- ./knowledge:/app/data:rw
# OPTIONAL: Mount additional knowledge directories for multiple projects
# - ./work-notes:/app/data/work:rw
# - ./personal-notes:/app/data/personal:rw
# You can edit the project config manually in the mounted config volume
# The default project will be configured to use /app/data
environment:
# Project configuration
- BASIC_MEMORY_DEFAULT_PROJECT=main
# Enable real-time file synchronization (recommended for Docker)
- BASIC_MEMORY_SYNC_CHANGES=true
# Logging configuration
- BASIC_MEMORY_LOG_LEVEL=INFO
# Sync delay in milliseconds (adjust for performance vs responsiveness)
- BASIC_MEMORY_SYNC_DELAY=1000
# Port exposure for HTTP transport (only needed if not using STDIO)
ports:
- "8000:8000"
# Command with SSE transport (configurable via environment variables above)
# IMPORTANT: The SSE and streamable-http endpoints are not secured
command: ["basic-memory", "mcp", "--transport", "sse", "--host", "0.0.0.0", "--port", "8000"]
# Container management
restart: unless-stopped
# Health monitoring
healthcheck:
test: ["CMD", "basic-memory", "--version"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# Optional: Resource limits
# deploy:
# resources:
# limits:
# memory: 512M
# cpus: '0.5'
# reservations:
# memory: 256M
# cpus: '0.25'
volumes:
# Named volume for persistent configuration and database
# This ensures your configuration and knowledge graph persist across container restarts
basic-memory-config:
driver: local
# Network configuration (optional)
# networks:
# basic-memory-net:
# driver: bridge
+431
View File
@@ -0,0 +1,431 @@
---
title: AI Assistant Guide
type: note
permalink: docs/ai-assistant-guide
---
> Note: This is an optional document that can be copy/pasted into the project knowledge for an LLM to provide a full description of how it can work with Basic Memory. It is provided as a helpful resource. The tools contain extensive usage description prompts with enable the LLM to understand them.
You can [download](https://github.com/basicmachines-co/basic-memory/blob/main/docs/AI%20Assistant%20Guide.md) the contents of this file from GitHub
# AI Assistant Guide for Basic Memory
This guide helps you, the AI assistant, use Basic Memory tools effectively when working with users. It covers reading, writing, and navigating knowledge through the Model Context Protocol (MCP).
## Quick Reference
**Essential Tools:**
- `write_note()` - Create/update notes (primary tool)
- `read_note()` - Read existing content
- `search_notes()` - Find information
- `edit_note()` - Modify existing notes incrementally (v0.13.0)
- `move_note()` - Organize files with database consistency (v0.13.0)
**Project Management (v0.13.0):**
- `list_projects()` - Show available projects
- `switch_project()` - Change active project
- `get_current_project()` - Current project info
**Key Principles:**
1. **Build connections** - Rich knowledge graphs > isolated notes
2. **Ask permission** - "Would you like me to record this?"
3. **Use exact titles** - For accurate `[[WikiLinks]]`
4. **Leverage v0.13.0** - Edit incrementally, organize proactively, switch projects contextually
## Overview
Basic Memory allows you and users to record context in local Markdown files, building a rich knowledge base through natural conversations. The system automatically creates a semantic knowledge graph from simple text patterns.
- **Local-First**: All data is stored in plain text files on the user's computer
- **Real-Time**: Users see content updates immediately
- **Bi-Directional**: Both you and users can read and edit notes
- **Semantic**: Simple patterns create a structured knowledge graph
- **Persistent**: Knowledge persists across sessions and conversations
## The Importance of the Knowledge Graph
Basic Memory's value comes from connections between notes, not just the notes themselves. When writing notes, your primary goal should be creating a rich, interconnected knowledge graph.
When creating content, focus on:
1. **Increasing Semantic Density**: Add multiple observations and relations to each note
2. **Using Accurate References**: Aim to reference existing entities by their exact titles
3. **Creating Forward References**: Feel free to reference entities that don't exist yet - Basic Memory will resolve these when they're created later
4. **Creating Bidirectional Links**: When appropriate, connect entities from both directions
5. **Using Meaningful Categories**: Add semantic context with appropriate observation categories
6. **Choosing Precise Relations**: Use specific relation types that convey meaning
Remember that a knowledge graph with 10 heavily connected notes is more valuable than 20 isolated notes. Your job is to help build these connections.
## Core Tools Reference
### Essential Content Management
**Writing knowledge** (most important tool):
```
write_note(
title="Search Design",
content="# Search Design\n...",
folder="specs", # Optional
tags=["search", "design"], # v0.13.0: now searchable!
project="work-notes" # v0.13.0: target specific project
)
```
**Reading knowledge:**
```
read_note("Search Design") # By title
read_note("specs/search-design") # By path
read_note("memory://specs/search") # By memory URL
```
**Viewing notes as formatted artifacts (Claude Desktop):**
```
view_note("Search Design") # Creates readable artifact
view_note("specs/search-design") # By permalink
view_note("memory://specs/search") # By memory URL
```
**Incremental editing** (v0.13.0):
```
edit_note(
identifier="Search Design", # Must be EXACT title/permalink (strict matching)
operation="append", # append, prepend, find_replace, replace_section
content="\n## New Section\nContent here..."
)
```
**⚠️ Important:** `edit_note` requires exact identifiers (no fuzzy matching). Use `search_notes()` first if uncertain.
**File organization** (v0.13.0):
```
move_note(
identifier="Old Note", # Must be EXACT title/permalink (strict matching)
destination="archive/old-note.md" # Folders created automatically
)
```
**⚠️ Important:** `move_note` requires exact identifiers (no fuzzy matching). Use `search_notes()` first if uncertain.
### Project Management (v0.13.0)
```
list_projects() # Show available projects
switch_project("work-notes") # Change active project
get_current_project() # Current project info
```
### Search & Discovery
```
search_notes("authentication system") # v0.13.0: includes frontmatter tags
build_context("memory://specs/search") # Follow knowledge graph connections
recent_activity(timeframe="1 week") # Check what's been updated
```
## memory:// URLs Explained
Basic Memory uses a special URL format to reference entities in the knowledge graph:
- `memory://title` - Reference by title
- `memory://folder/title` - Reference by folder and title
- `memory://permalink` - Reference by permalink
- `memory://path/relation_type/*` - Follow all relations of a specific type
- `memory://path/*/target` - Find all entities with relations to target
## Semantic Markdown Format
Knowledge is encoded in standard markdown using simple patterns:
**Observations** - Facts about an entity:
```markdown
- [category] This is an observation #tag1 #tag2 (optional context)
```
**Relations** - Links between entities:
```markdown
- relation_type [[Target Entity]] (optional context)
```
**Common Categories & Relation Types:**
- Categories: `[idea]`, `[decision]`, `[question]`, `[fact]`, `[requirement]`, `[technique]`, `[recipe]`, `[preference]`
- Relations: `relates_to`, `implements`, `requires`, `extends`, `part_of`, `pairs_with`, `inspired_by`, `originated_from`
## When to Record Context
**Always consider recording context when**:
1. Users make decisions or reach conclusions
2. Important information emerges during conversation
3. Multiple related topics are discussed
4. The conversation contains information that might be useful later
5. Plans, tasks, or action items are mentioned
**Protocol for recording context**:
1. Identify valuable information in the conversation
2. Ask the user: "Would you like me to record our discussion about [topic] in Basic Memory?"
3. If they agree, use `write_note` to capture the information
4. If they decline, continue without recording
5. Let the user know when information has been recorded: "I've saved our discussion about [topic] to Basic Memory."
## Understanding User Interactions
Users will interact with Basic Memory in patterns like:
1. **Creating knowledge**:
```
Human: "Let's write up what we discussed about search."
You: I'll create a note capturing our discussion about the search functionality.
[Use write_note() to record the conversation details]
```
2. **Referencing existing knowledge**:
```
Human: "Take a look at memory://specs/search"
You: I'll examine that information.
[Use build_context() to gather related information]
[Then read_note() to access specific content]
```
3. **Finding information**:
```
Human: "What were our decisions about auth?"
You: Let me find that information for you.
[Use search_notes() to find relevant notes]
[Then build_context() to understand connections]
```
4. **Editing existing notes (v0.13.0)**:
```
Human: "Add a section about deployment to my API documentation"
You: I'll add that section to your existing documentation.
[Use edit_note() with operation="append" to add new content]
```
5. **Project management (v0.13.0)**:
```
Human: "Switch to my work project and show recent activity"
You: I'll switch to your work project and check what's been updated recently.
[Use switch_project() then recent_activity()]
```
6. **File organization (v0.13.0)**:
```
Human: "Move my old meeting notes to the archive folder"
You: I'll organize those notes for you.
[Use move_note() to relocate files with database consistency]
```
## Key Things to Remember
1. **Files are Truth**
- All knowledge lives in local files on the user's computer
- Users can edit files outside your interaction
- Changes need to be synced by the user (usually automatic)
- Always verify information is current with `recent_activity()`
2. **Building Context Effectively**
- Start with specific entities
- Follow meaningful relations
- Check recent changes
- Build context incrementally
- Combine related information
3. **Writing Knowledge Wisely**
- Same title+folder overwrites existing notes
- Structure with clear headings and semantic markup
- Use tags for searchability (v0.13.0: frontmatter tags indexed)
- Keep files organized in logical folders
4. **Leverage v0.13.0 Features**
- **Edit incrementally**: Use `edit_note()` for small changes vs rewriting
- **Switch projects**: Change context when user mentions different work areas
- **Organize proactively**: Move old content to archive folders
- **Cross-project operations**: Create notes in specific projects while maintaining context
## Common Knowledge Patterns
### Capturing Decisions
```markdown
---
title: Coffee Brewing Methods
tags: [coffee, brewing, pour-over, techniques] # v0.13.0: Now searchable!
---
# Coffee Brewing Methods
## Context
I've experimented with various brewing methods including French press, pour over, and espresso.
## Decision
Pour over is my preferred method for light to medium roasts because it highlights subtle flavors and offers more control over the extraction.
## Observations
- [technique] Blooming the coffee grounds for 30 seconds improves extraction #brewing
- [preference] Water temperature between 195-205°F works best #temperature
- [equipment] Gooseneck kettle provides better control of water flow #tools
- [timing] Total brew time of 3-4 minutes produces optimal extraction #process
## Relations
- pairs_with [[Light Roast Beans]]
- contrasts_with [[French Press Method]]
- requires [[Proper Grinding Technique]]
- part_of [[Morning Coffee Routine]]
```
### Recording Project Structure
```markdown
# Garden Planning
## Overview
This document outlines the garden layout and planting strategy for this season.
## Observations
- [structure] Raised beds in south corner for sun exposure #layout
- [structure] Drip irrigation system installed for efficiency #watering
- [pattern] Companion planting used to deter pests naturally #technique
## Relations
- contains [[Vegetable Section]]
- contains [[Herb Garden]]
- implements [[Organic Gardening Principles]]
```
### Technical Discussions
```markdown
# Recipe Improvement Discussion
## Key Points
Discussed strategies for improving the chocolate chip cookie recipe.
## Observations
- [issue] Cookies spread too thin when baked at 350°F #texture
- [solution] Chilling dough for 24 hours improves flavor and reduces spreading #technique
- [decision] Will use brown butter instead of regular butter #flavor
## Relations
- improves [[Basic Cookie Recipe]]
- inspired_by [[Bakery-Style Cookies]]
- pairs_with [[Homemade Ice Cream]]
```
## v0.13.0 Workflow Examples
### Multi-Project Conversations
**User:** "I need to update my work documentation and also add a personal recipe note."
**Workflow:**
1. `list_projects()` - Check available projects
2. `write_note(title="Sprint Planning", project="work-notes")` - Work content
3. `write_note(title="Weekend Recipes", project="personal")` - Personal content
### Incremental Note Building
**User:** "Add a troubleshooting section to my setup guide."
**Workflow:**
1. `edit_note(identifier="Setup Guide", operation="append", content="\n## Troubleshooting\n...")`
**User:** "Update the authentication section in my API docs."
**Workflow:**
1. `edit_note(identifier="API Documentation", operation="replace_section", section="## Authentication")`
### Smart File Organization
**User:** "My notes are getting messy in the main folder."
**Workflow:**
1. `move_note("Old Meeting Notes", "archive/2024/old-meetings.md")`
2. `move_note("Project Notes", "projects/client-work/notes.md")`
### Creating Effective Relations
When creating relations:
1. **Reference existing entities** by their exact title: `[[Exact Title]]`
2. **Create forward references** to entities that don't exist yet - they'll be linked automatically when created
3. **Search first** to find existing entities to reference
4. **Use meaningful relation types**: `implements`, `requires`, `part_of` vs generic `relates_to`
**Example workflow:**
1. `search_notes("travel")` to find existing travel-related notes
2. Reference found entities: `- part_of [[Japan Travel Guide]]`
3. Add forward references: `- located_in [[Tokyo]]` (even if Tokyo note doesn't exist yet)
## Common Issues & Solutions
**Missing Content:**
- Try `search_notes()` with broader terms if `read_note()` fails
- Use fuzzy matching: search for partial titles
**Forward References:**
- These are normal! Basic Memory links them automatically when target notes are created
- Inform users: "I've created forward references that will be linked when you create those notes"
**Sync Issues:**
- If information seems outdated, suggest `basic-memory sync`
- Use `recent_activity()` to check if content is current
**Strict Mode for Edit/Move Operations:**
- `edit_note()` and `move_note()` require **exact identifiers** (no fuzzy matching for safety)
- If identifier not found: use `search_notes()` first to find the exact title/permalink
- Error messages will guide you to find correct identifiers
- Example workflow:
```
# ❌ This might fail if identifier isn't exact
edit_note("Meeting Note", "append", "content")
# ✅ Safe approach: search first, then use exact result
results = search_notes("meeting")
edit_note("Meeting Notes 2024", "append", "content") # Use exact title from search
```
## Best Practices
1. **Proactively Record Context**
- Offer to capture important discussions
- Record decisions, rationales, and conclusions
- Link to related topics
- Ask for permission first: "Would you like me to save our discussion about [topic]?"
- Confirm when complete: "I've saved our discussion to Basic Memory"
2. **Create a Rich Semantic Graph**
- **Add meaningful observations**: Include at least 3-5 categorized observations in each note
- **Create deliberate relations**: Connect each note to at least 2-3 related entities
- **Use existing entities**: Before creating a new relation, search for existing entities
- **Verify wikilinks**: When referencing `[[Entity]]`, use exact titles of existing notes
- **Check accuracy**: Use `search_notes()` or `recent_activity()` to confirm entity titles
- **Use precise relation types**: Choose specific relation types that convey meaning (e.g., "implements" instead of "relates_to")
- **Consider bidirectional relations**: When appropriate, create inverse relations in both entities
3. **Structure Content Thoughtfully**
- Use clear, descriptive titles
- Organize with logical sections (Context, Decision, Implementation, etc.)
- Include relevant context and background
- Add semantic observations with appropriate categories
- Use a consistent format for similar types of notes
- Balance detail with conciseness
4. **Navigate Knowledge Effectively**
- Start with specific searches
- Follow relation paths
- Combine information from multiple sources
- Verify information is current
- Build a complete picture before responding
5. **Help Users Maintain Their Knowledge**
- Suggest organizing related topics
- Identify potential duplicates
- Recommend adding relations between topics
- Offer to create summaries of scattered information
- Suggest potential missing relations: "I notice this might relate to [topic], would you like me to add that connection?"
Built with ♥️ by Basic Machines
+365
View File
@@ -0,0 +1,365 @@
# Docker Setup Guide
Basic Memory can be run in Docker containers to provide a consistent, isolated environment for your knowledge management
system. This is particularly useful for integrating with existing Dockerized MCP servers or for deployment scenarios.
## Quick Start
### Option 1: Using Pre-built Images (Recommended)
Basic Memory provides pre-built Docker images on GitHub Container Registry that are automatically updated with each release.
1. **Use the official image directly:**
```bash
docker run -d \
--name basic-memory-server \
-p 8000:8000 \
-v /path/to/your/obsidian-vault:/app/data:rw \
-v basic-memory-config:/app/.basic-memory:rw \
ghcr.io/basicmachines-co/basic-memory:latest
```
2. **Or use Docker Compose with the pre-built image:**
```yaml
version: '3.8'
services:
basic-memory:
image: ghcr.io/basicmachines-co/basic-memory:latest
container_name: basic-memory-server
ports:
- "8000:8000"
volumes:
- /path/to/your/obsidian-vault:/app/data:rw
- basic-memory-config:/app/.basic-memory:rw
environment:
- BASIC_MEMORY_DEFAULT_PROJECT=main
restart: unless-stopped
```
### Option 2: Using Docker Compose (Building Locally)
1. **Clone the repository:**
```bash
git clone https://github.com/basicmachines-co/basic-memory.git
cd basic-memory
```
2. **Update the docker-compose.yml:**
Edit the volume mount to point to your Obsidian vault:
```yaml
volumes:
# Change './obsidian-vault' to your actual directory path
- /path/to/your/obsidian-vault:/app/data:rw
```
3. **Start the container:**
```bash
docker-compose up -d
```
### Option 3: Using Docker CLI
```bash
# Build the image
docker build -t basic-memory .
# Run with volume mounting
docker run -d \
--name basic-memory-server \
-v /path/to/your/obsidian-vault:/app/data:rw \
-v basic-memory-config:/app/.basic-memory:rw \
-e BASIC_MEMORY_DEFAULT_PROJECT=main \
basic-memory
```
## Configuration
### Volume Mounts
Basic Memory requires several volume mounts for proper operation:
1. **Knowledge Directory** (Required):
```yaml
- /path/to/your/obsidian-vault:/app/data:rw
```
Mount your Obsidian vault or knowledge base directory.
2. **Configuration and Database** (Recommended):
```yaml
- basic-memory-config:/app/.basic-memory:rw
```
Persistent storage for configuration and SQLite database.
You can edit the basic-memory config.json file located in the /app/.basic-memory/config.json after Basic Memory starts.
3. **Multiple Projects** (Optional):
```yaml
- /path/to/project1:/app/data/project1:rw
- /path/to/project2:/app/data/project2:rw
```
You can edit the basic-memory config.json file located in the /app/.basic-memory/config.json
## CLI Commands via Docker
You can run Basic Memory CLI commands inside the container using `docker exec`:
### Basic Commands
```bash
# Check status
docker exec basic-memory-server basic-memory status
# Sync files
docker exec basic-memory-server basic-memory sync
# Show help
docker exec basic-memory-server basic-memory --help
```
### Managing Projects with Volume Mounts
When using Docker volumes, you'll need to configure projects to point to your mounted directories:
1. **Check current configuration:**
```bash
docker exec basic-memory-server cat /app/.basic-memory/config.json
```
2. **Add a project for your mounted volume:**
```bash
# If you mounted /path/to/your/vault to /app/data
docker exec basic-memory-server basic-memory project create my-vault /app/data
# Set it as default
docker exec basic-memory-server basic-memory project set-default my-vault
```
3. **Sync the new project:**
```bash
docker exec basic-memory-server basic-memory sync
```
### Example: Setting up an Obsidian Vault
If you mounted your Obsidian vault like this in docker-compose.yml:
```yaml
volumes:
- /Users/yourname/Documents/ObsidianVault:/app/data:rw
```
Then configure it:
```bash
# Create project pointing to mounted vault
docker exec basic-memory-server basic-memory project create obsidian /app/data
# Set as default
docker exec basic-memory-server basic-memory project set-default obsidian
# Sync to index all files
docker exec basic-memory-server basic-memory sync
```
### Environment Variables
Configure Basic Memory using environment variables:
```yaml
environment:
# Default project
- BASIC_MEMORY_DEFAULT_PROJECT=main
# Enable real-time sync
- BASIC_MEMORY_SYNC_CHANGES=true
# Logging level
- BASIC_MEMORY_LOG_LEVEL=INFO
# Sync delay in milliseconds
- BASIC_MEMORY_SYNC_DELAY=1000
```
## File Permissions
### Linux/macOS
The Docker container now runs as a non-root user to avoid file ownership issues. By default, the container uses UID/GID 1000, but you can customize this to match your user:
```bash
# Build with custom UID/GID to match your user
docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) -t basic-memory .
# Or use docker-compose with build args
```
**Example docker-compose.yml with custom user:**
```yaml
version: '3.8'
services:
basic-memory:
build:
context: .
dockerfile: Dockerfile
args:
UID: 1000 # Replace with your UID
GID: 1000 # Replace with your GID
container_name: basic-memory-server
ports:
- "8000:8000"
volumes:
- /path/to/your/obsidian-vault:/app/data:rw
- basic-memory-config:/app/.basic-memory:rw
environment:
- BASIC_MEMORY_DEFAULT_PROJECT=main
restart: unless-stopped
```
**Using pre-built images:**
If using the pre-built image from GitHub Container Registry, files will be created with UID/GID 1000. You can either:
1. Change your local directory ownership to match:
```bash
sudo chown -R 1000:1000 /path/to/your/obsidian-vault
```
2. Or build your own image with custom UID/GID as shown above.
### Windows
When using Docker Desktop on Windows, ensure the directories are shared:
1. Open Docker Desktop
2. Go to Settings → Resources → File Sharing
3. Add your knowledge directory path
4. Apply & Restart
## Troubleshooting
### Common Issues
1. **File Watching Not Working:**
- Ensure volume mounts are read-write (`:rw`)
- Check directory permissions
- On Linux, may need to increase inotify limits:
```bash
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```
2. **Configuration Not Persisting:**
- Use named volumes for `/app/.basic-memory`
- Check volume mount permissions
3. **Network Connectivity:**
- For HTTP transport, ensure port 8000 is exposed
- Check firewall settings
### Debug Mode
Run with debug logging:
```yaml
environment:
- BASIC_MEMORY_LOG_LEVEL=DEBUG
```
View logs:
```bash
docker-compose logs -f basic-memory
```
## Security Considerations
1. **Docker Security:**
The container runs as a non-root user (UID/GID 1000 by default) for improved security. You can customize the user ID using build arguments to match your local user.
2. **Volume Permissions:**
Ensure mounted directories have appropriate permissions and don't expose sensitive data. With the non-root container, files will be created with the specified user ownership.
3. **Network Security:**
If using HTTP transport, consider using reverse proxy with SSL/TLS and authentication if the endpoint is available on
a network.
4. **IMPORTANT:** The HTTP endpoints have no authorization. They should not be exposed on a public network.
## Integration Examples
### Claude Desktop with Docker
The recommended way to connect Claude Desktop to the containerized Basic Memory is using `mcp-proxy`, which converts the HTTP transport to STDIO that Claude Desktop expects:
1. **Start the Docker container:**
```bash
docker-compose up -d
```
2. **Configure Claude Desktop** to use mcp-proxy:
```json
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": [
"mcp-proxy",
"http://localhost:8000/mcp"
]
}
}
}
```
## Support
For Docker-specific issues:
1. Check the [troubleshooting section](#troubleshooting) above
2. Review container logs: `docker-compose logs basic-memory`
3. Verify volume mounts: `docker inspect basic-memory-server`
4. Test file permissions: `docker exec basic-memory-server ls -la /app`
For general Basic Memory support, see the main [README](../README.md)
and [documentation](https://memory.basicmachines.co/).
## GitHub Container Registry Images
### Available Images
Pre-built Docker images are available on GitHub Container Registry at [`ghcr.io/basicmachines-co/basic-memory`](https://github.com/basicmachines-co/basic-memory/pkgs/container/basic-memory).
**Supported architectures:**
- `linux/amd64` (Intel/AMD x64)
- `linux/arm64` (ARM64, including Apple Silicon)
**Available tags:**
- `latest` - Latest stable release
- `v0.13.8`, `v0.13.7`, etc. - Specific version tags
- `v0.13`, `v0.12`, etc. - Major.minor tags
### Automated Builds
Docker images are automatically built and published when new releases are tagged:
1. **Release Process:** When a git tag matching `v*` (e.g., `v0.13.8`) is pushed, the CI workflow automatically:
- Builds multi-platform Docker images
- Pushes to GitHub Container Registry with appropriate tags
- Uses native GitHub integration for seamless publishing
2. **CI/CD Pipeline:** The Docker workflow includes:
- Multi-platform builds (AMD64 and ARM64)
- Layer caching for faster builds
- Automatic tagging with semantic versioning
- Security scanning and optimization
### Setup Requirements (For Maintainers)
GitHub Container Registry integration is automatic for this repository:
1. **No external setup required** - GHCR is natively integrated with GitHub
2. **Automatic permissions** - Uses `GITHUB_TOKEN` with `packages: write` permission
3. **Public by default** - Images are automatically public for public repositories
The Docker CI workflow (`.github/workflows/docker.yml`) handles everything automatically when version tags are pushed.
+241
View File
@@ -0,0 +1,241 @@
# Character Handling and Conflict Resolution
Basic Memory handles various character encoding scenarios and file naming conventions to provide consistent permalink generation and conflict resolution. This document explains how the system works and how to resolve common character-related issues.
## Overview
Basic Memory uses a sophisticated system to generate permalinks from file paths while maintaining consistency across different operating systems and character encodings. The system normalizes file paths and generates unique permalinks to prevent conflicts.
## Character Normalization Rules
### 1. Permalink Generation
When Basic Memory processes a file path, it applies these normalization rules:
```
Original: "Finance/My Investment Strategy.md"
Permalink: "finance/my-investment-strategy"
```
**Transformation process:**
1. Remove file extension (`.md`)
2. Convert to lowercase (case-insensitive)
3. Replace spaces with hyphens
4. Replace underscores with hyphens
5. Handle international characters (transliteration for Latin, preservation for non-Latin)
6. Convert camelCase to kebab-case
### 2. International Character Support
**Latin characters with diacritics** are transliterated:
- `ø``o` (Søren → soren)
- `ü``u` (Müller → muller)
- `é``e` (Café → cafe)
- `ñ``n` (Niño → nino)
**Non-Latin characters** are preserved:
- Chinese: `中文/测试文档.md``中文/测试文档`
- Japanese: `日本語/文書.md``日本語/文書`
## Common Conflict Scenarios
### 1. Hyphen vs Space Conflicts
**Problem:** Files with existing hyphens conflict with generated permalinks from spaces.
**Example:**
```
File 1: "basic memory bug.md" → permalink: "basic-memory-bug"
File 2: "basic-memory-bug.md" → permalink: "basic-memory-bug" (CONFLICT!)
```
**Resolution:** The system automatically resolves this by adding suffixes:
```
File 1: "basic memory bug.md" → permalink: "basic-memory-bug"
File 2: "basic-memory-bug.md" → permalink: "basic-memory-bug-1"
```
**Best Practice:** Choose consistent naming conventions within your project.
### 2. Case Sensitivity Conflicts
**Problem:** Different case variations that normalize to the same permalink.
**Example on macOS:**
```
Directory: Finance/investment.md
Directory: finance/investment.md (different on filesystem, same permalink)
```
**Resolution:** Basic Memory detects case conflicts and prevents them during sync operations with helpful error messages.
**Best Practice:** Use consistent casing for directory and file names.
### 3. Character Encoding Conflicts
**Problem:** Different Unicode normalizations of the same logical character.
**Example:**
```
File 1: "café.md" (é as single character)
File 2: "café.md" (e + combining accent)
```
**Resolution:** Basic Memory normalizes Unicode characters using NFD normalization to detect these conflicts.
### 4. Forward Slash Conflicts
**Problem:** Forward slashes in frontmatter or file names interpreted as path separators.
**Example:**
```yaml
---
permalink: finance/investment/strategy
---
```
**Resolution:** Basic Memory validates frontmatter permalinks and warns about path separator conflicts.
## Error Messages and Troubleshooting
### "UNIQUE constraint failed: entity.file_path, entity.project_id"
**Cause:** Two entities trying to use the same file path within a project.
**Common scenarios:**
1. File move operation where destination is already occupied
2. Case sensitivity differences on macOS
3. Character encoding conflicts
4. Concurrent file operations
**Resolution steps:**
1. Check for duplicate file names with different cases
2. Look for files with similar names but different character encodings
3. Rename conflicting files to have unique names
4. Run sync again after resolving conflicts
### "File path conflict detected during move"
**Cause:** Enhanced conflict detection preventing potential database integrity violations.
**What this means:** The system detected that moving a file would create a conflict before attempting the database operation.
**Resolution:** Follow the specific guidance in the error message, which will indicate the type of conflict detected.
## Best Practices
### 1. File Naming Conventions
**Recommended patterns:**
- Use consistent casing (prefer lowercase)
- Use hyphens instead of spaces for multi-word files
- Avoid special characters that could conflict with path separators
- Be consistent with directory structure casing
**Examples:**
```
✅ Good:
- finance/investment-strategy.md
- projects/basic-memory-features.md
- docs/api-reference.md
❌ Problematic:
- Finance/Investment Strategy.md (mixed case, spaces)
- finance/Investment Strategy.md (inconsistent case)
- docs/API/Reference.md (mixed case directories)
```
### 2. Permalink Management
**Custom permalinks in frontmatter:**
```yaml
---
type: knowledge
permalink: custom-permalink-name
---
```
**Guidelines:**
- Use lowercase permalinks
- Use hyphens for word separation
- Avoid path separators unless creating sub-paths
- Ensure uniqueness within your project
### 3. Directory Structure
**Consistent casing:**
```
✅ Good:
finance/
investment-strategies.md
portfolio-management.md
❌ Problematic:
Finance/ (capital F)
investment-strategies.md
finance/ (lowercase f)
portfolio-management.md
```
## Migration and Cleanup
### Identifying Conflicts
Use Basic Memory's built-in conflict detection:
```bash
# Sync will report conflicts
basic-memory sync
# Check sync status for warnings
basic-memory status
```
### Resolving Existing Conflicts
1. **Identify conflicting files** from sync error messages
2. **Choose consistent naming convention** for your project
3. **Rename files** to follow the convention
4. **Re-run sync** to verify resolution
### Bulk Renaming Strategy
For projects with many conflicts:
1. **Backup your project** before making changes
2. **Standardize on lowercase** file and directory names
3. **Replace spaces with hyphens** in file names
4. **Use consistent character encoding** (UTF-8)
5. **Test sync after each batch** of changes
## System Enhancements
### Recent Improvements (v0.13+)
1. **Enhanced conflict detection** before database operations
2. **Improved error messages** with specific resolution guidance
3. **Character normalization utilities** for consistent handling
4. **File swap detection** for complex move scenarios
5. **Proactive conflict warnings** during permalink resolution
### Monitoring and Logging
The system now provides detailed logging for conflict resolution:
```
DEBUG: Detected potential file path conflicts for 'Finance/Investment.md': ['finance/investment.md']
WARNING: File path conflict detected during move: entity_id=123 trying to move from 'old.md' to 'new.md'
```
These logs help identify and resolve conflicts before they cause sync failures.
## Support and Resources
If you encounter character-related conflicts not covered in this guide:
1. **Check the logs** for specific conflict details
2. **Review error messages** for resolution guidance
3. **Report issues** with examples of the conflicting files
4. **Consider the file naming best practices** outlined above
The Basic Memory system is designed to handle most character conflicts automatically while providing clear guidance for manual resolution when needed.
Binary file not shown.
-16
View File
@@ -1,16 +0,0 @@
# Basic Memory Installer
This installer configures Basic Memory to work with Claude Desktop.
## Installation
1. Download the latest installer from the [releases page](https://github.com/basicmachines-co/basic-memory/releases)
2. Unzip the downloaded file
3. Since the app is currently unsigned, you'll need to:
- Right-click (or Control-click) the app
- Select "Open" from the context menu
- Click "Open" in the warning dialog
4. Follow the installation instructions
5. Restart Claude Desktop
The warning only appears the first time you open the app. Future updates will include proper code signing.
-64
View File
@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<!-- Background -->
<rect x="0" y="0" width="512" height="512" rx="64" fill="#111111"/>
<!-- Define arrowhead marker -->
<defs>
<marker id="arrowhead"
markerWidth="10"
markerHeight="10"
refX="8"
refY="5"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 Z"
fill="#00cc00"/>
</marker>
</defs>
<!-- State 1 (initial) -->
<circle cx="156" cy="256" r="30" fill="none" stroke="#00cc00" stroke-width="3"/>
<!-- State 2 (accept) -->
<circle cx="356" cy="176" r="34" fill="none" stroke="#00cc00" stroke-width="3"/>
<circle cx="356" cy="176" r="28" fill="none" stroke="#00cc00" stroke-width="3"/>
<!-- State 3 (accept) -->
<circle cx="356" cy="336" r="34" fill="none" stroke="#00cc00" stroke-width="3"/>
<circle cx="356" cy="336" r="28" fill="none" stroke="#00cc00" stroke-width="3"/>
<!-- Initial arrow -->
<path d="M 96 256 L 126 256"
stroke="#00cc00" stroke-width="3" fill="none"
marker-end="url(#arrowhead)"/>
<!-- State transitions -->
<!-- 1 -> 2 -->
<path d="M 180 240
Q 260 200, 320 176"
stroke="#00cc00" stroke-width="3" fill="none"
marker-end="url(#arrowhead)"/>
<!-- 1 -> 3 -->
<path d="M 180 272
Q 260 312, 320 336"
stroke="#00cc00" stroke-width="3" fill="none"
marker-end="url(#arrowhead)"/>
<!-- Self loops -->
<path d="M 356 142
Q 396 142, 396 176
Q 396 210, 356 210
Q 316 210, 316 176
Q 316 142, 356 142"
stroke="#00cc00" stroke-width="2" fill="none"
marker-end="url(#arrowhead)"/>
<path d="M 356 302
Q 396 302, 396 336
Q 396 370, 356 370
Q 316 370, 316 336
Q 316 302, 356 302"
stroke="#00cc00" stroke-width="2" fill="none"
marker-end="url(#arrowhead)"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

-89
View File
@@ -1,89 +0,0 @@
import json
import subprocess
import sys
from pathlib import Path
# Use tkinter for GUI alerts on macOS
if sys.platform == "darwin":
import tkinter as tk
from tkinter import messagebox
def ensure_uv_installed():
"""Check if uv is installed, install if not."""
try:
subprocess.run(["uv", "--version"], capture_output=True, check=True)
except (subprocess.CalledProcessError, FileNotFoundError):
print("Installing uv package manager...")
subprocess.run(
[
"curl",
"-LsSf",
"https://astral.sh/uv/install.sh",
"|",
"sh",
],
shell=True,
)
def get_config_path():
"""Get Claude Desktop config path for current platform."""
if sys.platform == "darwin":
return Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
elif sys.platform == "win32":
return Path.home() / "AppData/Roaming/Claude/claude_desktop_config.json"
else:
raise RuntimeError(f"Unsupported platform: {sys.platform}")
def update_claude_config():
"""Update Claude Desktop config to include basic-memory."""
config_path = get_config_path()
config_path.parent.mkdir(parents=True, exist_ok=True)
# Load existing config or create new
if config_path.exists():
config = json.loads(config_path.read_text())
else:
config = {"mcpServers": {}}
# Add/update basic-memory config
config["mcpServers"]["basic-memory"] = {"command": "uvx", "args": ["basic-memory", "mcp"]}
# Write back config
config_path.write_text(json.dumps(config, indent=2))
def print_completion_message():
"""Show completion message with helpful tips."""
message = """Installation complete! Basic Memory is now available in Claude Desktop.
Please restart Claude Desktop for changes to take effect.
Quick Start:
1. You can run sync directly using: uvx basic-memory sync
2. Optionally, install globally with: uv pip install basic-memory
Built with ♥️ by Basic Machines."""
if sys.platform == "darwin":
# Show GUI message on macOS
root = tk.Tk()
root.withdraw() # Hide the main window
messagebox.showinfo("Basic Memory", message)
root.destroy()
else:
# Fallback to console output
print(message)
def main():
print("Welcome to Basic Memory installer")
ensure_uv_installed()
print("Configuring Claude Desktop...")
update_claude_config()
print_completion_message()
if __name__ == "__main__":
main()
-27
View File
@@ -1,27 +0,0 @@
#!/bin/bash
# Convert SVG to PNG at various required sizes
rsvg-convert -h 16 -w 16 icon.svg > icon_16x16.png
rsvg-convert -h 32 -w 32 icon.svg > icon_32x32.png
rsvg-convert -h 128 -w 128 icon.svg > icon_128x128.png
rsvg-convert -h 256 -w 256 icon.svg > icon_256x256.png
rsvg-convert -h 512 -w 512 icon.svg > icon_512x512.png
# Create iconset directory
mkdir -p Basic.iconset
# Move files into iconset with Mac-specific names
cp icon_16x16.png Basic.iconset/icon_16x16.png
cp icon_32x32.png Basic.iconset/icon_16x16@2x.png
cp icon_32x32.png Basic.iconset/icon_32x32.png
cp icon_128x128.png Basic.iconset/icon_32x32@2x.png
cp icon_256x256.png Basic.iconset/icon_128x128.png
cp icon_512x512.png Basic.iconset/icon_256x256.png
cp icon_512x512.png Basic.iconset/icon_512x512.png
# Convert iconset to icns
iconutil -c icns Basic.iconset
# Clean up
rm -rf Basic.iconset
rm icon_*.png
-42
View File
@@ -1,42 +0,0 @@
from cx_Freeze import setup, Executable
import sys
# Build options for all platforms
build_exe_options = {
"packages": ["json", "pathlib"],
"excludes": [],
}
# Platform-specific options
if sys.platform == "win32":
base = "Win32GUI" # Use GUI base for Windows
build_exe_options.update({
"include_msvcr": True,
})
target_name = "Basic Memory Installer.exe"
else: # darwin
base = None # Don't use GUI base for macOS
target_name = "Basic Memory Installer"
executables = [
Executable(
script="installer.py",
target_name=target_name,
base=base,
icon="Basic.icns"
)
]
setup(
name="basic-memory",
version=open("../pyproject.toml").read().split('version = "', 1)[1].split('"', 1)[0],
description="Basic Memory - Local-first knowledge management",
options={
"build_exe": build_exe_options,
"bdist_mac": {
"bundle_name": "Basic Memory Installer",
"iconfile": "Basic.icns"
}
},
executables=executables,
)
+185
View File
@@ -0,0 +1,185 @@
# Basic Memory - Modern Command Runner
# Install dependencies
install:
pip install -e ".[dev]"
uv sync
@echo ""
@echo "💡 Remember to activate the virtual environment by running: source .venv/bin/activate"
# Run unit tests in parallel
test-unit:
uv run pytest -p pytest_mock -v -n auto
# Run integration tests in parallel
test-int:
uv run pytest -p pytest_mock -v --no-cov -n auto test-int
# Run all tests
test: test-unit test-int
# Lint and fix code
lint:
uv run ruff check . --fix
# Type check code
type-check:
uv run pyright
# Clean build artifacts and cache files
clean:
find . -type f -name '*.pyc' -delete
find . -type d -name '__pycache__' -exec rm -r {} +
rm -rf installer/build/ installer/dist/ dist/
rm -f rw.*.dmg .coverage.*
# Format code with ruff
format:
uv run ruff format .
# Run MCP inspector tool
run-inspector:
npx @modelcontextprotocol/inspector
# Build macOS installer
installer-mac:
cd installer && chmod +x make_icons.sh && ./make_icons.sh
cd installer && uv run python setup.py bdist_mac
# Build Windows installer
installer-win:
cd installer && uv run python setup.py bdist_win32
# Update all dependencies to latest versions
update-deps:
uv sync --upgrade
# Run all code quality checks and tests
check: lint format type-check test
# Generate Alembic migration with descriptive message
migration message:
cd src/basic_memory/alembic && alembic revision --autogenerate -m "{{message}}"
# Create a stable release (e.g., just release v0.13.2)
release version:
#!/usr/bin/env bash
set -euo pipefail
# Validate version format
if [[ ! "{{version}}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "❌ Invalid version format. Use: v0.13.2"
exit 1
fi
# Extract version number without 'v' prefix
VERSION_NUM=$(echo "{{version}}" | sed 's/^v//')
echo "🚀 Creating stable release {{version}}"
# Pre-flight checks
echo "📋 Running pre-flight checks..."
if [[ -n $(git status --porcelain) ]]; then
echo "❌ Uncommitted changes found. Please commit or stash them first."
exit 1
fi
if [[ $(git branch --show-current) != "main" ]]; then
echo "❌ Not on main branch. Switch to main first."
exit 1
fi
# Check if tag already exists
if git tag -l "{{version}}" | grep -q "{{version}}"; then
echo "❌ Tag {{version}} already exists"
exit 1
fi
# Run quality checks
echo "🔍 Running quality checks..."
just check
# Update version in __init__.py
echo "📝 Updating version in __init__.py..."
sed -i.bak "s/__version__ = \".*\"/__version__ = \"$VERSION_NUM\"/" src/basic_memory/__init__.py
rm -f src/basic_memory/__init__.py.bak
# Commit version update
git add src/basic_memory/__init__.py
git commit -m "chore: update version to $VERSION_NUM for {{version}} release"
# Create and push tag
echo "🏷️ Creating tag {{version}}..."
git tag "{{version}}"
echo "📤 Pushing to GitHub..."
git push origin main
git push origin "{{version}}"
echo "✅ Release {{version}} created successfully!"
echo "📦 GitHub Actions will build and publish to PyPI"
echo "🔗 Monitor at: https://github.com/basicmachines-co/basic-memory/actions"
# Create a beta release (e.g., just beta v0.13.2b1)
beta version:
#!/usr/bin/env bash
set -euo pipefail
# Validate version format (allow beta/rc suffixes)
if [[ ! "{{version}}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(b[0-9]+|rc[0-9]+)$ ]]; then
echo "❌ Invalid beta version format. Use: v0.13.2b1 or v0.13.2rc1"
exit 1
fi
# Extract version number without 'v' prefix
VERSION_NUM=$(echo "{{version}}" | sed 's/^v//')
echo "🧪 Creating beta release {{version}}"
# Pre-flight checks
echo "📋 Running pre-flight checks..."
if [[ -n $(git status --porcelain) ]]; then
echo "❌ Uncommitted changes found. Please commit or stash them first."
exit 1
fi
if [[ $(git branch --show-current) != "main" ]]; then
echo "❌ Not on main branch. Switch to main first."
exit 1
fi
# Check if tag already exists
if git tag -l "{{version}}" | grep -q "{{version}}"; then
echo "❌ Tag {{version}} already exists"
exit 1
fi
# Run quality checks
echo "🔍 Running quality checks..."
just check
# Update version in __init__.py
echo "📝 Updating version in __init__.py..."
sed -i.bak "s/__version__ = \".*\"/__version__ = \"$VERSION_NUM\"/" src/basic_memory/__init__.py
rm -f src/basic_memory/__init__.py.bak
# Commit version update
git add src/basic_memory/__init__.py
git commit -m "chore: update version to $VERSION_NUM for {{version}} beta release"
# Create and push tag
echo "🏷️ Creating tag {{version}}..."
git tag "{{version}}"
echo "📤 Pushing to GitHub..."
git push origin main
git push origin "{{version}}"
echo "✅ Beta release {{version}} created successfully!"
echo "📦 GitHub Actions will build and publish to PyPI as pre-release"
echo "🔗 Monitor at: https://github.com/basicmachines-co/basic-memory/actions"
echo "📥 Install with: uv tool install basic-memory --pre"
# List all available recipes
default:
@just --list
+31
View File
@@ -0,0 +1,31 @@
file_path,file_name,category,size_bytes,modified_date,primary_author,all_contributors,sha256_hash
.github/workflows/release.yml,release.yml,configuration,2479,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez,163307a99e2f3d317af6ae8927e1537654d88bf574a6958ac0bcd2d4de266b2a
CLAUDE.md,CLAUDE.md,legal,12310,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant); Ikko Eltociear Ashimine,751f10c1a9a9c0ba2054d9c9cd36cf0989d6a347491fd505bb6504ee74b12900
README.md,README.md,documentation,16261,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez; Jason Noble; Marc Baiza; Matias Forbord; bm-claudeai (AI Assistant),2c4b82b30f49ab465617034fda999157450ed168f8e097fe8e9ca7ac65a197a7
justfile,justfile,other,5496,2025-07-30,jope-bm,jope-bm; Paul Hernandez; Drew Cain,a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
pyproject.toml,pyproject.toml,configuration,3279,2025-07-30,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); semantic-release,428a5d64d4555dc7cd2a81b89a3444bdb1d2f3017257fbc9160bd0ae982718e1
src/basic_memory/__init__.py,__init__.py,source_code,256,2025-07-06,Paul Hernandez,Paul Hernandez; Drew Cain; semantic-release,c946490ab9d64957d25df37f721392024916f8a81ed838f70a8e938b1c2637db
src/basic_memory/alembic/env.py,env.py,source_code,2838,2025-07-08,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),e241d987eadfcd5011cbd9ddbecb833d306de87937759d81c08d37d04a6906b0
src/basic_memory/api/routers/utils.py,utils.py,source_code,5159,2025-07-03,Drew Cain,Drew Cain; bm-claudeai (AI Assistant),9e60f57da24e1dc9d64236c26a7a2353003dc618a77fbeb853c494aa3357a57c
src/basic_memory/cli/commands/mcp.py,mcp.py,source_code,2593,2025-07-08,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),3e1be3d27b18ef4743204b7cf8a37fbc2a1a91fc1636c468e08cefcd8597bac6
src/basic_memory/config.py,config.py,source_code,12487,2025-07-30,jope-bm,jope-bm; Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant),86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
src/basic_memory/db.py,db.py,source_code,7428,2025-07-08,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),25e053b0b3f9e8fa823b05fc099001efe8a3a4f6e0f80728e5079ba45aa406d8
src/basic_memory/mcp/server.py,server.py,source_code,1248,2025-07-08,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),0a910cae27d61ea923e90fbe2d4b5c7cacf3b29d3e156f0b7f77872ab973c761
src/basic_memory/mcp/tools/__init__.py,__init__.py,source_code,1619,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez,872b771dd52ec3b763645a2baf6e10a70f049ce3106830a6d3f053b3e09a5fe6
src/basic_memory/mcp/tools/project_management.py,project_management.py,source_code,12944,2025-07-06,Drew Cain,Drew Cain; Paul Hernandez,cdac736d65129f689a85c6b82f8e043bc84a31657ead7a8331771171eeaa860f
src/basic_memory/mcp/tools/search.py,search.py,source_code,15883,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant),8519b0057468c4450eb543a2f561bcd0d7cb96e1ce1b95e948e02b309ba6b7ca
src/basic_memory/repository/entity_repository.py,entity_repository.py,source_code,10405,2025-07-03,Drew Cain,Drew Cain; bm-claudeai (AI Assistant); Paul Hernandez,e2a8d1eba6c8d64bc61d7168df0fe8c29a670858bf9daeac464a0f440273fae0
src/basic_memory/schemas/memory.py,memory.py,source_code,5833,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant),acb4a953a553feca672c4895798a7d948ec51f922f75b66dd7d55716e3bebed3
src/basic_memory/services/entity_service.py,entity_service.py,source_code,30440,2025-07-03,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant),7cd5163eca6b8a0772e838c8c869e478166763cd6a2d745b0b9aa5c25a65baee
src/basic_memory/services/initialization.py,initialization.py,source_code,6715,2025-07-08,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),4dde58b799cf4ac90631e59949b55b3355a93bdf99df0d9c2408c0cea67e10c4
src/basic_memory/templates/prompts/continue_conversation.hbs,continue_conversation.hbs,templates,3076,2025-07-01,Drew Cain,Drew Cain; bm-claudeai (AI Assistant),b6bac31d25c0e52d0909b2273285092f4e31bc219107f92ed511cd407b65e992
src/basic_memory/utils.py,utils.py,source_code,8654,2025-07-30,jope-bm,jope-bm; Paul Hernandez; Drew Cain; andyxinweiminicloud; github-actions[bot] (AI Assistant),111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
tests/mcp/test_tool_edit_note.py,test_tool_edit_note.py,source_code,13503,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez,dd441969aa54b3739f2d9202d3feaf46aee807ec51e01a13ef41eda52743944f
tests/mcp/test_tool_search.py,test_tool_search.py,source_code,10959,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez; github-actions[bot] (AI Assistant),07839cf8e89d74ba05ec1dc55fa842444c1f0cc3d1587823b0ac3458ad89e87c
tests/mcp/test_tool_write_note.py,test_tool_write_note.py,source_code,35136,2025-07-30,jope-bm,jope-bm; Drew Cain; Paul Hernandez,45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
tests/repository/test_entity_repository_upsert.py,test_entity_repository_upsert.py,source_code,16983,2025-07-03,Paul Hernandez,Paul Hernandez; Drew Cain,ee0ecd6f4ff8b31838bd6de6fb1018af437e02813d8315c06f4e20a6b78a0572
tests/schemas/test_schemas.py,test_schemas.py,source_code,16880,2025-07-03,Drew Cain,Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant),2c746a00c340f063c160ace67569955a300a294040949695c79fd4ae124fb611
tests/services/test_entity_service.py,test_entity_service.py,source_code,59278,2025-07-03,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),d7d495756faa10b415d705cf26b69d2efbc5f190a834b6767386ff296629ea71
tests/test_config.py,test_config.py,source_code,3680,2025-07-03,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),6a246431cff739274efda895dfa28f38710289a73e645312f5fa05fce0885ec8
tests/test_db_migration_deduplication.py,test_db_migration_deduplication.py,source_code,6166,2025-07-08,Paul Hernandez,Paul Hernandez; Drew Cain,ab768e061531ca2edcd598c101b5d884e549f90c7a4b305a23713a199d263fbb
uv.lock,uv.lock,other,232710,2025-07-30,Paul Hernandez,Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant),caa1e3f6e66464b884a78cab77df2fe303fa3c0dc573be0196474b6d3c150581
1 file_path file_name category size_bytes modified_date primary_author all_contributors sha256_hash
2 .github/workflows/release.yml release.yml configuration 2479 2025-07-03 Drew Cain Drew Cain; Paul Hernandez 163307a99e2f3d317af6ae8927e1537654d88bf574a6958ac0bcd2d4de266b2a
3 CLAUDE.md CLAUDE.md legal 12310 2025-07-03 Drew Cain Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant); Ikko Eltociear Ashimine 751f10c1a9a9c0ba2054d9c9cd36cf0989d6a347491fd505bb6504ee74b12900
4 README.md README.md documentation 16261 2025-07-03 Drew Cain Drew Cain; Paul Hernandez; Jason Noble; Marc Baiza; Matias Forbord; bm-claudeai (AI Assistant) 2c4b82b30f49ab465617034fda999157450ed168f8e097fe8e9ca7ac65a197a7
5 justfile justfile other 5496 2025-07-30 jope-bm jope-bm; Paul Hernandez; Drew Cain a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
6 pyproject.toml pyproject.toml configuration 3279 2025-07-30 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); semantic-release 428a5d64d4555dc7cd2a81b89a3444bdb1d2f3017257fbc9160bd0ae982718e1
7 src/basic_memory/__init__.py __init__.py source_code 256 2025-07-06 Paul Hernandez Paul Hernandez; Drew Cain; semantic-release c946490ab9d64957d25df37f721392024916f8a81ed838f70a8e938b1c2637db
8 src/basic_memory/alembic/env.py env.py source_code 2838 2025-07-08 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) e241d987eadfcd5011cbd9ddbecb833d306de87937759d81c08d37d04a6906b0
9 src/basic_memory/api/routers/utils.py utils.py source_code 5159 2025-07-03 Drew Cain Drew Cain; bm-claudeai (AI Assistant) 9e60f57da24e1dc9d64236c26a7a2353003dc618a77fbeb853c494aa3357a57c
10 src/basic_memory/cli/commands/mcp.py mcp.py source_code 2593 2025-07-08 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) 3e1be3d27b18ef4743204b7cf8a37fbc2a1a91fc1636c468e08cefcd8597bac6
11 src/basic_memory/config.py config.py source_code 12487 2025-07-30 jope-bm jope-bm; Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant) 86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
12 src/basic_memory/db.py db.py source_code 7428 2025-07-08 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) 25e053b0b3f9e8fa823b05fc099001efe8a3a4f6e0f80728e5079ba45aa406d8
13 src/basic_memory/mcp/server.py server.py source_code 1248 2025-07-08 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) 0a910cae27d61ea923e90fbe2d4b5c7cacf3b29d3e156f0b7f77872ab973c761
14 src/basic_memory/mcp/tools/__init__.py __init__.py source_code 1619 2025-07-03 Drew Cain Drew Cain; Paul Hernandez 872b771dd52ec3b763645a2baf6e10a70f049ce3106830a6d3f053b3e09a5fe6
15 src/basic_memory/mcp/tools/project_management.py project_management.py source_code 12944 2025-07-06 Drew Cain Drew Cain; Paul Hernandez cdac736d65129f689a85c6b82f8e043bc84a31657ead7a8331771171eeaa860f
16 src/basic_memory/mcp/tools/search.py search.py source_code 15883 2025-07-03 Drew Cain Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant) 8519b0057468c4450eb543a2f561bcd0d7cb96e1ce1b95e948e02b309ba6b7ca
17 src/basic_memory/repository/entity_repository.py entity_repository.py source_code 10405 2025-07-03 Drew Cain Drew Cain; bm-claudeai (AI Assistant); Paul Hernandez e2a8d1eba6c8d64bc61d7168df0fe8c29a670858bf9daeac464a0f440273fae0
18 src/basic_memory/schemas/memory.py memory.py source_code 5833 2025-07-03 Drew Cain Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant) acb4a953a553feca672c4895798a7d948ec51f922f75b66dd7d55716e3bebed3
19 src/basic_memory/services/entity_service.py entity_service.py source_code 30440 2025-07-03 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant) 7cd5163eca6b8a0772e838c8c869e478166763cd6a2d745b0b9aa5c25a65baee
20 src/basic_memory/services/initialization.py initialization.py source_code 6715 2025-07-08 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) 4dde58b799cf4ac90631e59949b55b3355a93bdf99df0d9c2408c0cea67e10c4
21 src/basic_memory/templates/prompts/continue_conversation.hbs continue_conversation.hbs templates 3076 2025-07-01 Drew Cain Drew Cain; bm-claudeai (AI Assistant) b6bac31d25c0e52d0909b2273285092f4e31bc219107f92ed511cd407b65e992
22 src/basic_memory/utils.py utils.py source_code 8654 2025-07-30 jope-bm jope-bm; Paul Hernandez; Drew Cain; andyxinweiminicloud; github-actions[bot] (AI Assistant) 111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
23 tests/mcp/test_tool_edit_note.py test_tool_edit_note.py source_code 13503 2025-07-03 Drew Cain Drew Cain; Paul Hernandez dd441969aa54b3739f2d9202d3feaf46aee807ec51e01a13ef41eda52743944f
24 tests/mcp/test_tool_search.py test_tool_search.py source_code 10959 2025-07-03 Drew Cain Drew Cain; Paul Hernandez; github-actions[bot] (AI Assistant) 07839cf8e89d74ba05ec1dc55fa842444c1f0cc3d1587823b0ac3458ad89e87c
25 tests/mcp/test_tool_write_note.py test_tool_write_note.py source_code 35136 2025-07-30 jope-bm jope-bm; Drew Cain; Paul Hernandez 45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
26 tests/repository/test_entity_repository_upsert.py test_entity_repository_upsert.py source_code 16983 2025-07-03 Paul Hernandez Paul Hernandez; Drew Cain ee0ecd6f4ff8b31838bd6de6fb1018af437e02813d8315c06f4e20a6b78a0572
27 tests/schemas/test_schemas.py test_schemas.py source_code 16880 2025-07-03 Drew Cain Drew Cain; Paul Hernandez; bm-claudeai (AI Assistant) 2c746a00c340f063c160ace67569955a300a294040949695c79fd4ae124fb611
28 tests/services/test_entity_service.py test_entity_service.py source_code 59278 2025-07-03 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) d7d495756faa10b415d705cf26b69d2efbc5f190a834b6767386ff296629ea71
29 tests/test_config.py test_config.py source_code 3680 2025-07-03 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) 6a246431cff739274efda895dfa28f38710289a73e645312f5fa05fce0885ec8
30 tests/test_db_migration_deduplication.py test_db_migration_deduplication.py source_code 6166 2025-07-08 Paul Hernandez Paul Hernandez; Drew Cain ab768e061531ca2edcd598c101b5d884e549f90c7a4b305a23713a199d263fbb
31 uv.lock uv.lock other 232710 2025-07-30 Paul Hernandez Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant) caa1e3f6e66464b884a78cab77df2fe303fa3c0dc573be0196474b6d3c150581
+28
View File
@@ -0,0 +1,28 @@
file_path,file_name,category,size_bytes,modified_date,primary_author,all_contributors,sha256_hash
CONTRIBUTING.md,CONTRIBUTING.md,documentation,7329,2025-07-30,jope-bm,jope-bm; Paul Hernandez,ca822fe39cc529bfc3822d317ab8a20fd141ec3ecb8c20de9e2eca3edce1c282
justfile,justfile,other,5496,2025-07-30,jope-bm,jope-bm; Paul Hernandez; Drew Cain,a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
src/basic_memory/api/routers/project_router.py,project_router.py,source_code,8444,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),6539c69f1d506c65d14cc2c151876b19057f37d84d51a9e6f464ed47a4692648
src/basic_memory/cli/commands/import_memory_json.py,import_memory_json.py,source_code,3013,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),7ea193f6720b2672290ad16c79a143a31d88a1d567838f12b9ebf9110a7c0338
src/basic_memory/cli/commands/project.py,project.py,source_code,13836,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),af3e6f30410ab48355f4b1a46aaa3aa5423cb0a0490f51447db1d25e09f39916
src/basic_memory/config.py,config.py,source_code,12487,2025-07-30,jope-bm,jope-bm; Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant),86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
src/basic_memory/importers/memory_json_importer.py,memory_json_importer.py,source_code,4631,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),bc7d045299f17ed9ad5cebff7b1423250ec28a11130e47a0ac48d3ab82bdeafc
src/basic_memory/mcp/async_client.py,async_client.py,source_code,925,2025-07-30,jope-bm,jope-bm; Paul Hernandez,6531f4387f30a30a322197ff51d6eacae4b25a58c648095931b3d1145d1da303
src/basic_memory/mcp/tools/move_note.py,move_note.py,source_code,17541,2025-07-30,jope-bm,jope-bm; Paul Hernandez,5ef27d9baaebc2c5656fc49c4798a4e4e40a70b6cd9d1e761dbcae021bad558c
src/basic_memory/mcp/tools/read_content.py,read_content.py,source_code,9125,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),96a13addac507fd874394dfa2e1e5ed71af5eb89d0872c1d68cacf9cac3f8724
src/basic_memory/mcp/tools/read_note.py,read_note.py,source_code,8132,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant); Amadeusz Wieczorek; github-actions[bot] (AI Assistant),dff53ce02b16d9c5fca315b3f09bb70867a89d614b0ef3f0548dce87978048ee
src/basic_memory/mcp/tools/write_note.py,write_note.py,source_code,6612,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),771396fb49d397feb5f7e36321d4d233c22c4d1b53414912c849957c6e96fc83
src/basic_memory/repository/project_repository.py,project_repository.py,source_code,3803,2025-07-30,jope-bm,jope-bm; bm-claudeai (AI Assistant),9083ba214b2bcaaf98164d9c33cda7add52bc77f7269ecb6e43cdd5088728b7c
src/basic_memory/schemas/importer.py,importer.py,source_code,693,2025-07-30,jope-bm,jope-bm; bm-claudeai (AI Assistant),ac33df423ca32b28ce7b6ea9c29d541f8783a86c0c29f78db35163bf93f139cd
src/basic_memory/services/project_service.py,project_service.py,source_code,30125,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),bce95c00aa9a1da0a8c8090ee34b5b1494207f8c99e6c25de4ec43fddc38f6be
src/basic_memory/utils.py,utils.py,source_code,8654,2025-07-30,jope-bm,jope-bm; Paul Hernandez; Drew Cain; andyxinweiminicloud; github-actions[bot] (AI Assistant),111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
tests/api/test_async_client.py,test_async_client.py,source_code,1382,2025-07-30,jope-bm,jope-bm; Paul Hernandez,a2f96226a75e5cff2326ca48ddccea4915964d83e529f7b99958bc233ccdc31a
tests/api/test_project_router.py,test_project_router.py,source_code,13288,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),af85d0870069d3831a9214372853994e5d12dc910e37298eb9958f72f6a8bb31
tests/cli/test_import_memory_json.py,test_import_memory_json.py,source_code,4891,2025-07-30,jope-bm,jope-bm; bm-claudeai (AI Assistant); Paul Hernandez,d6734ce059dacf97bc764d848b2e2a6ba52fa96871bc331ec9d2ddc60b766bb6
tests/cli/test_project_commands.py,test_project_commands.py,source_code,6578,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),51e2ac7ff44b0d1a1db6da406c5c2e6aebceb1b63a1e8d5ab51bbaa834507157
tests/mcp/test_tool_move_note.py,test_tool_move_note.py,source_code,25851,2025-07-30,jope-bm,jope-bm; Paul Hernandez,c9f95158503fa42e37532aaa35027538fa49cea718d059d570cf547d31f01043
tests/mcp/test_tool_read_content.py,test_tool_read_content.py,source_code,19442,2025-07-30,jope-bm,jope-bm,1817e32f997b06dbdabf02864d0c70584c1cd80bf1fae8dfbef649de79434bc5
tests/mcp/test_tool_read_note.py,test_tool_read_note.py,source_code,22991,2025-07-30,jope-bm,jope-bm; Paul Hernandez; Amadeusz Wieczorek; github-actions[bot] (AI Assistant),4e13ea9ff977525aa62b6a8c22505ffe989329dc3e7d07b71e044cf43ef3ddfd
tests/mcp/test_tool_write_note.py,test_tool_write_note.py,source_code,35136,2025-07-30,jope-bm,jope-bm; Drew Cain; Paul Hernandez,45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
tests/repository/test_project_repository.py,test_project_repository.py,source_code,10511,2025-07-30,jope-bm,jope-bm; bm-claudeai (AI Assistant),279a3324635b1b515c18003bd1875cf230fef1192cadef9ca426846783717e75
tests/services/test_project_service.py,test_project_service.py,source_code,28152,2025-07-30,jope-bm,jope-bm; Paul Hernandez; bm-claudeai (AI Assistant),430868ed796518937a3b0bed4d8c33be53264a6100d61d54b0745bb2b58bf29a
tests/utils/test_validate_project_path.py,test_validate_project_path.py,source_code,15346,2025-07-30,jope-bm,jope-bm,27a4bf2a9d277e6cd773619e5241b20175d211ec60c284361bec404fd99143f3
1 file_path file_name category size_bytes modified_date primary_author all_contributors sha256_hash
2 CONTRIBUTING.md CONTRIBUTING.md documentation 7329 2025-07-30 jope-bm jope-bm; Paul Hernandez ca822fe39cc529bfc3822d317ab8a20fd141ec3ecb8c20de9e2eca3edce1c282
3 justfile justfile other 5496 2025-07-30 jope-bm jope-bm; Paul Hernandez; Drew Cain a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
4 src/basic_memory/api/routers/project_router.py project_router.py source_code 8444 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) 6539c69f1d506c65d14cc2c151876b19057f37d84d51a9e6f464ed47a4692648
5 src/basic_memory/cli/commands/import_memory_json.py import_memory_json.py source_code 3013 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) 7ea193f6720b2672290ad16c79a143a31d88a1d567838f12b9ebf9110a7c0338
6 src/basic_memory/cli/commands/project.py project.py source_code 13836 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) af3e6f30410ab48355f4b1a46aaa3aa5423cb0a0490f51447db1d25e09f39916
7 src/basic_memory/config.py config.py source_code 12487 2025-07-30 jope-bm jope-bm; Paul Hernandez; Drew Cain; bm-claudeai (AI Assistant); github-actions[bot] (AI Assistant) 86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
8 src/basic_memory/importers/memory_json_importer.py memory_json_importer.py source_code 4631 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) bc7d045299f17ed9ad5cebff7b1423250ec28a11130e47a0ac48d3ab82bdeafc
9 src/basic_memory/mcp/async_client.py async_client.py source_code 925 2025-07-30 jope-bm jope-bm; Paul Hernandez 6531f4387f30a30a322197ff51d6eacae4b25a58c648095931b3d1145d1da303
10 src/basic_memory/mcp/tools/move_note.py move_note.py source_code 17541 2025-07-30 jope-bm jope-bm; Paul Hernandez 5ef27d9baaebc2c5656fc49c4798a4e4e40a70b6cd9d1e761dbcae021bad558c
11 src/basic_memory/mcp/tools/read_content.py read_content.py source_code 9125 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) 96a13addac507fd874394dfa2e1e5ed71af5eb89d0872c1d68cacf9cac3f8724
12 src/basic_memory/mcp/tools/read_note.py read_note.py source_code 8132 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant); Amadeusz Wieczorek; github-actions[bot] (AI Assistant) dff53ce02b16d9c5fca315b3f09bb70867a89d614b0ef3f0548dce87978048ee
13 src/basic_memory/mcp/tools/write_note.py write_note.py source_code 6612 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) 771396fb49d397feb5f7e36321d4d233c22c4d1b53414912c849957c6e96fc83
14 src/basic_memory/repository/project_repository.py project_repository.py source_code 3803 2025-07-30 jope-bm jope-bm; bm-claudeai (AI Assistant) 9083ba214b2bcaaf98164d9c33cda7add52bc77f7269ecb6e43cdd5088728b7c
15 src/basic_memory/schemas/importer.py importer.py source_code 693 2025-07-30 jope-bm jope-bm; bm-claudeai (AI Assistant) ac33df423ca32b28ce7b6ea9c29d541f8783a86c0c29f78db35163bf93f139cd
16 src/basic_memory/services/project_service.py project_service.py source_code 30125 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) bce95c00aa9a1da0a8c8090ee34b5b1494207f8c99e6c25de4ec43fddc38f6be
17 src/basic_memory/utils.py utils.py source_code 8654 2025-07-30 jope-bm jope-bm; Paul Hernandez; Drew Cain; andyxinweiminicloud; github-actions[bot] (AI Assistant) 111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
18 tests/api/test_async_client.py test_async_client.py source_code 1382 2025-07-30 jope-bm jope-bm; Paul Hernandez a2f96226a75e5cff2326ca48ddccea4915964d83e529f7b99958bc233ccdc31a
19 tests/api/test_project_router.py test_project_router.py source_code 13288 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) af85d0870069d3831a9214372853994e5d12dc910e37298eb9958f72f6a8bb31
20 tests/cli/test_import_memory_json.py test_import_memory_json.py source_code 4891 2025-07-30 jope-bm jope-bm; bm-claudeai (AI Assistant); Paul Hernandez d6734ce059dacf97bc764d848b2e2a6ba52fa96871bc331ec9d2ddc60b766bb6
21 tests/cli/test_project_commands.py test_project_commands.py source_code 6578 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) 51e2ac7ff44b0d1a1db6da406c5c2e6aebceb1b63a1e8d5ab51bbaa834507157
22 tests/mcp/test_tool_move_note.py test_tool_move_note.py source_code 25851 2025-07-30 jope-bm jope-bm; Paul Hernandez c9f95158503fa42e37532aaa35027538fa49cea718d059d570cf547d31f01043
23 tests/mcp/test_tool_read_content.py test_tool_read_content.py source_code 19442 2025-07-30 jope-bm jope-bm 1817e32f997b06dbdabf02864d0c70584c1cd80bf1fae8dfbef649de79434bc5
24 tests/mcp/test_tool_read_note.py test_tool_read_note.py source_code 22991 2025-07-30 jope-bm jope-bm; Paul Hernandez; Amadeusz Wieczorek; github-actions[bot] (AI Assistant) 4e13ea9ff977525aa62b6a8c22505ffe989329dc3e7d07b71e044cf43ef3ddfd
25 tests/mcp/test_tool_write_note.py test_tool_write_note.py source_code 35136 2025-07-30 jope-bm jope-bm; Drew Cain; Paul Hernandez 45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
26 tests/repository/test_project_repository.py test_project_repository.py source_code 10511 2025-07-30 jope-bm jope-bm; bm-claudeai (AI Assistant) 279a3324635b1b515c18003bd1875cf230fef1192cadef9ca426846783717e75
27 tests/services/test_project_service.py test_project_service.py source_code 28152 2025-07-30 jope-bm jope-bm; Paul Hernandez; bm-claudeai (AI Assistant) 430868ed796518937a3b0bed4d8c33be53264a6100d61d54b0745bb2b58bf29a
28 tests/utils/test_validate_project_path.py test_validate_project_path.py source_code 15346 2025-07-30 jope-bm jope-bm 27a4bf2a9d277e6cd773619e5241b20175d211ec60c284361bec404fd99143f3
+438
View File
@@ -0,0 +1,438 @@
#!/usr/bin/env python3
"""
Legal File Inventory Generator for Basic Memory
This script generates a comprehensive file inventory for legal documentation purposes,
including copyright assignments and company agreement exhibits.
The inventory includes:
- All source code files and their contributors
- Documentation and configuration files
- License and legal files
- Excludes generated files, dependencies, and temporary files
Usage:
python legal_file_inventory.py [--output inventory.csv] [--format csv|json|markdown]
"""
import os
import json
import csv
import subprocess
from pathlib import Path
from datetime import datetime
from typing import Dict, List
import argparse
import hashlib
class FileInventoryGenerator:
def __init__(self, repo_path: str = "."):
self.repo_path = Path(repo_path).resolve()
self.inventory = []
# File patterns to exclude from legal inventory
self.exclude_patterns = {
# Version control and git
'.git', '.gitignore', '.gitmodules',
# Python compiled and cache files
'__pycache__', '*.pyc', '*.pyo', '*.pyd', '.pytest_cache',
# Virtual environments and dependencies
'.venv', 'venv', '.env', 'env', 'ENV',
'*.dist-info', 'site-packages',
# IDE and editor files
'.idea', '.vscode', '*.swp', '*.swo', '.DS_Store',
# Build and distribution artifacts
'build', 'dist', 'htmlcov', '.coverage', '.coverage.*',
'*.egg-info', '.eggs', 'wheels',
# Cache and temporary files
'.ruff_cache', '.mypy_cache', '.tox',
'node_modules', '.npm',
# Documentation build artifacts (but keep source docs)
'.obsidian',
# Lock files (these are generated)
'uv.lock', 'Pipfile.lock', 'poetry.lock', 'package-lock.json'
}
# File extensions that are definitely source/authored content
self.source_extensions = {
'.py', '.md', '.rst', '.txt', '.toml', '.yaml', '.yml',
'.json', '.cfg', '.ini', '.conf', '.sh', '.sql',
'.js', '.ts', '.jsx', '.tsx', '.css', '.scss', '.sass',
'.html', '.htm', '.xml', '.svg', '.dockerfile', '.Dockerfile'
}
# License file patterns
self.license_patterns = {
'LICENSE', 'LICENCE', 'COPYING', 'COPYRIGHT',
'license.txt', 'LICENSE.txt', 'LICENSE.md',
'CITATION.cff', 'CLA.md'
}
def run_git_command(self, command: List[str]) -> str:
"""Run a git command and return the output."""
try:
result = subprocess.run(
['git'] + command,
cwd=self.repo_path,
capture_output=True,
text=True,
check=True
)
return result.stdout.strip()
except subprocess.CalledProcessError:
return ""
def get_file_contributors(self, file_path: str) -> Dict[str, int]:
"""Get contributors and their line contributions for a file."""
try:
blame_output = self.run_git_command(['blame', '--line-porcelain', file_path])
contributors = {}
for line in blame_output.split('\n'):
if line.startswith('author '):
author = line[7:] # Remove 'author ' prefix
contributors[author] = contributors.get(author, 0) + 1
return contributors
except Exception:
return {}
def get_file_history(self, file_path: str) -> Dict[str, any]:
"""Get file creation date, last modification, and total commits."""
try:
# Get creation date (first commit)
first_commit = self.run_git_command([
'log', '--follow', '--format=%ad', '--date=iso',
'--reverse', file_path
]).split('\n')[0] if self.run_git_command([
'log', '--follow', '--format=%ad', '--date=iso',
'--reverse', file_path
]) else None
# Get last modification date
last_commit = self.run_git_command([
'log', '-1', '--format=%ad', '--date=iso', file_path
])
# Get total commits for this file
commit_count = len(self.run_git_command([
'log', '--follow', '--oneline', file_path
]).split('\n')) if self.run_git_command([
'log', '--follow', '--oneline', file_path
]) else 0
return {
'created': first_commit or 'Unknown',
'last_modified': last_commit or 'Unknown',
'commit_count': commit_count
}
except Exception:
return {
'created': 'Unknown',
'last_modified': 'Unknown',
'commit_count': 0
}
def should_exclude_file(self, file_path: Path) -> bool:
"""Determine if a file should be excluded from the inventory."""
str_path = str(file_path)
# Check if any part of the path matches exclude patterns
for pattern in self.exclude_patterns:
if pattern in str_path or file_path.match(pattern):
return True
# Exclude files in virtual environment paths
if '/.venv/' in str_path or '/venv/' in str_path:
return True
# Exclude binary files that are likely dependencies
if file_path.suffix in {'.so', '.dylib', '.dll', '.pyd'}:
return True
return False
def calculate_file_hash(self, file_path: Path) -> str:
"""Calculate SHA-256 hash of file content."""
try:
with open(file_path, 'rb') as f:
return hashlib.sha256(f.read()).hexdigest()
except Exception:
return ""
def categorize_file(self, file_path: Path) -> str:
"""Categorize the file based on its path and extension."""
str_path = str(file_path).lower()
# License and legal files
if any(pattern.lower() in file_path.name.lower() for pattern in self.license_patterns):
return "Legal/License"
# Documentation
if file_path.suffix.lower() in {'.md', '.rst', '.txt'} and any(
doc_dir in str_path for doc_dir in ['doc', 'readme', 'changelog', 'contributing']
):
return "Documentation"
# Configuration files
if file_path.suffix.lower() in {'.toml', '.yaml', '.yml', '.json', '.cfg', '.ini', '.conf'}:
return "Configuration"
# Source code
if file_path.suffix.lower() in {'.py', '.js', '.ts', '.jsx', '.tsx'}:
return "Source Code"
# Tests
if 'test' in str_path and file_path.suffix.lower() == '.py':
return "Test Code"
# Build and deployment
if file_path.name.lower() in {'dockerfile', 'justfile', 'makefile'} or file_path.suffix.lower() in {'.sh'}:
return "Build/Deployment"
# Database and migrations
if 'migration' in str_path or 'alembic' in str_path or file_path.suffix.lower() == '.sql':
return "Database/Migration"
# Templates and resources
if file_path.suffix.lower() in {'.hbs', '.j2', '.jinja', '.template'}:
return "Templates/Resources"
return "Other"
def scan_repository(self):
"""Scan the repository and build the file inventory."""
print(f"Scanning repository: {self.repo_path}")
for root, dirs, files in os.walk(self.repo_path):
# Skip excluded directories
dirs[:] = [d for d in dirs if not any(pattern in d for pattern in self.exclude_patterns)]
for file in files:
file_path = Path(root) / file
relative_path = file_path.relative_to(self.repo_path)
# Skip excluded files
if self.should_exclude_file(relative_path):
continue
# Get file stats
try:
stat_info = file_path.stat()
file_size = stat_info.st_size
modified_time = datetime.fromtimestamp(stat_info.st_mtime)
except Exception:
file_size = 0
modified_time = datetime.now()
# Get git information
contributors = self.get_file_contributors(str(relative_path))
history = self.get_file_history(str(relative_path))
# Calculate file hash for integrity verification
file_hash = self.calculate_file_hash(file_path)
# Build inventory entry
entry = {
'file_path': str(relative_path),
'full_path': str(file_path),
'file_name': file_path.name,
'file_extension': file_path.suffix,
'file_size_bytes': file_size,
'category': self.categorize_file(relative_path),
'fs_modified_date': modified_time.isoformat(),
'git_created_date': history['created'],
'git_last_modified': history['last_modified'],
'git_commit_count': history['commit_count'],
'contributors': contributors,
'primary_author': max(contributors.items(), key=lambda x: x[1])[0] if contributors else 'Unknown',
'contributor_count': len(contributors),
'total_author_lines': sum(contributors.values()) if contributors else 0,
'sha256_hash': file_hash,
'scan_timestamp': datetime.now().isoformat()
}
self.inventory.append(entry)
print(f"Scanned {len(self.inventory)} files")
def get_summary_statistics(self) -> Dict:
"""Generate summary statistics for the inventory."""
if not self.inventory:
return {}
# Collect all contributors
all_contributors = set()
for entry in self.inventory:
all_contributors.update(entry['contributors'].keys())
# Category breakdown
categories = {}
for entry in self.inventory:
cat = entry['category']
categories[cat] = categories.get(cat, 0) + 1
# File extension breakdown
extensions = {}
for entry in self.inventory:
ext = entry['file_extension'] or 'no_extension'
extensions[ext] = extensions.get(ext, 0) + 1
# Contributor statistics
contributor_files = {}
contributor_lines = {}
for entry in self.inventory:
for contributor, lines in entry['contributors'].items():
contributor_files[contributor] = contributor_files.get(contributor, 0) + 1
contributor_lines[contributor] = contributor_lines.get(contributor, 0) + lines
return {
'total_files': len(self.inventory),
'total_contributors': len(all_contributors),
'categories': categories,
'file_extensions': extensions,
'contributor_file_counts': contributor_files,
'contributor_line_counts': contributor_lines,
'scan_date': datetime.now().isoformat(),
'repository_path': str(self.repo_path)
}
def export_csv(self, output_file: str):
"""Export inventory to CSV format."""
with open(output_file, 'w', newline='', encoding='utf-8') as f:
if not self.inventory:
return
fieldnames = list(self.inventory[0].keys())
# Convert complex fields to strings for CSV
fieldnames = [f for f in fieldnames if f != 'contributors']
fieldnames.append('contributors_json')
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for entry in self.inventory:
row = {k: v for k, v in entry.items() if k != 'contributors'}
row['contributors_json'] = json.dumps(entry['contributors'])
writer.writerow(row)
def export_json(self, output_file: str):
"""Export inventory to JSON format."""
export_data = {
'metadata': self.get_summary_statistics(),
'files': self.inventory
}
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(export_data, f, indent=2, ensure_ascii=False)
def export_markdown(self, output_file: str):
"""Export inventory to Markdown format."""
stats = self.get_summary_statistics()
with open(output_file, 'w', encoding='utf-8') as f:
f.write("# Basic Memory - Legal File Inventory\n\n")
f.write(f"**Generated:** {datetime.now().isoformat()}\n\n")
f.write(f"**Repository:** {stats.get('repository_path', 'Unknown')}\n\n")
# Summary statistics
f.write("## Summary Statistics\n\n")
f.write(f"- **Total Files:** {stats.get('total_files', 0)}\n")
f.write(f"- **Total Contributors:** {stats.get('total_contributors', 0)}\n\n")
# Categories
if 'categories' in stats:
f.write("### Files by Category\n\n")
for category, count in sorted(stats['categories'].items()):
f.write(f"- **{category}:** {count} files\n")
f.write("\n")
# Top contributors
if 'contributor_file_counts' in stats:
f.write("### Top Contributors by Files Modified\n\n")
sorted_contributors = sorted(
stats['contributor_file_counts'].items(),
key=lambda x: x[1],
reverse=True
)[:10]
for contributor, count in sorted_contributors:
f.write(f"- **{contributor}:** {count} files\n")
f.write("\n")
# Detailed file listing
f.write("## Detailed File Inventory\n\n")
f.write("| File Path | Category | Size (bytes) | Primary Author | Contributors |\n")
f.write("|-----------|----------|--------------|----------------|-------------|\n")
for entry in sorted(self.inventory, key=lambda x: x['file_path']):
contributors_str = ', '.join(entry['contributors'].keys())[:50]
if len(contributors_str) == 50:
contributors_str += "..."
f.write(f"| {entry['file_path']} | {entry['category']} | "
f"{entry['file_size_bytes']} | {entry['primary_author']} | "
f"{contributors_str} |\n")
def main():
parser = argparse.ArgumentParser(
description="Generate legal file inventory for Basic Memory repository"
)
parser.add_argument(
'--output', '-o',
default='basic_memory_legal_inventory.csv',
help='Output file path (default: basic_memory_legal_inventory.csv)'
)
parser.add_argument(
'--format', '-f',
choices=['csv', 'json', 'markdown'],
default='csv',
help='Output format (default: csv)'
)
parser.add_argument(
'--repo-path', '-r',
default='.',
help='Path to repository (default: current directory)'
)
args = parser.parse_args()
# Initialize and run the inventory generator
generator = FileInventoryGenerator(args.repo_path)
generator.scan_repository()
# Export in requested format
if args.format == 'csv':
generator.export_csv(args.output)
elif args.format == 'json':
generator.export_json(args.output)
elif args.format == 'markdown':
generator.export_markdown(args.output)
# Print summary
stats = generator.get_summary_statistics()
print("\n=== Legal File Inventory Complete ===")
print(f"Repository: {stats.get('repository_path', 'Unknown')}")
print(f"Total files inventoried: {stats.get('total_files', 0)}")
print(f"Total contributors identified: {stats.get('total_contributors', 0)}")
print(f"Output written to: {args.output}")
# Show top contributors
if 'contributor_file_counts' in stats:
print("\nTop 5 contributors by files modified:")
sorted_contributors = sorted(
stats['contributor_file_counts'].items(),
key=lambda x: x[1],
reverse=True
)[:5]
for i, (contributor, count) in enumerate(sorted_contributors, 1):
print(f" {i}. {contributor}: {count} files")
if __name__ == '__main__':
main()
@@ -0,0 +1,272 @@
path,name,category,size_bytes,modified_time,primary_author,contributor_count,contributors_list,sha256_hash
.claude/commands/release/beta.md,beta.md,documentation,3103,2025-07-01T08:33:22.037438,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),345f06e3f304470a8892e96979355919c8e5d8f4212ebbe543c3272fd15a5cbe
.claude/commands/release/changelog.md,changelog.md,documentation,4648,2025-07-03T18:43:10.075727,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),ea2484352f4f881aa71f546dcf84b0882d60c96673a88406aa2f7e12a282a1f4
.claude/commands/release/release-check.md,release-check.md,documentation,3344,2025-07-01T08:33:22.040060,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),7dd41a40e95c89153936c4ea60a3c989eccd5973fff9f6caef156de82f12bd04
.claude/commands/release/release.md,release.md,documentation,2925,2025-07-01T08:33:22.043674,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),0e4afd788fcf85fbe46094452e9b92a4290c3e23702283e72ee56aa9288476e5
.claude/commands/test-live.md,test-live.md,documentation,18720,2025-07-03T18:43:10.076403,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),21a9edeefb3e5673d833151a2fd0464087c0f0a9d056fdd7fca474c1d177d6fc
.dockerignore,.dockerignore,other,623,2025-07-01T08:33:22.048301,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),b3079bffad89d07186c9166725075524ffc07ceea6dc1d53fdbea6dca9585684
.github/ISSUE_TEMPLATE/bug_report.md,bug_report.md,documentation,967,2025-03-01T14:22:50.968994,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),0d34443ddda84a5e9726c8268083c9646d2cc64ff9c5ebf56c89587cef4c7706
.github/ISSUE_TEMPLATE/config.yml,config.yml,configuration,374,2025-03-01T14:23:26.936836,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),f4e21bb9b7f053509b6c08548a2649a5d62f44f0106810aa8c915d2f29acc623
.github/ISSUE_TEMPLATE/documentation.md,documentation.md,documentation,557,2025-03-01T14:23:40.020117,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),78f80a6b9a2b954695f74a847a068e0b780da6020572401c13c931555a4a9db5
.github/ISSUE_TEMPLATE/feature_request.md,feature_request.md,documentation,786,2025-03-01T14:23:06.344081,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),cee834de442221d53f3d2eeb85b81f3a641b3a7cb587ef8a169452305007439d
.github/dependabot.yml,dependabot.yml,configuration,529,2025-03-15T10:40:16.936258,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),8c6c2ef9a1417da63adb49c70f45524129bd5c46bbd7452b6b97cfe65205f89d
.github/workflows/claude.yml,claude.yml,legal,4628,2025-07-03T18:43:10.076958,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),d026f1756310781b85abc491b454cc31b52dfce4b951cdf8a4a555b6b047604c
.github/workflows/dev-release.yml,dev-release.yml,configuration,1405,2025-06-03T08:31:42.915367,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),58bcfc9e11e210e02dee76aabe7d1378da4edafb7f61857049ee6ccee9d45ffa
.github/workflows/docker.yml,docker.yml,configuration,1621,2025-07-01T08:33:22.049870,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c918a86f2b16ebb45182a73c45272bcd6cea7022cc6e0eaeb2b2a24d8eebfe4d
.github/workflows/pr-title.yml,pr-title.yml,configuration,887,2025-02-17T16:29:35.733646,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),b6df62a20235496feba4d9419c85d6e8446c4d447ad69e7f57b51cc8953f68f4
.github/workflows/release.yml,release.yml,configuration,2479,2025-07-03T18:43:10.077261,Drew Cain,2,Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co),163307a99e2f3d317af6ae8927e1537654d88bf574a6958ac0bcd2d4de266b2a
.github/workflows/test.yml,test.yml,configuration,1426,2025-07-01T08:33:22.054430,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),ab09084a11be8adfc83fc6285c652fbe44a4584aa7d7d3658fcf0c57112d1640
.gitignore,.gitignore,other,566,2025-07-01T08:33:22.055006,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),358658b0faa8c3145e539421deba4ad0bac4a8ea2e608b2c2f867a822c67b36f
.python-version,.python-version,other,5,2024-12-02T16:41:37.012830,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),7b55f8e67b5623c4bef3fa691288da9437d79d3aba156de48d481db32ac7d16d
CHANGELOG.md,CHANGELOG.md,documentation,53647,2025-07-06T10:34:45.550847,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); semantic-release (semantic-release),0b165eb18975ff253cde08f4687b7808ac6ce63b6d8c10912c495a76c9058d1a
CITATION.cff,CITATION.cff,other,302,2025-02-17T16:29:35.735146,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),bc4878cf6f80bb64655f3f93a5821ffe0924ad8311c784b5f81a36093fcffdda
CLA.md,CLA.md,legal,1342,2025-03-01T14:12:38.435132,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),c238c7ff4f2b8451c6bba1bbacd10b04fb7d41d9a9cd76a62644d8193791d169
CLAUDE.md,CLAUDE.md,legal,12310,2025-07-03T18:43:10.078147,Drew Cain,4,Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); Ikko Eltociear Ashimine (eltociear@gmail.com),751f10c1a9a9c0ba2054d9c9cd36cf0989d6a347491fd505bb6504ee74b12900
CODE_OF_CONDUCT.md,CODE_OF_CONDUCT.md,documentation,509,2025-02-17T16:29:35.735238,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),b276b464e85eb1e5d9f09d90bba9573508a7bf81d2eeb38d0f25bd9f2fa66198
CONTRIBUTING.md,CONTRIBUTING.md,documentation,7329,2025-07-30T09:39:36.607158,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co),ca822fe39cc529bfc3822d317ab8a20fd141ec3ecb8c20de9e2eca3edce1c282
Dockerfile,Dockerfile,other,856,2025-07-01T08:33:22.056908,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),c45501905423990e31ffdb8ae4e976eca6423c6784905c1036bcc7795b70feef
LICENSE,LICENSE,legal,34523,2024-12-02T16:41:20.739392,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),8486a10c4393cee1c25392769ddd3b2d6c242d6ec7928e1414efff7dfb2f07ef
README.md,README.md,documentation,16261,2025-07-03T18:43:10.078281,Drew Cain,6,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Jason Noble (github+jasonn@jasonnoble.org); Marc Baiza (43151891+mbaiza27@users.noreply.github.com); Matias Forbord (codeluggage@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),2c4b82b30f49ab465617034fda999157450ed168f8e097fe8e9ca7ac65a197a7
SECURITY.md,SECURITY.md,documentation,303,2025-03-12T16:04:01.989927,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),96932268b8fe737577941b49e9dff5ff8ad59c11cc3f9a016989589ef5c98c1f
docker-compose.yml,docker-compose.yml,configuration,2534,2025-07-01T08:33:22.059281,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),4a9fdfd2f0d42b148fe021eee77fd5e772c7ba9c2fe5d0cc310c8c7a64257417
docs/AI Assistant Guide.md,AI Assistant Guide.md,documentation,16423,2025-07-01T08:33:22.060491,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c717869a3d356852077026591364ecb0589a6d53f9764af027c57d142ea7ff55
docs/Docker.md,Docker.md,documentation,9088,2025-07-01T08:33:22.060976,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),e13d3f50148353046b52d9d493986880f76f2914ef4efe1a759b2cc9d10913a4
justfile,justfile,other,5496,2025-07-30T09:39:36.608008,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com),a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
llms-install.md,llms-install.md,documentation,2307,2025-06-29T14:19:28.826375,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),674105eb85c8f1d59fc2ddc6840f2a2a3e293358687a305c37dffc8144304f97
memory.json,memory.json,configuration,90075,2025-06-29T14:19:28.827172,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),22d5eee995ca0548b7d9dd152f9a3690c42a514cbf38fea750b3ed2a17dd99c5
pyproject.toml,pyproject.toml,configuration,3279,2025-07-30T09:39:36.608791,Paul Hernandez,4,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); semantic-release (semantic-release),428a5d64d4555dc7cd2a81b89a3444bdb1d2f3017257fbc9160bd0ae982718e1
smithery.yaml,smithery.yaml,configuration,433,2025-03-11T16:36:03.389716,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),63f13499cf4fee0751b5005f5bd85597dc1c7f9a881f4ec8147cc23e95e75c2d
src/basic_memory/__init__.py,__init__.py,source_code,256,2025-07-06T10:34:45.551291,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@gmail.com); semantic-release (semantic-release),c946490ab9d64957d25df37f721392024916f8a81ed838f70a8e938b1c2637db
src/basic_memory/alembic/alembic.ini,alembic.ini,configuration,3733,2025-02-23T17:31:23.198433,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),20466c9c5f026db66793006bebb2f328a3686c7bb34da40d52f33c3eca29e717
src/basic_memory/alembic/env.py,env.py,source_code,2838,2025-07-08T20:39:18.336650,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),e241d987eadfcd5011cbd9ddbecb833d306de87937759d81c08d37d04a6906b0
src/basic_memory/alembic/migrations.py,migrations.py,source_code,718,2025-06-21T00:01:59.613806,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),96b8873d70dd04b48d5c45b7413a54d1224ab9577557ef0dad5929377a9fb144
src/basic_memory/alembic/script.py.mako,script.py.mako,other,635,2025-02-17T16:29:35.739659,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),304a8bfb6a804e5493f5300e79882c70c9f5bb2e87512f4d16f0e097dddd323f
src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py,3dae7c7b1564_initial_schema.py,source_code,4363,2025-06-21T00:01:59.595762,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),9536d69409ddd5eb3bc54f7d0e82607da45ed7f2ad7bc4cbf7cae2a9e28657cd
src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py,502b60eaa905_remove_required_from_entity_permalink.py,source_code,1840,2025-06-21T00:01:59.604717,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),93ac584e660f33d468b3eec203b070641298c282bf82655d0beda7f050237681
src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py,5fe1ab1ccebe_add_projects_table.py,source_code,4379,2025-06-21T00:01:59.601299,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),d82098f5aca3cdbada60c7229ea4ac262f527349eed9ef9e864509bacfaccf7e
src/basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py,647e7a75e2cd_project_constraint_fix.py,source_code,4210,2025-07-01T08:33:22.063463,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),604ac5908a5976272f52297866d13abb14a99390590935d9fd37cf13e32049fa
src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py,b3c3938bacdb_relation_to_name_unique_index.py,source_code,1428,2025-06-21T00:01:59.598551,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),46c1b2990cdf4575752d234a8b28b494c8a54f15b5360c12f6347aef27b66a92
src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py,cc7172b46608_update_search_index_schema.py,source_code,3679,2025-06-21T00:01:59.610909,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),9036af47d42ac7dc12bb93f7a9de1266aff0688b031b550c4e0d92983a24b4c5
src/basic_memory/api/__init__.py,__init__.py,source_code,72,2025-06-21T00:01:59.579981,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),c02a63fb6d63d43d0acca97d425eae9cb055158d0ad6e1a9fc57926512adaa99
src/basic_memory/api/app.py,app.py,source_code,2897,2025-07-08T20:39:18.337081,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ad673ac2c09410af5830f6afdffaa28b0040480dacd52ff01750b8b2c066e8cf
src/basic_memory/api/routers/__init__.py,__init__.py,source_code,398,2025-06-21T00:01:59.549416,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),4443b908a43dea8e6fb4658009cb08c48a56c9b21449e29773cdd159b59cf014
src/basic_memory/api/routers/directory_router.py,directory_router.py,source_code,2054,2025-06-21T00:01:59.567371,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ac1407beec1f7d43a4d222af704b3642559c960bebf2eaf6e1ffe91f7fac5514
src/basic_memory/api/routers/importer_router.py,importer_router.py,source_code,4513,2025-06-21T00:01:59.561600,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),c45502a2b90f5a8f00174c9ad14adc2e65cd7fc0a33d9740a9d750207f0f3bea
src/basic_memory/api/routers/knowledge_router.py,knowledge_router.py,source_code,9738,2025-07-01T08:33:22.064119,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),e1d0ffb4fa5c246582ba844a11b417092de1a173567be55b7060bbc55fbc5681
src/basic_memory/api/routers/management_router.py,management_router.py,source_code,2730,2025-07-08T20:39:18.337438,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),cdbce294dcec6146c56c4dae15744cdf77039fd21b23eef7cbc0b5f9bfb5f4ee
src/basic_memory/api/routers/memory_router.py,memory_router.py,source_code,3003,2025-07-01T08:33:22.064510,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),6bd0a7c775e0c1290efb6001173237c0cdcfa0c1b1bb27c9145a7b35f1596a97
src/basic_memory/api/routers/project_router.py,project_router.py,source_code,8444,2025-07-30T09:39:45.721369,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),6539c69f1d506c65d14cc2c151876b19057f37d84d51a9e6f464ed47a4692648
src/basic_memory/api/routers/prompt_router.py,prompt_router.py,source_code,9948,2025-07-01T08:33:22.065221,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),e30c6aebe35112054933c37d0b462c3750005030fc9e44c23b35b2cd2a93485c
src/basic_memory/api/routers/resource_router.py,resource_router.py,source_code,8058,2025-06-21T00:01:59.570399,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),584244a84698ff24ca8f9f94fab5b891740a51c25f972920c08ebf83f478d5c9
src/basic_memory/api/routers/search_router.py,search_router.py,source_code,1226,2025-06-21T00:01:59.543020,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),183eb68e50904e22ff54db1d89b8be6f57fa1f8d0a096a3d497d8297b607e105
src/basic_memory/api/routers/utils.py,utils.py,source_code,5159,2025-07-03T18:43:10.079143,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),9e60f57da24e1dc9d64236c26a7a2353003dc618a77fbeb853c494aa3357a57c
src/basic_memory/api/template_loader.py,template_loader.py,source_code,8607,2025-06-21T00:01:59.576132,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),7b16d3797c89460c8b1664a335eae8c634fb5f60d6166d97e6a5156b776b6d83
src/basic_memory/cli/__init__.py,__init__.py,source_code,33,2025-06-21T00:01:59.456735,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),6ab70a2c05910e13c3ef1e6df34325be265e633c076741998a0cb2dcd295a069
src/basic_memory/cli/app.py,app.py,source_code,2268,2025-07-08T20:39:18.337708,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),f710670380d707c4458ad881f7a25bb3c5cdb2bcff59f139f37421264fe8f2f8
src/basic_memory/cli/commands/__init__.py,__init__.py,source_code,393,2025-07-08T20:39:18.338070,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),de8a23702f98fb844fa9f7fdbedc16ce24ff4f8baf05589c2f4a521cd8a55645
src/basic_memory/cli/commands/db.py,db.py,source_code,1480,2025-07-08T20:39:18.338326,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),704a1096d80ab9d12e247d029fe6223e935a0d0ceee7e615c020f46a720828e0
src/basic_memory/cli/commands/import_chatgpt.py,import_chatgpt.py,source_code,2856,2025-07-08T20:39:18.338787,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),8957cca3acab6351335624a518bdc19d956487e93d86dd1b6c2309e9d5850ae5
src/basic_memory/cli/commands/import_claude_conversations.py,import_claude_conversations.py,legal,2946,2025-07-08T20:39:18.339053,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7bc97838732bf00f4fb4a80e3ba4fdfbce8971ae85cc2ac902c3b3a3e110ae57
src/basic_memory/cli/commands/import_claude_projects.py,import_claude_projects.py,legal,2891,2025-07-08T20:39:18.339310,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),6321577075801c99ad47a0cdc13b5aa3c9ca102a05ca8f06ae2a51125a8c43bc
src/basic_memory/cli/commands/import_memory_json.py,import_memory_json.py,source_code,3013,2025-07-30T09:39:45.721637,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7ea193f6720b2672290ad16c79a143a31d88a1d567838f12b9ebf9110a7c0338
src/basic_memory/cli/commands/mcp.py,mcp.py,source_code,2593,2025-07-08T20:39:18.340025,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),3e1be3d27b18ef4743204b7cf8a37fbc2a1a91fc1636c468e08cefcd8597bac6
src/basic_memory/cli/commands/project.py,project.py,source_code,13836,2025-07-30T09:39:45.721838,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),af3e6f30410ab48355f4b1a46aaa3aa5423cb0a0490f51447db1d25e09f39916
src/basic_memory/cli/commands/status.py,status.py,source_code,5809,2025-07-08T20:39:18.340324,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),b6d0ea237d714d054f69b24a2058beba74e224a2fa4a80a525d62a2aa2ea2d70
src/basic_memory/cli/commands/sync.py,sync.py,source_code,8213,2025-07-08T20:39:18.340627,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),703b3e73c4c33850c27f6f4c07abbf5d4ce5dc43f706bf0c43264bbb45f8b213
src/basic_memory/cli/commands/tool.py,tool.py,source_code,9540,2025-07-01T08:33:22.070903,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),9b2fa400b9f7921bf55b602f8bbdfa36b1ec7e4a5bc8fe7b9838b92e31f0a9ed
src/basic_memory/cli/main.py,main.py,source_code,465,2025-07-08T20:39:18.340868,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7a405b12bff98e319968526238ae15859df0362bba5a3857562fecca47b5c70d
src/basic_memory/config.py,config.py,source_code,12487,2025-07-30T09:39:45.722031,jope-bm,5,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
src/basic_memory/db.py,db.py,source_code,7428,2025-07-08T20:39:18.341550,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),25e053b0b3f9e8fa823b05fc099001efe8a3a4f6e0f80728e5079ba45aa406d8
src/basic_memory/deps.py,deps.py,source_code,12144,2025-07-08T20:39:18.341870,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),bce28cd9ca549b8afce0bc689cc1fb2dc80cd5b929f85114aa682bb8ae82411d
src/basic_memory/file_utils.py,file_utils.py,source_code,6700,2025-06-21T00:01:59.587200,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),79ac5328b2c46d3232fcc6ff22ffc39ade085c0252ad91958be2a7ae9c9c8b71
src/basic_memory/importers/__init__.py,__init__.py,source_code,795,2025-06-21T00:01:59.295471,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),0537015bdecfded85cb166b9c3db50b2f3aef329c70e0c36fbcb4f824099a21f
src/basic_memory/importers/base.py,base.py,source_code,2531,2025-06-21T00:01:59.305335,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),6b0c1efd4f827f348834aa0cea2ae8eebbb842a2e5b1f5f3747ced0ef79b9f13
src/basic_memory/importers/chatgpt_importer.py,chatgpt_importer.py,source_code,7372,2025-06-21T00:01:59.308956,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),dfa540b196ab23b5c4e6bfcac4da567873351cf7c78fa35f4c3b87e84c58e218
src/basic_memory/importers/claude_conversations_importer.py,claude_conversations_importer.py,legal,5725,2025-06-21T00:01:59.288540,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),a7bc9e872f4f81ce5f79fe9dd1a6fd0f00a6f020a2cb2664184a97f14eeb1dbc
src/basic_memory/importers/claude_projects_importer.py,claude_projects_importer.py,legal,5389,2025-06-21T00:01:59.291737,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),a452675fd9bb18ebf64eb4bd7f69ccd7e993b617931015a3c4ab700d67493863
src/basic_memory/importers/memory_json_importer.py,memory_json_importer.py,source_code,4631,2025-07-30T09:39:45.722316,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),bc7d045299f17ed9ad5cebff7b1423250ec28a11130e47a0ac48d3ab82bdeafc
src/basic_memory/importers/utils.py,utils.py,source_code,1792,2025-06-21T00:01:59.298428,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),ee7e22fd4812362394f62ed8944abe80738c1e3ab88131faf639f4a8ccfd6c89
src/basic_memory/markdown/__init__.py,__init__.py,source_code,501,2025-06-21T00:01:59.316337,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),0ddce2a025ad0e729aab4e411d82e02ffefc15ac041cba4b5e7a7e90f4957c87
src/basic_memory/markdown/entity_parser.py,entity_parser.py,source_code,4516,2025-06-21T00:01:59.321461,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),1b0d1177358645ccbadd170b3f62760dc9bd838d38c741978ab0da5836234d68
src/basic_memory/markdown/markdown_processor.py,markdown_processor.py,source_code,4968,2025-06-21T00:01:59.325241,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),4b99f2ebdceed9d96a3bbb562682eba4b4b383c7a64080eaec3bbba25a4952c9
src/basic_memory/markdown/plugins.py,plugins.py,source_code,6639,2025-06-21T00:01:59.312733,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),82d2332918e866ccaf06a2e954d9eb9b397f71b4d9e591a7f2472e5f1423464a
src/basic_memory/markdown/schemas.py,schemas.py,source_code,1896,2025-06-21T00:01:59.329982,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),7b2c580abd615725a62267257b46ac13922dfc30fa01192a681658bb528ae67e
src/basic_memory/markdown/utils.py,utils.py,source_code,3410,2025-07-03T18:43:10.079889,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),1b757f0d06e60e3ea276c0b2ea44fe1a156a895e093c1e607d6286e702bf4ae4
src/basic_memory/mcp/__init__.py,__init__.py,source_code,35,2025-06-21T00:01:59.404757,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),76c0ce84aaa361e21b0942db1c8c5f708b536eab9d12e120d4da7ce9eab41844
src/basic_memory/mcp/async_client.py,async_client.py,source_code,925,2025-07-30T09:39:45.722547,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),6531f4387f30a30a322197ff51d6eacae4b25a58c648095931b3d1145d1da303
src/basic_memory/mcp/project_session.py,project_session.py,source_code,4203,2025-07-08T20:39:18.342906,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),4da403ec93dec9063eeb8b05246e3501740d162cc77a067d3ce54ba43d690819
src/basic_memory/mcp/prompts/__init__.py,__init__.py,source_code,615,2025-07-08T20:39:18.343263,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),f8197d0e08f64c3f4f50b8f38203ea5eebcf123582472ed2f58834de1dbe53b0
src/basic_memory/mcp/prompts/ai_assistant_guide.py,ai_assistant_guide.py,source_code,821,2025-06-21T00:13:53.262832,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),f13239c4e6e2455730bfac3d6f2d71407957d3086fc84efe2c6b22a833114c58
src/basic_memory/mcp/prompts/continue_conversation.py,continue_conversation.py,source_code,1998,2025-06-21T00:13:53.263309,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),aec9a50b657b7bb1ba0c02b42bcdb9bc5b0f2a0b1143bd361c5ce7ea59076833
src/basic_memory/mcp/prompts/recent_activity.py,recent_activity.py,source_code,3311,2025-07-01T08:33:22.073986,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),d2fd5cddbd927430f15d5b85f1e3a3368a18cb4e2e4587a5d29749d2b9e0830e
src/basic_memory/mcp/prompts/search.py,search.py,source_code,1692,2025-06-21T00:13:53.264093,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),9dbf3c319cbdb5d5bf32608b51522d8ae92b2dd6f7c441d62efd0954b525738a
src/basic_memory/mcp/prompts/utils.py,utils.py,source_code,5431,2025-06-21T00:01:59.425042,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),55a72b6eac18b724a9225608aca1e8e6cea3b684ccb1c609aab1511f7ce90ba4
src/basic_memory/mcp/resources/ai_assistant_guide.md,ai_assistant_guide.md,documentation,14777,2025-03-28T19:12:38.653627,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),aa76160e46256fe2662ae3a86799659916acfede1d5835c1fe2f0b136efb2e0b
src/basic_memory/mcp/resources/project_info.py,project_info.py,source_code,1906,2025-06-21T00:13:53.264918,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),2dc5244f1e225c17d4e8ba784d5721efc3aa2e8a5b3b2e258f22a77ebe155eca
src/basic_memory/mcp/server.py,server.py,source_code,1248,2025-07-08T20:39:18.343419,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),0a910cae27d61ea923e90fbe2d4b5c7cacf3b29d3e156f0b7f77872ab973c761
src/basic_memory/mcp/tools/__init__.py,__init__.py,source_code,1619,2025-07-03T18:43:10.080029,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co),872b771dd52ec3b763645a2baf6e10a70f049ce3106830a6d3f053b3e09a5fe6
src/basic_memory/mcp/tools/build_context.py,build_context.py,source_code,4611,2025-07-03T18:43:10.080426,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),724280b77b8f5f3e61cd3fdeebc3ee66e2bcfedaaea3638e6a2e2e33fcb1978e
src/basic_memory/mcp/tools/canvas.py,canvas.py,source_code,3738,2025-07-01T08:33:22.076204,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),db617d1bd81f3dbfa5f22d41e6b6b825afe1f73618f37acf63d9830390b98246
src/basic_memory/mcp/tools/delete_note.py,delete_note.py,source_code,7346,2025-07-01T08:33:22.076726,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),b52c9173f5600662f255e7a70a5c17d5293ef8b29c19a8403334d7da62b65c8b
src/basic_memory/mcp/tools/edit_note.py,edit_note.py,source_code,13570,2025-07-01T08:33:22.077181,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),ab8c7e7fbfa3fe5fb0ce6d7bf805454f5fd6182a340aae25237b1e6127b6d5a6
src/basic_memory/mcp/tools/list_directory.py,list_directory.py,source_code,5236,2025-06-21T00:13:53.267453,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),f85c43b02aeee580f4d8ce2a9100c0bab1095b245a0bb608e1847ace0d1ab51f
src/basic_memory/mcp/tools/move_note.py,move_note.py,source_code,17541,2025-07-30T09:39:45.722919,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),5ef27d9baaebc2c5656fc49c4798a4e4e40a70b6cd9d1e761dbcae021bad558c
src/basic_memory/mcp/tools/project_management.py,project_management.py,source_code,12944,2025-07-06T10:34:45.552403,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co),cdac736d65129f689a85c6b82f8e043bc84a31657ead7a8331771171eeaa860f
src/basic_memory/mcp/tools/read_content.py,read_content.py,source_code,9125,2025-07-30T09:39:45.723469,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),96a13addac507fd874394dfa2e1e5ed71af5eb89d0872c1d68cacf9cac3f8724
src/basic_memory/mcp/tools/read_note.py,read_note.py,source_code,8132,2025-07-30T09:39:45.723828,jope-bm,5,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),dff53ce02b16d9c5fca315b3f09bb70867a89d614b0ef3f0548dce87978048ee
src/basic_memory/mcp/tools/recent_activity.py,recent_activity.py,source_code,4833,2025-06-21T00:13:53.269120,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),5d58cd2402679b1bf3c7dfcbb3503e40e776c9347ba499524d3b91c528af98de
src/basic_memory/mcp/tools/search.py,search.py,source_code,15883,2025-07-03T18:43:10.081557,Drew Cain,4,Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),8519b0057468c4450eb543a2f561bcd0d7cb96e1ce1b95e948e02b309ba6b7ca
src/basic_memory/mcp/tools/sync_status.py,sync_status.py,source_code,10517,2025-07-08T20:39:18.344231,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),73dd73b186eaec8b82e6b17e39a67c27082d24e0653dc4e4b35712bd83b80a22
src/basic_memory/mcp/tools/utils.py,utils.py,source_code,20892,2025-07-30T09:39:36.616253,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),a95004911e276822eba88a3fef15c5b9ba861b1ca9a2ecfe0c1e3fb2f4ef0116
src/basic_memory/mcp/tools/view_note.py,view_note.py,source_code,2499,2025-07-01T08:33:22.080024,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),75d357c72113b1d0394987e521a4158ff09b77b23b08b56cddab5144331b1a68
src/basic_memory/mcp/tools/write_note.py,write_note.py,source_code,6612,2025-07-30T09:39:45.723985,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),771396fb49d397feb5f7e36321d4d233c22c4d1b53414912c849957c6e96fc83
src/basic_memory/models/__init__.py,__init__.py,source_code,333,2025-06-21T00:01:59.437212,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),8f40b876d162f85384690291f1d416106f9d26d750d793414e2260e276c85cd5
src/basic_memory/models/base.py,base.py,source_code,225,2025-06-21T00:01:59.447249,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),e2101727c084d519e32a16f6de53ddf9033b1bf15721d4e8c0c27d6d18b1b295
src/basic_memory/models/knowledge.py,knowledge.py,source_code,7087,2025-06-21T00:01:59.444376,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),005c5f292f1f45ae372aadc48c9080b9fa6d7b854d0bb7ecf587ec843ac1e28d
src/basic_memory/models/project.py,project.py,source_code,2773,2025-07-01T08:33:22.080907,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),a14ad06943aeeff9ae4a5fa2dfc0e1d07ce6085acc02dc20c402c3513b7d9397
src/basic_memory/models/search.py,search.py,source_code,1300,2025-06-21T00:01:59.440923,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),3e143cc38b5a0294af8e1d43a4f841e1c1fd193b76136a68f83159ce19e86646
src/basic_memory/repository/__init__.py,__init__.py,source_code,327,2025-06-21T00:01:59.256363,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),3162bea3c42292accea5ee52c8f6ca4368a8079056034529cfae6d820f84d035
src/basic_memory/repository/entity_repository.py,entity_repository.py,source_code,10405,2025-07-03T18:43:10.082570,Drew Cain,3,Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),e2a8d1eba6c8d64bc61d7168df0fe8c29a670858bf9daeac464a0f440273fae0
src/basic_memory/repository/observation_repository.py,observation_repository.py,source_code,2943,2025-06-21T00:01:59.269646,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),aa132f1cb4a36a84f715afdc40e2ac4f98d83e3eba1974b2b4404cc0b020ca04
src/basic_memory/repository/project_info_repository.py,project_info_repository.py,source_code,338,2025-06-21T00:01:59.252582,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),f172d50182a405643a19b2a3d62a80f4e2b41463c775394eb3b66d7de51ff6df
src/basic_memory/repository/project_repository.py,project_repository.py,source_code,3803,2025-07-30T09:39:45.724344,jope-bm,2,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),9083ba214b2bcaaf98164d9c33cda7add52bc77f7269ecb6e43cdd5088728b7c
src/basic_memory/repository/relation_repository.py,relation_repository.py,source_code,3179,2025-06-21T00:01:59.246745,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),cfb3a8e59cff27e063e91bd00e949647bdd92e4d9fc46edeee3acc6de15e26f4
src/basic_memory/repository/repository.py,repository.py,source_code,15224,2025-06-21T00:01:59.273355,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),3096fe71bf106506cbf86aeafe2aafe0aabbe5a5f6c90a212c8aa1e53e1f171c
src/basic_memory/repository/search_repository.py,search_repository.py,source_code,21936,2025-07-03T18:43:10.082844,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),a972f73d1b71dac5770e8eb3793c6c9ac44e4e792f9dab528f8c4e6c6a80bcaa
src/basic_memory/schemas/__init__.py,__init__.py,source_code,1674,2025-06-21T00:01:59.514555,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),98480815c75379bfafe32d2090e87fa40e73caa19b664fbd5db5ea9528ba58cb
src/basic_memory/schemas/base.py,base.py,source_code,6738,2025-07-01T08:33:22.082193,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),171f7b0c4ab33abef2f7379eb1e3bda950586ce7edff83907fd12255f84e267e
src/basic_memory/schemas/delete.py,delete.py,source_code,1180,2025-06-21T00:01:59.502563,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),50047624af7d58c8f780ffb2a065a51c3dde64492f9534917fc42860813e59fc
src/basic_memory/schemas/directory.py,directory.py,source_code,881,2025-06-21T00:01:59.529023,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),17dfcbac9a91a9bfe43b4f060ca2735cb6f69e16d81b63dd554a397830ff29fe
src/basic_memory/schemas/importer.py,importer.py,source_code,693,2025-07-30T09:39:45.724633,jope-bm,2,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ac33df423ca32b28ce7b6ea9c29d541f8783a86c0c29f78db35163bf93f139cd
src/basic_memory/schemas/memory.py,memory.py,source_code,5833,2025-07-03T18:43:10.083167,Drew Cain,3,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),acb4a953a553feca672c4895798a7d948ec51f922f75b66dd7d55716e3bebed3
src/basic_memory/schemas/project_info.py,project_info.py,source_code,7047,2025-07-01T08:33:22.083248,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),7dc3635297b6e7fe6e3262b2d78da26f7a79a846a4cecd5624f2e4828979cf2c
src/basic_memory/schemas/prompt.py,prompt.py,source_code,3648,2025-06-21T00:01:59.525753,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),4a92157d9a6b413f04e6e3f8d23dc2a417369c729f9703a8de2643ec114f2071
src/basic_memory/schemas/request.py,request.py,source_code,3760,2025-06-21T00:01:59.511789,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),32fe44beb2d99452223ebf1d3a3a3fe105ef92c79885023b71dfd7db30ecc503
src/basic_memory/schemas/response.py,response.py,source_code,6450,2025-07-03T18:43:10.083478,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),5eea4660a2abe48d83ed083d1c2483fdcfb403e0b504f03c14d22f1cae866abb
src/basic_memory/schemas/search.py,search.py,source_code,3657,2025-06-21T00:01:59.522804,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),cb032c0c60102b6b0ed934f995cf9d6bf93aece296d71d537a75e8ae61c75afe
src/basic_memory/services/__init__.py,__init__.py,source_code,259,2025-06-21T00:01:59.655059,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),5c6b7c597ddf5ffd0af4bdfb32ccbc1c5f2794c658206dee43a9945fafe226d8
src/basic_memory/services/context_service.py,context_service.py,source_code,14462,2025-06-21T00:01:59.672086,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (paulmh@gmail.com),e1178b005e6a89f03d6b239e3c6b152aeb30d535a3f280734440a3aec16228f2
src/basic_memory/services/directory_service.py,directory_service.py,source_code,6017,2025-06-21T00:01:59.648501,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),fd838f5ec79033892777b3c8140868f4b57f13e1658d513959524a434b9f959b
src/basic_memory/services/entity_service.py,entity_service.py,source_code,30440,2025-07-03T18:43:10.083956,Paul Hernandez,4,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),7cd5163eca6b8a0772e838c8c869e478166763cd6a2d745b0b9aa5c25a65baee
src/basic_memory/services/exceptions.py,exceptions.py,source_code,390,2025-06-21T00:01:59.668908,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),a158d0af9d1742a9c5ab5f8c34a062948d9286d1c3c72a5abf20e4d547b21e1c
src/basic_memory/services/file_service.py,file_service.py,source_code,10059,2025-06-21T00:01:59.641785,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),8c2ae69c4913438b7d1c5ecbfcce812fbb5d0ea8e3cedcbd8694e8f40cf086f3
src/basic_memory/services/initialization.py,initialization.py,source_code,6715,2025-07-08T20:39:18.344482,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),4dde58b799cf4ac90631e59949b55b3355a93bdf99df0d9c2408c0cea67e10c4
src/basic_memory/services/link_resolver.py,link_resolver.py,source_code,4594,2025-07-01T08:33:22.084908,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),d7efd516cbea753e6b5411def09aeaeb7539f5743487119ecf163c736e138a8c
src/basic_memory/services/project_service.py,project_service.py,source_code,30125,2025-07-30T09:39:45.725079,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),bce95c00aa9a1da0a8c8090ee34b5b1494207f8c99e6c25de4ec43fddc38f6be
src/basic_memory/services/search_service.py,search_service.py,source_code,12782,2025-06-21T00:01:59.665439,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),7392b2d2e7f3ed83c5807855ccd450e0e79c17f254aedee700bce9323a1b5b83
src/basic_memory/services/service.py,service.py,source_code,336,2025-06-21T00:01:59.636167,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),57e77ff20395d3bcc62100e92fe2acaacdd937d977a9fdc764e2b57ff60d4da8
src/basic_memory/services/sync_status_service.py,sync_status_service.py,source_code,7504,2025-07-03T18:43:10.084229,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),0a025d689e8e16f1632872104952105fc904537f3d32bcff592eb1f1dc76fbb7
src/basic_memory/sync/__init__.py,__init__.py,source_code,156,2025-06-21T00:01:59.621137,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),0951e0b981f8e7b876bb6c6833c2af3a29490bbd5726567ea9487c947723623e
src/basic_memory/sync/background_sync.py,background_sync.py,source_code,726,2025-07-08T20:39:18.345062,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),549af64ae91128b76c6df07ef517b82de85ca4ad796be44b5c0141fac01d4513
src/basic_memory/sync/sync_service.py,sync_service.py,source_code,23387,2025-07-01T08:33:22.086507,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),0310b927561370f593980d07773bce641b618b8fbf2d9e3890d174290a0344fc
src/basic_memory/sync/watch_service.py,watch_service.py,source_code,15316,2025-06-26T09:28:51.859209,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),240ba6ac7523575945f4db442b7da3820d26c9605f2d7a2d357c4e35e215f523
src/basic_memory/templates/prompts/continue_conversation.hbs,continue_conversation.hbs,templates,3076,2025-07-01T08:33:22.086792,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),b6bac31d25c0e52d0909b2273285092f4e31bc219107f92ed511cd407b65e992
src/basic_memory/templates/prompts/search.hbs,search.hbs,templates,3098,2025-05-25T10:07:54.520119,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),1f570222c1caa78542d46ac7d8a79407ca467b9bd714fa9bd953e8b72a667820
src/basic_memory/utils.py,utils.py,source_code,8654,2025-07-30T09:39:45.725428,jope-bm,5,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); andyxinweiminicloud (andyxinweimin263@icloud.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
test-int/conftest.py,conftest.py,source_code,8203,2025-07-08T20:39:18.345735,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),7231e1bc76cddc7c94433e853825dc0165b103bedf996c2c24eda6ae32fff5ad
test-int/mcp/test_build_context_validation.py,test_build_context_validation.py,source_code,6469,2025-07-08T20:39:18.346021,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),ee61d6b15cee0194fd74c1bcf9361d5a839f6081c7d571ef081da8fcefe1bbf2
test-int/mcp/test_delete_note_integration.py,test_delete_note_integration.py,source_code,13175,2025-07-08T20:39:18.346366,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),497495249b8bcf0af177d8705c6899875460707697980434e560cfe56f86feb3
test-int/mcp/test_edit_note_integration.py,test_edit_note_integration.py,source_code,19822,2025-07-08T20:39:18.346730,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),9ba704badd05808aee0b5a686b7e250e1c865229ec92dab561cba5287b6f6fc6
test-int/mcp/test_list_directory_integration.py,test_list_directory_integration.py,source_code,14744,2025-07-08T20:39:18.347106,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),2c4336a59de63f17ed252bb52d1330ebca901ad83bfebc9e5aa67f132a3c77c6
test-int/mcp/test_move_note_integration.py,test_move_note_integration.py,source_code,19825,2025-07-08T20:39:18.347344,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),cbb17688d0f9551306a7520b059ace7f7dfba70fc20bf0ec98b1148000d7ad7d
test-int/mcp/test_project_management_integration.py,test_project_management_integration.py,source_code,33175,2025-07-08T20:39:18.347658,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),93a43cd699453a7602a5def839740ba5027ab914eba3e7b66a026860ed6bd567
test-int/mcp/test_project_state_sync_integration.py,test_project_state_sync_integration.py,source_code,7728,2025-07-08T20:39:18.347907,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),80b0f5b5cd359498dcbd3af7dcb6194afa4582d8efb3faa38d28675ee45e0748
test-int/mcp/test_read_content_integration.py,test_read_content_integration.py,source_code,11187,2025-07-08T20:39:18.348233,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),6955dd343b40df088ac79175e52723501d83796335a16e43b7f58e16e757e1b8
test-int/mcp/test_read_note_integration.py,test_read_note_integration.py,source_code,1381,2025-07-08T20:39:18.348463,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),b93050da68d0e9d47d46879a386567f688399e28390f4eb31ee37353dc27514b
test-int/mcp/test_search_integration.py,test_search_integration.py,source_code,14690,2025-07-08T20:39:18.348959,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),e0957ada9dd9b12eae5843a37d241ec9293ca929f18281e31197dae36bff589d
test-int/mcp/test_write_note_integration.py,test_write_note_integration.py,source_code,9472,2025-07-08T20:39:18.349398,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),b2b56fee8351168d0c65640c295d969dc4575d9bea87927b2dc07e591cabdff3
tests/Non-MarkdownFileSupport.pdf,Non-MarkdownFileSupport.pdf,other,106751,2025-02-23T17:31:23.206428,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),4aa96f9d0ee830ef6a1ec92243f302bbe2fa8971b84945f4eb5e276bf1ffde96
tests/Screenshot.png,Screenshot.png,other,190076,2025-02-23T17:31:23.207771,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),dd82612fe013c39810d28ae0f2bbcca6ab2c9925b035d7720bb02493ddf5d0a9
tests/__init__.py,__init__.py,source_code,141,2025-06-21T00:01:46.216456,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),2ac5605e69ad8829e96b3689632536539f1cdd3149a29c1903f25af0793a5d65
tests/api/conftest.py,conftest.py,source_code,1404,2025-06-21T00:01:46.359728,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),ea46cde47a37c1f43fe079e48f5d0de8007155a0187f4445abc4f2ffde9c1791
tests/api/test_async_client.py,test_async_client.py,source_code,1382,2025-07-30T09:39:45.725666,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),a2f96226a75e5cff2326ca48ddccea4915964d83e529f7b99958bc233ccdc31a
tests/api/test_continue_conversation_template.py,test_continue_conversation_template.py,source_code,5152,2025-06-21T00:01:46.390901,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),cca08b0291db0ad693c60d8dc203660021feab46d9eb530be7f67e0ebb52c1d3
tests/api/test_directory_router.py,test_directory_router.py,source_code,9376,2025-06-21T00:01:46.356659,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),428626589f0010512481ba495368b0bf2b9617b22764e588eaa3562e86da4d37
tests/api/test_importer_router.py,test_importer_router.py,source_code,16578,2025-06-21T00:01:46.368070,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),03edf6e7404c7350afe76e54ea2bf0d66f668bcdb49f59702067a67b3694309d
tests/api/test_knowledge_router.py,test_knowledge_router.py,source_code,45771,2025-07-01T08:33:22.090490,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),43a5f91ae1fb9038e65c09701336fbdc4dbf40c8319c94727e6312fda9d6d56e
tests/api/test_management_router.py,test_management_router.py,source_code,6220,2025-06-21T00:01:46.402764,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),f6a3f41f263f10c08281525571e2e39fc9ae818ebb7e9895e3f3f3115ea05677
tests/api/test_memory_router.py,test_memory_router.py,source_code,5555,2025-06-21T00:01:46.399667,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),2b8782015c893081fc67b7f13a7255d4e3dc45b27705a524f94918a339e2d486
tests/api/test_project_router.py,test_project_router.py,source_code,13288,2025-07-30T09:39:45.725847,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),af85d0870069d3831a9214372853994e5d12dc910e37298eb9958f72f6a8bb31
tests/api/test_project_router_operations.py,test_project_router_operations.py,source_code,1812,2025-06-21T00:01:46.381705,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),afd40879de3d7c508cca0feeae3cb7a8f3afcfbb06f59a6104189b1e3291376a
tests/api/test_prompt_router.py,test_prompt_router.py,source_code,5046,2025-06-21T00:01:46.396588,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),9115995b7dd8b44d8a9c06c5e1bbb177618286675a769889e35ac16f26fd9897
tests/api/test_resource_router.py,test_resource_router.py,source_code,13960,2025-06-21T00:01:46.384919,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ad3cb2cabaeab82a7e64253ceede7c1791e2bd70c92f60bc5f3be939292ca22d
tests/api/test_search_router.py,test_search_router.py,source_code,6409,2025-06-21T00:01:46.375427,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (phernandez@basicmachines.co),ba3e3809795e72db9dd9c8c729048bdbbbdb897c2a5aa8b175112b5d4b56d152
tests/api/test_search_template.py,test_search_template.py,source_code,5258,2025-06-21T00:01:46.378721,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),8f0d16a1de947d0466d96afed02e695f7648adac70b9ba99753250068207a686
tests/api/test_template_loader.py,test_template_loader.py,source_code,8035,2025-06-21T00:01:46.406694,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),4fd7c6c4862cc0d877d29244ecdc0b52a0693fc4574a9667663bee36bfd36b62
tests/api/test_template_loader_helpers.py,test_template_loader_helpers.py,source_code,7445,2025-06-21T00:01:46.372114,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),8dd35f11c9b3f2d96ac36263edf4430308728c04c9da543b1cb845b96ab20aa7
tests/cli/conftest.py,conftest.py,source_code,1185,2025-07-01T08:33:22.090848,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c3c73da7ad73224931e1fba4ebd70792221be607bfb1488bb5c9420bba03bdb8
tests/cli/test_cli_tools.py,test_cli_tools.py,source_code,13528,2025-06-21T00:01:46.318964,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),befb8cab50132e26a1b13b82ce8e93a3258282cf157a4230214bfcefeae65102
tests/cli/test_import_chatgpt.py,test_import_chatgpt.py,source_code,6719,2025-07-08T20:39:18.350234,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),df447335545248e2fb2417af33f8cc2f0143bd413a1783e41f89605de305b7c8
tests/cli/test_import_claude_conversations.py,test_import_claude_conversations.py,legal,5028,2025-07-08T20:39:18.350607,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ac4b3b9dfc331fa7fa32a2941c027ff8b6585a94a5ccfaaf0a4affe5cf19c00c
tests/cli/test_import_claude_projects.py,test_import_claude_projects.py,legal,4585,2025-07-08T20:39:18.350885,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7eaab3d491d50ca59c8ba015ecd5740a5feae94d970ee17559c6df9d8558c2cc
tests/cli/test_import_memory_json.py,test_import_memory_json.py,source_code,4891,2025-07-30T09:39:45.726290,jope-bm,3,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),d6734ce059dacf97bc764d848b2e2a6ba52fa96871bc331ec9d2ddc60b766bb6
tests/cli/test_project_commands.py,test_project_commands.py,source_code,6578,2025-07-30T09:39:45.726703,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),51e2ac7ff44b0d1a1db6da406c5c2e6aebceb1b63a1e8d5ab51bbaa834507157
tests/cli/test_project_info.py,test_project_info.py,source_code,3874,2025-07-01T08:33:22.091600,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),0b08950e95a5f276f14c56f6fe99af4d41b8f04548e9b7746f807c5ac4155578
tests/cli/test_status.py,test_status.py,source_code,4160,2025-07-01T08:33:22.091978,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),a1ff89fdac4bf57ba03be92ac79b8ca3210af0b1132d5a2bd0fc0c253fcbf988
tests/cli/test_sync.py,test_sync.py,source_code,3864,2025-07-08T20:43:47.816788,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),77e0f6b42b584a5acfda3c2ff194ff5e71ca57a40cb4484d563f5482bbbb4c0f
tests/cli/test_version.py,test_version.py,source_code,289,2025-06-21T00:01:46.305368,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),db95665178a32d391bd83011d073db269cefba9da8a4dc4d3e392d47bc0e0a8f
tests/conftest.py,conftest.py,source_code,15286,2025-07-08T20:39:18.351368,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),c6f38f103ce58144ffe4562f0c47dad849974e96327f02805e854447e19bc411
tests/importers/test_importer_base.py,test_importer_base.py,source_code,4329,2025-07-08T20:39:00.549594,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),da872a073f2b90fda3c98c9f44cf45884f4f682d91ec1b1f931d42c34eee1939
tests/importers/test_importer_utils.py,test_importer_utils.py,source_code,1827,2025-06-21T00:01:46.184343,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),cbee630c855ceb1de764ac0cdb1d5d781c16cd3a934d67166adc235c98f363d7
tests/markdown/__init__.py,__init__.py,source_code,0,2025-06-21T00:01:46.196570,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
tests/markdown/test_entity_parser.py,test_entity_parser.py,source_code,8669,2025-06-21T00:01:46.206579,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),496fdab6fe164634f8223f827585a4c0dedd30ccea7b0b69dc79004ad0996de2
tests/markdown/test_markdown_plugins.py,test_markdown_plugins.py,source_code,5139,2025-06-21T00:01:46.200759,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),9624d73462aadcd47fb0edd0d87880959a8982eecfa39529f21e3b292c34cb83
tests/markdown/test_markdown_processor.py,test_markdown_processor.py,source_code,5728,2025-06-21T00:01:46.194175,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),35042aa57dd2aeed848c624aa7f69decfb18e83c3b217eca1fdacfc4a10831db
tests/markdown/test_observation_edge_cases.py,test_observation_edge_cases.py,source_code,4295,2025-06-21T00:01:46.209598,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),6f1ab7684bfa8b02af0e0c42b3d7aed91fcd0b1c6288cbc9b6d6943c166979fa
tests/markdown/test_parser_edge_cases.py,test_parser_edge_cases.py,source_code,5142,2025-06-21T00:01:46.213291,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),d511d7d1187e3c1d3a8d3e0ab9efc9e68e84115c46811e7a9dc21eca9a87d520
tests/markdown/test_relation_edge_cases.py,test_relation_edge_cases.py,source_code,3952,2025-06-21T00:01:46.203846,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),f8e2016308f84139342cc37ec6e389ffe52d7eb46f998ee327c7f0d5bba3ad9b
tests/markdown/test_task_detection.py,test_task_detection.py,source_code,401,2025-06-21T00:01:46.191444,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),37fe91a689742033a0eb76723557e31c2a85e591133383b3887572cb714db2a5
tests/mcp/conftest.py,conftest.py,source_code,1761,2025-07-08T20:39:18.351554,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),350b2ca42c52ef76e002deddb65fc0eccb9f8989bd26078ea1c100e3b93bae3f
tests/mcp/test_prompts.py,test_prompts.py,source_code,5989,2025-07-01T08:33:22.093691,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),e3b2ee5b4bc120b5043225ebdbf73eadd71be9c3d9d8e1fdd66a24a8ff11a780
tests/mcp/test_resource_project_info.py,test_resource_project_info.py,source_code,4885,2025-07-01T08:33:22.094085,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),6a043736789b239c8d4ae00d1a5332a0fc3bed4038fe3388970ba97dc7431a93
tests/mcp/test_resources.py,test_resources.py,source_code,549,2025-07-01T08:33:22.094481,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),77a6396b9b8a9d3b3d202e438243ca6178d87fd7680c9fc063ee013f2042aa4c
tests/mcp/test_tool_build_context.py,test_tool_build_context.py,source_code,3714,2025-07-01T08:33:22.094661,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),5f0a39fdb652605335ed54aa91fe994262441bb7ba46f381c46ebca882fc23f2
tests/mcp/test_tool_canvas.py,test_tool_canvas.py,source_code,7997,2025-07-01T08:33:22.094982,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c517bb1f9edc77b76fbeb483dfcb2dd57de9f0b80a10738708bc90cbe388dc9e
tests/mcp/test_tool_delete_note.py,test_tool_delete_note.py,source_code,4208,2025-07-01T08:33:22.095578,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),4cbf3ba4313438651b0608d5b25faf1400f7bd6a78af630351aecd4457800895
tests/mcp/test_tool_edit_note.py,test_tool_edit_note.py,source_code,13503,2025-07-03T18:43:10.084890,Drew Cain,2,Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),dd441969aa54b3739f2d9202d3feaf46aee807ec51e01a13ef41eda52743944f
tests/mcp/test_tool_list_directory.py,test_tool_list_directory.py,source_code,7730,2025-07-01T08:33:22.096737,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),cfbb5c06bcfe74ea60f31051eb9b03ac80b86232b053c188bf3b172132f7c0f5
tests/mcp/test_tool_move_note.py,test_tool_move_note.py,source_code,25851,2025-07-30T09:39:45.727347,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co),c9f95158503fa42e37532aaa35027538fa49cea718d059d570cf547d31f01043
tests/mcp/test_tool_read_content.py,test_tool_read_content.py,source_code,19442,2025-07-30T09:39:45.727526,jope-bm,1,jope-bm (joe@basicmemory.com),1817e32f997b06dbdabf02864d0c70584c1cd80bf1fae8dfbef649de79434bc5
tests/mcp/test_tool_read_note.py,test_tool_read_note.py,source_code,22991,2025-07-30T09:39:45.727746,jope-bm,4,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),4e13ea9ff977525aa62b6a8c22505ffe989329dc3e7d07b71e044cf43ef3ddfd
tests/mcp/test_tool_recent_activity.py,test_tool_recent_activity.py,source_code,3983,2025-07-01T08:33:22.098561,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),45414152cd45334b84df56f653146b7bd2939907548e7245a37207fdccfc4c87
tests/mcp/test_tool_resource.py,test_tool_resource.py,source_code,6782,2025-07-01T08:33:22.098948,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),3916ae1c4d458eee53d2c570b9bbb708ecd617de5a145c3a7552389954bc9195
tests/mcp/test_tool_search.py,test_tool_search.py,source_code,10959,2025-07-03T18:43:10.085177,Drew Cain,3,Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),07839cf8e89d74ba05ec1dc55fa842444c1f0cc3d1587823b0ac3458ad89e87c
tests/mcp/test_tool_sync_status.py,test_tool_sync_status.py,source_code,6331,2025-07-01T08:33:22.100021,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),3f3566df5b9f3c66bb9b3bd77d4c05825480d0e85015305cb1b7ab9429c7a7ec
tests/mcp/test_tool_utils.py,test_tool_utils.py,source_code,9228,2025-07-01T08:33:22.100561,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),b50789f7a78b0169f52dc8bd16e262510ed4a0ac130fce698d4be84af1fe2d31
tests/mcp/test_tool_view_note.py,test_tool_view_note.py,source_code,10004,2025-07-01T08:33:22.101164,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),385535ce791c3ab55db827cbcf27ea25ae85faf3a027f52df4eea052cede7f36
tests/mcp/test_tool_write_note.py,test_tool_write_note.py,source_code,35136,2025-07-30T09:39:45.728137,jope-bm,3,jope-bm (joe@basicmemory.com); Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
tests/repository/test_entity_repository.py,test_entity_repository.py,source_code,15498,2025-06-21T00:01:46.176265,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),8f5d1ff6cff7b640993ff73f463b1e7801a4dd69640fc55fa23dc58b865e9943
tests/repository/test_entity_repository_upsert.py,test_entity_repository_upsert.py,source_code,16983,2025-07-03T18:43:10.085482,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com),ee0ecd6f4ff8b31838bd6de6fb1018af437e02813d8315c06f4e20a6b78a0572
tests/repository/test_observation_repository.py,test_observation_repository.py,source_code,11786,2025-06-21T00:01:46.158862,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),3006d392ad94dcc9b3ae031d63a1af6935624534389dd025de70d4c9e112aa0b
tests/repository/test_project_info_repository.py,test_project_info_repository.py,source_code,1186,2025-06-21T00:01:46.161876,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),dbce7ae7350403cbc37343c2e3e68e4d2255e247006aaa6c495a7ce8bfddea7d
tests/repository/test_project_repository.py,test_project_repository.py,source_code,10511,2025-07-30T09:39:45.728536,jope-bm,2,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),279a3324635b1b515c18003bd1875cf230fef1192cadef9ca426846783717e75
tests/repository/test_relation_repository.py,test_relation_repository.py,source_code,11980,2025-06-21T00:01:46.167567,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),fcdbdf40f7b56145b98eedde5ead64ef6187e859adde48cc09f5a97754757428
tests/repository/test_repository.py,test_repository.py,source_code,5996,2025-06-21T00:01:46.152691,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),3a6d4ca0b7a438a30ae504f5eac22874d4e1a937a4246e90efad46c90f0e1c95
tests/repository/test_search_repository.py,test_search_repository.py,source_code,25471,2025-07-03T18:43:10.086041,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),805b5cc55a53ae9d6e86c0de735c7f38ac9fd92c23194b0150fa3e7f5507a146
tests/schemas/test_memory_url.py,test_memory_url.py,source_code,2000,2025-06-21T00:01:46.346515,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),946fa6c48534f41c8b9cc27bbad164d3e3673a79afa84fbb439fae4cd26c504b
tests/schemas/test_memory_url_validation.py,test_memory_url_validation.py,source_code,9338,2025-07-01T08:33:22.103247,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),7054c3a3cdb8e05d2ffd254ed298908ff3d48a0a3927d960975eae1ab9beeb38
tests/schemas/test_schemas.py,test_schemas.py,source_code,16880,2025-07-03T18:43:10.086337,Drew Cain,3,Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),2c746a00c340f063c160ace67569955a300a294040949695c79fd4ae124fb611
tests/schemas/test_search.py,test_search.py,source_code,3264,2025-06-21T00:01:46.343685,github-actions[bot] (AI Assistant),2,github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),7437775d1b4a61a438cbabe3dbb1becd2adc4dbcc0c24595830c0843fa7a3166
tests/services/test_context_service.py,test_context_service.py,source_code,8833,2025-06-21T00:01:46.446200,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),ab49d21a05d5364e7e8a2f00b07aabe1109b7417698e0acd92792e2cb5f22732
tests/services/test_directory_service.py,test_directory_service.py,source_code,6854,2025-06-21T00:01:46.457258,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),a0c765fb6bd1a75b6ba4592b1df344c48273b6ab03ba6bd15d2b5e840eb2d521
tests/services/test_entity_service.py,test_entity_service.py,source_code,59278,2025-07-03T18:43:10.086674,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),d7d495756faa10b415d705cf26b69d2efbc5f190a834b6767386ff296629ea71
tests/services/test_file_service.py,test_file_service.py,source_code,5243,2025-06-21T00:01:46.460141,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),83e6e9a7584b7baeccbc84865d8c1d3e2a0223e7d2b9c066d3799c289196ab7d
tests/services/test_initialization.py,test_initialization.py,source_code,6939,2025-07-08T20:39:18.351946,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ebb8d11ff37dcb36c4844c68f873c8e0e8aa6ab1b82abb22ee96c4233e6ab287
tests/services/test_link_resolver.py,test_link_resolver.py,source_code,13618,2025-07-01T08:33:22.105766,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),c9fc56d0c3572770e95ca6175c213ed8b44c2a6ddddc298b5662cc2d8f41014e
tests/services/test_project_service.py,test_project_service.py,source_code,28152,2025-07-30T09:39:45.728920,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),430868ed796518937a3b0bed4d8c33be53264a6100d61d54b0745bb2b58bf29a
tests/services/test_project_service_operations.py,test_project_service_operations.py,source_code,4679,2025-06-21T00:01:46.442141,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),d4103b6c5fff7e74ba84b86033537b8522aa60fc75aec4974d52e1dfec68b1b4
tests/services/test_search_service.py,test_search_service.py,source_code,25299,2025-06-21T00:01:46.439133,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),b3e58258db2b727ab8a1792e52fcb038d3a0779bcd1b70f2d295a9d06e5e2513
tests/services/test_sync_status_service.py,test_sync_status_service.py,source_code,9926,2025-07-03T18:43:10.087266,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),00245ca356e33fc7afcd2d42cb5ec082038c95383d738067821cf1e8d23c9a4b
tests/sync/test_sync_service.py,test_sync_service.py,source_code,39659,2025-07-01T08:33:22.107088,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),0609aee9906549f27fc4289b5ac2d46a50e53e12a0615a2701f17fbe9a74e169
tests/sync/test_sync_wikilink_issue.py,test_sync_wikilink_issue.py,source_code,1959,2025-06-21T00:01:46.420370,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),db4b98dd7008a1a26b0fd02b9a2d03bca950b281efc19d98a91b017c500b23a5
tests/sync/test_tmp_files.py,test_tmp_files.py,source_code,5930,2025-06-21T00:01:46.424277,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),cead95a07b29f6c1ab933abe67f9648122f5f33d33753c8e4ab4934af96cbc25
tests/sync/test_watch_service.py,test_watch_service.py,source_code,14076,2025-06-26T09:28:51.860679,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),e324a4127f8bfe59798f3a08125488c701e88239b7482d87a0394b91c55b893e
tests/sync/test_watch_service_edge_cases.py,test_watch_service_edge_cases.py,source_code,2169,2025-06-21T00:01:46.409830,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),b87c5015330e9b551630aab7ef95ac1e7663f0ce46e912d8155b319e139559aa
tests/test_config.py,test_config.py,source_code,3680,2025-07-03T18:43:10.087558,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),6a246431cff739274efda895dfa28f38710289a73e645312f5fa05fce0885ec8
tests/test_db_migration_deduplication.py,test_db_migration_deduplication.py,source_code,6166,2025-07-08T20:39:18.352690,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com),ab768e061531ca2edcd598c101b5d884e549f90c7a4b305a23713a199d263fbb
tests/utils/test_file_utils.py,test_file_utils.py,source_code,6199,2025-06-21T00:01:46.219673,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),4615bb20b92b8a79d9e086301f852b34c3360f17ecc209920d68528268ddeed4
tests/utils/test_parse_tags.py,test_parse_tags.py,source_code,1691,2025-06-21T00:01:46.223400,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),b83afdf18dac8b3411bd0fab1301683217d3d1abceaf2d22c09e79c709efd8eb
tests/utils/test_permalink_formatting.py,test_permalink_formatting.py,source_code,4193,2025-06-21T00:01:46.225738,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),d998a4ca846c78679728a918b6f71df67c30b6961ede3cffa609f2cf6ad160eb
tests/utils/test_utf8_handling.py,test_utf8_handling.py,source_code,5791,2025-06-21T00:01:46.228483,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),50ec792e572af51cd2d996d4ddacbcfd3bbd79aa928818a90c42117451ea829f
tests/utils/test_validate_project_path.py,test_validate_project_path.py,source_code,15346,2025-07-30T09:39:45.729224,jope-bm,1,jope-bm (joe@basicmemory.com),27a4bf2a9d277e6cd773619e5241b20175d211ec60c284361bec404fd99143f3
uv.lock,uv.lock,other,232710,2025-07-30T09:39:36.619155,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),caa1e3f6e66464b884a78cab77df2fe303fa3c0dc573be0196474b6d3c150581
1 path name category size_bytes modified_time primary_author contributor_count contributors_list sha256_hash
2 .claude/commands/release/beta.md beta.md documentation 3103 2025-07-01T08:33:22.037438 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 345f06e3f304470a8892e96979355919c8e5d8f4212ebbe543c3272fd15a5cbe
3 .claude/commands/release/changelog.md changelog.md documentation 4648 2025-07-03T18:43:10.075727 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) ea2484352f4f881aa71f546dcf84b0882d60c96673a88406aa2f7e12a282a1f4
4 .claude/commands/release/release-check.md release-check.md documentation 3344 2025-07-01T08:33:22.040060 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 7dd41a40e95c89153936c4ea60a3c989eccd5973fff9f6caef156de82f12bd04
5 .claude/commands/release/release.md release.md documentation 2925 2025-07-01T08:33:22.043674 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 0e4afd788fcf85fbe46094452e9b92a4290c3e23702283e72ee56aa9288476e5
6 .claude/commands/test-live.md test-live.md documentation 18720 2025-07-03T18:43:10.076403 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 21a9edeefb3e5673d833151a2fd0464087c0f0a9d056fdd7fca474c1d177d6fc
7 .dockerignore .dockerignore other 623 2025-07-01T08:33:22.048301 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) b3079bffad89d07186c9166725075524ffc07ceea6dc1d53fdbea6dca9585684
8 .github/ISSUE_TEMPLATE/bug_report.md bug_report.md documentation 967 2025-03-01T14:22:50.968994 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 0d34443ddda84a5e9726c8268083c9646d2cc64ff9c5ebf56c89587cef4c7706
9 .github/ISSUE_TEMPLATE/config.yml config.yml configuration 374 2025-03-01T14:23:26.936836 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) f4e21bb9b7f053509b6c08548a2649a5d62f44f0106810aa8c915d2f29acc623
10 .github/ISSUE_TEMPLATE/documentation.md documentation.md documentation 557 2025-03-01T14:23:40.020117 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 78f80a6b9a2b954695f74a847a068e0b780da6020572401c13c931555a4a9db5
11 .github/ISSUE_TEMPLATE/feature_request.md feature_request.md documentation 786 2025-03-01T14:23:06.344081 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) cee834de442221d53f3d2eeb85b81f3a641b3a7cb587ef8a169452305007439d
12 .github/dependabot.yml dependabot.yml configuration 529 2025-03-15T10:40:16.936258 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 8c6c2ef9a1417da63adb49c70f45524129bd5c46bbd7452b6b97cfe65205f89d
13 .github/workflows/claude.yml claude.yml legal 4628 2025-07-03T18:43:10.076958 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) d026f1756310781b85abc491b454cc31b52dfce4b951cdf8a4a555b6b047604c
14 .github/workflows/dev-release.yml dev-release.yml configuration 1405 2025-06-03T08:31:42.915367 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 58bcfc9e11e210e02dee76aabe7d1378da4edafb7f61857049ee6ccee9d45ffa
15 .github/workflows/docker.yml docker.yml configuration 1621 2025-07-01T08:33:22.049870 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c918a86f2b16ebb45182a73c45272bcd6cea7022cc6e0eaeb2b2a24d8eebfe4d
16 .github/workflows/pr-title.yml pr-title.yml configuration 887 2025-02-17T16:29:35.733646 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) b6df62a20235496feba4d9419c85d6e8446c4d447ad69e7f57b51cc8953f68f4
17 .github/workflows/release.yml release.yml configuration 2479 2025-07-03T18:43:10.077261 Drew Cain 2 Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co) 163307a99e2f3d317af6ae8927e1537654d88bf574a6958ac0bcd2d4de266b2a
18 .github/workflows/test.yml test.yml configuration 1426 2025-07-01T08:33:22.054430 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) ab09084a11be8adfc83fc6285c652fbe44a4584aa7d7d3658fcf0c57112d1640
19 .gitignore .gitignore other 566 2025-07-01T08:33:22.055006 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 358658b0faa8c3145e539421deba4ad0bac4a8ea2e608b2c2f867a822c67b36f
20 .python-version .python-version other 5 2024-12-02T16:41:37.012830 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 7b55f8e67b5623c4bef3fa691288da9437d79d3aba156de48d481db32ac7d16d
21 CHANGELOG.md CHANGELOG.md documentation 53647 2025-07-06T10:34:45.550847 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); semantic-release (semantic-release) 0b165eb18975ff253cde08f4687b7808ac6ce63b6d8c10912c495a76c9058d1a
22 CITATION.cff CITATION.cff other 302 2025-02-17T16:29:35.735146 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) bc4878cf6f80bb64655f3f93a5821ffe0924ad8311c784b5f81a36093fcffdda
23 CLA.md CLA.md legal 1342 2025-03-01T14:12:38.435132 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) c238c7ff4f2b8451c6bba1bbacd10b04fb7d41d9a9cd76a62644d8193791d169
24 CLAUDE.md CLAUDE.md legal 12310 2025-07-03T18:43:10.078147 Drew Cain 4 Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); Ikko Eltociear Ashimine (eltociear@gmail.com) 751f10c1a9a9c0ba2054d9c9cd36cf0989d6a347491fd505bb6504ee74b12900
25 CODE_OF_CONDUCT.md CODE_OF_CONDUCT.md documentation 509 2025-02-17T16:29:35.735238 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) b276b464e85eb1e5d9f09d90bba9573508a7bf81d2eeb38d0f25bd9f2fa66198
26 CONTRIBUTING.md CONTRIBUTING.md documentation 7329 2025-07-30T09:39:36.607158 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co) ca822fe39cc529bfc3822d317ab8a20fd141ec3ecb8c20de9e2eca3edce1c282
27 Dockerfile Dockerfile other 856 2025-07-01T08:33:22.056908 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) c45501905423990e31ffdb8ae4e976eca6423c6784905c1036bcc7795b70feef
28 LICENSE LICENSE legal 34523 2024-12-02T16:41:20.739392 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 8486a10c4393cee1c25392769ddd3b2d6c242d6ec7928e1414efff7dfb2f07ef
29 README.md README.md documentation 16261 2025-07-03T18:43:10.078281 Drew Cain 6 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Jason Noble (github+jasonn@jasonnoble.org); Marc Baiza (43151891+mbaiza27@users.noreply.github.com); Matias Forbord (codeluggage@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 2c4b82b30f49ab465617034fda999157450ed168f8e097fe8e9ca7ac65a197a7
30 SECURITY.md SECURITY.md documentation 303 2025-03-12T16:04:01.989927 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 96932268b8fe737577941b49e9dff5ff8ad59c11cc3f9a016989589ef5c98c1f
31 docker-compose.yml docker-compose.yml configuration 2534 2025-07-01T08:33:22.059281 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 4a9fdfd2f0d42b148fe021eee77fd5e772c7ba9c2fe5d0cc310c8c7a64257417
32 docs/AI Assistant Guide.md AI Assistant Guide.md documentation 16423 2025-07-01T08:33:22.060491 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c717869a3d356852077026591364ecb0589a6d53f9764af027c57d142ea7ff55
33 docs/Docker.md Docker.md documentation 9088 2025-07-01T08:33:22.060976 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) e13d3f50148353046b52d9d493986880f76f2914ef4efe1a759b2cc9d10913a4
34 justfile justfile other 5496 2025-07-30T09:39:36.608008 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com) a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
35 llms-install.md llms-install.md documentation 2307 2025-06-29T14:19:28.826375 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 674105eb85c8f1d59fc2ddc6840f2a2a3e293358687a305c37dffc8144304f97
36 memory.json memory.json configuration 90075 2025-06-29T14:19:28.827172 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 22d5eee995ca0548b7d9dd152f9a3690c42a514cbf38fea750b3ed2a17dd99c5
37 pyproject.toml pyproject.toml configuration 3279 2025-07-30T09:39:36.608791 Paul Hernandez 4 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); semantic-release (semantic-release) 428a5d64d4555dc7cd2a81b89a3444bdb1d2f3017257fbc9160bd0ae982718e1
38 smithery.yaml smithery.yaml configuration 433 2025-03-11T16:36:03.389716 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 63f13499cf4fee0751b5005f5bd85597dc1c7f9a881f4ec8147cc23e95e75c2d
39 src/basic_memory/__init__.py __init__.py source_code 256 2025-07-06T10:34:45.551291 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@gmail.com); semantic-release (semantic-release) c946490ab9d64957d25df37f721392024916f8a81ed838f70a8e938b1c2637db
40 src/basic_memory/alembic/alembic.ini alembic.ini configuration 3733 2025-02-23T17:31:23.198433 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 20466c9c5f026db66793006bebb2f328a3686c7bb34da40d52f33c3eca29e717
41 src/basic_memory/alembic/env.py env.py source_code 2838 2025-07-08T20:39:18.336650 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) e241d987eadfcd5011cbd9ddbecb833d306de87937759d81c08d37d04a6906b0
42 src/basic_memory/alembic/migrations.py migrations.py source_code 718 2025-06-21T00:01:59.613806 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 96b8873d70dd04b48d5c45b7413a54d1224ab9577557ef0dad5929377a9fb144
43 src/basic_memory/alembic/script.py.mako script.py.mako other 635 2025-02-17T16:29:35.739659 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 304a8bfb6a804e5493f5300e79882c70c9f5bb2e87512f4d16f0e097dddd323f
44 src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py 3dae7c7b1564_initial_schema.py source_code 4363 2025-06-21T00:01:59.595762 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 9536d69409ddd5eb3bc54f7d0e82607da45ed7f2ad7bc4cbf7cae2a9e28657cd
45 src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py 502b60eaa905_remove_required_from_entity_permalink.py source_code 1840 2025-06-21T00:01:59.604717 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 93ac584e660f33d468b3eec203b070641298c282bf82655d0beda7f050237681
46 src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py 5fe1ab1ccebe_add_projects_table.py source_code 4379 2025-06-21T00:01:59.601299 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) d82098f5aca3cdbada60c7229ea4ac262f527349eed9ef9e864509bacfaccf7e
47 src/basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py 647e7a75e2cd_project_constraint_fix.py source_code 4210 2025-07-01T08:33:22.063463 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 604ac5908a5976272f52297866d13abb14a99390590935d9fd37cf13e32049fa
48 src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py b3c3938bacdb_relation_to_name_unique_index.py source_code 1428 2025-06-21T00:01:59.598551 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 46c1b2990cdf4575752d234a8b28b494c8a54f15b5360c12f6347aef27b66a92
49 src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py cc7172b46608_update_search_index_schema.py source_code 3679 2025-06-21T00:01:59.610909 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 9036af47d42ac7dc12bb93f7a9de1266aff0688b031b550c4e0d92983a24b4c5
50 src/basic_memory/api/__init__.py __init__.py source_code 72 2025-06-21T00:01:59.579981 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) c02a63fb6d63d43d0acca97d425eae9cb055158d0ad6e1a9fc57926512adaa99
51 src/basic_memory/api/app.py app.py source_code 2897 2025-07-08T20:39:18.337081 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ad673ac2c09410af5830f6afdffaa28b0040480dacd52ff01750b8b2c066e8cf
52 src/basic_memory/api/routers/__init__.py __init__.py source_code 398 2025-06-21T00:01:59.549416 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 4443b908a43dea8e6fb4658009cb08c48a56c9b21449e29773cdd159b59cf014
53 src/basic_memory/api/routers/directory_router.py directory_router.py source_code 2054 2025-06-21T00:01:59.567371 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ac1407beec1f7d43a4d222af704b3642559c960bebf2eaf6e1ffe91f7fac5514
54 src/basic_memory/api/routers/importer_router.py importer_router.py source_code 4513 2025-06-21T00:01:59.561600 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) c45502a2b90f5a8f00174c9ad14adc2e65cd7fc0a33d9740a9d750207f0f3bea
55 src/basic_memory/api/routers/knowledge_router.py knowledge_router.py source_code 9738 2025-07-01T08:33:22.064119 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) e1d0ffb4fa5c246582ba844a11b417092de1a173567be55b7060bbc55fbc5681
56 src/basic_memory/api/routers/management_router.py management_router.py source_code 2730 2025-07-08T20:39:18.337438 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) cdbce294dcec6146c56c4dae15744cdf77039fd21b23eef7cbc0b5f9bfb5f4ee
57 src/basic_memory/api/routers/memory_router.py memory_router.py source_code 3003 2025-07-01T08:33:22.064510 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6bd0a7c775e0c1290efb6001173237c0cdcfa0c1b1bb27c9145a7b35f1596a97
58 src/basic_memory/api/routers/project_router.py project_router.py source_code 8444 2025-07-30T09:39:45.721369 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6539c69f1d506c65d14cc2c151876b19057f37d84d51a9e6f464ed47a4692648
59 src/basic_memory/api/routers/prompt_router.py prompt_router.py source_code 9948 2025-07-01T08:33:22.065221 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) e30c6aebe35112054933c37d0b462c3750005030fc9e44c23b35b2cd2a93485c
60 src/basic_memory/api/routers/resource_router.py resource_router.py source_code 8058 2025-06-21T00:01:59.570399 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 584244a84698ff24ca8f9f94fab5b891740a51c25f972920c08ebf83f478d5c9
61 src/basic_memory/api/routers/search_router.py search_router.py source_code 1226 2025-06-21T00:01:59.543020 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 183eb68e50904e22ff54db1d89b8be6f57fa1f8d0a096a3d497d8297b607e105
62 src/basic_memory/api/routers/utils.py utils.py source_code 5159 2025-07-03T18:43:10.079143 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 9e60f57da24e1dc9d64236c26a7a2353003dc618a77fbeb853c494aa3357a57c
63 src/basic_memory/api/template_loader.py template_loader.py source_code 8607 2025-06-21T00:01:59.576132 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 7b16d3797c89460c8b1664a335eae8c634fb5f60d6166d97e6a5156b776b6d83
64 src/basic_memory/cli/__init__.py __init__.py source_code 33 2025-06-21T00:01:59.456735 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 6ab70a2c05910e13c3ef1e6df34325be265e633c076741998a0cb2dcd295a069
65 src/basic_memory/cli/app.py app.py source_code 2268 2025-07-08T20:39:18.337708 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) f710670380d707c4458ad881f7a25bb3c5cdb2bcff59f139f37421264fe8f2f8
66 src/basic_memory/cli/commands/__init__.py __init__.py source_code 393 2025-07-08T20:39:18.338070 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) de8a23702f98fb844fa9f7fdbedc16ce24ff4f8baf05589c2f4a521cd8a55645
67 src/basic_memory/cli/commands/db.py db.py source_code 1480 2025-07-08T20:39:18.338326 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 704a1096d80ab9d12e247d029fe6223e935a0d0ceee7e615c020f46a720828e0
68 src/basic_memory/cli/commands/import_chatgpt.py import_chatgpt.py source_code 2856 2025-07-08T20:39:18.338787 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 8957cca3acab6351335624a518bdc19d956487e93d86dd1b6c2309e9d5850ae5
69 src/basic_memory/cli/commands/import_claude_conversations.py import_claude_conversations.py legal 2946 2025-07-08T20:39:18.339053 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7bc97838732bf00f4fb4a80e3ba4fdfbce8971ae85cc2ac902c3b3a3e110ae57
70 src/basic_memory/cli/commands/import_claude_projects.py import_claude_projects.py legal 2891 2025-07-08T20:39:18.339310 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6321577075801c99ad47a0cdc13b5aa3c9ca102a05ca8f06ae2a51125a8c43bc
71 src/basic_memory/cli/commands/import_memory_json.py import_memory_json.py source_code 3013 2025-07-30T09:39:45.721637 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7ea193f6720b2672290ad16c79a143a31d88a1d567838f12b9ebf9110a7c0338
72 src/basic_memory/cli/commands/mcp.py mcp.py source_code 2593 2025-07-08T20:39:18.340025 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 3e1be3d27b18ef4743204b7cf8a37fbc2a1a91fc1636c468e08cefcd8597bac6
73 src/basic_memory/cli/commands/project.py project.py source_code 13836 2025-07-30T09:39:45.721838 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) af3e6f30410ab48355f4b1a46aaa3aa5423cb0a0490f51447db1d25e09f39916
74 src/basic_memory/cli/commands/status.py status.py source_code 5809 2025-07-08T20:39:18.340324 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) b6d0ea237d714d054f69b24a2058beba74e224a2fa4a80a525d62a2aa2ea2d70
75 src/basic_memory/cli/commands/sync.py sync.py source_code 8213 2025-07-08T20:39:18.340627 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 703b3e73c4c33850c27f6f4c07abbf5d4ce5dc43f706bf0c43264bbb45f8b213
76 src/basic_memory/cli/commands/tool.py tool.py source_code 9540 2025-07-01T08:33:22.070903 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 9b2fa400b9f7921bf55b602f8bbdfa36b1ec7e4a5bc8fe7b9838b92e31f0a9ed
77 src/basic_memory/cli/main.py main.py source_code 465 2025-07-08T20:39:18.340868 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7a405b12bff98e319968526238ae15859df0362bba5a3857562fecca47b5c70d
78 src/basic_memory/config.py config.py source_code 12487 2025-07-30T09:39:45.722031 jope-bm 5 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
79 src/basic_memory/db.py db.py source_code 7428 2025-07-08T20:39:18.341550 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 25e053b0b3f9e8fa823b05fc099001efe8a3a4f6e0f80728e5079ba45aa406d8
80 src/basic_memory/deps.py deps.py source_code 12144 2025-07-08T20:39:18.341870 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) bce28cd9ca549b8afce0bc689cc1fb2dc80cd5b929f85114aa682bb8ae82411d
81 src/basic_memory/file_utils.py file_utils.py source_code 6700 2025-06-21T00:01:59.587200 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 79ac5328b2c46d3232fcc6ff22ffc39ade085c0252ad91958be2a7ae9c9c8b71
82 src/basic_memory/importers/__init__.py __init__.py source_code 795 2025-06-21T00:01:59.295471 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 0537015bdecfded85cb166b9c3db50b2f3aef329c70e0c36fbcb4f824099a21f
83 src/basic_memory/importers/base.py base.py source_code 2531 2025-06-21T00:01:59.305335 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 6b0c1efd4f827f348834aa0cea2ae8eebbb842a2e5b1f5f3747ced0ef79b9f13
84 src/basic_memory/importers/chatgpt_importer.py chatgpt_importer.py source_code 7372 2025-06-21T00:01:59.308956 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) dfa540b196ab23b5c4e6bfcac4da567873351cf7c78fa35f4c3b87e84c58e218
85 src/basic_memory/importers/claude_conversations_importer.py claude_conversations_importer.py legal 5725 2025-06-21T00:01:59.288540 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) a7bc9e872f4f81ce5f79fe9dd1a6fd0f00a6f020a2cb2664184a97f14eeb1dbc
86 src/basic_memory/importers/claude_projects_importer.py claude_projects_importer.py legal 5389 2025-06-21T00:01:59.291737 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) a452675fd9bb18ebf64eb4bd7f69ccd7e993b617931015a3c4ab700d67493863
87 src/basic_memory/importers/memory_json_importer.py memory_json_importer.py source_code 4631 2025-07-30T09:39:45.722316 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) bc7d045299f17ed9ad5cebff7b1423250ec28a11130e47a0ac48d3ab82bdeafc
88 src/basic_memory/importers/utils.py utils.py source_code 1792 2025-06-21T00:01:59.298428 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) ee7e22fd4812362394f62ed8944abe80738c1e3ab88131faf639f4a8ccfd6c89
89 src/basic_memory/markdown/__init__.py __init__.py source_code 501 2025-06-21T00:01:59.316337 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 0ddce2a025ad0e729aab4e411d82e02ffefc15ac041cba4b5e7a7e90f4957c87
90 src/basic_memory/markdown/entity_parser.py entity_parser.py source_code 4516 2025-06-21T00:01:59.321461 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 1b0d1177358645ccbadd170b3f62760dc9bd838d38c741978ab0da5836234d68
91 src/basic_memory/markdown/markdown_processor.py markdown_processor.py source_code 4968 2025-06-21T00:01:59.325241 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 4b99f2ebdceed9d96a3bbb562682eba4b4b383c7a64080eaec3bbba25a4952c9
92 src/basic_memory/markdown/plugins.py plugins.py source_code 6639 2025-06-21T00:01:59.312733 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 82d2332918e866ccaf06a2e954d9eb9b397f71b4d9e591a7f2472e5f1423464a
93 src/basic_memory/markdown/schemas.py schemas.py source_code 1896 2025-06-21T00:01:59.329982 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 7b2c580abd615725a62267257b46ac13922dfc30fa01192a681658bb528ae67e
94 src/basic_memory/markdown/utils.py utils.py source_code 3410 2025-07-03T18:43:10.079889 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 1b757f0d06e60e3ea276c0b2ea44fe1a156a895e093c1e607d6286e702bf4ae4
95 src/basic_memory/mcp/__init__.py __init__.py source_code 35 2025-06-21T00:01:59.404757 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 76c0ce84aaa361e21b0942db1c8c5f708b536eab9d12e120d4da7ce9eab41844
96 src/basic_memory/mcp/async_client.py async_client.py source_code 925 2025-07-30T09:39:45.722547 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 6531f4387f30a30a322197ff51d6eacae4b25a58c648095931b3d1145d1da303
97 src/basic_memory/mcp/project_session.py project_session.py source_code 4203 2025-07-08T20:39:18.342906 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 4da403ec93dec9063eeb8b05246e3501740d162cc77a067d3ce54ba43d690819
98 src/basic_memory/mcp/prompts/__init__.py __init__.py source_code 615 2025-07-08T20:39:18.343263 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) f8197d0e08f64c3f4f50b8f38203ea5eebcf123582472ed2f58834de1dbe53b0
99 src/basic_memory/mcp/prompts/ai_assistant_guide.py ai_assistant_guide.py source_code 821 2025-06-21T00:13:53.262832 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) f13239c4e6e2455730bfac3d6f2d71407957d3086fc84efe2c6b22a833114c58
100 src/basic_memory/mcp/prompts/continue_conversation.py continue_conversation.py source_code 1998 2025-06-21T00:13:53.263309 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) aec9a50b657b7bb1ba0c02b42bcdb9bc5b0f2a0b1143bd361c5ce7ea59076833
101 src/basic_memory/mcp/prompts/recent_activity.py recent_activity.py source_code 3311 2025-07-01T08:33:22.073986 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) d2fd5cddbd927430f15d5b85f1e3a3368a18cb4e2e4587a5d29749d2b9e0830e
102 src/basic_memory/mcp/prompts/search.py search.py source_code 1692 2025-06-21T00:13:53.264093 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 9dbf3c319cbdb5d5bf32608b51522d8ae92b2dd6f7c441d62efd0954b525738a
103 src/basic_memory/mcp/prompts/utils.py utils.py source_code 5431 2025-06-21T00:01:59.425042 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 55a72b6eac18b724a9225608aca1e8e6cea3b684ccb1c609aab1511f7ce90ba4
104 src/basic_memory/mcp/resources/ai_assistant_guide.md ai_assistant_guide.md documentation 14777 2025-03-28T19:12:38.653627 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) aa76160e46256fe2662ae3a86799659916acfede1d5835c1fe2f0b136efb2e0b
105 src/basic_memory/mcp/resources/project_info.py project_info.py source_code 1906 2025-06-21T00:13:53.264918 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 2dc5244f1e225c17d4e8ba784d5721efc3aa2e8a5b3b2e258f22a77ebe155eca
106 src/basic_memory/mcp/server.py server.py source_code 1248 2025-07-08T20:39:18.343419 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 0a910cae27d61ea923e90fbe2d4b5c7cacf3b29d3e156f0b7f77872ab973c761
107 src/basic_memory/mcp/tools/__init__.py __init__.py source_code 1619 2025-07-03T18:43:10.080029 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co) 872b771dd52ec3b763645a2baf6e10a70f049ce3106830a6d3f053b3e09a5fe6
108 src/basic_memory/mcp/tools/build_context.py build_context.py source_code 4611 2025-07-03T18:43:10.080426 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 724280b77b8f5f3e61cd3fdeebc3ee66e2bcfedaaea3638e6a2e2e33fcb1978e
109 src/basic_memory/mcp/tools/canvas.py canvas.py source_code 3738 2025-07-01T08:33:22.076204 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) db617d1bd81f3dbfa5f22d41e6b6b825afe1f73618f37acf63d9830390b98246
110 src/basic_memory/mcp/tools/delete_note.py delete_note.py source_code 7346 2025-07-01T08:33:22.076726 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) b52c9173f5600662f255e7a70a5c17d5293ef8b29c19a8403334d7da62b65c8b
111 src/basic_memory/mcp/tools/edit_note.py edit_note.py source_code 13570 2025-07-01T08:33:22.077181 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) ab8c7e7fbfa3fe5fb0ce6d7bf805454f5fd6182a340aae25237b1e6127b6d5a6
112 src/basic_memory/mcp/tools/list_directory.py list_directory.py source_code 5236 2025-06-21T00:13:53.267453 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) f85c43b02aeee580f4d8ce2a9100c0bab1095b245a0bb608e1847ace0d1ab51f
113 src/basic_memory/mcp/tools/move_note.py move_note.py source_code 17541 2025-07-30T09:39:45.722919 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 5ef27d9baaebc2c5656fc49c4798a4e4e40a70b6cd9d1e761dbcae021bad558c
114 src/basic_memory/mcp/tools/project_management.py project_management.py source_code 12944 2025-07-06T10:34:45.552403 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co) cdac736d65129f689a85c6b82f8e043bc84a31657ead7a8331771171eeaa860f
115 src/basic_memory/mcp/tools/read_content.py read_content.py source_code 9125 2025-07-30T09:39:45.723469 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 96a13addac507fd874394dfa2e1e5ed71af5eb89d0872c1d68cacf9cac3f8724
116 src/basic_memory/mcp/tools/read_note.py read_note.py source_code 8132 2025-07-30T09:39:45.723828 jope-bm 5 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) dff53ce02b16d9c5fca315b3f09bb70867a89d614b0ef3f0548dce87978048ee
117 src/basic_memory/mcp/tools/recent_activity.py recent_activity.py source_code 4833 2025-06-21T00:13:53.269120 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 5d58cd2402679b1bf3c7dfcbb3503e40e776c9347ba499524d3b91c528af98de
118 src/basic_memory/mcp/tools/search.py search.py source_code 15883 2025-07-03T18:43:10.081557 Drew Cain 4 Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 8519b0057468c4450eb543a2f561bcd0d7cb96e1ce1b95e948e02b309ba6b7ca
119 src/basic_memory/mcp/tools/sync_status.py sync_status.py source_code 10517 2025-07-08T20:39:18.344231 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 73dd73b186eaec8b82e6b17e39a67c27082d24e0653dc4e4b35712bd83b80a22
120 src/basic_memory/mcp/tools/utils.py utils.py source_code 20892 2025-07-30T09:39:36.616253 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) a95004911e276822eba88a3fef15c5b9ba861b1ca9a2ecfe0c1e3fb2f4ef0116
121 src/basic_memory/mcp/tools/view_note.py view_note.py source_code 2499 2025-07-01T08:33:22.080024 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 75d357c72113b1d0394987e521a4158ff09b77b23b08b56cddab5144331b1a68
122 src/basic_memory/mcp/tools/write_note.py write_note.py source_code 6612 2025-07-30T09:39:45.723985 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 771396fb49d397feb5f7e36321d4d233c22c4d1b53414912c849957c6e96fc83
123 src/basic_memory/models/__init__.py __init__.py source_code 333 2025-06-21T00:01:59.437212 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 8f40b876d162f85384690291f1d416106f9d26d750d793414e2260e276c85cd5
124 src/basic_memory/models/base.py base.py source_code 225 2025-06-21T00:01:59.447249 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) e2101727c084d519e32a16f6de53ddf9033b1bf15721d4e8c0c27d6d18b1b295
125 src/basic_memory/models/knowledge.py knowledge.py source_code 7087 2025-06-21T00:01:59.444376 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 005c5f292f1f45ae372aadc48c9080b9fa6d7b854d0bb7ecf587ec843ac1e28d
126 src/basic_memory/models/project.py project.py source_code 2773 2025-07-01T08:33:22.080907 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) a14ad06943aeeff9ae4a5fa2dfc0e1d07ce6085acc02dc20c402c3513b7d9397
127 src/basic_memory/models/search.py search.py source_code 1300 2025-06-21T00:01:59.440923 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 3e143cc38b5a0294af8e1d43a4f841e1c1fd193b76136a68f83159ce19e86646
128 src/basic_memory/repository/__init__.py __init__.py source_code 327 2025-06-21T00:01:59.256363 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 3162bea3c42292accea5ee52c8f6ca4368a8079056034529cfae6d820f84d035
129 src/basic_memory/repository/entity_repository.py entity_repository.py source_code 10405 2025-07-03T18:43:10.082570 Drew Cain 3 Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) e2a8d1eba6c8d64bc61d7168df0fe8c29a670858bf9daeac464a0f440273fae0
130 src/basic_memory/repository/observation_repository.py observation_repository.py source_code 2943 2025-06-21T00:01:59.269646 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) aa132f1cb4a36a84f715afdc40e2ac4f98d83e3eba1974b2b4404cc0b020ca04
131 src/basic_memory/repository/project_info_repository.py project_info_repository.py source_code 338 2025-06-21T00:01:59.252582 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) f172d50182a405643a19b2a3d62a80f4e2b41463c775394eb3b66d7de51ff6df
132 src/basic_memory/repository/project_repository.py project_repository.py source_code 3803 2025-07-30T09:39:45.724344 jope-bm 2 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 9083ba214b2bcaaf98164d9c33cda7add52bc77f7269ecb6e43cdd5088728b7c
133 src/basic_memory/repository/relation_repository.py relation_repository.py source_code 3179 2025-06-21T00:01:59.246745 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) cfb3a8e59cff27e063e91bd00e949647bdd92e4d9fc46edeee3acc6de15e26f4
134 src/basic_memory/repository/repository.py repository.py source_code 15224 2025-06-21T00:01:59.273355 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 3096fe71bf106506cbf86aeafe2aafe0aabbe5a5f6c90a212c8aa1e53e1f171c
135 src/basic_memory/repository/search_repository.py search_repository.py source_code 21936 2025-07-03T18:43:10.082844 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) a972f73d1b71dac5770e8eb3793c6c9ac44e4e792f9dab528f8c4e6c6a80bcaa
136 src/basic_memory/schemas/__init__.py __init__.py source_code 1674 2025-06-21T00:01:59.514555 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 98480815c75379bfafe32d2090e87fa40e73caa19b664fbd5db5ea9528ba58cb
137 src/basic_memory/schemas/base.py base.py source_code 6738 2025-07-01T08:33:22.082193 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 171f7b0c4ab33abef2f7379eb1e3bda950586ce7edff83907fd12255f84e267e
138 src/basic_memory/schemas/delete.py delete.py source_code 1180 2025-06-21T00:01:59.502563 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 50047624af7d58c8f780ffb2a065a51c3dde64492f9534917fc42860813e59fc
139 src/basic_memory/schemas/directory.py directory.py source_code 881 2025-06-21T00:01:59.529023 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 17dfcbac9a91a9bfe43b4f060ca2735cb6f69e16d81b63dd554a397830ff29fe
140 src/basic_memory/schemas/importer.py importer.py source_code 693 2025-07-30T09:39:45.724633 jope-bm 2 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ac33df423ca32b28ce7b6ea9c29d541f8783a86c0c29f78db35163bf93f139cd
141 src/basic_memory/schemas/memory.py memory.py source_code 5833 2025-07-03T18:43:10.083167 Drew Cain 3 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) acb4a953a553feca672c4895798a7d948ec51f922f75b66dd7d55716e3bebed3
142 src/basic_memory/schemas/project_info.py project_info.py source_code 7047 2025-07-01T08:33:22.083248 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7dc3635297b6e7fe6e3262b2d78da26f7a79a846a4cecd5624f2e4828979cf2c
143 src/basic_memory/schemas/prompt.py prompt.py source_code 3648 2025-06-21T00:01:59.525753 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 4a92157d9a6b413f04e6e3f8d23dc2a417369c729f9703a8de2643ec114f2071
144 src/basic_memory/schemas/request.py request.py source_code 3760 2025-06-21T00:01:59.511789 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 32fe44beb2d99452223ebf1d3a3a3fe105ef92c79885023b71dfd7db30ecc503
145 src/basic_memory/schemas/response.py response.py source_code 6450 2025-07-03T18:43:10.083478 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 5eea4660a2abe48d83ed083d1c2483fdcfb403e0b504f03c14d22f1cae866abb
146 src/basic_memory/schemas/search.py search.py source_code 3657 2025-06-21T00:01:59.522804 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) cb032c0c60102b6b0ed934f995cf9d6bf93aece296d71d537a75e8ae61c75afe
147 src/basic_memory/services/__init__.py __init__.py source_code 259 2025-06-21T00:01:59.655059 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 5c6b7c597ddf5ffd0af4bdfb32ccbc1c5f2794c658206dee43a9945fafe226d8
148 src/basic_memory/services/context_service.py context_service.py source_code 14462 2025-06-21T00:01:59.672086 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (paulmh@gmail.com) e1178b005e6a89f03d6b239e3c6b152aeb30d535a3f280734440a3aec16228f2
149 src/basic_memory/services/directory_service.py directory_service.py source_code 6017 2025-06-21T00:01:59.648501 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) fd838f5ec79033892777b3c8140868f4b57f13e1658d513959524a434b9f959b
150 src/basic_memory/services/entity_service.py entity_service.py source_code 30440 2025-07-03T18:43:10.083956 Paul Hernandez 4 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 7cd5163eca6b8a0772e838c8c869e478166763cd6a2d745b0b9aa5c25a65baee
151 src/basic_memory/services/exceptions.py exceptions.py source_code 390 2025-06-21T00:01:59.668908 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) a158d0af9d1742a9c5ab5f8c34a062948d9286d1c3c72a5abf20e4d547b21e1c
152 src/basic_memory/services/file_service.py file_service.py source_code 10059 2025-06-21T00:01:59.641785 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 8c2ae69c4913438b7d1c5ecbfcce812fbb5d0ea8e3cedcbd8694e8f40cf086f3
153 src/basic_memory/services/initialization.py initialization.py source_code 6715 2025-07-08T20:39:18.344482 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 4dde58b799cf4ac90631e59949b55b3355a93bdf99df0d9c2408c0cea67e10c4
154 src/basic_memory/services/link_resolver.py link_resolver.py source_code 4594 2025-07-01T08:33:22.084908 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) d7efd516cbea753e6b5411def09aeaeb7539f5743487119ecf163c736e138a8c
155 src/basic_memory/services/project_service.py project_service.py source_code 30125 2025-07-30T09:39:45.725079 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) bce95c00aa9a1da0a8c8090ee34b5b1494207f8c99e6c25de4ec43fddc38f6be
156 src/basic_memory/services/search_service.py search_service.py source_code 12782 2025-06-21T00:01:59.665439 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7392b2d2e7f3ed83c5807855ccd450e0e79c17f254aedee700bce9323a1b5b83
157 src/basic_memory/services/service.py service.py source_code 336 2025-06-21T00:01:59.636167 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 57e77ff20395d3bcc62100e92fe2acaacdd937d977a9fdc764e2b57ff60d4da8
158 src/basic_memory/services/sync_status_service.py sync_status_service.py source_code 7504 2025-07-03T18:43:10.084229 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 0a025d689e8e16f1632872104952105fc904537f3d32bcff592eb1f1dc76fbb7
159 src/basic_memory/sync/__init__.py __init__.py source_code 156 2025-06-21T00:01:59.621137 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 0951e0b981f8e7b876bb6c6833c2af3a29490bbd5726567ea9487c947723623e
160 src/basic_memory/sync/background_sync.py background_sync.py source_code 726 2025-07-08T20:39:18.345062 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 549af64ae91128b76c6df07ef517b82de85ca4ad796be44b5c0141fac01d4513
161 src/basic_memory/sync/sync_service.py sync_service.py source_code 23387 2025-07-01T08:33:22.086507 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 0310b927561370f593980d07773bce641b618b8fbf2d9e3890d174290a0344fc
162 src/basic_memory/sync/watch_service.py watch_service.py source_code 15316 2025-06-26T09:28:51.859209 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 240ba6ac7523575945f4db442b7da3820d26c9605f2d7a2d357c4e35e215f523
163 src/basic_memory/templates/prompts/continue_conversation.hbs continue_conversation.hbs templates 3076 2025-07-01T08:33:22.086792 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) b6bac31d25c0e52d0909b2273285092f4e31bc219107f92ed511cd407b65e992
164 src/basic_memory/templates/prompts/search.hbs search.hbs templates 3098 2025-05-25T10:07:54.520119 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 1f570222c1caa78542d46ac7d8a79407ca467b9bd714fa9bd953e8b72a667820
165 src/basic_memory/utils.py utils.py source_code 8654 2025-07-30T09:39:45.725428 jope-bm 5 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); andyxinweiminicloud (andyxinweimin263@icloud.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
166 test-int/conftest.py conftest.py source_code 8203 2025-07-08T20:39:18.345735 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 7231e1bc76cddc7c94433e853825dc0165b103bedf996c2c24eda6ae32fff5ad
167 test-int/mcp/test_build_context_validation.py test_build_context_validation.py source_code 6469 2025-07-08T20:39:18.346021 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) ee61d6b15cee0194fd74c1bcf9361d5a839f6081c7d571ef081da8fcefe1bbf2
168 test-int/mcp/test_delete_note_integration.py test_delete_note_integration.py source_code 13175 2025-07-08T20:39:18.346366 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 497495249b8bcf0af177d8705c6899875460707697980434e560cfe56f86feb3
169 test-int/mcp/test_edit_note_integration.py test_edit_note_integration.py source_code 19822 2025-07-08T20:39:18.346730 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 9ba704badd05808aee0b5a686b7e250e1c865229ec92dab561cba5287b6f6fc6
170 test-int/mcp/test_list_directory_integration.py test_list_directory_integration.py source_code 14744 2025-07-08T20:39:18.347106 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 2c4336a59de63f17ed252bb52d1330ebca901ad83bfebc9e5aa67f132a3c77c6
171 test-int/mcp/test_move_note_integration.py test_move_note_integration.py source_code 19825 2025-07-08T20:39:18.347344 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) cbb17688d0f9551306a7520b059ace7f7dfba70fc20bf0ec98b1148000d7ad7d
172 test-int/mcp/test_project_management_integration.py test_project_management_integration.py source_code 33175 2025-07-08T20:39:18.347658 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 93a43cd699453a7602a5def839740ba5027ab914eba3e7b66a026860ed6bd567
173 test-int/mcp/test_project_state_sync_integration.py test_project_state_sync_integration.py source_code 7728 2025-07-08T20:39:18.347907 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 80b0f5b5cd359498dcbd3af7dcb6194afa4582d8efb3faa38d28675ee45e0748
174 test-int/mcp/test_read_content_integration.py test_read_content_integration.py source_code 11187 2025-07-08T20:39:18.348233 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 6955dd343b40df088ac79175e52723501d83796335a16e43b7f58e16e757e1b8
175 test-int/mcp/test_read_note_integration.py test_read_note_integration.py source_code 1381 2025-07-08T20:39:18.348463 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) b93050da68d0e9d47d46879a386567f688399e28390f4eb31ee37353dc27514b
176 test-int/mcp/test_search_integration.py test_search_integration.py source_code 14690 2025-07-08T20:39:18.348959 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) e0957ada9dd9b12eae5843a37d241ec9293ca929f18281e31197dae36bff589d
177 test-int/mcp/test_write_note_integration.py test_write_note_integration.py source_code 9472 2025-07-08T20:39:18.349398 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) b2b56fee8351168d0c65640c295d969dc4575d9bea87927b2dc07e591cabdff3
178 tests/Non-MarkdownFileSupport.pdf Non-MarkdownFileSupport.pdf other 106751 2025-02-23T17:31:23.206428 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 4aa96f9d0ee830ef6a1ec92243f302bbe2fa8971b84945f4eb5e276bf1ffde96
179 tests/Screenshot.png Screenshot.png other 190076 2025-02-23T17:31:23.207771 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) dd82612fe013c39810d28ae0f2bbcca6ab2c9925b035d7720bb02493ddf5d0a9
180 tests/__init__.py __init__.py source_code 141 2025-06-21T00:01:46.216456 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 2ac5605e69ad8829e96b3689632536539f1cdd3149a29c1903f25af0793a5d65
181 tests/api/conftest.py conftest.py source_code 1404 2025-06-21T00:01:46.359728 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) ea46cde47a37c1f43fe079e48f5d0de8007155a0187f4445abc4f2ffde9c1791
182 tests/api/test_async_client.py test_async_client.py source_code 1382 2025-07-30T09:39:45.725666 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) a2f96226a75e5cff2326ca48ddccea4915964d83e529f7b99958bc233ccdc31a
183 tests/api/test_continue_conversation_template.py test_continue_conversation_template.py source_code 5152 2025-06-21T00:01:46.390901 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) cca08b0291db0ad693c60d8dc203660021feab46d9eb530be7f67e0ebb52c1d3
184 tests/api/test_directory_router.py test_directory_router.py source_code 9376 2025-06-21T00:01:46.356659 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 428626589f0010512481ba495368b0bf2b9617b22764e588eaa3562e86da4d37
185 tests/api/test_importer_router.py test_importer_router.py source_code 16578 2025-06-21T00:01:46.368070 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 03edf6e7404c7350afe76e54ea2bf0d66f668bcdb49f59702067a67b3694309d
186 tests/api/test_knowledge_router.py test_knowledge_router.py source_code 45771 2025-07-01T08:33:22.090490 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 43a5f91ae1fb9038e65c09701336fbdc4dbf40c8319c94727e6312fda9d6d56e
187 tests/api/test_management_router.py test_management_router.py source_code 6220 2025-06-21T00:01:46.402764 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) f6a3f41f263f10c08281525571e2e39fc9ae818ebb7e9895e3f3f3115ea05677
188 tests/api/test_memory_router.py test_memory_router.py source_code 5555 2025-06-21T00:01:46.399667 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) 2b8782015c893081fc67b7f13a7255d4e3dc45b27705a524f94918a339e2d486
189 tests/api/test_project_router.py test_project_router.py source_code 13288 2025-07-30T09:39:45.725847 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) af85d0870069d3831a9214372853994e5d12dc910e37298eb9958f72f6a8bb31
190 tests/api/test_project_router_operations.py test_project_router_operations.py source_code 1812 2025-06-21T00:01:46.381705 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) afd40879de3d7c508cca0feeae3cb7a8f3afcfbb06f59a6104189b1e3291376a
191 tests/api/test_prompt_router.py test_prompt_router.py source_code 5046 2025-06-21T00:01:46.396588 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 9115995b7dd8b44d8a9c06c5e1bbb177618286675a769889e35ac16f26fd9897
192 tests/api/test_resource_router.py test_resource_router.py source_code 13960 2025-06-21T00:01:46.384919 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ad3cb2cabaeab82a7e64253ceede7c1791e2bd70c92f60bc5f3be939292ca22d
193 tests/api/test_search_router.py test_search_router.py source_code 6409 2025-06-21T00:01:46.375427 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (phernandez@basicmachines.co) ba3e3809795e72db9dd9c8c729048bdbbbdb897c2a5aa8b175112b5d4b56d152
194 tests/api/test_search_template.py test_search_template.py source_code 5258 2025-06-21T00:01:46.378721 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 8f0d16a1de947d0466d96afed02e695f7648adac70b9ba99753250068207a686
195 tests/api/test_template_loader.py test_template_loader.py source_code 8035 2025-06-21T00:01:46.406694 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 4fd7c6c4862cc0d877d29244ecdc0b52a0693fc4574a9667663bee36bfd36b62
196 tests/api/test_template_loader_helpers.py test_template_loader_helpers.py source_code 7445 2025-06-21T00:01:46.372114 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 8dd35f11c9b3f2d96ac36263edf4430308728c04c9da543b1cb845b96ab20aa7
197 tests/cli/conftest.py conftest.py source_code 1185 2025-07-01T08:33:22.090848 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c3c73da7ad73224931e1fba4ebd70792221be607bfb1488bb5c9420bba03bdb8
198 tests/cli/test_cli_tools.py test_cli_tools.py source_code 13528 2025-06-21T00:01:46.318964 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) befb8cab50132e26a1b13b82ce8e93a3258282cf157a4230214bfcefeae65102
199 tests/cli/test_import_chatgpt.py test_import_chatgpt.py source_code 6719 2025-07-08T20:39:18.350234 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) df447335545248e2fb2417af33f8cc2f0143bd413a1783e41f89605de305b7c8
200 tests/cli/test_import_claude_conversations.py test_import_claude_conversations.py legal 5028 2025-07-08T20:39:18.350607 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ac4b3b9dfc331fa7fa32a2941c027ff8b6585a94a5ccfaaf0a4affe5cf19c00c
201 tests/cli/test_import_claude_projects.py test_import_claude_projects.py legal 4585 2025-07-08T20:39:18.350885 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7eaab3d491d50ca59c8ba015ecd5740a5feae94d970ee17559c6df9d8558c2cc
202 tests/cli/test_import_memory_json.py test_import_memory_json.py source_code 4891 2025-07-30T09:39:45.726290 jope-bm 3 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) d6734ce059dacf97bc764d848b2e2a6ba52fa96871bc331ec9d2ddc60b766bb6
203 tests/cli/test_project_commands.py test_project_commands.py source_code 6578 2025-07-30T09:39:45.726703 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 51e2ac7ff44b0d1a1db6da406c5c2e6aebceb1b63a1e8d5ab51bbaa834507157
204 tests/cli/test_project_info.py test_project_info.py source_code 3874 2025-07-01T08:33:22.091600 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 0b08950e95a5f276f14c56f6fe99af4d41b8f04548e9b7746f807c5ac4155578
205 tests/cli/test_status.py test_status.py source_code 4160 2025-07-01T08:33:22.091978 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) a1ff89fdac4bf57ba03be92ac79b8ca3210af0b1132d5a2bd0fc0c253fcbf988
206 tests/cli/test_sync.py test_sync.py source_code 3864 2025-07-08T20:43:47.816788 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 77e0f6b42b584a5acfda3c2ff194ff5e71ca57a40cb4484d563f5482bbbb4c0f
207 tests/cli/test_version.py test_version.py source_code 289 2025-06-21T00:01:46.305368 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) db95665178a32d391bd83011d073db269cefba9da8a4dc4d3e392d47bc0e0a8f
208 tests/conftest.py conftest.py source_code 15286 2025-07-08T20:39:18.351368 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) c6f38f103ce58144ffe4562f0c47dad849974e96327f02805e854447e19bc411
209 tests/importers/test_importer_base.py test_importer_base.py source_code 4329 2025-07-08T20:39:00.549594 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) da872a073f2b90fda3c98c9f44cf45884f4f682d91ec1b1f931d42c34eee1939
210 tests/importers/test_importer_utils.py test_importer_utils.py source_code 1827 2025-06-21T00:01:46.184343 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) cbee630c855ceb1de764ac0cdb1d5d781c16cd3a934d67166adc235c98f363d7
211 tests/markdown/__init__.py __init__.py source_code 0 2025-06-21T00:01:46.196570 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
212 tests/markdown/test_entity_parser.py test_entity_parser.py source_code 8669 2025-06-21T00:01:46.206579 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 496fdab6fe164634f8223f827585a4c0dedd30ccea7b0b69dc79004ad0996de2
213 tests/markdown/test_markdown_plugins.py test_markdown_plugins.py source_code 5139 2025-06-21T00:01:46.200759 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 9624d73462aadcd47fb0edd0d87880959a8982eecfa39529f21e3b292c34cb83
214 tests/markdown/test_markdown_processor.py test_markdown_processor.py source_code 5728 2025-06-21T00:01:46.194175 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 35042aa57dd2aeed848c624aa7f69decfb18e83c3b217eca1fdacfc4a10831db
215 tests/markdown/test_observation_edge_cases.py test_observation_edge_cases.py source_code 4295 2025-06-21T00:01:46.209598 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 6f1ab7684bfa8b02af0e0c42b3d7aed91fcd0b1c6288cbc9b6d6943c166979fa
216 tests/markdown/test_parser_edge_cases.py test_parser_edge_cases.py source_code 5142 2025-06-21T00:01:46.213291 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) d511d7d1187e3c1d3a8d3e0ab9efc9e68e84115c46811e7a9dc21eca9a87d520
217 tests/markdown/test_relation_edge_cases.py test_relation_edge_cases.py source_code 3952 2025-06-21T00:01:46.203846 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) f8e2016308f84139342cc37ec6e389ffe52d7eb46f998ee327c7f0d5bba3ad9b
218 tests/markdown/test_task_detection.py test_task_detection.py source_code 401 2025-06-21T00:01:46.191444 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 37fe91a689742033a0eb76723557e31c2a85e591133383b3887572cb714db2a5
219 tests/mcp/conftest.py conftest.py source_code 1761 2025-07-08T20:39:18.351554 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 350b2ca42c52ef76e002deddb65fc0eccb9f8989bd26078ea1c100e3b93bae3f
220 tests/mcp/test_prompts.py test_prompts.py source_code 5989 2025-07-01T08:33:22.093691 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) e3b2ee5b4bc120b5043225ebdbf73eadd71be9c3d9d8e1fdd66a24a8ff11a780
221 tests/mcp/test_resource_project_info.py test_resource_project_info.py source_code 4885 2025-07-01T08:33:22.094085 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6a043736789b239c8d4ae00d1a5332a0fc3bed4038fe3388970ba97dc7431a93
222 tests/mcp/test_resources.py test_resources.py source_code 549 2025-07-01T08:33:22.094481 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 77a6396b9b8a9d3b3d202e438243ca6178d87fd7680c9fc063ee013f2042aa4c
223 tests/mcp/test_tool_build_context.py test_tool_build_context.py source_code 3714 2025-07-01T08:33:22.094661 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 5f0a39fdb652605335ed54aa91fe994262441bb7ba46f381c46ebca882fc23f2
224 tests/mcp/test_tool_canvas.py test_tool_canvas.py source_code 7997 2025-07-01T08:33:22.094982 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c517bb1f9edc77b76fbeb483dfcb2dd57de9f0b80a10738708bc90cbe388dc9e
225 tests/mcp/test_tool_delete_note.py test_tool_delete_note.py source_code 4208 2025-07-01T08:33:22.095578 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 4cbf3ba4313438651b0608d5b25faf1400f7bd6a78af630351aecd4457800895
226 tests/mcp/test_tool_edit_note.py test_tool_edit_note.py source_code 13503 2025-07-03T18:43:10.084890 Drew Cain 2 Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) dd441969aa54b3739f2d9202d3feaf46aee807ec51e01a13ef41eda52743944f
227 tests/mcp/test_tool_list_directory.py test_tool_list_directory.py source_code 7730 2025-07-01T08:33:22.096737 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) cfbb5c06bcfe74ea60f31051eb9b03ac80b86232b053c188bf3b172132f7c0f5
228 tests/mcp/test_tool_move_note.py test_tool_move_note.py source_code 25851 2025-07-30T09:39:45.727347 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co) c9f95158503fa42e37532aaa35027538fa49cea718d059d570cf547d31f01043
229 tests/mcp/test_tool_read_content.py test_tool_read_content.py source_code 19442 2025-07-30T09:39:45.727526 jope-bm 1 jope-bm (joe@basicmemory.com) 1817e32f997b06dbdabf02864d0c70584c1cd80bf1fae8dfbef649de79434bc5
230 tests/mcp/test_tool_read_note.py test_tool_read_note.py source_code 22991 2025-07-30T09:39:45.727746 jope-bm 4 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 4e13ea9ff977525aa62b6a8c22505ffe989329dc3e7d07b71e044cf43ef3ddfd
231 tests/mcp/test_tool_recent_activity.py test_tool_recent_activity.py source_code 3983 2025-07-01T08:33:22.098561 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 45414152cd45334b84df56f653146b7bd2939907548e7245a37207fdccfc4c87
232 tests/mcp/test_tool_resource.py test_tool_resource.py source_code 6782 2025-07-01T08:33:22.098948 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 3916ae1c4d458eee53d2c570b9bbb708ecd617de5a145c3a7552389954bc9195
233 tests/mcp/test_tool_search.py test_tool_search.py source_code 10959 2025-07-03T18:43:10.085177 Drew Cain 3 Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 07839cf8e89d74ba05ec1dc55fa842444c1f0cc3d1587823b0ac3458ad89e87c
234 tests/mcp/test_tool_sync_status.py test_tool_sync_status.py source_code 6331 2025-07-01T08:33:22.100021 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 3f3566df5b9f3c66bb9b3bd77d4c05825480d0e85015305cb1b7ab9429c7a7ec
235 tests/mcp/test_tool_utils.py test_tool_utils.py source_code 9228 2025-07-01T08:33:22.100561 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) b50789f7a78b0169f52dc8bd16e262510ed4a0ac130fce698d4be84af1fe2d31
236 tests/mcp/test_tool_view_note.py test_tool_view_note.py source_code 10004 2025-07-01T08:33:22.101164 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 385535ce791c3ab55db827cbcf27ea25ae85faf3a027f52df4eea052cede7f36
237 tests/mcp/test_tool_write_note.py test_tool_write_note.py source_code 35136 2025-07-30T09:39:45.728137 jope-bm 3 jope-bm (joe@basicmemory.com); Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
238 tests/repository/test_entity_repository.py test_entity_repository.py source_code 15498 2025-06-21T00:01:46.176265 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 8f5d1ff6cff7b640993ff73f463b1e7801a4dd69640fc55fa23dc58b865e9943
239 tests/repository/test_entity_repository_upsert.py test_entity_repository_upsert.py source_code 16983 2025-07-03T18:43:10.085482 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com) ee0ecd6f4ff8b31838bd6de6fb1018af437e02813d8315c06f4e20a6b78a0572
240 tests/repository/test_observation_repository.py test_observation_repository.py source_code 11786 2025-06-21T00:01:46.158862 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) 3006d392ad94dcc9b3ae031d63a1af6935624534389dd025de70d4c9e112aa0b
241 tests/repository/test_project_info_repository.py test_project_info_repository.py source_code 1186 2025-06-21T00:01:46.161876 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) dbce7ae7350403cbc37343c2e3e68e4d2255e247006aaa6c495a7ce8bfddea7d
242 tests/repository/test_project_repository.py test_project_repository.py source_code 10511 2025-07-30T09:39:45.728536 jope-bm 2 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 279a3324635b1b515c18003bd1875cf230fef1192cadef9ca426846783717e75
243 tests/repository/test_relation_repository.py test_relation_repository.py source_code 11980 2025-06-21T00:01:46.167567 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) fcdbdf40f7b56145b98eedde5ead64ef6187e859adde48cc09f5a97754757428
244 tests/repository/test_repository.py test_repository.py source_code 5996 2025-06-21T00:01:46.152691 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 3a6d4ca0b7a438a30ae504f5eac22874d4e1a937a4246e90efad46c90f0e1c95
245 tests/repository/test_search_repository.py test_search_repository.py source_code 25471 2025-07-03T18:43:10.086041 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 805b5cc55a53ae9d6e86c0de735c7f38ac9fd92c23194b0150fa3e7f5507a146
246 tests/schemas/test_memory_url.py test_memory_url.py source_code 2000 2025-06-21T00:01:46.346515 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 946fa6c48534f41c8b9cc27bbad164d3e3673a79afa84fbb439fae4cd26c504b
247 tests/schemas/test_memory_url_validation.py test_memory_url_validation.py source_code 9338 2025-07-01T08:33:22.103247 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 7054c3a3cdb8e05d2ffd254ed298908ff3d48a0a3927d960975eae1ab9beeb38
248 tests/schemas/test_schemas.py test_schemas.py source_code 16880 2025-07-03T18:43:10.086337 Drew Cain 3 Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 2c746a00c340f063c160ace67569955a300a294040949695c79fd4ae124fb611
249 tests/schemas/test_search.py test_search.py source_code 3264 2025-06-21T00:01:46.343685 github-actions[bot] (AI Assistant) 2 github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 7437775d1b4a61a438cbabe3dbb1becd2adc4dbcc0c24595830c0843fa7a3166
250 tests/services/test_context_service.py test_context_service.py source_code 8833 2025-06-21T00:01:46.446200 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) ab49d21a05d5364e7e8a2f00b07aabe1109b7417698e0acd92792e2cb5f22732
251 tests/services/test_directory_service.py test_directory_service.py source_code 6854 2025-06-21T00:01:46.457258 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) a0c765fb6bd1a75b6ba4592b1df344c48273b6ab03ba6bd15d2b5e840eb2d521
252 tests/services/test_entity_service.py test_entity_service.py source_code 59278 2025-07-03T18:43:10.086674 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) d7d495756faa10b415d705cf26b69d2efbc5f190a834b6767386ff296629ea71
253 tests/services/test_file_service.py test_file_service.py source_code 5243 2025-06-21T00:01:46.460141 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 83e6e9a7584b7baeccbc84865d8c1d3e2a0223e7d2b9c066d3799c289196ab7d
254 tests/services/test_initialization.py test_initialization.py source_code 6939 2025-07-08T20:39:18.351946 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ebb8d11ff37dcb36c4844c68f873c8e0e8aa6ab1b82abb22ee96c4233e6ab287
255 tests/services/test_link_resolver.py test_link_resolver.py source_code 13618 2025-07-01T08:33:22.105766 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) c9fc56d0c3572770e95ca6175c213ed8b44c2a6ddddc298b5662cc2d8f41014e
256 tests/services/test_project_service.py test_project_service.py source_code 28152 2025-07-30T09:39:45.728920 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 430868ed796518937a3b0bed4d8c33be53264a6100d61d54b0745bb2b58bf29a
257 tests/services/test_project_service_operations.py test_project_service_operations.py source_code 4679 2025-06-21T00:01:46.442141 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) d4103b6c5fff7e74ba84b86033537b8522aa60fc75aec4974d52e1dfec68b1b4
258 tests/services/test_search_service.py test_search_service.py source_code 25299 2025-06-21T00:01:46.439133 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) b3e58258db2b727ab8a1792e52fcb038d3a0779bcd1b70f2d295a9d06e5e2513
259 tests/services/test_sync_status_service.py test_sync_status_service.py source_code 9926 2025-07-03T18:43:10.087266 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 00245ca356e33fc7afcd2d42cb5ec082038c95383d738067821cf1e8d23c9a4b
260 tests/sync/test_sync_service.py test_sync_service.py source_code 39659 2025-07-01T08:33:22.107088 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 0609aee9906549f27fc4289b5ac2d46a50e53e12a0615a2701f17fbe9a74e169
261 tests/sync/test_sync_wikilink_issue.py test_sync_wikilink_issue.py source_code 1959 2025-06-21T00:01:46.420370 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) db4b98dd7008a1a26b0fd02b9a2d03bca950b281efc19d98a91b017c500b23a5
262 tests/sync/test_tmp_files.py test_tmp_files.py source_code 5930 2025-06-21T00:01:46.424277 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) cead95a07b29f6c1ab933abe67f9648122f5f33d33753c8e4ab4934af96cbc25
263 tests/sync/test_watch_service.py test_watch_service.py source_code 14076 2025-06-26T09:28:51.860679 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) e324a4127f8bfe59798f3a08125488c701e88239b7482d87a0394b91c55b893e
264 tests/sync/test_watch_service_edge_cases.py test_watch_service_edge_cases.py source_code 2169 2025-06-21T00:01:46.409830 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) b87c5015330e9b551630aab7ef95ac1e7663f0ce46e912d8155b319e139559aa
265 tests/test_config.py test_config.py source_code 3680 2025-07-03T18:43:10.087558 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6a246431cff739274efda895dfa28f38710289a73e645312f5fa05fce0885ec8
266 tests/test_db_migration_deduplication.py test_db_migration_deduplication.py source_code 6166 2025-07-08T20:39:18.352690 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com) ab768e061531ca2edcd598c101b5d884e549f90c7a4b305a23713a199d263fbb
267 tests/utils/test_file_utils.py test_file_utils.py source_code 6199 2025-06-21T00:01:46.219673 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 4615bb20b92b8a79d9e086301f852b34c3360f17ecc209920d68528268ddeed4
268 tests/utils/test_parse_tags.py test_parse_tags.py source_code 1691 2025-06-21T00:01:46.223400 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) b83afdf18dac8b3411bd0fab1301683217d3d1abceaf2d22c09e79c709efd8eb
269 tests/utils/test_permalink_formatting.py test_permalink_formatting.py source_code 4193 2025-06-21T00:01:46.225738 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) d998a4ca846c78679728a918b6f71df67c30b6961ede3cffa609f2cf6ad160eb
270 tests/utils/test_utf8_handling.py test_utf8_handling.py source_code 5791 2025-06-21T00:01:46.228483 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 50ec792e572af51cd2d996d4ddacbcfd3bbd79aa928818a90c42117451ea829f
271 tests/utils/test_validate_project_path.py test_validate_project_path.py source_code 15346 2025-07-30T09:39:45.729224 jope-bm 1 jope-bm (joe@basicmemory.com) 27a4bf2a9d277e6cd773619e5241b20175d211ec60c284361bec404fd99143f3
272 uv.lock uv.lock other 232710 2025-07-30T09:39:36.619155 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) caa1e3f6e66464b884a78cab77df2fe303fa3c0dc573be0196474b6d3c150581
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,272 @@
path,name,category,size_bytes,modified_time,primary_author,contributor_count,contributors_list,sha256_hash
.claude/commands/release/beta.md,beta.md,documentation,3103,2025-07-01T08:33:22.037438,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),345f06e3f304470a8892e96979355919c8e5d8f4212ebbe543c3272fd15a5cbe
.claude/commands/release/changelog.md,changelog.md,documentation,4648,2025-07-03T18:43:10.075727,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),ea2484352f4f881aa71f546dcf84b0882d60c96673a88406aa2f7e12a282a1f4
.claude/commands/release/release-check.md,release-check.md,documentation,3344,2025-07-01T08:33:22.040060,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),7dd41a40e95c89153936c4ea60a3c989eccd5973fff9f6caef156de82f12bd04
.claude/commands/release/release.md,release.md,documentation,2925,2025-07-01T08:33:22.043674,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),0e4afd788fcf85fbe46094452e9b92a4290c3e23702283e72ee56aa9288476e5
.claude/commands/test-live.md,test-live.md,documentation,18720,2025-07-03T18:43:10.076403,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),21a9edeefb3e5673d833151a2fd0464087c0f0a9d056fdd7fca474c1d177d6fc
.dockerignore,.dockerignore,other,623,2025-07-01T08:33:22.048301,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),b3079bffad89d07186c9166725075524ffc07ceea6dc1d53fdbea6dca9585684
.github/ISSUE_TEMPLATE/bug_report.md,bug_report.md,documentation,967,2025-03-01T14:22:50.968994,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),0d34443ddda84a5e9726c8268083c9646d2cc64ff9c5ebf56c89587cef4c7706
.github/ISSUE_TEMPLATE/config.yml,config.yml,configuration,374,2025-03-01T14:23:26.936836,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),f4e21bb9b7f053509b6c08548a2649a5d62f44f0106810aa8c915d2f29acc623
.github/ISSUE_TEMPLATE/documentation.md,documentation.md,documentation,557,2025-03-01T14:23:40.020117,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),78f80a6b9a2b954695f74a847a068e0b780da6020572401c13c931555a4a9db5
.github/ISSUE_TEMPLATE/feature_request.md,feature_request.md,documentation,786,2025-03-01T14:23:06.344081,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),cee834de442221d53f3d2eeb85b81f3a641b3a7cb587ef8a169452305007439d
.github/dependabot.yml,dependabot.yml,configuration,529,2025-03-15T10:40:16.936258,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),8c6c2ef9a1417da63adb49c70f45524129bd5c46bbd7452b6b97cfe65205f89d
.github/workflows/claude.yml,claude.yml,legal,4628,2025-07-03T18:43:10.076958,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),d026f1756310781b85abc491b454cc31b52dfce4b951cdf8a4a555b6b047604c
.github/workflows/dev-release.yml,dev-release.yml,configuration,1405,2025-06-03T08:31:42.915367,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),58bcfc9e11e210e02dee76aabe7d1378da4edafb7f61857049ee6ccee9d45ffa
.github/workflows/docker.yml,docker.yml,configuration,1621,2025-07-01T08:33:22.049870,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c918a86f2b16ebb45182a73c45272bcd6cea7022cc6e0eaeb2b2a24d8eebfe4d
.github/workflows/pr-title.yml,pr-title.yml,configuration,887,2025-02-17T16:29:35.733646,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),b6df62a20235496feba4d9419c85d6e8446c4d447ad69e7f57b51cc8953f68f4
.github/workflows/release.yml,release.yml,configuration,2479,2025-07-03T18:43:10.077261,Drew Cain,2,Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co),163307a99e2f3d317af6ae8927e1537654d88bf574a6958ac0bcd2d4de266b2a
.github/workflows/test.yml,test.yml,configuration,1426,2025-07-01T08:33:22.054430,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),ab09084a11be8adfc83fc6285c652fbe44a4584aa7d7d3658fcf0c57112d1640
.gitignore,.gitignore,other,566,2025-07-01T08:33:22.055006,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),358658b0faa8c3145e539421deba4ad0bac4a8ea2e608b2c2f867a822c67b36f
.python-version,.python-version,other,5,2024-12-02T16:41:37.012830,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),7b55f8e67b5623c4bef3fa691288da9437d79d3aba156de48d481db32ac7d16d
CHANGELOG.md,CHANGELOG.md,documentation,53647,2025-07-06T10:34:45.550847,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); semantic-release (semantic-release),0b165eb18975ff253cde08f4687b7808ac6ce63b6d8c10912c495a76c9058d1a
CITATION.cff,CITATION.cff,other,302,2025-02-17T16:29:35.735146,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),bc4878cf6f80bb64655f3f93a5821ffe0924ad8311c784b5f81a36093fcffdda
CLA.md,CLA.md,legal,1342,2025-03-01T14:12:38.435132,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),c238c7ff4f2b8451c6bba1bbacd10b04fb7d41d9a9cd76a62644d8193791d169
CLAUDE.md,CLAUDE.md,legal,12310,2025-07-03T18:43:10.078147,Drew Cain,4,Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); Ikko Eltociear Ashimine (eltociear@gmail.com),751f10c1a9a9c0ba2054d9c9cd36cf0989d6a347491fd505bb6504ee74b12900
CODE_OF_CONDUCT.md,CODE_OF_CONDUCT.md,documentation,509,2025-02-17T16:29:35.735238,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),b276b464e85eb1e5d9f09d90bba9573508a7bf81d2eeb38d0f25bd9f2fa66198
CONTRIBUTING.md,CONTRIBUTING.md,documentation,7329,2025-07-30T09:39:36.607158,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co),ca822fe39cc529bfc3822d317ab8a20fd141ec3ecb8c20de9e2eca3edce1c282
Dockerfile,Dockerfile,other,856,2025-07-01T08:33:22.056908,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),c45501905423990e31ffdb8ae4e976eca6423c6784905c1036bcc7795b70feef
LICENSE,LICENSE,legal,34523,2024-12-02T16:41:20.739392,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),8486a10c4393cee1c25392769ddd3b2d6c242d6ec7928e1414efff7dfb2f07ef
README.md,README.md,documentation,16261,2025-07-03T18:43:10.078281,Drew Cain,6,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Jason Noble (github+jasonn@jasonnoble.org); Marc Baiza (43151891+mbaiza27@users.noreply.github.com); Matias Forbord (codeluggage@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),2c4b82b30f49ab465617034fda999157450ed168f8e097fe8e9ca7ac65a197a7
SECURITY.md,SECURITY.md,documentation,303,2025-03-12T16:04:01.989927,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),96932268b8fe737577941b49e9dff5ff8ad59c11cc3f9a016989589ef5c98c1f
docker-compose.yml,docker-compose.yml,configuration,2534,2025-07-01T08:33:22.059281,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),4a9fdfd2f0d42b148fe021eee77fd5e772c7ba9c2fe5d0cc310c8c7a64257417
docs/AI Assistant Guide.md,AI Assistant Guide.md,documentation,16423,2025-07-01T08:33:22.060491,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c717869a3d356852077026591364ecb0589a6d53f9764af027c57d142ea7ff55
docs/Docker.md,Docker.md,documentation,9088,2025-07-01T08:33:22.060976,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),e13d3f50148353046b52d9d493986880f76f2914ef4efe1a759b2cc9d10913a4
justfile,justfile,other,5496,2025-07-30T09:39:36.608008,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com),a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
llms-install.md,llms-install.md,documentation,2307,2025-06-29T14:19:28.826375,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),674105eb85c8f1d59fc2ddc6840f2a2a3e293358687a305c37dffc8144304f97
memory.json,memory.json,configuration,90075,2025-06-29T14:19:28.827172,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),22d5eee995ca0548b7d9dd152f9a3690c42a514cbf38fea750b3ed2a17dd99c5
pyproject.toml,pyproject.toml,configuration,3279,2025-07-30T09:39:36.608791,Paul Hernandez,4,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); semantic-release (semantic-release),428a5d64d4555dc7cd2a81b89a3444bdb1d2f3017257fbc9160bd0ae982718e1
smithery.yaml,smithery.yaml,configuration,433,2025-03-11T16:36:03.389716,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),63f13499cf4fee0751b5005f5bd85597dc1c7f9a881f4ec8147cc23e95e75c2d
src/basic_memory/__init__.py,__init__.py,source_code,256,2025-07-06T10:34:45.551291,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@gmail.com); semantic-release (semantic-release),c946490ab9d64957d25df37f721392024916f8a81ed838f70a8e938b1c2637db
src/basic_memory/alembic/alembic.ini,alembic.ini,configuration,3733,2025-02-23T17:31:23.198433,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),20466c9c5f026db66793006bebb2f328a3686c7bb34da40d52f33c3eca29e717
src/basic_memory/alembic/env.py,env.py,source_code,2838,2025-07-08T20:39:18.336650,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),e241d987eadfcd5011cbd9ddbecb833d306de87937759d81c08d37d04a6906b0
src/basic_memory/alembic/migrations.py,migrations.py,source_code,718,2025-06-21T00:01:59.613806,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),96b8873d70dd04b48d5c45b7413a54d1224ab9577557ef0dad5929377a9fb144
src/basic_memory/alembic/script.py.mako,script.py.mako,other,635,2025-02-17T16:29:35.739659,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),304a8bfb6a804e5493f5300e79882c70c9f5bb2e87512f4d16f0e097dddd323f
src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py,3dae7c7b1564_initial_schema.py,source_code,4363,2025-06-21T00:01:59.595762,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),9536d69409ddd5eb3bc54f7d0e82607da45ed7f2ad7bc4cbf7cae2a9e28657cd
src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py,502b60eaa905_remove_required_from_entity_permalink.py,source_code,1840,2025-06-21T00:01:59.604717,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),93ac584e660f33d468b3eec203b070641298c282bf82655d0beda7f050237681
src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py,5fe1ab1ccebe_add_projects_table.py,source_code,4379,2025-06-21T00:01:59.601299,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),d82098f5aca3cdbada60c7229ea4ac262f527349eed9ef9e864509bacfaccf7e
src/basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py,647e7a75e2cd_project_constraint_fix.py,source_code,4210,2025-07-01T08:33:22.063463,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),604ac5908a5976272f52297866d13abb14a99390590935d9fd37cf13e32049fa
src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py,b3c3938bacdb_relation_to_name_unique_index.py,source_code,1428,2025-06-21T00:01:59.598551,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),46c1b2990cdf4575752d234a8b28b494c8a54f15b5360c12f6347aef27b66a92
src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py,cc7172b46608_update_search_index_schema.py,source_code,3679,2025-06-21T00:01:59.610909,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),9036af47d42ac7dc12bb93f7a9de1266aff0688b031b550c4e0d92983a24b4c5
src/basic_memory/api/__init__.py,__init__.py,source_code,72,2025-06-21T00:01:59.579981,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),c02a63fb6d63d43d0acca97d425eae9cb055158d0ad6e1a9fc57926512adaa99
src/basic_memory/api/app.py,app.py,source_code,2897,2025-07-08T20:39:18.337081,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ad673ac2c09410af5830f6afdffaa28b0040480dacd52ff01750b8b2c066e8cf
src/basic_memory/api/routers/__init__.py,__init__.py,source_code,398,2025-06-21T00:01:59.549416,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),4443b908a43dea8e6fb4658009cb08c48a56c9b21449e29773cdd159b59cf014
src/basic_memory/api/routers/directory_router.py,directory_router.py,source_code,2054,2025-06-21T00:01:59.567371,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ac1407beec1f7d43a4d222af704b3642559c960bebf2eaf6e1ffe91f7fac5514
src/basic_memory/api/routers/importer_router.py,importer_router.py,source_code,4513,2025-06-21T00:01:59.561600,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),c45502a2b90f5a8f00174c9ad14adc2e65cd7fc0a33d9740a9d750207f0f3bea
src/basic_memory/api/routers/knowledge_router.py,knowledge_router.py,source_code,9738,2025-07-01T08:33:22.064119,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),e1d0ffb4fa5c246582ba844a11b417092de1a173567be55b7060bbc55fbc5681
src/basic_memory/api/routers/management_router.py,management_router.py,source_code,2730,2025-07-08T20:39:18.337438,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),cdbce294dcec6146c56c4dae15744cdf77039fd21b23eef7cbc0b5f9bfb5f4ee
src/basic_memory/api/routers/memory_router.py,memory_router.py,source_code,3003,2025-07-01T08:33:22.064510,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),6bd0a7c775e0c1290efb6001173237c0cdcfa0c1b1bb27c9145a7b35f1596a97
src/basic_memory/api/routers/project_router.py,project_router.py,source_code,8444,2025-07-30T09:39:45.721369,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),6539c69f1d506c65d14cc2c151876b19057f37d84d51a9e6f464ed47a4692648
src/basic_memory/api/routers/prompt_router.py,prompt_router.py,source_code,9948,2025-07-01T08:33:22.065221,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),e30c6aebe35112054933c37d0b462c3750005030fc9e44c23b35b2cd2a93485c
src/basic_memory/api/routers/resource_router.py,resource_router.py,source_code,8058,2025-06-21T00:01:59.570399,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),584244a84698ff24ca8f9f94fab5b891740a51c25f972920c08ebf83f478d5c9
src/basic_memory/api/routers/search_router.py,search_router.py,source_code,1226,2025-06-21T00:01:59.543020,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),183eb68e50904e22ff54db1d89b8be6f57fa1f8d0a096a3d497d8297b607e105
src/basic_memory/api/routers/utils.py,utils.py,source_code,5159,2025-07-03T18:43:10.079143,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),9e60f57da24e1dc9d64236c26a7a2353003dc618a77fbeb853c494aa3357a57c
src/basic_memory/api/template_loader.py,template_loader.py,source_code,8607,2025-06-21T00:01:59.576132,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),7b16d3797c89460c8b1664a335eae8c634fb5f60d6166d97e6a5156b776b6d83
src/basic_memory/cli/__init__.py,__init__.py,source_code,33,2025-06-21T00:01:59.456735,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),6ab70a2c05910e13c3ef1e6df34325be265e633c076741998a0cb2dcd295a069
src/basic_memory/cli/app.py,app.py,source_code,2268,2025-07-08T20:39:18.337708,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),f710670380d707c4458ad881f7a25bb3c5cdb2bcff59f139f37421264fe8f2f8
src/basic_memory/cli/commands/__init__.py,__init__.py,source_code,393,2025-07-08T20:39:18.338070,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),de8a23702f98fb844fa9f7fdbedc16ce24ff4f8baf05589c2f4a521cd8a55645
src/basic_memory/cli/commands/db.py,db.py,source_code,1480,2025-07-08T20:39:18.338326,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),704a1096d80ab9d12e247d029fe6223e935a0d0ceee7e615c020f46a720828e0
src/basic_memory/cli/commands/import_chatgpt.py,import_chatgpt.py,source_code,2856,2025-07-08T20:39:18.338787,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),8957cca3acab6351335624a518bdc19d956487e93d86dd1b6c2309e9d5850ae5
src/basic_memory/cli/commands/import_claude_conversations.py,import_claude_conversations.py,legal,2946,2025-07-08T20:39:18.339053,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7bc97838732bf00f4fb4a80e3ba4fdfbce8971ae85cc2ac902c3b3a3e110ae57
src/basic_memory/cli/commands/import_claude_projects.py,import_claude_projects.py,legal,2891,2025-07-08T20:39:18.339310,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),6321577075801c99ad47a0cdc13b5aa3c9ca102a05ca8f06ae2a51125a8c43bc
src/basic_memory/cli/commands/import_memory_json.py,import_memory_json.py,source_code,3013,2025-07-30T09:39:45.721637,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7ea193f6720b2672290ad16c79a143a31d88a1d567838f12b9ebf9110a7c0338
src/basic_memory/cli/commands/mcp.py,mcp.py,source_code,2593,2025-07-08T20:39:18.340025,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),3e1be3d27b18ef4743204b7cf8a37fbc2a1a91fc1636c468e08cefcd8597bac6
src/basic_memory/cli/commands/project.py,project.py,source_code,13836,2025-07-30T09:39:45.721838,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),af3e6f30410ab48355f4b1a46aaa3aa5423cb0a0490f51447db1d25e09f39916
src/basic_memory/cli/commands/status.py,status.py,source_code,5809,2025-07-08T20:39:18.340324,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),b6d0ea237d714d054f69b24a2058beba74e224a2fa4a80a525d62a2aa2ea2d70
src/basic_memory/cli/commands/sync.py,sync.py,source_code,8213,2025-07-08T20:39:18.340627,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),703b3e73c4c33850c27f6f4c07abbf5d4ce5dc43f706bf0c43264bbb45f8b213
src/basic_memory/cli/commands/tool.py,tool.py,source_code,9540,2025-07-01T08:33:22.070903,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),9b2fa400b9f7921bf55b602f8bbdfa36b1ec7e4a5bc8fe7b9838b92e31f0a9ed
src/basic_memory/cli/main.py,main.py,source_code,465,2025-07-08T20:39:18.340868,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7a405b12bff98e319968526238ae15859df0362bba5a3857562fecca47b5c70d
src/basic_memory/config.py,config.py,source_code,12487,2025-07-30T09:39:45.722031,jope-bm,5,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
src/basic_memory/db.py,db.py,source_code,7428,2025-07-08T20:39:18.341550,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),25e053b0b3f9e8fa823b05fc099001efe8a3a4f6e0f80728e5079ba45aa406d8
src/basic_memory/deps.py,deps.py,source_code,12144,2025-07-08T20:39:18.341870,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),bce28cd9ca549b8afce0bc689cc1fb2dc80cd5b929f85114aa682bb8ae82411d
src/basic_memory/file_utils.py,file_utils.py,source_code,6700,2025-06-21T00:01:59.587200,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),79ac5328b2c46d3232fcc6ff22ffc39ade085c0252ad91958be2a7ae9c9c8b71
src/basic_memory/importers/__init__.py,__init__.py,source_code,795,2025-06-21T00:01:59.295471,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),0537015bdecfded85cb166b9c3db50b2f3aef329c70e0c36fbcb4f824099a21f
src/basic_memory/importers/base.py,base.py,source_code,2531,2025-06-21T00:01:59.305335,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),6b0c1efd4f827f348834aa0cea2ae8eebbb842a2e5b1f5f3747ced0ef79b9f13
src/basic_memory/importers/chatgpt_importer.py,chatgpt_importer.py,source_code,7372,2025-06-21T00:01:59.308956,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),dfa540b196ab23b5c4e6bfcac4da567873351cf7c78fa35f4c3b87e84c58e218
src/basic_memory/importers/claude_conversations_importer.py,claude_conversations_importer.py,legal,5725,2025-06-21T00:01:59.288540,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),a7bc9e872f4f81ce5f79fe9dd1a6fd0f00a6f020a2cb2664184a97f14eeb1dbc
src/basic_memory/importers/claude_projects_importer.py,claude_projects_importer.py,legal,5389,2025-06-21T00:01:59.291737,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),a452675fd9bb18ebf64eb4bd7f69ccd7e993b617931015a3c4ab700d67493863
src/basic_memory/importers/memory_json_importer.py,memory_json_importer.py,source_code,4631,2025-07-30T09:39:45.722316,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),bc7d045299f17ed9ad5cebff7b1423250ec28a11130e47a0ac48d3ab82bdeafc
src/basic_memory/importers/utils.py,utils.py,source_code,1792,2025-06-21T00:01:59.298428,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),ee7e22fd4812362394f62ed8944abe80738c1e3ab88131faf639f4a8ccfd6c89
src/basic_memory/markdown/__init__.py,__init__.py,source_code,501,2025-06-21T00:01:59.316337,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),0ddce2a025ad0e729aab4e411d82e02ffefc15ac041cba4b5e7a7e90f4957c87
src/basic_memory/markdown/entity_parser.py,entity_parser.py,source_code,4516,2025-06-21T00:01:59.321461,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),1b0d1177358645ccbadd170b3f62760dc9bd838d38c741978ab0da5836234d68
src/basic_memory/markdown/markdown_processor.py,markdown_processor.py,source_code,4968,2025-06-21T00:01:59.325241,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),4b99f2ebdceed9d96a3bbb562682eba4b4b383c7a64080eaec3bbba25a4952c9
src/basic_memory/markdown/plugins.py,plugins.py,source_code,6639,2025-06-21T00:01:59.312733,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),82d2332918e866ccaf06a2e954d9eb9b397f71b4d9e591a7f2472e5f1423464a
src/basic_memory/markdown/schemas.py,schemas.py,source_code,1896,2025-06-21T00:01:59.329982,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),7b2c580abd615725a62267257b46ac13922dfc30fa01192a681658bb528ae67e
src/basic_memory/markdown/utils.py,utils.py,source_code,3410,2025-07-03T18:43:10.079889,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),1b757f0d06e60e3ea276c0b2ea44fe1a156a895e093c1e607d6286e702bf4ae4
src/basic_memory/mcp/__init__.py,__init__.py,source_code,35,2025-06-21T00:01:59.404757,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),76c0ce84aaa361e21b0942db1c8c5f708b536eab9d12e120d4da7ce9eab41844
src/basic_memory/mcp/async_client.py,async_client.py,source_code,925,2025-07-30T09:39:45.722547,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),6531f4387f30a30a322197ff51d6eacae4b25a58c648095931b3d1145d1da303
src/basic_memory/mcp/project_session.py,project_session.py,source_code,4203,2025-07-08T20:39:18.342906,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),4da403ec93dec9063eeb8b05246e3501740d162cc77a067d3ce54ba43d690819
src/basic_memory/mcp/prompts/__init__.py,__init__.py,source_code,615,2025-07-08T20:39:18.343263,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),f8197d0e08f64c3f4f50b8f38203ea5eebcf123582472ed2f58834de1dbe53b0
src/basic_memory/mcp/prompts/ai_assistant_guide.py,ai_assistant_guide.py,source_code,821,2025-06-21T00:13:53.262832,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),f13239c4e6e2455730bfac3d6f2d71407957d3086fc84efe2c6b22a833114c58
src/basic_memory/mcp/prompts/continue_conversation.py,continue_conversation.py,source_code,1998,2025-06-21T00:13:53.263309,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),aec9a50b657b7bb1ba0c02b42bcdb9bc5b0f2a0b1143bd361c5ce7ea59076833
src/basic_memory/mcp/prompts/recent_activity.py,recent_activity.py,source_code,3311,2025-07-01T08:33:22.073986,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),d2fd5cddbd927430f15d5b85f1e3a3368a18cb4e2e4587a5d29749d2b9e0830e
src/basic_memory/mcp/prompts/search.py,search.py,source_code,1692,2025-06-21T00:13:53.264093,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),9dbf3c319cbdb5d5bf32608b51522d8ae92b2dd6f7c441d62efd0954b525738a
src/basic_memory/mcp/prompts/utils.py,utils.py,source_code,5431,2025-06-21T00:01:59.425042,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),55a72b6eac18b724a9225608aca1e8e6cea3b684ccb1c609aab1511f7ce90ba4
src/basic_memory/mcp/resources/ai_assistant_guide.md,ai_assistant_guide.md,documentation,14777,2025-03-28T19:12:38.653627,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),aa76160e46256fe2662ae3a86799659916acfede1d5835c1fe2f0b136efb2e0b
src/basic_memory/mcp/resources/project_info.py,project_info.py,source_code,1906,2025-06-21T00:13:53.264918,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),2dc5244f1e225c17d4e8ba784d5721efc3aa2e8a5b3b2e258f22a77ebe155eca
src/basic_memory/mcp/server.py,server.py,source_code,1248,2025-07-08T20:39:18.343419,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),0a910cae27d61ea923e90fbe2d4b5c7cacf3b29d3e156f0b7f77872ab973c761
src/basic_memory/mcp/tools/__init__.py,__init__.py,source_code,1619,2025-07-03T18:43:10.080029,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co),872b771dd52ec3b763645a2baf6e10a70f049ce3106830a6d3f053b3e09a5fe6
src/basic_memory/mcp/tools/build_context.py,build_context.py,source_code,4611,2025-07-03T18:43:10.080426,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),724280b77b8f5f3e61cd3fdeebc3ee66e2bcfedaaea3638e6a2e2e33fcb1978e
src/basic_memory/mcp/tools/canvas.py,canvas.py,source_code,3738,2025-07-01T08:33:22.076204,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),db617d1bd81f3dbfa5f22d41e6b6b825afe1f73618f37acf63d9830390b98246
src/basic_memory/mcp/tools/delete_note.py,delete_note.py,source_code,7346,2025-07-01T08:33:22.076726,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),b52c9173f5600662f255e7a70a5c17d5293ef8b29c19a8403334d7da62b65c8b
src/basic_memory/mcp/tools/edit_note.py,edit_note.py,source_code,13570,2025-07-01T08:33:22.077181,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),ab8c7e7fbfa3fe5fb0ce6d7bf805454f5fd6182a340aae25237b1e6127b6d5a6
src/basic_memory/mcp/tools/list_directory.py,list_directory.py,source_code,5236,2025-06-21T00:13:53.267453,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),f85c43b02aeee580f4d8ce2a9100c0bab1095b245a0bb608e1847ace0d1ab51f
src/basic_memory/mcp/tools/move_note.py,move_note.py,source_code,17541,2025-07-30T09:39:45.722919,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),5ef27d9baaebc2c5656fc49c4798a4e4e40a70b6cd9d1e761dbcae021bad558c
src/basic_memory/mcp/tools/project_management.py,project_management.py,source_code,12944,2025-07-06T10:34:45.552403,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co),cdac736d65129f689a85c6b82f8e043bc84a31657ead7a8331771171eeaa860f
src/basic_memory/mcp/tools/read_content.py,read_content.py,source_code,9125,2025-07-30T09:39:45.723469,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),96a13addac507fd874394dfa2e1e5ed71af5eb89d0872c1d68cacf9cac3f8724
src/basic_memory/mcp/tools/read_note.py,read_note.py,source_code,8132,2025-07-30T09:39:45.723828,jope-bm,5,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),dff53ce02b16d9c5fca315b3f09bb70867a89d614b0ef3f0548dce87978048ee
src/basic_memory/mcp/tools/recent_activity.py,recent_activity.py,source_code,4833,2025-06-21T00:13:53.269120,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),5d58cd2402679b1bf3c7dfcbb3503e40e776c9347ba499524d3b91c528af98de
src/basic_memory/mcp/tools/search.py,search.py,source_code,15883,2025-07-03T18:43:10.081557,Drew Cain,4,Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),8519b0057468c4450eb543a2f561bcd0d7cb96e1ce1b95e948e02b309ba6b7ca
src/basic_memory/mcp/tools/sync_status.py,sync_status.py,source_code,10517,2025-07-08T20:39:18.344231,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),73dd73b186eaec8b82e6b17e39a67c27082d24e0653dc4e4b35712bd83b80a22
src/basic_memory/mcp/tools/utils.py,utils.py,source_code,20892,2025-07-30T09:39:36.616253,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),a95004911e276822eba88a3fef15c5b9ba861b1ca9a2ecfe0c1e3fb2f4ef0116
src/basic_memory/mcp/tools/view_note.py,view_note.py,source_code,2499,2025-07-01T08:33:22.080024,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),75d357c72113b1d0394987e521a4158ff09b77b23b08b56cddab5144331b1a68
src/basic_memory/mcp/tools/write_note.py,write_note.py,source_code,6612,2025-07-30T09:39:45.723985,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),771396fb49d397feb5f7e36321d4d233c22c4d1b53414912c849957c6e96fc83
src/basic_memory/models/__init__.py,__init__.py,source_code,333,2025-06-21T00:01:59.437212,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),8f40b876d162f85384690291f1d416106f9d26d750d793414e2260e276c85cd5
src/basic_memory/models/base.py,base.py,source_code,225,2025-06-21T00:01:59.447249,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),e2101727c084d519e32a16f6de53ddf9033b1bf15721d4e8c0c27d6d18b1b295
src/basic_memory/models/knowledge.py,knowledge.py,source_code,7087,2025-06-21T00:01:59.444376,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),005c5f292f1f45ae372aadc48c9080b9fa6d7b854d0bb7ecf587ec843ac1e28d
src/basic_memory/models/project.py,project.py,source_code,2773,2025-07-01T08:33:22.080907,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),a14ad06943aeeff9ae4a5fa2dfc0e1d07ce6085acc02dc20c402c3513b7d9397
src/basic_memory/models/search.py,search.py,source_code,1300,2025-06-21T00:01:59.440923,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),3e143cc38b5a0294af8e1d43a4f841e1c1fd193b76136a68f83159ce19e86646
src/basic_memory/repository/__init__.py,__init__.py,source_code,327,2025-06-21T00:01:59.256363,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),3162bea3c42292accea5ee52c8f6ca4368a8079056034529cfae6d820f84d035
src/basic_memory/repository/entity_repository.py,entity_repository.py,source_code,10405,2025-07-03T18:43:10.082570,Drew Cain,3,Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),e2a8d1eba6c8d64bc61d7168df0fe8c29a670858bf9daeac464a0f440273fae0
src/basic_memory/repository/observation_repository.py,observation_repository.py,source_code,2943,2025-06-21T00:01:59.269646,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),aa132f1cb4a36a84f715afdc40e2ac4f98d83e3eba1974b2b4404cc0b020ca04
src/basic_memory/repository/project_info_repository.py,project_info_repository.py,source_code,338,2025-06-21T00:01:59.252582,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),f172d50182a405643a19b2a3d62a80f4e2b41463c775394eb3b66d7de51ff6df
src/basic_memory/repository/project_repository.py,project_repository.py,source_code,3803,2025-07-30T09:39:45.724344,jope-bm,2,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),9083ba214b2bcaaf98164d9c33cda7add52bc77f7269ecb6e43cdd5088728b7c
src/basic_memory/repository/relation_repository.py,relation_repository.py,source_code,3179,2025-06-21T00:01:59.246745,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),cfb3a8e59cff27e063e91bd00e949647bdd92e4d9fc46edeee3acc6de15e26f4
src/basic_memory/repository/repository.py,repository.py,source_code,15224,2025-06-21T00:01:59.273355,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),3096fe71bf106506cbf86aeafe2aafe0aabbe5a5f6c90a212c8aa1e53e1f171c
src/basic_memory/repository/search_repository.py,search_repository.py,source_code,21936,2025-07-03T18:43:10.082844,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),a972f73d1b71dac5770e8eb3793c6c9ac44e4e792f9dab528f8c4e6c6a80bcaa
src/basic_memory/schemas/__init__.py,__init__.py,source_code,1674,2025-06-21T00:01:59.514555,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),98480815c75379bfafe32d2090e87fa40e73caa19b664fbd5db5ea9528ba58cb
src/basic_memory/schemas/base.py,base.py,source_code,6738,2025-07-01T08:33:22.082193,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),171f7b0c4ab33abef2f7379eb1e3bda950586ce7edff83907fd12255f84e267e
src/basic_memory/schemas/delete.py,delete.py,source_code,1180,2025-06-21T00:01:59.502563,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),50047624af7d58c8f780ffb2a065a51c3dde64492f9534917fc42860813e59fc
src/basic_memory/schemas/directory.py,directory.py,source_code,881,2025-06-21T00:01:59.529023,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),17dfcbac9a91a9bfe43b4f060ca2735cb6f69e16d81b63dd554a397830ff29fe
src/basic_memory/schemas/importer.py,importer.py,source_code,693,2025-07-30T09:39:45.724633,jope-bm,2,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ac33df423ca32b28ce7b6ea9c29d541f8783a86c0c29f78db35163bf93f139cd
src/basic_memory/schemas/memory.py,memory.py,source_code,5833,2025-07-03T18:43:10.083167,Drew Cain,3,Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),acb4a953a553feca672c4895798a7d948ec51f922f75b66dd7d55716e3bebed3
src/basic_memory/schemas/project_info.py,project_info.py,source_code,7047,2025-07-01T08:33:22.083248,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),7dc3635297b6e7fe6e3262b2d78da26f7a79a846a4cecd5624f2e4828979cf2c
src/basic_memory/schemas/prompt.py,prompt.py,source_code,3648,2025-06-21T00:01:59.525753,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),4a92157d9a6b413f04e6e3f8d23dc2a417369c729f9703a8de2643ec114f2071
src/basic_memory/schemas/request.py,request.py,source_code,3760,2025-06-21T00:01:59.511789,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),32fe44beb2d99452223ebf1d3a3a3fe105ef92c79885023b71dfd7db30ecc503
src/basic_memory/schemas/response.py,response.py,source_code,6450,2025-07-03T18:43:10.083478,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),5eea4660a2abe48d83ed083d1c2483fdcfb403e0b504f03c14d22f1cae866abb
src/basic_memory/schemas/search.py,search.py,source_code,3657,2025-06-21T00:01:59.522804,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),cb032c0c60102b6b0ed934f995cf9d6bf93aece296d71d537a75e8ae61c75afe
src/basic_memory/services/__init__.py,__init__.py,source_code,259,2025-06-21T00:01:59.655059,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),5c6b7c597ddf5ffd0af4bdfb32ccbc1c5f2794c658206dee43a9945fafe226d8
src/basic_memory/services/context_service.py,context_service.py,source_code,14462,2025-06-21T00:01:59.672086,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (paulmh@gmail.com),e1178b005e6a89f03d6b239e3c6b152aeb30d535a3f280734440a3aec16228f2
src/basic_memory/services/directory_service.py,directory_service.py,source_code,6017,2025-06-21T00:01:59.648501,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),fd838f5ec79033892777b3c8140868f4b57f13e1658d513959524a434b9f959b
src/basic_memory/services/entity_service.py,entity_service.py,source_code,30440,2025-07-03T18:43:10.083956,Paul Hernandez,4,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),7cd5163eca6b8a0772e838c8c869e478166763cd6a2d745b0b9aa5c25a65baee
src/basic_memory/services/exceptions.py,exceptions.py,source_code,390,2025-06-21T00:01:59.668908,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),a158d0af9d1742a9c5ab5f8c34a062948d9286d1c3c72a5abf20e4d547b21e1c
src/basic_memory/services/file_service.py,file_service.py,source_code,10059,2025-06-21T00:01:59.641785,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),8c2ae69c4913438b7d1c5ecbfcce812fbb5d0ea8e3cedcbd8694e8f40cf086f3
src/basic_memory/services/initialization.py,initialization.py,source_code,6715,2025-07-08T20:39:18.344482,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),4dde58b799cf4ac90631e59949b55b3355a93bdf99df0d9c2408c0cea67e10c4
src/basic_memory/services/link_resolver.py,link_resolver.py,source_code,4594,2025-07-01T08:33:22.084908,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),d7efd516cbea753e6b5411def09aeaeb7539f5743487119ecf163c736e138a8c
src/basic_memory/services/project_service.py,project_service.py,source_code,30125,2025-07-30T09:39:45.725079,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),bce95c00aa9a1da0a8c8090ee34b5b1494207f8c99e6c25de4ec43fddc38f6be
src/basic_memory/services/search_service.py,search_service.py,source_code,12782,2025-06-21T00:01:59.665439,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),7392b2d2e7f3ed83c5807855ccd450e0e79c17f254aedee700bce9323a1b5b83
src/basic_memory/services/service.py,service.py,source_code,336,2025-06-21T00:01:59.636167,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),57e77ff20395d3bcc62100e92fe2acaacdd937d977a9fdc764e2b57ff60d4da8
src/basic_memory/services/sync_status_service.py,sync_status_service.py,source_code,7504,2025-07-03T18:43:10.084229,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),0a025d689e8e16f1632872104952105fc904537f3d32bcff592eb1f1dc76fbb7
src/basic_memory/sync/__init__.py,__init__.py,source_code,156,2025-06-21T00:01:59.621137,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),0951e0b981f8e7b876bb6c6833c2af3a29490bbd5726567ea9487c947723623e
src/basic_memory/sync/background_sync.py,background_sync.py,source_code,726,2025-07-08T20:39:18.345062,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),549af64ae91128b76c6df07ef517b82de85ca4ad796be44b5c0141fac01d4513
src/basic_memory/sync/sync_service.py,sync_service.py,source_code,23387,2025-07-01T08:33:22.086507,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),0310b927561370f593980d07773bce641b618b8fbf2d9e3890d174290a0344fc
src/basic_memory/sync/watch_service.py,watch_service.py,source_code,15316,2025-06-26T09:28:51.859209,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),240ba6ac7523575945f4db442b7da3820d26c9605f2d7a2d357c4e35e215f523
src/basic_memory/templates/prompts/continue_conversation.hbs,continue_conversation.hbs,templates,3076,2025-07-01T08:33:22.086792,Drew Cain,2,Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),b6bac31d25c0e52d0909b2273285092f4e31bc219107f92ed511cd407b65e992
src/basic_memory/templates/prompts/search.hbs,search.hbs,templates,3098,2025-05-25T10:07:54.520119,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),1f570222c1caa78542d46ac7d8a79407ca467b9bd714fa9bd953e8b72a667820
src/basic_memory/utils.py,utils.py,source_code,8654,2025-07-30T09:39:45.725428,jope-bm,5,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); andyxinweiminicloud (andyxinweimin263@icloud.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
test-int/conftest.py,conftest.py,source_code,8203,2025-07-08T20:39:18.345735,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),7231e1bc76cddc7c94433e853825dc0165b103bedf996c2c24eda6ae32fff5ad
test-int/mcp/test_build_context_validation.py,test_build_context_validation.py,source_code,6469,2025-07-08T20:39:18.346021,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),ee61d6b15cee0194fd74c1bcf9361d5a839f6081c7d571ef081da8fcefe1bbf2
test-int/mcp/test_delete_note_integration.py,test_delete_note_integration.py,source_code,13175,2025-07-08T20:39:18.346366,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),497495249b8bcf0af177d8705c6899875460707697980434e560cfe56f86feb3
test-int/mcp/test_edit_note_integration.py,test_edit_note_integration.py,source_code,19822,2025-07-08T20:39:18.346730,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),9ba704badd05808aee0b5a686b7e250e1c865229ec92dab561cba5287b6f6fc6
test-int/mcp/test_list_directory_integration.py,test_list_directory_integration.py,source_code,14744,2025-07-08T20:39:18.347106,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),2c4336a59de63f17ed252bb52d1330ebca901ad83bfebc9e5aa67f132a3c77c6
test-int/mcp/test_move_note_integration.py,test_move_note_integration.py,source_code,19825,2025-07-08T20:39:18.347344,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),cbb17688d0f9551306a7520b059ace7f7dfba70fc20bf0ec98b1148000d7ad7d
test-int/mcp/test_project_management_integration.py,test_project_management_integration.py,source_code,33175,2025-07-08T20:39:18.347658,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),93a43cd699453a7602a5def839740ba5027ab914eba3e7b66a026860ed6bd567
test-int/mcp/test_project_state_sync_integration.py,test_project_state_sync_integration.py,source_code,7728,2025-07-08T20:39:18.347907,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),80b0f5b5cd359498dcbd3af7dcb6194afa4582d8efb3faa38d28675ee45e0748
test-int/mcp/test_read_content_integration.py,test_read_content_integration.py,source_code,11187,2025-07-08T20:39:18.348233,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),6955dd343b40df088ac79175e52723501d83796335a16e43b7f58e16e757e1b8
test-int/mcp/test_read_note_integration.py,test_read_note_integration.py,source_code,1381,2025-07-08T20:39:18.348463,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),b93050da68d0e9d47d46879a386567f688399e28390f4eb31ee37353dc27514b
test-int/mcp/test_search_integration.py,test_search_integration.py,source_code,14690,2025-07-08T20:39:18.348959,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),e0957ada9dd9b12eae5843a37d241ec9293ca929f18281e31197dae36bff589d
test-int/mcp/test_write_note_integration.py,test_write_note_integration.py,source_code,9472,2025-07-08T20:39:18.349398,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),b2b56fee8351168d0c65640c295d969dc4575d9bea87927b2dc07e591cabdff3
tests/Non-MarkdownFileSupport.pdf,Non-MarkdownFileSupport.pdf,other,106751,2025-02-23T17:31:23.206428,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),4aa96f9d0ee830ef6a1ec92243f302bbe2fa8971b84945f4eb5e276bf1ffde96
tests/Screenshot.png,Screenshot.png,other,190076,2025-02-23T17:31:23.207771,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),dd82612fe013c39810d28ae0f2bbcca6ab2c9925b035d7720bb02493ddf5d0a9
tests/__init__.py,__init__.py,source_code,141,2025-06-21T00:01:46.216456,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),2ac5605e69ad8829e96b3689632536539f1cdd3149a29c1903f25af0793a5d65
tests/api/conftest.py,conftest.py,source_code,1404,2025-06-21T00:01:46.359728,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),ea46cde47a37c1f43fe079e48f5d0de8007155a0187f4445abc4f2ffde9c1791
tests/api/test_async_client.py,test_async_client.py,source_code,1382,2025-07-30T09:39:45.725666,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),a2f96226a75e5cff2326ca48ddccea4915964d83e529f7b99958bc233ccdc31a
tests/api/test_continue_conversation_template.py,test_continue_conversation_template.py,source_code,5152,2025-06-21T00:01:46.390901,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),cca08b0291db0ad693c60d8dc203660021feab46d9eb530be7f67e0ebb52c1d3
tests/api/test_directory_router.py,test_directory_router.py,source_code,9376,2025-06-21T00:01:46.356659,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),428626589f0010512481ba495368b0bf2b9617b22764e588eaa3562e86da4d37
tests/api/test_importer_router.py,test_importer_router.py,source_code,16578,2025-06-21T00:01:46.368070,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),03edf6e7404c7350afe76e54ea2bf0d66f668bcdb49f59702067a67b3694309d
tests/api/test_knowledge_router.py,test_knowledge_router.py,source_code,45771,2025-07-01T08:33:22.090490,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),43a5f91ae1fb9038e65c09701336fbdc4dbf40c8319c94727e6312fda9d6d56e
tests/api/test_management_router.py,test_management_router.py,source_code,6220,2025-06-21T00:01:46.402764,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),f6a3f41f263f10c08281525571e2e39fc9ae818ebb7e9895e3f3f3115ea05677
tests/api/test_memory_router.py,test_memory_router.py,source_code,5555,2025-06-21T00:01:46.399667,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),2b8782015c893081fc67b7f13a7255d4e3dc45b27705a524f94918a339e2d486
tests/api/test_project_router.py,test_project_router.py,source_code,13288,2025-07-30T09:39:45.725847,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),af85d0870069d3831a9214372853994e5d12dc910e37298eb9958f72f6a8bb31
tests/api/test_project_router_operations.py,test_project_router_operations.py,source_code,1812,2025-06-21T00:01:46.381705,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),afd40879de3d7c508cca0feeae3cb7a8f3afcfbb06f59a6104189b1e3291376a
tests/api/test_prompt_router.py,test_prompt_router.py,source_code,5046,2025-06-21T00:01:46.396588,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),9115995b7dd8b44d8a9c06c5e1bbb177618286675a769889e35ac16f26fd9897
tests/api/test_resource_router.py,test_resource_router.py,source_code,13960,2025-06-21T00:01:46.384919,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ad3cb2cabaeab82a7e64253ceede7c1791e2bd70c92f60bc5f3be939292ca22d
tests/api/test_search_router.py,test_search_router.py,source_code,6409,2025-06-21T00:01:46.375427,bm-claudeai (AI Assistant),3,bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (phernandez@basicmachines.co),ba3e3809795e72db9dd9c8c729048bdbbbdb897c2a5aa8b175112b5d4b56d152
tests/api/test_search_template.py,test_search_template.py,source_code,5258,2025-06-21T00:01:46.378721,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),8f0d16a1de947d0466d96afed02e695f7648adac70b9ba99753250068207a686
tests/api/test_template_loader.py,test_template_loader.py,source_code,8035,2025-06-21T00:01:46.406694,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),4fd7c6c4862cc0d877d29244ecdc0b52a0693fc4574a9667663bee36bfd36b62
tests/api/test_template_loader_helpers.py,test_template_loader_helpers.py,source_code,7445,2025-06-21T00:01:46.372114,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),8dd35f11c9b3f2d96ac36263edf4430308728c04c9da543b1cb845b96ab20aa7
tests/cli/conftest.py,conftest.py,source_code,1185,2025-07-01T08:33:22.090848,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c3c73da7ad73224931e1fba4ebd70792221be607bfb1488bb5c9420bba03bdb8
tests/cli/test_cli_tools.py,test_cli_tools.py,source_code,13528,2025-06-21T00:01:46.318964,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),befb8cab50132e26a1b13b82ce8e93a3258282cf157a4230214bfcefeae65102
tests/cli/test_import_chatgpt.py,test_import_chatgpt.py,source_code,6719,2025-07-08T20:39:18.350234,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),df447335545248e2fb2417af33f8cc2f0143bd413a1783e41f89605de305b7c8
tests/cli/test_import_claude_conversations.py,test_import_claude_conversations.py,legal,5028,2025-07-08T20:39:18.350607,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ac4b3b9dfc331fa7fa32a2941c027ff8b6585a94a5ccfaaf0a4affe5cf19c00c
tests/cli/test_import_claude_projects.py,test_import_claude_projects.py,legal,4585,2025-07-08T20:39:18.350885,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),7eaab3d491d50ca59c8ba015ecd5740a5feae94d970ee17559c6df9d8558c2cc
tests/cli/test_import_memory_json.py,test_import_memory_json.py,source_code,4891,2025-07-30T09:39:45.726290,jope-bm,3,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com),d6734ce059dacf97bc764d848b2e2a6ba52fa96871bc331ec9d2ddc60b766bb6
tests/cli/test_project_commands.py,test_project_commands.py,source_code,6578,2025-07-30T09:39:45.726703,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),51e2ac7ff44b0d1a1db6da406c5c2e6aebceb1b63a1e8d5ab51bbaa834507157
tests/cli/test_project_info.py,test_project_info.py,source_code,3874,2025-07-01T08:33:22.091600,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),0b08950e95a5f276f14c56f6fe99af4d41b8f04548e9b7746f807c5ac4155578
tests/cli/test_status.py,test_status.py,source_code,4160,2025-07-01T08:33:22.091978,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),a1ff89fdac4bf57ba03be92ac79b8ca3210af0b1132d5a2bd0fc0c253fcbf988
tests/cli/test_sync.py,test_sync.py,source_code,3864,2025-07-08T20:43:47.816788,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),77e0f6b42b584a5acfda3c2ff194ff5e71ca57a40cb4484d563f5482bbbb4c0f
tests/cli/test_version.py,test_version.py,source_code,289,2025-06-21T00:01:46.305368,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),db95665178a32d391bd83011d073db269cefba9da8a4dc4d3e392d47bc0e0a8f
tests/conftest.py,conftest.py,source_code,15286,2025-07-08T20:39:18.351368,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),c6f38f103ce58144ffe4562f0c47dad849974e96327f02805e854447e19bc411
tests/importers/test_importer_base.py,test_importer_base.py,source_code,4329,2025-07-08T20:39:00.549594,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),da872a073f2b90fda3c98c9f44cf45884f4f682d91ec1b1f931d42c34eee1939
tests/importers/test_importer_utils.py,test_importer_utils.py,source_code,1827,2025-06-21T00:01:46.184343,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),cbee630c855ceb1de764ac0cdb1d5d781c16cd3a934d67166adc235c98f363d7
tests/markdown/__init__.py,__init__.py,source_code,0,2025-06-21T00:01:46.196570,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
tests/markdown/test_entity_parser.py,test_entity_parser.py,source_code,8669,2025-06-21T00:01:46.206579,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),496fdab6fe164634f8223f827585a4c0dedd30ccea7b0b69dc79004ad0996de2
tests/markdown/test_markdown_plugins.py,test_markdown_plugins.py,source_code,5139,2025-06-21T00:01:46.200759,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),9624d73462aadcd47fb0edd0d87880959a8982eecfa39529f21e3b292c34cb83
tests/markdown/test_markdown_processor.py,test_markdown_processor.py,source_code,5728,2025-06-21T00:01:46.194175,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),35042aa57dd2aeed848c624aa7f69decfb18e83c3b217eca1fdacfc4a10831db
tests/markdown/test_observation_edge_cases.py,test_observation_edge_cases.py,source_code,4295,2025-06-21T00:01:46.209598,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),6f1ab7684bfa8b02af0e0c42b3d7aed91fcd0b1c6288cbc9b6d6943c166979fa
tests/markdown/test_parser_edge_cases.py,test_parser_edge_cases.py,source_code,5142,2025-06-21T00:01:46.213291,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),d511d7d1187e3c1d3a8d3e0ab9efc9e68e84115c46811e7a9dc21eca9a87d520
tests/markdown/test_relation_edge_cases.py,test_relation_edge_cases.py,source_code,3952,2025-06-21T00:01:46.203846,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),f8e2016308f84139342cc37ec6e389ffe52d7eb46f998ee327c7f0d5bba3ad9b
tests/markdown/test_task_detection.py,test_task_detection.py,source_code,401,2025-06-21T00:01:46.191444,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),37fe91a689742033a0eb76723557e31c2a85e591133383b3887572cb714db2a5
tests/mcp/conftest.py,conftest.py,source_code,1761,2025-07-08T20:39:18.351554,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),350b2ca42c52ef76e002deddb65fc0eccb9f8989bd26078ea1c100e3b93bae3f
tests/mcp/test_prompts.py,test_prompts.py,source_code,5989,2025-07-01T08:33:22.093691,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),e3b2ee5b4bc120b5043225ebdbf73eadd71be9c3d9d8e1fdd66a24a8ff11a780
tests/mcp/test_resource_project_info.py,test_resource_project_info.py,source_code,4885,2025-07-01T08:33:22.094085,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),6a043736789b239c8d4ae00d1a5332a0fc3bed4038fe3388970ba97dc7431a93
tests/mcp/test_resources.py,test_resources.py,source_code,549,2025-07-01T08:33:22.094481,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),77a6396b9b8a9d3b3d202e438243ca6178d87fd7680c9fc063ee013f2042aa4c
tests/mcp/test_tool_build_context.py,test_tool_build_context.py,source_code,3714,2025-07-01T08:33:22.094661,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),5f0a39fdb652605335ed54aa91fe994262441bb7ba46f381c46ebca882fc23f2
tests/mcp/test_tool_canvas.py,test_tool_canvas.py,source_code,7997,2025-07-01T08:33:22.094982,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),c517bb1f9edc77b76fbeb483dfcb2dd57de9f0b80a10738708bc90cbe388dc9e
tests/mcp/test_tool_delete_note.py,test_tool_delete_note.py,source_code,4208,2025-07-01T08:33:22.095578,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),4cbf3ba4313438651b0608d5b25faf1400f7bd6a78af630351aecd4457800895
tests/mcp/test_tool_edit_note.py,test_tool_edit_note.py,source_code,13503,2025-07-03T18:43:10.084890,Drew Cain,2,Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),dd441969aa54b3739f2d9202d3feaf46aee807ec51e01a13ef41eda52743944f
tests/mcp/test_tool_list_directory.py,test_tool_list_directory.py,source_code,7730,2025-07-01T08:33:22.096737,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),cfbb5c06bcfe74ea60f31051eb9b03ac80b86232b053c188bf3b172132f7c0f5
tests/mcp/test_tool_move_note.py,test_tool_move_note.py,source_code,25851,2025-07-30T09:39:45.727347,jope-bm,2,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co),c9f95158503fa42e37532aaa35027538fa49cea718d059d570cf547d31f01043
tests/mcp/test_tool_read_content.py,test_tool_read_content.py,source_code,19442,2025-07-30T09:39:45.727526,jope-bm,1,jope-bm (joe@basicmemory.com),1817e32f997b06dbdabf02864d0c70584c1cd80bf1fae8dfbef649de79434bc5
tests/mcp/test_tool_read_note.py,test_tool_read_note.py,source_code,22991,2025-07-30T09:39:45.727746,jope-bm,4,jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),4e13ea9ff977525aa62b6a8c22505ffe989329dc3e7d07b71e044cf43ef3ddfd
tests/mcp/test_tool_recent_activity.py,test_tool_recent_activity.py,source_code,3983,2025-07-01T08:33:22.098561,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),45414152cd45334b84df56f653146b7bd2939907548e7245a37207fdccfc4c87
tests/mcp/test_tool_resource.py,test_tool_resource.py,source_code,6782,2025-07-01T08:33:22.098948,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),3916ae1c4d458eee53d2c570b9bbb708ecd617de5a145c3a7552389954bc9195
tests/mcp/test_tool_search.py,test_tool_search.py,source_code,10959,2025-07-03T18:43:10.085177,Drew Cain,3,Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),07839cf8e89d74ba05ec1dc55fa842444c1f0cc3d1587823b0ac3458ad89e87c
tests/mcp/test_tool_sync_status.py,test_tool_sync_status.py,source_code,6331,2025-07-01T08:33:22.100021,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),3f3566df5b9f3c66bb9b3bd77d4c05825480d0e85015305cb1b7ab9429c7a7ec
tests/mcp/test_tool_utils.py,test_tool_utils.py,source_code,9228,2025-07-01T08:33:22.100561,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),b50789f7a78b0169f52dc8bd16e262510ed4a0ac130fce698d4be84af1fe2d31
tests/mcp/test_tool_view_note.py,test_tool_view_note.py,source_code,10004,2025-07-01T08:33:22.101164,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),385535ce791c3ab55db827cbcf27ea25ae85faf3a027f52df4eea052cede7f36
tests/mcp/test_tool_write_note.py,test_tool_write_note.py,source_code,35136,2025-07-30T09:39:45.728137,jope-bm,3,jope-bm (joe@basicmemory.com); Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
tests/repository/test_entity_repository.py,test_entity_repository.py,source_code,15498,2025-06-21T00:01:46.176265,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),8f5d1ff6cff7b640993ff73f463b1e7801a4dd69640fc55fa23dc58b865e9943
tests/repository/test_entity_repository_upsert.py,test_entity_repository_upsert.py,source_code,16983,2025-07-03T18:43:10.085482,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com),ee0ecd6f4ff8b31838bd6de6fb1018af437e02813d8315c06f4e20a6b78a0572
tests/repository/test_observation_repository.py,test_observation_repository.py,source_code,11786,2025-06-21T00:01:46.158862,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),3006d392ad94dcc9b3ae031d63a1af6935624534389dd025de70d4c9e112aa0b
tests/repository/test_project_info_repository.py,test_project_info_repository.py,source_code,1186,2025-06-21T00:01:46.161876,bm-claudeai (AI Assistant),1,bm-claudeai (AI Assistant) (claude@basicmachines.co),dbce7ae7350403cbc37343c2e3e68e4d2255e247006aaa6c495a7ce8bfddea7d
tests/repository/test_project_repository.py,test_project_repository.py,source_code,10511,2025-07-30T09:39:45.728536,jope-bm,2,jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),279a3324635b1b515c18003bd1875cf230fef1192cadef9ca426846783717e75
tests/repository/test_relation_repository.py,test_relation_repository.py,source_code,11980,2025-06-21T00:01:46.167567,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co),fcdbdf40f7b56145b98eedde5ead64ef6187e859adde48cc09f5a97754757428
tests/repository/test_repository.py,test_repository.py,source_code,5996,2025-06-21T00:01:46.152691,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),3a6d4ca0b7a438a30ae504f5eac22874d4e1a937a4246e90efad46c90f0e1c95
tests/repository/test_search_repository.py,test_search_repository.py,source_code,25471,2025-07-03T18:43:10.086041,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),805b5cc55a53ae9d6e86c0de735c7f38ac9fd92c23194b0150fa3e7f5507a146
tests/schemas/test_memory_url.py,test_memory_url.py,source_code,2000,2025-06-21T00:01:46.346515,Paul Hernandez,1,Paul Hernandez (paulmh@gmail.com),946fa6c48534f41c8b9cc27bbad164d3e3673a79afa84fbb439fae4cd26c504b
tests/schemas/test_memory_url_validation.py,test_memory_url_validation.py,source_code,9338,2025-07-01T08:33:22.103247,Paul Hernandez,1,Paul Hernandez (paul@basicmachines.co),7054c3a3cdb8e05d2ffd254ed298908ff3d48a0a3927d960975eae1ab9beeb38
tests/schemas/test_schemas.py,test_schemas.py,source_code,16880,2025-07-03T18:43:10.086337,Drew Cain,3,Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),2c746a00c340f063c160ace67569955a300a294040949695c79fd4ae124fb611
tests/schemas/test_search.py,test_search.py,source_code,3264,2025-06-21T00:01:46.343685,github-actions[bot] (AI Assistant),2,github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com),7437775d1b4a61a438cbabe3dbb1becd2adc4dbcc0c24595830c0843fa7a3166
tests/services/test_context_service.py,test_context_service.py,source_code,8833,2025-06-21T00:01:46.446200,bm-claudeai (AI Assistant),2,bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com),ab49d21a05d5364e7e8a2f00b07aabe1109b7417698e0acd92792e2cb5f22732
tests/services/test_directory_service.py,test_directory_service.py,source_code,6854,2025-06-21T00:01:46.457258,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),a0c765fb6bd1a75b6ba4592b1df344c48273b6ab03ba6bd15d2b5e840eb2d521
tests/services/test_entity_service.py,test_entity_service.py,source_code,59278,2025-07-03T18:43:10.086674,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),d7d495756faa10b415d705cf26b69d2efbc5f190a834b6767386ff296629ea71
tests/services/test_file_service.py,test_file_service.py,source_code,5243,2025-06-21T00:01:46.460141,Paul Hernandez,1,Paul Hernandez (phernandez@basicmachines.co),83e6e9a7584b7baeccbc84865d8c1d3e2a0223e7d2b9c066d3799c289196ab7d
tests/services/test_initialization.py,test_initialization.py,source_code,6939,2025-07-08T20:39:18.351946,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),ebb8d11ff37dcb36c4844c68f873c8e0e8aa6ab1b82abb22ee96c4233e6ab287
tests/services/test_link_resolver.py,test_link_resolver.py,source_code,13618,2025-07-01T08:33:22.105766,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),c9fc56d0c3572770e95ca6175c213ed8b44c2a6ddddc298b5662cc2d8f41014e
tests/services/test_project_service.py,test_project_service.py,source_code,28152,2025-07-30T09:39:45.728920,jope-bm,3,jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),430868ed796518937a3b0bed4d8c33be53264a6100d61d54b0745bb2b58bf29a
tests/services/test_project_service_operations.py,test_project_service_operations.py,source_code,4679,2025-06-21T00:01:46.442141,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),d4103b6c5fff7e74ba84b86033537b8522aa60fc75aec4974d52e1dfec68b1b4
tests/services/test_search_service.py,test_search_service.py,source_code,25299,2025-06-21T00:01:46.439133,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),b3e58258db2b727ab8a1792e52fcb038d3a0779bcd1b70f2d295a9d06e5e2513
tests/services/test_sync_status_service.py,test_sync_status_service.py,source_code,9926,2025-07-03T18:43:10.087266,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),00245ca356e33fc7afcd2d42cb5ec082038c95383d738067821cf1e8d23c9a4b
tests/sync/test_sync_service.py,test_sync_service.py,source_code,39659,2025-07-01T08:33:22.107088,Paul Hernandez,2,Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co),0609aee9906549f27fc4289b5ac2d46a50e53e12a0615a2701f17fbe9a74e169
tests/sync/test_sync_wikilink_issue.py,test_sync_wikilink_issue.py,source_code,1959,2025-06-21T00:01:46.420370,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),db4b98dd7008a1a26b0fd02b9a2d03bca950b281efc19d98a91b017c500b23a5
tests/sync/test_tmp_files.py,test_tmp_files.py,source_code,5930,2025-06-21T00:01:46.424277,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),cead95a07b29f6c1ab933abe67f9648122f5f33d33753c8e4ab4934af96cbc25
tests/sync/test_watch_service.py,test_watch_service.py,source_code,14076,2025-06-26T09:28:51.860679,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),e324a4127f8bfe59798f3a08125488c701e88239b7482d87a0394b91c55b893e
tests/sync/test_watch_service_edge_cases.py,test_watch_service_edge_cases.py,source_code,2169,2025-06-21T00:01:46.409830,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),b87c5015330e9b551630aab7ef95ac1e7663f0ce46e912d8155b319e139559aa
tests/test_config.py,test_config.py,source_code,3680,2025-07-03T18:43:10.087558,Paul Hernandez,3,Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),6a246431cff739274efda895dfa28f38710289a73e645312f5fa05fce0885ec8
tests/test_db_migration_deduplication.py,test_db_migration_deduplication.py,source_code,6166,2025-07-08T20:39:18.352690,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com),ab768e061531ca2edcd598c101b5d884e549f90c7a4b305a23713a199d263fbb
tests/utils/test_file_utils.py,test_file_utils.py,source_code,6199,2025-06-21T00:01:46.219673,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),4615bb20b92b8a79d9e086301f852b34c3360f17ecc209920d68528268ddeed4
tests/utils/test_parse_tags.py,test_parse_tags.py,source_code,1691,2025-06-21T00:01:46.223400,Paul Hernandez,2,Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com),b83afdf18dac8b3411bd0fab1301683217d3d1abceaf2d22c09e79c709efd8eb
tests/utils/test_permalink_formatting.py,test_permalink_formatting.py,source_code,4193,2025-06-21T00:01:46.225738,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),d998a4ca846c78679728a918b6f71df67c30b6961ede3cffa609f2cf6ad160eb
tests/utils/test_utf8_handling.py,test_utf8_handling.py,source_code,5791,2025-06-21T00:01:46.228483,Paul Hernandez,1,Paul Hernandez (60959+phernandez@users.noreply.github.com),50ec792e572af51cd2d996d4ddacbcfd3bbd79aa928818a90c42117451ea829f
tests/utils/test_validate_project_path.py,test_validate_project_path.py,source_code,15346,2025-07-30T09:39:45.729224,jope-bm,1,jope-bm (joe@basicmemory.com),27a4bf2a9d277e6cd773619e5241b20175d211ec60c284361bec404fd99143f3
uv.lock,uv.lock,other,232710,2025-07-30T09:39:36.619155,Paul Hernandez,3,Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co),caa1e3f6e66464b884a78cab77df2fe303fa3c0dc573be0196474b6d3c150581
1 path name category size_bytes modified_time primary_author contributor_count contributors_list sha256_hash
2 .claude/commands/release/beta.md beta.md documentation 3103 2025-07-01T08:33:22.037438 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 345f06e3f304470a8892e96979355919c8e5d8f4212ebbe543c3272fd15a5cbe
3 .claude/commands/release/changelog.md changelog.md documentation 4648 2025-07-03T18:43:10.075727 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) ea2484352f4f881aa71f546dcf84b0882d60c96673a88406aa2f7e12a282a1f4
4 .claude/commands/release/release-check.md release-check.md documentation 3344 2025-07-01T08:33:22.040060 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 7dd41a40e95c89153936c4ea60a3c989eccd5973fff9f6caef156de82f12bd04
5 .claude/commands/release/release.md release.md documentation 2925 2025-07-01T08:33:22.043674 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 0e4afd788fcf85fbe46094452e9b92a4290c3e23702283e72ee56aa9288476e5
6 .claude/commands/test-live.md test-live.md documentation 18720 2025-07-03T18:43:10.076403 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 21a9edeefb3e5673d833151a2fd0464087c0f0a9d056fdd7fca474c1d177d6fc
7 .dockerignore .dockerignore other 623 2025-07-01T08:33:22.048301 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) b3079bffad89d07186c9166725075524ffc07ceea6dc1d53fdbea6dca9585684
8 .github/ISSUE_TEMPLATE/bug_report.md bug_report.md documentation 967 2025-03-01T14:22:50.968994 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 0d34443ddda84a5e9726c8268083c9646d2cc64ff9c5ebf56c89587cef4c7706
9 .github/ISSUE_TEMPLATE/config.yml config.yml configuration 374 2025-03-01T14:23:26.936836 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) f4e21bb9b7f053509b6c08548a2649a5d62f44f0106810aa8c915d2f29acc623
10 .github/ISSUE_TEMPLATE/documentation.md documentation.md documentation 557 2025-03-01T14:23:40.020117 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 78f80a6b9a2b954695f74a847a068e0b780da6020572401c13c931555a4a9db5
11 .github/ISSUE_TEMPLATE/feature_request.md feature_request.md documentation 786 2025-03-01T14:23:06.344081 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) cee834de442221d53f3d2eeb85b81f3a641b3a7cb587ef8a169452305007439d
12 .github/dependabot.yml dependabot.yml configuration 529 2025-03-15T10:40:16.936258 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 8c6c2ef9a1417da63adb49c70f45524129bd5c46bbd7452b6b97cfe65205f89d
13 .github/workflows/claude.yml claude.yml legal 4628 2025-07-03T18:43:10.076958 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) d026f1756310781b85abc491b454cc31b52dfce4b951cdf8a4a555b6b047604c
14 .github/workflows/dev-release.yml dev-release.yml configuration 1405 2025-06-03T08:31:42.915367 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 58bcfc9e11e210e02dee76aabe7d1378da4edafb7f61857049ee6ccee9d45ffa
15 .github/workflows/docker.yml docker.yml configuration 1621 2025-07-01T08:33:22.049870 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c918a86f2b16ebb45182a73c45272bcd6cea7022cc6e0eaeb2b2a24d8eebfe4d
16 .github/workflows/pr-title.yml pr-title.yml configuration 887 2025-02-17T16:29:35.733646 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) b6df62a20235496feba4d9419c85d6e8446c4d447ad69e7f57b51cc8953f68f4
17 .github/workflows/release.yml release.yml configuration 2479 2025-07-03T18:43:10.077261 Drew Cain 2 Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co) 163307a99e2f3d317af6ae8927e1537654d88bf574a6958ac0bcd2d4de266b2a
18 .github/workflows/test.yml test.yml configuration 1426 2025-07-01T08:33:22.054430 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) ab09084a11be8adfc83fc6285c652fbe44a4584aa7d7d3658fcf0c57112d1640
19 .gitignore .gitignore other 566 2025-07-01T08:33:22.055006 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 358658b0faa8c3145e539421deba4ad0bac4a8ea2e608b2c2f867a822c67b36f
20 .python-version .python-version other 5 2024-12-02T16:41:37.012830 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 7b55f8e67b5623c4bef3fa691288da9437d79d3aba156de48d481db32ac7d16d
21 CHANGELOG.md CHANGELOG.md documentation 53647 2025-07-06T10:34:45.550847 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); semantic-release (semantic-release) 0b165eb18975ff253cde08f4687b7808ac6ce63b6d8c10912c495a76c9058d1a
22 CITATION.cff CITATION.cff other 302 2025-02-17T16:29:35.735146 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) bc4878cf6f80bb64655f3f93a5821ffe0924ad8311c784b5f81a36093fcffdda
23 CLA.md CLA.md legal 1342 2025-03-01T14:12:38.435132 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) c238c7ff4f2b8451c6bba1bbacd10b04fb7d41d9a9cd76a62644d8193791d169
24 CLAUDE.md CLAUDE.md legal 12310 2025-07-03T18:43:10.078147 Drew Cain 4 Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); Ikko Eltociear Ashimine (eltociear@gmail.com) 751f10c1a9a9c0ba2054d9c9cd36cf0989d6a347491fd505bb6504ee74b12900
25 CODE_OF_CONDUCT.md CODE_OF_CONDUCT.md documentation 509 2025-02-17T16:29:35.735238 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) b276b464e85eb1e5d9f09d90bba9573508a7bf81d2eeb38d0f25bd9f2fa66198
26 CONTRIBUTING.md CONTRIBUTING.md documentation 7329 2025-07-30T09:39:36.607158 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co) ca822fe39cc529bfc3822d317ab8a20fd141ec3ecb8c20de9e2eca3edce1c282
27 Dockerfile Dockerfile other 856 2025-07-01T08:33:22.056908 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) c45501905423990e31ffdb8ae4e976eca6423c6784905c1036bcc7795b70feef
28 LICENSE LICENSE legal 34523 2024-12-02T16:41:20.739392 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 8486a10c4393cee1c25392769ddd3b2d6c242d6ec7928e1414efff7dfb2f07ef
29 README.md README.md documentation 16261 2025-07-03T18:43:10.078281 Drew Cain 6 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Jason Noble (github+jasonn@jasonnoble.org); Marc Baiza (43151891+mbaiza27@users.noreply.github.com); Matias Forbord (codeluggage@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 2c4b82b30f49ab465617034fda999157450ed168f8e097fe8e9ca7ac65a197a7
30 SECURITY.md SECURITY.md documentation 303 2025-03-12T16:04:01.989927 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 96932268b8fe737577941b49e9dff5ff8ad59c11cc3f9a016989589ef5c98c1f
31 docker-compose.yml docker-compose.yml configuration 2534 2025-07-01T08:33:22.059281 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 4a9fdfd2f0d42b148fe021eee77fd5e772c7ba9c2fe5d0cc310c8c7a64257417
32 docs/AI Assistant Guide.md AI Assistant Guide.md documentation 16423 2025-07-01T08:33:22.060491 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c717869a3d356852077026591364ecb0589a6d53f9764af027c57d142ea7ff55
33 docs/Docker.md Docker.md documentation 9088 2025-07-01T08:33:22.060976 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) e13d3f50148353046b52d9d493986880f76f2914ef4efe1a759b2cc9d10913a4
34 justfile justfile other 5496 2025-07-30T09:39:36.608008 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com) a8df6c73ee8cf3eaa48e4cba193dffbc2821b843a8cc0c0cd58b8517f2252907
35 llms-install.md llms-install.md documentation 2307 2025-06-29T14:19:28.826375 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 674105eb85c8f1d59fc2ddc6840f2a2a3e293358687a305c37dffc8144304f97
36 memory.json memory.json configuration 90075 2025-06-29T14:19:28.827172 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 22d5eee995ca0548b7d9dd152f9a3690c42a514cbf38fea750b3ed2a17dd99c5
37 pyproject.toml pyproject.toml configuration 3279 2025-07-30T09:39:36.608791 Paul Hernandez 4 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); semantic-release (semantic-release) 428a5d64d4555dc7cd2a81b89a3444bdb1d2f3017257fbc9160bd0ae982718e1
38 smithery.yaml smithery.yaml configuration 433 2025-03-11T16:36:03.389716 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 63f13499cf4fee0751b5005f5bd85597dc1c7f9a881f4ec8147cc23e95e75c2d
39 src/basic_memory/__init__.py __init__.py source_code 256 2025-07-06T10:34:45.551291 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@gmail.com); semantic-release (semantic-release) c946490ab9d64957d25df37f721392024916f8a81ed838f70a8e938b1c2637db
40 src/basic_memory/alembic/alembic.ini alembic.ini configuration 3733 2025-02-23T17:31:23.198433 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 20466c9c5f026db66793006bebb2f328a3686c7bb34da40d52f33c3eca29e717
41 src/basic_memory/alembic/env.py env.py source_code 2838 2025-07-08T20:39:18.336650 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) e241d987eadfcd5011cbd9ddbecb833d306de87937759d81c08d37d04a6906b0
42 src/basic_memory/alembic/migrations.py migrations.py source_code 718 2025-06-21T00:01:59.613806 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 96b8873d70dd04b48d5c45b7413a54d1224ab9577557ef0dad5929377a9fb144
43 src/basic_memory/alembic/script.py.mako script.py.mako other 635 2025-02-17T16:29:35.739659 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 304a8bfb6a804e5493f5300e79882c70c9f5bb2e87512f4d16f0e097dddd323f
44 src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py 3dae7c7b1564_initial_schema.py source_code 4363 2025-06-21T00:01:59.595762 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 9536d69409ddd5eb3bc54f7d0e82607da45ed7f2ad7bc4cbf7cae2a9e28657cd
45 src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py 502b60eaa905_remove_required_from_entity_permalink.py source_code 1840 2025-06-21T00:01:59.604717 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 93ac584e660f33d468b3eec203b070641298c282bf82655d0beda7f050237681
46 src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py 5fe1ab1ccebe_add_projects_table.py source_code 4379 2025-06-21T00:01:59.601299 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) d82098f5aca3cdbada60c7229ea4ac262f527349eed9ef9e864509bacfaccf7e
47 src/basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py 647e7a75e2cd_project_constraint_fix.py source_code 4210 2025-07-01T08:33:22.063463 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 604ac5908a5976272f52297866d13abb14a99390590935d9fd37cf13e32049fa
48 src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py b3c3938bacdb_relation_to_name_unique_index.py source_code 1428 2025-06-21T00:01:59.598551 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 46c1b2990cdf4575752d234a8b28b494c8a54f15b5360c12f6347aef27b66a92
49 src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py cc7172b46608_update_search_index_schema.py source_code 3679 2025-06-21T00:01:59.610909 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 9036af47d42ac7dc12bb93f7a9de1266aff0688b031b550c4e0d92983a24b4c5
50 src/basic_memory/api/__init__.py __init__.py source_code 72 2025-06-21T00:01:59.579981 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) c02a63fb6d63d43d0acca97d425eae9cb055158d0ad6e1a9fc57926512adaa99
51 src/basic_memory/api/app.py app.py source_code 2897 2025-07-08T20:39:18.337081 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ad673ac2c09410af5830f6afdffaa28b0040480dacd52ff01750b8b2c066e8cf
52 src/basic_memory/api/routers/__init__.py __init__.py source_code 398 2025-06-21T00:01:59.549416 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 4443b908a43dea8e6fb4658009cb08c48a56c9b21449e29773cdd159b59cf014
53 src/basic_memory/api/routers/directory_router.py directory_router.py source_code 2054 2025-06-21T00:01:59.567371 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ac1407beec1f7d43a4d222af704b3642559c960bebf2eaf6e1ffe91f7fac5514
54 src/basic_memory/api/routers/importer_router.py importer_router.py source_code 4513 2025-06-21T00:01:59.561600 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) c45502a2b90f5a8f00174c9ad14adc2e65cd7fc0a33d9740a9d750207f0f3bea
55 src/basic_memory/api/routers/knowledge_router.py knowledge_router.py source_code 9738 2025-07-01T08:33:22.064119 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) e1d0ffb4fa5c246582ba844a11b417092de1a173567be55b7060bbc55fbc5681
56 src/basic_memory/api/routers/management_router.py management_router.py source_code 2730 2025-07-08T20:39:18.337438 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) cdbce294dcec6146c56c4dae15744cdf77039fd21b23eef7cbc0b5f9bfb5f4ee
57 src/basic_memory/api/routers/memory_router.py memory_router.py source_code 3003 2025-07-01T08:33:22.064510 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6bd0a7c775e0c1290efb6001173237c0cdcfa0c1b1bb27c9145a7b35f1596a97
58 src/basic_memory/api/routers/project_router.py project_router.py source_code 8444 2025-07-30T09:39:45.721369 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6539c69f1d506c65d14cc2c151876b19057f37d84d51a9e6f464ed47a4692648
59 src/basic_memory/api/routers/prompt_router.py prompt_router.py source_code 9948 2025-07-01T08:33:22.065221 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) e30c6aebe35112054933c37d0b462c3750005030fc9e44c23b35b2cd2a93485c
60 src/basic_memory/api/routers/resource_router.py resource_router.py source_code 8058 2025-06-21T00:01:59.570399 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 584244a84698ff24ca8f9f94fab5b891740a51c25f972920c08ebf83f478d5c9
61 src/basic_memory/api/routers/search_router.py search_router.py source_code 1226 2025-06-21T00:01:59.543020 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 183eb68e50904e22ff54db1d89b8be6f57fa1f8d0a096a3d497d8297b607e105
62 src/basic_memory/api/routers/utils.py utils.py source_code 5159 2025-07-03T18:43:10.079143 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 9e60f57da24e1dc9d64236c26a7a2353003dc618a77fbeb853c494aa3357a57c
63 src/basic_memory/api/template_loader.py template_loader.py source_code 8607 2025-06-21T00:01:59.576132 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 7b16d3797c89460c8b1664a335eae8c634fb5f60d6166d97e6a5156b776b6d83
64 src/basic_memory/cli/__init__.py __init__.py source_code 33 2025-06-21T00:01:59.456735 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 6ab70a2c05910e13c3ef1e6df34325be265e633c076741998a0cb2dcd295a069
65 src/basic_memory/cli/app.py app.py source_code 2268 2025-07-08T20:39:18.337708 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) f710670380d707c4458ad881f7a25bb3c5cdb2bcff59f139f37421264fe8f2f8
66 src/basic_memory/cli/commands/__init__.py __init__.py source_code 393 2025-07-08T20:39:18.338070 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) de8a23702f98fb844fa9f7fdbedc16ce24ff4f8baf05589c2f4a521cd8a55645
67 src/basic_memory/cli/commands/db.py db.py source_code 1480 2025-07-08T20:39:18.338326 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 704a1096d80ab9d12e247d029fe6223e935a0d0ceee7e615c020f46a720828e0
68 src/basic_memory/cli/commands/import_chatgpt.py import_chatgpt.py source_code 2856 2025-07-08T20:39:18.338787 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 8957cca3acab6351335624a518bdc19d956487e93d86dd1b6c2309e9d5850ae5
69 src/basic_memory/cli/commands/import_claude_conversations.py import_claude_conversations.py legal 2946 2025-07-08T20:39:18.339053 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7bc97838732bf00f4fb4a80e3ba4fdfbce8971ae85cc2ac902c3b3a3e110ae57
70 src/basic_memory/cli/commands/import_claude_projects.py import_claude_projects.py legal 2891 2025-07-08T20:39:18.339310 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6321577075801c99ad47a0cdc13b5aa3c9ca102a05ca8f06ae2a51125a8c43bc
71 src/basic_memory/cli/commands/import_memory_json.py import_memory_json.py source_code 3013 2025-07-30T09:39:45.721637 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7ea193f6720b2672290ad16c79a143a31d88a1d567838f12b9ebf9110a7c0338
72 src/basic_memory/cli/commands/mcp.py mcp.py source_code 2593 2025-07-08T20:39:18.340025 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 3e1be3d27b18ef4743204b7cf8a37fbc2a1a91fc1636c468e08cefcd8597bac6
73 src/basic_memory/cli/commands/project.py project.py source_code 13836 2025-07-30T09:39:45.721838 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) af3e6f30410ab48355f4b1a46aaa3aa5423cb0a0490f51447db1d25e09f39916
74 src/basic_memory/cli/commands/status.py status.py source_code 5809 2025-07-08T20:39:18.340324 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) b6d0ea237d714d054f69b24a2058beba74e224a2fa4a80a525d62a2aa2ea2d70
75 src/basic_memory/cli/commands/sync.py sync.py source_code 8213 2025-07-08T20:39:18.340627 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 703b3e73c4c33850c27f6f4c07abbf5d4ce5dc43f706bf0c43264bbb45f8b213
76 src/basic_memory/cli/commands/tool.py tool.py source_code 9540 2025-07-01T08:33:22.070903 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 9b2fa400b9f7921bf55b602f8bbdfa36b1ec7e4a5bc8fe7b9838b92e31f0a9ed
77 src/basic_memory/cli/main.py main.py source_code 465 2025-07-08T20:39:18.340868 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7a405b12bff98e319968526238ae15859df0362bba5a3857562fecca47b5c70d
78 src/basic_memory/config.py config.py source_code 12487 2025-07-30T09:39:45.722031 jope-bm 5 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 86341330a041b94d38f5e4f1b94f3509d74351c67cc826af1a4ff57313e5f726
79 src/basic_memory/db.py db.py source_code 7428 2025-07-08T20:39:18.341550 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 25e053b0b3f9e8fa823b05fc099001efe8a3a4f6e0f80728e5079ba45aa406d8
80 src/basic_memory/deps.py deps.py source_code 12144 2025-07-08T20:39:18.341870 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) bce28cd9ca549b8afce0bc689cc1fb2dc80cd5b929f85114aa682bb8ae82411d
81 src/basic_memory/file_utils.py file_utils.py source_code 6700 2025-06-21T00:01:59.587200 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 79ac5328b2c46d3232fcc6ff22ffc39ade085c0252ad91958be2a7ae9c9c8b71
82 src/basic_memory/importers/__init__.py __init__.py source_code 795 2025-06-21T00:01:59.295471 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 0537015bdecfded85cb166b9c3db50b2f3aef329c70e0c36fbcb4f824099a21f
83 src/basic_memory/importers/base.py base.py source_code 2531 2025-06-21T00:01:59.305335 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 6b0c1efd4f827f348834aa0cea2ae8eebbb842a2e5b1f5f3747ced0ef79b9f13
84 src/basic_memory/importers/chatgpt_importer.py chatgpt_importer.py source_code 7372 2025-06-21T00:01:59.308956 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) dfa540b196ab23b5c4e6bfcac4da567873351cf7c78fa35f4c3b87e84c58e218
85 src/basic_memory/importers/claude_conversations_importer.py claude_conversations_importer.py legal 5725 2025-06-21T00:01:59.288540 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) a7bc9e872f4f81ce5f79fe9dd1a6fd0f00a6f020a2cb2664184a97f14eeb1dbc
86 src/basic_memory/importers/claude_projects_importer.py claude_projects_importer.py legal 5389 2025-06-21T00:01:59.291737 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) a452675fd9bb18ebf64eb4bd7f69ccd7e993b617931015a3c4ab700d67493863
87 src/basic_memory/importers/memory_json_importer.py memory_json_importer.py source_code 4631 2025-07-30T09:39:45.722316 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) bc7d045299f17ed9ad5cebff7b1423250ec28a11130e47a0ac48d3ab82bdeafc
88 src/basic_memory/importers/utils.py utils.py source_code 1792 2025-06-21T00:01:59.298428 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) ee7e22fd4812362394f62ed8944abe80738c1e3ab88131faf639f4a8ccfd6c89
89 src/basic_memory/markdown/__init__.py __init__.py source_code 501 2025-06-21T00:01:59.316337 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 0ddce2a025ad0e729aab4e411d82e02ffefc15ac041cba4b5e7a7e90f4957c87
90 src/basic_memory/markdown/entity_parser.py entity_parser.py source_code 4516 2025-06-21T00:01:59.321461 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 1b0d1177358645ccbadd170b3f62760dc9bd838d38c741978ab0da5836234d68
91 src/basic_memory/markdown/markdown_processor.py markdown_processor.py source_code 4968 2025-06-21T00:01:59.325241 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 4b99f2ebdceed9d96a3bbb562682eba4b4b383c7a64080eaec3bbba25a4952c9
92 src/basic_memory/markdown/plugins.py plugins.py source_code 6639 2025-06-21T00:01:59.312733 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 82d2332918e866ccaf06a2e954d9eb9b397f71b4d9e591a7f2472e5f1423464a
93 src/basic_memory/markdown/schemas.py schemas.py source_code 1896 2025-06-21T00:01:59.329982 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 7b2c580abd615725a62267257b46ac13922dfc30fa01192a681658bb528ae67e
94 src/basic_memory/markdown/utils.py utils.py source_code 3410 2025-07-03T18:43:10.079889 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 1b757f0d06e60e3ea276c0b2ea44fe1a156a895e093c1e607d6286e702bf4ae4
95 src/basic_memory/mcp/__init__.py __init__.py source_code 35 2025-06-21T00:01:59.404757 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 76c0ce84aaa361e21b0942db1c8c5f708b536eab9d12e120d4da7ce9eab41844
96 src/basic_memory/mcp/async_client.py async_client.py source_code 925 2025-07-30T09:39:45.722547 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 6531f4387f30a30a322197ff51d6eacae4b25a58c648095931b3d1145d1da303
97 src/basic_memory/mcp/project_session.py project_session.py source_code 4203 2025-07-08T20:39:18.342906 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 4da403ec93dec9063eeb8b05246e3501740d162cc77a067d3ce54ba43d690819
98 src/basic_memory/mcp/prompts/__init__.py __init__.py source_code 615 2025-07-08T20:39:18.343263 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) f8197d0e08f64c3f4f50b8f38203ea5eebcf123582472ed2f58834de1dbe53b0
99 src/basic_memory/mcp/prompts/ai_assistant_guide.py ai_assistant_guide.py source_code 821 2025-06-21T00:13:53.262832 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) f13239c4e6e2455730bfac3d6f2d71407957d3086fc84efe2c6b22a833114c58
100 src/basic_memory/mcp/prompts/continue_conversation.py continue_conversation.py source_code 1998 2025-06-21T00:13:53.263309 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) aec9a50b657b7bb1ba0c02b42bcdb9bc5b0f2a0b1143bd361c5ce7ea59076833
101 src/basic_memory/mcp/prompts/recent_activity.py recent_activity.py source_code 3311 2025-07-01T08:33:22.073986 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) d2fd5cddbd927430f15d5b85f1e3a3368a18cb4e2e4587a5d29749d2b9e0830e
102 src/basic_memory/mcp/prompts/search.py search.py source_code 1692 2025-06-21T00:13:53.264093 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 9dbf3c319cbdb5d5bf32608b51522d8ae92b2dd6f7c441d62efd0954b525738a
103 src/basic_memory/mcp/prompts/utils.py utils.py source_code 5431 2025-06-21T00:01:59.425042 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 55a72b6eac18b724a9225608aca1e8e6cea3b684ccb1c609aab1511f7ce90ba4
104 src/basic_memory/mcp/resources/ai_assistant_guide.md ai_assistant_guide.md documentation 14777 2025-03-28T19:12:38.653627 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) aa76160e46256fe2662ae3a86799659916acfede1d5835c1fe2f0b136efb2e0b
105 src/basic_memory/mcp/resources/project_info.py project_info.py source_code 1906 2025-06-21T00:13:53.264918 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 2dc5244f1e225c17d4e8ba784d5721efc3aa2e8a5b3b2e258f22a77ebe155eca
106 src/basic_memory/mcp/server.py server.py source_code 1248 2025-07-08T20:39:18.343419 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 0a910cae27d61ea923e90fbe2d4b5c7cacf3b29d3e156f0b7f77872ab973c761
107 src/basic_memory/mcp/tools/__init__.py __init__.py source_code 1619 2025-07-03T18:43:10.080029 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co) 872b771dd52ec3b763645a2baf6e10a70f049ce3106830a6d3f053b3e09a5fe6
108 src/basic_memory/mcp/tools/build_context.py build_context.py source_code 4611 2025-07-03T18:43:10.080426 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 724280b77b8f5f3e61cd3fdeebc3ee66e2bcfedaaea3638e6a2e2e33fcb1978e
109 src/basic_memory/mcp/tools/canvas.py canvas.py source_code 3738 2025-07-01T08:33:22.076204 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) db617d1bd81f3dbfa5f22d41e6b6b825afe1f73618f37acf63d9830390b98246
110 src/basic_memory/mcp/tools/delete_note.py delete_note.py source_code 7346 2025-07-01T08:33:22.076726 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) b52c9173f5600662f255e7a70a5c17d5293ef8b29c19a8403334d7da62b65c8b
111 src/basic_memory/mcp/tools/edit_note.py edit_note.py source_code 13570 2025-07-01T08:33:22.077181 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) ab8c7e7fbfa3fe5fb0ce6d7bf805454f5fd6182a340aae25237b1e6127b6d5a6
112 src/basic_memory/mcp/tools/list_directory.py list_directory.py source_code 5236 2025-06-21T00:13:53.267453 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) f85c43b02aeee580f4d8ce2a9100c0bab1095b245a0bb608e1847ace0d1ab51f
113 src/basic_memory/mcp/tools/move_note.py move_note.py source_code 17541 2025-07-30T09:39:45.722919 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 5ef27d9baaebc2c5656fc49c4798a4e4e40a70b6cd9d1e761dbcae021bad558c
114 src/basic_memory/mcp/tools/project_management.py project_management.py source_code 12944 2025-07-06T10:34:45.552403 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co) cdac736d65129f689a85c6b82f8e043bc84a31657ead7a8331771171eeaa860f
115 src/basic_memory/mcp/tools/read_content.py read_content.py source_code 9125 2025-07-30T09:39:45.723469 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 96a13addac507fd874394dfa2e1e5ed71af5eb89d0872c1d68cacf9cac3f8724
116 src/basic_memory/mcp/tools/read_note.py read_note.py source_code 8132 2025-07-30T09:39:45.723828 jope-bm 5 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) dff53ce02b16d9c5fca315b3f09bb70867a89d614b0ef3f0548dce87978048ee
117 src/basic_memory/mcp/tools/recent_activity.py recent_activity.py source_code 4833 2025-06-21T00:13:53.269120 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 5d58cd2402679b1bf3c7dfcbb3503e40e776c9347ba499524d3b91c528af98de
118 src/basic_memory/mcp/tools/search.py search.py source_code 15883 2025-07-03T18:43:10.081557 Drew Cain 4 Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 8519b0057468c4450eb543a2f561bcd0d7cb96e1ce1b95e948e02b309ba6b7ca
119 src/basic_memory/mcp/tools/sync_status.py sync_status.py source_code 10517 2025-07-08T20:39:18.344231 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 73dd73b186eaec8b82e6b17e39a67c27082d24e0653dc4e4b35712bd83b80a22
120 src/basic_memory/mcp/tools/utils.py utils.py source_code 20892 2025-07-30T09:39:36.616253 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) a95004911e276822eba88a3fef15c5b9ba861b1ca9a2ecfe0c1e3fb2f4ef0116
121 src/basic_memory/mcp/tools/view_note.py view_note.py source_code 2499 2025-07-01T08:33:22.080024 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 75d357c72113b1d0394987e521a4158ff09b77b23b08b56cddab5144331b1a68
122 src/basic_memory/mcp/tools/write_note.py write_note.py source_code 6612 2025-07-30T09:39:45.723985 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 771396fb49d397feb5f7e36321d4d233c22c4d1b53414912c849957c6e96fc83
123 src/basic_memory/models/__init__.py __init__.py source_code 333 2025-06-21T00:01:59.437212 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 8f40b876d162f85384690291f1d416106f9d26d750d793414e2260e276c85cd5
124 src/basic_memory/models/base.py base.py source_code 225 2025-06-21T00:01:59.447249 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) e2101727c084d519e32a16f6de53ddf9033b1bf15721d4e8c0c27d6d18b1b295
125 src/basic_memory/models/knowledge.py knowledge.py source_code 7087 2025-06-21T00:01:59.444376 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 005c5f292f1f45ae372aadc48c9080b9fa6d7b854d0bb7ecf587ec843ac1e28d
126 src/basic_memory/models/project.py project.py source_code 2773 2025-07-01T08:33:22.080907 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) a14ad06943aeeff9ae4a5fa2dfc0e1d07ce6085acc02dc20c402c3513b7d9397
127 src/basic_memory/models/search.py search.py source_code 1300 2025-06-21T00:01:59.440923 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 3e143cc38b5a0294af8e1d43a4f841e1c1fd193b76136a68f83159ce19e86646
128 src/basic_memory/repository/__init__.py __init__.py source_code 327 2025-06-21T00:01:59.256363 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 3162bea3c42292accea5ee52c8f6ca4368a8079056034529cfae6d820f84d035
129 src/basic_memory/repository/entity_repository.py entity_repository.py source_code 10405 2025-07-03T18:43:10.082570 Drew Cain 3 Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) e2a8d1eba6c8d64bc61d7168df0fe8c29a670858bf9daeac464a0f440273fae0
130 src/basic_memory/repository/observation_repository.py observation_repository.py source_code 2943 2025-06-21T00:01:59.269646 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) aa132f1cb4a36a84f715afdc40e2ac4f98d83e3eba1974b2b4404cc0b020ca04
131 src/basic_memory/repository/project_info_repository.py project_info_repository.py source_code 338 2025-06-21T00:01:59.252582 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) f172d50182a405643a19b2a3d62a80f4e2b41463c775394eb3b66d7de51ff6df
132 src/basic_memory/repository/project_repository.py project_repository.py source_code 3803 2025-07-30T09:39:45.724344 jope-bm 2 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 9083ba214b2bcaaf98164d9c33cda7add52bc77f7269ecb6e43cdd5088728b7c
133 src/basic_memory/repository/relation_repository.py relation_repository.py source_code 3179 2025-06-21T00:01:59.246745 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) cfb3a8e59cff27e063e91bd00e949647bdd92e4d9fc46edeee3acc6de15e26f4
134 src/basic_memory/repository/repository.py repository.py source_code 15224 2025-06-21T00:01:59.273355 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 3096fe71bf106506cbf86aeafe2aafe0aabbe5a5f6c90a212c8aa1e53e1f171c
135 src/basic_memory/repository/search_repository.py search_repository.py source_code 21936 2025-07-03T18:43:10.082844 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) a972f73d1b71dac5770e8eb3793c6c9ac44e4e792f9dab528f8c4e6c6a80bcaa
136 src/basic_memory/schemas/__init__.py __init__.py source_code 1674 2025-06-21T00:01:59.514555 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 98480815c75379bfafe32d2090e87fa40e73caa19b664fbd5db5ea9528ba58cb
137 src/basic_memory/schemas/base.py base.py source_code 6738 2025-07-01T08:33:22.082193 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 171f7b0c4ab33abef2f7379eb1e3bda950586ce7edff83907fd12255f84e267e
138 src/basic_memory/schemas/delete.py delete.py source_code 1180 2025-06-21T00:01:59.502563 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 50047624af7d58c8f780ffb2a065a51c3dde64492f9534917fc42860813e59fc
139 src/basic_memory/schemas/directory.py directory.py source_code 881 2025-06-21T00:01:59.529023 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 17dfcbac9a91a9bfe43b4f060ca2735cb6f69e16d81b63dd554a397830ff29fe
140 src/basic_memory/schemas/importer.py importer.py source_code 693 2025-07-30T09:39:45.724633 jope-bm 2 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ac33df423ca32b28ce7b6ea9c29d541f8783a86c0c29f78db35163bf93f139cd
141 src/basic_memory/schemas/memory.py memory.py source_code 5833 2025-07-03T18:43:10.083167 Drew Cain 3 Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) acb4a953a553feca672c4895798a7d948ec51f922f75b66dd7d55716e3bebed3
142 src/basic_memory/schemas/project_info.py project_info.py source_code 7047 2025-07-01T08:33:22.083248 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7dc3635297b6e7fe6e3262b2d78da26f7a79a846a4cecd5624f2e4828979cf2c
143 src/basic_memory/schemas/prompt.py prompt.py source_code 3648 2025-06-21T00:01:59.525753 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 4a92157d9a6b413f04e6e3f8d23dc2a417369c729f9703a8de2643ec114f2071
144 src/basic_memory/schemas/request.py request.py source_code 3760 2025-06-21T00:01:59.511789 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 32fe44beb2d99452223ebf1d3a3a3fe105ef92c79885023b71dfd7db30ecc503
145 src/basic_memory/schemas/response.py response.py source_code 6450 2025-07-03T18:43:10.083478 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 5eea4660a2abe48d83ed083d1c2483fdcfb403e0b504f03c14d22f1cae866abb
146 src/basic_memory/schemas/search.py search.py source_code 3657 2025-06-21T00:01:59.522804 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) cb032c0c60102b6b0ed934f995cf9d6bf93aece296d71d537a75e8ae61c75afe
147 src/basic_memory/services/__init__.py __init__.py source_code 259 2025-06-21T00:01:59.655059 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 5c6b7c597ddf5ffd0af4bdfb32ccbc1c5f2794c658206dee43a9945fafe226d8
148 src/basic_memory/services/context_service.py context_service.py source_code 14462 2025-06-21T00:01:59.672086 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (paulmh@gmail.com) e1178b005e6a89f03d6b239e3c6b152aeb30d535a3f280734440a3aec16228f2
149 src/basic_memory/services/directory_service.py directory_service.py source_code 6017 2025-06-21T00:01:59.648501 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) fd838f5ec79033892777b3c8140868f4b57f13e1658d513959524a434b9f959b
150 src/basic_memory/services/entity_service.py entity_service.py source_code 30440 2025-07-03T18:43:10.083956 Paul Hernandez 4 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 7cd5163eca6b8a0772e838c8c869e478166763cd6a2d745b0b9aa5c25a65baee
151 src/basic_memory/services/exceptions.py exceptions.py source_code 390 2025-06-21T00:01:59.668908 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) a158d0af9d1742a9c5ab5f8c34a062948d9286d1c3c72a5abf20e4d547b21e1c
152 src/basic_memory/services/file_service.py file_service.py source_code 10059 2025-06-21T00:01:59.641785 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 8c2ae69c4913438b7d1c5ecbfcce812fbb5d0ea8e3cedcbd8694e8f40cf086f3
153 src/basic_memory/services/initialization.py initialization.py source_code 6715 2025-07-08T20:39:18.344482 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 4dde58b799cf4ac90631e59949b55b3355a93bdf99df0d9c2408c0cea67e10c4
154 src/basic_memory/services/link_resolver.py link_resolver.py source_code 4594 2025-07-01T08:33:22.084908 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) d7efd516cbea753e6b5411def09aeaeb7539f5743487119ecf163c736e138a8c
155 src/basic_memory/services/project_service.py project_service.py source_code 30125 2025-07-30T09:39:45.725079 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) bce95c00aa9a1da0a8c8090ee34b5b1494207f8c99e6c25de4ec43fddc38f6be
156 src/basic_memory/services/search_service.py search_service.py source_code 12782 2025-06-21T00:01:59.665439 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7392b2d2e7f3ed83c5807855ccd450e0e79c17f254aedee700bce9323a1b5b83
157 src/basic_memory/services/service.py service.py source_code 336 2025-06-21T00:01:59.636167 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 57e77ff20395d3bcc62100e92fe2acaacdd937d977a9fdc764e2b57ff60d4da8
158 src/basic_memory/services/sync_status_service.py sync_status_service.py source_code 7504 2025-07-03T18:43:10.084229 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 0a025d689e8e16f1632872104952105fc904537f3d32bcff592eb1f1dc76fbb7
159 src/basic_memory/sync/__init__.py __init__.py source_code 156 2025-06-21T00:01:59.621137 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 0951e0b981f8e7b876bb6c6833c2af3a29490bbd5726567ea9487c947723623e
160 src/basic_memory/sync/background_sync.py background_sync.py source_code 726 2025-07-08T20:39:18.345062 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 549af64ae91128b76c6df07ef517b82de85ca4ad796be44b5c0141fac01d4513
161 src/basic_memory/sync/sync_service.py sync_service.py source_code 23387 2025-07-01T08:33:22.086507 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 0310b927561370f593980d07773bce641b618b8fbf2d9e3890d174290a0344fc
162 src/basic_memory/sync/watch_service.py watch_service.py source_code 15316 2025-06-26T09:28:51.859209 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) 240ba6ac7523575945f4db442b7da3820d26c9605f2d7a2d357c4e35e215f523
163 src/basic_memory/templates/prompts/continue_conversation.hbs continue_conversation.hbs templates 3076 2025-07-01T08:33:22.086792 Drew Cain 2 Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) b6bac31d25c0e52d0909b2273285092f4e31bc219107f92ed511cd407b65e992
164 src/basic_memory/templates/prompts/search.hbs search.hbs templates 3098 2025-05-25T10:07:54.520119 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 1f570222c1caa78542d46ac7d8a79407ca467b9bd714fa9bd953e8b72a667820
165 src/basic_memory/utils.py utils.py source_code 8654 2025-07-30T09:39:45.725428 jope-bm 5 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); andyxinweiminicloud (andyxinweimin263@icloud.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 111f343e3367339730e081c08acf4613667be574f946126513b5d82da3086bed
166 test-int/conftest.py conftest.py source_code 8203 2025-07-08T20:39:18.345735 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 7231e1bc76cddc7c94433e853825dc0165b103bedf996c2c24eda6ae32fff5ad
167 test-int/mcp/test_build_context_validation.py test_build_context_validation.py source_code 6469 2025-07-08T20:39:18.346021 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) ee61d6b15cee0194fd74c1bcf9361d5a839f6081c7d571ef081da8fcefe1bbf2
168 test-int/mcp/test_delete_note_integration.py test_delete_note_integration.py source_code 13175 2025-07-08T20:39:18.346366 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 497495249b8bcf0af177d8705c6899875460707697980434e560cfe56f86feb3
169 test-int/mcp/test_edit_note_integration.py test_edit_note_integration.py source_code 19822 2025-07-08T20:39:18.346730 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 9ba704badd05808aee0b5a686b7e250e1c865229ec92dab561cba5287b6f6fc6
170 test-int/mcp/test_list_directory_integration.py test_list_directory_integration.py source_code 14744 2025-07-08T20:39:18.347106 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 2c4336a59de63f17ed252bb52d1330ebca901ad83bfebc9e5aa67f132a3c77c6
171 test-int/mcp/test_move_note_integration.py test_move_note_integration.py source_code 19825 2025-07-08T20:39:18.347344 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) cbb17688d0f9551306a7520b059ace7f7dfba70fc20bf0ec98b1148000d7ad7d
172 test-int/mcp/test_project_management_integration.py test_project_management_integration.py source_code 33175 2025-07-08T20:39:18.347658 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 93a43cd699453a7602a5def839740ba5027ab914eba3e7b66a026860ed6bd567
173 test-int/mcp/test_project_state_sync_integration.py test_project_state_sync_integration.py source_code 7728 2025-07-08T20:39:18.347907 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 80b0f5b5cd359498dcbd3af7dcb6194afa4582d8efb3faa38d28675ee45e0748
174 test-int/mcp/test_read_content_integration.py test_read_content_integration.py source_code 11187 2025-07-08T20:39:18.348233 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 6955dd343b40df088ac79175e52723501d83796335a16e43b7f58e16e757e1b8
175 test-int/mcp/test_read_note_integration.py test_read_note_integration.py source_code 1381 2025-07-08T20:39:18.348463 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) b93050da68d0e9d47d46879a386567f688399e28390f4eb31ee37353dc27514b
176 test-int/mcp/test_search_integration.py test_search_integration.py source_code 14690 2025-07-08T20:39:18.348959 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) e0957ada9dd9b12eae5843a37d241ec9293ca929f18281e31197dae36bff589d
177 test-int/mcp/test_write_note_integration.py test_write_note_integration.py source_code 9472 2025-07-08T20:39:18.349398 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) b2b56fee8351168d0c65640c295d969dc4575d9bea87927b2dc07e591cabdff3
178 tests/Non-MarkdownFileSupport.pdf Non-MarkdownFileSupport.pdf other 106751 2025-02-23T17:31:23.206428 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 4aa96f9d0ee830ef6a1ec92243f302bbe2fa8971b84945f4eb5e276bf1ffde96
179 tests/Screenshot.png Screenshot.png other 190076 2025-02-23T17:31:23.207771 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) dd82612fe013c39810d28ae0f2bbcca6ab2c9925b035d7720bb02493ddf5d0a9
180 tests/__init__.py __init__.py source_code 141 2025-06-21T00:01:46.216456 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 2ac5605e69ad8829e96b3689632536539f1cdd3149a29c1903f25af0793a5d65
181 tests/api/conftest.py conftest.py source_code 1404 2025-06-21T00:01:46.359728 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) ea46cde47a37c1f43fe079e48f5d0de8007155a0187f4445abc4f2ffde9c1791
182 tests/api/test_async_client.py test_async_client.py source_code 1382 2025-07-30T09:39:45.725666 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) a2f96226a75e5cff2326ca48ddccea4915964d83e529f7b99958bc233ccdc31a
183 tests/api/test_continue_conversation_template.py test_continue_conversation_template.py source_code 5152 2025-06-21T00:01:46.390901 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) cca08b0291db0ad693c60d8dc203660021feab46d9eb530be7f67e0ebb52c1d3
184 tests/api/test_directory_router.py test_directory_router.py source_code 9376 2025-06-21T00:01:46.356659 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 428626589f0010512481ba495368b0bf2b9617b22764e588eaa3562e86da4d37
185 tests/api/test_importer_router.py test_importer_router.py source_code 16578 2025-06-21T00:01:46.368070 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 03edf6e7404c7350afe76e54ea2bf0d66f668bcdb49f59702067a67b3694309d
186 tests/api/test_knowledge_router.py test_knowledge_router.py source_code 45771 2025-07-01T08:33:22.090490 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 43a5f91ae1fb9038e65c09701336fbdc4dbf40c8319c94727e6312fda9d6d56e
187 tests/api/test_management_router.py test_management_router.py source_code 6220 2025-06-21T00:01:46.402764 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) f6a3f41f263f10c08281525571e2e39fc9ae818ebb7e9895e3f3f3115ea05677
188 tests/api/test_memory_router.py test_memory_router.py source_code 5555 2025-06-21T00:01:46.399667 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) 2b8782015c893081fc67b7f13a7255d4e3dc45b27705a524f94918a339e2d486
189 tests/api/test_project_router.py test_project_router.py source_code 13288 2025-07-30T09:39:45.725847 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) af85d0870069d3831a9214372853994e5d12dc910e37298eb9958f72f6a8bb31
190 tests/api/test_project_router_operations.py test_project_router_operations.py source_code 1812 2025-06-21T00:01:46.381705 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) afd40879de3d7c508cca0feeae3cb7a8f3afcfbb06f59a6104189b1e3291376a
191 tests/api/test_prompt_router.py test_prompt_router.py source_code 5046 2025-06-21T00:01:46.396588 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 9115995b7dd8b44d8a9c06c5e1bbb177618286675a769889e35ac16f26fd9897
192 tests/api/test_resource_router.py test_resource_router.py source_code 13960 2025-06-21T00:01:46.384919 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ad3cb2cabaeab82a7e64253ceede7c1791e2bd70c92f60bc5f3be939292ca22d
193 tests/api/test_search_router.py test_search_router.py source_code 6409 2025-06-21T00:01:46.375427 bm-claudeai (AI Assistant) 3 bm-claudeai (AI Assistant) (claude@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (phernandez@basicmachines.co) ba3e3809795e72db9dd9c8c729048bdbbbdb897c2a5aa8b175112b5d4b56d152
194 tests/api/test_search_template.py test_search_template.py source_code 5258 2025-06-21T00:01:46.378721 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 8f0d16a1de947d0466d96afed02e695f7648adac70b9ba99753250068207a686
195 tests/api/test_template_loader.py test_template_loader.py source_code 8035 2025-06-21T00:01:46.406694 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 4fd7c6c4862cc0d877d29244ecdc0b52a0693fc4574a9667663bee36bfd36b62
196 tests/api/test_template_loader_helpers.py test_template_loader_helpers.py source_code 7445 2025-06-21T00:01:46.372114 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) 8dd35f11c9b3f2d96ac36263edf4430308728c04c9da543b1cb845b96ab20aa7
197 tests/cli/conftest.py conftest.py source_code 1185 2025-07-01T08:33:22.090848 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c3c73da7ad73224931e1fba4ebd70792221be607bfb1488bb5c9420bba03bdb8
198 tests/cli/test_cli_tools.py test_cli_tools.py source_code 13528 2025-06-21T00:01:46.318964 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) befb8cab50132e26a1b13b82ce8e93a3258282cf157a4230214bfcefeae65102
199 tests/cli/test_import_chatgpt.py test_import_chatgpt.py source_code 6719 2025-07-08T20:39:18.350234 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) df447335545248e2fb2417af33f8cc2f0143bd413a1783e41f89605de305b7c8
200 tests/cli/test_import_claude_conversations.py test_import_claude_conversations.py legal 5028 2025-07-08T20:39:18.350607 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ac4b3b9dfc331fa7fa32a2941c027ff8b6585a94a5ccfaaf0a4affe5cf19c00c
201 tests/cli/test_import_claude_projects.py test_import_claude_projects.py legal 4585 2025-07-08T20:39:18.350885 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 7eaab3d491d50ca59c8ba015ecd5740a5feae94d970ee17559c6df9d8558c2cc
202 tests/cli/test_import_memory_json.py test_import_memory_json.py source_code 4891 2025-07-30T09:39:45.726290 jope-bm 3 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (60959+phernandez@users.noreply.github.com) d6734ce059dacf97bc764d848b2e2a6ba52fa96871bc331ec9d2ddc60b766bb6
203 tests/cli/test_project_commands.py test_project_commands.py source_code 6578 2025-07-30T09:39:45.726703 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 51e2ac7ff44b0d1a1db6da406c5c2e6aebceb1b63a1e8d5ab51bbaa834507157
204 tests/cli/test_project_info.py test_project_info.py source_code 3874 2025-07-01T08:33:22.091600 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 0b08950e95a5f276f14c56f6fe99af4d41b8f04548e9b7746f807c5ac4155578
205 tests/cli/test_status.py test_status.py source_code 4160 2025-07-01T08:33:22.091978 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) a1ff89fdac4bf57ba03be92ac79b8ca3210af0b1132d5a2bd0fc0c253fcbf988
206 tests/cli/test_sync.py test_sync.py source_code 3864 2025-07-08T20:43:47.816788 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 77e0f6b42b584a5acfda3c2ff194ff5e71ca57a40cb4484d563f5482bbbb4c0f
207 tests/cli/test_version.py test_version.py source_code 289 2025-06-21T00:01:46.305368 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) db95665178a32d391bd83011d073db269cefba9da8a4dc4d3e392d47bc0e0a8f
208 tests/conftest.py conftest.py source_code 15286 2025-07-08T20:39:18.351368 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) c6f38f103ce58144ffe4562f0c47dad849974e96327f02805e854447e19bc411
209 tests/importers/test_importer_base.py test_importer_base.py source_code 4329 2025-07-08T20:39:00.549594 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) da872a073f2b90fda3c98c9f44cf45884f4f682d91ec1b1f931d42c34eee1939
210 tests/importers/test_importer_utils.py test_importer_utils.py source_code 1827 2025-06-21T00:01:46.184343 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) cbee630c855ceb1de764ac0cdb1d5d781c16cd3a934d67166adc235c98f363d7
211 tests/markdown/__init__.py __init__.py source_code 0 2025-06-21T00:01:46.196570 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
212 tests/markdown/test_entity_parser.py test_entity_parser.py source_code 8669 2025-06-21T00:01:46.206579 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 496fdab6fe164634f8223f827585a4c0dedd30ccea7b0b69dc79004ad0996de2
213 tests/markdown/test_markdown_plugins.py test_markdown_plugins.py source_code 5139 2025-06-21T00:01:46.200759 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 9624d73462aadcd47fb0edd0d87880959a8982eecfa39529f21e3b292c34cb83
214 tests/markdown/test_markdown_processor.py test_markdown_processor.py source_code 5728 2025-06-21T00:01:46.194175 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 35042aa57dd2aeed848c624aa7f69decfb18e83c3b217eca1fdacfc4a10831db
215 tests/markdown/test_observation_edge_cases.py test_observation_edge_cases.py source_code 4295 2025-06-21T00:01:46.209598 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 6f1ab7684bfa8b02af0e0c42b3d7aed91fcd0b1c6288cbc9b6d6943c166979fa
216 tests/markdown/test_parser_edge_cases.py test_parser_edge_cases.py source_code 5142 2025-06-21T00:01:46.213291 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) d511d7d1187e3c1d3a8d3e0ab9efc9e68e84115c46811e7a9dc21eca9a87d520
217 tests/markdown/test_relation_edge_cases.py test_relation_edge_cases.py source_code 3952 2025-06-21T00:01:46.203846 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) f8e2016308f84139342cc37ec6e389ffe52d7eb46f998ee327c7f0d5bba3ad9b
218 tests/markdown/test_task_detection.py test_task_detection.py source_code 401 2025-06-21T00:01:46.191444 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 37fe91a689742033a0eb76723557e31c2a85e591133383b3887572cb714db2a5
219 tests/mcp/conftest.py conftest.py source_code 1761 2025-07-08T20:39:18.351554 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 350b2ca42c52ef76e002deddb65fc0eccb9f8989bd26078ea1c100e3b93bae3f
220 tests/mcp/test_prompts.py test_prompts.py source_code 5989 2025-07-01T08:33:22.093691 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) e3b2ee5b4bc120b5043225ebdbf73eadd71be9c3d9d8e1fdd66a24a8ff11a780
221 tests/mcp/test_resource_project_info.py test_resource_project_info.py source_code 4885 2025-07-01T08:33:22.094085 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6a043736789b239c8d4ae00d1a5332a0fc3bed4038fe3388970ba97dc7431a93
222 tests/mcp/test_resources.py test_resources.py source_code 549 2025-07-01T08:33:22.094481 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 77a6396b9b8a9d3b3d202e438243ca6178d87fd7680c9fc063ee013f2042aa4c
223 tests/mcp/test_tool_build_context.py test_tool_build_context.py source_code 3714 2025-07-01T08:33:22.094661 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 5f0a39fdb652605335ed54aa91fe994262441bb7ba46f381c46ebca882fc23f2
224 tests/mcp/test_tool_canvas.py test_tool_canvas.py source_code 7997 2025-07-01T08:33:22.094982 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) c517bb1f9edc77b76fbeb483dfcb2dd57de9f0b80a10738708bc90cbe388dc9e
225 tests/mcp/test_tool_delete_note.py test_tool_delete_note.py source_code 4208 2025-07-01T08:33:22.095578 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 4cbf3ba4313438651b0608d5b25faf1400f7bd6a78af630351aecd4457800895
226 tests/mcp/test_tool_edit_note.py test_tool_edit_note.py source_code 13503 2025-07-03T18:43:10.084890 Drew Cain 2 Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) dd441969aa54b3739f2d9202d3feaf46aee807ec51e01a13ef41eda52743944f
227 tests/mcp/test_tool_list_directory.py test_tool_list_directory.py source_code 7730 2025-07-01T08:33:22.096737 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) cfbb5c06bcfe74ea60f31051eb9b03ac80b86232b053c188bf3b172132f7c0f5
228 tests/mcp/test_tool_move_note.py test_tool_move_note.py source_code 25851 2025-07-30T09:39:45.727347 jope-bm 2 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co) c9f95158503fa42e37532aaa35027538fa49cea718d059d570cf547d31f01043
229 tests/mcp/test_tool_read_content.py test_tool_read_content.py source_code 19442 2025-07-30T09:39:45.727526 jope-bm 1 jope-bm (joe@basicmemory.com) 1817e32f997b06dbdabf02864d0c70584c1cd80bf1fae8dfbef649de79434bc5
230 tests/mcp/test_tool_read_note.py test_tool_read_note.py source_code 22991 2025-07-30T09:39:45.727746 jope-bm 4 jope-bm (joe@basicmemory.com); Paul Hernandez (paul@basicmachines.co); Amadeusz Wieczorek (git@amadeusw.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 4e13ea9ff977525aa62b6a8c22505ffe989329dc3e7d07b71e044cf43ef3ddfd
231 tests/mcp/test_tool_recent_activity.py test_tool_recent_activity.py source_code 3983 2025-07-01T08:33:22.098561 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 45414152cd45334b84df56f653146b7bd2939907548e7245a37207fdccfc4c87
232 tests/mcp/test_tool_resource.py test_tool_resource.py source_code 6782 2025-07-01T08:33:22.098948 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 3916ae1c4d458eee53d2c570b9bbb708ecd617de5a145c3a7552389954bc9195
233 tests/mcp/test_tool_search.py test_tool_search.py source_code 10959 2025-07-03T18:43:10.085177 Drew Cain 3 Drew Cain (groksrc@gmail.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) 07839cf8e89d74ba05ec1dc55fa842444c1f0cc3d1587823b0ac3458ad89e87c
234 tests/mcp/test_tool_sync_status.py test_tool_sync_status.py source_code 6331 2025-07-01T08:33:22.100021 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 3f3566df5b9f3c66bb9b3bd77d4c05825480d0e85015305cb1b7ab9429c7a7ec
235 tests/mcp/test_tool_utils.py test_tool_utils.py source_code 9228 2025-07-01T08:33:22.100561 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) b50789f7a78b0169f52dc8bd16e262510ed4a0ac130fce698d4be84af1fe2d31
236 tests/mcp/test_tool_view_note.py test_tool_view_note.py source_code 10004 2025-07-01T08:33:22.101164 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 385535ce791c3ab55db827cbcf27ea25ae85faf3a027f52df4eea052cede7f36
237 tests/mcp/test_tool_write_note.py test_tool_write_note.py source_code 35136 2025-07-30T09:39:45.728137 jope-bm 3 jope-bm (joe@basicmemory.com); Drew Cain (groksrc@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 45172de20cfc4f4436287573b4f5a94b8b616a360647af67ba1c6c343ccd41b8
238 tests/repository/test_entity_repository.py test_entity_repository.py source_code 15498 2025-06-21T00:01:46.176265 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) 8f5d1ff6cff7b640993ff73f463b1e7801a4dd69640fc55fa23dc58b865e9943
239 tests/repository/test_entity_repository_upsert.py test_entity_repository_upsert.py source_code 16983 2025-07-03T18:43:10.085482 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com) ee0ecd6f4ff8b31838bd6de6fb1018af437e02813d8315c06f4e20a6b78a0572
240 tests/repository/test_observation_repository.py test_observation_repository.py source_code 11786 2025-06-21T00:01:46.158862 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) 3006d392ad94dcc9b3ae031d63a1af6935624534389dd025de70d4c9e112aa0b
241 tests/repository/test_project_info_repository.py test_project_info_repository.py source_code 1186 2025-06-21T00:01:46.161876 bm-claudeai (AI Assistant) 1 bm-claudeai (AI Assistant) (claude@basicmachines.co) dbce7ae7350403cbc37343c2e3e68e4d2255e247006aaa6c495a7ce8bfddea7d
242 tests/repository/test_project_repository.py test_project_repository.py source_code 10511 2025-07-30T09:39:45.728536 jope-bm 2 jope-bm (joe@basicmemory.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 279a3324635b1b515c18003bd1875cf230fef1192cadef9ca426846783717e75
243 tests/repository/test_relation_repository.py test_relation_repository.py source_code 11980 2025-06-21T00:01:46.167567 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (phernandez@basicmachines.co) fcdbdf40f7b56145b98eedde5ead64ef6187e859adde48cc09f5a97754757428
244 tests/repository/test_repository.py test_repository.py source_code 5996 2025-06-21T00:01:46.152691 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 3a6d4ca0b7a438a30ae504f5eac22874d4e1a937a4246e90efad46c90f0e1c95
245 tests/repository/test_search_repository.py test_search_repository.py source_code 25471 2025-07-03T18:43:10.086041 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 805b5cc55a53ae9d6e86c0de735c7f38ac9fd92c23194b0150fa3e7f5507a146
246 tests/schemas/test_memory_url.py test_memory_url.py source_code 2000 2025-06-21T00:01:46.346515 Paul Hernandez 1 Paul Hernandez (paulmh@gmail.com) 946fa6c48534f41c8b9cc27bbad164d3e3673a79afa84fbb439fae4cd26c504b
247 tests/schemas/test_memory_url_validation.py test_memory_url_validation.py source_code 9338 2025-07-01T08:33:22.103247 Paul Hernandez 1 Paul Hernandez (paul@basicmachines.co) 7054c3a3cdb8e05d2ffd254ed298908ff3d48a0a3927d960975eae1ab9beeb38
248 tests/schemas/test_schemas.py test_schemas.py source_code 16880 2025-07-03T18:43:10.086337 Drew Cain 3 Drew Cain (groksrc@gmail.com); Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 2c746a00c340f063c160ace67569955a300a294040949695c79fd4ae124fb611
249 tests/schemas/test_search.py test_search.py source_code 3264 2025-06-21T00:01:46.343685 github-actions[bot] (AI Assistant) 2 github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com); Paul Hernandez (60959+phernandez@users.noreply.github.com) 7437775d1b4a61a438cbabe3dbb1becd2adc4dbcc0c24595830c0843fa7a3166
250 tests/services/test_context_service.py test_context_service.py source_code 8833 2025-06-21T00:01:46.446200 bm-claudeai (AI Assistant) 2 bm-claudeai (AI Assistant) (claude@basicmachines.co); Paul Hernandez (paulmh@gmail.com) ab49d21a05d5364e7e8a2f00b07aabe1109b7417698e0acd92792e2cb5f22732
251 tests/services/test_directory_service.py test_directory_service.py source_code 6854 2025-06-21T00:01:46.457258 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) a0c765fb6bd1a75b6ba4592b1df344c48273b6ab03ba6bd15d2b5e840eb2d521
252 tests/services/test_entity_service.py test_entity_service.py source_code 59278 2025-07-03T18:43:10.086674 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) d7d495756faa10b415d705cf26b69d2efbc5f190a834b6767386ff296629ea71
253 tests/services/test_file_service.py test_file_service.py source_code 5243 2025-06-21T00:01:46.460141 Paul Hernandez 1 Paul Hernandez (phernandez@basicmachines.co) 83e6e9a7584b7baeccbc84865d8c1d3e2a0223e7d2b9c066d3799c289196ab7d
254 tests/services/test_initialization.py test_initialization.py source_code 6939 2025-07-08T20:39:18.351946 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) ebb8d11ff37dcb36c4844c68f873c8e0e8aa6ab1b82abb22ee96c4233e6ab287
255 tests/services/test_link_resolver.py test_link_resolver.py source_code 13618 2025-07-01T08:33:22.105766 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) c9fc56d0c3572770e95ca6175c213ed8b44c2a6ddddc298b5662cc2d8f41014e
256 tests/services/test_project_service.py test_project_service.py source_code 28152 2025-07-30T09:39:45.728920 jope-bm 3 jope-bm (joe@basicmemory.com); Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 430868ed796518937a3b0bed4d8c33be53264a6100d61d54b0745bb2b58bf29a
257 tests/services/test_project_service_operations.py test_project_service_operations.py source_code 4679 2025-06-21T00:01:46.442141 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) d4103b6c5fff7e74ba84b86033537b8522aa60fc75aec4974d52e1dfec68b1b4
258 tests/services/test_search_service.py test_search_service.py source_code 25299 2025-06-21T00:01:46.439133 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) b3e58258db2b727ab8a1792e52fcb038d3a0779bcd1b70f2d295a9d06e5e2513
259 tests/services/test_sync_status_service.py test_sync_status_service.py source_code 9926 2025-07-03T18:43:10.087266 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 00245ca356e33fc7afcd2d42cb5ec082038c95383d738067821cf1e8d23c9a4b
260 tests/sync/test_sync_service.py test_sync_service.py source_code 39659 2025-07-01T08:33:22.107088 Paul Hernandez 2 Paul Hernandez (paul@basicmachines.co); bm-claudeai (AI Assistant) (claude@basicmachines.co) 0609aee9906549f27fc4289b5ac2d46a50e53e12a0615a2701f17fbe9a74e169
261 tests/sync/test_sync_wikilink_issue.py test_sync_wikilink_issue.py source_code 1959 2025-06-21T00:01:46.420370 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) db4b98dd7008a1a26b0fd02b9a2d03bca950b281efc19d98a91b017c500b23a5
262 tests/sync/test_tmp_files.py test_tmp_files.py source_code 5930 2025-06-21T00:01:46.424277 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) cead95a07b29f6c1ab933abe67f9648122f5f33d33753c8e4ab4934af96cbc25
263 tests/sync/test_watch_service.py test_watch_service.py source_code 14076 2025-06-26T09:28:51.860679 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) e324a4127f8bfe59798f3a08125488c701e88239b7482d87a0394b91c55b893e
264 tests/sync/test_watch_service_edge_cases.py test_watch_service_edge_cases.py source_code 2169 2025-06-21T00:01:46.409830 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) b87c5015330e9b551630aab7ef95ac1e7663f0ce46e912d8155b319e139559aa
265 tests/test_config.py test_config.py source_code 3680 2025-07-03T18:43:10.087558 Paul Hernandez 3 Paul Hernandez (paul@basicmachines.co); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) 6a246431cff739274efda895dfa28f38710289a73e645312f5fa05fce0885ec8
266 tests/test_db_migration_deduplication.py test_db_migration_deduplication.py source_code 6166 2025-07-08T20:39:18.352690 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com) ab768e061531ca2edcd598c101b5d884e549f90c7a4b305a23713a199d263fbb
267 tests/utils/test_file_utils.py test_file_utils.py source_code 6199 2025-06-21T00:01:46.219673 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 4615bb20b92b8a79d9e086301f852b34c3360f17ecc209920d68528268ddeed4
268 tests/utils/test_parse_tags.py test_parse_tags.py source_code 1691 2025-06-21T00:01:46.223400 Paul Hernandez 2 Paul Hernandez (60959+phernandez@users.noreply.github.com); github-actions[bot] (AI Assistant) (41898282+github-actions[bot]@users.noreply.github.com) b83afdf18dac8b3411bd0fab1301683217d3d1abceaf2d22c09e79c709efd8eb
269 tests/utils/test_permalink_formatting.py test_permalink_formatting.py source_code 4193 2025-06-21T00:01:46.225738 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) d998a4ca846c78679728a918b6f71df67c30b6961ede3cffa609f2cf6ad160eb
270 tests/utils/test_utf8_handling.py test_utf8_handling.py source_code 5791 2025-06-21T00:01:46.228483 Paul Hernandez 1 Paul Hernandez (60959+phernandez@users.noreply.github.com) 50ec792e572af51cd2d996d4ddacbcfd3bbd79aa928818a90c42117451ea829f
271 tests/utils/test_validate_project_path.py test_validate_project_path.py source_code 15346 2025-07-30T09:39:45.729224 jope-bm 1 jope-bm (joe@basicmemory.com) 27a4bf2a9d277e6cd773619e5241b20175d211ec60c284361bec404fd99143f3
272 uv.lock uv.lock other 232710 2025-07-30T09:39:36.619155 Paul Hernandez 3 Paul Hernandez (60959+phernandez@users.noreply.github.com); Drew Cain (groksrc@users.noreply.github.com); bm-claudeai (AI Assistant) (claude@basicmachines.co) caa1e3f6e66464b884a78cab77df2fe303fa3c0dc573be0196474b6d3c150581
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+294
View File
@@ -0,0 +1,294 @@
# Basic Memory - Legal File Inventory
**Generated:** 2025-07-29T16:10:54.745774
**Repository:** /Users/phernandez/dev/basicmachines/basic-memory
## Summary Statistics
- **Total Files:** 255
- **Total Contributors:** 12
### Files by Category
- **Build/Deployment:** 2 files
- **Configuration:** 6 files
- **Database/Migration:** 1 files
- **Documentation:** 6 files
- **Legal/License:** 3 files
- **Other:** 13 files
- **Source Code:** 222 files
- **Templates/Resources:** 2 files
### Top Contributors by Files Modified
- **phernandez:** 190 files
- **Paul Hernandez:** 181 files
- **bm-claudeai:** 135 files
- **Drew Cain:** 24 files
- **github-actions[bot]:** 20 files
- **Amadeusz Wieczorek:** 2 files
- **semantic-release:** 1 files
- **Jason Noble:** 1 files
- **Marc Baiza:** 1 files
- **Matias Forbord:** 1 files
## Detailed File Inventory
| File Path | Category | Size (bytes) | Primary Author | Contributors |
|-----------|----------|--------------|----------------|-------------|
| .claude/commands/release/beta.md | Other | 3103 | phernandez | phernandez |
| .claude/commands/release/changelog.md | Documentation | 4648 | phernandez | phernandez |
| .claude/commands/release/release-check.md | Other | 3344 | phernandez | phernandez |
| .claude/commands/release/release.md | Other | 2925 | phernandez | phernandez |
| .claude/commands/test-live.md | Other | 18720 | phernandez | phernandez |
| .claude/settings.local.json | Configuration | 3122 | Unknown | |
| .dockerignore | Other | 623 | Paul Hernandez | Paul Hernandez |
| .python-version | Other | 5 | phernandez | phernandez |
| CHANGELOG.md | Documentation | 53647 | semantic-release | semantic-release, phernandez |
| CITATION.cff | Legal/License | 302 | phernandez | phernandez |
| CLA.md | Legal/License | 1342 | phernandez | phernandez |
| CLAUDE.md | Other | 12310 | Paul Hernandez | Paul Hernandez, phernandez, Ikko Eltociear Ashimin... |
| CODE_OF_CONDUCT.md | Other | 509 | phernandez | phernandez |
| CONTRIBUTING.md | Documentation | 7241 | phernandez | phernandez, Paul Hernandez |
| Dockerfile | Build/Deployment | 856 | Paul Hernandez | Paul Hernandez, bm-claudeai |
| LICENSE | Legal/License | 34523 | Paul Hernandez | Paul Hernandez |
| README.md | Documentation | 16261 | phernandez | phernandez, bm-claudeai, Paul Hernandez, Jason Nob... |
| SECURITY.md | Other | 303 | Paul Hernandez | Paul Hernandez |
| docker-compose.yml | Configuration | 2534 | Paul Hernandez | Paul Hernandez, phernandez |
| docs/AI Assistant Guide.md | Documentation | 16423 | Paul Hernandez | Paul Hernandez, phernandez |
| docs/Docker.md | Documentation | 9088 | Paul Hernandez | Paul Hernandez, phernandez |
| justfile | Build/Deployment | 5371 | phernandez | phernandez, Drew Cain |
| legal_file_inventory.py | Source Code | 17407 | Unknown | |
| llms-install.md | Other | 2307 | phernandez | phernandez |
| memory.json | Configuration | 90075 | phernandez | phernandez |
| pyproject.toml | Configuration | 3279 | phernandez | phernandez, Paul Hernandez, bm-claudeai, Drew Cain... |
| smithery.yaml | Configuration | 433 | bm-claudeai | bm-claudeai |
| src/basic_memory/__init__.py | Source Code | 256 | phernandez | phernandez |
| src/basic_memory/alembic/alembic.ini | Configuration | 3733 | phernandez | phernandez |
| src/basic_memory/alembic/migrations.py | Source Code | 718 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/alembic/script.py.mako | Database/Migration | 635 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py | Source Code | 4363 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/alembic/versions/502b60eaa905_remove_required_from_entity_permalink.py | Source Code | 1840 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py | Source Code | 4379 | bm-claudeai | bm-claudeai |
| src/basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py | Source Code | 4210 | phernandez | phernandez |
| src/basic_memory/alembic/versions/b3c3938bacdb_relation_to_name_unique_index.py | Source Code | 1428 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py | Source Code | 3679 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/api/__init__.py | Source Code | 72 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/api/app.py | Source Code | 2897 | bm-claudeai | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/api/routers/__init__.py | Source Code | 398 | phernandez | phernandez, bm-claudeai |
| src/basic_memory/api/routers/directory_router.py | Source Code | 2054 | Paul Hernandez | bm-claudeai, Paul Hernandez |
| src/basic_memory/api/routers/importer_router.py | Source Code | 4513 | bm-claudeai | bm-claudeai |
| src/basic_memory/api/routers/knowledge_router.py | Source Code | 9738 | Paul Hernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/api/routers/management_router.py | Source Code | 2730 | bm-claudeai | bm-claudeai, phernandez |
| src/basic_memory/api/routers/memory_router.py | Source Code | 3003 | phernandez | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/api/routers/project_router.py | Source Code | 8239 | bm-claudeai | bm-claudeai, phernandez, Paul Hernandez |
| src/basic_memory/api/routers/prompt_router.py | Source Code | 9948 | bm-claudeai | bm-claudeai, phernandez |
| src/basic_memory/api/routers/resource_router.py | Source Code | 8058 | Paul Hernandez | phernandez, Paul Hernandez |
| src/basic_memory/api/routers/search_router.py | Source Code | 1226 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/api/routers/utils.py | Source Code | 5159 | bm-claudeai | bm-claudeai, Drew Cain |
| src/basic_memory/api/template_loader.py | Source Code | 8607 | bm-claudeai | bm-claudeai |
| src/basic_memory/cli/__init__.py | Source Code | 33 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/cli/app.py | Source Code | 2268 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/cli/commands/__init__.py | Source Code | 393 | Paul Hernandez | Paul Hernandez, phernandez |
| src/basic_memory/cli/commands/db.py | Source Code | 1480 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/cli/commands/import_chatgpt.py | Source Code | 2856 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| src/basic_memory/cli/commands/import_claude_conversations.py | Source Code | 2946 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| src/basic_memory/cli/commands/import_claude_projects.py | Source Code | 2891 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| src/basic_memory/cli/commands/import_memory_json.py | Source Code | 2947 | Paul Hernandez | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/cli/commands/mcp.py | Source Code | 2593 | phernandez | bm-claudeai, phernandez, Paul Hernandez |
| src/basic_memory/cli/commands/project.py | Source Code | 12252 | phernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/cli/commands/status.py | Source Code | 5809 | phernandez | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/cli/commands/sync.py | Source Code | 8213 | phernandez | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/cli/commands/tool.py | Source Code | 9540 | phernandez | Paul Hernandez, phernandez, github-actions[bot] |
| src/basic_memory/cli/main.py | Source Code | 465 | Paul Hernandez | Paul Hernandez, phernandez |
| src/basic_memory/config.py | Source Code | 12620 | Paul Hernandez | phernandez, Paul Hernandez, bm-claudeai, Drew Cain... |
| src/basic_memory/db.py | Source Code | 7428 | phernandez | phernandez, Paul Hernandez, Drew Cain, bm-claudeai... |
| src/basic_memory/deps.py | Source Code | 12144 | bm-claudeai | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/file_utils.py | Source Code | 6700 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/importers/__init__.py | Source Code | 795 | bm-claudeai | bm-claudeai |
| src/basic_memory/importers/base.py | Source Code | 2531 | bm-claudeai | bm-claudeai |
| src/basic_memory/importers/chatgpt_importer.py | Source Code | 7372 | bm-claudeai | bm-claudeai |
| src/basic_memory/importers/claude_conversations_importer.py | Source Code | 5725 | bm-claudeai | bm-claudeai |
| src/basic_memory/importers/claude_projects_importer.py | Source Code | 5389 | bm-claudeai | bm-claudeai |
| src/basic_memory/importers/memory_json_importer.py | Source Code | 3986 | bm-claudeai | bm-claudeai, phernandez |
| src/basic_memory/importers/utils.py | Source Code | 1792 | bm-claudeai | bm-claudeai |
| src/basic_memory/markdown/__init__.py | Source Code | 501 | phernandez | phernandez |
| src/basic_memory/markdown/entity_parser.py | Source Code | 4516 | phernandez | phernandez, Paul Hernandez, github-actions[bot] |
| src/basic_memory/markdown/markdown_processor.py | Source Code | 4968 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/markdown/plugins.py | Source Code | 6639 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/markdown/schemas.py | Source Code | 1896 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/markdown/utils.py | Source Code | 3410 | Paul Hernandez | Paul Hernandez, phernandez |
| src/basic_memory/mcp/__init__.py | Source Code | 35 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/mcp/async_client.py | Source Code | 925 | Paul Hernandez | phernandez, Paul Hernandez |
| src/basic_memory/mcp/project_session.py | Source Code | 4203 | Paul Hernandez | Paul Hernandez, phernandez |
| src/basic_memory/mcp/prompts/__init__.py | Source Code | 615 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/mcp/prompts/ai_assistant_guide.py | Source Code | 821 | Paul Hernandez | Paul Hernandez, phernandez |
| src/basic_memory/mcp/prompts/continue_conversation.py | Source Code | 1998 | Paul Hernandez | Paul Hernandez, github-actions[bot], bm-claudeai |
| src/basic_memory/mcp/prompts/recent_activity.py | Source Code | 3311 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/mcp/prompts/search.py | Source Code | 1692 | Paul Hernandez | Paul Hernandez, bm-claudeai |
| src/basic_memory/mcp/prompts/utils.py | Source Code | 5431 | Paul Hernandez | Paul Hernandez, bm-claudeai |
| src/basic_memory/mcp/resources/ai_assistant_guide.md | Other | 14777 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/mcp/resources/project_info.py | Source Code | 1906 | Paul Hernandez | Paul Hernandez, bm-claudeai |
| src/basic_memory/mcp/server.py | Source Code | 1248 | Paul Hernandez | bm-claudeai, phernandez, Paul Hernandez |
| src/basic_memory/mcp/tools/__init__.py | Source Code | 1619 | Paul Hernandez | phernandez, Paul Hernandez, Drew Cain |
| src/basic_memory/mcp/tools/auth.py | Source Code | 1231 | phernandez | phernandez |
| src/basic_memory/mcp/tools/canvas.py | Source Code | 3738 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/mcp/tools/delete_note.py | Source Code | 7346 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/mcp/tools/edit_note.py | Source Code | 13570 | Paul Hernandez | Paul Hernandez, phernandez |
| src/basic_memory/mcp/tools/list_directory.py | Source Code | 5236 | Paul Hernandez | Paul Hernandez |
| src/basic_memory/mcp/tools/move_note.py | Source Code | 16708 | phernandez | Paul Hernandez, phernandez |
| src/basic_memory/mcp/tools/project_management.py | Source Code | 12944 | Paul Hernandez | Paul Hernandez, phernandez, Drew Cain |
| src/basic_memory/mcp/tools/read_content.py | Source Code | 8596 | Paul Hernandez | Paul Hernandez, bm-claudeai |
| src/basic_memory/mcp/tools/read_note.py | Source Code | 7614 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez, Amadeusz ... |
| src/basic_memory/mcp/tools/recent_activity.py | Source Code | 4833 | phernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/mcp/tools/search.py | Source Code | 15883 | phernandez | phernandez, github-actions[bot], Paul Hernandez, D... |
| src/basic_memory/mcp/tools/sync_status.py | Source Code | 10517 | phernandez | phernandez |
| src/basic_memory/mcp/tools/utils.py | Source Code | 21426 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/mcp/tools/view_note.py | Source Code | 2499 | phernandez | phernandez |
| src/basic_memory/mcp/tools/write_note.py | Source Code | 6178 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| src/basic_memory/models/__init__.py | Source Code | 333 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/models/base.py | Source Code | 225 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/models/knowledge.py | Source Code | 7087 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/models/project.py | Source Code | 2773 | bm-claudeai | bm-claudeai, phernandez |
| src/basic_memory/models/search.py | Source Code | 1300 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/repository/__init__.py | Source Code | 327 | Paul Hernandez | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/repository/entity_repository.py | Source Code | 10405 | Drew Cain | phernandez, Paul Hernandez, Drew Cain, bm-claudeai... |
| src/basic_memory/repository/observation_repository.py | Source Code | 2943 | phernandez | phernandez, bm-claudeai |
| src/basic_memory/repository/project_info_repository.py | Source Code | 338 | Paul Hernandez | Paul Hernandez, bm-claudeai |
| src/basic_memory/repository/project_repository.py | Source Code | 3159 | bm-claudeai | bm-claudeai |
| src/basic_memory/repository/relation_repository.py | Source Code | 3179 | phernandez | phernandez, bm-claudeai |
| src/basic_memory/repository/repository.py | Source Code | 15224 | phernandez | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/repository/search_repository.py | Source Code | 21936 | phernandez | phernandez, Paul Hernandez, github-actions[bot], b... |
| src/basic_memory/schemas/__init__.py | Source Code | 1674 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/schemas/base.py | Source Code | 6738 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/schemas/delete.py | Source Code | 1180 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/schemas/directory.py | Source Code | 881 | bm-claudeai | bm-claudeai |
| src/basic_memory/schemas/importer.py | Source Code | 663 | bm-claudeai | bm-claudeai |
| src/basic_memory/schemas/memory.py | Source Code | 5833 | phernandez | phernandez, Paul Hernandez, Drew Cain, bm-claudeai... |
| src/basic_memory/schemas/project_info.py | Source Code | 7047 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| src/basic_memory/schemas/prompt.py | Source Code | 3648 | bm-claudeai | bm-claudeai |
| src/basic_memory/schemas/request.py | Source Code | 3760 | Paul Hernandez | phernandez, Paul Hernandez |
| src/basic_memory/schemas/response.py | Source Code | 6450 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/schemas/search.py | Source Code | 3657 | phernandez | phernandez, Paul Hernandez, github-actions[bot], b... |
| src/basic_memory/services/__init__.py | Source Code | 259 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/services/context_service.py | Source Code | 14462 | bm-claudeai | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/services/directory_service.py | Source Code | 6017 | bm-claudeai | bm-claudeai, Paul Hernandez |
| src/basic_memory/services/entity_service.py | Source Code | 30440 | Paul Hernandez | phernandez, Paul Hernandez, bm-claudeai, Drew Cain... |
| src/basic_memory/services/exceptions.py | Source Code | 390 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/services/file_service.py | Source Code | 10059 | Paul Hernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/services/initialization.py | Source Code | 6715 | bm-claudeai | Paul Hernandez, bm-claudeai, Drew Cain, phernandez... |
| src/basic_memory/services/link_resolver.py | Source Code | 4594 | phernandez | phernandez, Paul Hernandez, bm-claudeai, github-ac... |
| src/basic_memory/services/project_service.py | Source Code | 28386 | bm-claudeai | bm-claudeai, Paul Hernandez, phernandez |
| src/basic_memory/services/search_service.py | Source Code | 12782 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| src/basic_memory/services/service.py | Source Code | 336 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/services/sync_status_service.py | Source Code | 7504 | phernandez | phernandez, Paul Hernandez |
| src/basic_memory/sync/__init__.py | Source Code | 156 | Paul Hernandez | Paul Hernandez, phernandez |
| src/basic_memory/sync/background_sync.py | Source Code | 726 | bm-claudeai | bm-claudeai, phernandez |
| src/basic_memory/sync/sync_service.py | Source Code | 23387 | Paul Hernandez | phernandez, Paul Hernandez, bm-claudeai, github-ac... |
| src/basic_memory/sync/watch_service.py | Source Code | 15316 | Paul Hernandez | phernandez, bm-claudeai, Paul Hernandez |
| src/basic_memory/templates/prompts/continue_conversation.hbs | Templates/Resources | 3076 | bm-claudeai | bm-claudeai, Drew Cain |
| src/basic_memory/templates/prompts/search.hbs | Templates/Resources | 3098 | bm-claudeai | bm-claudeai |
| src/basic_memory/utils.py | Source Code | 7657 | phernandez | phernandez, Paul Hernandez, andyxinweiminicloud, D... |
| test-int/conftest.py | Source Code | 8203 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_delete_note_integration.py | Source Code | 13175 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_edit_note_integration.py | Source Code | 19822 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_list_directory_integration.py | Source Code | 14744 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_move_note_integration.py | Source Code | 19825 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_project_management_integration.py | Source Code | 33175 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_project_state_sync_integration.py | Source Code | 7728 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_read_content_integration.py | Source Code | 11187 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_read_note_integration.py | Source Code | 1381 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_search_integration.py | Source Code | 14690 | Paul Hernandez | Paul Hernandez, phernandez |
| test-int/mcp/test_write_note_integration.py | Source Code | 9472 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/Non-MarkdownFileSupport.pdf | Other | 106751 | Unknown | |
| tests/Screenshot.png | Other | 190076 | Unknown | |
| tests/__init__.py | Source Code | 141 | phernandez | phernandez, Paul Hernandez |
| tests/api/conftest.py | Source Code | 1404 | phernandez | phernandez, bm-claudeai, Paul Hernandez |
| tests/api/test_async_client.py | Source Code | 1382 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/api/test_continue_conversation_template.py | Source Code | 5152 | bm-claudeai | bm-claudeai |
| tests/api/test_directory_router.py | Source Code | 9376 | Paul Hernandez | bm-claudeai, Paul Hernandez |
| tests/api/test_importer_router.py | Source Code | 16578 | bm-claudeai | bm-claudeai, Paul Hernandez |
| tests/api/test_knowledge_router.py | Source Code | 45771 | Paul Hernandez | phernandez, bm-claudeai, Paul Hernandez |
| tests/api/test_management_router.py | Source Code | 6220 | bm-claudeai | bm-claudeai |
| tests/api/test_memory_router.py | Source Code | 5555 | phernandez | phernandez, bm-claudeai |
| tests/api/test_project_router.py | Source Code | 5201 | Paul Hernandez | bm-claudeai, Paul Hernandez, phernandez |
| tests/api/test_project_router_operations.py | Source Code | 1812 | bm-claudeai | bm-claudeai, Paul Hernandez |
| tests/api/test_prompt_router.py | Source Code | 5046 | bm-claudeai | bm-claudeai |
| tests/api/test_resource_router.py | Source Code | 13960 | Paul Hernandez | phernandez, Paul Hernandez, bm-claudeai |
| tests/api/test_search_router.py | Source Code | 6409 | phernandez | phernandez, bm-claudeai, Paul Hernandez, github-ac... |
| tests/api/test_search_template.py | Source Code | 5258 | bm-claudeai | bm-claudeai |
| tests/api/test_template_loader.py | Source Code | 8035 | bm-claudeai | bm-claudeai |
| tests/api/test_template_loader_helpers.py | Source Code | 7445 | bm-claudeai | bm-claudeai |
| tests/cli/conftest.py | Source Code | 1185 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/cli/test_cli_tools.py | Source Code | 13528 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| tests/cli/test_import_chatgpt.py | Source Code | 6719 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| tests/cli/test_import_claude_conversations.py | Source Code | 5028 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| tests/cli/test_import_claude_projects.py | Source Code | 4585 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| tests/cli/test_import_memory_json.py | Source Code | 3532 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| tests/cli/test_project_commands.py | Source Code | 5143 | bm-claudeai | bm-claudeai, Paul Hernandez, phernandez |
| tests/cli/test_project_info.py | Source Code | 3874 | phernandez | Paul Hernandez, phernandez |
| tests/cli/test_status.py | Source Code | 4160 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| tests/cli/test_sync.py | Source Code | 3864 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| tests/cli/test_version.py | Source Code | 289 | Paul Hernandez | Paul Hernandez |
| tests/conftest.py | Source Code | 15286 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| tests/importers/test_importer_base.py | Source Code | 4329 | bm-claudeai | bm-claudeai |
| tests/importers/test_importer_utils.py | Source Code | 1827 | bm-claudeai | bm-claudeai |
| tests/markdown/__init__.py | Source Code | 0 | Unknown | |
| tests/markdown/test_entity_parser.py | Source Code | 8669 | phernandez | phernandez, Paul Hernandez, github-actions[bot] |
| tests/markdown/test_markdown_plugins.py | Source Code | 5139 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/markdown/test_markdown_processor.py | Source Code | 5728 | phernandez | phernandez, Paul Hernandez |
| tests/markdown/test_observation_edge_cases.py | Source Code | 4295 | phernandez | phernandez |
| tests/markdown/test_parser_edge_cases.py | Source Code | 5142 | phernandez | phernandez |
| tests/markdown/test_relation_edge_cases.py | Source Code | 3952 | phernandez | phernandez |
| tests/markdown/test_task_detection.py | Source Code | 401 | Paul Hernandez | Paul Hernandez |
| tests/mcp/conftest.py | Source Code | 1761 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| tests/mcp/test_prompts.py | Source Code | 5989 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| tests/mcp/test_resource_project_info.py | Source Code | 4885 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| tests/mcp/test_resources.py | Source Code | 549 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/mcp/test_tool_canvas.py | Source Code | 7997 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/mcp/test_tool_delete_note.py | Source Code | 4208 | phernandez | phernandez |
| tests/mcp/test_tool_edit_note.py | Source Code | 13503 | Paul Hernandez | Paul Hernandez, phernandez, Drew Cain |
| tests/mcp/test_tool_list_directory.py | Source Code | 7730 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/mcp/test_tool_move_note.py | Source Code | 16346 | Paul Hernandez | Paul Hernandez, phernandez |
| tests/mcp/test_tool_read_note.py | Source Code | 9741 | Paul Hernandez | Paul Hernandez, phernandez, github-actions[bot], A... |
| tests/mcp/test_tool_recent_activity.py | Source Code | 3983 | phernandez | phernandez, bm-claudeai |
| tests/mcp/test_tool_resource.py | Source Code | 6782 | Paul Hernandez | Paul Hernandez, phernandez, github-actions[bot] |
| tests/mcp/test_tool_search.py | Source Code | 10959 | phernandez | Paul Hernandez, phernandez, github-actions[bot], D... |
| tests/mcp/test_tool_sync_status.py | Source Code | 6331 | phernandez | phernandez |
| tests/mcp/test_tool_utils.py | Source Code | 9228 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| tests/mcp/test_tool_view_note.py | Source Code | 10004 | phernandez | phernandez |
| tests/mcp/test_tool_write_note.py | Source Code | 19537 | Paul Hernandez | phernandez, Paul Hernandez, Drew Cain |
| tests/repository/test_entity_repository.py | Source Code | 15498 | phernandez | phernandez, bm-claudeai, Paul Hernandez |
| tests/repository/test_entity_repository_upsert.py | Source Code | 16983 | Drew Cain | Drew Cain, phernandez |
| tests/repository/test_observation_repository.py | Source Code | 11786 | phernandez | phernandez, bm-claudeai |
| tests/repository/test_project_info_repository.py | Source Code | 1186 | bm-claudeai | bm-claudeai |
| tests/repository/test_project_repository.py | Source Code | 9455 | bm-claudeai | bm-claudeai |
| tests/repository/test_relation_repository.py | Source Code | 11980 | phernandez | phernandez, bm-claudeai |
| tests/repository/test_repository.py | Source Code | 5996 | phernandez | phernandez, Paul Hernandez |
| tests/repository/test_search_repository.py | Source Code | 25471 | bm-claudeai | bm-claudeai, phernandez, Paul Hernandez |
| tests/schemas/test_memory_url.py | Source Code | 2000 | phernandez | phernandez, Paul Hernandez |
| tests/schemas/test_memory_url_validation.py | Source Code | 9338 | phernandez | phernandez |
| tests/schemas/test_schemas.py | Source Code | 16880 | phernandez | phernandez, Paul Hernandez, bm-claudeai, Drew Cain... |
| tests/schemas/test_search.py | Source Code | 3264 | phernandez | phernandez, Paul Hernandez, github-actions[bot] |
| tests/services/test_context_service.py | Source Code | 8833 | phernandez | phernandez, bm-claudeai, Paul Hernandez |
| tests/services/test_directory_service.py | Source Code | 6854 | Paul Hernandez | bm-claudeai, Paul Hernandez |
| tests/services/test_entity_service.py | Source Code | 59278 | Paul Hernandez | phernandez, Paul Hernandez, bm-claudeai, Drew Cain... |
| tests/services/test_file_service.py | Source Code | 5243 | phernandez | phernandez |
| tests/services/test_initialization.py | Source Code | 6939 | bm-claudeai | Paul Hernandez, bm-claudeai, phernandez |
| tests/services/test_link_resolver.py | Source Code | 13618 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| tests/services/test_project_service.py | Source Code | 23576 | phernandez | bm-claudeai, Paul Hernandez, phernandez |
| tests/services/test_project_service_operations.py | Source Code | 4679 | bm-claudeai | bm-claudeai, Paul Hernandez |
| tests/services/test_search_service.py | Source Code | 25299 | Paul Hernandez | phernandez, Paul Hernandez, github-actions[bot] |
| tests/services/test_sync_status_service.py | Source Code | 9926 | phernandez | phernandez, Paul Hernandez |
| tests/sync/test_sync_service.py | Source Code | 39659 | phernandez | phernandez, Paul Hernandez, bm-claudeai |
| tests/sync/test_sync_wikilink_issue.py | Source Code | 1959 | github-actions[bot] | github-actions[bot], Paul Hernandez |
| tests/sync/test_tmp_files.py | Source Code | 5930 | Paul Hernandez | Paul Hernandez, bm-claudeai, phernandez |
| tests/sync/test_watch_service.py | Source Code | 14076 | Paul Hernandez | Paul Hernandez, phernandez, bm-claudeai |
| tests/sync/test_watch_service_edge_cases.py | Source Code | 2169 | Paul Hernandez | Paul Hernandez, bm-claudeai |
| tests/test_config.py | Source Code | 3680 | Drew Cain | Drew Cain |
| tests/test_db_migration_deduplication.py | Source Code | 6166 | Paul Hernandez | Paul Hernandez, Drew Cain, phernandez |
| tests/utils/test_file_utils.py | Source Code | 6199 | phernandez | phernandez, Paul Hernandez |
| tests/utils/test_parse_tags.py | Source Code | 1691 | github-actions[bot] | github-actions[bot], Paul Hernandez |
| tests/utils/test_permalink_formatting.py | Source Code | 4193 | phernandez | phernandez, Paul Hernandez |
| tests/utils/test_utf8_handling.py | Source Code | 5791 | phernandez | phernandez, Paul Hernandez |
+128
View File
@@ -0,0 +1,128 @@
# Basic Memory Installation Guide for LLMs
This guide is specifically designed to help AI assistants like Cline install and configure Basic Memory. Follow these
steps in order.
## Installation Steps
### 1. Install Basic Memory Package
Use one of the following package managers to install:
```bash
# Install with uv (recommended)
uv tool install basic-memory
# Or with pip
pip install basic-memory
```
### 2. Configure MCP Server
Add the following to your config:
```json
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": [
"basic-memory",
"mcp"
]
}
}
}
```
For Claude Desktop, this file is located at:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
### 3. Start Synchronization (optional)
To synchronize files in real-time, run:
```bash
basic-memory sync --watch
```
Or for a one-time sync:
```bash
basic-memory sync
```
## Configuration Options
### Custom Directory
To use a directory other than the default `~/basic-memory`:
```bash
basic-memory project add custom-project /path/to/your/directory
basic-memory project default custom-project
```
### Multiple Projects
To manage multiple knowledge bases:
```bash
# List all projects
basic-memory project list
# Add a new project
basic-memory project add work ~/work-basic-memory
# Set default project
basic-memory project default work
```
## Importing Existing Data
### From Claude.ai
```bash
basic-memory import claude conversations path/to/conversations.json
basic-memory import claude projects path/to/projects.json
```
### From ChatGPT
```bash
basic-memory import chatgpt path/to/conversations.json
```
### From MCP Memory Server
```bash
basic-memory import memory-json path/to/memory.json
```
## Troubleshooting
If you encounter issues:
1. Check that Basic Memory is properly installed:
```bash
basic-memory --version
```
2. Verify the sync process is running:
```bash
ps aux | grep basic-memory
```
3. Check sync output for errors:
```bash
basic-memory sync --verbose
```
4. Check log output:
```bash
cat ~/.basic-memory/basic-memory.log
```
For more detailed information, refer to the [full documentation](https://memory.basicmachines.co/).
+49 -23
View File
@@ -1,6 +1,6 @@
[project]
name = "basic-memory"
version = "0.2.19"
dynamic = ["version"]
description = "Local-first knowledge management combining Zettelkasten with knowledge graphs"
readme = "README.md"
requires-python = ">=3.12.1"
@@ -28,7 +28,12 @@ dependencies = [
"watchfiles>=1.0.4",
"fastapi[standard]>=0.115.8",
"alembic>=1.14.1",
"qasync>=0.27.1",
"pillow>=11.1.0",
"pybars3>=0.9.7",
"fastmcp==2.10.2",
"pyjwt>=2.10.1",
"python-dotenv>=1.1.0",
"pytest-aio>=1.9.0",
]
@@ -39,14 +44,15 @@ Documentation = "https://github.com/basicmachines-co/basic-memory#readme"
[project.scripts]
basic-memory = "basic_memory.cli.main:app"
bm = "basic_memory.cli.main:app"
[build-system]
requires = ["hatchling"]
requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
build-backend = "hatchling.build"
[tool.pytest.ini_options]
pythonpath = ["src", "tests"]
addopts = "--cov=basic_memory --cov-report term-missing -ra -q"
addopts = "--cov=basic_memory --cov-report term-missing"
testpaths = ["tests"]
asyncio_mode = "strict"
asyncio_default_fixture_loop_scope = "function"
@@ -63,16 +69,19 @@ dev-dependencies = [
"pytest-cov>=4.1.0",
"pytest-mock>=3.12.0",
"pytest-asyncio>=0.24.0",
"pytest-xdist>=3.0.0",
"ruff>=0.1.6",
"pytest>=8.3.4",
"pytest-cov>=4.1.0",
"pytest-mock>=3.12.0",
"pytest-asyncio>=0.24.0",
"ruff>=0.1.6",
"cx-freeze>=7.2.10",
"pyqt6>=6.8.1",
]
[tool.hatch.version]
source = "uv-dynamic-versioning"
[tool.uv-dynamic-versioning]
vcs = "git"
style = "pep440"
bump = true
fallback-version = "0.0.0"
[tool.pyright]
include = ["src/"]
exclude = ["**/__pycache__"]
@@ -83,18 +92,35 @@ reportMissingTypeStubs = false
pythonVersion = "3.12"
[tool.semantic_release]
version_variable = "src/basic_memory/__init__.py:__version__"
version_toml = [
"pyproject.toml:project.version",
]
major_on_zero = false
branch = "main"
changelog_file = "CHANGELOG.md"
build_command = "pip install uv && uv build"
dist_path = "dist/"
upload_to_pypi = true
commit_message = "chore(release): {version} [skip ci]"
[tool.coverage.run]
concurrency = ["thread", "gevent"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
# Exclude specific modules that are difficult to test comprehensively
omit = [
"*/external_auth_provider.py", # External HTTP calls to OAuth providers
"*/supabase_auth_provider.py", # External HTTP calls to Supabase APIs
"*/watch_service.py", # File system watching - complex integration testing
"*/background_sync.py", # Background processes
"*/cli/main.py", # CLI entry point
"*/mcp/tools/project_management.py", # Covered by integration tests
"*/mcp/tools/sync_status.py", # Covered by integration tests
"*/services/migration_service.py", # Complex migration scenarios
]
[tool.logfire]
ignore_no_config = true
+483
View File
@@ -0,0 +1,483 @@
#!/usr/bin/env python3
"""
Legal File Inventory Generator for Basic Memory
Generates comprehensive file inventory with contributor information
for legal documentation, copyright assignments, and due diligence.
Usage:
python scripts/generate_legal_inventory.py [options]
Output formats:
- CSV: Detailed spreadsheet for analysis
- JSON: Structured data for integration
- Markdown: Human-readable legal report
"""
import argparse
import csv
import hashlib
import json
import subprocess
from collections import defaultdict
from datetime import datetime
from pathlib import Path
from typing import Dict, List
class LegalInventoryGenerator:
"""Generate comprehensive file inventory for legal documentation."""
# Files to exclude from legal inventory
EXCLUDED_PATTERNS = {
# Generated/compiled files
'*.pyc', '*.pyo', '*.pyd', '__pycache__',
'*.so', '*.dylib', '*.dll',
# Build/cache directories
'build/', 'dist/', '.eggs/', '*.egg-info/',
'.coverage', '.pytest_cache/', '.mypy_cache/',
'.ruff_cache/', '.tox/', 'venv/', '.venv/', 'env/', '.env/',
'node_modules/', '.npm/', '.yarn/',
# IDE and editor files
'.vscode/', '.idea/', '*.swp', '*.swo', '*~',
'.DS_Store', 'Thumbs.db',
# Version control
'.git/', '.gitignore',
# OS generated
'desktop.ini', '*.tmp', '*.temp'
}
# File categories for legal classification
FILE_CATEGORIES = {
'source_code': ['.py', '.pyx', '.pyi'],
'documentation': ['.md', '.rst', '.txt'],
'configuration': ['.toml', '.yaml', '.yml', '.json', '.ini', '.cfg'],
'legal': ['LICENSE', 'COPYING', 'COPYRIGHT', '.md'],
'build_deployment': ['Dockerfile', 'Makefile', 'justfile', '.sh'],
'database': ['.sql', '.sqlite', '.db'],
'templates': ['.j2', '.jinja2', '.hbs', '.handlebars'],
'data': ['.csv', '.json', '.xml'],
'other': [] # Catch-all for uncategorized files
}
def __init__(self, repo_path: str = "."):
"""Initialize generator with repository path."""
self.repo_path = Path(repo_path).resolve()
self.file_inventory: List[Dict] = []
self.contributors: Dict[str, Dict] = defaultdict(lambda: {
'email': '', 'commits': 0, 'lines_added': 0, 'files': set()
})
def should_exclude_file(self, file_path: Path) -> bool:
"""Check if file should be excluded from inventory."""
# Check if file is tracked by git (more efficient than check-ignore)
try:
rel_path = str(file_path.relative_to(self.repo_path))
result = subprocess.run([
'git', 'ls-files', '--error-unmatch', rel_path
], capture_output=True, cwd=self.repo_path)
# If git ls-files returns non-zero, file is not tracked (likely ignored)
if result.returncode != 0:
return True
except Exception:
# Fallback to manual exclusion patterns if git fails
pass
# Additional manual exclusions for safety
file_str = str(file_path.relative_to(self.repo_path))
for pattern in self.EXCLUDED_PATTERNS:
if pattern.endswith('/'):
if any(part == pattern[:-1] for part in file_path.parts):
return True
elif '*' in pattern:
import fnmatch
if fnmatch.fnmatch(file_str, pattern):
return True
else:
if file_path.name == pattern or file_str == pattern:
return True
return False
def categorize_file(self, file_path: Path) -> str:
"""Categorize file based on extension and name."""
suffix = file_path.suffix.lower()
name = file_path.name.upper()
# Check legal files by name first
if any(legal in name for legal in ['LICENSE', 'COPYING', 'COPYRIGHT', 'CLA']):
return 'legal'
# Check by extension
for category, extensions in self.FILE_CATEGORIES.items():
if suffix in extensions:
return category
return 'other'
def get_file_hash(self, file_path: Path) -> str:
"""Generate SHA-256 hash of file content."""
try:
with open(file_path, 'rb') as f:
return hashlib.sha256(f.read()).hexdigest()
except (IOError, OSError):
return "ERROR_READING_FILE"
def get_git_contributors(self, file_path: Path) -> List[Dict]:
"""Get contributor information for a specific file."""
try:
rel_path = file_path.relative_to(self.repo_path)
# Get contributors with line counts
result = subprocess.run([
'git', 'log', '--follow', '--pretty=format:%an|%ae|%ad|%H',
'--date=short', '--', str(rel_path)
], capture_output=True, text=True, cwd=self.repo_path)
if result.returncode != 0:
return []
contributors = []
seen = set()
for line in result.stdout.strip().split('\n'):
if not line:
continue
parts = line.split('|')
if len(parts) >= 4:
name, email, date, commit_hash = parts[:4]
# Normalize author names/emails
normalized_name = self.normalize_author_name(name, email)
if normalized_name not in seen:
contributors.append({
'name': normalized_name,
'email': email,
'first_contribution': date,
'commit_hash': commit_hash
})
seen.add(normalized_name)
return contributors
except Exception as e:
print(f"Warning: Could not get git info for {file_path}: {e}")
return []
def normalize_author_name(self, name: str, email: str) -> str:
"""Normalize author names to handle multiple emails for same person."""
# Known mappings for Basic Memory team
name_mappings = {
'phernandez': 'Paul Hernandez',
'Paul Hernandez': 'Paul Hernandez',
'drew-cain': 'Drew Cain',
'Drew Cain': 'Drew Cain'
}
# Handle GitHub bot accounts
if 'bot' in name.lower() or 'claude' in name.lower():
return f"{name} (AI Assistant)"
return name_mappings.get(name, name)
def get_file_stats(self, file_path: Path) -> Dict:
"""Get comprehensive file statistics."""
try:
stat = file_path.stat()
rel_path = file_path.relative_to(self.repo_path)
# Basic file info
file_info = {
'path': str(rel_path),
'name': file_path.name,
'size_bytes': stat.st_size,
'modified_time': datetime.fromtimestamp(stat.st_mtime).isoformat(),
'category': self.categorize_file(file_path),
'sha256_hash': self.get_file_hash(file_path)
}
# Git information
contributors = self.get_git_contributors(file_path)
file_info['contributors'] = contributors
file_info['primary_author'] = contributors[0]['name'] if contributors else 'Unknown'
file_info['contributor_count'] = len(contributors)
# Update global contributor stats
for contrib in contributors:
name = contrib['name']
self.contributors[name]['email'] = contrib['email']
self.contributors[name]['files'].add(str(rel_path))
return file_info
except Exception as e:
print(f"Error processing {file_path}: {e}")
return None
def scan_repository(self) -> None:
"""Scan repository and build file inventory."""
print(f"Scanning repository: {self.repo_path}")
# Get all git-tracked files first (much more efficient)
try:
result = subprocess.run([
'git', 'ls-files'
], capture_output=True, text=True, cwd=self.repo_path)
if result.returncode == 0:
tracked_files = [self.repo_path / f for f in result.stdout.strip().split('\n') if f]
print(f"Found {len(tracked_files)} git-tracked files")
for file_path in tracked_files:
if file_path.is_file():
file_info = self.get_file_stats(file_path)
if file_info:
self.file_inventory.append(file_info)
else:
print("Warning: Could not get git tracked files, falling back to directory scan")
self._fallback_scan()
except Exception as e:
print(f"Warning: Git command failed ({e}), falling back to directory scan")
self._fallback_scan()
# Get global git stats
self._get_global_git_stats()
print(f"Processed {len(self.file_inventory)} files")
print(f"Found {len(self.contributors)} contributors")
def _fallback_scan(self) -> None:
"""Fallback directory scan if git commands fail."""
for file_path in self.repo_path.rglob('*'):
if file_path.is_file() and not self.should_exclude_file(file_path):
file_info = self.get_file_stats(file_path)
if file_info:
self.file_inventory.append(file_info)
def _get_global_git_stats(self) -> None:
"""Get global contributor statistics from git."""
try:
# Get commit counts per author
result = subprocess.run([
'git', 'shortlog', '-sn', '--all'
], capture_output=True, text=True, cwd=self.repo_path)
if result.returncode == 0:
for line in result.stdout.strip().split('\n'):
if line.strip():
parts = line.strip().split('\t', 1)
if len(parts) == 2:
count, name = parts
normalized_name = self.normalize_author_name(name, '')
self.contributors[normalized_name]['commits'] = int(count)
except Exception as e:
print(f"Warning: Could not get global git stats: {e}")
def generate_summary(self) -> Dict:
"""Generate inventory summary statistics."""
total_files = len(self.file_inventory)
total_size = sum(f['size_bytes'] for f in self.file_inventory)
# Category breakdown
categories = defaultdict(int)
for file_info in self.file_inventory:
categories[file_info['category']] += 1
# Top contributors
top_contributors = sorted(
self.contributors.items(),
key=lambda x: len(x[1]['files']),
reverse=True
)[:10]
return {
'scan_date': datetime.now().isoformat(),
'repository_path': str(self.repo_path),
'total_files': total_files,
'total_size_bytes': total_size,
'categories': dict(categories),
'contributor_count': len(self.contributors),
'top_contributors': [
{
'name': name,
'file_count': len(stats['files']),
'commit_count': stats['commits'],
'email': stats['email']
}
for name, stats in top_contributors
]
}
def export_csv(self, output_path: str) -> None:
"""Export inventory to CSV format."""
with open(output_path, 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = [
'path', 'name', 'category', 'size_bytes', 'modified_time',
'primary_author', 'contributor_count', 'contributors_list',
'sha256_hash'
]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for file_info in sorted(self.file_inventory, key=lambda x: x['path']):
contributors_list = '; '.join([
f"{c['name']} ({c['email']})" for c in file_info['contributors']
])
writer.writerow({
'path': file_info['path'],
'name': file_info['name'],
'category': file_info['category'],
'size_bytes': file_info['size_bytes'],
'modified_time': file_info['modified_time'],
'primary_author': file_info['primary_author'],
'contributor_count': file_info['contributor_count'],
'contributors_list': contributors_list,
'sha256_hash': file_info['sha256_hash']
})
print(f"CSV export saved to: {output_path}")
def export_json(self, output_path: str) -> None:
"""Export inventory to JSON format."""
# Convert sets to lists for JSON serialization
contributors_serializable = {}
for name, stats in self.contributors.items():
contributors_serializable[name] = {
'email': stats['email'],
'commits': stats['commits'],
'lines_added': stats['lines_added'],
'files': list(stats['files'])
}
data = {
'summary': self.generate_summary(),
'files': self.file_inventory,
'contributors': contributors_serializable
}
with open(output_path, 'w', encoding='utf-8') as jsonfile:
json.dump(data, jsonfile, indent=2, ensure_ascii=False)
print(f"JSON export saved to: {output_path}")
def export_markdown(self, output_path: str) -> None:
"""Export inventory to Markdown format for legal documentation."""
summary = self.generate_summary()
with open(output_path, 'w', encoding='utf-8') as mdfile:
mdfile.write("# Basic Memory - Legal File Inventory\n\n")
# Summary section
mdfile.write("## Summary\n\n")
mdfile.write(f"**Scan Date:** {summary['scan_date']}\n")
mdfile.write(f"**Repository:** {summary['repository_path']}\n")
mdfile.write(f"**Total Files:** {summary['total_files']:,}\n")
mdfile.write(f"**Total Size:** {summary['total_size_bytes']:,} bytes\n")
mdfile.write(f"**Contributors:** {summary['contributor_count']}\n\n")
# Category breakdown
mdfile.write("## File Categories\n\n")
for category, count in sorted(summary['categories'].items()):
mdfile.write(f"- **{category.replace('_', ' ').title()}:** {count} files\n")
mdfile.write("\n")
# Top contributors
mdfile.write("## Contributors\n\n")
for contrib in summary['top_contributors']:
mdfile.write(f"- **{contrib['name']}** ({contrib['email']}): ")
mdfile.write(f"{contrib['file_count']} files, {contrib['commit_count']} commits\n")
mdfile.write("\n")
# Detailed file listing by category
mdfile.write("## Detailed File Inventory\n\n")
for category in sorted(summary['categories'].keys()):
category_files = [f for f in self.file_inventory if f['category'] == category]
if not category_files:
continue
mdfile.write(f"### {category.replace('_', ' ').title()}\n\n")
for file_info in sorted(category_files, key=lambda x: x['path']):
mdfile.write(f"**{file_info['path']}**\n")
mdfile.write(f"- Primary Author: {file_info['primary_author']}\n")
mdfile.write(f"- Contributors: {file_info['contributor_count']}\n")
mdfile.write(f"- Size: {file_info['size_bytes']:,} bytes\n")
if file_info['contributors']:
contributors_str = ', '.join([c['name'] for c in file_info['contributors']])
mdfile.write(f"- All Contributors: {contributors_str}\n")
mdfile.write(f"- SHA-256: `{file_info['sha256_hash']}`\n\n")
print(f"Markdown export saved to: {output_path}")
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(
description="Generate legal file inventory for Basic Memory repository"
)
parser.add_argument(
'--repo-path', '-r',
default='.',
help='Path to repository (default: current directory)'
)
parser.add_argument(
'--output-dir', '-o',
default='./legal_inventory',
help='Output directory for reports (default: ./legal_inventory)'
)
parser.add_argument(
'--formats', '-f',
nargs='+',
choices=['csv', 'json', 'markdown', 'all'],
default=['all'],
help='Output formats to generate (default: all)'
)
args = parser.parse_args()
# Create output directory
output_dir = Path(args.output_dir)
output_dir.mkdir(exist_ok=True)
# Generate inventory
generator = LegalInventoryGenerator(args.repo_path)
generator.scan_repository()
# Determine formats to export
formats = args.formats
if 'all' in formats:
formats = ['csv', 'json', 'markdown']
# Export in requested formats
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
if 'csv' in formats:
generator.export_csv(output_dir / f'basic_memory_inventory_{timestamp}.csv')
if 'json' in formats:
generator.export_json(output_dir / f'basic_memory_inventory_{timestamp}.json')
if 'markdown' in formats:
generator.export_markdown(output_dir / f'basic_memory_inventory_{timestamp}.md')
print("\nLegal inventory generation complete!")
print(f"Output saved to: {output_dir}")
if __name__ == '__main__':
main()
-36
View File
@@ -1,36 +0,0 @@
#!/bin/bash
set -e
echo "Welcome to Basic Memory installer"
# 1. Install uv if not present
if ! command -v uv &> /dev/null; then
echo "Installing uv package manager..."
curl -LsSf https://github.com/astral-sh/uv/releases/download/0.1.23/uv-installer.sh | sh
fi
# 2. Configure Claude Desktop
echo "Configuring Claude Desktop..."
CONFIG_FILE="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
# Create config directory if it doesn't exist
mkdir -p "$(dirname "$CONFIG_FILE")"
# If config file doesn't exist, create it with initial structure
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"mcpServers": {}}' > "$CONFIG_FILE"
fi
# Add/update the basic-memory config using jq
jq '.mcpServers."basic-memory" = {
"command": "uvx",
"args": ["basic-memory"]
}' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
echo "Installation complete! Basic Memory is now available in Claude Desktop."
echo "Please restart Claude Desktop for changes to take effect."
echo -e "\nQuick Start:"
echo "1. You can run sync directly using: uvx basic-memory sync"
echo "2. Optionally, install globally with: uv pip install basic-memory"
echo -e "\nBuilt with ♥️ by Basic Machines."
+15
View File
@@ -0,0 +1,15 @@
# Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
startCommand:
type: stdio
configSchema:
# JSON Schema defining the configuration options for the MCP.
type: object
properties: {}
description: No configuration required. This MCP server runs using the default command.
commandFunction: |-
(config) => ({
command: 'basic-memory',
args: ['mcp']
})
exampleConfig: {}
+5 -1
View File
@@ -1,3 +1,7 @@
"""basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
__version__ = "0.0.1"
# Package version - updated by release automation
__version__ = "0.14.4"
# API version for FastAPI - independent of package version
__api_version__ = "v0"
-1
View File
@@ -1 +0,0 @@
Generic single-database configuration.
@@ -3,7 +3,7 @@
[alembic]
# path to migration scripts
# Use forward slashes (/) also on windows to provide an os agnostic path
script_location = src/basic_memory/alembic
script_location = .
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
+27 -3
View File
@@ -1,5 +1,6 @@
"""Alembic environment configuration."""
import os
from logging.config import fileConfig
from sqlalchemy import engine_from_config
@@ -7,17 +8,25 @@ from sqlalchemy import pool
from alembic import context
from basic_memory.models import Base
from basic_memory.config import config as app_config
from basic_memory.config import ConfigManager
# set config.env to "test" for pytest to prevent logging to file in utils.setup_logging()
os.environ["BASIC_MEMORY_ENV"] = "test"
# Import after setting environment variable # noqa: E402
from basic_memory.models import Base # noqa: E402
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
app_config = ConfigManager().config
# Set the SQLAlchemy URL from our app config
sqlalchemy_url = f"sqlite:///{app_config.database_path}"
config.set_main_option("sqlalchemy.url", sqlalchemy_url)
# print(f"Using SQLAlchemy URL: {sqlalchemy_url}")
# Interpret the config file for Python logging.
if config.config_file_name is not None:
fileConfig(config.config_file_name)
@@ -27,6 +36,14 @@ if config.config_file_name is not None:
target_metadata = Base.metadata
# Add this function to tell Alembic what to include/exclude
def include_object(object, name, type_, reflected, compare_to):
# Ignore SQLite FTS tables
if type_ == "table" and name.startswith("search_index"):
return False
return True
def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode.
@@ -44,6 +61,8 @@ def run_migrations_offline() -> None:
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
include_object=include_object,
render_as_batch=True,
)
with context.begin_transaction():
@@ -63,7 +82,12 @@ def run_migrations_online() -> None:
)
with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)
context.configure(
connection=connection,
target_metadata=target_metadata,
include_object=include_object,
render_as_batch=True,
)
with context.begin_transaction():
context.run_migrations()
+4 -9
View File
@@ -1,6 +1,5 @@
"""Functions for managing database migrations."""
import asyncio
from pathlib import Path
from loguru import logger
from alembic.config import Config
@@ -10,20 +9,16 @@ from alembic import command
def get_alembic_config() -> Config: # pragma: no cover
"""Get alembic config with correct paths."""
migrations_path = Path(__file__).parent
alembic_ini = migrations_path.parent.parent.parent / "alembic.ini"
alembic_ini = migrations_path / "alembic.ini"
config = Config(alembic_ini)
config.set_main_option("script_location", str(migrations_path))
return config
async def reset_database(): # pragma: no cover
def reset_database(): # pragma: no cover
"""Drop and recreate all tables."""
logger.info("Resetting database...")
config = get_alembic_config()
def _reset(cfg):
command.downgrade(cfg, "base")
command.upgrade(cfg, "head")
await asyncio.get_event_loop().run_in_executor(None, _reset, config)
command.downgrade(config, "base")
command.upgrade(config, "head")
@@ -0,0 +1,51 @@
"""remove required from entity.permalink
Revision ID: 502b60eaa905
Revises: b3c3938bacdb
Create Date: 2025-02-24 13:33:09.790951
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "502b60eaa905"
down_revision: Union[str, None] = "b3c3938bacdb"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("entity", schema=None) as batch_op:
batch_op.alter_column("permalink", existing_type=sa.VARCHAR(), nullable=True)
batch_op.drop_index("ix_entity_permalink")
batch_op.create_index(batch_op.f("ix_entity_permalink"), ["permalink"], unique=False)
batch_op.drop_constraint("uix_entity_permalink", type_="unique")
batch_op.create_index(
"uix_entity_permalink",
["permalink"],
unique=True,
sqlite_where=sa.text("content_type = 'text/markdown' AND permalink IS NOT NULL"),
)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("entity", schema=None) as batch_op:
batch_op.drop_index(
"uix_entity_permalink",
sqlite_where=sa.text("content_type = 'text/markdown' AND permalink IS NOT NULL"),
)
batch_op.create_unique_constraint("uix_entity_permalink", ["permalink"])
batch_op.drop_index(batch_op.f("ix_entity_permalink"))
batch_op.create_index("ix_entity_permalink", ["permalink"], unique=1)
batch_op.alter_column("permalink", existing_type=sa.VARCHAR(), nullable=False)
# ### end Alembic commands ###
@@ -0,0 +1,108 @@
"""add projects table
Revision ID: 5fe1ab1ccebe
Revises: cc7172b46608
Create Date: 2025-05-14 09:05:18.214357
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "5fe1ab1ccebe"
down_revision: Union[str, None] = "cc7172b46608"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"project",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("permalink", sa.String(), nullable=False),
sa.Column("path", sa.String(), nullable=False),
sa.Column("is_active", sa.Boolean(), nullable=False),
sa.Column("is_default", sa.Boolean(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("is_default"),
sa.UniqueConstraint("name"),
sa.UniqueConstraint("permalink"),
if_not_exists=True,
)
with op.batch_alter_table("project", schema=None) as batch_op:
batch_op.create_index(
"ix_project_created_at", ["created_at"], unique=False, if_not_exists=True
)
batch_op.create_index("ix_project_name", ["name"], unique=True, if_not_exists=True)
batch_op.create_index("ix_project_path", ["path"], unique=False, if_not_exists=True)
batch_op.create_index(
"ix_project_permalink", ["permalink"], unique=True, if_not_exists=True
)
batch_op.create_index(
"ix_project_updated_at", ["updated_at"], unique=False, if_not_exists=True
)
with op.batch_alter_table("entity", schema=None) as batch_op:
batch_op.add_column(sa.Column("project_id", sa.Integer(), nullable=False))
batch_op.drop_index(
"uix_entity_permalink",
sqlite_where=sa.text("content_type = 'text/markdown' AND permalink IS NOT NULL"),
)
batch_op.drop_index("ix_entity_file_path")
batch_op.create_index(batch_op.f("ix_entity_file_path"), ["file_path"], unique=False)
batch_op.create_index("ix_entity_project_id", ["project_id"], unique=False)
batch_op.create_index(
"uix_entity_file_path_project", ["file_path", "project_id"], unique=True
)
batch_op.create_index(
"uix_entity_permalink_project",
["permalink", "project_id"],
unique=True,
sqlite_where=sa.text("content_type = 'text/markdown' AND permalink IS NOT NULL"),
)
batch_op.create_foreign_key("fk_entity_project_id", "project", ["project_id"], ["id"])
# drop the search index table. it will be recreated
op.drop_table("search_index")
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("entity", schema=None) as batch_op:
batch_op.drop_constraint("fk_entity_project_id", type_="foreignkey")
batch_op.drop_index(
"uix_entity_permalink_project",
sqlite_where=sa.text("content_type = 'text/markdown' AND permalink IS NOT NULL"),
)
batch_op.drop_index("uix_entity_file_path_project")
batch_op.drop_index("ix_entity_project_id")
batch_op.drop_index(batch_op.f("ix_entity_file_path"))
batch_op.create_index("ix_entity_file_path", ["file_path"], unique=1)
batch_op.create_index(
"uix_entity_permalink",
["permalink"],
unique=1,
sqlite_where=sa.text("content_type = 'text/markdown' AND permalink IS NOT NULL"),
)
batch_op.drop_column("project_id")
with op.batch_alter_table("project", schema=None) as batch_op:
batch_op.drop_index("ix_project_updated_at")
batch_op.drop_index("ix_project_permalink")
batch_op.drop_index("ix_project_path")
batch_op.drop_index("ix_project_name")
batch_op.drop_index("ix_project_created_at")
op.drop_table("project")
# ### end Alembic commands ###
@@ -0,0 +1,104 @@
"""project constraint fix
Revision ID: 647e7a75e2cd
Revises: 5fe1ab1ccebe
Create Date: 2025-06-03 12:48:30.162566
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "647e7a75e2cd"
down_revision: Union[str, None] = "5fe1ab1ccebe"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Remove the problematic UNIQUE constraint on is_default column.
The UNIQUE constraint prevents multiple projects from having is_default=FALSE,
which breaks project creation when the service sets is_default=False.
Since SQLite doesn't support dropping specific constraints easily, we'll
recreate the table without the problematic constraint.
"""
# For SQLite, we need to recreate the table without the UNIQUE constraint
# Create a new table without the UNIQUE constraint on is_default
op.create_table(
"project_new",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("permalink", sa.String(), nullable=False),
sa.Column("path", sa.String(), nullable=False),
sa.Column("is_active", sa.Boolean(), nullable=False),
sa.Column("is_default", sa.Boolean(), nullable=True), # No UNIQUE constraint!
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
sa.UniqueConstraint("permalink"),
)
# Copy data from old table to new table
op.execute("INSERT INTO project_new SELECT * FROM project")
# Drop the old table
op.drop_table("project")
# Rename the new table
op.rename_table("project_new", "project")
# Recreate the indexes
with op.batch_alter_table("project", schema=None) as batch_op:
batch_op.create_index("ix_project_created_at", ["created_at"], unique=False)
batch_op.create_index("ix_project_name", ["name"], unique=True)
batch_op.create_index("ix_project_path", ["path"], unique=False)
batch_op.create_index("ix_project_permalink", ["permalink"], unique=True)
batch_op.create_index("ix_project_updated_at", ["updated_at"], unique=False)
def downgrade() -> None:
"""Add back the UNIQUE constraint on is_default column.
WARNING: This will break project creation again if multiple projects
have is_default=FALSE.
"""
# Recreate the table with the UNIQUE constraint
op.create_table(
"project_old",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("permalink", sa.String(), nullable=False),
sa.Column("path", sa.String(), nullable=False),
sa.Column("is_active", sa.Boolean(), nullable=False),
sa.Column("is_default", sa.Boolean(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("is_default"), # Add back the problematic constraint
sa.UniqueConstraint("name"),
sa.UniqueConstraint("permalink"),
)
# Copy data (this may fail if multiple FALSE values exist)
op.execute("INSERT INTO project_old SELECT * FROM project")
# Drop the current table and rename
op.drop_table("project")
op.rename_table("project_old", "project")
# Recreate indexes
with op.batch_alter_table("project", schema=None) as batch_op:
batch_op.create_index("ix_project_created_at", ["created_at"], unique=False)
batch_op.create_index("ix_project_name", ["name"], unique=True)
batch_op.create_index("ix_project_path", ["path"], unique=False)
batch_op.create_index("ix_project_permalink", ["permalink"], unique=True)
batch_op.create_index("ix_project_updated_at", ["updated_at"], unique=False)
@@ -0,0 +1,53 @@
"""fix project foreign keys
Revision ID: a1b2c3d4e5f6
Revises: 647e7a75e2cd
Create Date: 2025-08-19 22:06:00.000000
"""
from typing import Sequence, Union
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "a1b2c3d4e5f6"
down_revision: Union[str, None] = "647e7a75e2cd"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Re-establish foreign key constraints that were lost during project table recreation.
The migration 647e7a75e2cd recreated the project table but did not re-establish
the foreign key constraint from entity.project_id to project.id, causing
foreign key constraint failures when trying to delete projects with related entities.
"""
# SQLite doesn't allow adding foreign key constraints to existing tables easily
# We need to be careful and handle the case where the constraint might already exist
with op.batch_alter_table("entity", schema=None) as batch_op:
# Try to drop existing foreign key constraint (may not exist)
try:
batch_op.drop_constraint("fk_entity_project_id", type_="foreignkey")
except Exception:
# Constraint may not exist, which is fine - we'll create it next
pass
# Add the foreign key constraint with CASCADE DELETE
# This ensures that when a project is deleted, all related entities are also deleted
batch_op.create_foreign_key(
"fk_entity_project_id",
"project",
["project_id"],
["id"],
ondelete="CASCADE"
)
def downgrade() -> None:
"""Remove the foreign key constraint."""
with op.batch_alter_table("entity", schema=None) as batch_op:
batch_op.drop_constraint("fk_entity_project_id", type_="foreignkey")
@@ -0,0 +1,44 @@
"""relation to_name unique index
Revision ID: b3c3938bacdb
Revises: 3dae7c7b1564
Create Date: 2025-02-22 14:59:30.668466
"""
from typing import Sequence, Union
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "b3c3938bacdb"
down_revision: Union[str, None] = "3dae7c7b1564"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# SQLite doesn't support constraint changes through ALTER
# Need to recreate table with desired constraints
with op.batch_alter_table("relation") as batch_op:
# Drop existing unique constraint
batch_op.drop_constraint("uix_relation", type_="unique")
# Add new constraints
batch_op.create_unique_constraint(
"uix_relation_from_id_to_id", ["from_id", "to_id", "relation_type"]
)
batch_op.create_unique_constraint(
"uix_relation_from_id_to_name", ["from_id", "to_name", "relation_type"]
)
def downgrade() -> None:
with op.batch_alter_table("relation") as batch_op:
# Drop new constraints
batch_op.drop_constraint("uix_relation_from_id_to_name", type_="unique")
batch_op.drop_constraint("uix_relation_from_id_to_id", type_="unique")
# Restore original constraint
batch_op.create_unique_constraint("uix_relation", ["from_id", "to_id", "relation_type"])
@@ -0,0 +1,100 @@
"""Update search index schema
Revision ID: cc7172b46608
Revises: 502b60eaa905
Create Date: 2025-02-28 18:48:23.244941
"""
from typing import Sequence, Union
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "cc7172b46608"
down_revision: Union[str, None] = "502b60eaa905"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade database schema to use new search index with content_stems and content_snippet."""
# First, drop the existing search_index table
op.execute("DROP TABLE IF EXISTS search_index")
# Create new search_index with updated schema
op.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS search_index USING fts5(
-- Core entity fields
id UNINDEXED, -- Row ID
title, -- Title for searching
content_stems, -- Main searchable content split into stems
content_snippet, -- File content snippet for display
permalink, -- Stable identifier (now indexed for path search)
file_path UNINDEXED, -- Physical location
type UNINDEXED, -- entity/relation/observation
-- Relation fields
from_id UNINDEXED, -- Source entity
to_id UNINDEXED, -- Target entity
relation_type UNINDEXED, -- Type of relation
-- Observation fields
entity_id UNINDEXED, -- Parent entity
category UNINDEXED, -- Observation category
-- Common fields
metadata UNINDEXED, -- JSON metadata
created_at UNINDEXED, -- Creation timestamp
updated_at UNINDEXED, -- Last update
-- Configuration
tokenize='unicode61 tokenchars 0x2F', -- Hex code for /
prefix='1,2,3,4' -- Support longer prefixes for paths
);
""")
def downgrade() -> None:
"""Downgrade database schema to use old search index."""
# Drop the updated search_index table
op.execute("DROP TABLE IF EXISTS search_index")
# Recreate the original search_index schema
op.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS search_index USING fts5(
-- Core entity fields
id UNINDEXED, -- Row ID
title, -- Title for searching
content, -- Main searchable content
permalink, -- Stable identifier (now indexed for path search)
file_path UNINDEXED, -- Physical location
type UNINDEXED, -- entity/relation/observation
-- Relation fields
from_id UNINDEXED, -- Source entity
to_id UNINDEXED, -- Target entity
relation_type UNINDEXED, -- Type of relation
-- Observation fields
entity_id UNINDEXED, -- Parent entity
category UNINDEXED, -- Observation category
-- Common fields
metadata UNINDEXED, -- JSON metadata
created_at UNINDEXED, -- Creation timestamp
updated_at UNINDEXED, -- Last update
-- Configuration
tokenize='unicode61 tokenchars 0x2F', -- Hex code for /
prefix='1,2,3,4' -- Support longer prefixes for paths
);
""")
# Print instruction to manually reindex after migration
print("\n------------------------------------------------------------------")
print("IMPORTANT: After downgrade completes, manually run the reindex command:")
print("basic-memory sync")
print("------------------------------------------------------------------\n")
+57 -31
View File
@@ -1,45 +1,54 @@
"""FastAPI application for basic-memory knowledge graph API."""
import asyncio
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from fastapi.exception_handlers import http_exception_handler
from loguru import logger
from basic_memory import __version__ as version
from basic_memory import db
from basic_memory.config import config as app_config
from basic_memory.api.routers import knowledge, search, memory, resource
from alembic import command
from alembic.config import Config
from basic_memory.db import DatabaseType
from basic_memory.repository.search_repository import SearchRepository
async def run_migrations(): # pragma: no cover
"""Run any pending alembic migrations."""
logger.info("Running database migrations...")
try:
config = Config("alembic.ini")
command.upgrade(config, "head")
logger.info("Migrations completed successfully")
_, session_maker = await db.get_or_create_db(
app_config.database_path, DatabaseType.FILESYSTEM
)
await SearchRepository(session_maker).init_search_index()
except Exception as e:
logger.error(f"Error running migrations: {e}")
raise
from basic_memory.api.routers import (
directory_router,
importer_router,
knowledge,
management,
memory,
project,
resource,
search,
prompt_router,
)
from basic_memory.config import ConfigManager
from basic_memory.services.initialization import initialize_app, initialize_file_sync
@asynccontextmanager
async def lifespan(app: FastAPI): # pragma: no cover
"""Lifecycle manager for the FastAPI app."""
app_config = ConfigManager().config
# Initialize app and database
logger.info("Starting Basic Memory API")
await run_migrations()
print(f"fastapi {app_config.projects}")
await initialize_app(app_config)
logger.info(f"Sync changes enabled: {app_config.sync_changes}")
if app_config.sync_changes:
# start file sync task in background
app.state.sync_task = asyncio.create_task(initialize_file_sync(app_config))
else:
logger.info("Sync changes disabled. Skipping file sync service.")
# proceed with startup
yield
logger.info("Shutting down Basic Memory API")
if app.state.sync_task:
logger.info("Stopping sync...")
app.state.sync_task.cancel() # pyright: ignore
await db.shutdown_db()
@@ -47,20 +56,37 @@ async def lifespan(app: FastAPI): # pragma: no cover
app = FastAPI(
title="Basic Memory API",
description="Knowledge graph API for basic-memory",
version="0.1.0",
version=version,
lifespan=lifespan,
)
# Include routers
app.include_router(knowledge.router)
app.include_router(search.router)
app.include_router(memory.router)
app.include_router(resource.router)
app.include_router(knowledge.router, prefix="/{project}")
app.include_router(memory.router, prefix="/{project}")
app.include_router(resource.router, prefix="/{project}")
app.include_router(search.router, prefix="/{project}")
app.include_router(project.project_router, prefix="/{project}")
app.include_router(directory_router.router, prefix="/{project}")
app.include_router(prompt_router.router, prefix="/{project}")
app.include_router(importer_router.router, prefix="/{project}")
# Project resource router works accross projects
app.include_router(project.project_resource_router)
app.include_router(management.router)
# Auth routes are handled by FastMCP automatically when auth is enabled
@app.exception_handler(Exception)
async def exception_handler(request, exc): # pragma: no cover
logger.exception(
f"An unhandled exception occurred for request '{request.url}', exception: {exc}"
"API unhandled exception",
url=str(request.url),
method=request.method,
client=request.client.host if request.client else None,
path=request.url.path,
error_type=type(exc).__name__,
error=str(exc),
)
return await http_exception_handler(request, HTTPException(status_code=500, detail=str(exc)))
+4 -1
View File
@@ -1,8 +1,11 @@
"""API routers."""
from . import knowledge_router as knowledge
from . import management_router as management
from . import memory_router as memory
from . import project_router as project
from . import resource_router as resource
from . import search_router as search
from . import prompt_router as prompt
__all__ = ["knowledge", "memory", "resource", "search"]
__all__ = ["knowledge", "management", "memory", "project", "resource", "search", "prompt"]
@@ -0,0 +1,63 @@
"""Router for directory tree operations."""
from typing import List, Optional
from fastapi import APIRouter, Query
from basic_memory.deps import DirectoryServiceDep, ProjectIdDep
from basic_memory.schemas.directory import DirectoryNode
router = APIRouter(prefix="/directory", tags=["directory"])
@router.get("/tree", response_model=DirectoryNode)
async def get_directory_tree(
directory_service: DirectoryServiceDep,
project_id: ProjectIdDep,
):
"""Get hierarchical directory structure from the knowledge base.
Args:
directory_service: Service for directory operations
project_id: ID of the current project
Returns:
DirectoryNode representing the root of the hierarchical tree structure
"""
# Get a hierarchical directory tree for the specific project
tree = await directory_service.get_directory_tree()
# Return the hierarchical tree
return tree
@router.get("/list", response_model=List[DirectoryNode])
async def list_directory(
directory_service: DirectoryServiceDep,
project_id: ProjectIdDep,
dir_name: str = Query("/", description="Directory path to list"),
depth: int = Query(1, ge=1, le=10, description="Recursion depth (1-10)"),
file_name_glob: Optional[str] = Query(
None, description="Glob pattern for filtering file names"
),
):
"""List directory contents with filtering and depth control.
Args:
directory_service: Service for directory operations
project_id: ID of the current project
dir_name: Directory path to list (default: root "/")
depth: Recursion depth (1-10, default: 1 for immediate children only)
file_name_glob: Optional glob pattern for filtering file names (e.g., "*.md", "*meeting*")
Returns:
List of DirectoryNode objects matching the criteria
"""
# Get directory listing with filtering
nodes = await directory_service.list_directory(
dir_name=dir_name,
depth=depth,
file_name_glob=file_name_glob,
)
return nodes
@@ -0,0 +1,152 @@
"""Import router for Basic Memory API."""
import json
import logging
from fastapi import APIRouter, Form, HTTPException, UploadFile, status
from basic_memory.deps import (
ChatGPTImporterDep,
ClaudeConversationsImporterDep,
ClaudeProjectsImporterDep,
MemoryJsonImporterDep,
)
from basic_memory.importers import Importer
from basic_memory.schemas.importer import (
ChatImportResult,
EntityImportResult,
ProjectImportResult,
)
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/import", tags=["import"])
@router.post("/chatgpt", response_model=ChatImportResult)
async def import_chatgpt(
importer: ChatGPTImporterDep,
file: UploadFile,
folder: str = Form("conversations"),
) -> ChatImportResult:
"""Import conversations from ChatGPT JSON export.
Args:
file: The ChatGPT conversations.json file.
folder: The folder to place the files in.
markdown_processor: MarkdownProcessor instance.
Returns:
ChatImportResult with import statistics.
Raises:
HTTPException: If import fails.
"""
return await import_file(importer, file, folder)
@router.post("/claude/conversations", response_model=ChatImportResult)
async def import_claude_conversations(
importer: ClaudeConversationsImporterDep,
file: UploadFile,
folder: str = Form("conversations"),
) -> ChatImportResult:
"""Import conversations from Claude conversations.json export.
Args:
file: The Claude conversations.json file.
folder: The folder to place the files in.
markdown_processor: MarkdownProcessor instance.
Returns:
ChatImportResult with import statistics.
Raises:
HTTPException: If import fails.
"""
return await import_file(importer, file, folder)
@router.post("/claude/projects", response_model=ProjectImportResult)
async def import_claude_projects(
importer: ClaudeProjectsImporterDep,
file: UploadFile,
folder: str = Form("projects"),
) -> ProjectImportResult:
"""Import projects from Claude projects.json export.
Args:
file: The Claude projects.json file.
base_folder: The base folder to place the files in.
markdown_processor: MarkdownProcessor instance.
Returns:
ProjectImportResult with import statistics.
Raises:
HTTPException: If import fails.
"""
return await import_file(importer, file, folder)
@router.post("/memory-json", response_model=EntityImportResult)
async def import_memory_json(
importer: MemoryJsonImporterDep,
file: UploadFile,
folder: str = Form("conversations"),
) -> EntityImportResult:
"""Import entities and relations from a memory.json file.
Args:
file: The memory.json file.
destination_folder: Optional destination folder within the project.
markdown_processor: MarkdownProcessor instance.
Returns:
EntityImportResult with import statistics.
Raises:
HTTPException: If import fails.
"""
try:
file_data = []
file_bytes = await file.read()
file_str = file_bytes.decode("utf-8")
for line in file_str.splitlines():
json_data = json.loads(line)
file_data.append(json_data)
result = await importer.import_data(file_data, folder)
if not result.success: # pragma: no cover
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=result.error_message or "Import failed",
)
except Exception as e:
logger.exception("Import failed")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Import failed: {str(e)}",
)
return result
async def import_file(importer: Importer, file: UploadFile, destination_folder: str):
try:
# Process file
json_data = json.load(file.file)
result = await importer.import_data(json_data, destination_folder)
if not result.success: # pragma: no cover
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=result.error_message or "Import failed",
)
return result
except Exception as e:
logger.exception("Import failed")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Import failed: {str(e)}",
)
+148 -28
View File
@@ -10,6 +10,11 @@ from basic_memory.deps import (
get_search_service,
SearchServiceDep,
LinkResolverDep,
ProjectPathDep,
FileServiceDep,
ProjectConfigDep,
AppConfigDep,
SyncServiceDep,
)
from basic_memory.schemas import (
EntityListResponse,
@@ -17,8 +22,8 @@ from basic_memory.schemas import (
DeleteEntitiesResponse,
DeleteEntitiesRequest,
)
from basic_memory.schemas.request import EditEntityRequest, MoveEntityRequest
from basic_memory.schemas.base import Permalink, Entity
from basic_memory.services.exceptions import EntityNotFoundError
router = APIRouter(prefix="/knowledge", tags=["knowledge"])
@@ -33,7 +38,9 @@ async def create_entity(
search_service: SearchServiceDep,
) -> EntityResponse:
"""Create an entity."""
logger.info(f"request: create_entity with data={data}")
logger.info(
"API request", endpoint="create_entity", entity_type=data.entity_type, title=data.title
)
entity = await entity_service.create_entity(data)
@@ -41,25 +48,38 @@ async def create_entity(
await search_service.index_entity(entity, background_tasks=background_tasks)
result = EntityResponse.model_validate(entity)
logger.info(f"response: create_entity with result={result}")
logger.info(
f"API response: endpoint='create_entity' title={result.title}, permalink={result.permalink}, status_code=201"
)
return result
@router.put("/entities/{permalink:path}", response_model=EntityResponse)
async def create_or_update_entity(
project: ProjectPathDep,
permalink: Permalink,
data: Entity,
response: Response,
background_tasks: BackgroundTasks,
entity_service: EntityServiceDep,
search_service: SearchServiceDep,
file_service: FileServiceDep,
sync_service: SyncServiceDep,
) -> EntityResponse:
"""Create or update an entity. If entity exists, it will be updated, otherwise created."""
logger.info(f"request: create_or_update_entity with permalink={permalink}, data={data}")
logger.info(
f"API request: create_or_update_entity for {project=}, {permalink=}, {data.entity_type=}, {data.title=}"
)
# Validate permalink matches
if data.permalink != permalink:
raise HTTPException(status_code=400, detail="Entity permalink must match URL path")
logger.warning(
f"API validation error: creating/updating entity with permalink mismatch - url={permalink}, data={data.permalink}",
)
raise HTTPException(
status_code=400,
detail=f"Entity permalink {data.permalink} must match URL path: '{permalink}'",
)
# Try create_or_update operation
entity, created = await entity_service.create_or_update_entity(data)
@@ -67,39 +87,144 @@ async def create_or_update_entity(
# reindex
await search_service.index_entity(entity, background_tasks=background_tasks)
# Attempt immediate relation resolution when creating new entities
# This helps resolve forward references when related entities are created in the same session
if created:
try:
await sync_service.resolve_relations()
logger.debug(f"Resolved relations after creating entity: {entity.permalink}")
except Exception as e: # pragma: no cover
# Don't fail the entire request if relation resolution fails
logger.warning(f"Failed to resolve relations after entity creation: {e}")
result = EntityResponse.model_validate(entity)
logger.info(
f"response: create_or_update_entity with result={result}, status_code={response.status_code}"
f"API response: {result.title=}, {result.permalink=}, {created=}, status_code={response.status_code}"
)
return result
@router.patch("/entities/{identifier:path}", response_model=EntityResponse)
async def edit_entity(
identifier: str,
data: EditEntityRequest,
background_tasks: BackgroundTasks,
entity_service: EntityServiceDep,
search_service: SearchServiceDep,
) -> EntityResponse:
"""Edit an existing entity using various operations like append, prepend, find_replace, or replace_section.
This endpoint allows for targeted edits without requiring the full entity content.
"""
logger.info(
f"API request: endpoint='edit_entity', identifier='{identifier}', operation='{data.operation}'"
)
try:
# Edit the entity using the service
entity = await entity_service.edit_entity(
identifier=identifier,
operation=data.operation,
content=data.content,
section=data.section,
find_text=data.find_text,
expected_replacements=data.expected_replacements,
)
# Reindex the updated entity
await search_service.index_entity(entity, background_tasks=background_tasks)
# Return the updated entity response
result = EntityResponse.model_validate(entity)
logger.info(
"API response",
endpoint="edit_entity",
identifier=identifier,
operation=data.operation,
permalink=result.permalink,
status_code=200,
)
return result
except Exception as e:
logger.error(f"Error editing entity: {e}")
raise HTTPException(status_code=400, detail=str(e))
@router.post("/move")
async def move_entity(
data: MoveEntityRequest,
background_tasks: BackgroundTasks,
entity_service: EntityServiceDep,
project_config: ProjectConfigDep,
app_config: AppConfigDep,
search_service: SearchServiceDep,
) -> EntityResponse:
"""Move an entity to a new file location with project consistency.
This endpoint moves a note to a different path while maintaining project
consistency and optionally updating permalinks based on configuration.
"""
logger.info(
f"API request: endpoint='move_entity', identifier='{data.identifier}', destination='{data.destination_path}'"
)
try:
# Move the entity using the service
moved_entity = await entity_service.move_entity(
identifier=data.identifier,
destination_path=data.destination_path,
project_config=project_config,
app_config=app_config,
)
# Get the moved entity to reindex it
entity = await entity_service.link_resolver.resolve_link(data.destination_path)
if entity:
await search_service.index_entity(entity, background_tasks=background_tasks)
logger.info(
"API response",
endpoint="move_entity",
identifier=data.identifier,
destination=data.destination_path,
status_code=200,
)
result = EntityResponse.model_validate(moved_entity)
return result
except Exception as e:
logger.error(f"Error moving entity: {e}")
raise HTTPException(status_code=400, detail=str(e))
## Read endpoints
@router.get("/entities/{permalink:path}", response_model=EntityResponse)
@router.get("/entities/{identifier:path}", response_model=EntityResponse)
async def get_entity(
entity_service: EntityServiceDep,
permalink: str,
link_resolver: LinkResolverDep,
identifier: str,
) -> EntityResponse:
"""Get a specific entity by ID.
"""Get a specific entity by file path or permalink..
Args:
permalink: Entity path ID
content: If True, include full file content
identifier: Entity file path or permalink
:param entity_service: EntityService
:param link_resolver: LinkResolver
"""
logger.info(f"request: get_entity with permalink={permalink}")
try:
entity = await entity_service.get_by_permalink(permalink)
result = EntityResponse.model_validate(entity)
logger.info(f"request: get_entity with identifier={identifier}")
entity = await link_resolver.resolve_link(identifier)
if not entity:
raise HTTPException(status_code=404, detail=f"Entity {identifier} not found")
logger.info(f"response: get_entity with result={result}")
return result
except EntityNotFoundError:
logger.error(f"Error: Entity with {permalink} not found")
raise HTTPException(status_code=404, detail=f"Entity with {permalink} not found")
result = EntityResponse.model_validate(entity)
return result
@router.get("/entities", response_model=EntityListResponse)
@@ -114,8 +239,6 @@ async def get_entities(
result = EntityListResponse(
entities=[EntityResponse.model_validate(entity) for entity in entities]
)
logger.info(f"response: get_entities with result={result}")
return result
@@ -135,17 +258,15 @@ async def delete_entity(
entity = await link_resolver.resolve_link(identifier)
if entity is None:
logger.info("response: delete_entity with result=DeleteEntitiesResponse(deleted=False)")
return DeleteEntitiesResponse(deleted=False)
# Delete the entity
deleted = await entity_service.delete_entity(entity.permalink)
deleted = await entity_service.delete_entity(entity.permalink or entity.id)
# Remove from search index
background_tasks.add_task(search_service.delete_by_permalink, entity.permalink)
# Remove from search index (entity, observations, and relations)
background_tasks.add_task(search_service.handle_delete, entity)
result = DeleteEntitiesResponse(deleted=deleted)
logger.info(f"response: delete_entity with result={result}")
return result
@@ -166,5 +287,4 @@ async def delete_entities(
background_tasks.add_task(search_service.delete_by_permalink, permalink)
result = DeleteEntitiesResponse(deleted=deleted)
logger.info(f"response: delete_entities with result={result}")
return result
@@ -0,0 +1,80 @@
"""Management router for basic-memory API."""
import asyncio
from fastapi import APIRouter, Request
from loguru import logger
from pydantic import BaseModel
from basic_memory.config import ConfigManager
from basic_memory.deps import SyncServiceDep, ProjectRepositoryDep
router = APIRouter(prefix="/management", tags=["management"])
class WatchStatusResponse(BaseModel):
"""Response model for watch status."""
running: bool
"""Whether the watch service is currently running."""
@router.get("/watch/status", response_model=WatchStatusResponse)
async def get_watch_status(request: Request) -> WatchStatusResponse:
"""Get the current status of the watch service."""
return WatchStatusResponse(
running=request.app.state.watch_task is not None and not request.app.state.watch_task.done()
)
@router.post("/watch/start", response_model=WatchStatusResponse)
async def start_watch_service(
request: Request, project_repository: ProjectRepositoryDep, sync_service: SyncServiceDep
) -> WatchStatusResponse:
"""Start the watch service if it's not already running."""
# needed because of circular imports from sync -> app
from basic_memory.sync import WatchService
from basic_memory.sync.background_sync import create_background_sync_task
if request.app.state.watch_task is not None and not request.app.state.watch_task.done():
# Watch service is already running
return WatchStatusResponse(running=True)
app_config = ConfigManager().config
# Create and start a new watch service
logger.info("Starting watch service via management API")
# Get services needed for the watch task
watch_service = WatchService(
app_config=app_config,
project_repository=project_repository,
)
# Create and store the task
watch_task = create_background_sync_task(sync_service, watch_service)
request.app.state.watch_task = watch_task
return WatchStatusResponse(running=True)
@router.post("/watch/stop", response_model=WatchStatusResponse)
async def stop_watch_service(request: Request) -> WatchStatusResponse: # pragma: no cover
"""Stop the watch service if it's running."""
if request.app.state.watch_task is None or request.app.state.watch_task.done():
# Watch service is not running
return WatchStatusResponse(running=False)
# Cancel the running task
logger.info("Stopping watch service via management API")
request.app.state.watch_task.cancel()
# Wait for it to be properly cancelled
try:
await request.app.state.watch_task
except asyncio.CancelledError:
pass
request.app.state.watch_task = None
return WatchStatusResponse(running=False)
+28 -67
View File
@@ -1,75 +1,22 @@
"""Routes for memory:// URI operations."""
from typing import Annotated
from typing import Annotated, Optional
from dateparser import parse
from fastapi import APIRouter, Query
from loguru import logger
from basic_memory.deps import ContextServiceDep, EntityRepositoryDep
from basic_memory.repository import EntityRepository
from basic_memory.repository.search_repository import SearchIndexRow
from basic_memory.schemas.base import TimeFrame
from basic_memory.schemas.base import TimeFrame, parse_timeframe
from basic_memory.schemas.memory import (
GraphContext,
RelationSummary,
EntitySummary,
ObservationSummary,
MemoryMetadata,
normalize_memory_url,
)
from basic_memory.schemas.search import SearchItemType
from basic_memory.services.context_service import ContextResultRow
from basic_memory.api.routers.utils import to_graph_context
router = APIRouter(prefix="/memory", tags=["memory"])
async def to_graph_context(context, entity_repository: EntityRepository):
# return results
async def to_summary(item: SearchIndexRow | ContextResultRow):
match item.type:
case SearchItemType.ENTITY:
assert item.title is not None
assert item.created_at is not None
return EntitySummary(
title=item.title,
permalink=item.permalink,
file_path=item.file_path,
created_at=item.created_at,
)
case SearchItemType.OBSERVATION:
assert item.category is not None
assert item.content is not None
return ObservationSummary(
category=item.category, content=item.content, permalink=item.permalink
)
case SearchItemType.RELATION:
assert item.from_id is not None
from_entity = await entity_repository.find_by_id(item.from_id)
assert from_entity is not None
to_entity = await entity_repository.find_by_id(item.to_id) if item.to_id else None
return RelationSummary(
permalink=item.permalink,
relation_type=item.type,
from_id=from_entity.permalink,
to_id=to_entity.permalink if to_entity else None,
)
case _: # pragma: no cover
raise ValueError(f"Unexpected type: {item.type}")
primary_results = [await to_summary(r) for r in context["primary_results"]]
related_results = [await to_summary(r) for r in context["related_results"]]
metadata = MemoryMetadata.model_validate(context["metadata"])
# Transform to GraphContext
return GraphContext(
primary_results=primary_results, related_results=related_results, metadata=metadata
)
@router.get("/recent", response_model=GraphContext)
async def recent(
context_service: ContextServiceDep,
@@ -77,7 +24,9 @@ async def recent(
type: Annotated[list[SearchItemType] | None, Query()] = None,
depth: int = 1,
timeframe: TimeFrame = "7d",
max_results: int = 10,
page: int = 1,
page_size: int = 10,
max_related: int = 10,
) -> GraphContext:
# return all types by default
types = (
@@ -87,16 +36,22 @@ async def recent(
)
logger.debug(
f"Getting recent context: `{types}` depth: `{depth}` timeframe: `{timeframe}` max_results: `{max_results}`"
f"Getting recent context: `{types}` depth: `{depth}` timeframe: `{timeframe}` page: `{page}` page_size: `{page_size}` max_related: `{max_related}`"
)
# Parse timeframe
since = parse(timeframe)
since = parse_timeframe(timeframe)
limit = page_size
offset = (page - 1) * page_size
# Build context
context = await context_service.build_context(
types=types, depth=depth, since=since, max_results=max_results
types=types, depth=depth, since=since, limit=limit, offset=offset, max_related=max_related
)
return await to_graph_context(context, entity_repository=entity_repository)
recent_context = await to_graph_context(
context, entity_repository=entity_repository, page=page, page_size=page_size
)
logger.debug(f"Recent context: {recent_context.model_dump_json()}")
return recent_context
# get_memory_context needs to be declared last so other paths can match
@@ -108,22 +63,28 @@ async def get_memory_context(
entity_repository: EntityRepositoryDep,
uri: str,
depth: int = 1,
timeframe: TimeFrame = "7d",
max_results: int = 10,
timeframe: Optional[TimeFrame] = None,
page: int = 1,
page_size: int = 10,
max_related: int = 10,
) -> GraphContext:
"""Get rich context from memory:// URI."""
# add the project name from the config to the url as the "host
# Parse URI
logger.debug(
f"Getting context for URI: `{uri}` depth: `{depth}` timeframe: `{timeframe}` max_results: `{max_results}`"
f"Getting context for URI: `{uri}` depth: `{depth}` timeframe: `{timeframe}` page: `{page}` page_size: `{page_size}` max_related: `{max_related}`"
)
memory_url = normalize_memory_url(uri)
# Parse timeframe
since = parse(timeframe)
since = parse_timeframe(timeframe) if timeframe else None
limit = page_size
offset = (page - 1) * page_size
# Build context
context = await context_service.build_context(
memory_url, depth=depth, since=since, max_results=max_results
memory_url, depth=depth, since=since, limit=limit, offset=offset, max_related=max_related
)
return await to_graph_context(
context, entity_repository=entity_repository, page=page, page_size=page_size
)
return await to_graph_context(context, entity_repository=entity_repository)
@@ -0,0 +1,242 @@
"""Router for project management."""
import os
from fastapi import APIRouter, HTTPException, Path, Body
from typing import Optional
from basic_memory.deps import ProjectServiceDep, ProjectPathDep
from basic_memory.schemas import ProjectInfoResponse
from basic_memory.schemas.project_info import (
ProjectList,
ProjectItem,
ProjectInfoRequest,
ProjectStatusResponse,
)
# Router for resources in a specific project
project_router = APIRouter(prefix="/project", tags=["project"])
# Router for managing project resources
project_resource_router = APIRouter(prefix="/projects", tags=["project_management"])
@project_router.get("/info", response_model=ProjectInfoResponse)
async def get_project_info(
project_service: ProjectServiceDep,
project: ProjectPathDep,
) -> ProjectInfoResponse:
"""Get comprehensive information about the specified Basic Memory project."""
return await project_service.get_project_info(project)
# Update a project
@project_router.patch("/{name}", response_model=ProjectStatusResponse)
async def update_project(
project_service: ProjectServiceDep,
name: str = Path(..., description="Name of the project to update"),
path: Optional[str] = Body(None, description="New absolute path for the project"),
is_active: Optional[bool] = Body(None, description="Status of the project (active/inactive)"),
) -> ProjectStatusResponse:
"""Update a project's information in configuration and database.
Args:
name: The name of the project to update
path: Optional new absolute path for the project
is_active: Optional status update for the project
Returns:
Response confirming the project was updated
"""
try:
# Validate that path is absolute if provided
if path and not os.path.isabs(path):
raise HTTPException(status_code=400, detail="Path must be absolute")
# Get original project info for the response
old_project_info = ProjectItem(
name=name,
path=project_service.projects.get(name, ""),
)
if path:
await project_service.move_project(name, path)
elif is_active is not None:
await project_service.update_project(name, is_active=is_active)
# Get updated project info
updated_path = path if path else project_service.projects.get(name, "")
return ProjectStatusResponse(
message=f"Project '{name}' updated successfully",
status="success",
default=(name == project_service.default_project),
old_project=old_project_info,
new_project=ProjectItem(name=name, path=updated_path),
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
# List all available projects
@project_resource_router.get("/projects", response_model=ProjectList)
async def list_projects(
project_service: ProjectServiceDep,
) -> ProjectList:
"""List all configured projects.
Returns:
A list of all projects with metadata
"""
projects = await project_service.list_projects()
default_project = project_service.default_project
project_items = [
ProjectItem(
name=project.name,
path=project.path,
is_default=project.is_default or False,
)
for project in projects
]
return ProjectList(
projects=project_items,
default_project=default_project,
)
# Add a new project
@project_resource_router.post("/projects", response_model=ProjectStatusResponse)
async def add_project(
project_data: ProjectInfoRequest,
project_service: ProjectServiceDep,
) -> ProjectStatusResponse:
"""Add a new project to configuration and database.
Args:
project_data: The project name and path, with option to set as default
Returns:
Response confirming the project was added
"""
try: # pragma: no cover
await project_service.add_project(
project_data.name, project_data.path, set_default=project_data.set_default
)
return ProjectStatusResponse( # pyright: ignore [reportCallIssue]
message=f"Project '{project_data.name}' added successfully",
status="success",
default=project_data.set_default,
new_project=ProjectItem(
name=project_data.name, path=project_data.path, is_default=project_data.set_default
),
)
except ValueError as e: # pragma: no cover
raise HTTPException(status_code=400, detail=str(e))
# Remove a project
@project_resource_router.delete("/{name}", response_model=ProjectStatusResponse)
async def remove_project(
project_service: ProjectServiceDep,
name: str = Path(..., description="Name of the project to remove"),
) -> ProjectStatusResponse:
"""Remove a project from configuration and database.
Args:
name: The name of the project to remove
Returns:
Response confirming the project was removed
"""
try:
old_project = await project_service.get_project(name)
if not old_project: # pragma: no cover
raise HTTPException(
status_code=404, detail=f"Project: '{name}' does not exist"
) # pragma: no cover
await project_service.remove_project(name)
return ProjectStatusResponse(
message=f"Project '{name}' removed successfully",
status="success",
default=False,
old_project=ProjectItem(name=old_project.name, path=old_project.path),
new_project=None,
)
except ValueError as e: # pragma: no cover
raise HTTPException(status_code=400, detail=str(e))
# Set a project as default
@project_resource_router.put("/{name}/default", response_model=ProjectStatusResponse)
async def set_default_project(
project_service: ProjectServiceDep,
name: str = Path(..., description="Name of the project to set as default"),
) -> ProjectStatusResponse:
"""Set a project as the default project.
Args:
name: The name of the project to set as default
Returns:
Response confirming the project was set as default
"""
try:
# Get the old default project
default_name = project_service.default_project
default_project = await project_service.get_project(default_name)
if not default_project: # pragma: no cover
raise HTTPException( # pragma: no cover
status_code=404, detail=f"Default Project: '{default_name}' does not exist"
)
# get the new project
new_default_project = await project_service.get_project(name)
if not new_default_project: # pragma: no cover
raise HTTPException(
status_code=404, detail=f"Project: '{name}' does not exist"
) # pragma: no cover
await project_service.set_default_project(name)
return ProjectStatusResponse(
message=f"Project '{name}' set as default successfully",
status="success",
default=True,
old_project=ProjectItem(name=default_name, path=default_project.path),
new_project=ProjectItem(
name=name,
path=new_default_project.path,
is_default=True,
),
)
except ValueError as e: # pragma: no cover
raise HTTPException(status_code=400, detail=str(e))
# Synchronize projects between config and database
@project_resource_router.post("/sync", response_model=ProjectStatusResponse)
async def synchronize_projects(
project_service: ProjectServiceDep,
) -> ProjectStatusResponse:
"""Synchronize projects between configuration file and database.
Ensures that all projects in the configuration file exist in the database
and vice versa.
Returns:
Response confirming synchronization was completed
"""
try: # pragma: no cover
await project_service.synchronize_projects()
return ProjectStatusResponse( # pyright: ignore [reportCallIssue]
message="Projects synchronized successfully between configuration and database",
status="success",
default=False,
)
except ValueError as e: # pragma: no cover
raise HTTPException(status_code=400, detail=str(e))
@@ -0,0 +1,260 @@
"""Router for prompt-related operations.
This router is responsible for rendering various prompts using Handlebars templates.
It centralizes all prompt formatting logic that was previously in the MCP prompts.
"""
from datetime import datetime, timezone
from fastapi import APIRouter, HTTPException, status
from loguru import logger
from basic_memory.api.routers.utils import to_graph_context, to_search_results
from basic_memory.api.template_loader import template_loader
from basic_memory.schemas.base import parse_timeframe
from basic_memory.deps import (
ContextServiceDep,
EntityRepositoryDep,
SearchServiceDep,
EntityServiceDep,
)
from basic_memory.schemas.prompt import (
ContinueConversationRequest,
SearchPromptRequest,
PromptResponse,
PromptMetadata,
)
from basic_memory.schemas.search import SearchItemType, SearchQuery
router = APIRouter(prefix="/prompt", tags=["prompt"])
@router.post("/continue-conversation", response_model=PromptResponse)
async def continue_conversation(
search_service: SearchServiceDep,
entity_service: EntityServiceDep,
context_service: ContextServiceDep,
entity_repository: EntityRepositoryDep,
request: ContinueConversationRequest,
) -> PromptResponse:
"""Generate a prompt for continuing a conversation.
This endpoint takes a topic and/or timeframe and generates a prompt with
relevant context from the knowledge base.
Args:
request: The request parameters
Returns:
Formatted continuation prompt with context
"""
logger.info(
f"Generating continue conversation prompt, topic: {request.topic}, timeframe: {request.timeframe}"
)
since = parse_timeframe(request.timeframe) if request.timeframe else None
# Initialize search results
search_results = []
# Get data needed for template
if request.topic:
query = SearchQuery(text=request.topic, after_date=request.timeframe)
results = await search_service.search(query, limit=request.search_items_limit)
search_results = await to_search_results(entity_service, results)
# Build context from results
all_hierarchical_results = []
for result in search_results:
if hasattr(result, "permalink") and result.permalink:
# Get hierarchical context using the new dataclass-based approach
context_result = await context_service.build_context(
result.permalink,
depth=request.depth,
since=since,
max_related=request.related_items_limit,
include_observations=True, # Include observations for entities
)
# Process results into the schema format
graph_context = await to_graph_context(
context_result, entity_repository=entity_repository
)
# Add results to our collection (limit to top results for each permalink)
if graph_context.results:
all_hierarchical_results.extend(graph_context.results[:3])
# Limit to a reasonable number of total results
all_hierarchical_results = all_hierarchical_results[:10]
template_context = {
"topic": request.topic,
"timeframe": request.timeframe,
"hierarchical_results": all_hierarchical_results,
"has_results": len(all_hierarchical_results) > 0,
}
else:
# If no topic, get recent activity
context_result = await context_service.build_context(
types=[SearchItemType.ENTITY],
depth=request.depth,
since=since,
max_related=request.related_items_limit,
include_observations=True,
)
recent_context = await to_graph_context(context_result, entity_repository=entity_repository)
hierarchical_results = recent_context.results[:5] # Limit to top 5 recent items
template_context = {
"topic": f"Recent Activity from ({request.timeframe})",
"timeframe": request.timeframe,
"hierarchical_results": hierarchical_results,
"has_results": len(hierarchical_results) > 0,
}
try:
# Render template
rendered_prompt = await template_loader.render(
"prompts/continue_conversation.hbs", template_context
)
# Calculate metadata
# Count items of different types
observation_count = 0
relation_count = 0
entity_count = 0
# Get the hierarchical results from the template context
hierarchical_results_for_count = template_context.get("hierarchical_results", [])
# For topic-based search
if request.topic:
for item in hierarchical_results_for_count:
if hasattr(item, "observations"):
observation_count += len(item.observations) if item.observations else 0
if hasattr(item, "related_results"):
for related in item.related_results or []:
if hasattr(related, "type"):
if related.type == "relation":
relation_count += 1
elif related.type == "entity": # pragma: no cover
entity_count += 1 # pragma: no cover
# For recent activity
else:
for item in hierarchical_results_for_count:
if hasattr(item, "observations"):
observation_count += len(item.observations) if item.observations else 0
if hasattr(item, "related_results"):
for related in item.related_results or []:
if hasattr(related, "type"):
if related.type == "relation":
relation_count += 1
elif related.type == "entity": # pragma: no cover
entity_count += 1 # pragma: no cover
# Build metadata
metadata = {
"query": request.topic,
"timeframe": request.timeframe,
"search_count": len(search_results)
if request.topic
else 0, # Original search results count
"context_count": len(hierarchical_results_for_count),
"observation_count": observation_count,
"relation_count": relation_count,
"total_items": (
len(hierarchical_results_for_count)
+ observation_count
+ relation_count
+ entity_count
),
"search_limit": request.search_items_limit,
"context_depth": request.depth,
"related_limit": request.related_items_limit,
"generated_at": datetime.now(timezone.utc).isoformat(),
}
prompt_metadata = PromptMetadata(**metadata)
return PromptResponse(
prompt=rendered_prompt, context=template_context, metadata=prompt_metadata
)
except Exception as e:
logger.error(f"Error rendering continue conversation template: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Error rendering prompt template: {str(e)}",
)
@router.post("/search", response_model=PromptResponse)
async def search_prompt(
search_service: SearchServiceDep,
entity_service: EntityServiceDep,
request: SearchPromptRequest,
page: int = 1,
page_size: int = 10,
) -> PromptResponse:
"""Generate a prompt for search results.
This endpoint takes a search query and formats the results into a helpful
prompt with context and suggestions.
Args:
request: The search parameters
page: The page number for pagination
page_size: The number of results per page, defaults to 10
Returns:
Formatted search results prompt with context
"""
logger.info(f"Generating search prompt, query: {request.query}, timeframe: {request.timeframe}")
limit = page_size
offset = (page - 1) * page_size
query = SearchQuery(text=request.query, after_date=request.timeframe)
results = await search_service.search(query, limit=limit, offset=offset)
search_results = await to_search_results(entity_service, results)
template_context = {
"query": request.query,
"timeframe": request.timeframe,
"results": search_results,
"has_results": len(search_results) > 0,
"result_count": len(search_results),
}
try:
# Render template
rendered_prompt = await template_loader.render("prompts/search.hbs", template_context)
# Build metadata
metadata = {
"query": request.query,
"timeframe": request.timeframe,
"search_count": len(search_results),
"context_count": len(search_results),
"observation_count": 0, # Search results don't include observations
"relation_count": 0, # Search results don't include relations
"total_items": len(search_results),
"search_limit": limit,
"context_depth": 0, # No context depth for basic search
"related_limit": 0, # No related items for basic search
"generated_at": datetime.now(timezone.utc).isoformat(),
}
prompt_metadata = PromptMetadata(**metadata)
return PromptResponse(
prompt=rendered_prompt, context=template_context, metadata=prompt_metadata
)
except Exception as e:
logger.error(f"Error rendering search template: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Error rendering prompt template: {str(e)}",
)
+204 -13
View File
@@ -1,34 +1,225 @@
"""Routes for getting entity content."""
import tempfile
from pathlib import Path
from typing import Annotated
from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse
from fastapi import APIRouter, HTTPException, BackgroundTasks, Body
from fastapi.responses import FileResponse, JSONResponse
from loguru import logger
from basic_memory.deps import ProjectConfigDep, LinkResolverDep
from basic_memory.deps import (
ProjectConfigDep,
LinkResolverDep,
SearchServiceDep,
EntityServiceDep,
FileServiceDep,
EntityRepositoryDep,
)
from basic_memory.repository.search_repository import SearchIndexRow
from basic_memory.schemas.memory import normalize_memory_url
from basic_memory.schemas.search import SearchQuery, SearchItemType
from basic_memory.models.knowledge import Entity as EntityModel
from datetime import datetime
router = APIRouter(prefix="/resource", tags=["resources"])
def get_entity_ids(item: SearchIndexRow) -> set[int]:
match item.type:
case SearchItemType.ENTITY:
return {item.id}
case SearchItemType.OBSERVATION:
return {item.entity_id} # pyright: ignore [reportReturnType]
case SearchItemType.RELATION:
from_entity = item.from_id
to_entity = item.to_id # pyright: ignore [reportReturnType]
return {from_entity, to_entity} if to_entity else {from_entity} # pyright: ignore [reportReturnType]
case _: # pragma: no cover
raise ValueError(f"Unexpected type: {item.type}")
@router.get("/{identifier:path}")
async def get_resource_content(
config: ProjectConfigDep,
link_resolver: LinkResolverDep,
search_service: SearchServiceDep,
entity_service: EntityServiceDep,
file_service: FileServiceDep,
background_tasks: BackgroundTasks,
identifier: str,
page: int = 1,
page_size: int = 10,
) -> FileResponse:
"""Get resource content by identifier: name or permalink."""
logger.debug(f"Getting content for permalink: {identifier}")
logger.debug(f"Getting content for: {identifier}")
# Find entity by permalink
# Find single entity by permalink
entity = await link_resolver.resolve_link(identifier)
if not entity:
raise HTTPException(status_code=404, detail=f"Entity not found: {identifier}")
results = [entity] if entity else []
file_path = Path(f"{config.home}/{entity.file_path}")
if not file_path.exists():
raise HTTPException(
status_code=404,
detail=f"File not found: {file_path}",
# pagination for multiple results
limit = page_size
offset = (page - 1) * page_size
# search using the identifier as a permalink
if not results:
# if the identifier contains a wildcard, use GLOB search
query = (
SearchQuery(permalink_match=identifier)
if "*" in identifier
else SearchQuery(permalink=identifier)
)
return FileResponse(path=file_path)
search_results = await search_service.search(query, limit, offset)
if not search_results:
raise HTTPException(status_code=404, detail=f"Resource not found: {identifier}")
# get the deduplicated entities related to the search results
entity_ids = {id for result in search_results for id in get_entity_ids(result)}
results = await entity_service.get_entities_by_id(list(entity_ids))
# return single response
if len(results) == 1:
entity = results[0]
file_path = Path(f"{config.home}/{entity.file_path}")
if not file_path.exists():
raise HTTPException(
status_code=404,
detail=f"File not found: {file_path}",
)
return FileResponse(path=file_path)
# for multiple files, initialize a temporary file for writing the results
with tempfile.NamedTemporaryFile(delete=False, mode="w", suffix=".md") as tmp_file:
temp_file_path = tmp_file.name
for result in results:
# Read content for each entity
content = await file_service.read_entity_content(result)
memory_url = normalize_memory_url(result.permalink)
modified_date = result.updated_at.isoformat()
checksum = result.checksum[:8] if result.checksum else ""
# Prepare the delimited content
response_content = f"--- {memory_url} {modified_date} {checksum}\n"
response_content += f"\n{content}\n"
response_content += "\n"
# Write content directly to the temporary file in append mode
tmp_file.write(response_content)
# Ensure all content is written to disk
tmp_file.flush()
# Schedule the temporary file to be deleted after the response
background_tasks.add_task(cleanup_temp_file, temp_file_path)
# Return the file response
return FileResponse(path=temp_file_path)
def cleanup_temp_file(file_path: str):
"""Delete the temporary file."""
try:
Path(file_path).unlink() # Deletes the file
logger.debug(f"Temporary file deleted: {file_path}")
except Exception as e: # pragma: no cover
logger.error(f"Error deleting temporary file {file_path}: {e}")
@router.put("/{file_path:path}")
async def write_resource(
config: ProjectConfigDep,
file_service: FileServiceDep,
entity_repository: EntityRepositoryDep,
search_service: SearchServiceDep,
file_path: str,
content: Annotated[str, Body()],
) -> JSONResponse:
"""Write content to a file in the project.
This endpoint allows writing content directly to a file in the project.
Also creates an entity record and indexes the file for search.
Args:
file_path: Path to write to, relative to project root
request: Contains the content to write
Returns:
JSON response with file information
"""
try:
# Get content from request body
# Ensure it's UTF-8 string content
if isinstance(content, bytes): # pragma: no cover
content_str = content.decode("utf-8")
else:
content_str = str(content)
# Get full file path
full_path = Path(f"{config.home}/{file_path}")
# Ensure parent directory exists
full_path.parent.mkdir(parents=True, exist_ok=True)
# Write content to file
checksum = await file_service.write_file(full_path, content_str)
# Get file info
file_stats = file_service.file_stats(full_path)
# Determine file details
file_name = Path(file_path).name
content_type = file_service.content_type(full_path)
entity_type = "canvas" if file_path.endswith(".canvas") else "file"
# Check if entity already exists
existing_entity = await entity_repository.get_by_file_path(file_path)
if existing_entity:
# Update existing entity
entity = await entity_repository.update(
existing_entity.id,
{
"title": file_name,
"entity_type": entity_type,
"content_type": content_type,
"file_path": file_path,
"checksum": checksum,
"updated_at": datetime.fromtimestamp(file_stats.st_mtime).astimezone(),
},
)
status_code = 200
else:
# Create a new entity model
entity = EntityModel(
title=file_name,
entity_type=entity_type,
content_type=content_type,
file_path=file_path,
checksum=checksum,
created_at=datetime.fromtimestamp(file_stats.st_ctime).astimezone(),
updated_at=datetime.fromtimestamp(file_stats.st_mtime).astimezone(),
)
entity = await entity_repository.add(entity)
status_code = 201
# Index the file for search
await search_service.index_entity(entity) # pyright: ignore
# Return success response
return JSONResponse(
status_code=status_code,
content={
"file_path": file_path,
"checksum": checksum,
"size": file_stats.st_size,
"created_at": file_stats.st_ctime,
"modified_at": file_stats.st_mtime,
},
)
except Exception as e: # pragma: no cover
logger.error(f"Error writing resource {file_path}: {e}")
raise HTTPException(status_code=500, detail=f"Failed to write resource: {str(e)}")
+21 -13
View File
@@ -1,28 +1,36 @@
"""Router for search operations."""
from dataclasses import asdict
from fastapi import APIRouter, BackgroundTasks
from fastapi import APIRouter, Depends, BackgroundTasks
from basic_memory.services.search_service import SearchService
from basic_memory.schemas.search import SearchQuery, SearchResult, SearchResponse
from basic_memory.deps import get_search_service
from basic_memory.api.routers.utils import to_search_results
from basic_memory.schemas.search import SearchQuery, SearchResponse
from basic_memory.deps import SearchServiceDep, EntityServiceDep
router = APIRouter(prefix="/search", tags=["search"])
@router.post("/", response_model=SearchResponse)
async def search(query: SearchQuery, search_service: SearchService = Depends(get_search_service)):
async def search(
query: SearchQuery,
search_service: SearchServiceDep,
entity_service: EntityServiceDep,
page: int = 1,
page_size: int = 10,
):
"""Search across all knowledge and documents."""
results = await search_service.search(query)
search_results = [SearchResult.model_validate(asdict(r)) for r in results]
return SearchResponse(results=search_results)
limit = page_size
offset = (page - 1) * page_size
results = await search_service.search(query, limit=limit, offset=offset)
search_results = await to_search_results(entity_service, results)
return SearchResponse(
results=search_results,
current_page=page,
page_size=page_size,
)
@router.post("/reindex")
async def reindex(
background_tasks: BackgroundTasks, search_service: SearchService = Depends(get_search_service)
):
async def reindex(background_tasks: BackgroundTasks, search_service: SearchServiceDep):
"""Recreate and populate the search index."""
await search_service.reindex_all(background_tasks=background_tasks)
return {"status": "ok", "message": "Reindex initiated"}
+130
View File
@@ -0,0 +1,130 @@
from typing import Optional, List
from basic_memory.repository import EntityRepository
from basic_memory.repository.search_repository import SearchIndexRow
from basic_memory.schemas.memory import (
EntitySummary,
ObservationSummary,
RelationSummary,
MemoryMetadata,
GraphContext,
ContextResult,
)
from basic_memory.schemas.search import SearchItemType, SearchResult
from basic_memory.services import EntityService
from basic_memory.services.context_service import (
ContextResultRow,
ContextResult as ServiceContextResult,
)
async def to_graph_context(
context_result: ServiceContextResult,
entity_repository: EntityRepository,
page: Optional[int] = None,
page_size: Optional[int] = None,
):
# Helper function to convert items to summaries
async def to_summary(item: SearchIndexRow | ContextResultRow):
match item.type:
case SearchItemType.ENTITY:
return EntitySummary(
title=item.title, # pyright: ignore
permalink=item.permalink,
content=item.content,
file_path=item.file_path,
created_at=item.created_at,
)
case SearchItemType.OBSERVATION:
return ObservationSummary(
title=item.title, # pyright: ignore
file_path=item.file_path,
category=item.category, # pyright: ignore
content=item.content, # pyright: ignore
permalink=item.permalink, # pyright: ignore
created_at=item.created_at,
)
case SearchItemType.RELATION:
from_entity = await entity_repository.find_by_id(item.from_id) # pyright: ignore
to_entity = await entity_repository.find_by_id(item.to_id) if item.to_id else None
return RelationSummary(
title=item.title, # pyright: ignore
file_path=item.file_path,
permalink=item.permalink, # pyright: ignore
relation_type=item.relation_type, # pyright: ignore
from_entity=from_entity.title if from_entity else None,
to_entity=to_entity.title if to_entity else None,
created_at=item.created_at,
)
case _: # pragma: no cover
raise ValueError(f"Unexpected type: {item.type}")
# Process the hierarchical results
hierarchical_results = []
for context_item in context_result.results:
# Process primary result
primary_result = await to_summary(context_item.primary_result)
# Process observations
observations = []
for obs in context_item.observations:
observations.append(await to_summary(obs))
# Process related results
related = []
for rel in context_item.related_results:
related.append(await to_summary(rel))
# Add to hierarchical results
hierarchical_results.append(
ContextResult(
primary_result=primary_result,
observations=observations,
related_results=related,
)
)
# Create schema metadata from service metadata
metadata = MemoryMetadata(
uri=context_result.metadata.uri,
types=context_result.metadata.types,
depth=context_result.metadata.depth,
timeframe=context_result.metadata.timeframe,
generated_at=context_result.metadata.generated_at,
primary_count=context_result.metadata.primary_count,
related_count=context_result.metadata.related_count,
total_results=context_result.metadata.primary_count + context_result.metadata.related_count,
total_relations=context_result.metadata.total_relations,
total_observations=context_result.metadata.total_observations,
)
# Return new GraphContext with just hierarchical results
return GraphContext(
results=hierarchical_results,
metadata=metadata,
page=page,
page_size=page_size,
)
async def to_search_results(entity_service: EntityService, results: List[SearchIndexRow]):
search_results = []
for r in results:
entities = await entity_service.get_entities_by_id([r.entity_id, r.from_id, r.to_id]) # pyright: ignore
search_results.append(
SearchResult(
title=r.title, # pyright: ignore
type=r.type, # pyright: ignore
permalink=r.permalink,
score=r.score, # pyright: ignore
entity=entities[0].permalink if entities else None,
content=r.content,
file_path=r.file_path,
metadata=r.metadata,
category=r.category,
from_entity=entities[0].permalink if entities else None,
to_entity=entities[1].permalink if len(entities) > 1 else None,
relation_type=r.relation_type,
)
)
return search_results
+292
View File
@@ -0,0 +1,292 @@
"""Template loading and rendering utilities for the Basic Memory API.
This module handles the loading and rendering of Handlebars templates from the
templates directory, providing a consistent interface for all prompt-related
formatting needs.
"""
import textwrap
from typing import Dict, Any, Optional, Callable
from pathlib import Path
import json
import datetime
import pybars
from loguru import logger
# Get the base path of the templates directory
TEMPLATES_DIR = Path(__file__).parent.parent / "templates"
# Custom helpers for Handlebars
def _date_helper(this, *args):
"""Format a date using the given format string."""
if len(args) < 1: # pragma: no cover
return ""
timestamp = args[0]
format_str = args[1] if len(args) > 1 else "%Y-%m-%d %H:%M"
if hasattr(timestamp, "strftime"):
result = timestamp.strftime(format_str)
elif isinstance(timestamp, str):
try:
dt = datetime.datetime.fromisoformat(timestamp)
result = dt.strftime(format_str)
except ValueError:
result = timestamp
else:
result = str(timestamp) # pragma: no cover
return pybars.strlist([result])
def _default_helper(this, *args):
"""Return a default value if the given value is None or empty."""
if len(args) < 2: # pragma: no cover
return ""
value = args[0]
default_value = args[1]
result = default_value if value is None or value == "" else value
# Use strlist for consistent handling of HTML escaping
return pybars.strlist([str(result)])
def _capitalize_helper(this, *args):
"""Capitalize the first letter of a string."""
if len(args) < 1: # pragma: no cover
return ""
text = args[0]
if not text or not isinstance(text, str): # pragma: no cover
result = ""
else:
result = text.capitalize()
return pybars.strlist([result])
def _round_helper(this, *args):
"""Round a number to the specified number of decimal places."""
if len(args) < 1:
return ""
value = args[0]
decimal_places = args[1] if len(args) > 1 else 2
try:
result = str(round(float(value), int(decimal_places)))
except (ValueError, TypeError):
result = str(value)
return pybars.strlist([result])
def _size_helper(this, *args):
"""Return the size/length of a collection."""
if len(args) < 1:
return 0
value = args[0]
if value is None:
result = "0"
elif isinstance(value, (list, tuple, dict, str)):
result = str(len(value)) # pragma: no cover
else: # pragma: no cover
result = "0"
return pybars.strlist([result])
def _json_helper(this, *args):
"""Convert a value to a JSON string."""
if len(args) < 1: # pragma: no cover
return "{}"
value = args[0]
# For pybars, we need to return a SafeString to prevent HTML escaping
result = json.dumps(value) # pragma: no cover
# Safe string implementation to prevent HTML escaping
return pybars.strlist([result])
def _math_helper(this, *args):
"""Perform basic math operations."""
if len(args) < 3:
return pybars.strlist(["Math error: Insufficient arguments"])
lhs = args[0]
operator = args[1]
rhs = args[2]
try:
lhs = float(lhs)
rhs = float(rhs)
if operator == "+":
result = str(lhs + rhs)
elif operator == "-":
result = str(lhs - rhs)
elif operator == "*":
result = str(lhs * rhs)
elif operator == "/":
result = str(lhs / rhs)
else:
result = f"Unsupported operator: {operator}"
except (ValueError, TypeError) as e:
result = f"Math error: {e}"
return pybars.strlist([result])
def _lt_helper(this, *args):
"""Check if left hand side is less than right hand side."""
if len(args) < 2:
return False
lhs = args[0]
rhs = args[1]
try:
return float(lhs) < float(rhs)
except (ValueError, TypeError):
# Fall back to string comparison for non-numeric values
return str(lhs) < str(rhs)
def _if_cond_helper(this, options, condition):
"""Block helper for custom if conditionals."""
if condition:
return options["fn"](this)
elif "inverse" in options:
return options["inverse"](this)
return "" # pragma: no cover
def _dedent_helper(this, options):
"""Dedent a block of text to remove common leading whitespace.
Usage:
{{#dedent}}
This text will have its
common leading whitespace removed
while preserving relative indentation.
{{/dedent}}
"""
if "fn" not in options: # pragma: no cover
return ""
# Get the content from the block
content = options["fn"](this)
# Convert to string if it's a strlist
if (
isinstance(content, list)
or hasattr(content, "__iter__")
and not isinstance(content, (str, bytes))
):
content_str = "".join(str(item) for item in content) # pragma: no cover
else:
content_str = str(content) # pragma: no cover
# Add trailing and leading newlines to ensure proper dedenting
# This is critical for textwrap.dedent to work correctly with mixed content
content_str = "\n" + content_str + "\n"
# Use textwrap to dedent the content and remove the extra newlines we added
dedented = textwrap.dedent(content_str)[1:-1]
# Return as a SafeString to prevent HTML escaping
return pybars.strlist([dedented]) # pragma: no cover
class TemplateLoader:
"""Loader for Handlebars templates.
This class is responsible for loading templates from disk and rendering
them with the provided context data.
"""
def __init__(self, template_dir: Optional[str] = None):
"""Initialize the template loader.
Args:
template_dir: Optional custom template directory path
"""
self.template_dir = Path(template_dir) if template_dir else TEMPLATES_DIR
self.template_cache: Dict[str, Callable] = {}
self.compiler = pybars.Compiler()
# Set up standard helpers
self.helpers = {
"date": _date_helper,
"default": _default_helper,
"capitalize": _capitalize_helper,
"round": _round_helper,
"size": _size_helper,
"json": _json_helper,
"math": _math_helper,
"lt": _lt_helper,
"if_cond": _if_cond_helper,
"dedent": _dedent_helper,
}
logger.debug(f"Initialized template loader with directory: {self.template_dir}")
def get_template(self, template_path: str) -> Callable:
"""Get a template by path, using cache if available.
Args:
template_path: The path to the template, relative to the templates directory
Returns:
The compiled Handlebars template
Raises:
FileNotFoundError: If the template doesn't exist
"""
if template_path in self.template_cache:
return self.template_cache[template_path]
# Convert from Liquid-style path to Handlebars extension
if template_path.endswith(".liquid"):
template_path = template_path.replace(".liquid", ".hbs")
elif not template_path.endswith(".hbs"):
template_path = f"{template_path}.hbs"
full_path = self.template_dir / template_path
if not full_path.exists():
raise FileNotFoundError(f"Template not found: {full_path}")
with open(full_path, "r", encoding="utf-8") as f:
template_str = f.read()
template = self.compiler.compile(template_str)
self.template_cache[template_path] = template
logger.debug(f"Loaded template: {template_path}")
return template
async def render(self, template_path: str, context: Dict[str, Any]) -> str:
"""Render a template with the given context.
Args:
template_path: The path to the template, relative to the templates directory
context: The context data to pass to the template
Returns:
The rendered template as a string
"""
template = self.get_template(template_path)
return template(context, helpers=self.helpers)
def clear_cache(self) -> None:
"""Clear the template cache."""
self.template_cache.clear()
logger.debug("Template cache cleared")
# Global template loader instance
template_loader = TemplateLoader()
+71 -1
View File
@@ -1,3 +1,73 @@
from typing import Optional
import typer
app = typer.Typer()
from basic_memory.config import get_project_config, ConfigManager
from basic_memory.mcp.project_session import session
def version_callback(value: bool) -> None:
"""Show version and exit."""
if value: # pragma: no cover
import basic_memory
config = get_project_config()
typer.echo(f"Basic Memory version: {basic_memory.__version__}")
typer.echo(f"Current project: {config.project}")
typer.echo(f"Project path: {config.home}")
raise typer.Exit()
app = typer.Typer(name="basic-memory")
@app.callback()
def app_callback(
ctx: typer.Context,
project: Optional[str] = typer.Option(
None,
"--project",
"-p",
help="Specify which project to use 1",
envvar="BASIC_MEMORY_PROJECT",
),
version: Optional[bool] = typer.Option(
None,
"--version",
"-v",
help="Show version and exit.",
callback=version_callback,
is_eager=True,
),
) -> None:
"""Basic Memory - Local-first personal knowledge management."""
# Run initialization for every command unless --version was specified
if not version and ctx.invoked_subcommand is not None:
from basic_memory.services.initialization import ensure_initialization
app_config = ConfigManager().config
ensure_initialization(app_config)
# Initialize MCP session with the specified project or default
if project: # pragma: no cover
# Use the project specified via --project flag
current_project_config = get_project_config(project)
session.set_current_project(current_project_config.name)
# Update the global config to use this project
from basic_memory.config import update_current_project
update_current_project(project)
else:
# Use the default project
current_project = app_config.default_project
session.set_current_project(current_project)
# Register sub-command groups
import_app = typer.Typer(help="Import data from various sources")
app.add_typer(import_app, name="import")
claude_app = typer.Typer()
import_app.add_typer(claude_app, name="claude")
+14 -2
View File
@@ -1,5 +1,17 @@
"""CLI commands for basic-memory."""
from . import status, sync, db, import_memory_json, mcp
from . import status, sync, db, import_memory_json, mcp, import_claude_conversations
from . import import_claude_projects, import_chatgpt, tool, project
__all__ = ["status", "sync", "db", "import_memory_json", "mcp"]
__all__ = [
"status",
"sync",
"db",
"import_memory_json",
"mcp",
"import_claude_conversations",
"import_claude_projects",
"import_chatgpt",
"tool",
"project",
]
+24 -5
View File
@@ -1,25 +1,44 @@
"""Database management commands."""
import asyncio
import typer
from loguru import logger
from basic_memory.alembic import migrations
from basic_memory import db
from basic_memory.cli.app import app
from basic_memory.config import ConfigManager, BasicMemoryConfig, save_basic_memory_config
@app.command()
def reset(
reindex: bool = typer.Option(False, "--reindex", help="Rebuild indices from filesystem"),
reindex: bool = typer.Option(False, "--reindex", help="Rebuild db index from filesystem"),
): # pragma: no cover
"""Reset database (drop all tables and recreate)."""
if typer.confirm("This will delete all data. Are you sure?"):
if typer.confirm("This will delete all data in your db. Are you sure?"):
logger.info("Resetting database...")
asyncio.run(migrations.reset_database())
config_manager = ConfigManager()
app_config = config_manager.config
# Get database path
db_path = app_config.app_database_path
# Delete the database file if it exists
if db_path.exists():
db_path.unlink()
logger.info(f"Database file deleted: {db_path}")
# Reset project configuration
config = BasicMemoryConfig()
save_basic_memory_config(config_manager.config_file, config)
logger.info("Project configuration reset to default")
# Create a new empty database
asyncio.run(db.run_migrations(app_config))
logger.info("Database reset complete")
if reindex:
# Import and run sync
from basic_memory.cli.commands.sync import sync
logger.info("Rebuilding search index from filesystem...")
asyncio.run(sync()) # pyright: ignore
sync(watch=False) # pyright: ignore
@@ -0,0 +1,83 @@
"""Import command for ChatGPT conversations."""
import asyncio
import json
from pathlib import Path
from typing import Annotated
import typer
from basic_memory.cli.app import import_app
from basic_memory.config import get_project_config
from basic_memory.importers import ChatGPTImporter
from basic_memory.markdown import EntityParser, MarkdownProcessor
from loguru import logger
from rich.console import Console
from rich.panel import Panel
console = Console()
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@import_app.command(name="chatgpt", help="Import conversations from ChatGPT JSON export.")
def import_chatgpt(
conversations_json: Annotated[
Path, typer.Argument(help="Path to ChatGPT conversations.json file")
] = Path("conversations.json"),
folder: Annotated[
str, typer.Option(help="The folder to place the files in.")
] = "conversations",
):
"""Import chat conversations from ChatGPT JSON format.
This command will:
1. Read the complex tree structure of messages
2. Convert them to linear markdown conversations
3. Save as clean, readable markdown files
After importing, run 'basic-memory sync' to index the new files.
"""
try:
if not conversations_json.exists(): # pragma: no cover
typer.echo(f"Error: File not found: {conversations_json}", err=True)
raise typer.Exit(1)
# Get markdown processor
markdown_processor = asyncio.run(get_markdown_processor())
config = get_project_config()
# Process the file
base_path = config.home / folder
console.print(f"\nImporting chats from {conversations_json}...writing to {base_path}")
# Create importer and run import
importer = ChatGPTImporter(config.home, markdown_processor)
with conversations_json.open("r", encoding="utf-8") as file:
json_data = json.load(file)
result = asyncio.run(importer.import_data(json_data, folder))
if not result.success: # pragma: no cover
typer.echo(f"Error during import: {result.error_message}", err=True)
raise typer.Exit(1)
# Show results
console.print(
Panel(
f"[green]Import complete![/green]\n\n"
f"Imported {result.conversations} conversations\n"
f"Containing {result.messages} messages",
expand=False,
)
)
console.print("\nRun 'basic-memory sync' to index the new files.")
except Exception as e:
logger.error("Import failed")
typer.echo(f"Error during import: {e}", err=True)
raise typer.Exit(1)
@@ -0,0 +1,86 @@
"""Import command for basic-memory CLI to import chat data from conversations2.json format."""
import asyncio
import json
from pathlib import Path
from typing import Annotated
import typer
from basic_memory.cli.app import claude_app
from basic_memory.config import get_project_config
from basic_memory.importers.claude_conversations_importer import ClaudeConversationsImporter
from basic_memory.markdown import EntityParser, MarkdownProcessor
from loguru import logger
from rich.console import Console
from rich.panel import Panel
console = Console()
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@claude_app.command(name="conversations", help="Import chat conversations from Claude.ai.")
def import_claude(
conversations_json: Annotated[
Path, typer.Argument(..., help="Path to conversations.json file")
] = Path("conversations.json"),
folder: Annotated[
str, typer.Option(help="The folder to place the files in.")
] = "conversations",
):
"""Import chat conversations from conversations2.json format.
This command will:
1. Read chat data and nested messages
2. Create markdown files for each conversation
3. Format content in clean, readable markdown
After importing, run 'basic-memory sync' to index the new files.
"""
config = get_project_config()
try:
if not conversations_json.exists():
typer.echo(f"Error: File not found: {conversations_json}", err=True)
raise typer.Exit(1)
# Get markdown processor
markdown_processor = asyncio.run(get_markdown_processor())
# Create the importer
importer = ClaudeConversationsImporter(config.home, markdown_processor)
# Process the file
base_path = config.home / folder
console.print(f"\nImporting chats from {conversations_json}...writing to {base_path}")
# Run the import
with conversations_json.open("r", encoding="utf-8") as file:
json_data = json.load(file)
result = asyncio.run(importer.import_data(json_data, folder))
if not result.success: # pragma: no cover
typer.echo(f"Error during import: {result.error_message}", err=True)
raise typer.Exit(1)
# Show results
console.print(
Panel(
f"[green]Import complete![/green]\n\n"
f"Imported {result.conversations} conversations\n"
f"Containing {result.messages} messages",
expand=False,
)
)
console.print("\nRun 'basic-memory sync' to index the new files.")
except Exception as e:
logger.error("Import failed")
typer.echo(f"Error during import: {e}", err=True)
raise typer.Exit(1)
@@ -0,0 +1,85 @@
"""Import command for basic-memory CLI to import project data from Claude.ai."""
import asyncio
import json
from pathlib import Path
from typing import Annotated
import typer
from basic_memory.cli.app import claude_app
from basic_memory.config import get_project_config
from basic_memory.importers.claude_projects_importer import ClaudeProjectsImporter
from basic_memory.markdown import EntityParser, MarkdownProcessor
from loguru import logger
from rich.console import Console
from rich.panel import Panel
console = Console()
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@claude_app.command(name="projects", help="Import projects from Claude.ai.")
def import_projects(
projects_json: Annotated[Path, typer.Argument(..., help="Path to projects.json file")] = Path(
"projects.json"
),
base_folder: Annotated[
str, typer.Option(help="The base folder to place project files in.")
] = "projects",
):
"""Import project data from Claude.ai.
This command will:
1. Create a directory for each project
2. Store docs in a docs/ subdirectory
3. Place prompt template in project root
After importing, run 'basic-memory sync' to index the new files.
"""
config = get_project_config()
try:
if not projects_json.exists():
typer.echo(f"Error: File not found: {projects_json}", err=True)
raise typer.Exit(1)
# Get markdown processor
markdown_processor = asyncio.run(get_markdown_processor())
# Create the importer
importer = ClaudeProjectsImporter(config.home, markdown_processor)
# Process the file
base_path = config.home / base_folder if base_folder else config.home
console.print(f"\nImporting projects from {projects_json}...writing to {base_path}")
# Run the import
with projects_json.open("r", encoding="utf-8") as file:
json_data = json.load(file)
result = asyncio.run(importer.import_data(json_data, base_folder))
if not result.success: # pragma: no cover
typer.echo(f"Error during import: {result.error_message}", err=True)
raise typer.Exit(1)
# Show results
console.print(
Panel(
f"[green]Import complete![/green]\n\n"
f"Imported {result.documents} project documents\n"
f"Imported {result.prompts} prompt templates",
expand=False,
)
)
console.print("\nRun 'basic-memory sync' to index the new files.")
except Exception as e:
logger.error("Import failed")
typer.echo(f"Error during import: {e}", err=True)
raise typer.Exit(1)
@@ -3,104 +3,35 @@
import asyncio
import json
from pathlib import Path
from typing import Dict, Any, List
from typing import Annotated
import typer
from basic_memory.cli.app import import_app
from basic_memory.config import get_project_config
from basic_memory.importers.memory_json_importer import MemoryJsonImporter
from basic_memory.markdown import EntityParser, MarkdownProcessor
from loguru import logger
from rich.console import Console
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
from basic_memory.cli.app import app
from basic_memory.config import config
from basic_memory.markdown import EntityParser, MarkdownProcessor
from basic_memory.markdown.schemas import EntityMarkdown, EntityFrontmatter, Observation, Relation
console = Console()
async def process_memory_json(
json_path: Path, base_path: Path, markdown_processor: MarkdownProcessor
):
"""Import entities from memory.json using markdown processor."""
# First pass - collect all relations by source entity
entity_relations: Dict[str, List[Relation]] = {}
entities: Dict[str, Dict[str, Any]] = {}
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
console=console,
) as progress:
read_task = progress.add_task("Reading memory.json...", total=None)
# First pass - collect entities and relations
with open(json_path) as f:
lines = f.readlines()
progress.update(read_task, total=len(lines))
for line in lines:
data = json.loads(line)
if data["type"] == "entity":
entities[data["name"]] = data
elif data["type"] == "relation":
# Store relation with its source entity
source = data.get("from") or data.get("from_id")
if source not in entity_relations:
entity_relations[source] = []
entity_relations[source].append(
Relation(
type=data.get("relationType") or data.get("relation_type"),
target=data.get("to") or data.get("to_id"),
)
)
progress.update(read_task, advance=1)
# Second pass - create and write entities
write_task = progress.add_task("Creating entities...", total=len(entities))
entities_created = 0
for name, entity_data in entities.items():
entity = EntityMarkdown(
frontmatter=EntityFrontmatter(
metadata={
"type": entity_data["entityType"],
"title": name,
"permalink": f"{entity_data['entityType']}/{name}",
}
),
content=f"# {name}\n",
observations=[Observation(content=obs) for obs in entity_data["observations"]],
relations=entity_relations.get(
name, []
), # Add any relations where this entity is the source
)
# Let markdown processor handle writing
file_path = base_path / f"{entity_data['entityType']}/{name}.md"
await markdown_processor.write_file(file_path, entity)
entities_created += 1
progress.update(write_task, advance=1)
return {
"entities": entities_created,
"relations": sum(len(rels) for rels in entity_relations.values()),
}
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@app.command()
def import_json(
json_path: Path = typer.Argument(..., help="Path to memory.json file to import"),
@import_app.command()
def memory_json(
json_path: Annotated[Path, typer.Argument(..., help="Path to memory.json file")] = Path(
"memory.json"
),
destination_folder: Annotated[
str, typer.Option(help="Optional destination folder within the project")
] = "",
):
"""Import entities and relations from a memory.json file.
@@ -116,21 +47,37 @@ def import_json(
typer.echo(f"Error: File not found: {json_path}", err=True)
raise typer.Exit(1)
config = get_project_config()
try:
# Get markdown processor
markdown_processor = asyncio.run(get_markdown_processor())
# Create the importer
importer = MemoryJsonImporter(config.home, markdown_processor)
# Process the file
base_path = config.home
base_path = config.home if not destination_folder else config.home / destination_folder
console.print(f"\nImporting from {json_path}...writing to {base_path}")
results = asyncio.run(process_memory_json(json_path, base_path, markdown_processor))
# Run the import for json log format
file_data = []
with json_path.open("r", encoding="utf-8") as file:
for line in file:
json_data = json.loads(line)
file_data.append(json_data)
result = asyncio.run(importer.import_data(file_data, destination_folder))
if not result.success: # pragma: no cover
typer.echo(f"Error during import: {result.error_message}", err=True)
raise typer.Exit(1)
# Show results
console.print(
Panel(
f"[green]Import complete![/green]\n\n"
f"Created {results['entities']} entities\n"
f"Added {results['relations']} relations",
f"Created {result.entities} entities\n"
f"Added {result.relations} relations\n"
f"Skipped {result.skipped_entities} entities\n",
expand=False,
)
)
@@ -138,6 +85,6 @@ def import_json(
console.print("\nRun 'basic-memory sync' to index the new files.")
except Exception as e:
logger.exception("Import failed")
logger.error("Import failed")
typer.echo(f"Error during import: {e}", err=True)
raise typer.Exit(1)
+66 -9
View File
@@ -1,8 +1,10 @@
"""MCP server command."""
"""MCP server command with streamable HTTP transport."""
import asyncio
import typer
from loguru import logger
from basic_memory.cli.app import app
from basic_memory.config import config
from basic_memory.config import ConfigManager
# Import mcp instance
from basic_memory.mcp.server import mcp as mcp_server # pragma: no cover
@@ -10,11 +12,66 @@ from basic_memory.mcp.server import mcp as mcp_server # pragma: no cover
# Import mcp tools to register them
import basic_memory.mcp.tools # noqa: F401 # pragma: no cover
# Import prompts to register them
import basic_memory.mcp.prompts # noqa: F401 # pragma: no cover
from loguru import logger
@app.command()
def mcp():
"""Run the MCP server for Claude Desktop integration."""
home_dir = config.home
logger.info("Starting Basic Memory MCP server")
logger.info(f"Home directory: {home_dir}")
mcp_server.run()
def mcp(
transport: str = typer.Option("stdio", help="Transport type: stdio, streamable-http, or sse"),
host: str = typer.Option(
"0.0.0.0", help="Host for HTTP transports (use 0.0.0.0 to allow external connections)"
),
port: int = typer.Option(8000, help="Port for HTTP transports"),
path: str = typer.Option("/mcp", help="Path prefix for streamable-http transport"),
): # pragma: no cover
"""Run the MCP server with configurable transport options.
This command starts an MCP server using one of three transport options:
- stdio: Standard I/O (good for local usage)
- streamable-http: Recommended for web deployments (default)
- sse: Server-Sent Events (for compatibility with existing clients)
"""
from basic_memory.services.initialization import initialize_file_sync
# Use unified thread-based sync approach for both transports
import threading
app_config = ConfigManager().config
def run_file_sync():
"""Run file sync in a separate thread with its own event loop."""
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(initialize_file_sync(app_config))
except Exception as e:
logger.error(f"File sync error: {e}", err=True)
finally:
loop.close()
logger.info(f"Sync changes enabled: {app_config.sync_changes}")
if app_config.sync_changes:
# Start the sync thread
sync_thread = threading.Thread(target=run_file_sync, daemon=True)
sync_thread.start()
logger.info("Started file sync in background")
# Now run the MCP server (blocks)
logger.info(f"Starting MCP server with {transport.upper()} transport")
if transport == "stdio":
mcp_server.run(
transport=transport,
)
elif transport == "streamable-http" or transport == "sse":
mcp_server.run(
transport=transport,
host=host,
port=port,
path=path,
log_level="INFO",
)
+338
View File
@@ -0,0 +1,338 @@
"""Command module for basic-memory project management."""
import asyncio
import os
from pathlib import Path
import typer
from rich.console import Console
from rich.table import Table
from basic_memory.cli.app import app
from basic_memory.mcp.project_session import session
from basic_memory.mcp.resources.project_info import project_info
import json
from datetime import datetime
from rich.panel import Panel
from rich.tree import Tree
from basic_memory.mcp.async_client import client
from basic_memory.mcp.tools.utils import call_get
from basic_memory.schemas.project_info import ProjectList
from basic_memory.mcp.tools.utils import call_post
from basic_memory.schemas.project_info import ProjectStatusResponse
from basic_memory.mcp.tools.utils import call_delete
from basic_memory.mcp.tools.utils import call_put
from basic_memory.utils import generate_permalink
from basic_memory.mcp.tools.utils import call_patch
console = Console()
# Create a project subcommand
project_app = typer.Typer(help="Manage multiple Basic Memory projects")
app.add_typer(project_app, name="project")
def format_path(path: str) -> str:
"""Format a path for display, using ~ for home directory."""
home = str(Path.home())
if path.startswith(home):
return path.replace(home, "~", 1) # pragma: no cover
return path
@project_app.command("list")
def list_projects() -> None:
"""List all configured projects."""
# Use API to list projects
try:
response = asyncio.run(call_get(client, "/projects/projects"))
result = ProjectList.model_validate(response.json())
table = Table(title="Basic Memory Projects")
table.add_column("Name", style="cyan")
table.add_column("Path", style="green")
table.add_column("Default", style="yellow")
table.add_column("Active", style="magenta")
for project in result.projects:
is_default = "" if project.is_default else ""
is_active = "" if session.get_current_project() == project.name else ""
table.add_row(project.name, format_path(project.path), is_default, is_active)
console.print(table)
except Exception as e:
console.print(f"[red]Error listing projects: {str(e)}[/red]")
raise typer.Exit(1)
@project_app.command("add")
def add_project(
name: str = typer.Argument(..., help="Name of the project"),
path: str = typer.Argument(..., help="Path to the project directory"),
set_default: bool = typer.Option(False, "--default", help="Set as default project"),
) -> None:
"""Add a new project."""
# Resolve to absolute path
resolved_path = Path(os.path.abspath(os.path.expanduser(path))).as_posix()
try:
data = {"name": name, "path": resolved_path, "set_default": set_default}
response = asyncio.run(call_post(client, "/projects/projects", json=data))
result = ProjectStatusResponse.model_validate(response.json())
console.print(f"[green]{result.message}[/green]")
except Exception as e:
console.print(f"[red]Error adding project: {str(e)}[/red]")
raise typer.Exit(1)
# Display usage hint
console.print("\nTo use this project:")
console.print(f" basic-memory --project={name} <command>")
console.print(" # or")
console.print(f" basic-memory project default {name}")
@project_app.command("remove")
def remove_project(
name: str = typer.Argument(..., help="Name of the project to remove"),
) -> None:
"""Remove a project from configuration."""
try:
project_permalink = generate_permalink(name)
response = asyncio.run(call_delete(client, f"/projects/{project_permalink}"))
result = ProjectStatusResponse.model_validate(response.json())
console.print(f"[green]{result.message}[/green]")
except Exception as e:
console.print(f"[red]Error removing project: {str(e)}[/red]")
raise typer.Exit(1)
# Show this message regardless of method used
console.print("[yellow]Note: The project files have not been deleted from disk.[/yellow]")
@project_app.command("default")
def set_default_project(
name: str = typer.Argument(..., help="Name of the project to set as default"),
) -> None:
"""Set the default project and activate it for the current session."""
try:
project_permalink = generate_permalink(name)
response = asyncio.run(call_put(client, f"/projects/{project_permalink}/default"))
result = ProjectStatusResponse.model_validate(response.json())
console.print(f"[green]{result.message}[/green]")
except Exception as e:
console.print(f"[red]Error setting default project: {str(e)}[/red]")
raise typer.Exit(1)
# The API call above should have updated both config and MCP session
# No need for manual reload - the project service handles this automatically
console.print("[green]Project activated for current session[/green]")
@project_app.command("sync-config")
def synchronize_projects() -> None:
"""Synchronize project config between configuration file and database."""
# Call the API to synchronize projects
try:
response = asyncio.run(call_post(client, "/projects/sync"))
result = ProjectStatusResponse.model_validate(response.json())
console.print(f"[green]{result.message}[/green]")
except Exception as e: # pragma: no cover
console.print(f"[red]Error synchronizing projects: {str(e)}[/red]")
raise typer.Exit(1)
@project_app.command("move")
def move_project(
name: str = typer.Argument(..., help="Name of the project to move"),
new_path: str = typer.Argument(..., help="New absolute path for the project"),
) -> None:
"""Move a project to a new location."""
# Resolve to absolute path
resolved_path = Path(os.path.abspath(os.path.expanduser(new_path))).as_posix()
try:
data = {"path": resolved_path}
project_permalink = generate_permalink(name)
current_project = session.get_current_project()
response = asyncio.run(
call_patch(client, f"/{current_project}/project/{project_permalink}", json=data)
)
result = ProjectStatusResponse.model_validate(response.json())
console.print(f"[green]{result.message}[/green]")
# Show important file movement reminder
console.print() # Empty line for spacing
console.print(
Panel(
"[bold red]IMPORTANT:[/bold red] Project configuration updated successfully.\n\n"
"[yellow]You must manually move your project files from the old location to:[/yellow]\n"
f"[cyan]{resolved_path}[/cyan]\n\n"
"[dim]Basic Memory has only updated the configuration - your files remain in their original location.[/dim]",
title="⚠️ Manual File Movement Required",
border_style="yellow",
expand=False,
)
)
except Exception as e:
console.print(f"[red]Error moving project: {str(e)}[/red]")
raise typer.Exit(1)
@project_app.command("info")
def display_project_info(
json_output: bool = typer.Option(False, "--json", help="Output in JSON format"),
):
"""Display detailed information and statistics about the current project."""
try:
# Get project info
info = asyncio.run(project_info.fn()) # type: ignore # pyright: ignore [reportAttributeAccessIssue]
if json_output:
# Convert to JSON and print
print(json.dumps(info.model_dump(), indent=2, default=str))
else:
# Create rich display
console = Console()
# Project configuration section
console.print(
Panel(
f"[bold]Project:[/bold] {info.project_name}\n"
f"[bold]Path:[/bold] {info.project_path}\n"
f"[bold]Default Project:[/bold] {info.default_project}\n",
title="📊 Basic Memory Project Info",
expand=False,
)
)
# Statistics section
stats_table = Table(title="📈 Statistics")
stats_table.add_column("Metric", style="cyan")
stats_table.add_column("Count", style="green")
stats_table.add_row("Entities", str(info.statistics.total_entities))
stats_table.add_row("Observations", str(info.statistics.total_observations))
stats_table.add_row("Relations", str(info.statistics.total_relations))
stats_table.add_row(
"Unresolved Relations", str(info.statistics.total_unresolved_relations)
)
stats_table.add_row("Isolated Entities", str(info.statistics.isolated_entities))
console.print(stats_table)
# Entity types
if info.statistics.entity_types:
entity_types_table = Table(title="📑 Entity Types")
entity_types_table.add_column("Type", style="blue")
entity_types_table.add_column("Count", style="green")
for entity_type, count in info.statistics.entity_types.items():
entity_types_table.add_row(entity_type, str(count))
console.print(entity_types_table)
# Most connected entities
if info.statistics.most_connected_entities: # pragma: no cover
connected_table = Table(title="🔗 Most Connected Entities")
connected_table.add_column("Title", style="blue")
connected_table.add_column("Permalink", style="cyan")
connected_table.add_column("Relations", style="green")
for entity in info.statistics.most_connected_entities:
connected_table.add_row(
entity["title"], entity["permalink"], str(entity["relation_count"])
)
console.print(connected_table)
# Recent activity
if info.activity.recently_updated: # pragma: no cover
recent_table = Table(title="🕒 Recent Activity")
recent_table.add_column("Title", style="blue")
recent_table.add_column("Type", style="cyan")
recent_table.add_column("Last Updated", style="green")
for entity in info.activity.recently_updated[:5]: # Show top 5
updated_at = (
datetime.fromisoformat(entity["updated_at"])
if isinstance(entity["updated_at"], str)
else entity["updated_at"]
)
recent_table.add_row(
entity["title"],
entity["entity_type"],
updated_at.strftime("%Y-%m-%d %H:%M"),
)
console.print(recent_table)
# System status
system_tree = Tree("🖥️ System Status")
system_tree.add(f"Basic Memory version: [bold green]{info.system.version}[/bold green]")
system_tree.add(
f"Database: [cyan]{info.system.database_path}[/cyan] ([green]{info.system.database_size}[/green])"
)
# Watch status
if info.system.watch_status: # pragma: no cover
watch_branch = system_tree.add("Watch Service")
running = info.system.watch_status.get("running", False)
status_color = "green" if running else "red"
watch_branch.add(
f"Status: [bold {status_color}]{'Running' if running else 'Stopped'}[/bold {status_color}]"
)
if running:
start_time = (
datetime.fromisoformat(info.system.watch_status.get("start_time", ""))
if isinstance(info.system.watch_status.get("start_time"), str)
else info.system.watch_status.get("start_time")
)
watch_branch.add(
f"Running since: [cyan]{start_time.strftime('%Y-%m-%d %H:%M')}[/cyan]"
)
watch_branch.add(
f"Files synced: [green]{info.system.watch_status.get('synced_files', 0)}[/green]"
)
watch_branch.add(
f"Errors: [{'red' if info.system.watch_status.get('error_count', 0) > 0 else 'green'}]{info.system.watch_status.get('error_count', 0)}[/{'red' if info.system.watch_status.get('error_count', 0) > 0 else 'green'}]"
)
else:
system_tree.add("[yellow]Watch service not running[/yellow]")
console.print(system_tree)
# Available projects
projects_table = Table(title="📁 Available Projects")
projects_table.add_column("Name", style="blue")
projects_table.add_column("Path", style="cyan")
projects_table.add_column("Default", style="green")
for name, proj_info in info.available_projects.items():
is_default = name == info.default_project
project_path = proj_info["path"]
projects_table.add_row(name, project_path, "" if is_default else "")
console.print(projects_table)
# Timestamp
current_time = (
datetime.fromisoformat(str(info.system.timestamp))
if isinstance(info.system.timestamp, str)
else info.system.timestamp
)
console.print(f"\nTimestamp: [cyan]{current_time.strftime('%Y-%m-%d %H:%M:%S')}[/cyan]")
except Exception as e: # pragma: no cover
typer.echo(f"Error getting project info: {e}", err=True)
raise typer.Exit(1)
+26 -27
View File
@@ -11,29 +11,15 @@ from rich.tree import Tree
from basic_memory import db
from basic_memory.cli.app import app
from basic_memory.config import config
from basic_memory.db import DatabaseType
from basic_memory.repository import EntityRepository
from basic_memory.sync import FileChangeScanner
from basic_memory.sync.utils import SyncReport
from basic_memory.cli.commands.sync import get_sync_service
from basic_memory.config import ConfigManager, get_project_config
from basic_memory.repository import ProjectRepository
from basic_memory.sync.sync_service import SyncReport
# Create rich console
console = Console()
async def get_file_change_scanner(
db_type=DatabaseType.FILESYSTEM,
) -> FileChangeScanner: # pragma: no cover
"""Get sync service instance."""
async with db.engine_session_factory(db_path=config.database_path, db_type=db_type) as (
engine,
session_maker,
):
entity_repository = EntityRepository(session_maker)
file_change_scanner = FileChangeScanner(entity_repository)
return file_change_scanner
def add_files_to_tree(
tree: Tree, paths: Set[str], style: str, checksums: Dict[str, str] | None = None
):
@@ -101,11 +87,11 @@ def build_directory_summary(counts: Dict[str, int]) -> str:
return " ".join(parts)
def display_changes(title: str, changes: SyncReport, verbose: bool = False):
def display_changes(project_name: str, title: str, changes: SyncReport, verbose: bool = False):
"""Display changes using Rich for better visualization."""
tree = Tree(title)
tree = Tree(f"{project_name}: {title}")
if changes.total_changes == 0:
if changes.total == 0:
tree.add("No changes")
console.print(Panel(tree, expand=False))
return
@@ -136,11 +122,24 @@ def display_changes(title: str, changes: SyncReport, verbose: bool = False):
console.print(Panel(tree, expand=False))
async def run_status(sync_service: FileChangeScanner, verbose: bool = False):
async def run_status(verbose: bool = False): # pragma: no cover
"""Check sync status of files vs database."""
# Check knowledge/ directory
knowledge_changes = await sync_service.find_knowledge_changes(config.home)
display_changes("Knowledge Files", knowledge_changes, verbose)
app_config = ConfigManager().config
config = get_project_config()
_, session_maker = await db.get_or_create_db(
db_path=app_config.database_path, db_type=db.DatabaseType.FILESYSTEM
)
project_repository = ProjectRepository(session_maker)
project = await project_repository.get_by_name(config.project)
if not project: # pragma: no cover
raise Exception(f"Project '{config.project}' not found")
sync_service = await get_sync_service(project)
knowledge_changes = await sync_service.scan(config.home)
display_changes(project.name, "Status", knowledge_changes, verbose)
@app.command()
@@ -149,8 +148,8 @@ def status(
):
"""Show sync status between files and database."""
try:
sync_service = asyncio.run(get_file_change_scanner())
asyncio.run(run_status(sync_service, verbose)) # pragma: no cover
asyncio.run(run_status(verbose)) # pragma: no cover
except Exception as e:
logger.exception(f"Error checking status: {e}")
logger.error(f"Error checking status: {e}")
typer.echo(f"Error checking status: {e}", err=True)
raise typer.Exit(code=1) # pragma: no cover
+114 -75
View File
@@ -13,22 +13,22 @@ from rich.tree import Tree
from basic_memory import db
from basic_memory.cli.app import app
from basic_memory.config import config
from basic_memory.db import DatabaseType
from basic_memory.config import ConfigManager, get_project_config
from basic_memory.markdown import EntityParser
from basic_memory.markdown.markdown_processor import MarkdownProcessor
from basic_memory.models import Project
from basic_memory.repository import (
EntityRepository,
ObservationRepository,
RelationRepository,
ProjectRepository,
)
from basic_memory.repository.search_repository import SearchRepository
from basic_memory.services import EntityService, FileService
from basic_memory.services.link_resolver import LinkResolver
from basic_memory.services.search_service import SearchService
from basic_memory.sync import SyncService, FileChangeScanner
from basic_memory.sync.utils import SyncReport
from basic_memory.sync.watch_service import WatchService
from basic_memory.sync import SyncService
from basic_memory.sync.sync_service import SyncReport
console = Console()
@@ -39,50 +39,51 @@ class ValidationIssue:
error: str
async def get_sync_service(db_type=DatabaseType.FILESYSTEM): # pragma: no cover
async def get_sync_service(project: Project) -> SyncService: # pragma: no cover
"""Get sync service instance with all dependencies."""
async with db.engine_session_factory(db_path=config.database_path, db_type=db_type) as (
engine,
session_maker,
):
entity_parser = EntityParser(config.home)
markdown_processor = MarkdownProcessor(entity_parser)
file_service = FileService(config.home, markdown_processor)
# Initialize repositories
entity_repository = EntityRepository(session_maker)
observation_repository = ObservationRepository(session_maker)
relation_repository = RelationRepository(session_maker)
search_repository = SearchRepository(session_maker)
app_config = ConfigManager().config
_, session_maker = await db.get_or_create_db(
db_path=app_config.database_path, db_type=db.DatabaseType.FILESYSTEM
)
# Initialize services
search_service = SearchService(search_repository, entity_repository, file_service)
link_resolver = LinkResolver(entity_repository, search_service)
project_path = Path(project.path)
entity_parser = EntityParser(project_path)
markdown_processor = MarkdownProcessor(entity_parser)
file_service = FileService(project_path, markdown_processor)
# Initialize scanner
file_change_scanner = FileChangeScanner(entity_repository)
# Initialize repositories
entity_repository = EntityRepository(session_maker, project_id=project.id)
observation_repository = ObservationRepository(session_maker, project_id=project.id)
relation_repository = RelationRepository(session_maker, project_id=project.id)
search_repository = SearchRepository(session_maker, project_id=project.id)
# Initialize services
entity_service = EntityService(
entity_parser,
entity_repository,
observation_repository,
relation_repository,
file_service,
link_resolver,
)
# Initialize services
search_service = SearchService(search_repository, entity_repository, file_service)
link_resolver = LinkResolver(entity_repository, search_service)
# Create sync service
sync_service = SyncService(
scanner=file_change_scanner,
entity_service=entity_service,
entity_parser=entity_parser,
entity_repository=entity_repository,
relation_repository=relation_repository,
search_service=search_service,
)
# Initialize services
entity_service = EntityService(
entity_parser,
entity_repository,
observation_repository,
relation_repository,
file_service,
link_resolver,
)
return sync_service
# Create sync service
sync_service = SyncService(
app_config=app_config,
entity_service=entity_service,
entity_parser=entity_parser,
entity_repository=entity_repository,
relation_repository=relation_repository,
search_service=search_service,
file_service=file_service,
)
return sync_service
def group_issues_by_directory(issues: List[ValidationIssue]) -> Dict[str, List[ValidationIssue]]:
@@ -96,9 +97,12 @@ def group_issues_by_directory(issues: List[ValidationIssue]) -> Dict[str, List[V
def display_sync_summary(knowledge: SyncReport):
"""Display a one-line summary of sync changes."""
total_changes = knowledge.total_changes
config = get_project_config()
total_changes = knowledge.total
project_name = config.project
if total_changes == 0:
console.print("[green]Everything up to date[/green]")
console.print(f"[green]Project '{project_name}': Everything up to date[/green]")
return
# Format as: "Synced X files (A new, B modified, C moved, D deleted)"
@@ -117,18 +121,21 @@ def display_sync_summary(knowledge: SyncReport):
if del_count:
changes.append(f"[red]{del_count} deleted[/red]")
console.print(f"Synced {total_changes} files ({', '.join(changes)})")
console.print(f"Project '{project_name}': Synced {total_changes} files ({', '.join(changes)})")
def display_detailed_sync_results(knowledge: SyncReport):
"""Display detailed sync results with trees."""
if knowledge.total_changes == 0:
console.print("\n[green]Everything up to date[/green]")
config = get_project_config()
project_name = config.project
if knowledge.total == 0:
console.print(f"\n[green]Project '{project_name}': Everything up to date[/green]")
return
console.print("\n[bold]Sync Results[/bold]")
console.print(f"\n[bold]Sync Results for Project '{project_name}'[/bold]")
if knowledge.total_changes > 0:
if knowledge.total > 0:
knowledge_tree = Tree("[bold]Knowledge Files[/bold]")
if knowledge.new:
created = knowledge_tree.add("[green]Created[/green]")
@@ -152,27 +159,53 @@ def display_detailed_sync_results(knowledge: SyncReport):
console.print(knowledge_tree)
async def run_sync(verbose: bool = False, watch: bool = False):
async def run_sync(verbose: bool = False):
"""Run sync operation."""
sync_service = await get_sync_service()
app_config = ConfigManager().config
config = get_project_config()
# Start watching if requested
if watch:
watch_service = WatchService(
sync_service=sync_service,
file_service=sync_service.entity_service.file_service,
config=config,
)
await watch_service.handle_changes(config.home)
await watch_service.run() # pragma: no cover
_, session_maker = await db.get_or_create_db(
db_path=app_config.database_path, db_type=db.DatabaseType.FILESYSTEM
)
project_repository = ProjectRepository(session_maker)
project = await project_repository.get_by_name(config.project)
if not project: # pragma: no cover
raise Exception(f"Project '{config.project}' not found")
import time
start_time = time.time()
logger.info(
"Sync command started",
project=config.project,
verbose=verbose,
directory=str(config.home),
)
sync_service = await get_sync_service(project)
logger.info("Running one-time sync")
knowledge_changes = await sync_service.sync(config.home, project_name=project.name)
# Log results
duration_ms = int((time.time() - start_time) * 1000)
logger.info(
"Sync command completed",
project=config.project,
total_changes=knowledge_changes.total,
new_files=len(knowledge_changes.new),
modified_files=len(knowledge_changes.modified),
deleted_files=len(knowledge_changes.deleted),
moved_files=len(knowledge_changes.moves),
duration_ms=duration_ms,
)
# Display results
if verbose:
display_detailed_sync_results(knowledge_changes)
else:
# one time sync
knowledge_changes = await sync_service.sync(config.home)
# Display results
if verbose:
display_detailed_sync_results(knowledge_changes)
else:
display_sync_summary(knowledge_changes) # pragma: no cover
display_sync_summary(knowledge_changes) # pragma: no cover
@app.command()
@@ -183,21 +216,27 @@ def sync(
"-v",
help="Show detailed sync information.",
),
watch: bool = typer.Option(
False,
"--watch",
"-w",
help="Start watching for changes after sync.",
),
) -> None:
"""Sync knowledge files with the database."""
config = get_project_config()
try:
# Show which project we're syncing
typer.echo(f"Syncing project: {config.project}")
typer.echo(f"Project path: {config.home}")
# Run sync
asyncio.run(run_sync(verbose=verbose, watch=watch))
asyncio.run(run_sync(verbose=verbose))
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
logger.exception("Sync failed")
logger.exception(
"Sync command failed",
f"project={config.project},"
f"error={str(e)},"
f"error_type={type(e).__name__},"
f"directory={str(config.home)}",
)
typer.echo(f"Error during sync: {e}", err=True)
raise typer.Exit(1)
raise
+270
View File
@@ -0,0 +1,270 @@
"""CLI tool commands for Basic Memory."""
import asyncio
import sys
from typing import Annotated, List, Optional
import typer
from loguru import logger
from rich import print as rprint
from basic_memory.cli.app import app
# Import prompts
from basic_memory.mcp.prompts.continue_conversation import (
continue_conversation as mcp_continue_conversation,
)
from basic_memory.mcp.prompts.recent_activity import (
recent_activity_prompt as recent_activity_prompt,
)
from basic_memory.mcp.tools import build_context as mcp_build_context
from basic_memory.mcp.tools import read_note as mcp_read_note
from basic_memory.mcp.tools import recent_activity as mcp_recent_activity
from basic_memory.mcp.tools import search_notes as mcp_search
from basic_memory.mcp.tools import write_note as mcp_write_note
from basic_memory.schemas.base import TimeFrame
from basic_memory.schemas.memory import MemoryUrl
from basic_memory.schemas.search import SearchItemType
tool_app = typer.Typer()
app.add_typer(tool_app, name="tool", help="Access to MCP tools via CLI")
@tool_app.command()
def write_note(
title: Annotated[str, typer.Option(help="The title of the note")],
folder: Annotated[str, typer.Option(help="The folder to create the note in")],
content: Annotated[
Optional[str],
typer.Option(
help="The content of the note. If not provided, content will be read from stdin. This allows piping content from other commands, e.g.: cat file.md | basic-memory tools write-note"
),
] = None,
tags: Annotated[
Optional[List[str]], typer.Option(help="A list of tags to apply to the note")
] = None,
):
"""Create or update a markdown note. Content can be provided as an argument or read from stdin.
Content can be provided in two ways:
1. Using the --content parameter
2. Piping content through stdin (if --content is not provided)
Examples:
# Using content parameter
basic-memory tools write-note --title "My Note" --folder "notes" --content "Note content"
# Using stdin pipe
echo "# My Note Content" | basic-memory tools write-note --title "My Note" --folder "notes"
# Using heredoc
cat << EOF | basic-memory tools write-note --title "My Note" --folder "notes"
# My Document
This is my document content.
- Point 1
- Point 2
EOF
# Reading from a file
cat document.md | basic-memory tools write-note --title "Document" --folder "docs"
"""
try:
# If content is not provided, read from stdin
if content is None:
# Check if we're getting data from a pipe or redirect
if not sys.stdin.isatty():
content = sys.stdin.read()
else: # pragma: no cover
# If stdin is a terminal (no pipe/redirect), inform the user
typer.echo(
"No content provided. Please provide content via --content or by piping to stdin.",
err=True,
)
raise typer.Exit(1)
# Also check for empty content
if content is not None and not content.strip():
typer.echo("Empty content provided. Please provide non-empty content.", err=True)
raise typer.Exit(1)
note = asyncio.run(mcp_write_note.fn(title, content, folder, tags))
rprint(note)
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
typer.echo(f"Error during write_note: {e}", err=True)
raise typer.Exit(1)
raise
@tool_app.command()
def read_note(identifier: str, page: int = 1, page_size: int = 10):
"""Read a markdown note from the knowledge base."""
try:
note = asyncio.run(mcp_read_note.fn(identifier, page, page_size))
rprint(note)
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
typer.echo(f"Error during read_note: {e}", err=True)
raise typer.Exit(1)
raise
@tool_app.command()
def build_context(
url: MemoryUrl,
depth: Optional[int] = 1,
timeframe: Optional[TimeFrame] = "7d",
page: int = 1,
page_size: int = 10,
max_related: int = 10,
):
"""Get context needed to continue a discussion."""
try:
context = asyncio.run(
mcp_build_context.fn(
url=url,
depth=depth,
timeframe=timeframe,
page=page,
page_size=page_size,
max_related=max_related,
)
)
# Use json module for more controlled serialization
import json
context_dict = context.model_dump(exclude_none=True)
print(json.dumps(context_dict, indent=2, ensure_ascii=True, default=str))
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
typer.echo(f"Error during build_context: {e}", err=True)
raise typer.Exit(1)
raise
@tool_app.command()
def recent_activity(
type: Annotated[Optional[List[SearchItemType]], typer.Option()] = None,
depth: Optional[int] = 1,
timeframe: Optional[TimeFrame] = "7d",
page: int = 1,
page_size: int = 10,
max_related: int = 10,
):
"""Get recent activity across the knowledge base."""
try:
context = asyncio.run(
mcp_recent_activity.fn(
type=type, # pyright: ignore [reportArgumentType]
depth=depth,
timeframe=timeframe,
page=page,
page_size=page_size,
max_related=max_related,
)
)
# Use json module for more controlled serialization
import json
context_dict = context.model_dump(exclude_none=True)
print(json.dumps(context_dict, indent=2, ensure_ascii=True, default=str))
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
typer.echo(f"Error during build_context: {e}", err=True)
raise typer.Exit(1)
raise
@tool_app.command("search-notes")
def search_notes(
query: str,
permalink: Annotated[bool, typer.Option("--permalink", help="Search permalink values")] = False,
title: Annotated[bool, typer.Option("--title", help="Search title values")] = False,
after_date: Annotated[
Optional[str],
typer.Option("--after_date", help="Search results after date, eg. '2d', '1 week'"),
] = None,
page: int = 1,
page_size: int = 10,
):
"""Search across all content in the knowledge base."""
if permalink and title: # pragma: no cover
print("Cannot search both permalink and title")
raise typer.Abort()
try:
if permalink and title: # pragma: no cover
typer.echo(
"Use either --permalink or --title, not both. Exiting.",
err=True,
)
raise typer.Exit(1)
# set search type
search_type = ("permalink" if permalink else None,)
search_type = ("permalink_match" if permalink and "*" in query else None,)
search_type = ("title" if title else None,)
search_type = "text" if search_type is None else search_type
results = asyncio.run(
mcp_search.fn(
query,
search_type=search_type,
page=page,
after_date=after_date,
page_size=page_size,
)
)
# Use json module for more controlled serialization
import json
results_dict = results.model_dump(exclude_none=True)
print(json.dumps(results_dict, indent=2, ensure_ascii=True, default=str))
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
logger.exception("Error during search", e)
typer.echo(f"Error during search: {e}", err=True)
raise typer.Exit(1)
raise
@tool_app.command(name="continue-conversation")
def continue_conversation(
topic: Annotated[Optional[str], typer.Option(help="Topic or keyword to search for")] = None,
timeframe: Annotated[
Optional[str], typer.Option(help="How far back to look for activity")
] = None,
):
"""Prompt to continue a previous conversation or work session."""
try:
# Prompt functions return formatted strings directly
session = asyncio.run(mcp_continue_conversation.fn(topic=topic, timeframe=timeframe)) # type: ignore
rprint(session)
except Exception as e: # pragma: no cover
if not isinstance(e, typer.Exit):
logger.exception("Error continuing conversation", e)
typer.echo(f"Error continuing conversation: {e}", err=True)
raise typer.Exit(1)
raise
# @tool_app.command(name="show-recent-activity")
# def show_recent_activity(
# timeframe: Annotated[
# str, typer.Option(help="How far back to look for activity")
# ] = "7d",
# ):
# """Prompt to show recent activity."""
# try:
# # Prompt functions return formatted strings directly
# session = asyncio.run(recent_activity_prompt(timeframe=timeframe))
# rprint(session)
# except Exception as e: # pragma: no cover
# if not isinstance(e, typer.Exit):
# logger.exception("Error continuing conversation", e)
# typer.echo(f"Error continuing conversation: {e}", err=True)
# raise typer.Exit(1)
# raise
+13 -6
View File
@@ -1,14 +1,21 @@
"""Main CLI entry point for basic-memory.""" # pragma: no cover
from basic_memory.cli.app import app # pragma: no cover
from basic_memory.utils import setup_logging # pragma: no cover
# Register commands
from basic_memory.cli.commands import status, sync, db, import_memory_json, mcp # noqa: F401 # pragma: no cover
# Set up logging when module is imported
setup_logging(log_file=".basic-memory/basic-memory-cli.log") # pragma: no cover
from basic_memory.cli.commands import ( # noqa: F401 # pragma: no cover
db,
import_chatgpt,
import_claude_conversations,
import_claude_projects,
import_memory_json,
mcp,
project,
status,
sync,
tool,
)
if __name__ == "__main__": # pragma: no cover
# start the app
app()
+346 -19
View File
@@ -1,32 +1,89 @@
"""Configuration management for basic-memory."""
import json
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Literal, Optional, List, Tuple
from loguru import logger
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
import basic_memory
from basic_memory.utils import setup_logging, generate_permalink
DATABASE_NAME = "memory.db"
APP_DATABASE_NAME = "memory.db" # Using the same name but in the app directory
DATA_DIR_NAME = ".basic-memory"
CONFIG_FILE_NAME = "config.json"
WATCH_STATUS_JSON = "watch-status.json"
Environment = Literal["test", "dev", "user"]
class ProjectConfig(BaseSettings):
@dataclass
class ProjectConfig:
"""Configuration for a specific basic-memory project."""
# Default to ~/basic-memory but allow override with env var: BASIC_MEMORY_HOME
home: Path = Field(
default_factory=lambda: Path.home() / "basic-memory",
description="Base path for basic-memory files",
name: str
home: Path
@property
def project(self):
return self.name
@property
def project_url(self) -> str: # pragma: no cover
return f"/{generate_permalink(self.name)}"
class BasicMemoryConfig(BaseSettings):
"""Pydantic model for Basic Memory global configuration."""
env: Environment = Field(default="dev", description="Environment name")
projects: Dict[str, str] = Field(
default_factory=lambda: {
"main": Path(os.getenv("BASIC_MEMORY_HOME", Path.home() / "basic-memory")).as_posix()
},
description="Mapping of project names to their filesystem paths",
)
default_project: str = Field(
default="main",
description="Name of the default project to use",
)
# Name of the project
project: str = Field(default="default", description="Project name")
# overridden by ~/.basic-memory/config.json
log_level: str = "INFO"
# Watch service configuration
sync_delay: int = Field(
default=500, description="Milliseconds to wait after changes before syncing", gt=0
default=1000, description="Milliseconds to wait after changes before syncing", gt=0
)
log_level: str = "INFO"
# update permalinks on move
update_permalinks_on_move: bool = Field(
default=False,
description="Whether to update permalinks when files are moved or renamed. default (False)",
)
sync_changes: bool = Field(
default=True,
description="Whether to sync changes in real time. default (True)",
)
kebab_filenames: bool = Field(
default=False,
description="Format for generated filenames. False preserves spaces and special chars, True converts them to hyphens for consistency with permalinks",
)
# API connection configuration
api_url: Optional[str] = Field(
default=None,
description="URL of remote Basic Memory API. If set, MCP will connect to this API instead of using local ASGI transport.",
)
model_config = SettingsConfigDict(
env_prefix="BASIC_MEMORY_",
@@ -35,23 +92,293 @@ class ProjectConfig(BaseSettings):
env_file_encoding="utf-8",
)
def get_project_path(self, project_name: Optional[str] = None) -> Path: # pragma: no cover
"""Get the path for a specific project or the default project."""
name = project_name or self.default_project
if name not in self.projects:
raise ValueError(f"Project '{name}' not found in configuration")
return Path(self.projects[name])
def model_post_init(self, __context: Any) -> None:
"""Ensure configuration is valid after initialization."""
# Ensure main project exists
if "main" not in self.projects: # pragma: no cover
self.projects["main"] = (
Path(os.getenv("BASIC_MEMORY_HOME", Path.home() / "basic-memory"))
).as_posix()
# Ensure default project is valid
if self.default_project not in self.projects: # pragma: no cover
self.default_project = "main"
@property
def database_path(self) -> Path:
"""Get SQLite database path."""
database_path = self.home / DATA_DIR_NAME / DATABASE_NAME
if not database_path.exists():
def app_database_path(self) -> Path:
"""Get the path to the app-level database.
This is the single database that will store all knowledge data
across all projects.
"""
database_path = Path.home() / DATA_DIR_NAME / APP_DATABASE_NAME
if not database_path.exists(): # pragma: no cover
database_path.parent.mkdir(parents=True, exist_ok=True)
database_path.touch()
return database_path
@field_validator("home")
@property
def database_path(self) -> Path:
"""Get SQLite database path.
Rreturns the app-level database path
for backward compatibility in the codebase.
"""
# Load the app-level database path from the global config
config_manager = ConfigManager()
config = config_manager.load_config() # pragma: no cover
return config.app_database_path # pragma: no cover
@property
def project_list(self) -> List[ProjectConfig]: # pragma: no cover
"""Get all configured projects as ProjectConfig objects."""
return [ProjectConfig(name=name, home=Path(path)) for name, path in self.projects.items()]
@field_validator("projects")
@classmethod
def ensure_path_exists(cls, v: Path) -> Path: # pragma: no cover
def ensure_project_paths_exists(cls, v: Dict[str, str]) -> Dict[str, str]: # pragma: no cover
"""Ensure project path exists."""
if not v.exists():
v.mkdir(parents=True)
for name, path_value in v.items():
path = Path(path_value)
if not Path(path).exists():
try:
path.mkdir(parents=True)
except Exception as e:
logger.error(f"Failed to create project path: {e}")
raise e
return v
# Load project config
config = ProjectConfig()
class ConfigManager:
"""Manages Basic Memory configuration."""
def __init__(self) -> None:
"""Initialize the configuration manager."""
home = os.getenv("HOME", Path.home())
if isinstance(home, str):
home = Path(home)
self.config_dir = home / DATA_DIR_NAME
self.config_file = self.config_dir / CONFIG_FILE_NAME
# Ensure config directory exists
self.config_dir.mkdir(parents=True, exist_ok=True)
@property
def config(self) -> BasicMemoryConfig:
"""Get configuration, loading it lazily if needed."""
return self.load_config()
def load_config(self) -> BasicMemoryConfig:
"""Load configuration from file or create default."""
if self.config_file.exists():
try:
data = json.loads(self.config_file.read_text(encoding="utf-8"))
return BasicMemoryConfig(**data)
except Exception as e: # pragma: no cover
logger.exception(f"Failed to load config: {e}")
raise e
else:
config = BasicMemoryConfig()
self.save_config(config)
return config
def save_config(self, config: BasicMemoryConfig) -> None:
"""Save configuration to file."""
save_basic_memory_config(self.config_file, config)
@property
def projects(self) -> Dict[str, str]:
"""Get all configured projects."""
return self.config.projects.copy()
@property
def default_project(self) -> str:
"""Get the default project name."""
return self.config.default_project
def add_project(self, name: str, path: str) -> ProjectConfig:
"""Add a new project to the configuration."""
project_name, _ = self.get_project(name)
if project_name: # pragma: no cover
raise ValueError(f"Project '{name}' already exists")
# Ensure the path exists
project_path = Path(path)
project_path.mkdir(parents=True, exist_ok=True) # pragma: no cover
# Load config, modify it, and save it
config = self.load_config()
config.projects[name] = project_path.as_posix()
self.save_config(config)
return ProjectConfig(name=name, home=project_path)
def remove_project(self, name: str) -> None:
"""Remove a project from the configuration."""
project_name, path = self.get_project(name)
if not project_name: # pragma: no cover
raise ValueError(f"Project '{name}' not found")
# Load config, check, modify, and save
config = self.load_config()
if project_name == config.default_project: # pragma: no cover
raise ValueError(f"Cannot remove the default project '{name}'")
del config.projects[name]
self.save_config(config)
def set_default_project(self, name: str) -> None:
"""Set the default project."""
project_name, path = self.get_project(name)
if not project_name: # pragma: no cover
raise ValueError(f"Project '{name}' not found")
# Load config, modify, and save
config = self.load_config()
config.default_project = project_name
self.save_config(config)
def get_project(self, name: str) -> Tuple[str, str] | Tuple[None, None]:
"""Look up a project from the configuration by name or permalink"""
project_permalink = generate_permalink(name)
app_config = self.config
for project_name, path in app_config.projects.items():
if project_permalink == generate_permalink(project_name):
return project_name, path
return None, None
def get_project_config(project_name: Optional[str] = None) -> ProjectConfig:
"""
Get the project configuration for the current session.
If project_name is provided, it will be used instead of the default project.
"""
actual_project_name = None
# load the config from file
config_manager = ConfigManager()
app_config = config_manager.load_config()
# Get project name from environment variable
os_project_name = os.environ.get("BASIC_MEMORY_PROJECT", None)
if os_project_name: # pragma: no cover
logger.warning(
f"BASIC_MEMORY_PROJECT is not supported anymore. Use the --project flag or set the default project in the config instead. Setting default project to {os_project_name}"
)
actual_project_name = project_name
# if the project_name is passed in, use it
elif not project_name:
# use default
actual_project_name = app_config.default_project
else: # pragma: no cover
actual_project_name = project_name
# the config contains a dict[str,str] of project names and absolute paths
assert actual_project_name is not None, "actual_project_name cannot be None"
project_permalink = generate_permalink(actual_project_name)
for name, path in app_config.projects.items():
if project_permalink == generate_permalink(name):
return ProjectConfig(name=name, home=Path(path))
# otherwise raise error
raise ValueError(f"Project '{actual_project_name}' not found") # pragma: no cover
def save_basic_memory_config(file_path: Path, config: BasicMemoryConfig) -> None:
"""Save configuration to file."""
try:
file_path.write_text(json.dumps(config.model_dump(), indent=2))
except Exception as e: # pragma: no cover
logger.error(f"Failed to save config: {e}")
def update_current_project(project_name: str) -> None:
"""Update the global config to use a different project.
This is used by the CLI when --project flag is specified.
"""
global config
config = get_project_config(project_name) # pragma: no cover
# setup logging to a single log file in user home directory
user_home = Path.home()
log_dir = user_home / DATA_DIR_NAME
log_dir.mkdir(parents=True, exist_ok=True)
# Process info for logging
def get_process_name(): # pragma: no cover
"""
get the type of process for logging
"""
import sys
if "sync" in sys.argv:
return "sync"
elif "mcp" in sys.argv:
return "mcp"
elif "cli" in sys.argv:
return "cli"
else:
return "api"
process_name = get_process_name()
# Global flag to track if logging has been set up
_LOGGING_SETUP = False
# Logging
def setup_basic_memory_logging(): # pragma: no cover
"""Set up logging for basic-memory, ensuring it only happens once."""
global _LOGGING_SETUP
if _LOGGING_SETUP:
# We can't log before logging is set up
# print("Skipping duplicate logging setup")
return
# Check for console logging environment variable - accept more truthy values
console_logging_env = os.getenv("BASIC_MEMORY_CONSOLE_LOGGING", "false").lower()
console_logging = console_logging_env in ("true", "1", "yes", "on")
# Check for log level environment variable first, fall back to config
log_level = os.getenv("BASIC_MEMORY_LOG_LEVEL")
if not log_level:
config_manager = ConfigManager()
log_level = config_manager.config.log_level
config_manager = ConfigManager()
config = get_project_config()
setup_logging(
env=config_manager.config.env,
home_dir=user_home, # Use user home for logs
log_level=log_level,
log_file=f"{DATA_DIR_NAME}/basic-memory-{process_name}.log",
console=console_logging,
)
logger.info(f"Basic Memory {basic_memory.__version__} (Project: {config.project})")
_LOGGING_SETUP = True
# Set up logging
setup_basic_memory_logging()
+93 -34
View File
@@ -4,6 +4,10 @@ from enum import Enum, auto
from pathlib import Path
from typing import AsyncGenerator, Optional
from basic_memory.config import BasicMemoryConfig, ConfigManager
from alembic import command
from alembic.config import Config
from loguru import logger
from sqlalchemy import text
from sqlalchemy.ext.asyncio import (
@@ -14,12 +18,12 @@ from sqlalchemy.ext.asyncio import (
async_scoped_session,
)
from basic_memory.models import Base
from basic_memory.models.search import CREATE_SEARCH_INDEX
from basic_memory.repository.search_repository import SearchRepository
# Module level state
_engine: Optional[AsyncEngine] = None
_session_maker: Optional[async_sessionmaker[AsyncSession]] = None
_migrations_completed: bool = False
class DatabaseType(Enum):
@@ -35,7 +39,7 @@ class DatabaseType(Enum):
logger.info("Using in-memory SQLite database")
return "sqlite+aiosqlite://"
return f"sqlite+aiosqlite:///{db_path}"
return f"sqlite+aiosqlite:///{db_path}" # pragma: no cover
def get_scoped_session_factory(
@@ -69,60 +73,61 @@ async def scoped_session(
await factory.remove()
async def init_db() -> None:
"""Initialize database with required tables."""
if _session_maker is None: # pragma: no cover
raise RuntimeError("Database session maker not initialized")
logger.info("Initializing database...")
async with scoped_session(_session_maker) as session:
await session.execute(text("PRAGMA foreign_keys=ON"))
conn = await session.connection()
await conn.run_sync(Base.metadata.create_all)
# recreate search index
await session.execute(CREATE_SEARCH_INDEX)
await session.commit()
def _create_engine_and_session(
db_path: Path, db_type: DatabaseType = DatabaseType.FILESYSTEM
) -> tuple[AsyncEngine, async_sessionmaker[AsyncSession]]:
"""Internal helper to create engine and session maker."""
db_url = DatabaseType.get_db_url(db_path, db_type)
logger.debug(f"Creating engine for db_url: {db_url}")
engine = create_async_engine(db_url, connect_args={"check_same_thread": False})
session_maker = async_sessionmaker(engine, expire_on_commit=False)
return engine, session_maker
async def get_or_create_db(
db_path: Path,
db_type: DatabaseType = DatabaseType.FILESYSTEM,
ensure_migrations: bool = True,
) -> tuple[AsyncEngine, async_sessionmaker[AsyncSession]]: # pragma: no cover
"""Get or create database engine and session maker."""
global _engine, _session_maker
if _engine is None:
db_url = DatabaseType.get_db_url(db_path, db_type)
logger.debug(f"Creating engine for db_url: {db_url}")
_engine = create_async_engine(db_url, connect_args={"check_same_thread": False})
_session_maker = async_sessionmaker(_engine, expire_on_commit=False)
_engine, _session_maker = _create_engine_and_session(db_path, db_type)
# Initialize database
await init_db()
# Run migrations automatically unless explicitly disabled
if ensure_migrations:
app_config = ConfigManager().config
await run_migrations(app_config, db_type)
# These checks should never fail since we just created the engine and session maker
# if they were None, but we'll check anyway for the type checker
if _engine is None:
logger.error("Failed to create database engine", db_path=str(db_path))
raise RuntimeError("Database engine initialization failed")
if _session_maker is None:
logger.error("Failed to create session maker", db_path=str(db_path))
raise RuntimeError("Session maker initialization failed")
assert _engine is not None # for type checker
assert _session_maker is not None # for type checker
return _engine, _session_maker
async def shutdown_db() -> None: # pragma: no cover
"""Clean up database connections."""
global _engine, _session_maker
global _engine, _session_maker, _migrations_completed
if _engine:
await _engine.dispose()
_engine = None
_session_maker = None
_migrations_completed = False
@asynccontextmanager
async def engine_session_factory(
db_path: Path,
db_type: DatabaseType = DatabaseType.MEMORY,
init: bool = True,
) -> AsyncGenerator[tuple[AsyncEngine, async_sessionmaker[AsyncSession]], None]:
"""Create engine and session factory.
@@ -130,7 +135,7 @@ async def engine_session_factory(
for each test. For production use, use get_or_create_db() instead.
"""
global _engine, _session_maker
global _engine, _session_maker, _migrations_completed
db_url = DatabaseType.get_db_url(db_path, db_type)
logger.debug(f"Creating engine for db_url: {db_url}")
@@ -139,14 +144,68 @@ async def engine_session_factory(
try:
_session_maker = async_sessionmaker(_engine, expire_on_commit=False)
if init:
await init_db()
# Verify that engine and session maker are initialized
if _engine is None: # pragma: no cover
logger.error("Database engine is None in engine_session_factory")
raise RuntimeError("Database engine initialization failed")
if _session_maker is None: # pragma: no cover
logger.error("Session maker is None in engine_session_factory")
raise RuntimeError("Session maker initialization failed")
assert _engine is not None # for type checker
assert _session_maker is not None # for type checker
yield _engine, _session_maker
finally:
if _engine:
await _engine.dispose()
_engine = None
_session_maker = None
_migrations_completed = False
async def run_migrations(
app_config: BasicMemoryConfig, database_type=DatabaseType.FILESYSTEM, force: bool = False
): # pragma: no cover
"""Run any pending alembic migrations."""
global _migrations_completed
# Skip if migrations already completed unless forced
if _migrations_completed and not force:
logger.debug("Migrations already completed in this session, skipping")
return
logger.info("Running database migrations...")
try:
# Get the absolute path to the alembic directory relative to this file
alembic_dir = Path(__file__).parent / "alembic"
config = Config()
# Set required Alembic config options programmatically
config.set_main_option("script_location", str(alembic_dir))
config.set_main_option(
"file_template",
"%%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s",
)
config.set_main_option("timezone", "UTC")
config.set_main_option("revision_environment", "false")
config.set_main_option(
"sqlalchemy.url", DatabaseType.get_db_url(app_config.database_path, database_type)
)
command.upgrade(config, "head")
logger.info("Migrations completed successfully")
# Get session maker - ensure we don't trigger recursive migration calls
if _session_maker is None:
_, session_maker = _create_engine_and_session(app_config.database_path, database_type)
else:
session_maker = _session_maker
# initialize the search Index schema
# the project_id is not used for init_search_index, so we pass a dummy value
await SearchRepository(session_maker, 1).init_search_index()
# Mark migrations as completed
_migrations_completed = True
except Exception as e: # pragma: no cover
logger.error(f"Error running migrations: {e}")
raise
+230 -21
View File
@@ -1,49 +1,88 @@
"""Dependency injection functions for basic-memory services."""
from typing import Annotated
from loguru import logger
from fastapi import Depends
from fastapi import Depends, HTTPException, Path, status
from sqlalchemy.ext.asyncio import (
AsyncSession,
AsyncEngine,
async_sessionmaker,
)
import pathlib
from basic_memory import db
from basic_memory.config import ProjectConfig, config
from basic_memory.config import ProjectConfig, BasicMemoryConfig, ConfigManager
from basic_memory.importers import (
ChatGPTImporter,
ClaudeConversationsImporter,
ClaudeProjectsImporter,
MemoryJsonImporter,
)
from basic_memory.markdown import EntityParser
from basic_memory.markdown.markdown_processor import MarkdownProcessor
from basic_memory.repository.entity_repository import EntityRepository
from basic_memory.repository.observation_repository import ObservationRepository
from basic_memory.repository.project_repository import ProjectRepository
from basic_memory.repository.relation_repository import RelationRepository
from basic_memory.repository.search_repository import SearchRepository
from basic_memory.services import (
EntityService,
)
from basic_memory.services import EntityService, ProjectService
from basic_memory.services.context_service import ContextService
from basic_memory.services.directory_service import DirectoryService
from basic_memory.services.file_service import FileService
from basic_memory.services.link_resolver import LinkResolver
from basic_memory.services.search_service import SearchService
from basic_memory.sync import SyncService
def get_app_config() -> BasicMemoryConfig: # pragma: no cover
app_config = ConfigManager().config
return app_config
AppConfigDep = Annotated[BasicMemoryConfig, Depends(get_app_config)] # pragma: no cover
## project
def get_project_config() -> ProjectConfig: # pragma: no cover
return config
async def get_project_config(
project: "ProjectPathDep", project_repository: "ProjectRepositoryDep"
) -> ProjectConfig: # pragma: no cover
"""Get the current project referenced from request state.
Args:
request: The current request object
project_repository: Repository for project operations
Returns:
The resolved project config
Raises:
HTTPException: If project is not found
"""
project_obj = await project_repository.get_by_permalink(str(project))
if project_obj:
return ProjectConfig(name=project_obj.name, home=pathlib.Path(project_obj.path))
# Not found
raise HTTPException( # pragma: no cover
status_code=status.HTTP_404_NOT_FOUND, detail=f"Project '{project}' not found."
)
ProjectConfigDep = Annotated[ProjectConfig, Depends(get_project_config)] # pragma: no cover
## sqlalchemy
async def get_engine_factory(
project_config: ProjectConfigDep,
app_config: AppConfigDep,
) -> tuple[AsyncEngine, async_sessionmaker[AsyncSession]]: # pragma: no cover
"""Get engine and session maker."""
return await db.get_or_create_db(project_config.database_path)
engine, session_maker = await db.get_or_create_db(app_config.database_path)
return engine, session_maker
EngineFactoryDep = Annotated[
@@ -63,11 +102,70 @@ SessionMakerDep = Annotated[async_sessionmaker, Depends(get_session_maker)]
## repositories
async def get_project_repository(
session_maker: SessionMakerDep,
) -> ProjectRepository:
"""Get the project repository."""
return ProjectRepository(session_maker)
ProjectRepositoryDep = Annotated[ProjectRepository, Depends(get_project_repository)]
ProjectPathDep = Annotated[str, Path()] # Use Path dependency to extract from URL
async def get_project_id(
project_repository: ProjectRepositoryDep,
project: ProjectPathDep,
) -> int:
"""Get the current project ID from request state.
When using sub-applications with /{project} mounting, the project value
is stored in request.state by middleware.
Args:
request: The current request object
project_repository: Repository for project operations
Returns:
The resolved project ID
Raises:
HTTPException: If project is not found
"""
# Try by permalink first (most common case with URL paths)
project_obj = await project_repository.get_by_permalink(str(project))
if project_obj:
return project_obj.id
# Try by name if permalink lookup fails
project_obj = await project_repository.get_by_name(str(project)) # pragma: no cover
if project_obj: # pragma: no cover
return project_obj.id
# Not found
raise HTTPException( # pragma: no cover
status_code=status.HTTP_404_NOT_FOUND, detail=f"Project '{project}' not found."
)
"""
The project_id dependency is used in the following:
- EntityRepository
- ObservationRepository
- RelationRepository
- SearchRepository
- ProjectInfoRepository
"""
ProjectIdDep = Annotated[int, Depends(get_project_id)]
async def get_entity_repository(
session_maker: SessionMakerDep,
project_id: ProjectIdDep,
) -> EntityRepository:
"""Create an EntityRepository instance."""
return EntityRepository(session_maker)
"""Create an EntityRepository instance for the current project."""
return EntityRepository(session_maker, project_id=project_id)
EntityRepositoryDep = Annotated[EntityRepository, Depends(get_entity_repository)]
@@ -75,9 +173,10 @@ EntityRepositoryDep = Annotated[EntityRepository, Depends(get_entity_repository)
async def get_observation_repository(
session_maker: SessionMakerDep,
project_id: ProjectIdDep,
) -> ObservationRepository:
"""Create an ObservationRepository instance."""
return ObservationRepository(session_maker)
"""Create an ObservationRepository instance for the current project."""
return ObservationRepository(session_maker, project_id=project_id)
ObservationRepositoryDep = Annotated[ObservationRepository, Depends(get_observation_repository)]
@@ -85,9 +184,10 @@ ObservationRepositoryDep = Annotated[ObservationRepository, Depends(get_observat
async def get_relation_repository(
session_maker: SessionMakerDep,
project_id: ProjectIdDep,
) -> RelationRepository:
"""Create a RelationRepository instance."""
return RelationRepository(session_maker)
"""Create a RelationRepository instance for the current project."""
return RelationRepository(session_maker, project_id=project_id)
RelationRepositoryDep = Annotated[RelationRepository, Depends(get_relation_repository)]
@@ -95,14 +195,18 @@ RelationRepositoryDep = Annotated[RelationRepository, Depends(get_relation_repos
async def get_search_repository(
session_maker: SessionMakerDep,
project_id: ProjectIdDep,
) -> SearchRepository:
"""Create a SearchRepository instance."""
return SearchRepository(session_maker)
"""Create a SearchRepository instance for the current project."""
return SearchRepository(session_maker, project_id=project_id)
SearchRepositoryDep = Annotated[SearchRepository, Depends(get_search_repository)]
# ProjectInfoRepository is deprecated and will be removed in a future version.
# Use ProjectRepository instead, which has the same functionality plus more project-specific operations.
## services
@@ -123,7 +227,12 @@ MarkdownProcessorDep = Annotated[MarkdownProcessor, Depends(get_markdown_process
async def get_file_service(
project_config: ProjectConfigDep, markdown_processor: MarkdownProcessorDep
) -> FileService:
return FileService(project_config.home, markdown_processor)
logger.debug(
f"Creating FileService for project: {project_config.name}, base_path: {project_config.home}"
)
file_service = FileService(project_config.home, markdown_processor)
logger.debug(f"Created FileService for project: {file_service} ")
return file_service
FileServiceDep = Annotated[FileService, Depends(get_file_service)]
@@ -173,9 +282,109 @@ LinkResolverDep = Annotated[LinkResolver, Depends(get_link_resolver)]
async def get_context_service(
search_repository: SearchRepositoryDep, entity_repository: EntityRepositoryDep
search_repository: SearchRepositoryDep,
entity_repository: EntityRepositoryDep,
observation_repository: ObservationRepositoryDep,
) -> ContextService:
return ContextService(search_repository, entity_repository)
return ContextService(
search_repository=search_repository,
entity_repository=entity_repository,
observation_repository=observation_repository,
)
ContextServiceDep = Annotated[ContextService, Depends(get_context_service)]
async def get_sync_service(
app_config: AppConfigDep,
entity_service: EntityServiceDep,
entity_parser: EntityParserDep,
entity_repository: EntityRepositoryDep,
relation_repository: RelationRepositoryDep,
search_service: SearchServiceDep,
file_service: FileServiceDep,
) -> SyncService: # pragma: no cover
"""
:rtype: object
"""
return SyncService(
app_config=app_config,
entity_service=entity_service,
entity_parser=entity_parser,
entity_repository=entity_repository,
relation_repository=relation_repository,
search_service=search_service,
file_service=file_service,
)
SyncServiceDep = Annotated[SyncService, Depends(get_sync_service)]
async def get_project_service(
project_repository: ProjectRepositoryDep,
) -> ProjectService:
"""Create ProjectService with repository."""
return ProjectService(repository=project_repository)
ProjectServiceDep = Annotated[ProjectService, Depends(get_project_service)]
async def get_directory_service(
entity_repository: EntityRepositoryDep,
) -> DirectoryService:
"""Create DirectoryService with dependencies."""
return DirectoryService(
entity_repository=entity_repository,
)
DirectoryServiceDep = Annotated[DirectoryService, Depends(get_directory_service)]
# Import
async def get_chatgpt_importer(
project_config: ProjectConfigDep, markdown_processor: MarkdownProcessorDep
) -> ChatGPTImporter:
"""Create ChatGPTImporter with dependencies."""
return ChatGPTImporter(project_config.home, markdown_processor)
ChatGPTImporterDep = Annotated[ChatGPTImporter, Depends(get_chatgpt_importer)]
async def get_claude_conversations_importer(
project_config: ProjectConfigDep, markdown_processor: MarkdownProcessorDep
) -> ClaudeConversationsImporter:
"""Create ChatGPTImporter with dependencies."""
return ClaudeConversationsImporter(project_config.home, markdown_processor)
ClaudeConversationsImporterDep = Annotated[
ClaudeConversationsImporter, Depends(get_claude_conversations_importer)
]
async def get_claude_projects_importer(
project_config: ProjectConfigDep, markdown_processor: MarkdownProcessorDep
) -> ClaudeProjectsImporter:
"""Create ChatGPTImporter with dependencies."""
return ClaudeProjectsImporter(project_config.home, markdown_processor)
ClaudeProjectsImporterDep = Annotated[ClaudeProjectsImporter, Depends(get_claude_projects_importer)]
async def get_memory_json_importer(
project_config: ProjectConfigDep, markdown_processor: MarkdownProcessorDep
) -> MemoryJsonImporter:
"""Create ChatGPTImporter with dependencies."""
return MemoryJsonImporter(project_config.home, markdown_processor)
MemoryJsonImporterDep = Annotated[MemoryJsonImporter, Depends(get_memory_json_importer)]
+107 -21
View File
@@ -2,11 +2,15 @@
import hashlib
from pathlib import Path
from typing import Dict, Any
import re
from typing import Any, Dict, Union
import yaml
import frontmatter
from loguru import logger
from basic_memory.utils import FilePath
class FileError(Exception):
"""Base exception for file operations."""
@@ -26,12 +30,12 @@ class ParseError(FileError):
pass
async def compute_checksum(content: str) -> str:
async def compute_checksum(content: Union[str, bytes]) -> str:
"""
Compute SHA-256 checksum of content.
Args:
content: Text content to hash
content: Content to hash (either text string or bytes)
Returns:
SHA-256 hex digest
@@ -40,48 +44,55 @@ async def compute_checksum(content: str) -> str:
FileError: If checksum computation fails
"""
try:
return hashlib.sha256(content.encode()).hexdigest()
if isinstance(content, str):
content = content.encode()
return hashlib.sha256(content).hexdigest()
except Exception as e: # pragma: no cover
logger.error(f"Failed to compute checksum: {e}")
raise FileError(f"Failed to compute checksum: {e}")
async def ensure_directory(path: Path) -> None:
async def ensure_directory(path: FilePath) -> None:
"""
Ensure directory exists, creating if necessary.
Args:
path: Directory path to ensure
path: Directory path to ensure (Path or string)
Raises:
FileWriteError: If directory creation fails
"""
try:
path.mkdir(parents=True, exist_ok=True)
# Convert string to Path if needed
path_obj = Path(path) if isinstance(path, str) else path
path_obj.mkdir(parents=True, exist_ok=True)
except Exception as e: # pragma: no cover
logger.error(f"Failed to create directory: {path}: {e}")
logger.error("Failed to create directory", path=str(path), error=str(e))
raise FileWriteError(f"Failed to create directory {path}: {e}")
async def write_file_atomic(path: Path, content: str) -> None:
async def write_file_atomic(path: FilePath, content: str) -> None:
"""
Write file with atomic operation using temporary file.
Args:
path: Target file path
path: Target file path (Path or string)
content: Content to write
Raises:
FileWriteError: If write operation fails
"""
temp_path = path.with_suffix(".tmp")
# Convert string to Path if needed
path_obj = Path(path) if isinstance(path, str) else path
temp_path = path_obj.with_suffix(".tmp")
try:
temp_path.write_text(content)
temp_path.replace(path)
logger.debug(f"wrote file: {path}")
temp_path.write_text(content, encoding="utf-8")
temp_path.replace(path_obj)
logger.debug("Wrote file atomically", path=str(path_obj), content_length=len(content))
except Exception as e: # pragma: no cover
temp_path.unlink(missing_ok=True)
logger.error(f"Failed to write file: {path}: {e}")
logger.error("Failed to write file", path=str(path_obj), error=str(e))
raise FileWriteError(f"Failed to write file {path}: {e}")
@@ -95,6 +106,9 @@ def has_frontmatter(content: str) -> bool:
Returns:
True if content has valid frontmatter markers (---), False otherwise
"""
if not content:
return False
content = content.strip()
if not content.startswith("---"):
return False
@@ -171,7 +185,7 @@ def remove_frontmatter(content: str) -> str:
return parts[2].strip()
async def update_frontmatter(path: Path, updates: Dict[str, Any]) -> str:
async def update_frontmatter(path: FilePath, updates: Dict[str, Any]) -> str:
"""Update frontmatter fields in a file while preserving all content.
Only modifies the frontmatter section, leaving all content untouched.
@@ -179,7 +193,7 @@ async def update_frontmatter(path: Path, updates: Dict[str, Any]) -> str:
Returns checksum of updated file.
Args:
path: Path to markdown file
path: Path to markdown file (Path or string)
updates: Dict of frontmatter fields to update
Returns:
@@ -190,8 +204,11 @@ async def update_frontmatter(path: Path, updates: Dict[str, Any]) -> str:
ParseError: If frontmatter parsing fails
"""
try:
# Convert string to Path if needed
path_obj = Path(path) if isinstance(path, str) else path
# Read current content
content = path.read_text()
content = path_obj.read_text(encoding="utf-8")
# Parse current frontmatter
current_fm = {}
@@ -203,12 +220,81 @@ async def update_frontmatter(path: Path, updates: Dict[str, Any]) -> str:
new_fm = {**current_fm, **updates}
# Write new file with updated frontmatter
yaml_fm = yaml.dump(new_fm, sort_keys=False)
yaml_fm = yaml.dump(new_fm, sort_keys=False, allow_unicode=True)
final_content = f"---\n{yaml_fm}---\n\n{content.strip()}"
await write_file_atomic(path, final_content)
logger.debug("Updating frontmatter", path=str(path_obj), update_keys=list(updates.keys()))
await write_file_atomic(path_obj, final_content)
return await compute_checksum(final_content)
except Exception as e: # pragma: no cover
logger.error(f"Failed to update frontmatter in {path}: {e}")
logger.error(
"Failed to update frontmatter",
path=str(path) if isinstance(path, (str, Path)) else "<unknown>",
error=str(e),
)
raise FileError(f"Failed to update frontmatter: {e}")
def dump_frontmatter(post: frontmatter.Post) -> str:
"""
Serialize frontmatter.Post to markdown with Obsidian-compatible YAML format.
This function ensures that tags are formatted as YAML lists instead of JSON arrays:
Good (Obsidian compatible):
---
tags:
- system
- overview
- reference
---
Bad (current behavior):
---
tags: ["system", "overview", "reference"]
---
Args:
post: frontmatter.Post object to serialize
Returns:
String containing markdown with properly formatted YAML frontmatter
"""
if not post.metadata:
# No frontmatter, just return content
return post.content
# Serialize YAML with block style for lists
yaml_str = yaml.dump(
post.metadata,
sort_keys=False,
allow_unicode=True,
default_flow_style=False
)
# Construct the final markdown with frontmatter
if post.content:
return f"---\n{yaml_str}---\n\n{post.content}"
else:
return f"---\n{yaml_str}---\n"
def sanitize_for_filename(text: str, replacement: str = "-") -> str:
"""
Sanitize string to be safe for use as a note title
Replaces path separators and other problematic characters
with hyphens.
"""
# replace both POSIX and Windows path separators
text = re.sub(r"[/\\]", replacement, text)
# replace some other problematic chars
text = re.sub(r'[<>:"|?*]', replacement, text)
# compress multiple, repeated replacements
text = re.sub(f"{re.escape(replacement)}+", replacement, text)
return text.strip(replacement)
+27
View File
@@ -0,0 +1,27 @@
"""Import services for Basic Memory."""
from basic_memory.importers.base import Importer
from basic_memory.importers.chatgpt_importer import ChatGPTImporter
from basic_memory.importers.claude_conversations_importer import (
ClaudeConversationsImporter,
)
from basic_memory.importers.claude_projects_importer import ClaudeProjectsImporter
from basic_memory.importers.memory_json_importer import MemoryJsonImporter
from basic_memory.schemas.importer import (
ChatImportResult,
EntityImportResult,
ImportResult,
ProjectImportResult,
)
__all__ = [
"Importer",
"ChatGPTImporter",
"ClaudeConversationsImporter",
"ClaudeProjectsImporter",
"MemoryJsonImporter",
"ImportResult",
"ChatImportResult",
"EntityImportResult",
"ProjectImportResult",
]
+79
View File
@@ -0,0 +1,79 @@
"""Base import service for Basic Memory."""
import logging
from abc import abstractmethod
from pathlib import Path
from typing import Any, Optional, TypeVar
from basic_memory.markdown.markdown_processor import MarkdownProcessor
from basic_memory.markdown.schemas import EntityMarkdown
from basic_memory.schemas.importer import ImportResult
logger = logging.getLogger(__name__)
T = TypeVar("T", bound=ImportResult)
class Importer[T: ImportResult]:
"""Base class for all import services."""
def __init__(self, base_path: Path, markdown_processor: MarkdownProcessor):
"""Initialize the import service.
Args:
markdown_processor: MarkdownProcessor instance for writing markdown files.
"""
self.base_path = base_path.resolve() # Get absolute path
self.markdown_processor = markdown_processor
@abstractmethod
async def import_data(self, source_data, destination_folder: str, **kwargs: Any) -> T:
"""Import data from source file to destination folder.
Args:
source_path: Path to the source file.
destination_folder: Destination folder within the project.
**kwargs: Additional keyword arguments for specific import types.
Returns:
ImportResult containing statistics and status of the import.
"""
pass # pragma: no cover
async def write_entity(self, entity: EntityMarkdown, file_path: Path) -> None:
"""Write entity to file using markdown processor.
Args:
entity: EntityMarkdown instance to write.
file_path: Path to write the entity to.
"""
await self.markdown_processor.write_file(file_path, entity)
def ensure_folder_exists(self, folder: str) -> Path:
"""Ensure folder exists, create if it doesn't.
Args:
base_path: Base path of the project.
folder: Folder name or path within the project.
Returns:
Path to the folder.
"""
folder_path = self.base_path / folder
folder_path.mkdir(parents=True, exist_ok=True)
return folder_path
@abstractmethod
def handle_error(
self, message: str, error: Optional[Exception] = None
) -> T: # pragma: no cover
"""Handle errors during import.
Args:
message: Error message.
error: Optional exception that caused the error.
Returns:
ImportResult with error information.
"""
pass
@@ -0,0 +1,232 @@
"""ChatGPT import service for Basic Memory."""
import logging
from datetime import datetime
from typing import Any, Dict, List, Optional, Set
from basic_memory.markdown.schemas import EntityFrontmatter, EntityMarkdown
from basic_memory.importers.base import Importer
from basic_memory.schemas.importer import ChatImportResult
from basic_memory.importers.utils import clean_filename, format_timestamp
logger = logging.getLogger(__name__)
class ChatGPTImporter(Importer[ChatImportResult]):
"""Service for importing ChatGPT conversations."""
async def import_data(
self, source_data, destination_folder: str, **kwargs: Any
) -> ChatImportResult:
"""Import conversations from ChatGPT JSON export.
Args:
source_path: Path to the ChatGPT conversations.json file.
destination_folder: Destination folder within the project.
**kwargs: Additional keyword arguments.
Returns:
ChatImportResult containing statistics and status of the import.
"""
try: # pragma: no cover
# Ensure the destination folder exists
self.ensure_folder_exists(destination_folder)
conversations = source_data
# Process each conversation
messages_imported = 0
chats_imported = 0
for chat in conversations:
# Convert to entity
entity = self._format_chat_content(destination_folder, chat)
# Write file
file_path = self.base_path / f"{entity.frontmatter.metadata['permalink']}.md"
await self.write_entity(entity, file_path)
# Count messages
msg_count = sum(
1
for node in chat["mapping"].values()
if node.get("message")
and not node.get("message", {})
.get("metadata", {})
.get("is_visually_hidden_from_conversation")
)
chats_imported += 1
messages_imported += msg_count
return ChatImportResult(
import_count={"conversations": chats_imported, "messages": messages_imported},
success=True,
conversations=chats_imported,
messages=messages_imported,
)
except Exception as e: # pragma: no cover
logger.exception("Failed to import ChatGPT conversations")
return self.handle_error("Failed to import ChatGPT conversations", e) # pyright: ignore [reportReturnType]
def _format_chat_content(
self, folder: str, conversation: Dict[str, Any]
) -> EntityMarkdown: # pragma: no cover
"""Convert chat conversation to Basic Memory entity.
Args:
folder: Destination folder name.
conversation: ChatGPT conversation data.
Returns:
EntityMarkdown instance representing the conversation.
"""
# Extract timestamps
created_at = conversation["create_time"]
modified_at = conversation["update_time"]
root_id = None
# Find root message
for node_id, node in conversation["mapping"].items():
if node.get("parent") is None:
root_id = node_id
break
# Generate permalink
date_prefix = datetime.fromtimestamp(created_at).astimezone().strftime("%Y%m%d")
clean_title = clean_filename(conversation["title"])
# Format content
content = self._format_chat_markdown(
title=conversation["title"],
mapping=conversation["mapping"],
root_id=root_id,
created_at=created_at,
modified_at=modified_at,
)
# Create entity
entity = EntityMarkdown(
frontmatter=EntityFrontmatter(
metadata={
"type": "conversation",
"title": conversation["title"],
"created": format_timestamp(created_at),
"modified": format_timestamp(modified_at),
"permalink": f"{folder}/{date_prefix}-{clean_title}",
}
),
content=content,
)
return entity
def _format_chat_markdown(
self,
title: str,
mapping: Dict[str, Any],
root_id: Optional[str],
created_at: float,
modified_at: float,
) -> str: # pragma: no cover
"""Format chat as clean markdown.
Args:
title: Chat title.
mapping: Message mapping.
root_id: Root message ID.
created_at: Creation timestamp.
modified_at: Modification timestamp.
Returns:
Formatted markdown content.
"""
# Start with title
lines = [f"# {title}\n"]
# Traverse message tree
seen_msgs: Set[str] = set()
messages = self._traverse_messages(mapping, root_id, seen_msgs)
# Format each message
for msg in messages:
# Skip hidden messages
if msg.get("metadata", {}).get("is_visually_hidden_from_conversation"):
continue
# Get author and timestamp
author = msg["author"]["role"].title()
ts = format_timestamp(msg["create_time"]) if msg.get("create_time") else ""
# Add message header
lines.append(f"### {author} ({ts})")
# Add message content
content = self._get_message_content(msg)
if content:
lines.append(content)
# Add spacing
lines.append("")
return "\n".join(lines)
def _get_message_content(self, message: Dict[str, Any]) -> str: # pragma: no cover
"""Extract clean message content.
Args:
message: Message data.
Returns:
Cleaned message content.
"""
if not message or "content" not in message:
return ""
content = message["content"]
if content.get("content_type") == "text":
return "\n".join(content.get("parts", []))
elif content.get("content_type") == "code":
return f"```{content.get('language', '')}\n{content.get('text', '')}\n```"
return ""
def _traverse_messages(
self, mapping: Dict[str, Any], root_id: Optional[str], seen: Set[str]
) -> List[Dict[str, Any]]: # pragma: no cover
"""Traverse message tree iteratively to handle deep conversations.
Args:
mapping: Message mapping.
root_id: Root message ID.
seen: Set of seen message IDs.
Returns:
List of message data.
"""
messages = []
if not root_id:
return messages
# Use iterative approach with stack to avoid recursion depth issues
stack = [root_id]
while stack:
node_id = stack.pop()
if not node_id:
continue
node = mapping.get(node_id)
if not node:
continue
# Process current node if it has a message and hasn't been seen
if node["id"] not in seen and node.get("message"):
seen.add(node["id"])
messages.append(node["message"])
# Add children to stack in reverse order to maintain conversation flow
children = node.get("children", [])
for child_id in reversed(children):
stack.append(child_id)
return messages
@@ -0,0 +1,172 @@
"""Claude conversations import service for Basic Memory."""
import logging
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List
from basic_memory.markdown.schemas import EntityFrontmatter, EntityMarkdown
from basic_memory.importers.base import Importer
from basic_memory.schemas.importer import ChatImportResult
from basic_memory.importers.utils import clean_filename, format_timestamp
logger = logging.getLogger(__name__)
class ClaudeConversationsImporter(Importer[ChatImportResult]):
"""Service for importing Claude conversations."""
async def import_data(
self, source_data, destination_folder: str, **kwargs: Any
) -> ChatImportResult:
"""Import conversations from Claude JSON export.
Args:
source_data: Path to the Claude conversations.json file.
destination_folder: Destination folder within the project.
**kwargs: Additional keyword arguments.
Returns:
ChatImportResult containing statistics and status of the import.
"""
try:
# Ensure the destination folder exists
folder_path = self.ensure_folder_exists(destination_folder)
conversations = source_data
# Process each conversation
messages_imported = 0
chats_imported = 0
for chat in conversations:
# Convert to entity
entity = self._format_chat_content(
base_path=folder_path,
name=chat["name"],
messages=chat["chat_messages"],
created_at=chat["created_at"],
modified_at=chat["updated_at"],
)
# Write file
file_path = self.base_path / Path(f"{entity.frontmatter.metadata['permalink']}.md")
await self.write_entity(entity, file_path)
chats_imported += 1
messages_imported += len(chat["chat_messages"])
return ChatImportResult(
import_count={"conversations": chats_imported, "messages": messages_imported},
success=True,
conversations=chats_imported,
messages=messages_imported,
)
except Exception as e: # pragma: no cover
logger.exception("Failed to import Claude conversations")
return self.handle_error("Failed to import Claude conversations", e) # pyright: ignore [reportReturnType]
def _format_chat_content(
self,
base_path: Path,
name: str,
messages: List[Dict[str, Any]],
created_at: str,
modified_at: str,
) -> EntityMarkdown:
"""Convert chat messages to Basic Memory entity format.
Args:
base_path: Base path for the entity.
name: Chat name.
messages: List of chat messages.
created_at: Creation timestamp.
modified_at: Modification timestamp.
Returns:
EntityMarkdown instance representing the conversation.
"""
# Generate permalink
date_prefix = datetime.fromisoformat(created_at.replace("Z", "+00:00")).strftime("%Y%m%d")
clean_title = clean_filename(name)
permalink = f"{base_path.name}/{date_prefix}-{clean_title}"
# Format content
content = self._format_chat_markdown(
name=name,
messages=messages,
created_at=created_at,
modified_at=modified_at,
permalink=permalink,
)
# Create entity
entity = EntityMarkdown(
frontmatter=EntityFrontmatter(
metadata={
"type": "conversation",
"title": name,
"created": created_at,
"modified": modified_at,
"permalink": permalink,
}
),
content=content,
)
return entity
def _format_chat_markdown(
self,
name: str,
messages: List[Dict[str, Any]],
created_at: str,
modified_at: str,
permalink: str,
) -> str:
"""Format chat as clean markdown.
Args:
name: Chat name.
messages: List of chat messages.
created_at: Creation timestamp.
modified_at: Modification timestamp.
permalink: Permalink for the entity.
Returns:
Formatted markdown content.
"""
# Start with frontmatter and title
lines = [
f"# {name}\n",
]
# Add messages
for msg in messages:
# Format timestamp
ts = format_timestamp(msg["created_at"])
# Add message header
lines.append(f"### {msg['sender'].title()} ({ts})")
# Handle message content
content = msg.get("text", "")
if msg.get("content"):
content = " ".join(c.get("text", "") for c in msg["content"])
lines.append(content)
# Handle attachments
attachments = msg.get("attachments", [])
for attachment in attachments:
if "file_name" in attachment:
lines.append(f"\n**Attachment: {attachment['file_name']}**")
if "extracted_content" in attachment:
lines.append("```")
lines.append(attachment["extracted_content"])
lines.append("```")
# Add spacing between messages
lines.append("")
return "\n".join(lines)

Some files were not shown because too many files have changed in this diff Show More