|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +`git-notes-memory` is a Python library and Claude Code plugin that provides git-native, semantically-searchable memory storage. Memories are stored as git notes with YAML front matter and indexed in SQLite with sqlite-vec for vector similarity search. |
| 8 | + |
| 9 | +## Development Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Install with dev dependencies |
| 13 | +uv sync |
| 14 | + |
| 15 | +# Run all tests |
| 16 | +make test |
| 17 | + |
| 18 | +# Run tests with coverage (80% minimum required) |
| 19 | +make coverage |
| 20 | + |
| 21 | +# Run a specific test file |
| 22 | +uv run pytest tests/test_capture.py -v |
| 23 | + |
| 24 | +# Run a single test |
| 25 | +uv run pytest tests/test_capture.py::TestCaptureService::test_capture_basic -v |
| 26 | + |
| 27 | +# Skip slow tests |
| 28 | +uv run pytest -m "not slow" |
| 29 | + |
| 30 | +# Run all quality checks (format, lint, typecheck, security, tests) |
| 31 | +make quality |
| 32 | + |
| 33 | +# Individual quality checks |
| 34 | +make format # Auto-fix formatting |
| 35 | +make lint # Ruff linting |
| 36 | +make typecheck # mypy strict mode |
| 37 | +make security # bandit security scan |
| 38 | +``` |
| 39 | + |
| 40 | +## Architecture |
| 41 | + |
| 42 | +### Service Layer Pattern |
| 43 | + |
| 44 | +The codebase uses a singleton service factory pattern with lazy initialization: |
| 45 | + |
| 46 | +``` |
| 47 | +__init__.py # Lazy imports via __getattr__ to avoid loading embedding model at import |
| 48 | + └── get_capture_service() → CaptureService |
| 49 | + └── get_recall_service() → RecallService |
| 50 | + └── get_sync_service() → SyncService |
| 51 | +``` |
| 52 | + |
| 53 | +Services are exposed through factory functions (`get_*_service()`) that return singleton instances. Internal modules use `get_default_service()` naming. |
| 54 | + |
| 55 | +### Core Data Flow |
| 56 | + |
| 57 | +``` |
| 58 | +Capture: |
| 59 | + CaptureService.capture() |
| 60 | + → validate (namespace, summary ≤100 chars, content ≤100KB) |
| 61 | + → serialize_note() (YAML front matter + body) |
| 62 | + → GitOps.append_note() (atomic append to refs/notes/mem/{namespace}) |
| 63 | + → EmbeddingService.embed() (sentence-transformers, graceful degradation) |
| 64 | + → IndexService.insert() (SQLite + sqlite-vec) |
| 65 | +
|
| 66 | +Recall: |
| 67 | + RecallService.search() |
| 68 | + → EmbeddingService.embed(query) |
| 69 | + → IndexService.search_vector() (KNN via sqlite-vec) |
| 70 | + → Memory objects with distance scores |
| 71 | +``` |
| 72 | + |
| 73 | +### Git Notes Storage |
| 74 | + |
| 75 | +Memories are stored under `refs/notes/mem/{namespace}` where namespace is one of: |
| 76 | +`inception`, `elicitation`, `research`, `decisions`, `progress`, `blockers`, `reviews`, `learnings`, `retrospective`, `patterns` |
| 77 | + |
| 78 | +Each note has YAML front matter: |
| 79 | +```yaml |
| 80 | +--- |
| 81 | +type: decisions |
| 82 | +timestamp: 2024-01-15T10:30:00Z |
| 83 | +summary: Use PostgreSQL for persistence |
| 84 | +spec: my-project |
| 85 | +tags: [database, architecture] |
| 86 | +--- |
| 87 | +## Context |
| 88 | +... |
| 89 | +``` |
| 90 | + |
| 91 | +### Key Modules |
| 92 | + |
| 93 | +| Module | Responsibility | |
| 94 | +|--------|---------------| |
| 95 | +| `capture.py` | Memory capture with file locking (`fcntl`) for concurrency | |
| 96 | +| `recall.py` | Search and retrieval with progressive hydration | |
| 97 | +| `index.py` | SQLite + sqlite-vec for metadata and vector search | |
| 98 | +| `embedding.py` | Sentence-transformer embeddings (all-MiniLM-L6-v2) | |
| 99 | +| `git_ops.py` | Git notes operations with security validation | |
| 100 | +| `note_parser.py` | YAML front matter parsing/serialization | |
| 101 | +| `models.py` | Frozen dataclasses for all domain objects | |
| 102 | +| `sync.py` | Index synchronization with git notes | |
| 103 | + |
| 104 | +### Models |
| 105 | + |
| 106 | +All models are immutable (`@dataclass(frozen=True)`): |
| 107 | +- `Memory` - Core entity with id format `{namespace}:{commit_sha}:{index}` |
| 108 | +- `MemoryResult` - Memory + distance score from vector search |
| 109 | +- `CaptureResult` - Operation result with success/warning status |
| 110 | +- `HydrationLevel` - SUMMARY → FULL → FILES progressive loading |
| 111 | + |
| 112 | +### Claude Code Plugin Integration |
| 113 | + |
| 114 | +The `.claude-plugin/` directory defines: |
| 115 | +- Commands: `/capture`, `/recall`, `/search`, `/sync`, `/status` |
| 116 | +- Hooks: `Stop` (sync index on session end) |
| 117 | +- Skills: `memory-recall` for semantic search |
| 118 | + |
| 119 | +## Code Conventions |
| 120 | + |
| 121 | +- Python 3.11+ with full type annotations (mypy strict) |
| 122 | +- Google-style docstrings |
| 123 | +- Frozen dataclasses for all models (immutability) |
| 124 | +- Tuple over list for immutable collections in models |
| 125 | +- Factory functions expose services; internal modules use `get_default_service()` |
| 126 | +- Graceful degradation: embedding failures don't block capture |
| 127 | + |
| 128 | +## Testing |
| 129 | + |
| 130 | +The test suite uses pytest with automatic singleton reset via `conftest.py`. Each test gets isolated service instances to prevent cross-test pollution. |
| 131 | + |
| 132 | +```python |
| 133 | +# Tests automatically reset singletons via autouse fixture |
| 134 | +# For manual isolation, use tmp_path and monkeypatch: |
| 135 | +@pytest.fixture |
| 136 | +def capture_service(tmp_path, monkeypatch): |
| 137 | + monkeypatch.setenv("MEMORY_PLUGIN_DATA_DIR", str(tmp_path)) |
| 138 | + return get_capture_service(repo_path=tmp_path) |
| 139 | +``` |
| 140 | + |
| 141 | +## Environment Variables |
| 142 | + |
| 143 | +| Variable | Description | Default | |
| 144 | +|----------|-------------|---------| |
| 145 | +| `MEMORY_PLUGIN_DATA_DIR` | Data/index directory | `~/.local/share/memory-plugin/` | |
| 146 | +| `MEMORY_PLUGIN_GIT_NAMESPACE` | Git notes ref prefix | `refs/notes/mem` | |
| 147 | +| `MEMORY_PLUGIN_EMBEDDING_MODEL` | Embedding model | `all-MiniLM-L6-v2` | |
0 commit comments