memctl 0.2.1__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {memctl-0.2.1 → memctl-0.4.0}/PKG-INFO +130 -10
  2. {memctl-0.2.1 → memctl-0.4.0}/README.md +129 -9
  3. {memctl-0.2.1 → memctl-0.4.0}/memctl/__init__.py +1 -1
  4. memctl-0.4.0/memctl/chat.py +414 -0
  5. {memctl-0.2.1 → memctl-0.4.0}/memctl/cli.py +345 -0
  6. {memctl-0.2.1 → memctl-0.4.0}/memctl/ingest.py +6 -2
  7. memctl-0.4.0/memctl/inspect.py +586 -0
  8. memctl-0.4.0/memctl/mount.py +111 -0
  9. {memctl-0.2.1 → memctl-0.4.0}/memctl/store.py +183 -5
  10. memctl-0.4.0/memctl/sync.py +368 -0
  11. {memctl-0.2.1 → memctl-0.4.0}/memctl.egg-info/PKG-INFO +130 -10
  12. {memctl-0.2.1 → memctl-0.4.0}/memctl.egg-info/SOURCES.txt +8 -0
  13. {memctl-0.2.1 → memctl-0.4.0}/pyproject.toml +1 -1
  14. memctl-0.4.0/tests/test_chat.py +317 -0
  15. {memctl-0.2.1 → memctl-0.4.0}/tests/test_cli.py +247 -1
  16. {memctl-0.2.1 → memctl-0.4.0}/tests/test_forward_compat.py +50 -0
  17. memctl-0.4.0/tests/test_inspect.py +571 -0
  18. memctl-0.4.0/tests/test_mount.py +118 -0
  19. {memctl-0.2.1 → memctl-0.4.0}/tests/test_store.py +177 -1
  20. memctl-0.4.0/tests/test_sync.py +297 -0
  21. {memctl-0.2.1 → memctl-0.4.0}/LICENSE +0 -0
  22. {memctl-0.2.1 → memctl-0.4.0}/memctl/config.py +0 -0
  23. {memctl-0.2.1 → memctl-0.4.0}/memctl/consolidate.py +0 -0
  24. {memctl-0.2.1 → memctl-0.4.0}/memctl/extract.py +0 -0
  25. {memctl-0.2.1 → memctl-0.4.0}/memctl/loop.py +0 -0
  26. {memctl-0.2.1 → memctl-0.4.0}/memctl/mcp/__init__.py +0 -0
  27. {memctl-0.2.1 → memctl-0.4.0}/memctl/mcp/formatting.py +0 -0
  28. {memctl-0.2.1 → memctl-0.4.0}/memctl/mcp/server.py +0 -0
  29. {memctl-0.2.1 → memctl-0.4.0}/memctl/mcp/tools.py +0 -0
  30. {memctl-0.2.1 → memctl-0.4.0}/memctl/policy.py +0 -0
  31. {memctl-0.2.1 → memctl-0.4.0}/memctl/proposer.py +0 -0
  32. {memctl-0.2.1 → memctl-0.4.0}/memctl/similarity.py +0 -0
  33. {memctl-0.2.1 → memctl-0.4.0}/memctl/types.py +0 -0
  34. {memctl-0.2.1 → memctl-0.4.0}/memctl.egg-info/dependency_links.txt +0 -0
  35. {memctl-0.2.1 → memctl-0.4.0}/memctl.egg-info/entry_points.txt +0 -0
  36. {memctl-0.2.1 → memctl-0.4.0}/memctl.egg-info/requires.txt +0 -0
  37. {memctl-0.2.1 → memctl-0.4.0}/memctl.egg-info/top_level.txt +0 -0
  38. {memctl-0.2.1 → memctl-0.4.0}/setup.cfg +0 -0
  39. {memctl-0.2.1 → memctl-0.4.0}/tests/test_contracts.py +0 -0
  40. {memctl-0.2.1 → memctl-0.4.0}/tests/test_extract.py +0 -0
  41. {memctl-0.2.1 → memctl-0.4.0}/tests/test_ingest.py +0 -0
  42. {memctl-0.2.1 → memctl-0.4.0}/tests/test_loop.py +0 -0
  43. {memctl-0.2.1 → memctl-0.4.0}/tests/test_pipe_compose.py +0 -0
  44. {memctl-0.2.1 → memctl-0.4.0}/tests/test_policy.py +0 -0
  45. {memctl-0.2.1 → memctl-0.4.0}/tests/test_similarity.py +0 -0
  46. {memctl-0.2.1 → memctl-0.4.0}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memctl
