superlocalmemory 4.1.5 → 4.1.6
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/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +36 -0
- package/README.md +3 -3
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +1 -1
- 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-governance/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-loop/SKILL.md +1 -1
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/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-scope/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/rules/AGENTS.md +1 -1
- 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-governance/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-loop/SKILL.md +1 -1
- package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
- package/plugin-src/skills/slm-profile/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-scope/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 +1 -1
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/core/maintenance_scheduler.py +36 -0
- package/src/superlocalmemory/encoding/fact_extractor.py +7 -3
- package/src/superlocalmemory/mcp/session_binding.py +7 -1
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"license": "AGPL-3.0-or-later",
|
|
22
22
|
"name": "superlocalmemory",
|
|
23
23
|
"source": "./plugin",
|
|
24
|
-
"version": "4.1.
|
|
24
|
+
"version": "4.1.6"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"author": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"license": "AGPL-3.0-or-later",
|
|
40
40
|
"name": "superlocalmemory-codex",
|
|
41
41
|
"source": "./codex-plugin",
|
|
42
|
-
"version": "4.1.
|
|
42
|
+
"version": "4.1.6"
|
|
43
43
|
}
|
|
44
44
|
]
|
|
45
45
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,42 @@ All notable changes to SuperLocalMemory will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.1.6] — A learning loop that never learns looks identical to one that works
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **The engagement-learning loop settled every outcome at neutral, regardless of
|
|
12
|
+
real usage.** `SESSION_ENV_VARS` checked `SLM_SESSION_ID` and `CLAUDE_SESSION_ID`
|
|
13
|
+
but not `CLAUDE_CODE_SESSION_ID` — the variable Claude Code's own MCP subprocess
|
|
14
|
+
actually sets. Every recall from Claude Code fell through to the synthetic
|
|
15
|
+
`mcp:<agent_id>` id, which step 4 of the resolution ladder deliberately excludes
|
|
16
|
+
from ever matching a pending outcome, by design — a real session should never be
|
|
17
|
+
confused with a placeholder. The result: measured on a live store, 6,013 of 6,039
|
|
18
|
+
settled outcomes carried exactly `reward=0.5`, and all 414 bandit arms held
|
|
19
|
+
`alpha == beta` at every play count. Adding the missing name is what closes the
|
|
20
|
+
loop; two test files that had never isolated session resolution from the ambient
|
|
21
|
+
environment were also hardened, since a live Claude Code session now genuinely
|
|
22
|
+
satisfies the check they'd only ever run without.
|
|
23
|
+
- **Auto-captured facts could assert a date nothing in the source text contained.**
|
|
24
|
+
The fact-extraction system prompt taught relative-date resolution with a fixed
|
|
25
|
+
worked example — `'Yesterday' with session date 2024-01-15 becomes '2024-01-14'`
|
|
26
|
+
— sent identically on every extraction call. A smaller local model under
|
|
27
|
+
uncertainty would echo that literal example date back as if it were extracted
|
|
28
|
+
content, rather than resolving against the real conversation date already present
|
|
29
|
+
in the same prompt. Reproduced live and fixed by removing the concrete date from
|
|
30
|
+
the instruction entirely, teaching the same rule without anything to leak.
|
|
31
|
+
Several existing memories carrying this exact signature — including one date
|
|
32
|
+
claim accessed 28 times — were identified and quarantined.
|
|
33
|
+
- **A store that drifted from M048's classification rule stayed unready for up to a
|
|
34
|
+
full maintenance interval (6 hours) after every restart.** The migration itself
|
|
35
|
+
is idempotent and safe to replay — its own `verify()` docstring says so — but the
|
|
36
|
+
migration runner never replays a completed migration, and the periodic
|
|
37
|
+
maintenance cycle that's supposed to reconcile it only runs once every
|
|
38
|
+
`scheduler_interval_minutes`. A restart landing between cycles reported
|
|
39
|
+
`ready=false, migrations=false` with "automatic replay is disabled" and stayed
|
|
40
|
+
that way until the next scheduled tick. A third staggered one-shot startup timer,
|
|
41
|
+
matching the two that already exist for the same reason (cache GC, graph
|
|
42
|
+
metrics), now runs the same reconciliation pass within seconds of boot instead.
|
|
43
|
+
|
|
8
44
|
## [4.1.5] — Ask whether a feature is working, not whether it is present
|
|
9
45
|
|
|
10
46
|
### Added
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
<h1 align="center">SuperLocalMemory V4.1.
|
|
8
|
+
<h1 align="center">SuperLocalMemory V4.1.6</h1>
|
|
9
9
|
|
|
10
10
|
<h2 align="center">Rent the LLM. Own the memory.</h2>
|
|
11
11
|
|
|
@@ -27,12 +27,12 @@ guarantee here is stated as a falsifiable invariant, tested under an adversarial
|
|
|
27
27
|
negative control, and shipped with the harness that regenerates the evidence:
|
|
28
28
|
<code>python benchmark/run_all.py --trials 200 --output-dir results/</code>. What each experiment
|
|
29
29
|
does <em>not</em> exercise is stated too.</p>
|
|
30
|
-
<p align="center"><code>v4.1.
|
|
30
|
+
<p align="center"><code>v4.1.6</code> — one control plane: <strong>SLM-Mesh</strong> peer coordination · multi-scope memory (personal / shared / global) · profiles · Cache · Compress · 7-layer retrieval · code graph · Entity Explorer · skill evolution · Modes A/B/C · GDPR retention & audit chain · bounded loops — across CLI, MCP, dashboard, the <strong>Claude plugin</strong>, the <strong>Codex add-on</strong>, and documented IDE integrations.<br/>
|
|
31
31
|
Proxy: <code>slm wrap claude</code> · MCP: add <code>slm_compress</code> to your config · Skill: zero-config</p>
|
|
32
32
|
<p align="center"><strong>Four public arXiv preprints</strong> · V4: <a href="https://arxiv.org/abs/2608.08253">arXiv:2608.08253</a> · companion archive: <a href="https://zenodo.org/records/21853302">Zenodo 21853302</a> (<a href="https://doi.org/10.5281/zenodo.21853302">DOI 10.5281/zenodo.21853302</a>) · prior preprints: <a href="https://arxiv.org/abs/2603.02240">2603.02240</a> · <a href="https://arxiv.org/abs/2603.14588">2603.14588</a> · <a href="https://arxiv.org/abs/2604.04514">2604.04514</a>.</p>
|
|
33
33
|
|
|
34
34
|
<p align="center">
|
|
35
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/v4.1.
|
|
35
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/v4.1.6-Current_Release-2ea44f?style=for-the-badge&logo=checkmarx&logoColor=white" alt="v4.1.6 — Current Release"/></a>
|
|
36
36
|
<a href="https://arxiv.org/abs/2608.08253"><img src="https://img.shields.io/badge/arXiv-2608.08253-b31b1b?style=for-the-badge&logo=arxiv&logoColor=white" alt="SuperLocalMemory 4.0 paper on arXiv:2608.08253"/></a>
|
|
37
37
|
<a href="https://zenodo.org/records/21853302"><img src="https://img.shields.io/badge/Zenodo-10.5281%2Fzenodo.21853302-1682D4?style=for-the-badge&logo=zenodo&logoColor=white" alt="V4 paper on Zenodo: 10.5281/zenodo.21853302"/></a>
|
|
38
38
|
<a href="https://arxiv.org/abs/2603.14588"><img src="https://img.shields.io/badge/arXiv-2603.14588-b31b1b?style=for-the-badge&logo=arxiv&logoColor=white" alt="arXiv Paper"/></a>
|
package/package.json
CHANGED
package/plugin/CLAUDE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- BEGIN SuperLocalMemory v4.1.
|
|
1
|
+
<!-- BEGIN SuperLocalMemory v4.1.6 -->
|
|
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, scope/profile guidance) · slm-optimize-advisor (context compression + KV cache) · slm-governance-advisor (scope/roles/compliance/GDPR)
|
|
41
41
|
|
|
42
|
-
<!-- END SuperLocalMemory v4.1.
|
|
42
|
+
<!-- END SuperLocalMemory v4.1.6 -->
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v4.1.
|
|
44
|
+
SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
|
|
@@ -77,4 +77,4 @@ slm-scope · slm-governance · slm-profile · slm-remember · slm-recall
|
|
|
77
77
|
# What NOT to do
|
|
78
78
|
Never session_init twice; never forget without dry-run preview; never store secrets; never bypass role checks; never claim an erasure succeeded without verifying via recall.
|
|
79
79
|
|
|
80
|
-
SuperLocalMemory v4.1.
|
|
80
|
+
SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
|
|
@@ -46,4 +46,4 @@ slm-recall · slm-remember · slm-session · slm-scope · slm-profile · slm-gov
|
|
|
46
46
|
# What NOT to do
|
|
47
47
|
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; never bypass scope or governance restrictions.
|
|
48
48
|
|
|
49
|
-
SuperLocalMemory v4.1.
|
|
49
|
+
SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
|
|
@@ -41,4 +41,4 @@ slm-compress · slm-cache · slm-status · slm-profile
|
|
|
41
41
|
# What NOT to do
|
|
42
42
|
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 %; never carry ccr_ids across profile switches.
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v4.1.
|
|
44
|
+
SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
|
package/plugin/requirements.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
superlocalmemory==4.1.
|
|
1
|
+
superlocalmemory==4.1.6
|
|
@@ -137,4 +137,4 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
|
|
|
137
137
|
- **slm-optimize-advisor** — context compression and KV cache
|
|
138
138
|
- **slm-governance-advisor** — scope/role compliance, retention policies, GDPR
|
|
139
139
|
|
|
140
|
-
SuperLocalMemory v4.1.
|
|
140
|
+
SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
|
package/pyproject.toml
CHANGED
|
@@ -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__ = "4.1.
|
|
35
|
+
__version__ = "4.1.6"
|
|
36
36
|
|
|
37
37
|
_REQUIRED_VERSIONS = {
|
|
38
38
|
"sentence_transformers": "5.3.0",
|
|
@@ -77,11 +77,43 @@ class MaintenanceScheduler:
|
|
|
77
77
|
)
|
|
78
78
|
self._initial_metrics_timer.daemon = True
|
|
79
79
|
self._initial_metrics_timer.start()
|
|
80
|
+
# M048's re-read pass is idempotent and safe to replay (see its
|
|
81
|
+
# verify() docstring), but the migration runner never replays a
|
|
82
|
+
# completed migration and the cycle above only reaches it every
|
|
83
|
+
# ``scheduler_interval_minutes`` (360 by default). A store that
|
|
84
|
+
# drifted since the last cycle stays blocking — ready=false,
|
|
85
|
+
# migrations=false — for up to that whole interval after every
|
|
86
|
+
# restart, not because the fix is slow, but because nothing asks
|
|
87
|
+
# for it sooner. Staggered behind the other two so none of the
|
|
88
|
+
# three one-shots contend for the write lock.
|
|
89
|
+
self._initial_reclassify_timer = threading.Timer(
|
|
90
|
+
210.0, self._initial_reclassify_upcoming,
|
|
91
|
+
)
|
|
92
|
+
self._initial_reclassify_timer.daemon = True
|
|
93
|
+
self._initial_reclassify_timer.start()
|
|
80
94
|
logger.info(
|
|
81
95
|
"Maintenance scheduler started (interval=%dm)",
|
|
82
96
|
self._config.forgetting.scheduler_interval_minutes,
|
|
83
97
|
)
|
|
84
98
|
|
|
99
|
+
def _initial_reclassify_upcoming(self) -> None:
|
|
100
|
+
"""Best-effort one-shot M048 re-read shortly after boot.
|
|
101
|
+
|
|
102
|
+
Runs the same pass the periodic cycle already runs (see below) so a
|
|
103
|
+
store that drifted before this restart converges within seconds
|
|
104
|
+
instead of waiting up to a full maintenance interval with the
|
|
105
|
+
daemon reporting itself not ready.
|
|
106
|
+
"""
|
|
107
|
+
if not self._running:
|
|
108
|
+
return
|
|
109
|
+
try:
|
|
110
|
+
from superlocalmemory.storage.migrations import (
|
|
111
|
+
M048_upcoming_holds_only_what_is_upcoming as _reclassify,
|
|
112
|
+
)
|
|
113
|
+
_reclassify.apply(open_connection=self._db.raw_connection)
|
|
114
|
+
except Exception as exc:
|
|
115
|
+
logger.debug("Startup plan re-read skipped: %s", exc)
|
|
116
|
+
|
|
85
117
|
def _initial_cache_gc(self) -> None:
|
|
86
118
|
"""Best-effort one-shot activation-cache GC shortly after boot."""
|
|
87
119
|
if not self._running:
|
|
@@ -133,6 +165,10 @@ class MaintenanceScheduler:
|
|
|
133
165
|
if _metrics_timer is not None:
|
|
134
166
|
_metrics_timer.cancel()
|
|
135
167
|
self._initial_metrics_timer = None
|
|
168
|
+
_reclassify_timer = getattr(self, "_initial_reclassify_timer", None)
|
|
169
|
+
if _reclassify_timer is not None:
|
|
170
|
+
_reclassify_timer.cancel()
|
|
171
|
+
self._initial_reclassify_timer = None
|
|
136
172
|
logger.info("Maintenance scheduler stopped")
|
|
137
173
|
|
|
138
174
|
def _schedule_next(self) -> None:
|
|
@@ -134,9 +134,13 @@ _SYSTEM_PROMPT = (
|
|
|
134
134
|
"must name the subject explicitly.\n"
|
|
135
135
|
"2. Each fact must be a COMPLETE, STANDALONE statement understandable "
|
|
136
136
|
"without the original conversation.\n"
|
|
137
|
-
"3. Convert ALL relative time to ABSOLUTE dates when possible
|
|
138
|
-
"
|
|
139
|
-
"
|
|
137
|
+
"3. Convert ALL relative time to ABSOLUTE dates when possible, using "
|
|
138
|
+
"ONLY the conversation date given in the user message below as your "
|
|
139
|
+
"reference point — never invent or assume a date. 'Yesterday' resolves "
|
|
140
|
+
"to one calendar day before that conversation date; 'next month' "
|
|
141
|
+
"resolves to the following calendar month of that same date. If no "
|
|
142
|
+
"conversation date is given, leave the date unresolved rather than "
|
|
143
|
+
"guessing one.\n"
|
|
140
144
|
"4. Resolve ALL coreferences. 'He went there' must become "
|
|
141
145
|
"'[Person name] went to [Place name]'.\n"
|
|
142
146
|
"5. Extract relationships between people when mentioned.\n"
|
|
@@ -34,7 +34,13 @@ __all__ = ["resolve_session_id", "SESSION_ENV_VARS"]
|
|
|
34
34
|
|
|
35
35
|
#: Checked in order. Hosts set one or the other; SLM's own takes precedence so a
|
|
36
36
|
#: user can override a host that sets its variable to something unhelpful.
|
|
37
|
-
|
|
37
|
+
#: ``CLAUDE_CODE_SESSION_ID`` is the actual variable Claude Code's MCP
|
|
38
|
+
#: subprocess environment carries — verified on a live daemon 2026-08-24,
|
|
39
|
+
#: this pipeline settled 6013/6039 outcomes at the neutral 0.5 fallback
|
|
40
|
+
#: because the old two-name list never matched it, and every recall fell
|
|
41
|
+
#: through to the synthetic ``mcp:<agent_id>`` id that step 4 deliberately
|
|
42
|
+
#: excludes from matching.
|
|
43
|
+
SESSION_ENV_VARS = ("SLM_SESSION_ID", "CLAUDE_SESSION_ID", "CLAUDE_CODE_SESSION_ID")
|
|
38
44
|
|
|
39
45
|
|
|
40
46
|
def resolve_session_id(
|