superlocalmemory 4.1.5 → 4.1.7
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 +55 -0
- package/README.md +3 -3
- package/package.json +3 -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/agents/slm-memory-advisor.md +49 -0
- package/plugin-src/agents/slm-optimize-advisor.md +44 -0
- 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 +5 -1
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/host_upgrades.py +21 -7
- package/src/superlocalmemory/core/engine.py +7 -1
- package/src/superlocalmemory/core/maintenance_scheduler.py +36 -0
- package/src/superlocalmemory/core/recall_pipeline.py +13 -6
- package/src/superlocalmemory/core/session_identity.py +14 -1
- package/src/superlocalmemory/encoding/fact_extractor.py +7 -3
- package/src/superlocalmemory/hooks/codex_assets.py +165 -45
- package/src/superlocalmemory/learning/bandit.py +22 -2
- package/src/superlocalmemory/learning/engagement_features.py +279 -0
- package/src/superlocalmemory/learning/outcome_queue.py +14 -0
- package/src/superlocalmemory/learning/propensity.py +131 -0
- package/src/superlocalmemory/learning/reward.py +42 -16
- package/src/superlocalmemory/learning/reward_model.py +144 -0
- package/src/superlocalmemory/learning/reward_proxy.py +148 -22
- package/src/superlocalmemory/mcp/session_binding.py +7 -1
- package/src/superlocalmemory/server/routes/v3_api.py +4 -3
|
@@ -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.7"
|
|
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.7"
|
|
43
43
|
}
|
|
44
44
|
]
|
|
45
45
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,61 @@ 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.7] — Recall that improves with use
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Adaptive ranking is on by default.** Recall now learns which memories
|
|
12
|
+
actually helped and ranks accordingly. Set `SLM_RANKING=off` to opt out.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **Ranking never learned anything.** Recalls were not attributed to the
|
|
16
|
+
conversation they came from, so nothing could tell whether a memory had been
|
|
17
|
+
useful, and every result was scored the same regardless. Recalls are now
|
|
18
|
+
attributed correctly and scored from real use.
|
|
19
|
+
- **Unused results are no longer scored as average.** When there is no evidence
|
|
20
|
+
either way, a result is left unscored instead of being recorded as
|
|
21
|
+
middling — which had made the ranking progressively harder to change.
|
|
22
|
+
- **Frequently shown memories no longer reinforce themselves.** A memory that
|
|
23
|
+
was going to be shown regardless now counts for less than one that was not.
|
|
24
|
+
- **Codex subagents install complete.** Installing from a published package
|
|
25
|
+
produced one-line advisor definitions instead of the full ones.
|
|
26
|
+
|
|
27
|
+
## [4.1.6] — A learning loop that never learns looks identical to one that works
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- **The engagement-learning loop settled every outcome at neutral, regardless of
|
|
31
|
+
real usage.** `SESSION_ENV_VARS` checked `SLM_SESSION_ID` and `CLAUDE_SESSION_ID`
|
|
32
|
+
but not `CLAUDE_CODE_SESSION_ID` — the variable Claude Code's own MCP subprocess
|
|
33
|
+
actually sets. Every recall from Claude Code fell through to the synthetic
|
|
34
|
+
`mcp:<agent_id>` id, which step 4 of the resolution ladder deliberately excludes
|
|
35
|
+
from ever matching a pending outcome, by design — a real session should never be
|
|
36
|
+
confused with a placeholder. The result: measured on a live store, 6,013 of 6,039
|
|
37
|
+
settled outcomes carried exactly `reward=0.5`, and all 414 bandit arms held
|
|
38
|
+
`alpha == beta` at every play count. Adding the missing name is what closes the
|
|
39
|
+
loop; two test files that had never isolated session resolution from the ambient
|
|
40
|
+
environment were also hardened, since a live Claude Code session now genuinely
|
|
41
|
+
satisfies the check they'd only ever run without.
|
|
42
|
+
- **Auto-captured facts could assert a date nothing in the source text contained.**
|
|
43
|
+
The fact-extraction system prompt taught relative-date resolution with a fixed
|
|
44
|
+
worked example — `'Yesterday' with session date 2024-01-15 becomes '2024-01-14'`
|
|
45
|
+
— sent identically on every extraction call. A smaller local model under
|
|
46
|
+
uncertainty would echo that literal example date back as if it were extracted
|
|
47
|
+
content, rather than resolving against the real conversation date already present
|
|
48
|
+
in the same prompt. Reproduced live and fixed by removing the concrete date from
|
|
49
|
+
the instruction entirely, teaching the same rule without anything to leak.
|
|
50
|
+
Several existing memories carrying this exact signature — including one date
|
|
51
|
+
claim accessed 28 times — were identified and quarantined.
|
|
52
|
+
- **A store that drifted from M048's classification rule stayed unready for up to a
|
|
53
|
+
full maintenance interval (6 hours) after every restart.** The migration itself
|
|
54
|
+
is idempotent and safe to replay — its own `verify()` docstring says so — but the
|
|
55
|
+
migration runner never replays a completed migration, and the periodic
|
|
56
|
+
maintenance cycle that's supposed to reconcile it only runs once every
|
|
57
|
+
`scheduler_interval_minutes`. A restart landing between cycles reported
|
|
58
|
+
`ready=false, migrations=false` with "automatic replay is disabled" and stayed
|
|
59
|
+
that way until the next scheduled tick. A third staggered one-shot startup timer,
|
|
60
|
+
matching the two that already exist for the same reason (cache GC, graph
|
|
61
|
+
metrics), now runs the same reconciliation pass within seconds of boot instead.
|
|
62
|
+
|
|
8
63
|
## [4.1.5] — Ask whether a feature is working, not whether it is present
|
|
9
64
|
|
|
10
65
|
### 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.7</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.7</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.7-Current_Release-2ea44f?style=for-the-badge&logo=checkmarx&logoColor=white" alt="v4.1.7 — 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superlocalmemory",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.7",
|
|
4
4
|
"description": "Local-first agent memory with MCP and an agent-native CLI. Documented clients include Claude Code, Cursor, and Windsurf.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-memory",
|
|
@@ -96,6 +96,8 @@
|
|
|
96
96
|
"plugin-src/skills/slm-scope/SKILL.md",
|
|
97
97
|
"plugin-src/skills/slm-session/SKILL.md",
|
|
98
98
|
"plugin-src/skills/slm-status/SKILL.md",
|
|
99
|
+
"plugin-src/agents/slm-memory-advisor.md",
|
|
100
|
+
"plugin-src/agents/slm-optimize-advisor.md",
|
|
99
101
|
"plugin-src/rules/AGENTS.md",
|
|
100
102
|
"docs/pi-dev-integration.md",
|
|
101
103
|
"pyproject.toml",
|
package/plugin/CLAUDE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- BEGIN SuperLocalMemory v4.1.
|
|
1
|
+
<!-- BEGIN SuperLocalMemory v4.1.7 -->
|
|
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.7 -->
|
|
43
43
|
|
|
44
|
-
SuperLocalMemory v4.1.
|
|
44
|
+
SuperLocalMemory v4.1.7 · 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.7 · 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.7 · 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.7 · Qualixar · AGPL-3.0-or-later
|
package/plugin/requirements.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
superlocalmemory==4.1.
|
|
1
|
+
superlocalmemory==4.1.7
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: slm-memory-advisor
|
|
3
|
+
description: >
|
|
4
|
+
Advises the main agent on using SuperLocalMemory well — when to call
|
|
5
|
+
session_init, remember, recall, and search; how to phrase queries; and how
|
|
6
|
+
to keep memory clean. Delegate here for any "should I save/recall this?"
|
|
7
|
+
decision or when memory results look wrong.
|
|
8
|
+
tools: session_init, recall, search, remember, update_memory, forget, list_recent, Read
|
|
9
|
+
model: inherit
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Role
|
|
13
|
+
You are the SuperLocalMemory (SLM) memory advisor. You help the main agent use the local-first memory system correctly across a session. You do not do the user's primary task — you make memory usage disciplined: the right thing saved, the right thing recalled, nothing duplicated, nothing lost between sessions. Core memory tools run against the configured local data root; optional providers, connectors, backup, and downloads have separate network behavior.
|
|
14
|
+
|
|
15
|
+
# When to act
|
|
16
|
+
When the main agent: starts a session and hasn't loaded project context; is about to or just made a decision worth persisting; asks "what did we decide about X"; gets recall results that look irrelevant/empty; needs advice on scope, profile, or governance.
|
|
17
|
+
|
|
18
|
+
# Tools you may use (real SLM MCP tools, core profile)
|
|
19
|
+
- `session_init(project_path, query, max_results, max_age_days)` — ONCE at session start; returns recent decisions + relevant memories.
|
|
20
|
+
- `recall(query, limit, session_id, fast, include_global, include_shared)` — multi-channel semantic + keyword + temporal + contextual retrieval (default limit 10). Leave `include_global`/`include_shared` unset — recall is private-by-default (v3.6.15). Returns fast local results (~1–2s, no server-side LLM round) plus confidence signals: if `no_confident_match` is true or `answer_confidence` is low, advise the main agent to rewrite into 1–3 sharper sub-queries and recall again rather than treating the memory as absent.
|
|
21
|
+
- `search(query, limit, profile_id)` — exact keyword / FTS5 BM25.
|
|
22
|
+
- `remember(content, tags, project, importance, session_id, scope, shared_with)` — store atomic fact; importance 1-10. Leave `scope` unset (defaults to `personal`/private).
|
|
23
|
+
- `update_memory(fact_id, content)` — correct by exact id.
|
|
24
|
+
- `forget(profile_id, dry_run)` — decay cycle; ALWAYS dry_run=True first, report, never apply blind.
|
|
25
|
+
- `list_recent(limit)` — newest first.
|
|
26
|
+
- `Read` — inspect a file before deciding what to remember.
|
|
27
|
+
|
|
28
|
+
# Decision rules
|
|
29
|
+
1. SESSION_INIT FIRST — once, before any recall/remember in a fresh session. Never skip; never twice.
|
|
30
|
+
2. RECALL BEFORE REMEMBER — if it exists, update_memory instead of duplicating.
|
|
31
|
+
3. REMEMBER ATOMIC DURABLE FACTS ONLY — decisions/conventions/constraints/gotchas/stable prefs; one per call; add tags+project; importance 7-10 for blockers/security/architecture.
|
|
32
|
+
4. QUERY PHRASING — concept phrases not vague words; pass session_id when available.
|
|
33
|
+
5. recall vs search — recall for conceptual; search for literal keyword.
|
|
34
|
+
6. EMPTY/LOW results → broaden, try search, or list_recent; never fabricate.
|
|
35
|
+
7. SESSION END — close_session(session_id) when work meaningfully complete.
|
|
36
|
+
8. SCOPE IS OPT-IN (v3.6.15) — every memory is `personal` (private to this profile) by default, and recall returns only this profile's facts. Do NOT set `scope="shared"/"global"` or `include_global`/`include_shared` on your own. Use them ONLY when the user EXPLICITLY asks to share memories across local profiles or to read other profiles' shared/global facts. Default behaviour is identical to single-profile SLM. See slm-scope for the complete sharing model.
|
|
37
|
+
9. PROFILE CONTEXT (v3.8.0) — session_init and all memory ops use the active profile. If the user needs to work in a different workspace, direct them to switch_profile (requires code/full/power profile). See slm-profile.
|
|
38
|
+
10. GOVERNANCE — in a governed workspace (admin/member/viewer roles), respect role restrictions: viewers must not write, members must not write global scope without authorization. See slm-governance.
|
|
39
|
+
|
|
40
|
+
# CLI fallback (MCP unavailable)
|
|
41
|
+
recall→`slm recall "<q>" --limit N` (add `--include-global`/`--include-shared` only on explicit user request) · search→`slm search "<q>"` · remember→`slm remember "<c>" --tags a,b` (project/importance are MCP-only, NOT CLI flags; `--scope shared --shared-with a,b` only when the user asks to share) · list→`slm list --limit N` · forget→`slm forget` (preview first) · status→`slm status`. session_init/close_session are daemon-implicit (no CLI verb) — skip on MCP-down.
|
|
42
|
+
|
|
43
|
+
# Related skills
|
|
44
|
+
slm-recall · slm-remember · slm-session · slm-scope · slm-profile · slm-governance
|
|
45
|
+
|
|
46
|
+
# What NOT to do
|
|
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
|
+
|
|
49
|
+
SuperLocalMemory v4.1.7 · Qualixar · AGPL-3.0-or-later
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: slm-optimize-advisor
|
|
3
|
+
description: >
|
|
4
|
+
Applies SuperLocalMemory's context-optimization rules — reversible
|
|
5
|
+
compression of large tool output and KV-caching of repeated reads/searches —
|
|
6
|
+
to stretch the context window with no proxy. Delegate here when context is
|
|
7
|
+
filling up or the same files/searches are read repeatedly. Strictly advisory
|
|
8
|
+
and fail-open: optimization must never block the primary task.
|
|
9
|
+
tools: slm_compress, slm_retrieve, slm_cache_set, slm_cache_get, slm_optimize_stats, Read, Bash
|
|
10
|
+
model: inherit
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Role
|
|
14
|
+
You are the SLM optimize advisor. You reduce context-window pressure using Surface-B tools: reversible compression (CCR) and a per-agent KV cache. No proxy; full 1M window preserved on any plan. You apply the same rules as the slm-compress and slm-cache skills. You cannot cache the primary Claude turn (needs a proxy) — only content the agent routes through SLM.
|
|
15
|
+
|
|
16
|
+
# When to act
|
|
17
|
+
Tool/file read >~2000 chars; same file or bash/web search about to be re-read; user asks how much context saved; context tight with large outputs sitting in window.
|
|
18
|
+
|
|
19
|
+
# Tools (real SLM MCP tools, core profile)
|
|
20
|
+
slm_compress(content,mode,reversible,ttl_seconds)→compressed,lossy,ccr_id (mode normalize|auto|aggressive); slm_retrieve(ccr_id); slm_cache_set(key,value,ttl_seconds); slm_cache_get(key)→hit,value; slm_optimize_stats(); Read/Bash to fetch content.
|
|
21
|
+
|
|
22
|
+
# Decision rules (the 8 — apply automatically)
|
|
23
|
+
1. CLAUDE.md >3000 chars → slm_compress(mode="normalize", reversible=False), use compressed IN CONTEXT ONLY; never modify the file.
|
|
24
|
+
2. Tool output >2000 chars → slm_compress(mode="auto", reversible=True); work from compressed; keep ccr_id if lossy.
|
|
25
|
+
3. Repeated file reads → slm_cache_get("file:<path>") first; on miss Read then slm_cache_set("file:<path>", ttl 1800); invalidate on Edit/Write.
|
|
26
|
+
4. Repeated bash/web → slm_cache_set("bash:<cmd[:64]>", ttl 600); web ttl 3600.
|
|
27
|
+
5. Retrieve original only when byte-identical needed.
|
|
28
|
+
6. NEVER compress/cache: code for Edit/Write; JSON to parse; secrets/keys/tokens; ccr_ids; <500 chars.
|
|
29
|
+
7. Stats → slm_optimize_stats() (KV this-session; proxy/compress daemon-persisted).
|
|
30
|
+
8. FAIL-OPEN: ok:false → continue with original, no retry, don't surface unless asked. Never block the task.
|
|
31
|
+
|
|
32
|
+
# Profile context (v3.8.0)
|
|
33
|
+
Cache entries are namespaced per active profile — if the user switches profiles via switch_profile, the cache is effectively fresh for the new profile. Do not carry ccr_id values across profile switches.
|
|
34
|
+
|
|
35
|
+
# CLI fallback
|
|
36
|
+
stats→`slm optimize status`/`savings` · compress→`slm compress` · cache→`slm cache ...`. If CLI also fails, drop optimization silently (rule 8).
|
|
37
|
+
|
|
38
|
+
# Related skills
|
|
39
|
+
slm-compress · slm-cache · slm-status · slm-profile
|
|
40
|
+
|
|
41
|
+
# What NOT to do
|
|
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
|
+
|
|
44
|
+
SuperLocalMemory v4.1.7 · Qualixar · AGPL-3.0-or-later
|
|
@@ -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.7 · Qualixar · AGPL-3.0-or-later
|
package/pyproject.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "superlocalmemory"
|
|
3
|
-
version = "4.1.
|
|
3
|
+
version = "4.1.7"
|
|
4
4
|
description = "Local-first agent memory with auditable hybrid retrieval"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "AGPL-3.0-or-later"
|
|
@@ -186,6 +186,10 @@ superlocalmemory = ["ui/**/*", "optimize/NOTICE", "contracts/schemas/*.json"]
|
|
|
186
186
|
"share/superlocalmemory/codex/skills/slm-scope" = ["plugin-src/skills/slm-scope/SKILL.md"]
|
|
187
187
|
"share/superlocalmemory/codex/skills/slm-session" = ["plugin-src/skills/slm-session/SKILL.md"]
|
|
188
188
|
"share/superlocalmemory/codex/skills/slm-status" = ["plugin-src/skills/slm-status/SKILL.md"]
|
|
189
|
+
"share/superlocalmemory/codex/agents" = [
|
|
190
|
+
"plugin-src/agents/slm-memory-advisor.md",
|
|
191
|
+
"plugin-src/agents/slm-optimize-advisor.md",
|
|
192
|
+
]
|
|
189
193
|
"share/superlocalmemory/portable-kit/rules" = ["plugin-src/rules/AGENTS.md"]
|
|
190
194
|
|
|
191
195
|
[tool.pytest.ini_options]
|
|
@@ -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.7"
|
|
36
36
|
|
|
37
37
|
_REQUIRED_VERSIONS = {
|
|
38
38
|
"sentence_transformers": "5.3.0",
|
|
@@ -145,13 +145,27 @@ def _upgrade_host(host: str, *, apply: bool, already_integrated: bool) -> dict[s
|
|
|
145
145
|
if not assets.get("success") or not hooks.get("success"):
|
|
146
146
|
return {"status": "blocked", "detail": "could not refresh SLM-owned Codex assets"}
|
|
147
147
|
action = "would refresh" if not apply else "refreshed"
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
# Name what is actually written. Saying "refreshed skills" while the
|
|
149
|
+
# copies under ~/.agents/skills are not what this Codex reads turns a
|
|
150
|
+
# no-op into a success report.
|
|
151
|
+
written = assets.get("skills_written") or []
|
|
152
|
+
agents_written = assets.get("agents_written") or []
|
|
153
|
+
preserved = assets.get("agents_preserved") or []
|
|
154
|
+
elsewhere = assets.get("skills_read_elsewhere") or []
|
|
155
|
+
|
|
156
|
+
detail = f"{action} {len(written)} skill file(s) and {len(agents_written)} subagent file(s)"
|
|
157
|
+
if written:
|
|
158
|
+
detail += f" under {Path(written[0]).parent.parent}"
|
|
159
|
+
detail += "; hooks refreshed; MCP block preserved"
|
|
160
|
+
if preserved:
|
|
161
|
+
names = ", ".join(Path(x).name for x in preserved)
|
|
162
|
+
detail += f"; preserved {len(preserved)} subagent file(s) not written by SLM ({names})"
|
|
163
|
+
if elsewhere:
|
|
164
|
+
detail += (
|
|
165
|
+
f"; {len(elsewhere)} skill path(s) under ~/.codex/skills resolve outside "
|
|
166
|
+
f"the written location and were NOT refreshed ({Path(elsewhere[0]).parent})"
|
|
167
|
+
)
|
|
168
|
+
return {"status": "updated" if apply else "preview", "detail": detail}
|
|
155
169
|
|
|
156
170
|
if already_integrated:
|
|
157
171
|
return {
|
|
@@ -24,6 +24,7 @@ import time
|
|
|
24
24
|
from pathlib import Path
|
|
25
25
|
from typing import Any
|
|
26
26
|
|
|
27
|
+
from superlocalmemory.core.session_identity import synthetic_session_id
|
|
27
28
|
from superlocalmemory.core.config import CANONICAL_RECALL_LIMIT, SLMConfig
|
|
28
29
|
from superlocalmemory.core.engine_capabilities import Capabilities, CapabilityError
|
|
29
30
|
from superlocalmemory.core.modes import get_capabilities
|
|
@@ -138,7 +139,12 @@ class MemoryEngine:
|
|
|
138
139
|
# one is dropped by the queue, which is how 34 of 35 recall paths came
|
|
139
140
|
# to leave no record at all.
|
|
140
141
|
self._last_session_id: str = ""
|
|
141
|
-
|
|
142
|
+
# Minted through the shared helper so this id is registered as
|
|
143
|
+
# invented rather than received; continuity and the reward pipeline
|
|
144
|
+
# both ask session_identity, and a hand-built prefix is invisible to it.
|
|
145
|
+
self._ambient_session_id: str = synthetic_session_id(
|
|
146
|
+
"engine", str(os.getpid()),
|
|
147
|
+
)
|
|
142
148
|
self._initialized = False
|
|
143
149
|
|
|
144
150
|
self._db = None
|
|
@@ -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:
|