superlocalmemory 3.2.3 → 3.3.1

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 (51) hide show
  1. package/CHANGELOG.md +43 -1
  2. package/README.md +106 -71
  3. package/package.json +1 -2
  4. package/pyproject.toml +16 -1
  5. package/src/superlocalmemory/cli/commands.py +419 -15
  6. package/src/superlocalmemory/cli/main.py +44 -0
  7. package/src/superlocalmemory/core/config.py +276 -4
  8. package/src/superlocalmemory/core/consolidation_engine.py +37 -0
  9. package/src/superlocalmemory/core/engine.py +21 -0
  10. package/src/superlocalmemory/core/engine_wiring.py +58 -8
  11. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +374 -0
  12. package/src/superlocalmemory/dynamics/eap_scheduler.py +276 -0
  13. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +171 -0
  14. package/src/superlocalmemory/encoding/cognitive_consolidator.py +804 -0
  15. package/src/superlocalmemory/hooks/auto_invoker.py +46 -8
  16. package/src/superlocalmemory/hooks/auto_parameterize.py +147 -0
  17. package/src/superlocalmemory/infra/heartbeat_monitor.py +140 -0
  18. package/src/superlocalmemory/infra/pid_manager.py +193 -0
  19. package/src/superlocalmemory/infra/process_reaper.py +572 -0
  20. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +115 -0
  21. package/src/superlocalmemory/learning/forgetting_scheduler.py +263 -0
  22. package/src/superlocalmemory/learning/quantization_scheduler.py +320 -0
  23. package/src/superlocalmemory/math/ebbinghaus.py +309 -0
  24. package/src/superlocalmemory/math/fisher_quantized.py +251 -0
  25. package/src/superlocalmemory/math/hopfield.py +279 -0
  26. package/src/superlocalmemory/math/polar_quant.py +379 -0
  27. package/src/superlocalmemory/math/qjl.py +115 -0
  28. package/src/superlocalmemory/mcp/server.py +2 -0
  29. package/src/superlocalmemory/mcp/tools_v3.py +10 -0
  30. package/src/superlocalmemory/mcp/tools_v33.py +351 -0
  31. package/src/superlocalmemory/parameterization/__init__.py +47 -0
  32. package/src/superlocalmemory/parameterization/pattern_extractor.py +534 -0
  33. package/src/superlocalmemory/parameterization/pii_filter.py +106 -0
  34. package/src/superlocalmemory/parameterization/prompt_injector.py +216 -0
  35. package/src/superlocalmemory/parameterization/prompt_lifecycle.py +275 -0
  36. package/src/superlocalmemory/parameterization/soft_prompt_generator.py +425 -0
  37. package/src/superlocalmemory/retrieval/engine.py +21 -3
  38. package/src/superlocalmemory/retrieval/forgetting_filter.py +145 -0
  39. package/src/superlocalmemory/retrieval/hopfield_channel.py +335 -0
  40. package/src/superlocalmemory/retrieval/quantization_aware_search.py +133 -0
  41. package/src/superlocalmemory/retrieval/strategy.py +16 -6
  42. package/src/superlocalmemory/server/routes/agents.py +68 -8
  43. package/src/superlocalmemory/server/routes/learning.py +18 -1
  44. package/src/superlocalmemory/server/routes/lifecycle.py +36 -17
  45. package/src/superlocalmemory/server/routes/v3_api.py +503 -1
  46. package/src/superlocalmemory/storage/database.py +206 -0
  47. package/src/superlocalmemory/storage/embedding_migrator.py +178 -0
  48. package/src/superlocalmemory/storage/migration_v33.py +140 -0
  49. package/src/superlocalmemory/storage/quantized_store.py +261 -0
  50. package/src/superlocalmemory/storage/schema_v32.py +137 -0
  51. package/conftest.py +0 -5
