Compare commits

...

70 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
172 changed files with 27474 additions and 4832 deletions
-190
View File
@@ -1,190 +0,0 @@
# /project:check-health - Project Health Assessment
Comprehensive health check of the Basic Memory project including code quality, test coverage, dependencies, and documentation.
## Usage
```
/project:check-health
```
## Implementation
You are an expert DevOps engineer for the Basic Memory project. When the user runs `/project:check-health`, execute the following comprehensive assessment:
### Step 1: Git Repository Health
1. **Repository Status**
```bash
git status
git log --oneline -5
git branch -vv
```
- Check working directory status
- Verify branch alignment with remote
- Check recent commit activity
2. **Branch Analysis**
- Verify on main branch
- Check if ahead/behind remote
- Identify any untracked files
### Step 2: Code Quality Assessment
1. **Linting and Formatting**
```bash
uv run ruff check .
uv run pyright
```
- Count linting issues by severity
- Check type annotation coverage
- Verify code formatting compliance
2. **Test Suite Health**
```bash
uv run pytest --collect-only -q
uv run pytest --co -q | wc -l
```
- Count total tests
- Check for test discovery issues
- Verify test structure integrity
### Step 3: Dependency Analysis
1. **Dependency Health**
```bash
uv tree
uv lock --dry-run
```
- Check for dependency conflicts
- Identify outdated dependencies
- Verify lock file consistency
2. **Security Scan**
```bash
uv run pip-audit --desc
```
- Scan for known vulnerabilities
- Check dependency licenses
- Identify security advisories
### Step 4: Performance Metrics
1. **Test Performance**
```bash
uv run pytest --durations=10
```
- Identify slowest tests
- Check overall test execution time
- Monitor test suite growth
2. **Build Performance**
```bash
time uv run python -c "import basic_memory"
```
- Check import time
- Validate package installation
- Monitor startup performance
### Step 5: Documentation Health
1. **Documentation Coverage**
- Check README.md currency
- Verify CLI documentation
- Validate MCP tool documentation
- Check changelog completeness
2. **API Documentation**
- Verify docstring coverage
- Check type annotation completeness
- Validate example code
### Step 6: Project Metrics
1. **Code Statistics**
```bash
find src -name "*.py" | xargs wc -l
find tests -name "*.py" | xargs wc -l
```
- Lines of code trends
- Test-to-code ratio
- File organization metrics
## Health Report Format
Generate comprehensive health dashboard:
```
🏥 Basic Memory Project Health Report
📊 OVERALL HEALTH: 🟢 EXCELLENT (92/100)
🗂️ GIT REPOSITORY
✅ Clean working directory
✅ Up to date with origin/main
✅ Recent commit activity (5 commits this week)
🔍 CODE QUALITY
✅ Linting: 0 errors, 2 warnings
✅ Type checking: 100% coverage
✅ Formatting: Compliant
⚠️ Complex functions: 3 need refactoring
🧪 TEST SUITE
✅ Total tests: 744
✅ Test discovery: All tests found
✅ Coverage: 98.2%
⚡ Performance: 45.2s (good)
📦 DEPENDENCIES
✅ Dependencies: Up to date
✅ Security: No vulnerabilities
✅ Conflicts: None detected
⚠️ Outdated: 2 minor updates available
📖 DOCUMENTATION
✅ README: Current
✅ API docs: 95% coverage
⚠️ CLI reference: Needs update
✅ Changelog: Complete
📈 METRICS
├── Source code: 15,432 lines
├── Test code: 8,967 lines
├── Test ratio: 58% (excellent)
└── Complexity: Low (maintainable)
🎯 RECOMMENDATIONS:
1. Update CLI documentation
2. Refactor 3 complex functions
3. Update minor dependencies
4. Consider splitting large test files
🏆 PROJECT STATUS: Ready for v0.13.0 release!
```
## Health Scoring
### Excellent (90-100)
- All quality gates pass
- High test coverage (>95%)
- No security issues
- Documentation current
### Good (75-89)
- Minor issues present
- Good test coverage (>90%)
- No critical security issues
- Most documentation current
### Needs Attention (60-74)
- Several quality issues
- Adequate test coverage (>80%)
- Minor security concerns
- Documentation gaps
### Critical (<60)
- Major quality problems
- Low test coverage (<80%)
- Security vulnerabilities
- Significant documentation issues
## Context
- Provides comprehensive project overview
- Identifies potential issues before they become problems
- Tracks project health trends over time
- Helps prioritize maintenance tasks
- Supports release readiness decisions
-62
View File
@@ -1,62 +0,0 @@
# Basic Memory Custom Commands
This directory contains custom Claude Code slash commands for the Basic Memory project.
## Available Commands
### Release Management (`/project:release:*`)
- `/project:release:beta` - Create beta releases with automated quality checks
- `/project:release:release` - Create stable releases with comprehensive validation
- `/project:release:release-check` - Pre-flight validation without making changes
- `/project:release:changelog` - Generate changelog entries from commits
### Development (`/project:*`)
- `/project:test-coverage` - Run tests with detailed coverage analysis
- `/project:test-live` - Live testing suite using real Basic Memory installation
- `/project:lint-fix` - Run comprehensive linting with auto-fix
- `/project:check-health` - Comprehensive project health assessment
## Command Structure
Commands are organized by functionality:
```
.claude/commands/
├── release/ # Release management commands
│ ├── beta.md # /project:release:beta
│ ├── release.md # /project:release:release
│ ├── release-check.md # /project:release:release-check
│ └── changelog.md # /project:release:changelog
├── test-coverage.md # /project:test-coverage
├── test-live.md # /project:test-live
├── lint-fix.md # /project:lint-fix
├── check-health.md # /project:check-health
└── commands.md # This overview file
```
## Usage
Commands are invoked using the `/project:` prefix:
- `/project:release:beta v0.13.0b4`
- `/project:test-coverage mcp`
- `/project:test-live core`
- `/project:release:release-check`
- `/project:check-health`
## Implementation
Each command is implemented as a Markdown file containing structured prompts that:
1. Validate preconditions
2. Execute steps in the correct order
3. Handle errors gracefully
4. Provide clear status updates
5. Return actionable results
## Tooling Integration
Commands leverage existing project tooling:
- `just check` - Quality checks
- `just test` - Test suite
- `just update-deps` - Dependency updates
- `uv` - Package management
- `git` - Version control
- GitHub Actions - CI/CD pipeline
-145
View File
@@ -1,145 +0,0 @@
# /project:lint-fix - Comprehensive Code Quality Fix
Run comprehensive linting and auto-fix code quality issues across the codebase.
## Usage
```
/project:lint-fix
```
## Implementation
You are an expert code quality engineer for the Basic Memory project. When the user runs `/project:lint-fix`, execute the following steps:
### Step 1: Pre-flight Check
1. **Verify Clean Working Directory**
```bash
git status --porcelain
```
- Check for uncommitted changes
- Warn if working directory is not clean
- Suggest stashing changes if needed
### Step 2: Import Organization
1. **Fix Import Order and Cleanup**
```bash
uv run ruff check --select I --fix .
```
- Sort imports by category (standard, third-party, local)
- Remove unused imports
- Fix import spacing and organization
### Step 3: Code Formatting
1. **Apply Consistent Formatting**
```bash
uv run ruff format .
```
- Format code according to project style
- Fix line length issues (100 chars max)
- Standardize quotes and spacing
### Step 4: Linting with Auto-fix
1. **Fix Linting Issues**
```bash
uv run ruff check --fix .
```
- Auto-fix safe linting issues
- Report any remaining manual fixes needed
- Focus on code quality and best practices
### Step 5: Type Checking
1. **Validate Type Annotations**
```bash
uv run pyright
```
- Check for type errors
- Report any missing type annotations
- Validate type compatibility
### Step 6: Report Generation
Generate comprehensive quality report:
```
🔧 Code Quality Fix Report
✅ FIXES APPLIED:
├── Import organization: 12 files updated
├── Code formatting: 8 files reformatted
├── Auto-fixable lint issues: 23 issues resolved
└── Total files processed: 156
⚠️ MANUAL ATTENTION NEEDED:
├── Type annotations missing in entity_service.py:45
├── Complex function needs refactoring in sync_service.py:123
└── Unused variable in test_utils.py:67
🎯 QUALITY SCORE: 96.2% (excellent)
📁 Run `git diff` to review all changes
```
## Error Handling
### Common Issues
- **Merge Conflicts**: Provide resolution guidance
- **Syntax Errors**: Point to specific files and lines
- **Type Errors**: Suggest specific fixes
- **Import Errors**: Check for missing dependencies
### Recovery Steps
- If auto-fixes introduce issues, provide rollback instructions
- If type checking fails, suggest incremental fixes
- If tests break, provide debugging guidance
## Quality Gates
### Must Pass
- [ ] All auto-fixable lint issues resolved
- [ ] Code formatting consistent
- [ ] No syntax errors
- [ ] Import organization clean
### Should Pass (Warnings)
- [ ] No type checking errors
- [ ] No complex function warnings
- [ ] No unused variables/imports
- [ ] Consistent naming conventions
## Output Examples
### Successful Fix
```
🎉 CODE QUALITY IMPROVED!
✅ All auto-fixes applied successfully
📏 Code formatting: 100% compliant
🔍 Linting: No issues found
🏷️ Type checking: All passed
Ready for commit! Use:
git add -A && git commit -m "style: fix code quality issues"
```
### Issues Requiring Attention
```
⚠️ PARTIAL SUCCESS - MANUAL FIXES NEEDED
✅ Auto-fixes applied: 45 issues
❌ Manual fixes needed: 3 issues
Priority fixes:
1. Fix type annotation in services/entity_service.py:142
2. Simplify complex function in sync/sync_service.py:67
3. Remove unused import in tests/conftest.py:12
Run these commands:
# Fix specific file
uv run pyright src/basic_memory/services/entity_service.py
```
## Context
- Uses ruff for fast Python linting and formatting
- Uses pyright for type checking
- Follows project code style guidelines (100 char line length)
- Maintains backward compatibility
- Integrates with existing pre-commit hooks
+5 -2
View File
@@ -8,7 +8,7 @@ Analyze commits and generate formatted changelog entry for a version.
```
**Parameters:**
- `version` (required): Version like `v0.13.0` or `v0.13.0b4`
- `version` (required): Version like `v0.14.0` or `v0.14.0b1`
- `type` (optional): `beta`, `rc`, or `stable` (default: `stable`)
## Implementation
@@ -59,8 +59,9 @@ You are an expert technical writer for the Basic Memory project. When the user r
### Step 3: Generate Changelog Entry
Create formatted entry following existing CHANGELOG.md style:
Example:
```markdown
## v0.13.0 (2025-06-03)
## <version> (<date>)
### Features
@@ -128,6 +129,8 @@ Create formatted entry following existing CHANGELOG.md style:
## Output Format
### For Beta Releases
Example:
```markdown
## v0.13.0b4 (2025-06-03)
-131
View File
@@ -1,131 +0,0 @@
# /test-coverage - Run Tests with Coverage Analysis
Execute test suite with comprehensive coverage reporting and analysis.
## Usage
```
/test-coverage [pattern]
```
**Parameters:**
- `pattern` (optional): Test pattern to run specific tests (e.g., `test_mcp`, `*integration*`)
## Implementation
You are an expert QA engineer for the Basic Memory project. When the user runs `/test-coverage`, execute the following steps:
### Step 1: Test Execution
1. **Run Tests with Coverage**
```bash
# Full test suite
uv run pytest --cov=basic_memory --cov-report=html --cov-report=term -v
# Or with pattern if provided
uv run pytest tests/*{pattern}* --cov=basic_memory --cov-report=html --cov-report=term -v
```
2. **Generate Coverage Reports**
- Terminal summary with percentages
- HTML report for detailed analysis
- Identify files below coverage threshold
### Step 2: Coverage Analysis
1. **Summary Statistics**
- Overall coverage percentage
- Number of files with 100% coverage
- Files below 95% threshold
- Total lines covered/missed
2. **Detailed Breakdown**
- Coverage by module/package
- Identify untested code paths
- Find missing edge case tests
### Step 3: Report Generation
Generate comprehensive coverage report:
```
🧪 Test Coverage Report
📊 OVERALL COVERAGE: 98.2% (target: 95%+)
✅ EXCELLENT COVERAGE (>95%):
├── basic_memory/mcp/: 99.1%
├── basic_memory/services/: 98.8%
├── basic_memory/repository/: 97.9%
└── basic_memory/api/: 96.2%
⚠️ NEEDS ATTENTION (<95%):
├── basic_memory/sync/: 94.1% (missing 12 lines)
└── basic_memory/importers/: 91.8% (missing 23 lines)
🎯 SPECIFIC GAPS:
├── sync_service.py:142-145 (error handling)
├── importer_base.py:67-70 (edge case)
└── file_utils.py:89 (exception path)
📁 HTML Report: htmlcov/index.html
🚀 Run `open htmlcov/index.html` to view detailed report
```
### Step 4: Actionable Recommendations
1. **Coverage Improvements**
- Suggest specific tests to add
- Identify edge cases to cover
- Recommend integration tests
2. **Quality Insights**
- Highlight well-tested modules
- Point out testing patterns to follow
- Suggest refactoring for testability
## Advanced Analysis
### Performance Metrics
- Test execution time by module
- Slowest tests identification
- Coverage collection overhead
### Integration Coverage
- MCP tool integration tests
- API endpoint coverage
- Database operation coverage
- File system operation coverage
## Output Examples
### Full Coverage Success
```
🎉 EXCELLENT COVERAGE!
📊 Coverage: 98.7% (744 tests passed)
✅ All modules above 95% threshold
🏆 23 files with 100% coverage
⚡ Tests completed in 45.2s
Ready for release! 🚀
```
### Coverage Issues Found
```
⚠️ COVERAGE GAPS DETECTED
📊 Coverage: 92.1% (below 95% target)
❌ 3 modules need attention
🔍 43 uncovered lines found
Priority fixes:
1. Add tests for error handling in sync_service.py
2. Cover edge cases in importer_base.py
3. Test exception paths in file_utils.py
Run specific tests:
uv run pytest tests/sync/ -v
```
## Context
- Uses pytest with coverage plugin
- Generates both terminal and HTML reports
- Focuses on actionable improvement suggestions
- Integrates with existing test infrastructure
- Helps maintain high code quality standards
+265 -80
View File
@@ -1,6 +1,7 @@
# /project:test-live - Live Basic Memory Testing Suite
Execute comprehensive real-world testing of Basic Memory using the installed version, following the methodology in TESTING.md. All test results are recorded as notes in a dedicated test project.
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
```
@@ -8,12 +9,45 @@ Execute comprehensive real-world testing of Basic Memory using the installed ver
```
**Parameters:**
- `phase` (optional): Specific test phase to run (`core`, `features`, `edge`, `workflows`, `stress`, or `all`)
- `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 testing following the TESTING.md methodology:
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
@@ -22,7 +56,13 @@ When the user runs `/project:test-live`, execute comprehensive testing following
- Check version and confirm it's the expected release
- Test MCP connection and tool availability
2. **Test Project Creation**
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.
@@ -34,83 +74,158 @@ Run the bash `date` command to get the current date/time.
Make sure to switch to the newly created project with the `switch_project()` tool.
3. **Baseline Documentation**
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 1: Core Functionality Validation
### Phase 0: Recent Changes Validation (if 'recent' or 'all' phase)
Test all fundamental MCP tools systematically:
Based on recent commit analysis, create targeted test scenarios:
**write_note Tests:**
- Basic note creation with various content types
- Frontmatter handling (tags, custom fields)
- Special characters in titles and content
- Unicode and emoji support
- Empty notes and minimal content
**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
**read_note Tests:**
- Read by title, permalink, memory:// URLs
- Non-existent notes (error handling)
- Notes with complex formatting
- Performance with large notes
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
**view_note Tests:**
- View notes as formatted artifacts (Claude Desktop)
- Title extraction from frontmatter and headings
- Unicode and emoji content in artifacts
- Error handling for non-existent notes
- Artifact display quality and readability
3. **Performance/Enhancement Validation** - For optimizations:
- Establish baseline timing
- Compare with expected improvements
- Test under various load conditions
- Document performance observations
**search_notes Tests:**
- Simple text queries
- Tag-based searches
- Boolean operators and complex queries
- Empty/no results scenarios
- Performance with growing knowledge base
**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
**Recent Activity Tests:**
- Various timeframes ("today", "1 week", "1d")
- Type filtering (if available)
- Empty project scenarios
- Performance with many recent changes
### Phase 1: Core Functionality Validation (Tier 1 Tools)
**Context Building Tests:**
- Different depth levels (1, 2, 3+)
- Various timeframes
- Relation traversal accuracy
- Performance with complex graphs
Test essential MCP tools that form the foundation of Basic Memory:
### Phase 2: v0.13.0 Feature Deep Dive
**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
**Project Management:**
- Create multiple projects dynamically
- Switch between projects mid-conversation
- Cross-project operations
- Project discovery and status
- Default project behavior
- Invalid project handling
**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)
**Advanced Note Editing:**
- `edit_note` with append operations
- Prepend operations
- Find/replace with validation
- Section replacement under headers
- Error scenarios (invalid operations)
- Frontmatter preservation
**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
**File Management:**
- `move_note` within same project
- Move between projects
- Automatic folder creation
- Special characters in paths
- Database consistency validation
- Search index updates after moves
**4. edit_note Tests (Critical):**
- ✅ Append operations preserving frontmatter
- ✅ Prepend operations
- ✅ Find/replace with validation
- ✅ Section replacement under headers
- ⚠️ Error scenarios (invalid operations)
### Phase 3: Edge Case Exploration
**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)
@@ -134,7 +249,7 @@ Test all fundamental MCP tools systematically:
- Rapid successive operations
- Memory usage monitoring
### Phase 4: Real-World Workflow Scenarios
### Phase 5: Real-World Workflow Scenarios
**Meeting Notes Pipeline:**
1. Create meeting notes with action items
@@ -164,7 +279,35 @@ Test all fundamental MCP tools systematically:
4. Update content with edit operations
5. Validate knowledge graph integrity
### Phase 5: Creative Stress Testing
### 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
@@ -180,6 +323,26 @@ Test all fundamental MCP tools systematically:
- 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:
@@ -202,14 +365,14 @@ permalink: test-session-[phase]-[timestamp]
## Test Results
### ✅ Successful Operations
- [timestamp] write_note: Created note with emoji title 📝 #functionality
- [timestamp] search_notes: Boolean query returned 23 results in 0.4s #performance
- [timestamp] edit_note: Append operation preserved frontmatter #reliability
- [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) #performance
- [timestamp] search_notes: Unicode query returned unexpected results #bug
- [timestamp] project switch: Context lost for memory:// URLs #issue
- [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
@@ -353,24 +516,44 @@ For each error discovered:
- 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:**
- v0.13.0 feature verification in real usage
- Edge case discovery beyond unit tests
- Feature verification prioritized by tier importance
- Recent changes validated for regression
- Performance baseline establishment
- Bug identification with reproduction cases
- Bug identification with severity assessment
**Knowledge Base Creation:**
- Comprehensive testing documentation
- Prioritized testing documentation
- Real usage examples for user guides
- Edge case scenarios for future testing
- Recent changes validation records
- Performance insights for optimization
**Development Insights:**
- Prioritized bug fix list
- Tier-based bug priority list
- Recent changes impact assessment
- Enhancement ideas from real usage
- Architecture validation results
- User experience improvement areas
## Post-Test Deliverables
@@ -402,9 +585,11 @@ For each error discovered:
- Add performance benchmarks and targets
## Context
- Uses installed basic-memory version (not development)
- 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 for development team
- Generates actionable insights prioritized by impact
+1 -1
View File
@@ -111,4 +111,4 @@ jobs:
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
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
+3
View File
@@ -57,6 +57,8 @@ jobs:
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
@@ -80,3 +82,4 @@ jobs:
env:
# Personal Access Token with repo scope for homebrew-basic-memory repo
COMMITTER_TOKEN: ${{ secrets.HOMEBREW_TOKEN }}
+12 -3
View File
@@ -14,11 +14,12 @@ on:
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
@@ -35,10 +36,18 @@ jobs:
run: |
pip install uv
- name: Install just
- 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
@@ -54,4 +63,4 @@ jobs:
- name: Run tests
run: |
uv pip install pytest pytest-cov
just test
just test
-14
View File
@@ -1,14 +0,0 @@
{
"mcpServers": {
"basic-memory": {
"command": "uv",
"args": [
"--directory",
"/Users/phernandez/dev/basicmachines/basic-memory",
"run",
"src/basic_memory/cli/main.py",
"mcp"
]
}
}
}
+168 -40
View File
@@ -1,56 +1,184 @@
# CHANGELOG
## v0.13.8 (2025-06-20)
### Features
- **Docker Container Support** - Complete Docker integration with volume mounting for Obsidian directories
([`3269a2f`](https://github.com/basicmachines-co/basic-memory/commit/3269a2f33a7595f6d9e5207924062e2542f46759))
- Docker Compose configuration for easy deployment
- Volume mounting for persistent data and Obsidian integration
- Comprehensive Docker documentation and setup guides
- Streamlined container-based workflow
## v0.14.2 (2025-07-03)
### Bug Fixes
- **#151**: Fix reset command project configuration persistence issue
([`af44941`](https://github.com/basicmachines-co/basic-memory/commit/af44941d5aa57b5ad7fcc6af4ed700f49bdb6d4d))
- Reset command now properly clears project configuration from `~/.basic-memory/config.json`
- Eliminates issue where projects would be recreated after database reset
- Ensures clean slate when resetting Basic Memory installation
- **#204**: Fix MCP Error with MCP-Hub integration
([`3621bb7`](https://github.com/basicmachines-co/basic-memory/commit/3621bb7b4d6ac12d892b18e36bb8f7c9101c7b10))
- Resolve compatibility issues with MCP-Hub
- Improve error handling in project management tools
- Ensure stable MCP tool integration across different environments
- **#148**: Resolve project state inconsistency between MCP and CLI
([`35e4f73`](https://github.com/basicmachines-co/basic-memory/commit/35e4f73ae8a65501da4d48258ed702f957184c92))
- Fix "Project not found" errors when switching default projects
- MCP session now automatically refreshes when project configuration changes
- Eliminates need to restart MCP server after project operations
- Ensures consistent project state across CLI and MCP interfaces
- **Modernize datetime handling and suppress SQLAlchemy warnings**
([`f80ac0e`](https://github.com/basicmachines-co/basic-memory/commit/f80ac0e3e74b7a737a7fc7b956b5c1d61b0c67b8))
- Replace deprecated `datetime.utcnow()` with timezone-aware alternatives
- Suppress SQLAlchemy deprecation warnings for cleaner output
- Improve future compatibility with Python datetime best practices
- **FastMCP Compatibility** - Resolve deprecation warnings for FastMCP integration
([`7be001c`](https://github.com/basicmachines-co/basic-memory/commit/7be001ca6834b3344bb6160cbe537b36bcbaa579))
- Update FastMCP usage patterns to eliminate deprecation warnings
- Improve future compatibility with FastMCP library updates
- Clean up entity repository and service layer code
## v0.14.1 (2025-07-03)
### Bug Fixes
- **#203**: Constrain fastmcp version to prevent breaking changes
([`827f7cf`](https://github.com/basicmachines-co/basic-memory/commit/827f7cf86e7b84c56e7a43bb83f2e5d84a1ad8b8))
- Pin fastmcp to compatible version range to avoid API breaking changes
- Ensure stable MCP server functionality across updates
- Improve dependency management for production deployments
- **#190**: Fix Problems with MCP integration
([`bd4f551`](https://github.com/basicmachines-co/basic-memory/commit/bd4f551a5bb0b7b4d3a5b04de70e08987c6ab2f9))
- Resolve MCP server initialization and communication issues
- Improve error handling and recovery in MCP operations
- Enhance stability for AI assistant integrations
### Features
- **Add Cursor IDE integration button** - One-click setup for Cursor IDE users
([`5360005`](https://github.com/basicmachines-co/basic-memory/commit/536000512294d66090bf87abc8014f4dfc284310))
- Direct installation button for Cursor IDE in README
- Streamlined setup process for Cursor users
- Enhanced developer experience for AI-powered coding
- **Add Homebrew installation instructions** - Official Homebrew tap support
([`39f811f`](https://github.com/basicmachines-co/basic-memory/commit/39f811f8b57dd998445ae43537cd492c680b2e11))
- Official Homebrew formula in basicmachines-co/basic-memory tap
- Simplified installation process for macOS users
- Package manager integration for easier dependency management
## v0.14.0 (2025-06-26)
### Features
- **Docker Container Registry Migration** - Switch from Docker Hub to GitHub Container Registry for better security and integration
([`616c1f0`](https://github.com/basicmachines-co/basic-memory/commit/616c1f0710da59c7098a5f4843d4f017877ff7b2))
- Automated Docker image publishing via GitHub Actions CI/CD pipeline
- Enhanced container security with GitHub's integrated vulnerability scanning
- Streamlined container deployment workflow for production environments
- **Enhanced Search Documentation** - Comprehensive search syntax examples for improved user experience
([`a589f8b`](https://github.com/basicmachines-co/basic-memory/commit/a589f8b894e78cce01eb25656856cfea8785fbbf))
- Detailed examples for Boolean search operators (AND, OR, NOT)
- Advanced search patterns including phrase matching and field-specific queries
- User-friendly documentation for complex search scenarios
- **Cross-Project File Management** - Intelligent move operations with project boundary detection
([`db5ef7d`](https://github.com/basicmachines-co/basic-memory/commit/db5ef7d35cc0894309c7a57b5741c9dd978526d4))
- Automatic detection of cross-project move attempts with helpful guidance
- Clear error messages when attempting unsupported cross-project operations
### Bug Fixes
- **#184**: Preserve permalinks when editing notes without frontmatter permalinks
([`c2f4b63`](https://github.com/basicmachines-co/basic-memory/commit/c2f4b632cf04921b1a3c2f0d43831b80c519cb31))
- Fix permalink preservation during note editing operations
- Ensure consistent permalink handling across different note formats
- Maintain note identity and searchability during incremental edits
- **#183**: Implement project-specific sync status checks for MCP tools
([`12b5152`](https://github.com/basicmachines-co/basic-memory/commit/12b51522bc953fca117fc5bc01fcb29c6ca7e13c))
- Fix sync status reporting to correctly reflect current project state
- Resolve inconsistencies where sync status showed global instead of project-specific information
- Improve project isolation for sync operations and status reporting
- **#180**: Handle Boolean search syntax with hyphenated terms
([`546e3cd`](https://github.com/basicmachines-co/basic-memory/commit/546e3cd8db98b74f746749d41887f8a213cd0b11))
- Fix search parsing issues with hyphenated terms in Boolean queries
- Improve search query tokenization for complex term structures
- Enhanced search reliability for technical documentation and multi-word concepts
- **#174**: Respect BASIC_MEMORY_HOME environment variable in Docker containers
([`9f1db23`](https://github.com/basicmachines-co/basic-memory/commit/9f1db23c78d4648e2c242ad1ee27eed85e3f3b5d))
- Fix Docker container configuration to properly honor custom home directory settings
- Improve containerized deployment flexibility with environment variable support
- Ensure consistent behavior between local and containerized installations
- **#168**: Scope entity queries by project_id in upsert_entity method
([`2a3adc1`](https://github.com/basicmachines-co/basic-memory/commit/2a3adc109a3e4d7ccd65cae4abf63d9bb2338326))
- Fix entity isolation issues in multi-project setups
- Prevent cross-project entity conflicts during database operations
- Strengthen project boundary enforcement at the database level
- **#166**: Handle None from_entity in Context API RelationSummary
([`8a065c3`](https://github.com/basicmachines-co/basic-memory/commit/8a065c32f4e41613207d29aafc952a56e3a52241))
- Fix null pointer exceptions in relation processing
- Improve error handling for incomplete relation data
- Enhanced stability for knowledge graph traversal operations
- **#164**: Remove log level configuration from mcp_server.run()
([`224e4bf`](https://github.com/basicmachines-co/basic-memory/commit/224e4bf9e4438c44a82ffc21bd1a282fe9087690))
- Simplify MCP server startup by removing redundant log level settings
- Fix potential logging configuration conflicts
- Streamline server initialization process
- **#162**: Ensure permalinks are generated for entities with null permalinks during move operations
([`f506507`](https://github.com/basicmachines-co/basic-memory/commit/f50650763dbd4322c132e4bdc959ce4bf074374b))
- Fix move operations for entities without existing permalinks
- Automatic permalink generation during file move operations
- Maintain database consistency during file reorganization
### Technical Improvements
- **Comprehensive Integration Testing** - New test suites for critical user workflows
- Full integration tests for database reset functionality
- End-to-end project state synchronization testing
- Real MCP client-server communication validation
- Direct config file validation without complex mocking
- **Comprehensive Test Coverage** - Extensive test suites for new features and edge cases
- Enhanced test coverage for project-specific sync status functionality
- Additional test scenarios for search syntax validation and edge cases
- Integration tests for Docker CI workflow and container publishing
- Comprehensive move operations testing with project boundary validation
- **Code Quality** - Enhanced error handling and validation
- Improved project state management across system components
- Better session refresh patterns for configuration changes
- Streamlined Docker setup with reduced image size
- **Docker CI/CD Pipeline** - Production-ready automated container publishing
([`74847cc`](https://github.com/basicmachines-co/basic-memory/commit/74847cc3807b0c6ed511e0d83e0d560e9f07ec44))
- Automated Docker image building and publishing on release
- Multi-architecture container support for AMD64 and ARM64 platforms
- Integrated security scanning and vulnerability assessments
- Streamlined deployment pipeline for production environments
### Documentation
- **Release Process Improvements** - Enhanced automation and quality gates
([`a52ce1c`](https://github.com/basicmachines-co/basic-memory/commit/a52ce1c8605ec2cd450d1f909154172cbc30faa2))
- Homebrew formula updates limited to stable releases only
- Improved release automation with better quality control
- Enhanced CI/CD pipeline reliability and error handling
- **Docker Integration Guide** - Complete documentation for container deployment
- Step-by-step Docker Compose setup instructions
- Volume mounting configuration for Obsidian workflows
- Container-based development environment setup
- **Code Quality Enhancements** - Improved error handling and validation
- Better null safety in entity and relation processing
- Enhanced project isolation validation throughout the codebase
- Improved error messages and user guidance for edge cases
- Strengthened database consistency guarantees across operations
### Infrastructure
- **GitHub Container Registry Integration** - Modern container infrastructure
- Migration from Docker Hub to GitHub Container Registry (ghcr.io)
- Improved security with integrated vulnerability scanning
- Better integration with GitHub-based development workflow
- Enhanced container versioning and artifact management
- **Enhanced CI/CD Workflows** - Robust automated testing and deployment
- Automated Docker image publishing on releases
- Comprehensive test coverage validation before deployment
- Multi-platform container building and publishing
- Integration with GitHub's security and monitoring tools
### Migration Guide
This release includes several behind-the-scenes improvements and fixes. All changes are backward compatible:
- **Docker Users**: Container images now served from `ghcr.io/basicmachines-co/basic-memory` instead of Docker Hub
- **Search Users**: Enhanced search syntax handling - existing queries continue to work unchanged
- **Multi-Project Users**: Improved project isolation - all existing projects remain fully functional
- **All Users**: Enhanced stability and error handling - no breaking changes to existing workflows
### Installation
```bash
# Latest stable release
uv tool install basic-memory
# Update existing installation
uv tool upgrade basic-memory
# Docker (new registry)
docker pull ghcr.io/basicmachines-co/basic-memory:latest
```
## v0.13.7 (2025-06-19)
+63 -26
View File
@@ -1,34 +1,71 @@
Developer Certificate of Origin
Version 1.1
https://developercertificate.org/
# Contributor License Agreement
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
## Copyright Assignment and License Grant
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
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.
Developer's Certificate of Origin 1.1
### 1. Definitions
By making a contribution to this project, I certify that:
"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.
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
"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").
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
### 2. Grant of Copyright License
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
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.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
### 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.
+32 -116
View File
@@ -14,15 +14,15 @@ See the [README.md](README.md) file for a project overview.
### Build and Test Commands
- Install: `just install` or `pip install -e ".[dev]"`
- Run tests: `uv run pytest -p pytest_mock -v` or `just test`
- 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: `just lint` or `ruff check . --fix`
- Type check: `just type-check` or `uv run pyright`
- Format: `just format` or `uv run ruff format .`
- Run all code checks: `just check` (runs lint, format, type-check, test)
- Create db migration: `just migration "Your migration message"`
- Run development MCP Inspector: `just run-inspector`
- 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
@@ -37,7 +37,6 @@ See the [README.md](README.md) file for a project overview.
- API uses FastAPI for endpoints
- Follow the repository pattern for data access
- Tools communicate to api routers via the httpx ASGI client (in process)
- avoid using "private" functions in modules or classes (prepended with _)
### Codebase Architecture
@@ -65,7 +64,6 @@ See the [README.md](README.md) file for a project overview.
- 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
- Do not use mocks in tests if possible. Tests run with an in memory sqlite db, so they are not needed. See fixtures in conftest.py
## BASIC MEMORY PRODUCT USAGE
@@ -97,29 +95,18 @@ See the [README.md](README.md) file for a project overview.
**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
- `edit_note(identifier, operation, content)` - Edit notes incrementally (append, prepend, find/replace, section replace)
- `move_note(identifier, destination_path)` - Move notes with database consistency and search reindexing
- `view_note(identifier)` - Display notes as formatted artifacts for better readability in Claude Desktop
- `read_content(path)` - Read raw file content (text, images, binaries) without knowledge graph processing
- `delete_note(identifier)` - Delete notes from knowledge base
**Project Management:**
- `list_memory_projects()` - List all available projects with status indicators
- `switch_project(project_name)` - Switch to different project context during conversations
- `get_current_project()` - Show currently active project with statistics
- `create_memory_project(name, path, set_default)` - Create new Basic Memory projects
- `delete_project(name)` - Delete projects from configuration and database
- `set_default_project(name)` - Set default project in config
- `sync_status()` - Check file synchronization status and background operations
- `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")
- `list_directory(dir_name, depth, file_name_glob)` - List directory contents with filtering and depth control
- `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_notes(query, page, page_size)` - Full-text search across all content with filtering options
- `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
@@ -127,7 +114,7 @@ See the [README.md](README.md) file for a project overview.
- MCP Prompts for better AI interaction:
- `ai_assistant_guide()` - Guidance on effectively using Basic Memory tools for AI assistants
- `continue_conversation(topic, timeframe)` - Continue previous conversations with relevant historical context
- `search_notes(query, after_date)` - Search with detailed, formatted results for better context understanding
- `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
@@ -147,32 +134,30 @@ could achieve independently.
## GitHub Integration
Basic Memory uses Claude directly into the development workflow through GitHub:
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:
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
- 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
- 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
- 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.
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
@@ -183,73 +168,4 @@ With GitHub integration, the development workflow includes:
3. **Branch management** - Claude can create feature branches for implementations
4. **Documentation maintenance** - Claude can keep documentation updated as the code evolves
With this integration, the AI assistant is a full-fledged team member rather than just a tool for generating code
snippets.
### Basic Memory Pro
Basic Memory Pro is a desktop GUI application that wraps the basic-memory CLI/MCP tools:
- Built with Tauri (Rust), React (TypeScript), and a Python FastAPI sidecar
- Provides visual knowledge graph exploration and project management
- Uses the same core codebase but adds a desktop-friendly interface
- Project configuration is shared between CLI and Pro versions
- Multiple project support with visual switching interface
local repo: /Users/phernandez/dev/basicmachines/basic-memory-pro
github: https://github.com/basicmachines-co/basic-memory-pro
## Release and Version Management
Basic Memory uses `uv-dynamic-versioning` for automatic version management based on git tags:
### Version Types
- **Development versions**: Automatically generated from commits (e.g., `0.12.4.dev26+468a22f`)
- **Beta releases**: Created by tagging with beta suffixes (e.g., `v0.13.0b1`, `v0.13.0rc1`)
- **Stable releases**: Created by tagging with version numbers (e.g., `v0.13.0`)
### Release Workflows
#### Development Builds (Automatic)
- Triggered on every push to `main` branch
- Publishes dev versions like `0.12.4.dev26+468a22f` to PyPI
- Allows continuous testing of latest changes
- Users install with: `pip install basic-memory --pre --force-reinstall`
#### Beta/RC Releases (Manual)
- Create beta tag: `git tag v0.13.0b1 && git push origin v0.13.0b1`
- Automatically builds and publishes to PyPI as pre-release
- Users install with: `pip install basic-memory --pre`
- Use for milestone testing before stable release
#### Stable Releases (Automated)
- Use the automated release system: `just release v0.13.0`
- Includes comprehensive quality checks (lint, format, type-check, tests)
- Automatically updates version in `__init__.py`
- Creates git tag and pushes to GitHub
- Triggers GitHub Actions workflow for:
- PyPI publication
- Homebrew formula update (requires HOMEBREW_TOKEN secret)
**Manual method (legacy):**
- Create version tag: `git tag v0.13.0 && git push origin v0.13.0`
#### Homebrew Formula Updates
- Automatically triggered after successful PyPI release
- Updates formula in `basicmachines-co/homebrew-basic-memory` repo
- Requires `HOMEBREW_TOKEN` secret in GitHub repository settings:
- Create a fine-grained Personal Access Token with `Contents: Read and Write` and `Actions: Read` scopes on `basicmachines-co/homebrew-basic-memory`
- Add as repository secret named `HOMEBREW_TOKEN` in `basicmachines-co/basic-memory`
- Formula updates include new version URL and SHA256 checksum
### For Development
- **Automated releases**: Use `just release v0.13.x` for stable releases and `just beta v0.13.0b1` for beta releases
- **Quality gates**: All releases require passing lint, format, type-check, and test suites
- **Version management**: Versions automatically derived from git tags via `uv-dynamic-versioning`
- **Configuration**: `pyproject.toml` uses `dynamic = ["version"]`
- **Release automation**: `__init__.py` updated automatically during release process
- **CI/CD**: GitHub Actions handles building and PyPI publication
## Development Notes
- make sure you sign off on commits
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.
+6 -1
View File
@@ -27,7 +27,12 @@ project and how to get started as a developer.
> **Note**: Basic Memory uses [just](https://just.systems) as a modern command runner. Install with `brew install just` or `cargo install just`.
3. **Run the Tests**:
3. **Activate the Virtual Environment**
```bash
source .venv/bin/activate
```
4. **Run the Tests**:
```bash
# Run all tests
just test
+15 -2
View File
@@ -1,5 +1,9 @@
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/
@@ -7,6 +11,11 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
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
@@ -14,13 +23,17 @@ ADD . /app
WORKDIR /app
RUN uv sync --locked
# Create data directory
RUN mkdir -p /app/data
# 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
+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.
+18 -78
View File
@@ -13,11 +13,8 @@ Basic Memory lets you build persistent knowledge through natural conversations w
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.
- Website: https://basicmemory.com
- Company: https://basicmachines.co
- Website: https://basicmachines.co
- Documentation: https://memory.basicmachines.co
- Discord: https://discord.gg/tyvKNccgqN
- YouTube: https://www.youtube.com/@basicmachines-co
## Pick up your conversation right where you left off
@@ -64,7 +61,8 @@ Memory for Claude Desktop:
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. Note: The Smithery installation uses their hosted MCP server, while your data remains stored locally as Markdown files.
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
@@ -155,8 +153,7 @@ The note embeds semantic content and links to other topics via simple Markdown f
3. You see this file on your computer in real time in the current project directory (default `~/$HOME/basic-memory`).
- Realtime sync is enabled by default starting with v0.12.0
- Project switching during conversations is supported starting with v0.13.0
- Realtime sync can be enabled via running `basic-memory sync --watch`
4. In a chat with the LLM, you can reference a topic:
@@ -266,13 +263,6 @@ Examples of relations:
```
## Using with VS Code
For one-click installation, click one of the install buttons below...
[![Install with UV in VS Code](https://img.shields.io/badge/VS_Code-UV-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=basic-memory&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22basic-memory%22%2C%22mcp%22%5D%7D) [![Install with UV in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-UV-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=basic-memory&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22basic-memory%22%2C%22mcp%22%5D%7D&quality=insiders)
You can use Basic Memory with VS Code to easily retrieve and store information while coding. Click the installation buttons above for one-click setup, or follow the manual installation instructions below.
### Manual Installation
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)`.
@@ -302,6 +292,8 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
}
```
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/):
@@ -325,8 +317,7 @@ for OS X):
}
```
If you want to use a specific project (see [Multiple Projects](docs/User%20Guide.md#multiple-projects)), update your
Claude Desktop
If you want to use a specific project (see [Multiple Projects](#multiple-projects) below), update your Claude Desktop
config:
```json
@@ -336,9 +327,9 @@ config:
"command": "uvx",
"args": [
"basic-memory",
"mcp",
"--project",
"your-project-name",
"mcp"
"your-project-name"
]
}
}
@@ -347,27 +338,23 @@ config:
2. Sync your knowledge:
Basic Memory will sync the files in your project in real time if you make manual edits.
```bash
# One-time sync of local knowledge updates
basic-memory sync
# Run realtime sync process (recommended)
basic-memory sync --watch
```
3. In Claude Desktop, the LLM can now use these tools:
```
write_note(title, content, folder, tags) - Create or update notes
read_note(identifier, page, page_size) - Read notes by title or permalink
edit_note(identifier, operation, content) - Edit notes incrementally (append, prepend, find/replace)
move_note(identifier, destination_path) - Move notes with database consistency
view_note(identifier) - Display notes as formatted artifacts for better readability
build_context(url, depth, timeframe) - Navigate knowledge graph via memory:// URLs
search_notes(query, page, page_size) - Search across your knowledge base
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
list_memory_projects() - List all available projects with status
switch_project(project_name) - Switch to different project context
get_current_project() - Show current project and statistics
create_memory_project(name, path, set_default) - Create new projects
delete_project(name) - Delete projects from configuration
set_default_project(name) - Set default project
sync_status() - Check file synchronization status
```
5. Example prompts to try:
@@ -378,10 +365,6 @@ sync_status() - Check file synchronization status
"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?"
"Switch to my work-notes project"
"List all my available projects"
"Edit my coffee brewing note to add a new technique"
"Move my old meeting notes to the archive folder"
```
## Futher info
@@ -393,49 +376,6 @@ See the [Documentation](https://memory.basicmachines.co/) for more info, includi
- [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)
## Installation Options
### Stable Release
```bash
pip install basic-memory
```
### Beta/Pre-releases
```bash
pip install basic-memory --pre
```
### Development Builds
Development versions are automatically published on every commit to main with versions like `0.12.4.dev26+468a22f`:
```bash
pip install basic-memory --pre --force-reinstall
```
### Docker
Run Basic Memory in a container with volume mounting for your Obsidian vault:
```bash
# Clone and start with Docker Compose
git clone https://github.com/basicmachines-co/basic-memory.git
cd basic-memory
# Edit docker-compose.yml to point to your Obsidian vault
# Then start the container
docker-compose up -d
```
Or use Docker directly:
```bash
docker run -d \
--name basic-memory-server \
-v /path/to/your/obsidian-vault:/data/knowledge:rw \
-v basic-memory-config:/root/.basic-memory:rw \
ghcr.io/basicmachines-co/basic-memory:latest
```
See [Docker Setup Guide](docs/Docker.md) for detailed configuration options, multiple project setup, and integration examples.
## License
AGPL-3.0
@@ -453,4 +393,4 @@ and submitting PRs.
</picture>
</a>
Built with ♥️ by Basic Machines
Built with ♥️ by Basic Machines
+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()
+47 -16
View File
@@ -15,7 +15,7 @@ Basic Memory provides pre-built Docker images on GitHub Container Registry that
--name basic-memory-server \
-p 8000:8000 \
-v /path/to/your/obsidian-vault:/app/data:rw \
-v basic-memory-config:/root/.basic-memory:rw \
-v basic-memory-config:/app/.basic-memory:rw \
ghcr.io/basicmachines-co/basic-memory:latest
```
@@ -30,7 +30,7 @@ Basic Memory provides pre-built Docker images on GitHub Container Registry that
- "8000:8000"
volumes:
- /path/to/your/obsidian-vault:/app/data:rw
- basic-memory-config:/root/.basic-memory:rw
- basic-memory-config:/app/.basic-memory:rw
environment:
- BASIC_MEMORY_DEFAULT_PROJECT=main
restart: unless-stopped
@@ -67,7 +67,7 @@ docker build -t basic-memory .
docker run -d \
--name basic-memory-server \
-v /path/to/your/obsidian-vault:/app/data:rw \
-v basic-memory-config:/root/.basic-memory:rw \
-v basic-memory-config:/app/.basic-memory:rw \
-e BASIC_MEMORY_DEFAULT_PROJECT=main \
basic-memory
```
@@ -86,11 +86,11 @@ Basic Memory requires several volume mounts for proper operation:
2. **Configuration and Database** (Recommended):
```yaml
- basic-memory-config:/root/.basic-memory:rw
- 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 /root/.basic-memory/config.json after Basic Memory starts.
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
@@ -98,7 +98,7 @@ You can edit the basic-memory config.json file located in the /root/.basic-memor
- /path/to/project2:/app/data/project2:rw
```
You can edit the basic-memory config.json file located in the /root/.basic-memory/config.json
You can edit the basic-memory config.json file located in the /app/.basic-memory/config.json
## CLI Commands via Docker
@@ -123,7 +123,7 @@ When using Docker volumes, you'll need to configure projects to point to your mo
1. **Check current configuration:**
```bash
docker exec basic-memory-server cat /root/.basic-memory/config.json
docker exec basic-memory-server cat /app/.basic-memory/config.json
```
2. **Add a project for your mounted volume:**
@@ -184,16 +184,47 @@ environment:
### Linux/macOS
Ensure your knowledge directories have proper permissions:
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
# Make directories readable/writable
chmod -R 755 /path/to/your/obsidian-vault
# Build with custom UID/GID to match your user
docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) -t basic-memory .
# If using specific user/group
chown -R $USER:$USER /path/to/your/obsidian-vault
# 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:
@@ -217,7 +248,7 @@ When using Docker Desktop on Windows, ensure the directories are shared:
```
2. **Configuration Not Persisting:**
- Use named volumes for `/root/.basic-memory`
- Use named volumes for `/app/.basic-memory`
- Check volume mount permissions
3. **Network Connectivity:**
@@ -243,10 +274,10 @@ docker-compose logs -f basic-memory
## Security Considerations
1. **Docker Security:**
The container runs as root for simplicity. For production, consider additional security measures.
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.
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
@@ -288,7 +319,7 @@ 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 /root`
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/).
+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.
+5 -2
View File
@@ -3,6 +3,9 @@
# 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:
@@ -17,7 +20,7 @@ test: test-unit test-int
# Lint and fix code
lint:
ruff check . --fix
uv run ruff check . --fix
# Type check code
type-check:
@@ -179,4 +182,4 @@ beta version:
# List all available recipes
default:
@just --list
@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 |
+3 -3
View File
@@ -30,7 +30,7 @@ dependencies = [
"alembic>=1.14.1",
"pillow>=11.1.0",
"pybars3>=0.9.7",
"fastmcp>=2.3.4",
"fastmcp==2.10.2",
"pyjwt>=2.10.1",
"python-dotenv>=1.1.0",
"pytest-aio>=1.9.0",
@@ -52,7 +52,7 @@ 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"
@@ -123,4 +123,4 @@ omit = [
]
[tool.logfire]
ignore_no_config = true
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()
+1 -1
View File
@@ -1,7 +1,7 @@
"""basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
# Package version - updated by release automation
__version__ = "0.13.7"
__version__ = "0.14.4"
# API version for FastAPI - independent of package version
__api_version__ = "v0"
+3 -1
View File
@@ -8,17 +8,19 @@ from sqlalchemy import pool
from alembic import context
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.config import app_config # 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)
@@ -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")
+4 -1
View File
@@ -20,15 +20,18 @@ from basic_memory.api.routers import (
search,
prompt_router,
)
from basic_memory.config import app_config
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")
print(f"fastapi {app_config.projects}")
await initialize_app(app_config)
logger.info(f"Sync changes enabled: {app_config.sync_changes}")
@@ -6,7 +6,7 @@ from fastapi import APIRouter, Request
from loguru import logger
from pydantic import BaseModel
from basic_memory.config import app_config
from basic_memory.config import ConfigManager
from basic_memory.deps import SyncServiceDep, ProjectRepositoryDep
router = APIRouter(prefix="/management", tags=["management"])
@@ -41,6 +41,8 @@ async def start_watch_service(
# 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")
+21 -13
View File
@@ -1,5 +1,6 @@
"""Router for project management."""
import os
from fastapi import APIRouter, HTTPException, Path, Body
from typing import Optional
@@ -32,40 +33,47 @@ async def get_project_info(
@project_router.patch("/{name}", response_model=ProjectStatusResponse)
async def update_project(
project_service: ProjectServiceDep,
project_name: str = Path(..., description="Name of the project to update"),
path: Optional[str] = Body(None, description="New path for the project"),
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:
project_name: The name of the project to update
path: Optional new path for the project
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: # pragma: no cover
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=project_name,
path=project_service.projects.get(project_name, ""),
name=name,
path=project_service.projects.get(name, ""),
)
await project_service.update_project(project_name, updated_path=path, is_active=is_active)
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(project_name, "")
updated_path = path if path else project_service.projects.get(name, "")
return ProjectStatusResponse(
message=f"Project '{project_name}' updated successfully",
message=f"Project '{name}' updated successfully",
status="success",
default=(project_name == project_service.default_project),
default=(name == project_service.default_project),
old_project=old_project_info,
new_project=ProjectItem(name=project_name, path=updated_path),
new_project=ProjectItem(name=name, path=updated_path),
)
except ValueError as e: # pragma: no cover
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@@ -188,7 +188,7 @@ async def write_resource(
"content_type": content_type,
"file_path": file_path,
"checksum": checksum,
"updated_at": datetime.fromtimestamp(file_stats.st_mtime),
"updated_at": datetime.fromtimestamp(file_stats.st_mtime).astimezone(),
},
)
status_code = 200
@@ -200,8 +200,8 @@ async def write_resource(
content_type=content_type,
file_path=file_path,
checksum=checksum,
created_at=datetime.fromtimestamp(file_stats.st_ctime),
updated_at=datetime.fromtimestamp(file_stats.st_mtime),
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
+1 -1
View File
@@ -52,7 +52,7 @@ async def to_graph_context(
file_path=item.file_path,
permalink=item.permalink, # pyright: ignore
relation_type=item.relation_type, # pyright: ignore
from_entity=from_entity.title, # 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,
)
+3 -3
View File
@@ -2,7 +2,7 @@ from typing import Optional
import typer
from basic_memory.config import get_project_config
from basic_memory.config import get_project_config, ConfigManager
from basic_memory.mcp.project_session import session
@@ -10,8 +10,8 @@ def version_callback(value: bool) -> None:
"""Show version and exit."""
if value: # pragma: no cover
import basic_memory
from basic_memory.config import config
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}")
@@ -44,9 +44,9 @@ def app_callback(
# Run initialization for every command unless --version was specified
if not version and ctx.invoked_subcommand is not None:
from basic_memory.config import app_config
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
+1 -2
View File
@@ -1,10 +1,9 @@
"""CLI commands for basic-memory."""
from . import auth, status, sync, db, import_memory_json, mcp, import_claude_conversations
from . import status, sync, db, import_memory_json, mcp, import_claude_conversations
from . import import_claude_projects, import_chatgpt, tool, project
__all__ = [
"auth",
"status",
"sync",
"db",
-136
View File
@@ -1,136 +0,0 @@
"""OAuth management commands."""
import typer
from typing import Optional
from pydantic import AnyHttpUrl
from basic_memory.cli.app import app
from basic_memory.mcp.auth_provider import BasicMemoryOAuthProvider
from mcp.shared.auth import OAuthClientInformationFull
auth_app = typer.Typer(help="OAuth client management commands")
app.add_typer(auth_app, name="auth")
@auth_app.command()
def register_client(
client_id: Optional[str] = typer.Option(
None, help="Client ID (auto-generated if not provided)"
),
client_secret: Optional[str] = typer.Option(
None, help="Client secret (auto-generated if not provided)"
),
issuer_url: str = typer.Option("http://localhost:8000", help="OAuth issuer URL"),
):
"""Register a new OAuth client for Basic Memory MCP server."""
# Create provider instance
provider = BasicMemoryOAuthProvider(issuer_url=issuer_url)
# Create client info with required redirect_uris
client_info = OAuthClientInformationFull(
client_id=client_id or "", # Provider will generate if empty
client_secret=client_secret or "", # Provider will generate if empty
redirect_uris=[AnyHttpUrl("http://localhost:8000/callback")], # Default redirect URI
client_name="Basic Memory OAuth Client",
grant_types=["authorization_code", "refresh_token"],
)
# Register the client
import asyncio
asyncio.run(provider.register_client(client_info))
typer.echo("Client registered successfully!")
typer.echo(f"Client ID: {client_info.client_id}")
typer.echo(f"Client Secret: {client_info.client_secret}")
typer.echo("\nSave these credentials securely - the client secret cannot be retrieved later.")
@auth_app.command()
def test_auth(
issuer_url: str = typer.Option("http://localhost:8000", help="OAuth issuer URL"),
):
"""Test OAuth authentication flow.
IMPORTANT: Use the same FASTMCP_AUTH_SECRET_KEY environment variable
as your MCP server for tokens to validate correctly.
"""
import asyncio
import secrets
from mcp.server.auth.provider import AuthorizationParams
from pydantic import AnyHttpUrl
async def test_flow():
# Create provider with same secret key as server
provider = BasicMemoryOAuthProvider(issuer_url=issuer_url)
# Register a test client
client_info = OAuthClientInformationFull(
client_id=secrets.token_urlsafe(16),
client_secret=secrets.token_urlsafe(32),
redirect_uris=[AnyHttpUrl("http://localhost:8000/callback")],
client_name="Test OAuth Client",
grant_types=["authorization_code", "refresh_token"],
)
await provider.register_client(client_info)
typer.echo(f"Registered test client: {client_info.client_id}")
# Get the client
client = await provider.get_client(client_info.client_id)
if not client:
typer.echo("Error: Client not found after registration", err=True)
return
# Create authorization request
auth_params = AuthorizationParams(
state="test-state",
scopes=["read", "write"],
code_challenge="test-challenge",
redirect_uri=AnyHttpUrl("http://localhost:8000/callback"),
redirect_uri_provided_explicitly=True,
)
# Get authorization URL
auth_url = await provider.authorize(client, auth_params)
typer.echo(f"Authorization URL: {auth_url}")
# Extract auth code from URL
from urllib.parse import urlparse, parse_qs
parsed = urlparse(auth_url)
params = parse_qs(parsed.query)
auth_code = params.get("code", [None])[0]
if not auth_code:
typer.echo("Error: No authorization code in URL", err=True)
return
# Load the authorization code
code_obj = await provider.load_authorization_code(client, auth_code)
if not code_obj:
typer.echo("Error: Invalid authorization code", err=True)
return
# Exchange for tokens
token = await provider.exchange_authorization_code(client, code_obj)
typer.echo(f"Access token: {token.access_token}")
typer.echo(f"Refresh token: {token.refresh_token}")
typer.echo(f"Expires in: {token.expires_in} seconds")
# Validate access token
access_token_obj = await provider.load_access_token(token.access_token)
if access_token_obj:
typer.echo("Access token validated successfully!")
typer.echo(f"Client ID: {access_token_obj.client_id}")
typer.echo(f"Scopes: {access_token_obj.scopes}")
else:
typer.echo("Error: Invalid access token", err=True)
asyncio.run(test_flow())
if __name__ == "__main__":
auth_app()
+5 -5
View File
@@ -1,14 +1,13 @@
"""Database management commands."""
import asyncio
from pathlib import Path
import typer
from loguru import logger
from basic_memory import db
from basic_memory.cli.app import app
from basic_memory.config import app_config, config_manager
from basic_memory.config import ConfigManager, BasicMemoryConfig, save_basic_memory_config
@app.command()
@@ -18,6 +17,8 @@ def reset(
"""Reset database (drop all tables and recreate)."""
if typer.confirm("This will delete all data in your db. Are you sure?"):
logger.info("Resetting database...")
config_manager = ConfigManager()
app_config = config_manager.config
# Get database path
db_path = app_config.app_database_path
@@ -27,9 +28,8 @@ def reset(
logger.info(f"Database file deleted: {db_path}")
# Reset project configuration
config_manager.config.projects = {"main": str(Path.home() / "basic-memory")}
config_manager.config.default_project = "main"
config_manager.save_config(config_manager.config)
config = BasicMemoryConfig()
save_basic_memory_config(config_manager.config_file, config)
logger.info("Project configuration reset to default")
# Create a new empty database
@@ -7,7 +7,7 @@ from typing import Annotated
import typer
from basic_memory.cli.app import import_app
from basic_memory.config import config
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
@@ -19,6 +19,7 @@ console = Console()
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@@ -49,7 +50,7 @@ def import_chatgpt(
# 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}")
@@ -7,7 +7,7 @@ from typing import Annotated
import typer
from basic_memory.cli.app import claude_app
from basic_memory.config import config
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
@@ -19,6 +19,7 @@ console = Console()
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@@ -42,6 +43,7 @@ def import_claude(
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)
@@ -7,7 +7,7 @@ from typing import Annotated
import typer
from basic_memory.cli.app import claude_app
from basic_memory.config import config
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
@@ -19,6 +19,7 @@ console = Console()
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@@ -41,6 +42,7 @@ def import_projects(
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)
@@ -7,7 +7,7 @@ from typing import Annotated
import typer
from basic_memory.cli.app import import_app
from basic_memory.config import config
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
@@ -19,6 +19,7 @@ console = Console()
async def get_markdown_processor() -> MarkdownProcessor:
"""Get MarkdownProcessor instance."""
config = get_project_config()
entity_parser = EntityParser(config.home)
return MarkdownProcessor(entity_parser)
@@ -46,6 +47,7 @@ def memory_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())
@@ -74,7 +76,8 @@ def memory_json(
Panel(
f"[green]Import complete![/green]\n\n"
f"Created {result.entities} entities\n"
f"Added {result.relations} relations",
f"Added {result.relations} relations\n"
f"Skipped {result.skipped_entities} entities\n",
expand=False,
)
)
+3 -16
View File
@@ -4,6 +4,7 @@ import asyncio
import typer
from basic_memory.cli.app import app
from basic_memory.config import ConfigManager
# Import mcp instance
from basic_memory.mcp.server import mcp as mcp_server # pragma: no cover
@@ -34,26 +35,13 @@ def mcp(
- sse: Server-Sent Events (for compatibility with existing clients)
"""
# Check if OAuth is enabled
import os
auth_enabled = os.getenv("FASTMCP_AUTH_ENABLED", "false").lower() == "true"
if auth_enabled:
logger.info("OAuth authentication is ENABLED")
logger.info(f"Issuer URL: {os.getenv('FASTMCP_AUTH_ISSUER_URL', 'http://localhost:8000')}")
if os.getenv("FASTMCP_AUTH_REQUIRED_SCOPES"):
logger.info(f"Required scopes: {os.getenv('FASTMCP_AUTH_REQUIRED_SCOPES')}")
else:
logger.info("OAuth authentication is DISABLED")
from basic_memory.config import app_config
from basic_memory.services.initialization import initialize_file_sync
# Start the MCP server with the specified transport
# 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()
@@ -78,7 +66,6 @@ def mcp(
if transport == "stdio":
mcp_server.run(
transport=transport,
log_level="INFO",
)
elif transport == "streamable-http" or transport == "sse":
mcp_server.run(
+46 -6
View File
@@ -24,6 +24,7 @@ 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()
@@ -73,7 +74,7 @@ def add_project(
) -> None:
"""Add a new project."""
# Resolve to absolute path
resolved_path = os.path.abspath(os.path.expanduser(path))
resolved_path = Path(os.path.abspath(os.path.expanduser(path))).as_posix()
try:
data = {"name": name, "path": resolved_path, "set_default": set_default}
@@ -99,8 +100,8 @@ def remove_project(
) -> None:
"""Remove a project from configuration."""
try:
project_name = generate_permalink(name)
response = asyncio.run(call_delete(client, f"/projects/{project_name}"))
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]")
@@ -118,9 +119,8 @@ def set_default_project(
) -> None:
"""Set the default project and activate it for the current session."""
try:
project_name = generate_permalink(name)
response = asyncio.run(call_put(client, f"/projects/{project_name}/default"))
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]")
@@ -148,6 +148,46 @@ def synchronize_projects() -> None:
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"),
+4 -1
View File
@@ -12,7 +12,7 @@ from rich.tree import Tree
from basic_memory import db
from basic_memory.cli.app import app
from basic_memory.cli.commands.sync import get_sync_service
from basic_memory.config import config, app_config
from basic_memory.config import ConfigManager, get_project_config
from basic_memory.repository import ProjectRepository
from basic_memory.sync.sync_service import SyncReport
@@ -126,6 +126,9 @@ async def run_status(verbose: bool = False): # pragma: no cover
"""Check sync status of files vs database."""
# Check knowledge/ directory
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
)
+10 -2
View File
@@ -13,7 +13,7 @@ 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.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
@@ -29,7 +29,6 @@ from basic_memory.services.link_resolver import LinkResolver
from basic_memory.services.search_service import SearchService
from basic_memory.sync import SyncService
from basic_memory.sync.sync_service import SyncReport
from basic_memory.config import app_config
console = Console()
@@ -42,6 +41,8 @@ class ValidationIssue:
async def get_sync_service(project: Project) -> SyncService: # pragma: no cover
"""Get sync service instance with all dependencies."""
app_config = ConfigManager().config
_, session_maker = await db.get_or_create_db(
db_path=app_config.database_path, db_type=db.DatabaseType.FILESYSTEM
)
@@ -96,6 +97,7 @@ 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."""
config = get_project_config()
total_changes = knowledge.total
project_name = config.project
@@ -124,6 +126,7 @@ def display_sync_summary(knowledge: SyncReport):
def display_detailed_sync_results(knowledge: SyncReport):
"""Display detailed sync results with trees."""
config = get_project_config()
project_name = config.project
if knowledge.total == 0:
@@ -158,6 +161,9 @@ def display_detailed_sync_results(knowledge: SyncReport):
async def run_sync(verbose: bool = False):
"""Run sync operation."""
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
)
@@ -212,6 +218,8 @@ def 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}")
-1
View File
@@ -4,7 +4,6 @@ from basic_memory.cli.app import app # pragma: no cover
# Register commands
from basic_memory.cli.commands import ( # noqa: F401 # pragma: no cover
auth,
db,
import_chatgpt,
import_claude_conversations,
+64 -33
View File
@@ -45,7 +45,9 @@ class BasicMemoryConfig(BaseSettings):
env: Environment = Field(default="dev", description="Environment name")
projects: Dict[str, str] = Field(
default_factory=lambda: {"main": str(Path.home() / "basic-memory")},
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(
@@ -72,6 +74,17 @@ class BasicMemoryConfig(BaseSettings):
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_",
extra="ignore",
@@ -92,7 +105,9 @@ class BasicMemoryConfig(BaseSettings):
"""Ensure configuration is valid after initialization."""
# Ensure main project exists
if "main" not in self.projects: # pragma: no cover
self.projects["main"] = str(Path.home() / "basic-memory")
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
@@ -120,6 +135,7 @@ class BasicMemoryConfig(BaseSettings):
"""
# 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
@@ -158,20 +174,21 @@ class ConfigManager:
# Ensure config directory exists
self.config_dir.mkdir(parents=True, exist_ok=True)
# Load or create configuration
self.config = self.load_config()
@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.error(f"Failed to load config: {e}")
config = BasicMemoryConfig()
self.save_config(config)
return config
logger.exception(f"Failed to load config: {e}")
raise e
else:
config = BasicMemoryConfig()
self.save_config(config)
@@ -179,10 +196,7 @@ class ConfigManager:
def save_config(self, config: BasicMemoryConfig) -> None:
"""Save configuration to file."""
try:
self.config_file.write_text(json.dumps(config.model_dump(), indent=2))
except Exception as e: # pragma: no cover
logger.error(f"Failed to save config: {e}")
save_basic_memory_config(self.config_file, config)
@property
def projects(self) -> Dict[str, str]:
@@ -204,8 +218,10 @@ class ConfigManager:
project_path = Path(path)
project_path.mkdir(parents=True, exist_ok=True) # pragma: no cover
self.config.projects[name] = str(project_path)
self.save_config(self.config)
# 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:
@@ -215,11 +231,13 @@ class ConfigManager:
if not project_name: # pragma: no cover
raise ValueError(f"Project '{name}' not found")
if project_name == self.config.default_project: # pragma: no cover
# 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 self.config.projects[name]
self.save_config(self.config)
del config.projects[name]
self.save_config(config)
def set_default_project(self, name: str) -> None:
"""Set the default project."""
@@ -227,15 +245,18 @@ class ConfigManager:
if not project_name: # pragma: no cover
raise ValueError(f"Project '{name}' not found")
self.config.default_project = name
self.save_config(self.config)
# 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)
for name, path in app_config.projects.items():
if project_permalink == generate_permalink(name):
return name, path
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
@@ -248,7 +269,7 @@ def get_project_config(project_name: Optional[str] = None) -> ProjectConfig:
actual_project_name = None
# load the config from file
global app_config
config_manager = ConfigManager()
app_config = config_manager.load_config()
# Get project name from environment variable
@@ -278,14 +299,12 @@ def get_project_config(project_name: Optional[str] = None) -> ProjectConfig:
raise ValueError(f"Project '{actual_project_name}' not found") # pragma: no cover
# Create config manager
config_manager = ConfigManager()
# Export the app-level config
app_config: BasicMemoryConfig = config_manager.config
# Load project config for the default project (backward compatibility)
config: ProjectConfig = get_project_config()
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:
@@ -337,12 +356,24 @@ def setup_basic_memory_logging(): # pragma: no cover
# 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=config_manager.load_config().log_level,
log_level=log_level,
log_file=f"{DATA_DIR_NAME}/basic-memory-{process_name}.log",
console=False,
console=console_logging,
)
logger.info(f"Basic Memory {basic_memory.__version__} (Project: {config.project})")
+2 -6
View File
@@ -4,7 +4,7 @@ from enum import Enum, auto
from pathlib import Path
from typing import AsyncGenerator, Optional
from basic_memory.config import BasicMemoryConfig
from basic_memory.config import BasicMemoryConfig, ConfigManager
from alembic import command
from alembic.config import Config
@@ -88,7 +88,6 @@ async def get_or_create_db(
db_path: Path,
db_type: DatabaseType = DatabaseType.FILESYSTEM,
ensure_migrations: bool = True,
app_config: Optional["BasicMemoryConfig"] = None,
) -> tuple[AsyncEngine, async_sessionmaker[AsyncSession]]: # pragma: no cover
"""Get or create database engine and session maker."""
global _engine, _session_maker
@@ -98,10 +97,7 @@ async def get_or_create_db(
# Run migrations automatically unless explicitly disabled
if ensure_migrations:
if app_config is None:
from basic_memory.config import app_config as global_app_config
app_config = global_app_config
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
+3 -2
View File
@@ -12,7 +12,7 @@ from sqlalchemy.ext.asyncio import (
import pathlib
from basic_memory import db
from basic_memory.config import ProjectConfig, BasicMemoryConfig
from basic_memory.config import ProjectConfig, BasicMemoryConfig, ConfigManager
from basic_memory.importers import (
ChatGPTImporter,
ClaudeConversationsImporter,
@@ -33,10 +33,10 @@ 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
from basic_memory.config import app_config
def get_app_config() -> BasicMemoryConfig: # pragma: no cover
app_config = ConfigManager().config
return app_config
@@ -297,6 +297,7 @@ ContextServiceDep = Annotated[ContextService, Depends(get_context_service)]
async def get_sync_service(
app_config: AppConfigDep,
entity_service: EntityServiceDep,
entity_parser: EntityParserDep,
entity_repository: EntityRepositoryDep,
+65
View File
@@ -2,9 +2,11 @@
import hashlib
from pathlib import Path
import re
from typing import Any, Dict, Union
import yaml
import frontmatter
from loguru import logger
from basic_memory.utils import FilePath
@@ -233,3 +235,66 @@ async def update_frontmatter(path: FilePath, updates: Dict[str, Any]) -> str:
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)
+20 -10
View File
@@ -93,7 +93,7 @@ class ChatGPTImporter(Importer[ChatImportResult]):
break
# Generate permalink
date_prefix = datetime.fromtimestamp(created_at).strftime("%Y%m%d")
date_prefix = datetime.fromtimestamp(created_at).astimezone().strftime("%Y%m%d")
clean_title = clean_filename(conversation["title"])
# Format content
@@ -193,7 +193,7 @@ class ChatGPTImporter(Importer[ChatImportResult]):
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 and return messages in order.
"""Traverse message tree iteratively to handle deep conversations.
Args:
mapping: Message mapping.
@@ -204,19 +204,29 @@ class ChatGPTImporter(Importer[ChatImportResult]):
List of message data.
"""
messages = []
node = mapping.get(root_id) if root_id else None
if not root_id:
return messages
while node:
# 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"])
# Follow children
# Add children to stack in reverse order to maintain conversation flow
children = node.get("children", [])
for child_id in children:
child_msgs = self._traverse_messages(mapping, child_id, seen)
messages.extend(child_msgs)
break # Don't follow siblings
for child_id in reversed(children):
stack.append(child_id)
return messages
@@ -3,7 +3,7 @@
import logging
from typing import Any, Dict, List
from basic_memory.config import config
from basic_memory.config import get_project_config
from basic_memory.markdown.schemas import EntityFrontmatter, EntityMarkdown, Observation, Relation
from basic_memory.importers.base import Importer
from basic_memory.schemas.importer import EntityImportResult
@@ -27,10 +27,12 @@ class MemoryJsonImporter(Importer[EntityImportResult]):
Returns:
EntityImportResult containing statistics and status of the import.
"""
config = get_project_config()
try:
# First pass - collect all relations by source entity
entity_relations: Dict[str, List[Relation]] = {}
entities: Dict[str, Dict[str, Any]] = {}
skipped_entities: int = 0
# Ensure the base path exists
base_path = config.home # pragma: no cover
@@ -41,7 +43,13 @@ class MemoryJsonImporter(Importer[EntityImportResult]):
for line in source_data:
data = line
if data["type"] == "entity":
entities[data["name"]] = data
# Handle different possible name keys
entity_name = data.get("name") or data.get("entityName") or data.get("id")
if not entity_name:
logger.warning(f"Entity missing name field: {data}")
skipped_entities += 1
continue
entities[entity_name] = data
elif data["type"] == "relation":
# Store relation with its source entity
source = data.get("from") or data.get("from_id")
@@ -57,25 +65,31 @@ class MemoryJsonImporter(Importer[EntityImportResult]):
# Second pass - create and write entities
entities_created = 0
for name, entity_data in entities.items():
# Get entity type with fallback
entity_type = entity_data.get("entityType") or entity_data.get("type") or "entity"
# Ensure entity type directory exists
entity_type_dir = base_path / entity_data["entityType"]
entity_type_dir = base_path / entity_type
entity_type_dir.mkdir(parents=True, exist_ok=True)
# Get observations with fallback to empty list
observations = entity_data.get("observations", [])
entity = EntityMarkdown(
frontmatter=EntityFrontmatter(
metadata={
"type": entity_data["entityType"],
"type": entity_type,
"title": name,
"permalink": f"{entity_data['entityType']}/{name}",
"permalink": f"{entity_type}/{name}",
}
),
content=f"# {name}\n",
observations=[Observation(content=obs) for obs in entity_data["observations"]],
observations=[Observation(content=obs) for obs in observations],
relations=entity_relations.get(name, []),
)
# Write entity file
file_path = base_path / f"{entity_data['entityType']}/{name}.md"
file_path = base_path / f"{entity_type}/{name}.md"
await self.write_entity(entity, file_path)
entities_created += 1
@@ -86,6 +100,7 @@ class MemoryJsonImporter(Importer[EntityImportResult]):
success=True,
entities=entities_created,
relations=relations_count,
skipped_entities=skipped_entities,
)
except Exception as e: # pragma: no cover
+2 -2
View File
@@ -43,13 +43,13 @@ def format_timestamp(timestamp: Any) -> str: # pragma: no cover
except ValueError:
try:
# Try unix timestamp as string
timestamp = datetime.fromtimestamp(float(timestamp))
timestamp = datetime.fromtimestamp(float(timestamp)).astimezone()
except ValueError:
# Return as is if we can't parse it
return timestamp
elif isinstance(timestamp, (int, float)):
# Unix timestamp
timestamp = datetime.fromtimestamp(timestamp)
timestamp = datetime.fromtimestamp(timestamp).astimezone()
if isinstance(timestamp, datetime):
return timestamp.strftime("%Y-%m-%d %H:%M:%S")
+2 -2
View File
@@ -130,6 +130,6 @@ class EntityParser:
content=post.content,
observations=entity_content.observations,
relations=entity_content.relations,
created=datetime.fromtimestamp(file_stats.st_ctime),
modified=datetime.fromtimestamp(file_stats.st_mtime),
created=datetime.fromtimestamp(file_stats.st_ctime).astimezone(),
modified=datetime.fromtimestamp(file_stats.st_mtime).astimezone(),
)
@@ -2,11 +2,11 @@ from pathlib import Path
from typing import Optional
from collections import OrderedDict
import frontmatter
from frontmatter import Post
from loguru import logger
from basic_memory import file_utils
from basic_memory.file_utils import dump_frontmatter
from basic_memory.markdown.entity_parser import EntityParser
from basic_memory.markdown.schemas import EntityMarkdown, Observation, Relation
@@ -115,7 +115,7 @@ class MarkdownProcessor:
# Create Post object for frontmatter
post = Post(content, **frontmatter_dict)
final_content = frontmatter.dumps(post, sort_keys=False)
final_content = dump_frontmatter(post)
logger.debug(f"writing file {path} with content:\n{final_content}")
+42 -26
View File
@@ -8,35 +8,49 @@ from markdown_it.token import Token
# Observation handling functions
def is_observation(token: Token) -> bool:
"""Check if token looks like our observation format."""
import re
if token.type != "inline": # pragma: no cover
return False
content = token.content.strip()
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
if not content: # pragma: no cover
return False
# if it's a markdown_task, return false
if content.startswith("[ ]") or content.startswith("[x]") or content.startswith("[-]"):
return False
has_category = content.startswith("[") and "]" in content
# Exclude markdown links: [text](url)
if re.match(r"^\[.*?\]\(.*?\)$", content):
return False
# Exclude wiki links: [[text]]
if re.match(r"^\[\[.*?\]\]$", content):
return False
# Check for proper observation format: [category] content
match = re.match(r"^\[([^\[\]()]+)\]\s+(.+)", content)
has_tags = "#" in content
return has_category or has_tags
return bool(match) or has_tags
def parse_observation(token: Token) -> Dict[str, Any]:
"""Extract observation parts from token."""
# Strip bullet point if present
content = token.content.strip()
# Parse [category]
import re
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
# Parse [category] with regex
match = re.match(r"^\[([^\[\]()]+)\]\s+(.+)", content)
category = None
if content.startswith("["):
end = content.find("]")
if end != -1:
category = content[1:end].strip() or None # Convert empty to None
content = content[end + 1 :].strip()
if match:
category = match.group(1).strip()
content = match.group(2).strip()
else:
# Handle empty brackets [] followed by content
empty_match = re.match(r"^\[\]\s+(.+)", content)
if empty_match:
content = empty_match.group(1).strip()
# Parse (context)
context = None
if content.endswith(")"):
@@ -44,20 +58,18 @@ def parse_observation(token: Token) -> Dict[str, Any]:
if start != -1:
context = content[start + 1 : -1].strip()
content = content[:start].strip()
# Extract tags and keep original content
tags = []
parts = content.split()
for part in parts:
if part.startswith("#"):
# Handle multiple #tags stuck together
if "#" in part[1:]:
# Split on # but keep non-empty tags
subtags = [t for t in part.split("#") if t]
tags.extend(subtags)
else:
tags.append(part[1:])
return {
"category": category,
"content": content,
@@ -72,14 +84,16 @@ def is_explicit_relation(token: Token) -> bool:
if token.type != "inline": # pragma: no cover
return False
content = token.content.strip()
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
return "[[" in content and "]]" in content
def parse_relation(token: Token) -> Dict[str, Any] | None:
"""Extract relation parts from token."""
# Remove bullet point if present
content = token.content.strip()
# Use token.tag which contains the actual content for test tokens, fallback to content
content = (token.tag or token.content).strip()
# Extract [[target]]
target = None
@@ -213,10 +227,12 @@ def relation_plugin(md: MarkdownIt) -> None:
token.meta["relations"] = [rel]
# Always check for inline links in any text
elif "[[" in token.content:
rels = parse_inline_relations(token.content)
if rels:
token.meta["relations"] = token.meta.get("relations", []) + rels
else:
content = token.tag or token.content
if "[[" in content:
rels = parse_inline_relations(content)
if rels:
token.meta["relations"] = token.meta.get("relations", []) + rels
# Add the rule after inline processing
md.core.ruler.after("inline", "relations", relation_rule)
+4 -2
View File
@@ -38,8 +38,10 @@ def entity_model_from_markdown(
# Update basic fields
model.title = markdown.frontmatter.title
model.entity_type = markdown.frontmatter.type
model.permalink = markdown.frontmatter.permalink
model.file_path = str(file_path)
# Only update permalink if it exists in frontmatter, otherwise preserve existing
if markdown.frontmatter.permalink is not None:
model.permalink = markdown.frontmatter.permalink
model.file_path = file_path.as_posix()
model.content_type = "text/markdown"
model.created_at = markdown.created
model.updated_at = markdown.modified
+22 -2
View File
@@ -1,8 +1,28 @@
from httpx import ASGITransport, AsyncClient
from loguru import logger
from basic_memory.api.app import app as fastapi_app
from basic_memory.config import ConfigManager
def create_client() -> AsyncClient:
"""Create an HTTP client based on configuration.
Returns:
AsyncClient configured for either local ASGI or remote HTTP transport
"""
config_manager = ConfigManager()
config = config_manager.load_config()
if config.api_url:
# Use HTTP transport for remote API
logger.info(f"Creating HTTP client for remote Basic Memory API: {config.api_url}")
return AsyncClient(base_url=config.api_url)
else:
# Use ASGI transport for local API
logger.debug("Creating ASGI client for local Basic Memory API")
return AsyncClient(transport=ASGITransport(app=fastapi_app), base_url="http://test")
BASE_URL = "http://test"
# Create shared async client
client = AsyncClient(transport=ASGITransport(app=fastapi_app), base_url=BASE_URL)
client = create_client()
-270
View File
@@ -1,270 +0,0 @@
"""OAuth authentication provider for Basic Memory MCP server."""
import secrets
from datetime import datetime, timedelta
from typing import Dict, Optional
import jwt
from mcp.server.auth.provider import (
OAuthAuthorizationServerProvider,
AuthorizationParams,
AuthorizationCode,
RefreshToken,
AccessToken,
)
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
from loguru import logger
class BasicMemoryAuthorizationCode(AuthorizationCode):
"""Extended authorization code with additional metadata."""
issuer_state: Optional[str] = None
class BasicMemoryRefreshToken(RefreshToken):
"""Extended refresh token with additional metadata."""
pass
class BasicMemoryAccessToken(AccessToken):
"""Extended access token with additional metadata."""
pass
class BasicMemoryOAuthProvider(
OAuthAuthorizationServerProvider[
BasicMemoryAuthorizationCode, BasicMemoryRefreshToken, BasicMemoryAccessToken
]
):
"""OAuth provider for Basic Memory MCP server.
This is a simple in-memory implementation that can be extended
to integrate with external OAuth providers or use persistent storage.
"""
def __init__(self, issuer_url: str = "http://localhost:8000", secret_key: Optional[str] = None):
self.issuer_url = issuer_url
# Use environment variable for secret key if available, otherwise generate
import os
self.secret_key = (
secret_key or os.getenv("FASTMCP_AUTH_SECRET_KEY") or secrets.token_urlsafe(32)
)
# In-memory storage - in production, use a proper database
self.clients: Dict[str, OAuthClientInformationFull] = {}
self.authorization_codes: Dict[str, BasicMemoryAuthorizationCode] = {}
self.refresh_tokens: Dict[str, BasicMemoryRefreshToken] = {}
self.access_tokens: Dict[str, BasicMemoryAccessToken] = {}
async def get_client(self, client_id: str) -> Optional[OAuthClientInformationFull]:
"""Get a client by ID."""
return self.clients.get(client_id)
async def register_client(self, client_info: OAuthClientInformationFull) -> None:
"""Register a new OAuth client."""
# Generate client ID if not provided
if not client_info.client_id:
client_info.client_id = secrets.token_urlsafe(16)
# Generate client secret if not provided
if not client_info.client_secret:
client_info.client_secret = secrets.token_urlsafe(32)
self.clients[client_info.client_id] = client_info
logger.info(f"Registered OAuth client: {client_info.client_id}")
async def authorize(
self, client: OAuthClientInformationFull, params: AuthorizationParams
) -> str:
"""Create an authorization URL for the OAuth flow.
For basic-memory, we'll implement a simple authorization flow.
In production, this might redirect to an external provider.
"""
# Generate authorization code
auth_code = secrets.token_urlsafe(32)
# Store authorization code with metadata
self.authorization_codes[auth_code] = BasicMemoryAuthorizationCode(
code=auth_code,
scopes=params.scopes or [],
expires_at=(datetime.utcnow() + timedelta(minutes=10)).timestamp(),
client_id=client.client_id,
code_challenge=params.code_challenge,
redirect_uri=params.redirect_uri,
redirect_uri_provided_explicitly=params.redirect_uri_provided_explicitly,
issuer_state=params.state,
)
# In a real implementation, we'd redirect to an authorization page
# For now, we'll just return the redirect URL with the code
redirect_uri = str(params.redirect_uri)
separator = "&" if "?" in redirect_uri else "?"
auth_url = f"{redirect_uri}{separator}code={auth_code}"
if params.state:
auth_url += f"&state={params.state}"
return auth_url
async def load_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: str
) -> Optional[BasicMemoryAuthorizationCode]:
"""Load an authorization code."""
code = self.authorization_codes.get(authorization_code)
if code and code.client_id == client.client_id:
# Check if expired
if datetime.utcnow().timestamp() > code.expires_at:
del self.authorization_codes[authorization_code]
return None
return code
return None
async def exchange_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: BasicMemoryAuthorizationCode
) -> OAuthToken:
"""Exchange an authorization code for tokens."""
# Generate tokens
access_token = self._generate_access_token(client.client_id, authorization_code.scopes)
refresh_token = secrets.token_urlsafe(32)
# Store tokens
expires_at = (datetime.utcnow() + timedelta(hours=1)).timestamp()
self.access_tokens[access_token] = BasicMemoryAccessToken(
token=access_token,
client_id=client.client_id,
scopes=authorization_code.scopes,
expires_at=int(expires_at),
)
self.refresh_tokens[refresh_token] = BasicMemoryRefreshToken(
token=refresh_token,
client_id=client.client_id,
scopes=authorization_code.scopes,
)
# Remove used authorization code
del self.authorization_codes[authorization_code.code]
return OAuthToken(
access_token=access_token,
token_type="bearer",
expires_in=3600, # 1 hour
refresh_token=refresh_token,
scope=" ".join(authorization_code.scopes) if authorization_code.scopes else None,
)
async def load_refresh_token(
self, client: OAuthClientInformationFull, refresh_token: str
) -> Optional[BasicMemoryRefreshToken]:
"""Load a refresh token."""
token = self.refresh_tokens.get(refresh_token)
if token and token.client_id == client.client_id:
return token
return None
async def exchange_refresh_token(
self,
client: OAuthClientInformationFull,
refresh_token: BasicMemoryRefreshToken,
scopes: list[str],
) -> OAuthToken:
"""Exchange a refresh token for new tokens."""
# Use requested scopes or original scopes
token_scopes = scopes if scopes else refresh_token.scopes
# Generate new tokens
new_access_token = self._generate_access_token(client.client_id, token_scopes)
new_refresh_token = secrets.token_urlsafe(32)
# Store new tokens
expires_at = (datetime.utcnow() + timedelta(hours=1)).timestamp()
self.access_tokens[new_access_token] = BasicMemoryAccessToken(
token=new_access_token,
client_id=client.client_id,
scopes=token_scopes,
expires_at=int(expires_at),
)
self.refresh_tokens[new_refresh_token] = BasicMemoryRefreshToken(
token=new_refresh_token,
client_id=client.client_id,
scopes=token_scopes,
)
# Remove old tokens
del self.refresh_tokens[refresh_token.token]
return OAuthToken(
access_token=new_access_token,
token_type="bearer",
expires_in=3600, # 1 hour
refresh_token=new_refresh_token,
scope=" ".join(token_scopes) if token_scopes else None,
)
async def load_access_token(self, token: str) -> Optional[BasicMemoryAccessToken]:
"""Load and validate an access token."""
logger.debug("Loading access token, checking in-memory store first")
access_token = self.access_tokens.get(token)
if access_token:
# Check if expired
if access_token.expires_at and datetime.utcnow().timestamp() > access_token.expires_at:
logger.debug("Token found in memory but expired, removing")
del self.access_tokens[token]
return None
logger.debug("Token found in memory and valid")
return access_token
# Try to decode as JWT
logger.debug("Token not in memory, attempting JWT decode with secret key")
try:
# Decode with audience verification - PyJWT expects the audience to match
payload = jwt.decode(
token,
self.secret_key,
algorithms=["HS256"],
audience="basic-memory", # Expecting this audience
issuer=self.issuer_url, # And this issuer
)
logger.debug(f"JWT decoded successfully: {payload}")
return BasicMemoryAccessToken(
token=token,
client_id=payload.get("sub", ""),
scopes=payload.get("scopes", []),
expires_at=payload.get("exp"),
)
except jwt.InvalidTokenError as e:
logger.error(f"JWT decode failed: {e}")
return None
async def revoke_token(self, token: BasicMemoryAccessToken | BasicMemoryRefreshToken) -> None:
"""Revoke an access or refresh token."""
if isinstance(token, BasicMemoryAccessToken):
self.access_tokens.pop(token.token, None)
else:
self.refresh_tokens.pop(token.token, None)
def _generate_access_token(self, client_id: str, scopes: list[str]) -> str:
"""Generate a JWT access token."""
payload = {
"iss": self.issuer_url,
"sub": client_id,
"aud": "basic-memory",
"exp": datetime.utcnow() + timedelta(hours=1),
"iat": datetime.utcnow(),
"scopes": scopes,
}
return jwt.encode(payload, self.secret_key, algorithm="HS256")
@@ -1,321 +0,0 @@
"""External OAuth provider integration for Basic Memory MCP server."""
import os
from typing import Optional, Dict, Any
from dataclasses import dataclass
import httpx
from loguru import logger
from mcp.server.auth.provider import (
OAuthAuthorizationServerProvider,
AuthorizationParams,
AuthorizationCode,
RefreshToken,
AccessToken,
construct_redirect_uri,
)
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
@dataclass
class ExternalAuthorizationCode(AuthorizationCode):
"""Authorization code with external provider metadata."""
external_code: Optional[str] = None
state: Optional[str] = None
@dataclass
class ExternalRefreshToken(RefreshToken):
"""Refresh token with external provider metadata."""
external_token: Optional[str] = None
@dataclass
class ExternalAccessToken(AccessToken):
"""Access token with external provider metadata."""
external_token: Optional[str] = None
class ExternalOAuthProvider(
OAuthAuthorizationServerProvider[
ExternalAuthorizationCode, ExternalRefreshToken, ExternalAccessToken
]
):
"""OAuth provider that delegates to external OAuth providers.
This provider can integrate with services like:
- GitHub OAuth
- Google OAuth
- Auth0
- Okta
"""
def __init__(
self,
issuer_url: str,
external_provider: str,
external_client_id: str,
external_client_secret: str,
external_authorize_url: str,
external_token_url: str,
external_userinfo_url: Optional[str] = None,
):
self.issuer_url = issuer_url
self.external_provider = external_provider
self.external_client_id = external_client_id
self.external_client_secret = external_client_secret
self.external_authorize_url = external_authorize_url
self.external_token_url = external_token_url
self.external_userinfo_url = external_userinfo_url
# In-memory storage - in production, use a database
self.clients: Dict[str, OAuthClientInformationFull] = {}
self.codes: Dict[str, ExternalAuthorizationCode] = {}
self.tokens: Dict[str, Any] = {}
self.http_client = httpx.AsyncClient()
async def get_client(self, client_id: str) -> Optional[OAuthClientInformationFull]:
"""Get a client by ID."""
return self.clients.get(client_id)
async def register_client(self, client_info: OAuthClientInformationFull) -> None:
"""Register a new OAuth client."""
self.clients[client_info.client_id] = client_info
logger.info(f"Registered external OAuth client: {client_info.client_id}")
async def authorize(
self, client: OAuthClientInformationFull, params: AuthorizationParams
) -> str:
"""Create authorization URL redirecting to external provider."""
# Store authorization request
import secrets
state = secrets.token_urlsafe(32)
self.codes[state] = ExternalAuthorizationCode(
code=state,
scopes=params.scopes or [],
expires_at=0, # Will be set by external provider
client_id=client.client_id,
code_challenge=params.code_challenge,
redirect_uri=params.redirect_uri,
redirect_uri_provided_explicitly=params.redirect_uri_provided_explicitly,
state=params.state,
)
# Build external provider URL
external_params = {
"client_id": self.external_client_id,
"redirect_uri": f"{self.issuer_url}/callback",
"response_type": "code",
"state": state,
"scope": " ".join(params.scopes or []),
}
return construct_redirect_uri(self.external_authorize_url, **external_params)
async def handle_callback(self, code: str, state: str) -> str:
"""Handle callback from external provider."""
# Get original authorization request
auth_code = self.codes.get(state)
if not auth_code:
raise ValueError("Invalid state parameter")
# Exchange code with external provider
token_data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": f"{self.issuer_url}/callback",
"client_id": self.external_client_id,
"client_secret": self.external_client_secret,
}
response = await self.http_client.post(
self.external_token_url,
data=token_data,
)
response.raise_for_status()
external_tokens = response.json()
# Store external tokens
import secrets
internal_code = secrets.token_urlsafe(32)
self.codes[internal_code] = ExternalAuthorizationCode(
code=internal_code,
scopes=auth_code.scopes,
expires_at=0,
client_id=auth_code.client_id,
code_challenge=auth_code.code_challenge,
redirect_uri=auth_code.redirect_uri,
redirect_uri_provided_explicitly=auth_code.redirect_uri_provided_explicitly,
external_code=code,
state=auth_code.state,
)
self.tokens[internal_code] = external_tokens
# Redirect to original client
return construct_redirect_uri(
str(auth_code.redirect_uri),
code=internal_code,
state=auth_code.state,
)
async def load_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: str
) -> Optional[ExternalAuthorizationCode]:
"""Load an authorization code."""
code = self.codes.get(authorization_code)
if code and code.client_id == client.client_id:
return code
return None
async def exchange_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: ExternalAuthorizationCode
) -> OAuthToken:
"""Exchange authorization code for tokens."""
# Get stored external tokens
external_tokens = self.tokens.get(authorization_code.code)
if not external_tokens:
raise ValueError("No tokens found for authorization code")
# Map external tokens to MCP tokens
access_token = external_tokens.get("access_token")
refresh_token = external_tokens.get("refresh_token")
expires_in = external_tokens.get("expires_in", 3600)
# Store the mapping
self.tokens[access_token] = {
"client_id": client.client_id,
"external_token": access_token,
"scopes": authorization_code.scopes,
}
if refresh_token:
self.tokens[refresh_token] = {
"client_id": client.client_id,
"external_token": refresh_token,
"scopes": authorization_code.scopes,
}
# Clean up authorization code
del self.codes[authorization_code.code]
return OAuthToken(
access_token=access_token,
token_type="bearer",
expires_in=expires_in,
refresh_token=refresh_token,
scope=" ".join(authorization_code.scopes) if authorization_code.scopes else None,
)
async def load_refresh_token(
self, client: OAuthClientInformationFull, refresh_token: str
) -> Optional[ExternalRefreshToken]:
"""Load a refresh token."""
token_info = self.tokens.get(refresh_token)
if token_info and token_info["client_id"] == client.client_id:
return ExternalRefreshToken(
token=refresh_token,
client_id=client.client_id,
scopes=token_info["scopes"],
external_token=token_info.get("external_token"),
)
return None
async def exchange_refresh_token(
self,
client: OAuthClientInformationFull,
refresh_token: ExternalRefreshToken,
scopes: list[str],
) -> OAuthToken:
"""Exchange refresh token for new tokens."""
# Exchange with external provider
token_data = {
"grant_type": "refresh_token",
"refresh_token": refresh_token.external_token or refresh_token.token,
"client_id": self.external_client_id,
"client_secret": self.external_client_secret,
}
response = await self.http_client.post(
self.external_token_url,
data=token_data,
)
response.raise_for_status()
external_tokens = response.json()
# Update stored tokens
new_access_token = external_tokens.get("access_token")
new_refresh_token = external_tokens.get("refresh_token", refresh_token.token)
expires_in = external_tokens.get("expires_in", 3600)
self.tokens[new_access_token] = {
"client_id": client.client_id,
"external_token": new_access_token,
"scopes": scopes or refresh_token.scopes,
}
if new_refresh_token != refresh_token.token:
self.tokens[new_refresh_token] = {
"client_id": client.client_id,
"external_token": new_refresh_token,
"scopes": scopes or refresh_token.scopes,
}
del self.tokens[refresh_token.token]
return OAuthToken(
access_token=new_access_token,
token_type="bearer",
expires_in=expires_in,
refresh_token=new_refresh_token,
scope=" ".join(scopes or refresh_token.scopes),
)
async def load_access_token(self, token: str) -> Optional[ExternalAccessToken]:
"""Load and validate an access token."""
token_info = self.tokens.get(token)
if token_info:
return ExternalAccessToken(
token=token,
client_id=token_info["client_id"],
scopes=token_info["scopes"],
external_token=token_info.get("external_token"),
)
return None
async def revoke_token(self, token: ExternalAccessToken | ExternalRefreshToken) -> None:
"""Revoke a token."""
self.tokens.pop(token.token, None)
def create_github_provider() -> ExternalOAuthProvider:
"""Create an OAuth provider for GitHub integration."""
return ExternalOAuthProvider(
issuer_url=os.getenv("FASTMCP_AUTH_ISSUER_URL", "http://localhost:8000"),
external_provider="github",
external_client_id=os.getenv("GITHUB_CLIENT_ID", ""),
external_client_secret=os.getenv("GITHUB_CLIENT_SECRET", ""),
external_authorize_url="https://github.com/login/oauth/authorize",
external_token_url="https://github.com/login/oauth/access_token",
external_userinfo_url="https://api.github.com/user",
)
def create_google_provider() -> ExternalOAuthProvider:
"""Create an OAuth provider for Google integration."""
return ExternalOAuthProvider(
issuer_url=os.getenv("FASTMCP_AUTH_ISSUER_URL", "http://localhost:8000"),
external_provider="google",
external_client_id=os.getenv("GOOGLE_CLIENT_ID", ""),
external_client_secret=os.getenv("GOOGLE_CLIENT_SECRET", ""),
external_authorize_url="https://accounts.google.com/o/oauth2/v2/auth",
external_token_url="https://oauth2.googleapis.com/token",
external_userinfo_url="https://www.googleapis.com/oauth2/v1/userinfo",
)
+6 -4
View File
@@ -8,7 +8,7 @@ from dataclasses import dataclass
from typing import Optional
from loguru import logger
from basic_memory.config import ProjectConfig, get_project_config, config_manager
from basic_memory.config import ProjectConfig, get_project_config, ConfigManager
@dataclass
@@ -23,7 +23,7 @@ class ProjectSession:
current_project: Optional[str] = None
default_project: Optional[str] = None
def initialize(self, default_project: str) -> None:
def initialize(self, default_project: str) -> "ProjectSession":
"""Set the default project from config on startup.
Args:
@@ -32,6 +32,7 @@ class ProjectSession:
self.default_project = default_project
self.current_project = default_project
logger.info(f"Initialized project session with default project: {default_project}")
return self
def get_current_project(self) -> str:
"""Get the currently active project name.
@@ -72,7 +73,7 @@ class ProjectSession:
via CLI or API to ensure MCP session stays in sync.
"""
# Reload config to get latest default project
current_config = config_manager.load_config()
current_config = ConfigManager().config
new_default = current_config.default_project
# Reinitialize with new default
@@ -102,7 +103,8 @@ def get_active_project(project_override: Optional[str] = None) -> ProjectConfig:
return project
current_project = session.get_current_project()
return get_project_config(current_project)
active_project = get_project_config(current_project)
return active_project
def add_project_metadata(result: str, project_name: str) -> str:
-2
View File
@@ -10,12 +10,10 @@ from basic_memory.mcp.prompts import continue_conversation
from basic_memory.mcp.prompts import recent_activity
from basic_memory.mcp.prompts import search
from basic_memory.mcp.prompts import ai_assistant_guide
from basic_memory.mcp.prompts import sync_status
__all__ = [
"ai_assistant_guide",
"continue_conversation",
"recent_activity",
"search",
"sync_status",
]
-112
View File
@@ -1,112 +0,0 @@
"""Sync status prompt for Basic Memory MCP server."""
from basic_memory.mcp.server import mcp
@mcp.prompt(
description="""Get sync status with recommendations for AI assistants.
This prompt provides both current sync status and guidance on how
AI assistants should respond when sync operations are in progress or completed.
""",
)
async def sync_status_prompt() -> str:
"""Get sync status with AI assistant guidance.
Returns:
Formatted sync status with AI assistant guidance
"""
try: # pragma: no cover
from basic_memory.services.migration_service import migration_manager
state = migration_manager.state
# Build status report
lines = [
"# Basic Memory Sync Status",
"",
f"**Current Status**: {state.status.value.replace('_', ' ').title()}",
f"**System Ready**: {'Yes' if migration_manager.is_ready else 'No'}",
"",
]
if migration_manager.is_ready:
lines.extend(
[
"✅ **All sync operations completed** - System is fully operational",
"",
"All Basic Memory tools are available and functioning normally.",
"File indexing is complete and knowledge graphs are up to date.",
"You can proceed with any knowledge management tasks.",
]
)
else:
lines.append(f"**Status Message**: {state.message}")
if state.status.value == "in_progress":
if state.projects_total > 0:
progress = f" ({state.projects_migrated}/{state.projects_total})"
lines.append(f"**Progress**: {progress}")
lines.extend(
[
"",
"🔄 **File synchronization in progress** - Processing files and building knowledge graphs",
"",
"**Impact**: Some tools may show status messages instead of normal responses",
"until sync completes (usually 1-3 minutes).",
]
)
elif state.status.value == "failed":
lines.extend(
[
"",
f"❌ **Sync failed**: {state.error or 'Unknown error'}",
"",
"**Impact**: System may have limited functionality until issue is resolved.",
]
)
# Add AI assistant recommendations
if not migration_manager.is_ready:
lines.extend(
[
"",
"---",
"",
"## AI Assistant Recommendations",
"",
"**When sync is in progress:**",
"- Inform the user about the background file processing",
"- Suggest using `sync_status()` tool to check progress",
"- Explain that tools will work normally once sync completes",
"- Avoid creating complex workflows until sync is done",
"",
"**What to tell users:**",
"- 'Basic Memory is processing your files and building knowledge graphs'",
"- 'This usually takes 1-3 minutes depending on your content size'",
"- 'You can check progress anytime with the sync_status tool'",
"- 'Full functionality will be available once processing completes'",
"",
"**User-friendly language:**",
"- Say 'processing files' instead of 'migration' or 'sync'",
"- Say 'building knowledge graphs' instead of 'indexing'",
"- Say 'setting up your knowledge base' instead of 'running migrations'",
]
)
return "\n".join(lines)
except Exception as e: # pragma: no cover
return f"""# Sync Status - Error
❌ **Unable to check sync status**: {str(e)}
## AI Assistant Recommendations
**When status is unavailable:**
- Assume the system is likely working normally
- Try proceeding with normal operations
- If users report issues, suggest checking logs or restarting
- Use user-friendly language about 'setting up the knowledge base'
"""
+8 -71
View File
@@ -7,25 +7,10 @@ from contextlib import asynccontextmanager
from dataclasses import dataclass
from typing import AsyncIterator, Optional, Any
from dotenv import load_dotenv
from fastmcp import FastMCP
from fastmcp.utilities.logging import configure_logging as mcp_configure_logging
from mcp.server.auth.settings import AuthSettings
from basic_memory.config import app_config
from basic_memory.config import ConfigManager
from basic_memory.services.initialization import initialize_app
from basic_memory.mcp.auth_provider import BasicMemoryOAuthProvider
from basic_memory.mcp.project_session import session
from basic_memory.mcp.external_auth_provider import (
create_github_provider,
create_google_provider,
)
from basic_memory.mcp.supabase_auth_provider import SupabaseOAuthProvider
# mcp console logging
mcp_configure_logging(level="ERROR")
load_dotenv()
@dataclass
@@ -36,7 +21,11 @@ class AppContext:
@asynccontextmanager
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: # pragma: no cover
"""Manage application lifecycle with type-safe context"""
""" """
# defer import so tests can monkeypatch
from basic_memory.mcp.project_session import session
app_config = ConfigManager().config
# Initialize on startup (now returns migration_manager)
migration_manager = await initialize_app(app_config)
@@ -50,60 +39,8 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: # pragma:
pass
# OAuth configuration function
def create_auth_config() -> tuple[AuthSettings | None, Any | None]:
"""Create OAuth configuration if enabled."""
# Check if OAuth is enabled via environment variable
import os
if os.getenv("FASTMCP_AUTH_ENABLED", "false").lower() == "true":
from pydantic import AnyHttpUrl
# Configure OAuth settings
issuer_url = os.getenv("FASTMCP_AUTH_ISSUER_URL", "http://localhost:8000")
required_scopes = os.getenv("FASTMCP_AUTH_REQUIRED_SCOPES", "read,write")
docs_url = os.getenv("FASTMCP_AUTH_DOCS_URL") or "http://localhost:8000/docs/oauth"
auth_settings = AuthSettings(
issuer_url=AnyHttpUrl(issuer_url),
service_documentation_url=AnyHttpUrl(docs_url),
required_scopes=required_scopes.split(",") if required_scopes else ["read", "write"],
)
# Create OAuth provider based on type
provider_type = os.getenv("FASTMCP_AUTH_PROVIDER", "basic").lower()
if provider_type == "github":
auth_provider = create_github_provider()
elif provider_type == "google":
auth_provider = create_google_provider()
elif provider_type == "supabase":
supabase_url = os.getenv("SUPABASE_URL")
supabase_anon_key = os.getenv("SUPABASE_ANON_KEY")
supabase_service_key = os.getenv("SUPABASE_SERVICE_KEY")
if not supabase_url or not supabase_anon_key:
raise ValueError("SUPABASE_URL and SUPABASE_ANON_KEY must be set for Supabase auth")
auth_provider = SupabaseOAuthProvider(
supabase_url=supabase_url,
supabase_anon_key=supabase_anon_key,
supabase_service_key=supabase_service_key,
issuer_url=issuer_url,
)
else: # default to "basic"
auth_provider = BasicMemoryOAuthProvider(issuer_url=issuer_url)
return auth_settings, auth_provider
return None, None
# Create auth configuration
auth_settings, auth_provider = create_auth_config()
# Create the shared server instance
# Create the shared server instance with custom Stytch auth
mcp = FastMCP(
name="Basic Memory",
auth=auth_provider,
lifespan=app_lifespan,
)
@@ -1,463 +0,0 @@
"""Supabase OAuth provider for Basic Memory MCP server."""
import os
import secrets
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
import httpx
import jwt
from loguru import logger
from mcp.server.auth.provider import (
OAuthAuthorizationServerProvider,
AuthorizationParams,
AuthorizationCode,
RefreshToken,
AccessToken,
TokenError,
AuthorizeError,
)
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
@dataclass
class SupabaseAuthorizationCode(AuthorizationCode):
"""Authorization code with Supabase metadata."""
user_id: Optional[str] = None
email: Optional[str] = None
@dataclass
class SupabaseRefreshToken(RefreshToken):
"""Refresh token with Supabase metadata."""
supabase_refresh_token: Optional[str] = None
user_id: Optional[str] = None
@dataclass
class SupabaseAccessToken(AccessToken):
"""Access token with Supabase metadata."""
supabase_access_token: Optional[str] = None
user_id: Optional[str] = None
email: Optional[str] = None
class SupabaseOAuthProvider(
OAuthAuthorizationServerProvider[
SupabaseAuthorizationCode, SupabaseRefreshToken, SupabaseAccessToken
]
):
"""OAuth provider that integrates with Supabase Auth.
This provider uses Supabase as the authentication backend while
maintaining compatibility with MCP's OAuth requirements.
"""
def __init__(
self,
supabase_url: str,
supabase_anon_key: str,
supabase_service_key: Optional[str] = None,
issuer_url: str = "http://localhost:8000",
):
self.supabase_url = supabase_url.rstrip("/")
self.supabase_anon_key = supabase_anon_key
self.supabase_service_key = supabase_service_key or supabase_anon_key
self.issuer_url = issuer_url
# HTTP client for Supabase API calls
self.http_client = httpx.AsyncClient()
# Temporary storage for auth flows (in production, use Supabase DB)
self.pending_auth_codes: Dict[str, SupabaseAuthorizationCode] = {}
self.mcp_to_supabase_tokens: Dict[str, Dict[str, Any]] = {}
async def get_client(self, client_id: str) -> Optional[OAuthClientInformationFull]:
"""Get a client from Supabase.
In production, this would query a clients table in Supabase.
"""
# For now, we'll validate against a configured list of allowed clients
# In production, query Supabase DB for client info
allowed_clients = os.getenv("SUPABASE_ALLOWED_CLIENTS", "").split(",")
if client_id in allowed_clients:
return OAuthClientInformationFull(
client_id=client_id,
client_secret="", # Supabase handles secrets
redirect_uris=[], # Supabase handles redirect URIs
)
return None
async def register_client(self, client_info: OAuthClientInformationFull) -> None:
"""Register a new OAuth client in Supabase.
In production, this would insert into a clients table.
"""
# For development, we just log the registration
logger.info(f"Would register client {client_info.client_id} in Supabase")
# In production:
# await self.supabase.table('oauth_clients').insert({
# 'client_id': client_info.client_id,
# 'client_secret': client_info.client_secret,
# 'metadata': client_info.client_metadata,
# }).execute()
async def authorize(
self, client: OAuthClientInformationFull, params: AuthorizationParams
) -> str:
"""Create authorization URL redirecting to Supabase Auth.
This initiates the OAuth flow with Supabase as the identity provider.
"""
# Generate state for this auth request
state = secrets.token_urlsafe(32)
# Store the authorization request
self.pending_auth_codes[state] = SupabaseAuthorizationCode(
code=state,
scopes=params.scopes or [],
expires_at=(datetime.utcnow() + timedelta(minutes=10)).timestamp(),
client_id=client.client_id,
code_challenge=params.code_challenge,
redirect_uri=params.redirect_uri,
redirect_uri_provided_explicitly=params.redirect_uri_provided_explicitly,
)
# Build Supabase auth URL
auth_params = {
"redirect_to": f"{self.issuer_url}/auth/callback",
"scopes": " ".join(params.scopes or ["openid", "email"]),
"state": state,
}
# Use Supabase's OAuth endpoint
auth_url = f"{self.supabase_url}/auth/v1/authorize"
query_string = "&".join(f"{k}={v}" for k, v in auth_params.items())
return f"{auth_url}?{query_string}"
async def handle_supabase_callback(self, code: str, state: str) -> str:
"""Handle callback from Supabase after user authentication."""
# Get the original auth request
auth_request = self.pending_auth_codes.get(state)
if not auth_request:
raise AuthorizeError(
error="invalid_request",
error_description="Invalid state parameter",
)
# Exchange code with Supabase for tokens
token_response = await self.http_client.post(
f"{self.supabase_url}/auth/v1/token",
json={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": f"{self.issuer_url}/auth/callback",
},
headers={
"apikey": self.supabase_anon_key,
"Authorization": f"Bearer {self.supabase_anon_key}",
},
)
if not token_response.is_success:
raise AuthorizeError(
error="server_error",
error_description="Failed to exchange code with Supabase",
)
supabase_tokens = token_response.json()
# Get user info from Supabase
user_response = await self.http_client.get(
f"{self.supabase_url}/auth/v1/user",
headers={
"apikey": self.supabase_anon_key,
"Authorization": f"Bearer {supabase_tokens['access_token']}",
},
)
user_data = user_response.json() if user_response.is_success else {}
# Generate MCP authorization code
mcp_code = secrets.token_urlsafe(32)
# Update auth request with user info
auth_request.code = mcp_code
auth_request.user_id = user_data.get("id")
auth_request.email = user_data.get("email")
# Store mapping
self.pending_auth_codes[mcp_code] = auth_request
self.mcp_to_supabase_tokens[mcp_code] = {
"supabase_tokens": supabase_tokens,
"user": user_data,
}
# Clean up old state
del self.pending_auth_codes[state]
# Redirect back to client
redirect_uri = str(auth_request.redirect_uri)
separator = "&" if "?" in redirect_uri else "?"
return f"{redirect_uri}{separator}code={mcp_code}&state={state}"
async def load_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: str
) -> Optional[SupabaseAuthorizationCode]:
"""Load an authorization code."""
code = self.pending_auth_codes.get(authorization_code)
if code and code.client_id == client.client_id:
# Check expiration
if datetime.utcnow().timestamp() > code.expires_at:
del self.pending_auth_codes[authorization_code]
return None
return code
return None
async def exchange_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: SupabaseAuthorizationCode
) -> OAuthToken:
"""Exchange authorization code for tokens."""
# Get stored Supabase tokens
token_data = self.mcp_to_supabase_tokens.get(authorization_code.code)
if not token_data:
raise TokenError(error="invalid_grant", error_description="Invalid authorization code")
supabase_tokens = token_data["supabase_tokens"]
user = token_data["user"]
# Generate MCP tokens that wrap Supabase tokens
access_token = self._generate_mcp_token(
client_id=client.client_id,
user_id=user.get("id", ""),
email=user.get("email", ""),
scopes=authorization_code.scopes,
supabase_access_token=supabase_tokens["access_token"],
)
refresh_token = secrets.token_urlsafe(32)
# Store the token mapping
self.mcp_to_supabase_tokens[access_token] = {
"client_id": client.client_id,
"user_id": user.get("id"),
"email": user.get("email"),
"supabase_access_token": supabase_tokens["access_token"],
"supabase_refresh_token": supabase_tokens["refresh_token"],
"scopes": authorization_code.scopes,
}
# Store refresh token mapping
self.mcp_to_supabase_tokens[refresh_token] = {
"client_id": client.client_id,
"user_id": user.get("id"),
"supabase_refresh_token": supabase_tokens["refresh_token"],
"scopes": authorization_code.scopes,
}
# Clean up authorization code
del self.pending_auth_codes[authorization_code.code]
del self.mcp_to_supabase_tokens[authorization_code.code]
return OAuthToken(
access_token=access_token,
token_type="bearer",
expires_in=supabase_tokens.get("expires_in", 3600),
refresh_token=refresh_token,
scope=" ".join(authorization_code.scopes) if authorization_code.scopes else None,
)
async def load_refresh_token(
self, client: OAuthClientInformationFull, refresh_token: str
) -> Optional[SupabaseRefreshToken]:
"""Load a refresh token."""
token_data = self.mcp_to_supabase_tokens.get(refresh_token)
if token_data and token_data["client_id"] == client.client_id:
return SupabaseRefreshToken(
token=refresh_token,
client_id=client.client_id,
scopes=token_data["scopes"],
supabase_refresh_token=token_data["supabase_refresh_token"],
user_id=token_data.get("user_id"),
)
return None
async def exchange_refresh_token(
self,
client: OAuthClientInformationFull,
refresh_token: SupabaseRefreshToken,
scopes: list[str],
) -> OAuthToken:
"""Exchange refresh token for new tokens using Supabase."""
# Refresh with Supabase
token_response = await self.http_client.post(
f"{self.supabase_url}/auth/v1/token",
json={
"grant_type": "refresh_token",
"refresh_token": refresh_token.supabase_refresh_token,
},
headers={
"apikey": self.supabase_anon_key,
"Authorization": f"Bearer {self.supabase_anon_key}",
},
)
if not token_response.is_success:
raise TokenError(
error="invalid_grant",
error_description="Failed to refresh with Supabase",
)
supabase_tokens = token_response.json()
# Get updated user info
user_response = await self.http_client.get(
f"{self.supabase_url}/auth/v1/user",
headers={
"apikey": self.supabase_anon_key,
"Authorization": f"Bearer {supabase_tokens['access_token']}",
},
)
user_data = user_response.json() if user_response.is_success else {}
# Generate new MCP tokens
new_access_token = self._generate_mcp_token(
client_id=client.client_id,
user_id=user_data.get("id", ""),
email=user_data.get("email", ""),
scopes=scopes or refresh_token.scopes,
supabase_access_token=supabase_tokens["access_token"],
)
new_refresh_token = secrets.token_urlsafe(32)
# Update token mappings
self.mcp_to_supabase_tokens[new_access_token] = {
"client_id": client.client_id,
"user_id": user_data.get("id"),
"email": user_data.get("email"),
"supabase_access_token": supabase_tokens["access_token"],
"supabase_refresh_token": supabase_tokens["refresh_token"],
"scopes": scopes or refresh_token.scopes,
}
self.mcp_to_supabase_tokens[new_refresh_token] = {
"client_id": client.client_id,
"user_id": user_data.get("id"),
"supabase_refresh_token": supabase_tokens["refresh_token"],
"scopes": scopes or refresh_token.scopes,
}
# Clean up old tokens
del self.mcp_to_supabase_tokens[refresh_token.token]
return OAuthToken(
access_token=new_access_token,
token_type="bearer",
expires_in=supabase_tokens.get("expires_in", 3600),
refresh_token=new_refresh_token,
scope=" ".join(scopes or refresh_token.scopes),
)
async def load_access_token(self, token: str) -> Optional[SupabaseAccessToken]:
"""Load and validate an access token."""
# First check our mapping
token_data = self.mcp_to_supabase_tokens.get(token)
if token_data:
return SupabaseAccessToken(
token=token,
client_id=token_data["client_id"],
scopes=token_data["scopes"],
supabase_access_token=token_data.get("supabase_access_token"),
user_id=token_data.get("user_id"),
email=token_data.get("email"),
)
# Try to decode as JWT
try:
# Verify with Supabase's JWT secret
payload = jwt.decode(
token,
os.getenv("SUPABASE_JWT_SECRET", ""),
algorithms=["HS256"],
audience="authenticated",
)
return SupabaseAccessToken(
token=token,
client_id=payload.get("client_id", ""),
scopes=payload.get("scopes", []),
user_id=payload.get("sub"),
email=payload.get("email"),
)
except jwt.InvalidTokenError:
pass
# Validate with Supabase
user_response = await self.http_client.get(
f"{self.supabase_url}/auth/v1/user",
headers={
"apikey": self.supabase_anon_key,
"Authorization": f"Bearer {token}",
},
)
if user_response.is_success:
user_data = user_response.json()
return SupabaseAccessToken(
token=token,
client_id="", # Unknown client for direct Supabase tokens
scopes=[],
supabase_access_token=token,
user_id=user_data.get("id"),
email=user_data.get("email"),
)
return None
async def revoke_token(self, token: SupabaseAccessToken | SupabaseRefreshToken) -> None:
"""Revoke a token."""
# Remove from our mapping
self.mcp_to_supabase_tokens.pop(token.token, None)
# In production, also revoke in Supabase:
# await self.supabase.auth.admin.sign_out(token.user_id)
def _generate_mcp_token(
self,
client_id: str,
user_id: str,
email: str,
scopes: list[str],
supabase_access_token: str,
) -> str:
"""Generate an MCP token that wraps Supabase authentication."""
payload = {
"iss": self.issuer_url,
"sub": user_id,
"client_id": client_id,
"email": email,
"scopes": scopes,
"supabase_token": supabase_access_token[:10] + "...", # Reference only
"exp": datetime.utcnow() + timedelta(hours=1),
"iat": datetime.utcnow(),
}
# Use Supabase JWT secret if available
secret = os.getenv("SUPABASE_JWT_SECRET", secrets.token_urlsafe(32))
return jwt.encode(payload, secret, algorithm="HS256")
+4 -4
View File
@@ -20,24 +20,24 @@ from basic_memory.mcp.tools.edit_note import edit_note
from basic_memory.mcp.tools.move_note import move_note
from basic_memory.mcp.tools.sync_status import sync_status
from basic_memory.mcp.tools.project_management import (
list_projects,
list_memory_projects,
switch_project,
get_current_project,
set_default_project,
create_project,
create_memory_project,
delete_project,
)
__all__ = [
"build_context",
"canvas",
"create_project",
"create_memory_project",
"delete_note",
"delete_project",
"edit_note",
"get_current_project",
"list_directory",
"list_projects",
"list_memory_projects",
"move_note",
"read_content",
"read_note",
+18 -5
View File
@@ -15,6 +15,7 @@ from basic_memory.schemas.memory import (
memory_url_path,
)
type StringOrInt = str | int
@mcp.tool(
description="""Build context from a memory:// URI to continue conversations naturally.
@@ -35,7 +36,7 @@ from basic_memory.schemas.memory import (
)
async def build_context(
url: MemoryUrl,
depth: Optional[int] = 1,
depth: Optional[StringOrInt] = 1,
timeframe: Optional[TimeFrame] = "7d",
page: int = 1,
page_size: int = 10,
@@ -80,12 +81,26 @@ async def build_context(
build_context("memory://specs/search", project="work-project")
"""
logger.info(f"Building context from {url}")
# Convert string depth to integer if needed
if isinstance(depth, str):
try:
depth = int(depth)
except ValueError:
from mcp.server.fastmcp.exceptions import ToolError
raise ToolError(f"Invalid depth parameter: '{depth}' is not a valid integer")
# URL is already validated and normalized by MemoryUrl type annotation
# Get the active project first to check project-specific sync status
active_project = get_active_project(project)
# Check migration status and wait briefly if needed
from basic_memory.mcp.tools.utils import wait_for_migration_or_return_status
migration_status = await wait_for_migration_or_return_status(timeout=5.0)
migration_status = await wait_for_migration_or_return_status(
timeout=5.0, project_name=active_project.name
)
if migration_status: # pragma: no cover
# Return a proper GraphContext with status message
from basic_memory.schemas.memory import MemoryMetadata
@@ -96,14 +111,12 @@ async def build_context(
metadata=MemoryMetadata(
depth=depth or 1,
timeframe=timeframe,
generated_at=datetime.now(),
generated_at=datetime.now().astimezone(),
primary_count=0,
related_count=0,
uri=migration_status, # Include status in metadata
),
)
active_project = get_active_project(project)
project_url = active_project.project_url
response = await call_get(
+167 -1
View File
@@ -7,9 +7,145 @@ from loguru import logger
from basic_memory.mcp.async_client import client
from basic_memory.mcp.server import mcp
from basic_memory.mcp.tools.utils import call_post
from basic_memory.mcp.tools.utils import call_post, call_get
from basic_memory.mcp.project_session import get_active_project
from basic_memory.schemas import EntityResponse
from basic_memory.schemas.project_info import ProjectList
from basic_memory.utils import validate_project_path
async def _detect_cross_project_move_attempt(
identifier: str, destination_path: str, current_project: str
) -> Optional[str]:
"""Detect potential cross-project move attempts and return guidance.
Args:
identifier: The note identifier being moved
destination_path: The destination path
current_project: The current active project
Returns:
Error message with guidance if cross-project move is detected, None otherwise
"""
try:
# Get list of all available projects to check against
response = await call_get(client, "/projects/projects")
project_list = ProjectList.model_validate(response.json())
project_names = [p.name.lower() for p in project_list.projects]
# Check if destination path contains any project names
dest_lower = destination_path.lower()
path_parts = dest_lower.split("/")
# Look for project names in the destination path
for part in path_parts:
if part in project_names and part != current_project.lower():
# Found a different project name in the path
matching_project = next(
p.name for p in project_list.projects if p.name.lower() == part
)
return _format_cross_project_error_response(
identifier, destination_path, current_project, matching_project
)
# No other cross-project patterns detected
except Exception as e:
# If we can't detect, don't interfere with normal error handling
logger.debug(f"Could not check for cross-project move: {e}")
return None
return None
def _format_cross_project_error_response(
identifier: str, destination_path: str, current_project: str, target_project: str
) -> str:
"""Format error response for detected cross-project move attempts."""
return dedent(f"""
# Move Failed - Cross-Project Move Not Supported
Cannot move '{identifier}' to '{destination_path}' because it appears to reference a different project ('{target_project}').
**Current project:** {current_project}
**Target project:** {target_project}
## Cross-project moves are not supported directly
Notes can only be moved within the same project. To move content between projects, use this workflow:
### Recommended approach:
```
# 1. Read the note content from current project
read_note("{identifier}")
# 2. Switch to the target project
switch_project("{target_project}")
# 3. Create the note in the target project
write_note("Note Title", "content from step 1", "target-folder")
# 4. Switch back to original project (optional)
switch_project("{current_project}")
# 5. Delete the original note if desired
delete_note("{identifier}")
```
### Alternative: Stay in current project
If you want to move the note within the **{current_project}** project only:
```
move_note("{identifier}", "new-folder/new-name.md")
```
## Available projects:
Use `list_projects()` to see all available projects and `switch_project("project-name")` to change projects.
""").strip()
def _format_potential_cross_project_guidance(
identifier: str, destination_path: str, current_project: str, available_projects: list[str]
) -> str:
"""Format guidance for potentially cross-project moves."""
other_projects = ", ".join(available_projects[:3]) # Show first 3 projects
if len(available_projects) > 3:
other_projects += f" (and {len(available_projects) - 3} others)"
return dedent(f"""
# Move Failed - Check Project Context
Cannot move '{identifier}' to '{destination_path}' within the current project '{current_project}'.
## If you intended to move within the current project:
The destination path should be relative to the project root:
```
move_note("{identifier}", "folder/filename.md")
```
## If you intended to move to a different project:
Cross-project moves require switching projects first. Available projects: {other_projects}
### To move to another project:
```
# 1. Read the content
read_note("{identifier}")
# 2. Switch to target project
switch_project("target-project-name")
# 3. Create note in target project
write_note("Title", "content", "folder")
# 4. Switch back and delete original if desired
switch_project("{current_project}")
delete_note("{identifier}")
```
### To see all projects:
```
list_projects()
```
""").strip()
def _format_move_error_response(error_message: str, identifier: str, destination_path: str) -> str:
@@ -258,6 +394,36 @@ async def move_note(
active_project = get_active_project(project)
project_url = active_project.project_url
# Validate destination path to prevent path traversal attacks
project_path = active_project.home
if not validate_project_path(destination_path, project_path):
logger.warning(
"Attempted path traversal attack blocked",
destination_path=destination_path,
project=active_project.name,
)
return f"""# Move Failed - Security Validation Error
The destination path '{destination_path}' is not allowed - paths must stay within project boundaries.
## Valid path examples:
- `notes/my-file.md`
- `projects/2025/meeting-notes.md`
- `archive/old-notes.md`
## Try again with a safe path:
```
move_note("{identifier}", "notes/{destination_path.split("/")[-1] if "/" in destination_path else destination_path}")
```"""
# Check for potential cross-project move attempts
cross_project_error = await _detect_cross_project_move_attempt(
identifier, destination_path, active_project.name
)
if cross_project_error:
logger.info(f"Detected cross-project move attempt: {identifier} -> {destination_path}")
return cross_project_error
try:
# Prepare move request
move_data = {
@@ -5,6 +5,7 @@ and manage project context during conversations.
"""
from textwrap import dedent
from typing import Optional
from fastmcp import Context
from loguru import logger
@@ -19,7 +20,9 @@ from basic_memory.utils import generate_permalink
@mcp.tool("list_memory_projects")
async def list_projects(ctx: Context | None = None) -> str:
async def list_memory_projects(
ctx: Context | None = None, _compatibility: Optional[str] = None
) -> str:
"""List all available projects with their status.
Shows all Basic Memory projects that are available, indicating which one
@@ -29,7 +32,7 @@ async def list_projects(ctx: Context | None = None) -> str:
Formatted list of projects with status indicators
Example:
list_projects()
list_memory_projects()
"""
if ctx: # pragma: no cover
await ctx.info("Listing all available projects")
@@ -144,13 +147,13 @@ async def switch_project(project_name: str, ctx: Context | None = None) -> str:
Your session remains on the previous project.
## Troubleshooting:
1. **Check available projects**: Use `list_projects()` to see valid project names
1. **Check available projects**: Use `list_memory_projects()` to see valid project names
2. **Verify spelling**: Ensure the project name is spelled correctly
3. **Check permissions**: Verify you have access to the requested project
4. **Try again**: The error might be temporary
## Available options:
- See all projects: `list_projects()`
- See all projects: `list_memory_projects()`
- Stay on current project: `get_current_project()`
- Try different project: `switch_project("correct-project-name")`
@@ -159,7 +162,9 @@ async def switch_project(project_name: str, ctx: Context | None = None) -> str:
@mcp.tool()
async def get_current_project(ctx: Context | None = None) -> str:
async def get_current_project(
ctx: Context | None = None, _compatibility: Optional[str] = None
) -> str:
"""Show the currently active project and basic stats.
Displays which project is currently active and provides basic information
@@ -216,8 +221,10 @@ async def set_default_project(project_name: str, ctx: Context | None = None) ->
if ctx: # pragma: no cover
await ctx.info(f"Setting default project to: {project_name}")
# Call API to set default project
response = await call_put(client, f"/projects/{project_name}/default")
# Call API to set default project using URL encoding for special characters
from urllib.parse import quote
encoded_name = quote(project_name, safe='')
response = await call_put(client, f"/projects/{encoded_name}/default")
status_response = ProjectStatusResponse.model_validate(response.json())
result = f"{status_response.message}\n\n"
@@ -231,7 +238,7 @@ async def set_default_project(project_name: str, ctx: Context | None = None) ->
@mcp.tool("create_memory_project")
async def create_project(
async def create_memory_project(
project_name: str, project_path: str, set_default: bool = False, ctx: Context | None = None
) -> str:
"""Create a new Basic Memory project.
@@ -248,8 +255,8 @@ async def create_project(
Confirmation message with project details
Example:
create_project("my-research", "~/Documents/research")
create_project("work-notes", "/home/user/work", set_default=True)
create_memory_project("my-research", "~/Documents/research")
create_memory_project("work-notes", "/home/user/work", set_default=True)
"""
if ctx: # pragma: no cover
await ctx.info(f"Creating project: {project_name} at {project_path}")
@@ -318,16 +325,29 @@ async def delete_project(project_name: str, ctx: Context | None = None) -> str:
response = await call_get(client, "/projects/projects")
project_list = ProjectList.model_validate(response.json())
# Check if project exists
project_exists = any(p.name == project_name for p in project_list.projects)
if not project_exists:
# Find the project by name (case-insensitive) or permalink - same logic as switch_project
project_permalink = generate_permalink(project_name)
target_project = None
for p in project_list.projects:
# Match by permalink (handles case-insensitive input)
if p.permalink == project_permalink:
target_project = p
break
# Also match by name comparison (case-insensitive)
if p.name.lower() == project_name.lower():
target_project = p
break
if not target_project:
available_projects = [p.name for p in project_list.projects]
raise ValueError(
f"Project '{project_name}' not found. Available projects: {', '.join(available_projects)}"
)
# Call API to delete project
response = await call_delete(client, f"/projects/{project_name}")
# Call API to delete project using URL encoding for special characters
from urllib.parse import quote
encoded_name = quote(target_project.name, safe='')
response = await call_delete(client, f"/projects/{encoded_name}")
status_response = ProjectStatusResponse.model_validate(response.json())
result = f"{status_response.message}\n\n"
@@ -17,6 +17,7 @@ from basic_memory.mcp.async_client import client
from basic_memory.mcp.tools.utils import call_get
from basic_memory.mcp.project_session import get_active_project
from basic_memory.schemas.memory import memory_url_path
from basic_memory.utils import validate_project_path
def calculate_target_params(content_length):
@@ -188,6 +189,21 @@ async def read_content(path: str, project: Optional[str] = None) -> dict:
project_url = active_project.project_url
url = memory_url_path(path)
# Validate path to prevent path traversal attacks
project_path = active_project.home
if not validate_project_path(url, project_path):
logger.warning(
"Attempted path traversal attack blocked",
path=path,
url=url,
project=active_project.name,
)
return {
"type": "error",
"error": f"Path '{path}' is not allowed - paths must stay within project boundaries",
}
response = await call_get(client, f"{project_url}/resource/{url}")
content_type = response.headers.get("content-type", "application/octet-stream")
content_length = int(response.headers.get("content-length", 0))
+23 -5
View File
@@ -11,6 +11,7 @@ from basic_memory.mcp.tools.search import search_notes
from basic_memory.mcp.tools.utils import call_get
from basic_memory.mcp.project_session import get_active_project
from basic_memory.schemas.memory import memory_url_path
from basic_memory.utils import validate_project_path
@mcp.tool(
@@ -52,14 +53,31 @@ async def read_note(
read_note("Meeting Notes", project="work-project")
"""
# Get the active project first to check project-specific sync status
active_project = get_active_project(project)
# Validate identifier to prevent path traversal attacks
# We need to check both the raw identifier and the processed path
processed_path = memory_url_path(identifier)
project_path = active_project.home
if not validate_project_path(identifier, project_path) or not validate_project_path(processed_path, project_path):
logger.warning(
"Attempted path traversal attack blocked",
identifier=identifier,
processed_path=processed_path,
project=active_project.name,
)
return f"# Error\n\nIdentifier '{identifier}' is not allowed - paths must stay within project boundaries"
# Check migration status and wait briefly if needed
from basic_memory.mcp.tools.utils import wait_for_migration_or_return_status
migration_status = await wait_for_migration_or_return_status(timeout=5.0)
migration_status = await wait_for_migration_or_return_status(
timeout=5.0, project_name=active_project.name
)
if migration_status: # pragma: no cover
return f"# System Status\n\n{migration_status}\n\nPlease wait for migration to complete before reading notes."
active_project = get_active_project(project)
project_url = active_project.project_url
# Get the file via REST API - first try direct permalink lookup
@@ -121,7 +139,7 @@ def format_not_found_message(identifier: str) -> str:
return dedent(f"""
# Note Not Found: "{identifier}"
I searched for "{identifier}" using multiple methods (direct lookup, title search, and text search) but couldn't find any matching notes. Here are some suggestions:
I couldn't find any notes matching "{identifier}". Here are some suggestions:
## Check Identifier Type
- If you provided a title, try using the exact permalink instead
@@ -167,7 +185,7 @@ def format_related_results(identifier: str, results) -> str:
message = dedent(f"""
# Note Not Found: "{identifier}"
I searched for "{identifier}" using direct lookup and title search but couldn't find an exact match. However, I found some related notes through text search:
I couldn't find an exact match for "{identifier}", but I found some related notes:
""")
+111 -34
View File
@@ -45,13 +45,18 @@ def _format_search_error_response(error_message: str, query: str, search_type: s
- Boolean OR: `meeting OR discussion`
- Boolean NOT: `project NOT archived`
- Grouped: `(project OR planning) AND notes`
- Exact phrases: `"weekly standup meeting"`
- Content-specific: `tag:example` or `category:observation`
## Try again with:
```
search_notes("INSERT_CLEAN_QUERY_HERE")
search_notes("{clean_query}")
```
Replace INSERT_CLEAN_QUERY_HERE with your simplified search terms.
## Alternative search strategies:
- Break into simpler terms: `search_notes("{" ".join(clean_query.split()[:2])}")`
- Try different search types: `search_notes("{clean_query}", search_type="title")`
- Use filtering: `search_notes("{clean_query}", types=["entity"])`
""").strip()
# Project not found errors (check before general "not found")
@@ -85,24 +90,39 @@ def _format_search_error_response(error_message: str, query: str, search_type: s
No content found matching '{query}' in the current project.
## Suggestions to try:
## Search strategy suggestions:
1. **Broaden your search**: Try fewer or more general terms
- Instead of: `{query}`
- Try: `{simplified_query}`
2. **Check spelling**: Verify terms are spelled correctly
3. **Try different search types**:
- Text search: `search_notes("{query}", search_type="text")`
- Title search: `search_notes("{query}", search_type="title")`
- Permalink search: `search_notes("{query}", search_type="permalink")`
2. **Check spelling and try variations**:
- Verify terms are spelled correctly
- Try synonyms or related terms
4. **Use boolean operators**:
- Try OR search for broader results
3. **Use different search approaches**:
- **Text search**: `search_notes("{query}", search_type="text")` (searches full content)
- **Title search**: `search_notes("{query}", search_type="title")` (searches only titles)
- **Permalink search**: `search_notes("{query}", search_type="permalink")` (searches file paths)
## Check what content exists:
- Recent activity: `recent_activity(timeframe="7d")`
- List files: `list_directory("/")`
- Browse by folder: `list_directory("/notes")` or `list_directory("/docs")`
4. **Try boolean operators for broader results**:
- OR search: `search_notes("{" OR ".join(query.split()[:3])}")`
- Remove restrictive terms: Focus on the most important keywords
5. **Use filtering to narrow scope**:
- By content type: `search_notes("{query}", types=["entity"])`
- By recent content: `search_notes("{query}", after_date="1 week")`
- By entity type: `search_notes("{query}", entity_types=["observation"])`
6. **Try advanced search patterns**:
- Tag search: `search_notes("tag:your-tag")`
- Category search: `search_notes("category:observation")`
- Pattern matching: `search_notes("*{query}*", search_type="permalink")`
## Explore what content exists:
- **Recent activity**: `recent_activity(timeframe="7d")` - See what's been updated recently
- **List directories**: `list_directory("/")` - Browse all content
- **Browse by folder**: `list_directory("/notes")` or `list_directory("/docs")`
- **Check project**: `get_current_project()` - Verify you're in the right project
""").strip()
# Server/API errors
@@ -151,25 +171,36 @@ You don't have permission to search in the current project: {error_message}
Error searching for '{query}': {error_message}
## General troubleshooting:
1. **Check your query**: Ensure it uses valid search syntax
2. **Try simpler terms**: Use basic words without special characters
## Troubleshooting steps:
1. **Simplify your query**: Try basic words without special characters
2. **Check search syntax**: Ensure boolean operators are correctly formatted
3. **Verify project access**: Make sure you can access the current project
4. **Check recent activity**: `recent_activity(timeframe="7d")` to see if content exists
4. **Test with simple search**: Try `search_notes("test")` to verify search is working
## Alternative approaches:
- Browse files: `list_directory("/")`
- Try different search type: `search_notes("{query}", search_type="title")`
- Search with filters: `search_notes("{query}", types=["entity"])`
## Alternative search approaches:
- **Different search types**:
- Title only: `search_notes("{query}", search_type="title")`
- Permalink patterns: `search_notes("{query}*", search_type="permalink")`
- **With filters**: `search_notes("{query}", types=["entity"])`
- **Recent content**: `search_notes("{query}", after_date="1 week")`
- **Boolean variations**: `search_notes("{" OR ".join(query.split()[:2])}")`
## Need help?
- View recent changes: `recent_activity()`
- List projects: `list_projects()`
- Check current project: `get_current_project()`"""
## Explore your content:
- **Browse files**: `list_directory("/")` - See all available content
- **Recent activity**: `recent_activity(timeframe="7d")` - Check what's been updated
- **Project info**: `get_current_project()` - Verify current project
- **All projects**: `list_projects()` - Switch to different project if needed
## Search syntax reference:
- **Basic**: `keyword` or `multiple words`
- **Boolean**: `term1 AND term2`, `term1 OR term2`, `term1 NOT term2`
- **Phrases**: `"exact phrase"`
- **Grouping**: `(term1 OR term2) AND term3`
- **Patterns**: `tag:example`, `category:observation`"""
@mcp.tool(
description="Search across all content in the knowledge base.",
description="Search across all content in the knowledge base with advanced syntax support.",
)
async def search_notes(
query: str,
@@ -181,24 +212,60 @@ async def search_notes(
after_date: Optional[str] = None,
project: Optional[str] = None,
) -> SearchResponse | str:
"""Search across all content in the knowledge base.
"""Search across all content in the knowledge base with comprehensive syntax support.
This tool searches the knowledge base using full-text search, pattern matching,
or exact permalink lookup. It supports filtering by content type, entity type,
and date.
and date, with advanced boolean and phrase search capabilities.
## Search Syntax Examples
### Basic Searches
- `search_notes("keyword")` - Find any content containing "keyword"
- `search_notes("exact phrase")` - Search for exact phrase match
### Advanced Boolean Searches
- `search_notes("term1 term2")` - Find content with both terms (implicit AND)
- `search_notes("term1 AND term2")` - Explicit AND search (both terms required)
- `search_notes("term1 OR term2")` - Either term can be present
- `search_notes("term1 NOT term2")` - Include term1 but exclude term2
- `search_notes("(project OR planning) AND notes")` - Grouped boolean logic
### Content-Specific Searches
- `search_notes("tag:example")` - Search within specific tags (if supported by content)
- `search_notes("category:observation")` - Filter by observation categories
- `search_notes("author:username")` - Find content by author (if metadata available)
### Search Type Examples
- `search_notes("Meeting", search_type="title")` - Search only in titles
- `search_notes("docs/meeting-*", search_type="permalink")` - Pattern match permalinks
- `search_notes("keyword", search_type="text")` - Full-text search (default)
### Filtering Options
- `search_notes("query", types=["entity"])` - Search only entities
- `search_notes("query", types=["note", "person"])` - Multiple content types
- `search_notes("query", entity_types=["observation"])` - Filter by entity type
- `search_notes("query", after_date="2024-01-01")` - Recent content only
- `search_notes("query", after_date="1 week")` - Relative date filtering
### Advanced Pattern Examples
- `search_notes("project AND (meeting OR discussion)")` - Complex boolean logic
- `search_notes("\"exact phrase\" AND keyword")` - Combine phrase and keyword search
- `search_notes("bug NOT fixed")` - Exclude resolved issues
- `search_notes("docs/2024-*", search_type="permalink")` - Year-based permalink search
Args:
query: The search query string
query: The search query string (supports boolean operators, phrases, patterns)
page: The page number of results to return (default 1)
page_size: The number of results to return per page (default 10)
search_type: Type of search to perform, one of: "text", "title", "permalink" (default: "text")
types: Optional list of note types to search (e.g., ["note", "person"])
entity_types: Optional list of entity types to filter by (e.g., ["entity", "observation"])
after_date: Optional date filter for recent content (e.g., "1 week", "2d")
after_date: Optional date filter for recent content (e.g., "1 week", "2d", "2024-01-01")
project: Optional project name to search in. If not provided, uses current active project.
Returns:
SearchResponse with results and pagination info
SearchResponse with results and pagination info, or helpful error guidance if search fails
Examples:
# Basic text search
@@ -216,16 +283,19 @@ async def search_notes(
# Boolean search with grouping
results = await search_notes("(project OR planning) AND notes")
# Exact phrase search
results = await search_notes("\"weekly standup meeting\"")
# Search with type filter
results = await search_notes(
query="meeting notes",
types=["entity"],
)
# Search with entity type filter, e.g., note vs
# Search with entity type filter
results = await search_notes(
query="meeting notes",
types=["entity"],
entity_types=["observation"],
)
# Search for recent content
@@ -242,6 +312,13 @@ async def search_notes(
# Search in specific project
results = await search_notes("meeting notes", project="work-project")
# Complex search with multiple filters
results = await search_notes(
query="(bug OR issue) AND NOT resolved",
types=["entity"],
after_date="2024-01-01"
)
"""
# Create a SearchQuery object based on the parameters
search_query = SearchQuery()
+3 -2
View File
@@ -4,8 +4,10 @@ from typing import Optional
from loguru import logger
from basic_memory.config import ConfigManager
from basic_memory.mcp.server import mcp
from basic_memory.mcp.project_session import get_active_project
from basic_memory.services.sync_status_service import sync_status_tracker
def _get_all_projects_status() -> list[str]:
@@ -13,8 +15,7 @@ def _get_all_projects_status() -> list[str]:
status_lines = []
try:
from basic_memory.config import app_config
from basic_memory.services.sync_status_service import sync_status_tracker
app_config = ConfigManager().config
if app_config.projects:
status_lines.extend(["", "---", "", "**All Projects Status:**"])
+27 -4
View File
@@ -525,11 +525,16 @@ def check_migration_status() -> Optional[str]:
return None
async def wait_for_migration_or_return_status(timeout: float = 5.0) -> Optional[str]:
async def wait_for_migration_or_return_status(
timeout: float = 5.0, project_name: Optional[str] = None
) -> Optional[str]:
"""Wait briefly for sync/migration to complete, or return status message.
Args:
timeout: Maximum time to wait for sync completion
project_name: Optional project name to check specific project status.
If provided, only checks that project's readiness.
If None, uses global status check (legacy behavior).
Returns:
Status message if sync is still in progress, None if ready
@@ -538,18 +543,36 @@ async def wait_for_migration_or_return_status(timeout: float = 5.0) -> Optional[
from basic_memory.services.sync_status_service import sync_status_tracker
import asyncio
if sync_status_tracker.is_ready:
# Check if we should use project-specific or global status
def is_ready() -> bool:
if project_name:
return sync_status_tracker.is_project_ready(project_name)
return sync_status_tracker.is_ready
if is_ready():
return None
# Wait briefly for sync to complete
start_time = asyncio.get_event_loop().time()
while (asyncio.get_event_loop().time() - start_time) < timeout:
if sync_status_tracker.is_ready:
if is_ready():
return None
await asyncio.sleep(0.1) # Check every 100ms
# Still not ready after timeout
return sync_status_tracker.get_summary()
if project_name:
# For project-specific checks, get project status details
project_status = sync_status_tracker.get_project_status(project_name)
if project_status and project_status.status.value == "failed":
error_msg = project_status.error or "Unknown sync error"
return f"❌ Sync failed for project '{project_name}': {error_msg}"
elif project_status:
return f"🔄 Project '{project_name}' is still syncing: {project_status.message}"
else:
return f"⚠️ Project '{project_name}' status unknown"
else:
# Fall back to global summary for legacy calls
return sync_status_tracker.get_summary()
except Exception: # pragma: no cover
# If there's any error, assume ready
return None
+15 -3
View File
@@ -10,7 +10,7 @@ from basic_memory.mcp.tools.utils import call_put
from basic_memory.mcp.project_session import get_active_project
from basic_memory.schemas import EntityResponse
from basic_memory.schemas.base import Entity
from basic_memory.utils import parse_tags
from basic_memory.utils import parse_tags, validate_project_path
# Define TagType as a Union that can accept either a string or a list of strings or None
TagType = Union[List[str], str, None]
@@ -72,10 +72,23 @@ async def write_note(
"""
logger.info(f"MCP tool call tool=write_note folder={folder}, title={title}, tags={tags}")
# Get the active project first to check project-specific sync status
active_project = get_active_project(project)
# Validate folder path to prevent path traversal attacks
project_path = active_project.home
if folder and not validate_project_path(folder, project_path):
logger.warning(
"Attempted path traversal attack blocked", folder=folder, project=active_project.name
)
return f"# Error\n\nFolder path '{folder}' is not allowed - paths must stay within project boundaries"
# Check migration status and wait briefly if needed
from basic_memory.mcp.tools.utils import wait_for_migration_or_return_status
migration_status = await wait_for_migration_or_return_status(timeout=5.0)
migration_status = await wait_for_migration_or_return_status(
timeout=5.0, project_name=active_project.name
)
if migration_status: # pragma: no cover
return f"# System Status\n\n{migration_status}\n\nPlease wait for migration to complete before creating notes."
@@ -91,7 +104,6 @@ async def write_note(
content=content,
entity_metadata=metadata,
)
active_project = get_active_project(project)
project_url = active_project.project_url
# Create or update via knowledge API
+13 -2
View File
@@ -1,6 +1,7 @@
"""Knowledge graph models."""
from datetime import datetime
from basic_memory.utils import ensure_timezone_aware
from typing import Optional
from sqlalchemy import (
@@ -73,8 +74,8 @@ class Entity(Base):
checksum: Mapped[Optional[str]] = mapped_column(String, nullable=True)
# Metadata and tracking
created_at: Mapped[datetime] = mapped_column(DateTime)
updated_at: Mapped[datetime] = mapped_column(DateTime)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now().astimezone())
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now().astimezone(), onupdate=lambda: datetime.now().astimezone())
# Relationships
project = relationship("Project", back_populates="entities")
@@ -103,6 +104,16 @@ class Entity(Base):
def is_markdown(self):
"""Check if the entity is a markdown file."""
return self.content_type == "text/markdown"
def __getattribute__(self, name):
"""Override attribute access to ensure datetime fields are timezone-aware."""
value = super().__getattribute__(name)
# Ensure datetime fields are timezone-aware
if name in ('created_at', 'updated_at') and isinstance(value, datetime):
return ensure_timezone_aware(value)
return value
def __repr__(self) -> str:
return f"Entity(id={self.id}, name='{self.title}', type='{self.entity_type}'"
+3 -3
View File
@@ -1,6 +1,6 @@
"""Project model for Basic Memory."""
from datetime import datetime
from datetime import datetime, UTC
from typing import Optional
from sqlalchemy import (
@@ -52,9 +52,9 @@ class Project(Base):
is_default: Mapped[Optional[bool]] = mapped_column(Boolean, default=None, nullable=True)
# Timestamps
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(UTC))
updated_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
DateTime(timezone=True), default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC)
)
# Define relationships to entities, observations, and relations
@@ -57,7 +57,7 @@ class EntityRepository(Repository[Entity]):
"""
query = (
self.select()
.where(Entity.file_path == str(file_path))
.where(Entity.file_path == Path(file_path).as_posix())
.options(*self.get_load_options())
)
return await self.find_one(query)
@@ -68,7 +68,7 @@ class EntityRepository(Repository[Entity]):
Args:
file_path: Path to the entity file (will be converted to string internally)
"""
return await self.delete_by_fields(file_path=str(file_path))
return await self.delete_by_fields(file_path=Path(file_path).as_posix())
def get_load_options(self) -> List[LoaderOption]:
"""Get SQLAlchemy loader options for eager loading relationships."""
@@ -142,7 +142,7 @@ class EntityRepository(Repository[Entity]):
await session.flush()
# Return with relationships loaded
query = (
select(Entity)
self.select()
.where(Entity.file_path == entity.file_path)
.options(*self.get_load_options())
)
@@ -162,7 +162,7 @@ class EntityRepository(Repository[Entity]):
# Return with relationships loaded
query = (
select(Entity)
self.select()
.where(Entity.file_path == entity.file_path)
.options(*self.get_load_options())
)
@@ -203,7 +203,7 @@ class EntityRepository(Repository[Entity]):
await session.flush()
# Return the updated entity with relationships loaded
query = (
select(Entity)
self.select()
.where(Entity.file_path == entity.file_path)
.options(*self.get_load_options())
)
@@ -243,7 +243,7 @@ class EntityRepository(Repository[Entity]):
# Return the inserted entity with relationships loaded
query = (
select(Entity)
self.select()
.where(Entity.file_path == entity.file_path)
.options(*self.get_load_options())
)
@@ -46,7 +46,7 @@ class ProjectRepository(Repository[Project]):
Args:
path: Path to the project directory (will be converted to string internally)
"""
query = self.select().where(Project.path == str(path))
query = self.select().where(Project.path == Path(path).as_posix())
return await self.find_one(query)
async def get_default_project(self) -> Optional[Project]:
@@ -83,3 +83,21 @@ class ProjectRepository(Repository[Project]):
await session.flush()
return target_project
return None # pragma: no cover
async def update_path(self, project_id: int, new_path: str) -> Optional[Project]:
"""Update project path.
Args:
project_id: ID of the project to update
new_path: New filesystem path for the project
Returns:
The updated project if found, None otherwise
"""
async with db.scoped_session(self.session_maker) as session:
project = await self.select_by_id(session, project_id)
if project:
project.path = new_path
await session.flush()
return project
return None
+160 -26
View File
@@ -1,10 +1,12 @@
"""Repository for search operations."""
import json
import re
import time
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Dict, List, Optional
from pathlib import Path
from loguru import logger
from sqlalchemy import Executable, Result, text
@@ -58,8 +60,11 @@ class SearchIndexRow:
if not self.type == SearchItemType.ENTITY.value and not self.file_path:
return ""
# Normalize path separators to handle both Windows (\) and Unix (/) paths
normalized_path = Path(self.file_path).as_posix()
# Split the path by slashes
parts = self.file_path.split("/")
parts = normalized_path.split("/")
# If there's only one part (e.g., "README.md"), it's at the root
if len(parts) <= 1:
@@ -120,23 +125,141 @@ class SearchRepository:
logger.error(f"Error initializing search index: {e}")
raise e
def _prepare_search_term(self, term: str, is_prefix: bool = True) -> str:
"""Prepare a search term for FTS5 query.
def _prepare_boolean_query(self, query: str) -> str:
"""Prepare a Boolean query by quoting individual terms while preserving operators.
Args:
term: The search term to prepare
query: A Boolean query like "tier1-test AND unicode" or "(hello OR world) NOT test"
Returns:
A properly formatted Boolean query with quoted terms that need quoting
"""
# Define Boolean operators and their boundaries
boolean_pattern = r"(\bAND\b|\bOR\b|\bNOT\b)"
# Split the query by Boolean operators, keeping the operators
parts = re.split(boolean_pattern, query)
processed_parts = []
for part in parts:
part = part.strip()
if not part:
continue
# If it's a Boolean operator, keep it as is
if part in ["AND", "OR", "NOT"]:
processed_parts.append(part)
else:
# Handle parentheses specially - they should be preserved for grouping
if "(" in part or ")" in part:
# Parse parenthetical expressions carefully
processed_part = self._prepare_parenthetical_term(part)
processed_parts.append(processed_part)
else:
# This is a search term - for Boolean queries, don't add prefix wildcards
prepared_term = self._prepare_single_term(part, is_prefix=False)
processed_parts.append(prepared_term)
return " ".join(processed_parts)
def _prepare_parenthetical_term(self, term: str) -> str:
"""Prepare a term that contains parentheses, preserving the parentheses for grouping.
Args:
term: A term that may contain parentheses like "(hello" or "world)" or "(hello OR world)"
Returns:
A properly formatted term with parentheses preserved
"""
# Handle terms that start/end with parentheses but may contain quotable content
result = ""
i = 0
while i < len(term):
if term[i] in "()":
# Preserve parentheses as-is
result += term[i]
i += 1
else:
# Find the next parenthesis or end of string
start = i
while i < len(term) and term[i] not in "()":
i += 1
# Extract the content between parentheses
content = term[start:i].strip()
if content:
# Only quote if it actually needs quoting (has hyphens, special chars, etc)
# but don't quote if it's just simple words
if self._needs_quoting(content):
escaped_content = content.replace('"', '""')
result += f'"{escaped_content}"'
else:
result += content
return result
def _needs_quoting(self, term: str) -> bool:
"""Check if a term needs to be quoted for FTS5 safety.
Args:
term: The term to check
Returns:
True if the term should be quoted
"""
if not term or not term.strip():
return False
# Characters that indicate we should quote (excluding parentheses which are valid syntax)
needs_quoting_chars = [
" ",
".",
":",
";",
",",
"<",
">",
"?",
"/",
"-",
"'",
'"',
"[",
"]",
"{",
"}",
"+",
"!",
"@",
"#",
"$",
"%",
"^",
"&",
"=",
"|",
"\\",
"~",
"`",
]
return any(c in term for c in needs_quoting_chars)
def _prepare_single_term(self, term: str, is_prefix: bool = True) -> str:
"""Prepare a single search term (no Boolean operators).
Args:
term: A single search term
is_prefix: Whether to add prefix search capability (* suffix)
For FTS5:
- Boolean operators (AND, OR, NOT) are preserved for complex queries
- Terms with FTS5 special characters are quoted to prevent syntax errors
- Simple terms get prefix wildcards for better matching
Returns:
A properly formatted single term
"""
# Check for explicit boolean operators - if present, return the term as is
boolean_operators = [" AND ", " OR ", " NOT "]
if any(op in f" {term} " for op in boolean_operators):
if not term or not term.strip():
return term
term = term.strip()
# Check if term is already a proper wildcard pattern (alphanumeric + *)
# e.g., "hello*", "test*world" - these should be left alone
if "*" in term and all(c.isalnum() or c in "*_-" for c in term):
@@ -218,6 +341,26 @@ class SearchRepository:
return term
def _prepare_search_term(self, term: str, is_prefix: bool = True) -> str:
"""Prepare a search term for FTS5 query.
Args:
term: The search term to prepare
is_prefix: Whether to add prefix search capability (* suffix)
For FTS5:
- Boolean operators (AND, OR, NOT) are preserved for complex queries
- Terms with FTS5 special characters are quoted to prevent syntax errors
- Simple terms get prefix wildcards for better matching
"""
# Check for explicit boolean operators - if present, process as Boolean query
boolean_operators = [" AND ", " OR ", " NOT "]
if any(op in f" {term} " for op in boolean_operators):
return self._prepare_boolean_query(term)
# For non-Boolean queries, use the single term preparation logic
return self._prepare_single_term(term, is_prefix)
async def search(
self,
search_text: Optional[str] = None,
@@ -242,19 +385,10 @@ class SearchRepository:
# For wildcard searches, don't add any text conditions - return all results
pass
else:
# Check for explicit boolean operators - only detect them in proper boolean contexts
has_boolean = any(op in f" {search_text} " for op in [" AND ", " OR ", " NOT "])
if has_boolean:
# If boolean operators are present, use the raw query
# No need to prepare it, FTS5 will understand the operators
params["text"] = search_text
conditions.append("(title MATCH :text OR content_stems MATCH :text)")
else:
# Standard search with term preparation
processed_text = self._prepare_search_term(search_text.strip())
params["text"] = processed_text
conditions.append("(title MATCH :text OR content_stems MATCH :text)")
# Use _prepare_search_term to handle both Boolean and non-Boolean queries
processed_text = self._prepare_search_term(search_text.strip())
params["text"] = processed_text
conditions.append("(title MATCH :text OR content_stems MATCH :text)")
# Handle title match search
if title:
@@ -393,8 +527,8 @@ class SearchRepository:
async with db.scoped_session(self.session_maker) as session:
# Delete existing record if any
await session.execute(
text("DELETE FROM search_index WHERE permalink = :permalink"),
{"permalink": search_index_row.permalink},
text("DELETE FROM search_index WHERE permalink = :permalink AND project_id = :project_id"),
{"permalink": search_index_row.permalink, "project_id": self.project_id},
)
# Prepare data for insert with project_id
+40 -10
View File
@@ -22,6 +22,8 @@ from dateparser import parse
from pydantic import BaseModel, BeforeValidator, Field, model_validator
from basic_memory.config import ConfigManager
from basic_memory.file_utils import sanitize_for_filename
from basic_memory.utils import generate_permalink
@@ -53,22 +55,28 @@ def parse_timeframe(timeframe: str) -> datetime:
timeframe: Natural language timeframe like 'today', '1d', '1 week ago', etc.
Returns:
datetime: The parsed datetime for the start of the timeframe
datetime: The parsed datetime for the start of the timeframe, timezone-aware in local system timezone
Examples:
parse_timeframe('today') -> 2025-06-05 00:00:00 (start of today)
parse_timeframe('1d') -> 2025-06-04 14:50:00 (24 hours ago)
parse_timeframe('1 week ago') -> 2025-05-29 14:50:00 (1 week ago)
parse_timeframe('today') -> 2025-06-05 00:00:00-07:00 (start of today with local timezone)
parse_timeframe('1d') -> 2025-06-04 14:50:00-07:00 (24 hours ago with local timezone)
parse_timeframe('1 week ago') -> 2025-05-29 14:50:00-07:00 (1 week ago with local timezone)
"""
if timeframe.lower() == "today":
# Return start of today (00:00:00)
return datetime.combine(datetime.now().date(), time.min)
# Return start of today (00:00:00) in local timezone
naive_dt = datetime.combine(datetime.now().date(), time.min)
return naive_dt.astimezone()
else:
# Use dateparser for other formats
parsed = parse(timeframe)
if not parsed:
raise ValueError(f"Could not parse timeframe: {timeframe}")
return parsed
# If the parsed datetime is naive, make it timezone-aware in local system timezone
if parsed.tzinfo is None:
return parsed.astimezone()
else:
return parsed
def validate_timeframe(timeframe: str) -> str:
@@ -85,7 +93,7 @@ def validate_timeframe(timeframe: str) -> str:
parsed = parse_timeframe(timeframe)
# Convert to duration
now = datetime.now()
now = datetime.now().astimezone()
if parsed > now:
raise ValueError("Timeframe cannot be in the future")
@@ -184,13 +192,35 @@ class Entity(BaseModel):
default="text/markdown",
)
@property
def safe_title(self) -> str:
"""
A sanitized version of the title, which is safe for use on the filesystem. For example,
a title of "Coupon Enable/Disable Feature" should create a the file as "Coupon Enable-Disable Feature.md"
instead of creating a file named "Disable Feature.md" beneath the "Coupon Enable" directory.
Replaces POSIX and/or Windows style slashes as well as a few other characters that are not safe for filenames.
If kebab_filenames is True, then behavior is consistent with transformation used when generating permalink
strings (e.g. "Coupon Enable/Disable Feature" -> "coupon-enable-disable-feature").
"""
fixed_title = sanitize_for_filename(self.title)
app_config = ConfigManager().config
use_kebab_case = app_config.kebab_filenames
if use_kebab_case:
fixed_title = generate_permalink(file_path=fixed_title, split_extension=False)
return fixed_title
@property
def file_path(self):
"""Get the file path for this entity based on its permalink."""
safe_title = self.safe_title
if self.content_type == "text/markdown":
return f"{self.folder}/{self.title}.md" if self.folder else f"{self.title}.md"
return f"{self.folder}/{safe_title}.md" if self.folder else f"{safe_title}.md"
else:
return f"{self.folder}/{self.title}" if self.folder else self.title
return f"{self.folder}/{safe_title}" if self.folder else safe_title
@property
def permalink(self) -> Permalink:
+1
View File
@@ -32,3 +32,4 @@ class EntityImportResult(ImportResult):
entities: int = 0
relations: int = 0
skipped_entities: int = 0
+24 -12
View File
@@ -1,10 +1,10 @@
"""Schemas for memory context."""
from datetime import datetime
from typing import List, Optional, Annotated, Sequence
from typing import List, Optional, Annotated, Sequence, Literal, Union
from annotated_types import MinLen, MaxLen
from pydantic import BaseModel, Field, BeforeValidator, TypeAdapter
from pydantic import BaseModel, Field, BeforeValidator, TypeAdapter, ConfigDict
from basic_memory.schemas.search import SearchItemType
@@ -117,8 +117,10 @@ def memory_url_path(url: memory_url) -> str: # pyright: ignore
class EntitySummary(BaseModel):
"""Simplified entity representation."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
type: str = "entity"
type: Literal["entity"] = "entity"
permalink: Optional[str]
title: str
content: Optional[str] = None
@@ -128,21 +130,25 @@ class EntitySummary(BaseModel):
class RelationSummary(BaseModel):
"""Simplified relation representation."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
type: str = "relation"
type: Literal["relation"] = "relation"
title: str
file_path: str
permalink: str
relation_type: str
from_entity: str
from_entity: Optional[str] = None
to_entity: Optional[str] = None
created_at: datetime
class ObservationSummary(BaseModel):
"""Simplified observation representation."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
type: str = "observation"
type: Literal["observation"] = "observation"
title: str
file_path: str
permalink: str
@@ -153,6 +159,8 @@ class ObservationSummary(BaseModel):
class MemoryMetadata(BaseModel):
"""Simplified response metadata."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
uri: Optional[str] = None
types: Optional[List[SearchItemType]] = None
@@ -169,17 +177,21 @@ class MemoryMetadata(BaseModel):
class ContextResult(BaseModel):
"""Context result containing a primary item with its observations and related items."""
primary_result: EntitySummary | RelationSummary | ObservationSummary = Field(
description="Primary item"
)
primary_result: Annotated[
Union[EntitySummary, RelationSummary, ObservationSummary],
Field(discriminator="type", description="Primary item")
]
observations: Sequence[ObservationSummary] = Field(
description="Observations belonging to this entity", default_factory=list
)
related_results: Sequence[EntitySummary | RelationSummary | ObservationSummary] = Field(
description="Related items", default_factory=list
)
related_results: Sequence[
Annotated[
Union[EntitySummary, RelationSummary, ObservationSummary],
Field(discriminator="type")
]
] = Field(description="Related items", default_factory=list)
class GraphContext(BaseModel):
+1 -1
View File
@@ -131,7 +131,7 @@ class EntityResponse(SQLAlchemyModel):
}
"""
permalink: Permalink
permalink: Optional[Permalink]
title: str
file_path: str
entity_type: EntityType
+12 -2
View File
@@ -245,8 +245,8 @@ class ContextService:
# For compatibility with the old query, we still need this for filtering
values = ", ".join([f"('{t}', {i})" for t, i in type_id_pairs])
# Parameters for bindings
params = {"max_depth": max_depth, "max_results": max_results}
# Parameters for bindings - include project_id for security filtering
params = {"max_depth": max_depth, "max_results": max_results, "project_id": self.search_repository.project_id}
# Build date and timeframe filters conditionally based on since parameter
if since:
@@ -258,6 +258,10 @@ class ContextService:
date_filter = ""
relation_date_filter = ""
timeframe_condition = ""
# Add project filtering for security - ensure all entities and relations belong to the same project
project_filter = "AND e.project_id = :project_id"
relation_project_filter = "AND e_from.project_id = :project_id"
# Use a CTE that operates directly on entity and relation tables
# This avoids the overhead of the search_index virtual table
@@ -284,6 +288,7 @@ class ContextService:
FROM entity e
WHERE e.id IN ({entity_id_values})
{date_filter}
{project_filter}
UNION ALL
@@ -314,8 +319,12 @@ class ContextService:
JOIN entity e_from ON (
r.from_id = e_from.id
{relation_date_filter}
{relation_project_filter}
)
LEFT JOIN entity e_to ON (r.to_id = e_to.id)
WHERE eg.depth < :max_depth
-- Ensure to_entity (if exists) also belongs to same project
AND (r.to_id IS NULL OR e_to.project_id = :project_id)
UNION ALL
@@ -348,6 +357,7 @@ class ContextService:
ELSE eg.from_id
END
{date_filter}
{project_filter}
)
WHERE eg.depth < :max_depth
-- Only include entities connected by relations within timeframe if specified
@@ -106,8 +106,15 @@ class DirectoryService:
List of DirectoryNode objects matching the criteria
"""
# Normalize directory path
# Strip ./ prefix if present (handles relative path notation)
if dir_name.startswith("./"):
dir_name = dir_name[2:] # Remove "./" prefix
# Ensure path starts with "/"
if not dir_name.startswith("/"):
dir_name = f"/{dir_name}"
# Remove trailing slashes except for root
if dir_name != "/" and dir_name.endswith("/"):
dir_name = dir_name.rstrip("/")
+64 -13
View File
@@ -9,12 +9,13 @@ from loguru import logger
from sqlalchemy.exc import IntegrityError
from basic_memory.config import ProjectConfig, BasicMemoryConfig
from basic_memory.file_utils import has_frontmatter, parse_frontmatter, remove_frontmatter
from basic_memory.file_utils import has_frontmatter, parse_frontmatter, remove_frontmatter, dump_frontmatter
from basic_memory.markdown import EntityMarkdown
from basic_memory.markdown.entity_parser import EntityParser
from basic_memory.markdown.utils import entity_model_from_markdown, schema_to_markdown
from basic_memory.models import Entity as EntityModel
from basic_memory.models import Observation, Relation
from basic_memory.models.knowledge import Entity
from basic_memory.repository import ObservationRepository, RelationRepository
from basic_memory.repository.entity_repository import EntityRepository
from basic_memory.schemas import Entity as EntitySchema
@@ -44,6 +45,39 @@ class EntityService(BaseService[EntityModel]):
self.file_service = file_service
self.link_resolver = link_resolver
async def detect_file_path_conflicts(self, file_path: str) -> List[Entity]:
"""Detect potential file path conflicts for a given file path.
This checks for entities with similar file paths that might cause conflicts:
- Case sensitivity differences (Finance/file.md vs finance/file.md)
- Character encoding differences
- Hyphen vs space differences
- Unicode normalization differences
Args:
file_path: The file path to check for conflicts
Returns:
List of entities that might conflict with the given file path
"""
from basic_memory.utils import detect_potential_file_conflicts
conflicts = []
# Get all existing file paths
all_entities = await self.repository.find_all()
existing_paths = [entity.file_path for entity in all_entities]
# Use the enhanced conflict detection utility
conflicting_paths = detect_potential_file_conflicts(file_path, existing_paths)
# Find the entities corresponding to conflicting paths
for entity in all_entities:
if entity.file_path in conflicting_paths:
conflicts.append(entity)
return conflicts
async def resolve_permalink(
self, file_path: Permalink | Path, markdown: Optional[EntityMarkdown] = None
) -> str:
@@ -54,18 +88,30 @@ class EntityService(BaseService[EntityModel]):
2. If markdown has permalink but it's used by another file -> make unique
3. For existing files, keep current permalink from db
4. Generate new unique permalink from file path
Enhanced to detect and handle character-related conflicts.
"""
file_path_str = Path(file_path).as_posix()
# Check for potential file path conflicts before resolving permalink
conflicts = await self.detect_file_path_conflicts(file_path_str)
if conflicts:
logger.warning(
f"Detected potential file path conflicts for '{file_path_str}': "
f"{[entity.file_path for entity in conflicts]}"
)
# If markdown has explicit permalink, try to validate it
if markdown and markdown.frontmatter.permalink:
desired_permalink = markdown.frontmatter.permalink
existing = await self.repository.get_by_permalink(desired_permalink)
# If no conflict or it's our own file, use as is
if not existing or existing.file_path == str(file_path):
if not existing or existing.file_path == file_path_str:
return desired_permalink
# For existing files, try to find current permalink
existing = await self.repository.get_by_file_path(str(file_path))
existing = await self.repository.get_by_file_path(file_path_str)
if existing:
return existing.permalink
@@ -73,9 +119,9 @@ class EntityService(BaseService[EntityModel]):
if markdown and markdown.frontmatter.permalink:
desired_permalink = markdown.frontmatter.permalink
else:
desired_permalink = generate_permalink(file_path)
desired_permalink = generate_permalink(file_path_str)
# Make unique if needed
# Make unique if needed - enhanced to handle character conflicts
permalink = desired_permalink
suffix = 1
while await self.repository.get_by_permalink(permalink):
@@ -150,7 +196,7 @@ class EntityService(BaseService[EntityModel]):
post = await schema_to_markdown(schema)
# write file
final_content = frontmatter.dumps(post, sort_keys=False)
final_content = dump_frontmatter(post)
checksum = await self.file_service.write_file(file_path, final_content)
# parse entity from file
@@ -227,7 +273,7 @@ class EntityService(BaseService[EntityModel]):
merged_post = frontmatter.Post(post.content, **existing_markdown.frontmatter.metadata)
# write file
final_content = frontmatter.dumps(merged_post, sort_keys=False)
final_content = dump_frontmatter(merged_post)
checksum = await self.file_service.write_file(file_path, final_content)
# parse entity from file
@@ -237,7 +283,7 @@ class EntityService(BaseService[EntityModel]):
entity = await self.update_entity_and_observations(file_path, entity_markdown)
# add relations
await self.update_entity_relations(str(file_path), entity_markdown)
await self.update_entity_relations(file_path.as_posix(), entity_markdown)
# Set final checksum to match file
entity = await self.repository.update(entity.id, {"checksum": checksum})
@@ -328,7 +374,7 @@ class EntityService(BaseService[EntityModel]):
"""
logger.debug(f"Updating entity and observations: {file_path}")
db_entity = await self.repository.get_by_file_path(str(file_path))
db_entity = await self.repository.get_by_file_path(file_path.as_posix())
# Clear observations for entity
await self.observation_repository.delete_by_fields(entity_id=db_entity.id)
@@ -452,7 +498,7 @@ class EntityService(BaseService[EntityModel]):
# Update entity and its relationships
entity = await self.update_entity_and_observations(file_path, entity_markdown)
await self.update_entity_relations(str(file_path), entity_markdown)
await self.update_entity_relations(file_path.as_posix(), entity_markdown)
# Set final checksum to match file
entity = await self.repository.update(entity.id, {"checksum": checksum})
@@ -682,8 +728,8 @@ class EntityService(BaseService[EntityModel]):
# 6. Prepare database updates
updates = {"file_path": destination_path}
# 7. Update permalink if configured
if app_config.update_permalinks_on_move:
# 7. Update permalink if configured or if entity has null permalink
if app_config.update_permalinks_on_move or old_permalink is None:
# Generate new permalink from destination path
new_permalink = await self.resolve_permalink(destination_path)
@@ -693,7 +739,12 @@ class EntityService(BaseService[EntityModel]):
)
updates["permalink"] = new_permalink
logger.info(f"Updated permalink: {old_permalink} -> {new_permalink}")
if old_permalink is None:
logger.info(
f"Generated permalink for entity with null permalink: {new_permalink}"
)
else:
logger.info(f"Updated permalink: {old_permalink} -> {new_permalink}")
# 8. Recalculate checksum
new_checksum = await self.file_service.compute_checksum(destination_path)
@@ -5,14 +5,12 @@ to ensure consistent application startup across all entry points.
"""
import asyncio
import shutil
from pathlib import Path
from loguru import logger
from basic_memory import db
from basic_memory.config import BasicMemoryConfig
from basic_memory.models import Project
from basic_memory.repository import ProjectRepository
@@ -70,63 +68,6 @@ async def reconcile_projects_with_config(app_config: BasicMemoryConfig):
logger.info("Continuing with initialization despite synchronization error")
async def migrate_legacy_projects(app_config: BasicMemoryConfig):
# Get database session - migrations handled centrally
_, session_maker = await db.get_or_create_db(
db_path=app_config.database_path,
db_type=db.DatabaseType.FILESYSTEM,
ensure_migrations=False,
)
logger.info("Migrating legacy projects...")
project_repository = ProjectRepository(session_maker)
# For each project in config.json, check if it has a .basic-memory dir
for project_name, project_path in app_config.projects.items():
legacy_dir = Path(project_path) / ".basic-memory"
if not legacy_dir.exists():
continue
logger.info(f"Detected legacy project directory: {legacy_dir}")
project = await project_repository.get_by_name(project_name)
if not project: # pragma: no cover
logger.error(f"Project {project_name} not found in database, skipping migration")
continue
logger.info(f"Starting migration for project: {project_name} (id: {project.id})")
await migrate_legacy_project_data(project, legacy_dir)
logger.info(f"Completed migration for project: {project_name}")
logger.info("Legacy projects successfully migrated")
async def migrate_legacy_project_data(project: Project, legacy_dir: Path) -> bool:
"""Check if project has legacy .basic-memory dir and migrate if needed.
Args:
project: The project to check and potentially migrate
Returns:
True if migration occurred, False otherwise
"""
# avoid circular imports
from basic_memory.cli.commands.sync import get_sync_service
sync_service = await get_sync_service(project)
sync_dir = Path(project.path)
logger.info(f"Sync starting project: {project.name}")
await sync_service.sync(sync_dir, project_name=project.name)
logger.info(f"Sync completed successfully for project: {project.name}")
# After successful sync, remove the legacy directory
try:
logger.info(f"Removing legacy directory: {legacy_dir}")
shutil.rmtree(legacy_dir)
return True
except Exception as e:
logger.error(f"Error removing legacy directory: {e}")
return False
async def initialize_file_sync(
app_config: BasicMemoryConfig,
):
@@ -186,16 +127,6 @@ async def initialize_file_sync(
sync_status_tracker.fail_project_sync(project.name, str(e))
# Continue with other projects even if one fails
# Mark migration complete if it was in progress
try:
from basic_memory.services.migration_service import migration_manager
if not migration_manager.is_ready: # pragma: no cover
migration_manager.mark_completed("Migration completed with file sync")
logger.info("Marked migration as completed after file sync")
except Exception as e: # pragma: no cover
logger.warning(f"Could not update migration status: {e}")
# Then start the watch service in the background
logger.info("Starting watch service for all projects")
# run the watch service
@@ -229,13 +160,7 @@ async def initialize_app(
# Reconcile projects from config.json with projects table
await reconcile_projects_with_config(app_config)
# Start background migration for legacy project data (non-blocking)
from basic_memory.services.migration_service import migration_manager
await migration_manager.start_background_migration(app_config)
logger.info("App initialization completed (migration running in background if needed)")
return migration_manager
def ensure_initialization(app_config: BasicMemoryConfig) -> None:
@@ -1,168 +0,0 @@
"""Migration service for handling background migrations and status tracking."""
import asyncio
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
from typing import Optional
from loguru import logger
from basic_memory.config import BasicMemoryConfig
class MigrationStatus(Enum):
"""Status of migration operations."""
NOT_NEEDED = "not_needed"
PENDING = "pending"
IN_PROGRESS = "in_progress"
COMPLETED = "completed"
FAILED = "failed"
@dataclass
class MigrationState:
"""Current state of migration operations."""
status: MigrationStatus
message: str
progress: Optional[str] = None
error: Optional[str] = None
projects_migrated: int = 0
projects_total: int = 0
class MigrationManager:
"""Manages background migration operations and status tracking."""
def __init__(self):
self._state = MigrationState(
status=MigrationStatus.NOT_NEEDED, message="No migration required"
)
self._migration_task: Optional[asyncio.Task] = None
@property
def state(self) -> MigrationState:
"""Get current migration state."""
return self._state
@property
def is_ready(self) -> bool:
"""Check if the system is ready for normal operations."""
return self._state.status in (MigrationStatus.NOT_NEEDED, MigrationStatus.COMPLETED)
@property
def status_message(self) -> str:
"""Get a user-friendly status message."""
if self._state.status == MigrationStatus.IN_PROGRESS:
progress = (
f" ({self._state.projects_migrated}/{self._state.projects_total})"
if self._state.projects_total > 0
else ""
)
return f"🔄 File sync in progress{progress}: {self._state.message}. Use sync_status() tool for details."
elif self._state.status == MigrationStatus.FAILED:
return f"❌ File sync failed: {self._state.error or 'Unknown error'}. Use sync_status() tool for details."
elif self._state.status == MigrationStatus.COMPLETED:
return "✅ File sync completed successfully"
else:
return "✅ System ready"
async def check_migration_needed(self, app_config: BasicMemoryConfig) -> bool:
"""Check if migration is needed without performing it."""
from basic_memory import db
from basic_memory.repository import ProjectRepository
try:
# Get database session
_, session_maker = await db.get_or_create_db(
db_path=app_config.database_path, db_type=db.DatabaseType.FILESYSTEM
)
project_repository = ProjectRepository(session_maker)
# Check for legacy projects
legacy_projects = []
for project_name, project_path in app_config.projects.items():
legacy_dir = Path(project_path) / ".basic-memory"
if legacy_dir.exists():
project = await project_repository.get_by_name(project_name)
if project:
legacy_projects.append(project)
if legacy_projects:
self._state = MigrationState(
status=MigrationStatus.PENDING,
message="Legacy projects detected",
projects_total=len(legacy_projects),
)
return True
else:
self._state = MigrationState(
status=MigrationStatus.NOT_NEEDED, message="No migration required"
)
return False
except Exception as e:
logger.error(f"Error checking migration status: {e}")
self._state = MigrationState(
status=MigrationStatus.FAILED, message="Migration check failed", error=str(e)
)
return False
async def start_background_migration(self, app_config: BasicMemoryConfig) -> None:
"""Start migration in background if needed."""
if not await self.check_migration_needed(app_config):
return
if self._migration_task and not self._migration_task.done():
logger.info("Migration already in progress")
return
logger.info("Starting background migration")
self._migration_task = asyncio.create_task(self._run_migration(app_config))
async def _run_migration(self, app_config: BasicMemoryConfig) -> None:
"""Run the actual migration process."""
try:
self._state.status = MigrationStatus.IN_PROGRESS
self._state.message = "Migrating legacy projects"
# Import here to avoid circular imports
from basic_memory.services.initialization import migrate_legacy_projects
# Run the migration
await migrate_legacy_projects(app_config)
self._state = MigrationState(
status=MigrationStatus.COMPLETED, message="Migration completed successfully"
)
logger.info("Background migration completed successfully")
except Exception as e:
logger.error(f"Background migration failed: {e}")
self._state = MigrationState(
status=MigrationStatus.FAILED, message="Migration failed", error=str(e)
)
async def wait_for_completion(self, timeout: Optional[float] = None) -> bool:
"""Wait for migration to complete."""
if self.is_ready:
return True
if not self._migration_task:
return False
try:
await asyncio.wait_for(self._migration_task, timeout=timeout)
return self.is_ready
except asyncio.TimeoutError:
return False
def mark_completed(self, message: str = "Migration completed") -> None:
"""Mark migration as completed externally."""
self._state = MigrationState(status=MigrationStatus.COMPLETED, message=message)
# Global migration manager instance
migration_manager = MigrationManager()
+93 -36
View File
@@ -9,7 +9,6 @@ from typing import Dict, Optional, Sequence
from loguru import logger
from sqlalchemy import text
from basic_memory.config import config, app_config
from basic_memory.models import Project
from basic_memory.repository.project_repository import ProjectRepository
from basic_memory.schemas import (
@@ -18,9 +17,8 @@ from basic_memory.schemas import (
ProjectStatistics,
SystemStatus,
)
from basic_memory.config import WATCH_STATUS_JSON
from basic_memory.config import WATCH_STATUS_JSON, ConfigManager, get_project_config, ProjectConfig
from basic_memory.utils import generate_permalink
from basic_memory.config import config_manager
class ProjectService:
@@ -33,6 +31,24 @@ class ProjectService:
super().__init__()
self.repository = repository
@property
def config_manager(self) -> ConfigManager:
"""Get a ConfigManager instance.
Returns:
Fresh ConfigManager instance for each access
"""
return ConfigManager()
@property
def config(self) -> ProjectConfig:
"""Get the current project configuration.
Returns:
Current project configuration
"""
return get_project_config()
@property
def projects(self) -> Dict[str, str]:
"""Get all configured projects.
@@ -40,7 +56,7 @@ class ProjectService:
Returns:
Dict mapping project names to their file paths
"""
return config_manager.projects
return self.config_manager.projects
@property
def default_project(self) -> str:
@@ -49,7 +65,7 @@ class ProjectService:
Returns:
The name of the default project
"""
return config_manager.default_project
return self.config_manager.default_project
@property
def current_project(self) -> str:
@@ -58,7 +74,7 @@ class ProjectService:
Returns:
The name of the current project
"""
return os.environ.get("BASIC_MEMORY_PROJECT", config_manager.default_project)
return os.environ.get("BASIC_MEMORY_PROJECT", self.config_manager.default_project)
async def list_projects(self) -> Sequence[Project]:
return await self.repository.find_all()
@@ -84,10 +100,10 @@ class ProjectService:
raise ValueError("Repository is required for add_project")
# Resolve to absolute path
resolved_path = os.path.abspath(os.path.expanduser(path))
resolved_path = Path(os.path.abspath(os.path.expanduser(path))).as_posix()
# First add to config file (this will validate the project doesn't exist)
project_config = config_manager.add_project(name, resolved_path)
project_config = self.config_manager.add_project(name, resolved_path)
# Then add to database
project_data = {
@@ -103,7 +119,7 @@ class ProjectService:
# If this should be the default project, ensure only one default exists
if set_default:
await self.repository.set_as_default(created_project.id)
config_manager.set_default_project(name)
self.config_manager.set_default_project(name)
logger.info(f"Project '{name}' set as default")
logger.info(f"Project '{name}' added at {resolved_path}")
@@ -121,10 +137,10 @@ class ProjectService:
raise ValueError("Repository is required for remove_project")
# First remove from config (this will validate the project exists and is not default)
config_manager.remove_project(name)
self.config_manager.remove_project(name)
# Then remove from database
project = await self.repository.get_by_name(name)
# Then remove from database using robust lookup
project = await self.get_project(name)
if project:
await self.repository.delete(project.id)
@@ -143,10 +159,10 @@ class ProjectService:
raise ValueError("Repository is required for set_default_project")
# First update config file (this will validate the project exists)
config_manager.set_default_project(name)
self.config_manager.set_default_project(name)
# Then update database
project = await self.repository.get_by_name(name)
# Then update database using the same lookup logic as get_project
project = await self.get_project(name)
if project:
await self.repository.set_as_default(project.id)
else:
@@ -196,7 +212,7 @@ class ProjectService:
elif len(default_projects) == 0: # pragma: no cover
# No default project - set the config default as default
# This is defensive code for edge cases where no default exists
config_default = config_manager.default_project # pragma: no cover
config_default = self.config_manager.default_project # pragma: no cover
config_project = await self.repository.get_by_name(config_default) # pragma: no cover
if config_project: # pragma: no cover
await self.repository.set_as_default(config_project.id) # pragma: no cover
@@ -221,7 +237,7 @@ class ProjectService:
db_projects_by_permalink = {p.permalink: p for p in db_projects}
# Get all projects from configuration and normalize names if needed
config_projects = config_manager.projects.copy()
config_projects = self.config_manager.projects.copy()
updated_config = {}
config_updated = False
@@ -237,8 +253,9 @@ class ProjectService:
# Update the configuration if any changes were made
if config_updated:
config_manager.config.projects = updated_config
config_manager.save_config(config_manager.config)
config = self.config_manager.load_config()
config.projects = updated_config
self.config_manager.save_config(config)
logger.info("Config updated with normalized project names")
# Use the normalized config for further processing
@@ -261,19 +278,19 @@ class ProjectService:
for name, project in db_projects_by_permalink.items():
if name not in config_projects:
logger.info(f"Adding project '{name}' to configuration")
config_manager.add_project(name, project.path)
self.config_manager.add_project(name, project.path)
# Ensure database default project state is consistent
await self._ensure_single_default_project()
# Make sure default project is synchronized between config and database
db_default = await self.repository.get_default_project()
config_default = config_manager.default_project
config_default = self.config_manager.default_project
if db_default and db_default.name != config_default:
# Update config to match DB default
logger.info(f"Updating default project in config to '{db_default.name}'")
config_manager.set_default_project(db_default.name)
self.config_manager.set_default_project(db_default.name)
elif not db_default and config_default:
# Update DB to match config default (if the project exists)
project = await self.repository.get_by_name(config_default)
@@ -292,6 +309,47 @@ class ProjectService:
# MCP components might not be available in all contexts
logger.debug("MCP session not available, skipping session refresh")
async def move_project(self, name: str, new_path: str) -> None:
"""Move a project to a new location.
Args:
name: The name of the project to move
new_path: The new absolute path for the project
Raises:
ValueError: If the project doesn't exist or repository isn't initialized
"""
if not self.repository:
raise ValueError("Repository is required for move_project")
# Resolve to absolute path
resolved_path = Path(os.path.abspath(os.path.expanduser(new_path))).as_posix()
# Validate project exists in config
if name not in self.config_manager.projects:
raise ValueError(f"Project '{name}' not found in configuration")
# Create the new directory if it doesn't exist
Path(resolved_path).mkdir(parents=True, exist_ok=True)
# Update in configuration
config = self.config_manager.load_config()
old_path = config.projects[name]
config.projects[name] = resolved_path
self.config_manager.save_config(config)
# Update in database using robust lookup
project = await self.get_project(name)
if project:
await self.repository.update_path(project.id, resolved_path)
logger.info(f"Moved project '{name}' from {old_path} to {resolved_path}")
else:
logger.error(f"Project '{name}' exists in config but not in database")
# Restore the old path in config since DB update failed
config.projects[name] = old_path
self.config_manager.save_config(config)
raise ValueError(f"Project '{name}' not found in database")
async def update_project( # pragma: no cover
self, name: str, updated_path: Optional[str] = None, is_active: Optional[bool] = None
) -> None:
@@ -309,24 +367,23 @@ class ProjectService:
raise ValueError("Repository is required for update_project")
# Validate project exists in config
if name not in config_manager.projects:
if name not in self.config_manager.projects:
raise ValueError(f"Project '{name}' not found in configuration")
# Get project from database
project = await self.repository.get_by_name(name)
# Get project from database using robust lookup
project = await self.get_project(name)
if not project:
logger.error(f"Project '{name}' exists in config but not in database")
return
# Update path if provided
if updated_path:
resolved_path = os.path.abspath(os.path.expanduser(updated_path))
resolved_path = Path(os.path.abspath(os.path.expanduser(updated_path))).as_posix()
# Update in config
projects = config_manager.config.projects.copy()
projects[name] = resolved_path
config_manager.config.projects = projects
config_manager.save_config(config_manager.config)
config = self.config_manager.load_config()
config.projects[name] = resolved_path
self.config_manager.save_config(config)
# Update in database
project.path = resolved_path
@@ -347,7 +404,7 @@ class ProjectService:
if active_projects:
new_default = active_projects[0]
await self.repository.set_as_default(new_default.id)
config_manager.set_default_project(new_default.name)
self.config_manager.set_default_project(new_default.name)
logger.info(
f"Changed default project to '{new_default.name}' as '{name}' was deactivated"
)
@@ -365,9 +422,9 @@ class ProjectService:
raise ValueError("Repository is required for get_project_info")
# Use specified project or fall back to config project
project_name = project_name or config.project
project_name = project_name or self.config.project
# Get project path from configuration
name, project_path = config_manager.get_project(project_name)
name, project_path = self.config_manager.get_project(project_name)
if not name: # pragma: no cover
raise ValueError(f"Project '{project_name}' not found in configuration")
@@ -393,11 +450,11 @@ class ProjectService:
db_projects_by_permalink = {p.permalink: p for p in db_projects}
# Get default project info
default_project = config_manager.default_project
default_project = self.config_manager.default_project
# Convert config projects to include database info
enhanced_projects = {}
for name, path in config_manager.projects.items():
for name, path in self.config_manager.projects.items():
config_permalink = generate_permalink(name)
db_project = db_projects_by_permalink.get(config_permalink)
enhanced_projects[name] = {
@@ -673,7 +730,7 @@ class ProjectService:
import basic_memory
# Get database information
db_path = app_config.database_path
db_path = self.config_manager.config.database_path
db_size = db_path.stat().st_size if db_path.exists() else 0
db_size_readable = f"{db_size / (1024 * 1024):.2f} MB"
@@ -131,6 +131,23 @@ class SyncStatusTracker:
"""Check if system is ready (no sync in progress)."""
return self._global_status in (SyncStatus.IDLE, SyncStatus.COMPLETED)
def is_project_ready(self, project_name: str) -> bool:
"""Check if a specific project is ready for operations.
Args:
project_name: Name of the project to check
Returns:
True if the project is ready (completed, watching, or not tracked),
False if the project is syncing, scanning, or failed
"""
project_status = self._project_statuses.get(project_name)
if not project_status:
# Project not tracked = ready (likely hasn't been synced yet)
return True
return project_status.status in (SyncStatus.COMPLETED, SyncStatus.WATCHING, SyncStatus.IDLE)
def get_project_status(self, project_name: str) -> Optional[ProjectSyncStatus]:
"""Get status for a specific project."""
return self._project_statuses.get(project_name)

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