3
- Version: 0.2.1
3
+ Version: 0.4.0
4
4
  Summary: A Unix-native memory control plane for LLM orchestration
5
5
  Author-email: Olivier Vitrac <olivier.vitrac@adservio.fr>
6
6
  License: MIT
@@ -150,7 +150,34 @@ memctl search "authentication"
150
150
  memctl search "database" --json -k 5
151
151
  ```
152
152
 
153
- ### 5. Inspect and manage
153
+ ### 5. Inspect a folder (one-liner)
154
+
155
+ ```bash
156
+ # Auto-mounts, auto-syncs, and inspects — all in one command
157
+ memctl inspect docs/
158
+
159
+ # Same in JSON (for scripts)
160
+ memctl inspect docs/ --json
161
+
162
+ # Skip sync (use cached state)
163
+ memctl inspect docs/ --no-sync
164
+ ```
165
+
166
+ `inspect` auto-mounts the folder if needed, checks staleness, syncs only if stale, and produces a structural summary. All implicit actions are announced on stderr.
167
+
168
+ ### 6. Chat with memory-backed context
169
+
170
+ ```bash
171
+ # Interactive chat with any LLM
172
+ memctl chat --llm "claude -p" --session
173
+
174
+ # With pre-ingested files and answer storage
175
+ memctl chat --llm "ollama run granite3.1:2b" --source docs/ --store --session
176
+ ```
177
+
178
+ Each question recalls from the memory store, sends context + question to the LLM, and displays the answer. `--session` keeps a sliding window of recent Q&A pairs. `--store` persists answers as STM items.
179
+
180
+ ### 7. Manage
154
181
 
155
182
  ```bash
156
183
  memctl show MEM-abc123def456 # Show item details
@@ -180,6 +207,10 @@ memctl <command> [options]
180
207
  | `stats` | Store statistics |
181
208
  | `consolidate [--dry-run]` | Deterministic merge of similar STM items |
182
209
  | `loop QUERY --llm CMD` | Bounded recall-answer loop with LLM |
210
+ | `mount PATH` | Register a folder as a structured source |
211
+ | `sync [PATH]` | Delta-sync mounted folders into the store |
212
+ | `inspect [PATH]` | Structural inspection with auto-mount and auto-sync |
213
+ | `chat --llm CMD` | Interactive memory-backed chat REPL |
183
214
  | `serve` | Start MCP server (requires `memctl[mcp]`) |
184
215
 
185
216
  ### Global Flags
@@ -291,6 +322,77 @@ memctl push "database schema" --source src/ \
291
322
  memctl loop --replay trace.jsonl "original question"