@@ -41,6 +41,12 @@ def dispatch(args: Namespace) -> None:
41
41
  "hooks": cmd_hooks,
42
42
  "session-context": cmd_session_context,
43
43
  "observe": cmd_observe,
44
+ # V3.3 commands
45
+ "decay": cmd_decay,
46
+ "quantize": cmd_quantize,
47
+ "consolidate": cmd_consolidate,
48
+ "soft-prompts": cmd_soft_prompts,
49
+ "reap": cmd_reap,
44
50
  }
45
51
  handler = handlers.get(args.command)
46
52
  if handler:
@@ -102,6 +108,11 @@ def cmd_mode(args: Namespace) -> None:
102
108
  )
103
109
  updated.save()
104
110
  print(f"Mode set to: {args.value.upper()}")
111
+
112
+ # V3.3: Check if embedding model changed — inform about re-indexing
113
+ if (config.embedding.provider != updated.embedding.provider
114
+ or config.embedding.model_name != updated.embedding.model_name):
115
+ print(" ⚠ Embedding model changed. Re-indexing will run on next recall.")
105
116
  else:
106
117
  print(f"Current mode: {config.mode.value.upper()}")
107
118
 
@@ -1118,27 +1129,122 @@ def cmd_hooks(args: Namespace) -> None:
1118
1129
 
1119
1130
 
1120
1131
  def cmd_session_context(args: Namespace) -> None:
1121
- """Print session context (for hook scripts and piping)."""
1122
- from superlocalmemory.hooks.auto_recall import AutoRecall
1132
+ """Print session context (for hook scripts and piping).
1133
+
1134
+ Uses a FAST PATH that queries SQLite directly (no engine/Ollama needed).
1135
+ This ensures the SessionStart hook completes within its 15s timeout even
1136
+ when Ollama requires a 60s+ cold start. The fast path returns:
1137
+ - Core Memory blocks (always-on context)
1138
+ - Recent high-importance memories (last 7 days)
1139
+ - Session summary from last session
1140
+ Falls back to the full engine path only if --full is passed explicitly.
1141
+ """
1142
+ import sqlite3
1143
+ from pathlib import Path
1123
1144
  from superlocalmemory.core.config import SLMConfig
1124
- from superlocalmemory.core.engine import MemoryEngine
1125
1145
 
1146
+ use_full = getattr(args, "full", False)
1147
+
1148
+ if use_full:
1149
+ # Full engine path (slow, requires Ollama) — for explicit CLI use
1150
+ try:
1151
+ from superlocalmemory.hooks.auto_recall import AutoRecall
1152
+ from superlocalmemory.core.engine import MemoryEngine
1153
+ config = SLMConfig.load()
1154
+ engine = MemoryEngine(config)
1155
+ engine.initialize()
1156
+ auto = AutoRecall(
1157
+ engine=engine,
1158
+ config={"enabled": True, "max_memories_injected": 10, "relevance_threshold": 0.3},
1159
+ )
1160
+ context = auto.get_session_context(
1161
+ query=getattr(args, "query", "") or "recent decisions and important context",
1162
+ )
1163
+ if context:
1164
+ print(context)
1165
+ except Exception as exc:
1166
+ logger.debug("session-context (full) failed: %s", exc)
1167
+ return
1168
+
1169
+ # ── FAST PATH: direct SQLite, no engine, <500ms ──────────────
1126
1170
  try:
1127
1171
  config = SLMConfig.load()
1128
- engine = MemoryEngine(config)
1129
- engine.initialize()
1172
+ db_path = config.base_dir / "memory.db"
1173
+ if not db_path.exists():
1174
+ return
1130
1175
 
