superlocalmemory 3.6.17 → 3.6.18
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.
- package/README.md +2 -2
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/agents/slm-optimize-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-cache/SKILL.md +1 -1
- package/plugin/skills/slm-compress/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-recall/SKILL.md +1 -1
- package/plugin/skills/slm-remember/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/agents/slm-memory-advisor.md +1 -1
- package/plugin-src/agents/slm-optimize-advisor.md +1 -1
- package/plugin-src/manifest.json +1 -1
- package/plugin-src/requirements.txt +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/rules/CLAUDE.md.fragment +3 -3
- package/plugin-src/skills/slm-cache/SKILL.md +1 -1
- package/plugin-src/skills/slm-compress/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-recall/SKILL.md +1 -1
- package/plugin-src/skills/slm-remember/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/pyproject.toml +3 -2
- package/scripts/build-plugin.js +1 -1
- package/scripts/postinstall-interactive.js +94 -7
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/setup_wizard.py +34 -0
- package/src/superlocalmemory/hooks/claude_code_hooks.py +40 -4
- package/src/superlocalmemory/hooks/hook_handlers.py +33 -0
- package/src/superlocalmemory/storage/migrations/M017_ccq_scope_column.py +79 -0
- package/src/superlocalmemory.egg-info/PKG-INFO +3 -3
- package/src/superlocalmemory.egg-info/SOURCES.txt +1 -0
- package/plugin-src/commands/slm-optimize.md +0 -22
- package/plugin-src/commands/slm-recall.md +0 -16
- package/plugin-src/commands/slm-remember.md +0 -16
- package/plugin-src/commands/slm-status.md +0 -15
package/README.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
<img src="https://superlocalmemory.com/assets/logo-mark.png" alt="SuperLocalMemory" width="200"/>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">SuperLocalMemory V3.6.
|
|
5
|
+
<h1 align="center">SuperLocalMemory V3.6.18</h1>
|
|
6
6
|
<p align="center"><strong>Cache. Compress. Remember. Three surfaces — proxy, MCP tools, or skill. Every setup covered.</strong><br/>
|
|
7
7
|
<em>To the best of our knowledge, the only zero-cloud agent memory that beats Mem0's zero-LLM score on LoCoMo. Mode A: 74.8% vs Mem0 64.2% — no GPU, no API key, on CPU.</em></p>
|
|
8
|
-
<p align="center"><code>v3.6.
|
|
8
|
+
<p align="center"><code>v3.6.18</code> — <strong>Plugin-native. Profile-aware. Distributed-ready.</strong><br/>
|
|
9
9
|
Proxy: <code>slm wrap claude</code> · MCP: add <code>slm_compress</code> to your config · Skill: zero-config</p>
|
|
10
10
|
<p align="center"><strong>3 published research papers</strong> (arXiv preprints + Zenodo-archived) · <a href="https://arxiv.org/abs/2603.02240">arXiv:2603.02240</a> · <a href="https://arxiv.org/abs/2603.14588">arXiv:2603.14588</a> · <a href="https://arxiv.org/abs/2604.04514">arXiv:2604.04514</a></p>
|
|
11
11
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superlocalmemory",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.18",
|
|
4
4
|
"description": "Information-geometric agent memory with mathematical guarantees. 4-channel retrieval, Fisher-Rao similarity, zero-LLM mode, EU AI Act compliant. Works with Claude, Cursor, Windsurf, and 17+ AI tools.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-memory",
|
package/plugin/CLAUDE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- BEGIN SuperLocalMemory v3.6.
|
|
1
|
+
<!-- BEGIN SuperLocalMemory v3.6.18 -->
|
|
2
2
|
|
|
3
3
|
## SuperLocalMemory (SLM) — Agent Rules
|
|
4
4
|
|
|
@@ -39,6 +39,6 @@ slm-recall · slm-remember · slm-session · slm-status · slm-cache · slm-comp
|
|
|
39
39
|
### Subagents
|
|
40
40
|
slm-memory-advisor (memory decisions, session hygiene) · slm-optimize-advisor (context compression + KV cache)
|
|
41
41
|
|
|
42
|
-
<!-- END SuperLocalMemory v3.6.
|
|
42
|
+
<!-- END SuperLocalMemory v3.6.18 -->
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v3.6.
|
|
44
|
+
SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
|
|
@@ -41,4 +41,4 @@ recall→`slm recall "<q>" --limit N` (add `--include-global`/`--include-shared`
|
|
|
41
41
|
# What NOT to do
|
|
42
42
|
Never session_init twice; never forget dry_run=False without reporting preview; never dump a whole file into remember; never invent a memory; never claim "saved" without success:true / clean CLI exit.
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v3.6.
|
|
44
|
+
SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
|
|
@@ -35,4 +35,4 @@ stats→`slm optimize status`/`savings` · compress→`slm compress` · cache→
|
|
|
35
35
|
# What NOT to do
|
|
36
36
|
Never compress code-for-edit/JSON-to-parse/<500 chars; never store secrets/ccr_ids; never let optimize failure block/alter the task; never claim a specific savings %.
|
|
37
37
|
|
|
38
|
-
SuperLocalMemory v3.6.
|
|
38
|
+
SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
|
package/plugin/requirements.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
superlocalmemory==3.6.
|
|
1
|
+
superlocalmemory==3.6.18
|
|
@@ -41,4 +41,4 @@ recall→`slm recall "<q>" --limit N` (add `--include-global`/`--include-shared`
|
|
|
41
41
|
# What NOT to do
|
|
42
42
|
Never session_init twice; never forget dry_run=False without reporting preview; never dump a whole file into remember; never invent a memory; never claim "saved" without success:true / clean CLI exit.
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v3.6.
|
|
44
|
+
SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
|
|
@@ -35,4 +35,4 @@ stats→`slm optimize status`/`savings` · compress→`slm compress` · cache→
|
|
|
35
35
|
# What NOT to do
|
|
36
36
|
Never compress code-for-edit/JSON-to-parse/<500 chars; never store secrets/ccr_ids; never let optimize failure block/alter the task; never claim a specific savings %.
|
|
37
37
|
|
|
38
|
-
SuperLocalMemory v3.6.
|
|
38
|
+
SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
|
package/plugin-src/manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
superlocalmemory==3.6.
|
|
1
|
+
superlocalmemory==3.6.18
|
|
@@ -88,4 +88,4 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
|
|
|
88
88
|
| `slm_cache_get` | `key` | KV cache get; returns hit, value |
|
|
89
89
|
| `slm_optimize_stats` | `()` | Returns compress_runs, tokens_saved_compress, cache_kv_hits |
|
|
90
90
|
|
|
91
|
-
SuperLocalMemory v3.6.
|
|
91
|
+
SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- BEGIN SuperLocalMemory v3.6.
|
|
1
|
+
<!-- BEGIN SuperLocalMemory v3.6.18 -->
|
|
2
2
|
|
|
3
3
|
## SuperLocalMemory (SLM) — Agent Rules
|
|
4
4
|
|
|
@@ -39,6 +39,6 @@ slm-recall · slm-remember · slm-session · slm-status · slm-cache · slm-comp
|
|
|
39
39
|
### Subagents
|
|
40
40
|
slm-memory-advisor (memory decisions, session hygiene) · slm-optimize-advisor (context compression + KV cache)
|
|
41
41
|
|
|
42
|
-
<!-- END SuperLocalMemory v3.6.
|
|
42
|
+
<!-- END SuperLocalMemory v3.6.18 -->
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v3.6.
|
|
44
|
+
SuperLocalMemory v3.6.18 · Qualixar · AGPL-3.0-or-later
|
package/pyproject.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "superlocalmemory"
|
|
3
|
-
version = "3.6.
|
|
3
|
+
version = "3.6.18"
|
|
4
4
|
description = "Information-geometric agent memory with mathematical guarantees"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "AGPL-3.0-or-later"}
|
|
@@ -146,8 +146,9 @@ superlocalmemory = ["ui/**/*"]
|
|
|
146
146
|
[tool.pytest.ini_options]
|
|
147
147
|
testpaths = ["tests"]
|
|
148
148
|
pythonpath = ["src"]
|
|
149
|
-
addopts = "-m 'not slow and not ollama and not benchmark'"
|
|
149
|
+
addopts = "-p no:cacheprovider -p no:subtests -m 'not slow and not ollama and not benchmark'"
|
|
150
150
|
asyncio_mode = "auto"
|
|
151
|
+
faulthandler_timeout = 0
|
|
151
152
|
markers = [
|
|
152
153
|
"slow: marks tests as slow — real engine/model loading (run with: pytest -m slow)",
|
|
153
154
|
"ollama: marks tests that require a running Ollama instance",
|
package/scripts/build-plugin.js
CHANGED
|
@@ -30,7 +30,7 @@ import process from 'node:process';
|
|
|
30
30
|
// ---------------------------------------------------------------------------
|
|
31
31
|
// Constants
|
|
32
32
|
// ---------------------------------------------------------------------------
|
|
33
|
-
const VERSION = '3.6.
|
|
33
|
+
const VERSION = '3.6.18';
|
|
34
34
|
const MANIFEST_REL = 'plugin-src/manifest.json';
|
|
35
35
|
const GENERATED_BANNER = `# _GENERATED — DO NOT HAND-EDIT
|
|
36
36
|
|
|
@@ -489,19 +489,99 @@ async function runInteractiveFlow(rl, recommendedProfile) {
|
|
|
489
489
|
// under 60 LOC per Stage-8 G2 scope.
|
|
490
490
|
function printLivingBrainDelta() {
|
|
491
491
|
console.log('');
|
|
492
|
-
console.log('What\'s new in v3.
|
|
493
|
-
console.log(' +
|
|
494
|
-
console.log(' +
|
|
495
|
-
console.log(' +
|
|
496
|
-
console.log(' +
|
|
497
|
-
console.log(' + Opt-in skill evolution (Haiku 4.5 default)');
|
|
498
|
-
console.log(' + Evo-Memory public benchmark');
|
|
492
|
+
console.log('What\'s new in v3.6.18:');
|
|
493
|
+
console.log(' + session_init mandate hook — Claude calls ToolSearch→session_init first, every session');
|
|
494
|
+
console.log(' + Plugin auto-install on npm/pip install — skills, agents, hooks wired automatically');
|
|
495
|
+
console.log(' + M017 migration — ccq_consolidated_blocks gets scope column (no more silent CCQ scope drop)');
|
|
496
|
+
console.log(' + GC-safe test flags baked into pyproject.toml + Makefile (no more macOS ARM SIGSEGV)');
|
|
499
497
|
console.log('What\'s unchanged:');
|
|
500
498
|
console.log(' * Your memory.db — zero deletes, zero rewrites');
|
|
501
499
|
console.log(' * Your profile settings');
|
|
502
500
|
console.log(' * All CLI commands you already use');
|
|
503
501
|
}
|
|
504
502
|
|
|
503
|
+
// T1-B: Auto-install the Claude Code plugin after pip/npm install.
|
|
504
|
+
// Best-effort: never fails the installer, never blocks the main flow.
|
|
505
|
+
// Checks for `claude` CLI, then runs:
|
|
506
|
+
// 1. claude plugin marketplace add qualixar/superlocalmemory
|
|
507
|
+
// 2. claude plugin install superlocalmemory@qualixar
|
|
508
|
+
// 3. slm hooks install
|
|
509
|
+
async function tryInstallClaudePlugin() {
|
|
510
|
+
const { execFile } = require('child_process');
|
|
511
|
+
const { promisify } = require('util');
|
|
512
|
+
const execFileAsync = promisify(execFile);
|
|
513
|
+
|
|
514
|
+
// Find claude binary — try PATH first, then common install locations.
|
|
515
|
+
const claudeCandidates = ['claude'];
|
|
516
|
+
if (process.platform !== 'win32') {
|
|
517
|
+
claudeCandidates.push(
|
|
518
|
+
'/usr/local/bin/claude',
|
|
519
|
+
process.env.HOME + '/.npm-global/bin/claude',
|
|
520
|
+
process.env.HOME + '/.local/bin/claude',
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
let claudeBin = null;
|
|
525
|
+
for (const candidate of claudeCandidates) {
|
|
526
|
+
try {
|
|
527
|
+
await execFileAsync(candidate, ['--version'], { timeout: 5000 });
|
|
528
|
+
claudeBin = candidate;
|
|
529
|
+
break;
|
|
530
|
+
} catch (_e) { /* keep looking */ }
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (!claudeBin) {
|
|
534
|
+
// Claude Code not installed — print guidance and skip.
|
|
535
|
+
console.log('SLM: Claude Code CLI not found — skipping plugin auto-install.');
|
|
536
|
+
console.log('SLM: To install the plugin manually after installing Claude Code:');
|
|
537
|
+
console.log('SLM: claude plugin marketplace add qualixar/superlocalmemory');
|
|
538
|
+
console.log('SLM: claude plugin install superlocalmemory@qualixar');
|
|
539
|
+
console.log('SLM: slm hooks install');
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
console.log('SLM: Claude Code found — installing SLM plugin...');
|
|
544
|
+
|
|
545
|
+
// Step 1: Add marketplace
|
|
546
|
+
try {
|
|
547
|
+
await execFileAsync(claudeBin,
|
|
548
|
+
['plugin', 'marketplace', 'add', 'qualixar/superlocalmemory'],
|
|
549
|
+
{ timeout: 30000 });
|
|
550
|
+
console.log('SLM: marketplace added (qualixar/superlocalmemory)');
|
|
551
|
+
} catch (e) {
|
|
552
|
+
// "already exists" or network error — not fatal
|
|
553
|
+
console.log('SLM: marketplace add note: ' + (e.stderr || e.message || String(e)).trim().split('\n')[0]);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Step 2: Install plugin
|
|
557
|
+
try {
|
|
558
|
+
await execFileAsync(claudeBin,
|
|
559
|
+
['plugin', 'install', 'superlocalmemory@qualixar'],
|
|
560
|
+
{ timeout: 30000 });
|
|
561
|
+
console.log('SLM: plugin installed (superlocalmemory@qualixar)');
|
|
562
|
+
} catch (e) {
|
|
563
|
+
console.log('SLM: plugin install note: ' + (e.stderr || e.message || String(e)).trim().split('\n')[0]);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Step 3: Install hooks (only if not already current — avoids needless writes)
|
|
567
|
+
// `slm hooks install` uses atomic tmp-then-rename and only touches the SLM
|
|
568
|
+
// section of settings.json; all other Claude Code settings are preserved.
|
|
569
|
+
try {
|
|
570
|
+
const statusResult = await execFileAsync('slm', ['hooks', 'status', '--json'],
|
|
571
|
+
{ timeout: 10000 }).catch(() => null);
|
|
572
|
+
const alreadyCurrent = statusResult &&
|
|
573
|
+
(() => { try { const s = JSON.parse(statusResult.stdout); return s.installed && !s.needs_upgrade; } catch { return false; } })();
|
|
574
|
+
if (!alreadyCurrent) {
|
|
575
|
+
await execFileAsync('slm', ['hooks', 'install'], { timeout: 15000 });
|
|
576
|
+
console.log('SLM: hooks installed into Claude Code settings');
|
|
577
|
+
} else {
|
|
578
|
+
console.log('SLM: hooks already current — skipped');
|
|
579
|
+
}
|
|
580
|
+
} catch (e) {
|
|
581
|
+
console.log('SLM: hooks install note: ' + (e.stderr || e.message || String(e)).trim().split('\n')[0]);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
505
585
|
function printFirstRunChecklist(config) {
|
|
506
586
|
console.log('');
|
|
507
587
|
console.log('SuperLocalMemory is configured.');
|
|
@@ -692,6 +772,13 @@ async function main() {
|
|
|
692
772
|
|
|
693
773
|
// UX-G2: show the one-screen delta banner so upgraders see what shipped.
|
|
694
774
|
printLivingBrainDelta();
|
|
775
|
+
|
|
776
|
+
// T1-B: Auto-install Claude Code plugin + hooks. Best-effort, non-blocking.
|
|
777
|
+
// Only runs on npm install (not --dry-run), when claude CLI is present.
|
|
778
|
+
if (!args.dryRun) {
|
|
779
|
+
await tryInstallClaudePlugin();
|
|
780
|
+
}
|
|
781
|
+
|
|
695
782
|
printFirstRunChecklist(config);
|
|
696
783
|
return 0;
|
|
697
784
|
}
|
|
@@ -32,7 +32,7 @@ if "OMP_NUM_THREADS" not in os.environ:
|
|
|
32
32
|
os.environ["OMP_NUM_THREADS"] = "2"
|
|
33
33
|
# ---------------------------------------------------------------------------
|
|
34
34
|
|
|
35
|
-
__version__ = "3.6.
|
|
35
|
+
__version__ = "3.6.18"
|
|
36
36
|
|
|
37
37
|
_REQUIRED_VERSIONS = {
|
|
38
38
|
"sentence_transformers": "5.3.0",
|
|
@@ -789,6 +789,40 @@ def _maybe_install_hooks_on_first_use() -> None:
|
|
|
789
789
|
# Best-effort: parity-fallback, never block CLI.
|
|
790
790
|
pass
|
|
791
791
|
|
|
792
|
+
# T1-B: Auto-install Claude Code plugin (skills, agents, hooks).
|
|
793
|
+
# Runs after hooks install, best-effort — never blocks CLI startup.
|
|
794
|
+
_try_install_claude_plugin()
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
def _try_install_claude_plugin() -> None:
|
|
798
|
+
"""Auto-install the Claude Code plugin on first pip/uvx SLM install.
|
|
799
|
+
|
|
800
|
+
Runs ``claude plugin marketplace add qualixar/superlocalmemory`` then
|
|
801
|
+
``claude plugin install superlocalmemory@qualixar`` if the ``claude``
|
|
802
|
+
CLI is found in PATH. Silent on any error — plugin install is a
|
|
803
|
+
convenience, not a hard requirement for SLM to function.
|
|
804
|
+
"""
|
|
805
|
+
import shutil
|
|
806
|
+
import subprocess
|
|
807
|
+
|
|
808
|
+
claude = shutil.which("claude")
|
|
809
|
+
if not claude:
|
|
810
|
+
return # Claude Code not in PATH — skip silently
|
|
811
|
+
|
|
812
|
+
_run = lambda cmd: subprocess.run( # noqa: E731
|
|
813
|
+
cmd, capture_output=True, timeout=30, check=False
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
try:
|
|
817
|
+
_run([claude, "plugin", "marketplace", "add", "qualixar/superlocalmemory"])
|
|
818
|
+
except Exception:
|
|
819
|
+
pass
|
|
820
|
+
|
|
821
|
+
try:
|
|
822
|
+
_run([claude, "plugin", "install", "superlocalmemory@qualixar"])
|
|
823
|
+
except Exception:
|
|
824
|
+
pass
|
|
825
|
+
|
|
792
826
|
|
|
793
827
|
# ---------------------------------------------------------------------------
|
|
794
828
|
# Mode C provider config (preserved from original)
|
|
@@ -21,6 +21,7 @@ from __future__ import annotations
|
|
|
21
21
|
|
|
22
22
|
import json
|
|
23
23
|
import logging
|
|
24
|
+
import os
|
|
24
25
|
import sys
|
|
25
26
|
import tempfile
|
|
26
27
|
from pathlib import Path
|
|
@@ -31,7 +32,7 @@ CLAUDE_SETTINGS = Path.home() / ".claude" / "settings.json"
|
|
|
31
32
|
VERSION_DIR = Path.home() / ".superlocalmemory" / "hooks"
|
|
32
33
|
VERSION_FILE = VERSION_DIR / ".version"
|
|
33
34
|
DISABLED_FILE = VERSION_DIR / ".hooks-disabled"
|
|
34
|
-
HOOKS_VERSION = "3.
|
|
35
|
+
HOOKS_VERSION = "3.6.18"
|
|
35
36
|
|
|
36
37
|
# Cross-platform temp dir and marker paths
|
|
37
38
|
_TMP = tempfile.gettempdir()
|
|
@@ -92,6 +93,19 @@ def _hook_definitions(include_gate: bool = False) -> dict[str, list]:
|
|
|
92
93
|
"""
|
|
93
94
|
defs: dict[str, list] = {
|
|
94
95
|
"SessionStart": [
|
|
96
|
+
# v3.6.18: mandate fires FIRST so session_init is never skipped.
|
|
97
|
+
# mcp__superlocalmemory__session_init is DEFERRED — Claude must call
|
|
98
|
+
# ToolSearch before it can invoke the tool. Without this hook,
|
|
99
|
+
# Claude responds before loading the schema → no 6-channel memory.
|
|
100
|
+
{
|
|
101
|
+
"hooks": [
|
|
102
|
+
{
|
|
103
|
+
"type": "command",
|
|
104
|
+
"command": _wrap_python_cmd("mandate"),
|
|
105
|
+
"timeout": 5000,
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
},
|
|
95
109
|
{
|
|
96
110
|
"hooks": [
|
|
97
111
|
{
|
|
@@ -100,7 +114,7 @@ def _hook_definitions(include_gate: bool = False) -> dict[str, list]:
|
|
|
100
114
|
"timeout": 15000,
|
|
101
115
|
}
|
|
102
116
|
]
|
|
103
|
-
}
|
|
117
|
+
},
|
|
104
118
|
],
|
|
105
119
|
"PostToolUse": [
|
|
106
120
|
{
|
|
@@ -278,9 +292,31 @@ def _read_settings() -> dict:
|
|
|
278
292
|
|
|
279
293
|
|
|
280
294
|
def _write_settings(settings: dict) -> None:
|
|
281
|
-
"""Write settings.json
|
|
295
|
+
"""Write settings.json atomically — tmp file + rename.
|
|
296
|
+
|
|
297
|
+
Direct .write_text() would truncate the file on a crash mid-write,
|
|
298
|
+
destroying the user's entire Claude Code configuration. The tmp-then-rename
|
|
299
|
+
pattern is atomic on POSIX (os.replace) and near-atomic on Windows: either
|
|
300
|
+
the full new content lands or the original file is untouched.
|
|
301
|
+
|
|
302
|
+
Never overwrites non-SLM settings — _merge_hooks() guarantees that only
|
|
303
|
+
the SLM hooks entries change; all other keys are preserved from the read.
|
|
304
|
+
"""
|
|
282
305
|
CLAUDE_SETTINGS.parent.mkdir(parents=True, exist_ok=True)
|
|
283
|
-
|
|
306
|
+
content = json.dumps(settings, indent=2) + "\n"
|
|
307
|
+
# Write to a sibling tmp file in the same directory so os.replace is atomic
|
|
308
|
+
# (cross-device rename would fail; same-dir rename is guaranteed atomic).
|
|
309
|
+
tmp_path = CLAUDE_SETTINGS.with_suffix(".json.slm_tmp")
|
|
310
|
+
try:
|
|
311
|
+
tmp_path.write_text(content, encoding="utf-8")
|
|
312
|
+
os.replace(tmp_path, CLAUDE_SETTINGS)
|
|
313
|
+
except Exception:
|
|
314
|
+
# Best-effort cleanup of the tmp file on failure
|
|
315
|
+
try:
|
|
316
|
+
tmp_path.unlink(missing_ok=True)
|
|
317
|
+
except Exception:
|
|
318
|
+
pass
|
|
319
|
+
raise
|
|
284
320
|
|
|
285
321
|
|
|
286
322
|
# ---------------------------------------------------------------------------
|
|
@@ -120,6 +120,7 @@ def handle_hook(action: str) -> None:
|
|
|
120
120
|
sys.exit(_main())
|
|
121
121
|
|
|
122
122
|
handlers = {
|
|
123
|
+
"mandate": _hook_mandate,
|
|
123
124
|
"start": _hook_start,
|
|
124
125
|
"gate": _hook_gate,
|
|
125
126
|
"init-done": _hook_init_done,
|
|
@@ -167,6 +168,38 @@ def _launch_post_session_evolution(
|
|
|
167
168
|
)
|
|
168
169
|
|
|
169
170
|
|
|
171
|
+
# ---------------------------------------------------------------------------
|
|
172
|
+
# 0. MANDATE — first SessionStart hook; fires before start
|
|
173
|
+
# ---------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
_MANDATE_TEXT = """<MANDATORY_SESSION_INIT>
|
|
176
|
+
BEFORE writing any text or calling any other tool, you MUST execute these two steps in order:
|
|
177
|
+
|
|
178
|
+
STEP 1 — Load schema:
|
|
179
|
+
Call ToolSearch with query: "select:mcp__superlocalmemory__session_init"
|
|
180
|
+
|
|
181
|
+
STEP 2 — Initialize memory brain:
|
|
182
|
+
Call mcp__superlocalmemory__session_init with:
|
|
183
|
+
project_path = your current working directory
|
|
184
|
+
query = a short description of the session topic (derive from user's first message)
|
|
185
|
+
|
|
186
|
+
This is non-negotiable. SLM is the brain. Without session_init, you have no 6-channel memory context (Ebbinghaus decay, entity graph, FSRS, spreading activation all go cold).
|
|
187
|
+
DO NOT output any text until session_init has completed.
|
|
188
|
+
</MANDATORY_SESSION_INIT>"""
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _hook_mandate() -> None:
|
|
192
|
+
"""Print the session_init mandate. MUST be the FIRST SessionStart hook.
|
|
193
|
+
|
|
194
|
+
mcp__superlocalmemory__session_init is DEFERRED at session start — Claude
|
|
195
|
+
cannot call it without ToolSearch first loading the schema. This hook
|
|
196
|
+
fires before `slm hook start` and injects the two-step protocol into the
|
|
197
|
+
system-reminder block so Claude's first action is always ToolSearch →
|
|
198
|
+
session_init, not a text response with no memory context.
|
|
199
|
+
"""
|
|
200
|
+
print(_MANDATE_TEXT)
|
|
201
|
+
|
|
202
|
+
|
|
170
203
|
# ---------------------------------------------------------------------------
|
|
171
204
|
# 1. SESSION START — SessionStart hook
|
|
172
205
|
# ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory v3.6.18
|
|
4
|
+
|
|
5
|
+
"""M017 — scope column on ccq_consolidated_blocks.
|
|
6
|
+
|
|
7
|
+
The cognitive-consolidation queue table (``ccq_consolidated_blocks``) was
|
|
8
|
+
created before the M016 multi-scope migration and therefore has no ``scope``
|
|
9
|
+
column. Without it, consolidation summaries are always stored as
|
|
10
|
+
``personal`` regardless of the source facts' scope — a silent data-loss edge
|
|
11
|
+
case when a user has opted into global or shared memory.
|
|
12
|
+
|
|
13
|
+
Fix: add a ``scope TEXT NOT NULL DEFAULT 'personal'`` column plus a
|
|
14
|
+
``(profile_id, scope)`` covering index for scope-filtered queries.
|
|
15
|
+
|
|
16
|
+
Deferred (like M006, M011, M013, M016): the CCQ table is created by the
|
|
17
|
+
engine, not by migration DDL, so we apply after engine init via
|
|
18
|
+
``apply_deferred``.
|
|
19
|
+
|
|
20
|
+
Author: Varun Pratap Bhardwaj / Qualixar
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import sqlite3
|
|
26
|
+
|
|
27
|
+
NAME = "M017_ccq_scope_column"
|
|
28
|
+
DB_TARGET = "memory"
|
|
29
|
+
|
|
30
|
+
TABLE = "ccq_consolidated_blocks"
|
|
31
|
+
|
|
32
|
+
DDL = (
|
|
33
|
+
f"ALTER TABLE {TABLE} ADD COLUMN scope TEXT NOT NULL DEFAULT 'personal';"
|
|
34
|
+
f"CREATE INDEX IF NOT EXISTS idx_{TABLE}_scope ON {TABLE}(scope);"
|
|
35
|
+
f"CREATE INDEX IF NOT EXISTS idx_{TABLE}_profile_scope ON {TABLE}(profile_id, scope);"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _table_exists(conn: sqlite3.Connection, table: str) -> bool:
|
|
40
|
+
return conn.execute(
|
|
41
|
+
"SELECT 1 FROM sqlite_master WHERE type='table' AND name=?", (table,)
|
|
42
|
+
).fetchone() is not None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _column_names(conn: sqlite3.Connection, table: str) -> set[str]:
|
|
46
|
+
return {r[1] for r in conn.execute(f"PRAGMA table_info({table})").fetchall()}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def apply(conn: sqlite3.Connection) -> None:
|
|
50
|
+
"""Idempotently add scope column + indexes to ccq_consolidated_blocks.
|
|
51
|
+
|
|
52
|
+
Skips silently when the table doesn't exist yet (engine hasn't created it)
|
|
53
|
+
or when the column is already present (re-apply or fresh install).
|
|
54
|
+
"""
|
|
55
|
+
if not _table_exists(conn, TABLE):
|
|
56
|
+
return
|
|
57
|
+
cols = _column_names(conn, TABLE)
|
|
58
|
+
if "scope" not in cols:
|
|
59
|
+
conn.execute(
|
|
60
|
+
f"ALTER TABLE {TABLE} ADD COLUMN scope TEXT NOT NULL DEFAULT 'personal'"
|
|
61
|
+
)
|
|
62
|
+
conn.execute(f"CREATE INDEX IF NOT EXISTS idx_{TABLE}_scope ON {TABLE}(scope)")
|
|
63
|
+
conn.execute(
|
|
64
|
+
f"CREATE INDEX IF NOT EXISTS idx_{TABLE}_profile_scope ON {TABLE}(profile_id, scope)"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def verify(conn: sqlite3.Connection) -> bool:
|
|
69
|
+
"""Applied when ccq_consolidated_blocks has the scope column and index."""
|
|
70
|
+
if not _table_exists(conn, TABLE):
|
|
71
|
+
return True # table absent — apply() skips it; nothing to verify
|
|
72
|
+
cols = _column_names(conn, TABLE)
|
|
73
|
+
if "scope" not in cols:
|
|
74
|
+
return False
|
|
75
|
+
idx = conn.execute(
|
|
76
|
+
"SELECT 1 FROM sqlite_master WHERE type='index' AND name=?",
|
|
77
|
+
(f"idx_{TABLE}_scope",),
|
|
78
|
+
).fetchone()
|
|
79
|
+
return idx is not None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: superlocalmemory
|
|
3
|
-
Version: 3.6.
|
|
3
|
+
Version: 3.6.18
|
|
4
4
|
Summary: Information-geometric agent memory with mathematical guarantees
|
|
5
5
|
Author-email: Varun Pratap Bhardwaj <admin@superlocalmemory.com>
|
|
6
6
|
License: AGPL-3.0-or-later
|
|
@@ -96,10 +96,10 @@ Dynamic: license-file
|
|
|
96
96
|
<img src="https://superlocalmemory.com/assets/logo-mark.png" alt="SuperLocalMemory" width="200"/>
|
|
97
97
|
</p>
|
|
98
98
|
|
|
99
|
-
<h1 align="center">SuperLocalMemory V3.6.
|
|
99
|
+
<h1 align="center">SuperLocalMemory V3.6.18</h1>
|
|
100
100
|
<p align="center"><strong>Cache. Compress. Remember. Three surfaces — proxy, MCP tools, or skill. Every setup covered.</strong><br/>
|
|
101
101
|
<em>To the best of our knowledge, the only zero-cloud agent memory that beats Mem0's zero-LLM score on LoCoMo. Mode A: 74.8% vs Mem0 64.2% — no GPU, no API key, on CPU.</em></p>
|
|
102
|
-
<p align="center"><code>v3.6.
|
|
102
|
+
<p align="center"><code>v3.6.18</code> — <strong>Plugin-native. Profile-aware. Distributed-ready.</strong><br/>
|
|
103
103
|
Proxy: <code>slm wrap claude</code> · MCP: add <code>slm_compress</code> to your config · Skill: zero-config</p>
|
|
104
104
|
<p align="center"><strong>3 published research papers</strong> (arXiv preprints + Zenodo-archived) · <a href="https://arxiv.org/abs/2603.02240">arXiv:2603.02240</a> · <a href="https://arxiv.org/abs/2603.14588">arXiv:2603.14588</a> · <a href="https://arxiv.org/abs/2604.04514">arXiv:2604.04514</a></p>
|
|
105
105
|
|
|
@@ -435,6 +435,7 @@ src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py
|
|
|
435
435
|
src/superlocalmemory/storage/migrations/M014_v345_scale_ready.py
|
|
436
436
|
src/superlocalmemory/storage/migrations/M015_add_pinned_column.py
|
|
437
437
|
src/superlocalmemory/storage/migrations/M016_add_scope_support.py
|
|
438
|
+
src/superlocalmemory/storage/migrations/M017_ccq_scope_column.py
|
|
438
439
|
src/superlocalmemory/storage/migrations/__init__.py
|
|
439
440
|
src/superlocalmemory/trust/__init__.py
|
|
440
441
|
src/superlocalmemory/trust/gate.py
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Apply SLM context-optimization (compress large output / cache repeats) and report savings.
|
|
3
|
-
argument-hint: [stats]
|
|
4
|
-
allowed-tools: slm_compress, slm_cache_set, slm_cache_get, slm_optimize_stats, Bash
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Apply SuperLocalMemory context-optimization. Arguments: $ARGUMENTS
|
|
8
|
-
|
|
9
|
-
If arguments are empty or "stats":
|
|
10
|
-
- Call `slm_optimize_stats()` and report: cache_kv_hits, compress_runs, tokens_saved_compress.
|
|
11
|
-
|
|
12
|
-
If there is large output to compress (>2000 chars):
|
|
13
|
-
- Call `slm_compress(content=<output>, mode="auto", reversible=True)`.
|
|
14
|
-
- Work from the compressed form; retain ccr_id if the result is lossy.
|
|
15
|
-
|
|
16
|
-
Rules (apply strictly):
|
|
17
|
-
- Rule 6 — NEVER compress/cache: code intended for Edit/Write; JSON being parsed; secrets/keys/tokens; ccr_ids; content <500 chars.
|
|
18
|
-
- Rule 8 — FAIL-OPEN: if ok:false, continue with original; do not retry; do not surface the error unless the user asks.
|
|
19
|
-
|
|
20
|
-
MCP unavailable → CLI fallback: `slm optimize status`.
|
|
21
|
-
|
|
22
|
-
SuperLocalMemory v3.6.17 · Qualixar · AGPL-3.0-or-later
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Recall relevant facts and decisions from SuperLocalMemory by query.
|
|
3
|
-
argument-hint: <what to recall>
|
|
4
|
-
allowed-tools: recall, search, Bash
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Recall from SuperLocalMemory using the query: $ARGUMENTS
|
|
8
|
-
|
|
9
|
-
1. Call `recall(query="$ARGUMENTS", limit=10)` via MCP.
|
|
10
|
-
2. If no confident match or count==0, also call `search("$ARGUMENTS", 10)`.
|
|
11
|
-
3. Present results concisely — fact, tags, importance, date. Never invent or fabricate a memory.
|
|
12
|
-
4. If MCP is unavailable, fall back to CLI:
|
|
13
|
-
- `slm recall "$ARGUMENTS" --limit 10`
|
|
14
|
-
- then `slm search "$ARGUMENTS"`
|
|
15
|
-
|
|
16
|
-
SuperLocalMemory v3.6.17 · Qualixar · AGPL-3.0-or-later
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Save an atomic fact or decision to SuperLocalMemory.
|
|
3
|
-
argument-hint: <the fact> [#tag1,tag2]
|
|
4
|
-
allowed-tools: recall, remember, Bash
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Save to SuperLocalMemory: $ARGUMENTS
|
|
8
|
-
|
|
9
|
-
1. First call `recall("$ARGUMENTS", 5)` — dedupe check. If a near-identical memory exists, tell the user and stop; delegate to slm-memory-advisor to update_memory if a correction is needed.
|
|
10
|
-
2. Extract tags from any trailing `#tag1,tag2` pattern in the arguments.
|
|
11
|
-
3. Determine importance: use 8 for blockers/security/architecture decisions; use 7 for conventions and constraints; use 5 for general facts.
|
|
12
|
-
4. Call `remember(content="$ARGUMENTS", tags=<extracted tags>, importance=<n>)`.
|
|
13
|
-
5. Confirm only on success:true. If success is not true, report the error — never claim "saved."
|
|
14
|
-
6. MCP unavailable → CLI fallback: `slm remember "$ARGUMENTS" --tags <tags>` (note: `--importance` is MCP-only, not a CLI flag).
|
|
15
|
-
|
|
16
|
-
SuperLocalMemory v3.6.17 · Qualixar · AGPL-3.0-or-later
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Show SuperLocalMemory health and optimization counters.
|
|
3
|
-
argument-hint: (no arguments)
|
|
4
|
-
allowed-tools: slm_optimize_stats, Bash
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Show SuperLocalMemory status and optimization counters.
|
|
8
|
-
|
|
9
|
-
1. Run `slm status` via Bash — this is the canonical health check (memory count, profile, daemon state, integrity).
|
|
10
|
-
2. Also call `slm_optimize_stats()` via MCP for Surface-B counters (cache_kv_hits, compress_runs, tokens_saved_compress). If ok:false, omit silently — do not surface the error.
|
|
11
|
-
3. Summarize both outputs in a concise report. Flag any integrity warnings from `slm status`.
|
|
12
|
-
|
|
13
|
-
Note: MCP get_status is intentionally NOT used here — it is outside the core profile and would error. Use `slm status` (CLI) + `slm_optimize_stats` (MCP) only.
|
|
14
|
-
|
|
15
|
-
SuperLocalMemory v3.6.17 · Qualixar · AGPL-3.0-or-later
|