292
323
  ```
293
324
 
325
+ #### `memctl mount`
326
+
327
+ ```bash
328
+ memctl mount PATH [--name NAME] [--ignore PATTERN ...] [--lang HINT]
329
+ memctl mount --list
330
+ memctl mount --remove ID_OR_NAME
331
+ ```
332
+
333
+ Registers a folder as a structured source. Stores metadata only — no scanning, no ingestion. The folder contents are synced separately via `sync` or automatically via `inspect`.
334
+
335
+ #### `memctl sync`
336
+
337
+ ```bash
338
+ memctl sync [PATH] [--full] [--json] [--quiet]
339
+ ```
340
+
341
+ Delta-syncs mounted folders into the memory store. Uses a 3-tier delta rule:
342
+ 1. **New file** (not in DB) → ingest
343
+ 2. **Size + mtime match** → fast skip (no hashing)
344
+ 3. **Hash compare** → ingest only if content changed
345
+
346
+ If `PATH` is given but not yet mounted, it is auto-registered first. `--full` forces re-processing of all files.
347
+
348
+ #### `memctl inspect`
349
+
350
+ ```bash
351
+ # Orchestration mode — auto-mounts, auto-syncs, and inspects
352
+ memctl inspect PATH [--sync auto|always|never] [--no-sync] [--mount-mode persist|ephemeral]
353
+ [--budget N] [--ignore PATTERN ...] [--json] [--quiet]
354
+
355
+ # Classic mode — inspect an existing mount by ID/name
356
+ memctl inspect --mount ID_OR_NAME [--budget N] [--json] [--quiet]
357
+ ```
358
+
359
+ When given a positional `PATH`, inspect operates in **orchestration mode**:
360
+ 1. **Auto-mount** — registers the folder if not already mounted
361
+ 2. **Staleness check** — compares disk inventory (path/size/mtime triples) against the store
362
+ 3. **Auto-sync** — runs delta sync only if stale (or always/never per `--sync`)
363
+ 4. **Inspect** — generates a deterministic structural summary
364
+
365
+ Output includes file/chunk/size totals, per-folder breakdown, per-extension distribution, top-5 largest files, and rule-based observations. All paths in output are mount-relative (never absolute).
366
+
367
+ `--mount-mode ephemeral` removes the mount record after inspection (corpus data is preserved). `--no-sync` is shorthand for `--sync never`.
368
+
369
+ All implicit actions (mount, sync) are announced on stderr. `--quiet` suppresses them.
370
+
371
+ #### `memctl chat`
372
+
373
+ ```bash
374
+ memctl chat --llm CMD [--session] [--store] [--protocol passive|json|regex]
375
+ [--max-calls N] [--budget N] [--source FILE ...] [--quiet]
376
+ ```
377
+
378
+ Interactive memory-backed chat REPL. Each turn: FTS5 recall from the memory store, send context + question to the LLM, display the answer.
379
+
380
+ **Stateless by default.** Each question sees only the memory store — no hidden conversation state.
381
+
382
+ | Flag | Default | Description |
383
+ |------|---------|-------------|
384
+ | `--llm CMD` | *(required)* | LLM command (e.g. `"claude -p"`, `"ollama run granite3.1:2b"`) |
385
+ | `--protocol` | `passive` | LLM output protocol. `passive` = single-pass; `json` = iterative refinement |
386
+ | `--max-calls` | `1` | Max loop iterations per turn |
387
+ | `--session` | off | Enable in-memory session context (sliding window of recent Q&A) |
388
+ | `--history-turns` | `5` | Session window size (turns) |
389
+ | `--session-budget` | `4000` | Session block character limit |
390
+ | `--store` | off | Persist each answer as STM item |
391
+ | `--source FILE...` | *(none)* | Pre-ingest files before starting |
392
+ | `--tags` | `chat` | Tags for stored items (comma-separated) |
393
+
394
+ **stdout purity:** answers go to stdout only. Prompt, banner, and hints go to stderr.
395
+
294
396
  ---
295
397
 
296
398
  ## Environment Variables
@@ -348,6 +450,18 @@ memctl search "" --json | jq -c '.[]'
348
450
 
349
451
  # Iterative recall-answer loop with trace
350
452
  memctl push "auth flow" --source docs/ | memctl loop "auth flow" --llm "claude -p" --trace
453
+
454
+ # One-liner: inspect a folder (auto-mount + auto-sync)
455
+ memctl inspect docs/
456
+
457
+ # Inspect in JSON, pipe to jq for extension breakdown
458
+ memctl inspect src/ --json | jq '.extensions'
459
+
460
+ # Inspect without syncing (use cached state)
461
+ memctl inspect docs/ --no-sync --json
462
+
463
+ # Interactive chat with pre-ingested docs
464
+ memctl chat --llm "claude -p" --source docs/ --session --store
351
465
  ```
352
466
 
353
467
  ---