1131
- auto = AutoRecall(
1132
- engine=engine,
1133
- config={"enabled": True, "max_memories_injected": 10, "relevance_threshold": 0.3},
1134
- )
1135
- context = auto.get_session_context(
1136
- query=getattr(args, "query", "") or "recent decisions and important context",
1137
- )
1138
- if context:
1139
- print(context)
1176
+ pid = config.active_profile
1177
+ conn = sqlite3.connect(str(db_path))
1178
+ conn.row_factory = sqlite3.Row
1179
+ sections = []
1180
+
1181
+ # 1. Core Memory blocks (compiled high-value context)
1182
+ try:
1183
+ rows = conn.execute(
1184
+ "SELECT block_type, content FROM core_memory_blocks "
1185
+ "WHERE profile_id = ? ORDER BY block_type",
1186
+ (pid,),
1187
+ ).fetchall()
1188
+ if rows:
1189
+ blocks = [f"[{r['block_type']}] {r['content']}" for r in rows]
1190
+ sections.append("## Core Memory\n" + "\n".join(blocks))
1191
+ except sqlite3.OperationalError:
1192
+ pass
1193
+
1194
+ # 2. Recent important memories (last 7 days, top 10 by importance)
1195
+ try:
1196
+ rows = conn.execute(
1197
+ "SELECT content, fact_type, created_at FROM atomic_facts "
1198
+ "WHERE profile_id = ? "
1199
+ "AND created_at >= datetime('now', '-7 days') "
1200
+ "AND lifecycle = 'active' "
1201
+ "ORDER BY importance DESC, created_at DESC LIMIT 10",
1202
+ (pid,),
1203
+ ).fetchall()
1204
+ if rows:
1205
+ items = []
1206
+ for r in rows:
1207
+ content = r["content"][:200]
1208
+ items.append(f"- [{r['fact_type'] or 'fact'}] {content}")
1209
+ sections.append("## Recent Context (7 days)\n" + "\n".join(items))
1210
+ except sqlite3.OperationalError:
1211
+ pass
1212
+
1213
+ # 3. Session markers (last session summary)
1214
+ try:
1215
+ rows = conn.execute(
1216
+ "SELECT content, created_at FROM atomic_facts "
1217
+ "WHERE profile_id = ? AND content LIKE 'Session%' "
1218
+ "ORDER BY created_at DESC LIMIT 3",
1219
+ (pid,),
1220
+ ).fetchall()
1221
+ if rows:
1222
+ items = [f"- {r['content'][:150]}" for r in rows]
1223
+ sections.append("## Recent Sessions\n" + "\n".join(items))
1224
+ except sqlite3.OperationalError:
1225
+ pass
1226
+
1227
+ # 4. V3.3 Soft prompts (auto-learned patterns)
1228
+ try:
1229
+ rows = conn.execute(
1230
+ "SELECT category, content FROM soft_prompt_templates "
1231
+ "WHERE profile_id = ? AND active = 1 "
1232
+ "ORDER BY confidence DESC LIMIT 5",
1233
+ (pid,),
1234
+ ).fetchall()
1235
+ if rows:
1236
+ items = [f"- [{r['category']}] {r['content'][:150]}" for r in rows]
1237
+ sections.append("## Learned Patterns\n" + "\n".join(items))
1238
+ except sqlite3.OperationalError:
1239
+ pass
1240
+
1241
+ conn.close()
1242
+
1243
+ if sections:
1244
+ header = f"# SLM Session Context — {config.active_profile}"
1245
+ print(header + "\n\n" + "\n\n".join(sections))
1140
1246
  except Exception as exc:
1141
- logger.debug("session-context failed: %s", exc)
1247
+ logger.debug("session-context (fast) failed: %s", exc)
1142
1248
 
1143
1249
 
1144
1250
  def cmd_observe(args: Namespace) -> None:
@@ -1174,3 +1280,301 @@ def cmd_observe(args: Namespace) -> None:
1174
1280
  print(f"Not captured: {decision.reason}")
1175
1281
  except Exception as exc:
1176
1282
  logger.debug("observe failed: %s", exc)
