feat: Multi-Domain Memories (User-Level vs Project-Level Storage)#25
Conversation
- Create PROGRESS.md with 24 tasks across 5 phases - Update README.md with approval and start timestamps - Update CHANGELOG.md with approval entry 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Task 1.1 complete - Add Domain Enum to Config Changes: - Add Domain enum with USER and PROJECT values - Add get_user_memories_path() for user-memories bare repo location - Add get_user_index_path() for user-domain SQLite index - Both functions support optional ensure_exists parameter for lazy dir creation - Add comprehensive tests for new configuration (17 tests) All 1851 tests pass, 88% coverage. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add domain awareness to the Memory model for multi-domain storage: - Add `domain: str` field with default "project" for backward compatibility - Add `domain_enum` property to get Domain enum value - Add `is_user_domain` and `is_project_domain` convenience properties - Add domain properties to MemoryResult for uniform access - Add 7 tests covering domain field and properties Uses string storage for SQLite/JSON serialization compatibility, with enum property for type-safe programmatic access. Part of: SPEC-2025-12-25-001 (Multi-Domain Memories) Resolves: Task 1.2 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 Foundation complete for multi-domain memories: Schema Migration (Task 1.3): - Bump SCHEMA_VERSION to 3 - Add domain TEXT column with 'project' default - Add idx_memories_domain index - Implement migration 3 for existing databases IndexService Domain (Task 1.4): - Update insert(), insert_batch(), update() for domain field - Update _row_to_memory() with backward-compatible domain reading Tests: - Add TestSchemaMigration class with v2→v3 migration test - Add fresh database schema test - Add domain-specific insert tests Closes phase 1 of SPEC-2025-12-25-001. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…s 2.1-2.4) ## Task 2.1: GitOps Factory for Domain - Add GitOps.for_domain(domain) class method for domain-specific instances - Implement domain instance caching with clear_domain_cache() for testing - USER domain uses user-memories path, PROJECT domain uses repo path ## Task 2.2: Initialize User-Memories Bare Repo - Add ensure_user_repo_initialized() class method - Creates bare git repo at ~/.local/share/memory-plugin/user-memories/ - Configures git identity and creates initial empty commit - Add is_bare_repository() method for verification ## Task 2.3: Add Domain Filter to IndexService Search - Add optional domain parameter to search_vector() - Add optional domain parameter to search_text() - Both methods filter by domain when specified, backward compatible ## Task 2.4: Add Domain Filter to Other Index Methods - Add domain filter to get_by_spec(), get_by_namespace(), list_recent() - Add domain filter to count() method - Update get_stats() to include by_domain breakdown - Add by_domain field and by_domain_dict property to IndexStats model Tests: 14 new GitOps tests, 13 new domain filter tests (1885 total, 89% coverage) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Mark Tasks 2.1-2.4 as done in IMPLEMENTATION_PLAN.md - Update Phase 2 status to 100% done in PROGRESS.md - Add session notes for Phase 2 completion - Update current_phase to 2 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Apply 8 high-priority fixes from comprehensive code review: Security: - CRIT-001: Add ThreadPoolExecutor timeout (30s/120s) to embedding ops - SEC-HIGH-001: Add symlink verification before user-memories git init - SEC-HIGH-002: Add 64KB YAML size limit to prevent billion laughs - SEC-HIGH-003: Implement PID-based stale lock detection Performance: - PERF-HIGH-001: Add pagination (limit/offset) to get_all_ids() - PERF-HIGH-004: Add composite indexes for common query patterns Code Quality: - CRIT-003: Remove unused thread lock, document SQLite WAL concurrency - QUAL-HIGH-001: Replace 10 broad exception handlers with specific types Also removes code-review reports from docs/ (not needed in repo). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
d22ecbd to
bfd5cc9
Compare
Add noqa: ARG005 comments for unused lambda arguments in test mocks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR implements comprehensive multi-domain memory storage, adding support for:
- User domain: Global, cross-project memories stored in
~/.local/share/memory-plugin/user-memories/ - Project domain: Repository-scoped memories (existing behavior)
The implementation spans 5 phases with 24 tasks, adding domain-aware capture, recall, sync, and hooks integration. All tasks are marked complete with 1955 passing tests.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/git_notes_memory/config.py | Domain enum, user paths, remote config |
| src/git_notes_memory/models.py | Memory model with domain field |
| src/git_notes_memory/index.py | Schema v3 migration, domain filtering |
| src/git_notes_memory/git_ops.py | Domain factory, user repo init |
| src/git_notes_memory/capture.py | Domain-aware capture, user service |
| src/git_notes_memory/recall.py | Multi-domain search with merge/dedup |
| src/git_notes_memory/sync.py | User memory sync methods |
| src/git_notes_memory/hooks/ | Domain markers, context builder updates |
| tests/ | Comprehensive test coverage additions |
The implementation appears thorough and well-tested. No blocking issues identified.
| # Initialize bare repository | ||
| cmd = ["git", "init", "--bare", str(user_path)] | ||
| try: | ||
| result = subprocess.run( |
| self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch | ||
| ) -> None: | ||
| """Test get_user_capture_service returns a CaptureService.""" | ||
| import git_notes_memory.capture as capture_module |
There was a problem hiding this comment.
Module 'git_notes_memory.capture' is imported with both 'import' and 'import from'.
| ) -> None: | ||
| """Test get_user_capture_service returns a CaptureService.""" | ||
| import git_notes_memory.capture as capture_module | ||
| import git_notes_memory.config as config_module |
There was a problem hiding this comment.
Module 'git_notes_memory.config' is imported with both 'import' and 'import from'.
| self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch | ||
| ) -> None: | ||
| """Test get_user_capture_service returns the same instance.""" | ||
| import git_notes_memory.capture as capture_module |
There was a problem hiding this comment.
Module 'git_notes_memory.capture' is imported with both 'import' and 'import from'.
| ) -> None: | ||
| """Test get_user_capture_service returns the same instance.""" | ||
| import git_notes_memory.capture as capture_module | ||
| import git_notes_memory.config as config_module |
There was a problem hiding this comment.
Module 'git_notes_memory.config' is imported with both 'import' and 'import from'.
| self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch | ||
| ) -> None: | ||
| """Test get_user_capture_service uses GitOps.for_domain(USER).""" | ||
| import git_notes_memory.capture as capture_module |
There was a problem hiding this comment.
Module 'git_notes_memory.capture' is imported with both 'import' and 'import from'.
| ) -> None: | ||
| """Test get_user_capture_service uses GitOps.for_domain(USER).""" | ||
| import git_notes_memory.capture as capture_module | ||
| import git_notes_memory.config as config_module |
There was a problem hiding this comment.
Module 'git_notes_memory.config' is imported with both 'import' and 'import from'.
| self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch | ||
| ) -> None: | ||
| """Test get_user_capture_service returns service with IndexService.""" | ||
| import git_notes_memory.capture as capture_module |
There was a problem hiding this comment.
Module 'git_notes_memory.capture' is imported with both 'import' and 'import from'.
| ) -> None: | ||
| """Test get_user_capture_service returns service with IndexService.""" | ||
| import git_notes_memory.capture as capture_module | ||
| import git_notes_memory.config as config_module |
There was a problem hiding this comment.
Module 'git_notes_memory.config' is imported with both 'import' and 'import from'.
| content = os.read(fd, 32).decode("utf-8", errors="ignore").strip() | ||
| if content and content.isdigit(): | ||
| return int(content) | ||
| except OSError: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
Multi-Domain Memories (SPEC-2025-12-25-001)
Implements GitHub Issue #13 - User-level vs project-level memory storage.
Summary
Add support for multi-domain memory storage to distinguish between:
~/.local/share/memory-plugin/user-memories/Key Features
[global]inline and▶ global:namespace ───blocksImplementation Progress
Spec Documents
Architecture Decisions
Auto-generated by /claude-spec:implement