@@ -402,14 +516,18 @@ Tool names use the `memory_*` prefix for drop-in compatibility with RAGIX.
402
516
  ```
403
517
  memctl/
404
518
  ├── types.py Data model (MemoryItem, MemoryProposal, MemoryEvent, MemoryLink)
405
- ├── store.py SQLite + FTS5 + WAL backend (9 tables + schema_meta)
519
+ ├── store.py SQLite + FTS5 + WAL backend (10 tables + schema_meta)
406
520
  ├── extract.py Text extraction (text files + binary format dispatch)
407
521
  ├── ingest.py Paragraph chunking, SHA-256 dedup, source resolution
408
522
  ├── policy.py Write governance (30 patterns: secrets, injection, instructional)
409
523
  ├── config.py Dataclass configuration
410
524
  ├── similarity.py Stdlib text similarity (Jaccard + SequenceMatcher)
411
525
  ├── loop.py Bounded recall-answer loop controller
412
- ├── cli.py 9 CLI commands
526
+ ├── mount.py Folder mount registration and management
527
+ ├── sync.py Delta sync with 3-tier change detection
528
+ ├── inspect.py Structural inspection and orchestration
529
+ ├── chat.py Interactive memory-backed chat REPL
530
+ ├── cli.py 13 CLI commands
413
531
  ├── consolidate.py Deterministic merge (Jaccard clustering, no LLM)
414
532
  ├── proposer.py LLM output parsing (delimiter + regex)
415
533
  └── mcp/
@@ -418,7 +536,7 @@ memctl/
418
536
  └── server.py FastMCP server entry point
419
537
  ```
420
538
 
421
- 16 source files. ~5,300 lines. Zero compiled dependencies for core.
539
+ 20 source files. ~7,700 lines. Zero compiled dependencies for core.
422
540
 
423
541
  ### Memory Tiers
424
542
 
@@ -485,7 +603,7 @@ Deterministic, no-LLM merge pipeline:
485
603
 
486
604
  ## Database Schema
487
605
 
488
- Single SQLite file with WAL mode. 9 tables + 1 FTS5 virtual table:
606
+ Single SQLite file with WAL mode. 10 tables + 1 FTS5 virtual table:
489
607
 
490
608
  | Table | Purpose |
491
609
  |-------|---------|
@@ -494,13 +612,14 @@ Single SQLite file with WAL mode. 9 tables + 1 FTS5 virtual table:
494
612
  | `memory_events` | Audit log (every read/write/consolidate) |
495
613
  | `memory_links` | Directional relationships (supersedes, supports, etc.) |
496
614
  | `memory_embeddings` | Reserved for RAGIX (empty in memctl) |
497
- | `corpus_hashes` | SHA-256 file dedup registry |
615
+ | `corpus_hashes` | SHA-256 file dedup + mount metadata (mount_id, rel_path, ext, size_bytes, mtime_epoch, lang_hint) |
498
616
  | `corpus_metadata` | Corpus-level metadata |
499
617
  | `schema_meta` | Schema version, creation info |
500
618
  | `memory_palace_locations` | Reserved for RAGIX |
619
+ | `memory_mounts` | Registered folder mounts (path, name, ignore patterns, lang hint) |
501
620
  | `memory_items_fts` | FTS5 virtual table for full-text search |
502
621
 
503
- Schema version is tracked in `schema_meta`. Current: `SCHEMA_VERSION=1`.
622
+ Schema version is tracked in `schema_meta`. Current: `SCHEMA_VERSION=2`. Migration from v1 is additive (ALTER TABLE ADD COLUMN) and idempotent.
504
623
 
505
624
  ---
506
625
 
@@ -518,10 +637,11 @@ ragix memory stats --db /path/to/your/.memory/memory.db
518
637
 
519
638
  | Feature | memctl | RAGIX |
520
639
  |---------|--------|-------|
521
- | SQLite schema | Identical | Identical |
640
+ | SQLite schema | Forward-compatible (RAGIX can open memctl DBs) | Superset |
522
641
  | Injection format | `format_version=1` | `format_version=1` |
523
642
  | MCP tool names | `memory_*` | `memory_*` |
524
643
  | FTS5 recall | Yes | Yes (+ hybrid embeddings) |
644
+ | Folder mount + sync | Yes (v0.3+) | No |
525
645
  | Embeddings | No | Yes (FAISS + Ollama) |
526
646
  | LLM-assisted merge | No | Yes |
527
647
  | Graph-RAG | No | Yes |
@@ -575,7 +695,7 @@ pip install memctl[dev]
575
695
  pytest tests/ -v
576
696
  ```
577
697
 
578
- 332 tests covering types, store, policy, ingest, text extraction, similarity, loop controller, forward compatibility, contracts, CLI (subprocess), and pipe composition.
698
+ 492 tests across 15 test files covering types, store, policy, ingest, text extraction, similarity, loop controller, mount, sync, inspect, chat, forward compatibility, contracts, CLI (subprocess), and pipe composition.
579
699
 
580
700
  ---
581
701
 
@@ -107,7 +107,34 @@ memctl search "authentication"
107
107
  memctl search "database" --json -k 5
108
108
  ```