1283
+
1284
+
1285
+ # -- V3.3 Commands -----------------------------------------------------------
1286
+
1287
+
1288
+ def cmd_decay(args: Namespace) -> None:
1289
+ """Run Ebbinghaus forgetting decay cycle."""
1290
+ from superlocalmemory.core.config import SLMConfig
1291
+ from superlocalmemory.core.engine import MemoryEngine
1292
+
1293
+ use_json = getattr(args, "json", False)
1294
+ dry_run = getattr(args, "dry_run", True)
1295
+ profile = getattr(args, "profile", "")
1296
+
1297
+ try:
1298
+ config = SLMConfig.load()
1299
+ engine = MemoryEngine(config)
1300
+ engine.initialize()
1301
+ pid = profile or engine.profile_id
1302
+
1303
+ from superlocalmemory.math.ebbinghaus import EbbinghausCurve
1304
+ from superlocalmemory.learning.forgetting_scheduler import (
1305
+ ForgettingScheduler,
1306
+ )
1307
+
1308
+ ebbinghaus = EbbinghausCurve(config.forgetting)
1309
+ scheduler = ForgettingScheduler(
1310
+ engine._db, ebbinghaus, config.forgetting,
1311
+ )
1312
+ result = scheduler.run_decay_cycle(pid, force=True)
1313
+ except Exception as exc:
1314
+ if use_json:
1315
+ from superlocalmemory.cli.json_output import json_print
1316
+ json_print("decay", error={"code": "DECAY_ERROR", "message": str(exc)})
1317
+ sys.exit(1)
1318
+ raise
1319
+
1320
+ if use_json:
1321
+ from superlocalmemory.cli.json_output import json_print
1322
+ json_print("decay", data={"dry_run": dry_run, **result},
1323
+ next_actions=[
1324
+ {"command": "slm decay --execute --json", "description": "Apply transitions"},
1325
+ {"command": "slm status --json", "description": "Check system status"},
1326
+ ])
1327
+ return
1328
+
1329
+ if result.get("skipped"):
1330
+ print(f"Skipped: {result.get('reason', 'unknown')}")
1331
+ return
1332
+
1333
+ total = result.get("total", 0)
1334
+ print(f"Decay cycle complete (dry_run={dry_run})")
1335
+ print(f" Total facts: {total}")
1336
+ print(f" Active: {result.get('active', 0)}")
1337
+ print(f" Warm: {result.get('warm', 0)}")
1338
+ print(f" Cold: {result.get('cold', 0)}")
1339
+ print(f" Archive: {result.get('archive', 0)}")
1340
+ print(f" Forgotten: {result.get('forgotten', 0)}")
1341
+ print(f" Transitions: {result.get('transitions', 0)}")
1342
+
1343
+
1344
+ def cmd_quantize(args: Namespace) -> None:
1345
+ """Run EAP embedding quantization cycle."""
1346
+ from superlocalmemory.core.config import SLMConfig
1347
+ from superlocalmemory.core.engine import MemoryEngine
1348
+
1349
+ use_json = getattr(args, "json", False)
1350
+ dry_run = getattr(args, "dry_run", True)
1351
+ profile = getattr(args, "profile", "")
1352
+
1353
+ try:
1354
+ config = SLMConfig.load()
1355
+ engine = MemoryEngine(config)
1356
+ engine.initialize()
1357
+ pid = profile or engine.profile_id
1358
+
1359
+ from superlocalmemory.math.ebbinghaus import EbbinghausCurve
1360
+ from superlocalmemory.dynamics.eap_scheduler import EAPScheduler
1361
+ from superlocalmemory.storage.quantized_store import (
1362
+ QuantizedEmbeddingStore,
1363
+ )
1364
+
1365
+ from superlocalmemory.math.polar_quant import PolarQuantEncoder
1366
+ from superlocalmemory.math.qjl import QJLEncoder
1367
+
1368
+ ebbinghaus = EbbinghausCurve(config.forgetting)
1369
+ polar = PolarQuantEncoder(config.quantization.polar)
1370
+ qjl = QJLEncoder(config.quantization.qjl)
1371
+ qstore = QuantizedEmbeddingStore(
1372
+ engine._db, polar, qjl, config.quantization,
1373
+ )
1374
+ scheduler = EAPScheduler(
1375
+ engine._db, ebbinghaus, qstore, config.quantization,
1376
+ )
1377
+ result = scheduler.run_eap_cycle(pid)
1378
+ except Exception as exc:
1379
+ if use_json:
1380
+ from superlocalmemory.cli.json_output import json_print
1381
+ json_print("quantize", error={"code": "EAP_ERROR", "message": str(exc)})
1382
+ sys.exit(1)
1383
+ raise
1384
+
1385
+ if use_json:
1386
+ from superlocalmemory.cli.json_output import json_print
1387
+ json_print("quantize", data={"dry_run": dry_run, **result},
1388
+ next_actions=[
1389
+ {"command": "slm quantize --execute --json", "description": "Apply changes"},
1390
+ {"command": "slm status --json", "description": "Check status"},
1391
+ ])
1392
+ return
1393
+
1394
+ print(f"EAP quantization cycle (dry_run={dry_run})")
1395
+ print(f" Total: {result.get('total', 0)}")
1396
+ print(f" Downgrades: {result.get('downgrades', 0)}")
1397
+ print(f" Upgrades: {result.get('upgrades', 0)}")
1398
+ print(f" Skipped: {result.get('skipped', 0)}")
1399
+ print(f" Errors: {result.get('errors', 0)}")
1400
+
1401
+
1402
+ def cmd_consolidate(args: Namespace) -> None:
1403
+ """Run cognitive consolidation pipeline."""
1404
+ from superlocalmemory.core.config import SLMConfig
1405
+ from superlocalmemory.core.engine import MemoryEngine
1406
+
1407
+ use_json = getattr(args, "json", False)
1408
+ cognitive = getattr(args, "cognitive", False)
1409
+ profile = getattr(args, "profile", "")
1410
+
1411
+ if not cognitive:
1412
+ if use_json:
1413
+ from superlocalmemory.cli.json_output import json_print
1414
+ json_print("consolidate", error={
1415
+ "code": "MISSING_FLAG",
1416
+ "message": "Use --cognitive to run CCQ pipeline",
1417
+ })
1418
+ sys.exit(1)
1419
+ print("Use --cognitive to run CCQ consolidation pipeline.")
1420
+ print(" slm consolidate --cognitive")
1421
+ return
1422
+
1423
+ try:
1424
+ config = SLMConfig.load()
1425
+ engine = MemoryEngine(config)
1426
+ engine.initialize()
1427
+ pid = profile or engine.profile_id
1428
+
1429
+ from superlocalmemory.encoding.cognitive_consolidator import (
1430
+ CognitiveConsolidator,
1431
+ )
1432
+
1433
+ consolidator = CognitiveConsolidator(db=engine._db)
1434
+ result = consolidator.run_pipeline(pid)
1435
+ except Exception as exc:
1436
+ if use_json:
1437
+ from superlocalmemory.cli.json_output import json_print
1438
+ json_print("consolidate", error={
1439
+ "code": "CCQ_ERROR", "message": str(exc),
1440
+ })
1441
+ sys.exit(1)
1442
+ raise
1443
+
1444
+ if use_json:
1445
+ from superlocalmemory.cli.json_output import json_print
1446
+ json_print("consolidate", data={
1447
+ "clusters_found": result.clusters_found,
1448
+ "blocks_created": result.blocks_created,
1449
+ "facts_archived": result.facts_archived,
1450
+ "compression_ratio": round(result.compression_ratio, 3),
1451
+ }, next_actions=[
1452
+ {"command": "slm list --json", "description": "List recent memories"},
1453
+ {"command": "slm status --json", "description": "Check status"},
1454
+ ])
1455
+ return
1456
+
1457
+ print("CCQ Cognitive Consolidation")
1458
+ print(f" Clusters found: {result.clusters_found}")
1459
+ print(f" Blocks created: {result.blocks_created}")
1460
+ print(f" Facts archived: {result.facts_archived}")
1461
+ print(f" Compression ratio: {result.compression_ratio:.3f}")
1462
+
1463
+
1464
+ def cmd_soft_prompts(args: Namespace) -> None:
1465
+ """List active soft prompts (auto-learned user patterns)."""
1466
+ from superlocalmemory.core.config import SLMConfig
1467
+ from superlocalmemory.core.engine import MemoryEngine
1468
+
1469
+ use_json = getattr(args, "json", False)
1470
+ profile = getattr(args, "profile", "")
1471
+
1472
+ try:
1473
+ config = SLMConfig.load()
1474
+ engine = MemoryEngine(config)
1475
+ engine.initialize()
1476
+ pid = profile or engine.profile_id
1477
+
1478
+ rows = engine._db.execute(
1479
+ "SELECT prompt_id, category, content, confidence, "
1480
+ " effectiveness, token_count, version, created_at "
1481
+ "FROM soft_prompt_templates "
1482
+ "WHERE profile_id = ? AND active = 1 "
1483
+ "ORDER BY confidence DESC",
1484
+ (pid,),
1485
+ )
1486
+ prompts = []
1487
+ for row in rows:
1488
+ r = dict(row)
1489
+ prompts.append({
1490
+ "prompt_id": r["prompt_id"],
1491
+ "category": r["category"],
1492
+ "content": r["content"],
1493
+ "confidence": round(float(r["confidence"]), 3),
1494
+ "effectiveness": round(float(r["effectiveness"]), 3),
1495
+ "token_count": int(r["token_count"]),
1496
+ "version": int(r["version"]),
1497
+ "created_at": r["created_at"],
1498
+ })
1499
+ except Exception as exc:
1500
+ if use_json:
1501
+ from superlocalmemory.cli.json_output import json_print
1502
+ json_print("soft-prompts", error={
1503
+ "code": "QUERY_ERROR", "message": str(exc),
1504
+ })
1505
+ sys.exit(1)
1506
+ raise
1507
+
1508
+ if use_json:
1509
+ from superlocalmemory.cli.json_output import json_print
1510
+ json_print("soft-prompts", data={
1511
+ "prompts": prompts, "count": len(prompts), "profile": pid,
1512
+ }, next_actions=[
1513
+ {"command": "slm status --json", "description": "Check status"},
1514
+ ])
1515
+ return
1516
+
1517
+ if not prompts:
1518
+ print("No active soft prompts.")
1519
+ return
1520
+
1521
+ print(f"Active soft prompts ({len(prompts)}):\n")
1522
+ for i, p in enumerate(prompts, 1):
1523
+ print(f" {i}. [{p['category']}] (conf={p['confidence']:.2f})")
1524
+ content_preview = p["content"][:100]
1525
+ if len(p["content"]) > 100:
1526
+ content_preview += "..."
1527
+ print(f" {content_preview}")
1528
+
1529
+
1530
+ def cmd_reap(args: Namespace) -> None:
1531
+ """Find and kill orphaned SLM processes."""
1532
+ use_json = getattr(args, "json", False)
1533
+ dry_run = not getattr(args, "force", False)
1534
+
1535
+ try:
1536
+ from superlocalmemory.infra.process_reaper import (
1537
+ cleanup_all_orphans,
1538
+ ReaperConfig,
1539
+ )
1540
+
1541
+ config = ReaperConfig()
1542
+ result = cleanup_all_orphans(config, dry_run=dry_run)
1543
+ except Exception as exc:
1544
+ if use_json:
1545
+ from superlocalmemory.cli.json_output import json_print
1546
+ json_print("reap", error={
1547
+ "code": "REAP_ERROR", "message": str(exc),
1548
+ })
1549
+ sys.exit(1)
1550
+ raise
1551
+
1552
+ if use_json:
1553
+ from superlocalmemory.cli.json_output import json_print
1554
+ json_print("reap", data={
1555
+ "dry_run": dry_run,
1556
+ "total_found": result.get("total_found", 0),
1557
+ "orphans_found": result.get("orphans_found", 0),
1558
+ "killed": result.get("killed", 0),
1559
+ "skipped": result.get("skipped", 0),
1560
+ }, next_actions=[
1561
+ {"command": "slm reap --force --json", "description": "Kill orphans"},
1562
+ {"command": "slm status --json", "description": "Check status"},
1563
+ ])
1564
+ return
1565
+
1566
+ total = result.get("total_found", 0)
1567
+ orphans = result.get("orphans_found", 0)
1568
+ killed = result.get("killed", 0)
1569
+ skipped = result.get("skipped", 0)
1570
+
1571
+ if dry_run:
1572
+ print(f"Process reaper (dry run)")
1573
+ else:
1574
+ print(f"Process reaper")
1575
+ print(f" Total SLM processes: {total}")
1576
+ print(f" Orphans found: {orphans}")
1577
+ print(f" Killed: {killed}")
1578
+ print(f" Skipped: {skipped}")
1579
+ if dry_run and orphans > 0:
1580
+ print("\n Use --force to kill orphaned processes.")
@@ -187,6 +187,50 @@ def main() -> None:
187
187
  obs_p = sub.add_parser("observe", help="Auto-capture content (pipe or argument)")
