@@ -9,6 +9,7 @@ Comprehensive reference for the mnemonic Python library modules.
99 - [ paths] ( #paths ) - Path resolution and filesystem layout
1010 - [ config] ( #config ) - Configuration management
1111 - [ memory_reader] ( #memory_reader ) - Memory file parsing
12+ - [ migrate_filenames] ( #migrate_filenames ) - Memory file migration utilities
1213 - [ search] ( #search ) - Memory search and ranking
1314 - [ relationships] ( #relationships ) - Relationship types and linking
1415 - [ ontology] ( #ontology ) - Custom ontology support
@@ -156,6 +157,112 @@ Dictionary with keys:
156157
157158---
158159
160+ ### migrate_filenames
161+
162+ ** File** : ` lib/migrate_filenames.py `
163+
164+ Migration utilities for transitioning memory files from ` {uuid}-{slug}.memory.md ` to ` {slug}.memory.md ` naming convention. Handles collision detection, content merging, and idempotent execution.
165+
166+ ** Key Functions** :
167+
168+ ```` python
169+ from lib.migrate_filenames import migrate_all, is_migration_complete, migrate_file
170+ from pathlib import Path
171+
172+ # Check if migration already completed
173+ memory_root = Path.home() / " .claude" / " mnemonic"
174+ if not is_migration_complete(memory_root):
175+ # Perform dry run first
176+ results = migrate_all(memory_root, dry_run = True )
177+ print (f " Would migrate { len (results)} files " )
178+
179+ # Execute migration
180+ results = migrate_all(memory_root, dry_run = False )
181+ for result in results:
182+ print (f " { result.action} : { result.original.name} → { result.target.name} " )
183+ ````
184+
185+ ** Migration Behavior** :
186+ - ** Rename** : ` {uuid}-decision.memory.md ` → ` decision.memory.md ` (preserves git history)
187+ - ** Merge** : If ` decision.memory.md ` already exists, merges content from UUID-prefixed file
188+ - ** Idempotent** : Marks completion with ` .migration_slug_only_complete ` marker file
189+
190+ ** API Reference** :
191+
192+ #### ` migrate_all(mnemonic_root: Path, dry_run: bool = False) -> list[MigrationResult] `
193+ Migrate all UUID-prefixed memory files in directory tree.
194+
195+ ** Parameters** :
196+ - ` mnemonic_root ` : Root directory to scan recursively
197+ - ` dry_run ` : If True, return results without modifying files
198+
199+ ** Returns** : List of ` MigrationResult ` objects with fields:
200+ - ` original ` (Path): Source file path
201+ - ` target ` (Path): Destination file path
202+ - ` action ` (str): One of "renamed", "merged", "skipped"
203+ - ` merged_with ` (Optional[ Path] ): Target file if merged
204+
205+ ** Behavior** :
206+ - Skips if ` .migration_slug_only_complete ` marker exists
207+ - Uses ` git mv ` when possible to preserve history
208+ - Merges content on collision (appends under "Merged Content" heading)
209+ - Creates marker file on completion
210+
211+ #### ` migrate_file(file_path: Path, dry_run: bool = False) -> MigrationResult `
212+ Migrate a single memory file.
213+
214+ ** Parameters** :
215+ - ` file_path ` : Path to memory file
216+ - ` dry_run ` : If True, return result without modifying files
217+
218+ ** Returns** : ` MigrationResult ` object
219+
220+ ** Collision Handling** :
221+ When target file exists, merges content by:
222+ 1 . Keeping existing frontmatter (preserves original ID, dates)
223+ 2 . Appending incoming body under separator
224+ 3 . Adding provenance note with incoming UUID
225+
226+ #### ` is_migration_complete(mnemonic_root: Path) -> bool `
227+ Check if migration has been run.
228+
229+ ** Returns** : True if ` .migration_slug_only_complete ` marker exists
230+
231+ #### ` mark_migration_complete(mnemonic_root: Path) -> None `
232+ Create marker file to prevent re-running migration.
233+
234+ ** Use Cases** :
235+ - ** Batch Migration** : Run once during setup to clean up legacy filenames
236+ - ** Continuous Integration** : Check ` is_migration_complete() ` before operations
237+ - ** Manual Recovery** : Use ` migrate_file() ` for selective migration after conflicts
238+
239+ ** Example - Bulk Migration** :
240+
241+ ```` python
242+ from lib.migrate_filenames import migrate_all, migration_summary
243+ from pathlib import Path
244+
245+ memory_root = Path(" ~/.claude/mnemonic" ).expanduser()
246+
247+ # Execute with logging
248+ results = migrate_all(memory_root, dry_run = False )
249+ summary = migration_summary(results)
250+
251+ print (f " Migration complete: " )
252+ print (f " Renamed: { summary[' renamed' ]} files " )
253+ print (f " Merged: { summary[' merged' ]} files " )
254+ print (f " Skipped: { summary[' skipped' ]} files " )
255+ ````
256+
257+ ** Design Notes** :
258+ - Atomic writes via ` .tmp ` files to prevent corruption
259+ - Git-aware (uses ` git mv ` when possible)
260+ - Collision-safe (merges rather than overwrites)
261+ - Idempotent by default (marker file prevents re-runs)
262+ - CLI support: ` python -m lib.migrate_filenames --dry-run `
263+
264+ ---
265+
159266### search
160267
161268** File** : ` lib/search.py `
@@ -633,6 +740,7 @@ def test_memory_operations(test_resolver):
633740| ` paths.py ` | Path resolution | ` get_memory_dir() ` , ` get_search_paths() ` |
634741| ` config.py ` | Configuration | ` get_memory_root() ` , ` MnemonicConfig.load() ` |
635742| ` memory_reader.py ` | Parsing | ` get_memory_metadata() ` , ` get_memory_summary() ` |
743+ | ` migrate_filenames.py ` | File migration | ` migrate_all() ` , ` migrate_file() ` , ` is_migration_complete() ` |
636744| ` search.py ` | Search/ranking | ` search_memories() ` , ` find_related_memories_scored() ` |
637745| ` relationships.py ` | Linking | ` add_bidirectional_relationship() ` , ` get_inverse() ` |
638746| ` ontology.py ` | Validation | ` load_ontology_data() ` , ` validate_memory_against_ontology() ` |
@@ -649,6 +757,9 @@ from lib.config import get_memory_root
649757# Memory reading
650758from lib.memory_reader import get_memory_metadata, get_memory_summary
651759
760+ # Migration
761+ from lib.migrate_filenames import migrate_all, is_migration_complete
762+
652763# Search
653764from lib.search import search_memories, find_related_memories_scored
654765
0 commit comments