109
109
 
110
- ### 5. Inspect and manage
110
+ ### 5. Inspect a folder (one-liner)
111
+
112
+ ```bash
113
+ # Auto-mounts, auto-syncs, and inspects — all in one command
114
+ memctl inspect docs/
115
+
116
+ # Same in JSON (for scripts)
117
+ memctl inspect docs/ --json
118
+
119
+ # Skip sync (use cached state)
120
+ memctl inspect docs/ --no-sync
121
+ ```
122
+
123
+ `inspect` auto-mounts the folder if needed, checks staleness, syncs only if stale, and produces a structural summary. All implicit actions are announced on stderr.
124
+
125
+ ### 6. Chat with memory-backed context
126
+
127
+ ```bash
128
+ # Interactive chat with any LLM
129
+ memctl chat --llm "claude -p" --session
130
+
131
+ # With pre-ingested files and answer storage
132
+ memctl chat --llm "ollama run granite3.1:2b" --source docs/ --store --session
133
+ ```
134
+
135
+ Each question recalls from the memory store, sends context + question to the LLM, and displays the answer. `--session` keeps a sliding window of recent Q&A pairs. `--store` persists answers as STM items.
136
+
137
+ ### 7. Manage
111
138
 
112
139
  ```bash
113
140
  memctl show MEM-abc123def456 # Show item details
@@ -137,6 +164,10 @@ memctl <command> [options]
137
164
  | `stats` | Store statistics |
138
165
  | `consolidate [--dry-run]` | Deterministic merge of similar STM items |
139
166
  | `loop QUERY --llm CMD` | Bounded recall-answer loop with LLM |
167
+ | `mount PATH` | Register a folder as a structured source |
168
+ | `sync [PATH]` | Delta-sync mounted folders into the store |
169
+ | `inspect [PATH]` | Structural inspection with auto-mount and auto-sync |
170
+ | `chat --llm CMD` | Interactive memory-backed chat REPL |
140
171
  | `serve` | Start MCP server (requires `memctl[mcp]`) |
141
172
 
142
173
  ### Global Flags
@@ -248,6 +279,77 @@ memctl push "database schema" --source src/ \
248
279
  memctl loop --replay trace.jsonl "original question"
249
280
  ```
250
281
 
282
+ #### `memctl mount`
283
+
284
+ ```bash
285
+ memctl mount PATH [--name NAME] [--ignore PATTERN ...] [--lang HINT]
286
+ memctl mount --list
287
+ memctl mount --remove ID_OR_NAME
288
+ ```
289
+
290
+ Registers a folder as a structured source. Stores metadata only — no scanning, no ingestion. The folder contents are synced separately via `sync` or automatically via `inspect`.
291
+
292
+ #### `memctl sync`
293
+
294
+ ```bash
295
+ memctl sync [PATH] [--full] [--json] [--quiet]
296
+ ```
297
+
298
+ Delta-syncs mounted folders into the memory store. Uses a 3-tier delta rule:
299
+ 1. **New file** (not in DB) → ingest
300
+ 2. **Size + mtime match** → fast skip (no hashing)
301
+ 3. **Hash compare** → ingest only if content changed
302
+
303
+ If `PATH` is given but not yet mounted, it is auto-registered first. `--full` forces re-processing of all files.
304
+
305
+ #### `memctl inspect`
306
+
307
+ ```bash
308
+ # Orchestration mode — auto-mounts, auto-syncs, and inspects
309
+ memctl inspect PATH [--sync auto|always|never] [--no-sync] [--mount-mode persist|ephemeral]
310
+ [--budget N] [--ignore PATTERN ...] [--json] [--quiet]
311
+
312
+ # Classic mode — inspect an existing mount by ID/name
313
+ memctl inspect --mount ID_OR_NAME [--budget N] [--json] [--quiet]
314
+ ```
315
+
316
+ When given a positional `PATH`, inspect operates in **orchestration mode**:
317
+ 1. **Auto-mount** — registers the folder if not already mounted
318
+ 2. **Staleness check** — compares disk inventory (path/size/mtime triples) against the store
319
+ 3. **Auto-sync** — runs delta sync only if stale (or always/never per `--sync`)
320
+ 4. **Inspect** — generates a deterministic structural summary
321
+
322
+ Output includes file/chunk/size totals, per-folder breakdown, per-extension distribution, top-5 largest files, and rule-based observations. All paths in output are mount-relative (never absolute).
323
+
324
+ `--mount-mode ephemeral` removes the mount record after inspection (corpus data is preserved). `--no-sync` is shorthand for `--sync never`.
325
+
326
+ All implicit actions (mount, sync) are announced on stderr. `--quiet` suppresses them.
327
+
328
+ #### `memctl chat`
329
+
330
+ ```bash
331
+ memctl chat --llm CMD [--session] [--store] [--protocol passive|json|regex]
332
+ [--max-calls N] [--budget N] [--source FILE ...] [--quiet]
333
+ ```
334
+
335
+ Interactive memory-backed chat REPL. Each turn: FTS5 recall from the memory store, send context + question to the LLM, display the answer.
336
+
337
+ **Stateless by default.** Each question sees only the memory store — no hidden conversation state.
338
+
339
+ | Flag | Default | Description |
340
+ |------|---------|-------------|
341
+ | `--llm CMD` | *(required)* | LLM command (e.g. `"claude -p"`, `"ollama run granite3.1:2b"`) |
342
+ | `--protocol` | `passive` | LLM output protocol. `passive` = single-pass; `json` = iterative refinement |
343
+ | `--max-calls` | `1` | Max loop iterations per turn |
344
+ | `--session` | off | Enable in-memory session context (sliding window of recent Q&A) |
345
+ | `--history-turns` | `5` | Session window size (turns) |
346
+ | `--session-budget` | `4000` | Session block character limit |
347
+ | `--store` | off | Persist each answer as STM item |
348
+ | `--source FILE...` | *(none)* | Pre-ingest files before starting |
349
+ | `--tags` | `chat` | Tags for stored items (comma-separated) |
350
+
351
+ **stdout purity:** answers go to stdout only. Prompt, banner, and hints go to stderr.
352
+
251
353
  ---
252
354
 
253
355
  ## Environment Variables
@@ -305,6 +407,18 @@ memctl search "" --json | jq -c '.[]'
305
407
 
306
408
  # Iterative recall-answer loop with trace
307
409
  memctl push "auth flow" --source docs/ | memctl loop "auth flow" --llm "claude -p" --trace
410
+
411
+ # One-liner: inspect a folder (auto-mount + auto-sync)
412
+ memctl inspect docs/
413
+
414
+ # Inspect in JSON, pipe to jq for extension breakdown
415
+ memctl inspect src/ --json | jq '.extensions'
416
+
417
+ # Inspect without syncing (use cached state)
418
+ memctl inspect docs/ --no-sync --json
419
+
420
+ # Interactive chat with pre-ingested docs
421
+ memctl chat --llm "claude -p" --source docs/ --session --store
308
422
  ```
309
423
 
310
424
  ---
@@ -359,14 +473,18 @@ Tool names use the `memory_*` prefix for drop-in compatibility with RAGIX.
359
473
  ```
360
474
  memctl/
361
475
  ├── types.py Data model (MemoryItem, MemoryProposal, MemoryEvent, MemoryLink)
362
- ├── store.py SQLite + FTS5 + WAL backend (9 tables + schema_meta)
476
+ ├── store.py SQLite + FTS5 + WAL backend (10 tables + schema_meta)
363
477
  ├── extract.py Text extraction (text files + binary format dispatch)
364
478
  ├── ingest.py Paragraph chunking, SHA-256 dedup, source resolution
365
479
  ├── policy.py Write governance (30 patterns: secrets, injection, instructional)
366
480
  ├── config.py Dataclass configuration
367
481
  ├── similarity.py Stdlib text similarity (Jaccard + SequenceMatcher)
368
482
  ├── loop.py Bounded recall-answer loop controller
369
- ├── cli.py 9 CLI commands
483
+ ├── mount.py Folder mount registration and management
484
+ ├── sync.py Delta sync with 3-tier change detection
485
+ ├── inspect.py Structural inspection and orchestration
486
+ ├── chat.py Interactive memory-backed chat REPL
487
+ ├── cli.py 13 CLI commands
370
488
  ├── consolidate.py Deterministic merge (Jaccard clustering, no LLM)
371
489
  ├── proposer.py LLM output parsing (delimiter + regex)
372
490
  └── mcp/
@@ -375,7 +493,7 @@ memctl/
375
493
  └── server.py FastMCP server entry point
376
494
  ```
377
495
 
378
- 16 source files. ~5,300 lines. Zero compiled dependencies for core.
496
+ 20 source files. ~7,700 lines. Zero compiled dependencies for core.
379
497
 
380
498
  ### Memory Tiers
381
499
 
@@ -442,7 +560,7 @@ Deterministic, no-LLM merge pipeline:
442
560
 
443
561
  ## Database Schema
444
562
 
445
- Single SQLite file with WAL mode. 9 tables + 1 FTS5 virtual table:
563
+ Single SQLite file with WAL mode. 10 tables + 1 FTS5 virtual table:
446
564
 
447
565
  | Table | Purpose |
448
566
  |-------|---------|
@@ -451,13 +569,14 @@ Single SQLite file with WAL mode. 9 tables + 1 FTS5 virtual table:
451
569
  | `memory_events` | Audit log (every read/write/consolidate) |
452
570
  | `memory_links` | Directional relationships (supersedes, supports, etc.) |
453
571
  | `memory_embeddings` | Reserved for RAGIX (empty in memctl) |
454
- | `corpus_hashes` | SHA-256 file dedup registry |
572
+ | `corpus_hashes` | SHA-256 file dedup + mount metadata (mount_id, rel_path, ext, size_bytes, mtime_epoch, lang_hint) |
455
573
  | `corpus_metadata` | Corpus-level metadata |
456
574
  | `schema_meta` | Schema version, creation info |
457
575
  | `memory_palace_locations` | Reserved for RAGIX |
576
+ | `memory_mounts` | Registered folder mounts (path, name, ignore patterns, lang hint) |
458
577
  | `memory_items_fts` | FTS5 virtual table for full-text search |
459
578
 
460
- Schema version is tracked in `schema_meta`. Current: `SCHEMA_VERSION=1`.
579
+ Schema version is tracked in `schema_meta`. Current: `SCHEMA_VERSION=2`. Migration from v1 is additive (ALTER TABLE ADD COLUMN) and idempotent.
461
580
 
462
581
  ---
463
582
 
@@ -475,10 +594,11 @@ ragix memory stats --db /path/to/your/.memory/memory.db
475
594
 
476
595
  | Feature | memctl | RAGIX |
477
596
  |---------|--------|-------|
478
- | SQLite schema | Identical | Identical |
597
+ | SQLite schema | Forward-compatible (RAGIX can open memctl DBs) | Superset |
479
598
  | Injection format | `format_version=1` | `format_version=1` |
480
599
  | MCP tool names | `memory_*` | `memory_*` |
481
600
  | FTS5 recall | Yes | Yes (+ hybrid embeddings) |
601
+ | Folder mount + sync | Yes (v0.3+) | No |
482
602
  | Embeddings | No | Yes (FAISS + Ollama) |
483
603
  | LLM-assisted merge | No | Yes |
484
604
  | Graph-RAG | No | Yes |
@@ -532,7 +652,7 @@ pip install memctl[dev]
532
652
  pytest tests/ -v
533
653
  ```
534
654
 
535
- 332 tests covering types, store, policy, ingest, text extraction, similarity, loop controller, forward compatibility, contracts, CLI (subprocess), and pipe composition.
655
+ 492 tests across 15 test files covering types, store, policy, ingest, text extraction, similarity, loop controller, mount, sync, inspect, chat, forward compatibility, contracts, CLI (subprocess), and pipe composition.
536
656
 
537
657
  ---
538
658
 
@@ -7,7 +7,7 @@ Policy-governed, content-addressed, and forward-compatible with RAGIX.
7
7
  Author: Olivier Vitrac, PhD, HDR | olivier.vitrac@adservio.fr | Adservio
8
8
  """
9
9
 
10
- __version__ = "0.2.1"
10
+ __version__ = "0.4.0"
11
11
 
12
12
  from memctl.types import (
13
13
  MemoryItem,