188
188
  obs_p.add_argument("content", nargs="?", default="", help="Content to evaluate")
189
189
 
190
+ # -- V3.3 Commands -------------------------------------------------
191
+ decay_p = sub.add_parser("decay", help="Run Ebbinghaus forgetting decay cycle")
192
+ decay_p.add_argument(
193
+ "--dry-run", action="store_true", default=True,
194
+ help="Preview without applying (default)",
195
+ )
196
+ decay_p.add_argument(
197
+ "--execute", dest="dry_run", action="store_false",
198
+ help="Apply zone transitions",
199
+ )
200
+ decay_p.add_argument("--profile", default="", help="Target profile")
201
+ decay_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
202
+
203
+ quantize_p = sub.add_parser("quantize", help="Run EAP embedding quantization cycle")
204
+ quantize_p.add_argument(
205
+ "--dry-run", action="store_true", default=True,
206
+ help="Preview without applying (default)",
207
+ )
208
+ quantize_p.add_argument(
209
+ "--execute", dest="dry_run", action="store_false",
210
+ help="Apply precision changes",
211
+ )
212
+ quantize_p.add_argument("--profile", default="", help="Target profile")
213
+ quantize_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
214
+
215
+ consolidate_p = sub.add_parser("consolidate", help="Run memory consolidation pipeline")
216
+ consolidate_p.add_argument(
217
+ "--cognitive", action="store_true",
218
+ help="Run CCQ cognitive consolidation",
219
+ )
220
+ consolidate_p.add_argument("--profile", default="", help="Target profile")
221
+ consolidate_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
222
+
223
+ sp_p = sub.add_parser("soft-prompts", help="List active soft prompts (auto-learned patterns)")
224
+ sp_p.add_argument("--profile", default="", help="Target profile")
225
+ sp_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
226
+
227
+ reap_p = sub.add_parser("reap", help="Find and kill orphaned SLM processes")
228
+ reap_p.add_argument(
229
+ "--force", action="store_true",
230
+ help="Kill orphans (default: dry run only)",
231
+ )
232
+ reap_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
233
+
190
234
  args = parser.parse_args()
191
235
 
192
236
  if not args.command: