superlocalmemory 4.0.10 → 4.1.2
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 +12 -2
- package/CHANGELOG.md +244 -0
- package/README.md +40 -75
- package/package.json +6 -3
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +4 -4
- 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 +2 -2
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +5 -5
- package/plugin/skills/slm-recall/SKILL.md +102 -15
- package/plugin/skills/slm-remember/SKILL.md +35 -3
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +29 -3
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/rules/AGENTS.md +16 -8
- 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 +2 -2
- package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
- package/plugin-src/skills/slm-profile/SKILL.md +5 -5
- package/plugin-src/skills/slm-recall/SKILL.md +102 -15
- package/plugin-src/skills/slm-remember/SKILL.md +35 -3
- package/plugin-src/skills/slm-scope/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +29 -3
- 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/cli/commands.py +357 -18
- package/src/superlocalmemory/cli/daemon.py +30 -0
- package/src/superlocalmemory/cli/db_migrate.py +71 -1
- package/src/superlocalmemory/cli/gdpr_cmd.py +15 -2
- package/src/superlocalmemory/cli/main.py +24 -2
- package/src/superlocalmemory/code_graph/database.py +44 -0
- package/src/superlocalmemory/compliance/gdpr.py +449 -39
- package/src/superlocalmemory/core/admission.py +231 -11
- package/src/superlocalmemory/core/backend_orchestrator.py +190 -84
- package/src/superlocalmemory/core/config.py +90 -11
- package/src/superlocalmemory/core/consolidation_engine.py +34 -0
- package/src/superlocalmemory/core/engine.py +140 -11
- package/src/superlocalmemory/core/graph_analyzer.py +76 -112
- package/src/superlocalmemory/core/graph_metrics.py +597 -0
- package/src/superlocalmemory/core/graph_pruner.py +121 -0
- package/src/superlocalmemory/core/maintenance_scheduler.py +205 -0
- package/src/superlocalmemory/core/mode_capability.py +111 -0
- package/src/superlocalmemory/core/ollama_validator.py +315 -0
- package/src/superlocalmemory/core/projection_drain.py +380 -0
- package/src/superlocalmemory/core/recall_pipeline.py +390 -3
- package/src/superlocalmemory/core/recall_worker.py +6 -3
- package/src/superlocalmemory/core/scale_autopromote.py +196 -0
- package/src/superlocalmemory/core/scale_engine.py +16 -2
- package/src/superlocalmemory/core/score_contract.py +21 -1
- package/src/superlocalmemory/core/session_identity.py +85 -0
- package/src/superlocalmemory/core/status_contract.py +108 -0
- package/src/superlocalmemory/core/worker_pool.py +4 -4
- package/src/superlocalmemory/core/working_memory.py +288 -0
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +36 -6
- package/src/superlocalmemory/encoding/context_generator.py +1 -1
- package/src/superlocalmemory/encoding/entity_resolver.py +38 -0
- package/src/superlocalmemory/encoding/fact_extractor.py +18 -14
- package/src/superlocalmemory/encoding/prospective_markers.py +262 -0
- package/src/superlocalmemory/encoding/type_router.py +12 -12
- package/src/superlocalmemory/evolution/mutation_generator.py +30 -4
- package/src/superlocalmemory/graph/cozo_adjacency.py +122 -0
- package/src/superlocalmemory/graph/cozo_backend.py +103 -138
- package/src/superlocalmemory/hooks/portable_kit.py +10 -2
- package/src/superlocalmemory/learning/bandit.py +43 -0
- package/src/superlocalmemory/learning/consolidation_worker.py +54 -0
- package/src/superlocalmemory/learning/database.py +60 -3
- package/src/superlocalmemory/learning/entity_compiler.py +21 -58
- package/src/superlocalmemory/learning/feedback.py +3 -1
- package/src/superlocalmemory/learning/outcomes.py +47 -16
- package/src/superlocalmemory/learning/pattern_miner.py +28 -3
- package/src/superlocalmemory/learning/pattern_miner_constants.py +43 -0
- package/src/superlocalmemory/learning/pcos.py +291 -0
- package/src/superlocalmemory/learning/reward_from_outcomes.py +365 -0
- package/src/superlocalmemory/learning/reward_proxy.py +100 -10
- package/src/superlocalmemory/learning/signal_kinds.py +79 -0
- package/src/superlocalmemory/mcp/profiles.py +14 -2
- package/src/superlocalmemory/mcp/tools_active.py +2 -1
- package/src/superlocalmemory/mcp/tools_core.py +31 -3
- package/src/superlocalmemory/mcp/tools_v28.py +20 -1
- package/src/superlocalmemory/parameterization/pattern_extractor.py +14 -1
- package/src/superlocalmemory/parameterization/soft_prompt_generator.py +98 -0
- package/src/superlocalmemory/retrieval/bm25_channel.py +64 -3
- package/src/superlocalmemory/retrieval/channel_status.py +117 -0
- package/src/superlocalmemory/retrieval/engine.py +106 -11
- package/src/superlocalmemory/retrieval/entity_channel.py +210 -256
- package/src/superlocalmemory/retrieval/graph_adjacency.py +219 -0
- package/src/superlocalmemory/retrieval/scope_policy.py +20 -0
- package/src/superlocalmemory/retrieval/semantic_channel.py +47 -5
- package/src/superlocalmemory/retrieval/spreading.py +288 -0
- package/src/superlocalmemory/server/api.py +24 -5
- package/src/superlocalmemory/server/bandit_loops.py +17 -1
- package/src/superlocalmemory/server/rbac_enforce.py +26 -6
- package/src/superlocalmemory/server/recall_health.py +87 -10
- package/src/superlocalmemory/server/recall_serializer.py +9 -0
- package/src/superlocalmemory/server/routes/behavioral.py +75 -10
- package/src/superlocalmemory/server/routes/compliance.py +98 -18
- package/src/superlocalmemory/server/routes/config_api.py +186 -4
- package/src/superlocalmemory/server/routes/evolution.py +178 -0
- package/src/superlocalmemory/server/routes/ingest.py +8 -0
- package/src/superlocalmemory/server/routes/learning_telemetry.py +2 -1
- package/src/superlocalmemory/server/routes/memories.py +49 -7
- package/src/superlocalmemory/server/routes/timeline.py +4 -0
- package/src/superlocalmemory/server/routes/v3_api.py +191 -15
- package/src/superlocalmemory/server/ui.py +20 -4
- package/src/superlocalmemory/server/unified_daemon.py +241 -7
- package/src/superlocalmemory/storage/_migration_internals.py +54 -2
- package/src/superlocalmemory/storage/_schema_version.py +24 -3
- package/src/superlocalmemory/storage/database.py +477 -59
- package/src/superlocalmemory/storage/embedding_codec.py +71 -0
- package/src/superlocalmemory/storage/lineage_retention.py +236 -0
- package/src/superlocalmemory/storage/logical_edges.py +43 -2
- package/src/superlocalmemory/storage/migration_runner.py +119 -0
- package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +60 -36
- package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +127 -0
- package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +158 -0
- package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +620 -0
- package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +306 -0
- package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +207 -0
- package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +201 -0
- package/src/superlocalmemory/storage/migrations.py +18 -2
- package/src/superlocalmemory/storage/models.py +40 -1
- package/src/superlocalmemory/storage/projection_outbox.py +346 -0
- package/src/superlocalmemory/storage/retention_policy.py +860 -0
- package/src/superlocalmemory/storage/schema.py +35 -1
- package/src/superlocalmemory/storage/write_coordinator.py +19 -2
- package/src/superlocalmemory/trust/scorer.py +43 -1
- package/src/superlocalmemory/ui/index.html +9 -18
- package/src/superlocalmemory/ui/js/event-delegation.js +12 -1
- package/src/superlocalmemory/ui/js/od-health.js +28 -6
- package/src/superlocalmemory/ui/js/od-memories.js +19 -0
- package/src/superlocalmemory/ui/js/od-settings.js +87 -1
- package/src/superlocalmemory/ui/js/recall-lab.js +78 -3
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: slm-loop
|
|
3
3
|
description: Run gate-verified bounded loops with SuperLocalMemory as the durable ledger. Use when a task has a checkable acceptance condition (tests, schema, lint, reconciliation) and you must iterate until an INDEPENDENT gate passes — never stopping just because the agent believes it is done. `slm loop demo` runs a keyless convergence demo; `slm loop history` and `slm loop show <run_id>` inspect past runs whose every lap is persisted as queryable SLM memory (tag `loop:<name>`). Terminal statuses are DONE / HALT / PAUSE / KILLED / ERROR — report them exactly, never converting HALT/PAUSE/ERROR into success.
|
|
4
4
|
when_to_use: "run a bounded loop, gate-verified task, iterate until tests pass, verify against an independent gate, don't trust the agent's own done claim, slm loop, convergence loop, loop until green, loop ledger, resume a loop"
|
|
5
|
-
allowed-tools: Bash,
|
|
5
|
+
allowed-tools: Bash, recall
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# slm-loop — Bounded, gate-verified agent loops
|
|
@@ -96,4 +96,4 @@ paused, name the approval needed; when errored, quote the short detail.
|
|
|
96
96
|
|
|
97
97
|
---
|
|
98
98
|
|
|
99
|
-
SuperLocalMemory v4.
|
|
99
|
+
SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later
|
|
@@ -30,10 +30,10 @@ project, a client engagement, a production vs staging environment.
|
|
|
30
30
|
|
|
31
31
|
| Profile | Tools | When to use |
|
|
32
32
|
|---------|-------|-------------|
|
|
33
|
-
| `core` |
|
|
34
|
-
| `code` |
|
|
35
|
-
| `full` |
|
|
36
|
-
| `power` |
|
|
33
|
+
| `core` | 18 tools — remember, recall, search, session, optimize | Minimal footprint, no code tools |
|
|
34
|
+
| `code` | 34 tools — core + portable Brain evidence + code graph + profile switching + bounded loops | Default for IDE/coding agents |
|
|
35
|
+
| `full` | 50 tools — code + all memory ops + mesh + bounded loops | Multi-session, team workflows |
|
|
36
|
+
| `power` | 62 tools — full + governance + behavioral tools | Enterprise, admin, audit use cases |
|
|
37
37
|
| `mesh` | 8 tools — mesh coordination only | Lightweight cross-session signalling |
|
|
38
38
|
|
|
39
39
|
The profile is set at MCP server startup via `SLM_MCP_PROFILE` in the MCP config.
|
|
@@ -146,4 +146,4 @@ Name them differently in your MCP config (e.g. `superlocalmemory-personal` and
|
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
149
|
-
*SuperLocalMemory v4.
|
|
149
|
+
*SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later*
|
|
@@ -50,7 +50,7 @@ recall(
|
|
|
50
50
|
query="authentication strategy decision",
|
|
51
51
|
limit=20, # default 20; reduce to 5 for quick pre-task checks
|
|
52
52
|
session_id="<sid>", # pass the session_id returned by session_init
|
|
53
|
-
fast=
|
|
53
|
+
fast=None, # leave unset; see "Fast mode" below for what it controls
|
|
54
54
|
)
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -65,12 +65,12 @@ Real response shape (`--json` equivalent):
|
|
|
65
65
|
"score": 0.87,
|
|
66
66
|
"confidence": 0.91,
|
|
67
67
|
"trust_score": 0.84,
|
|
68
|
-
"fact_type": "
|
|
68
|
+
"fact_type": "semantic",
|
|
69
69
|
"channel_scores": {
|
|
70
70
|
"semantic": 0.88,
|
|
71
|
-
"
|
|
71
|
+
"bm25": 0.61,
|
|
72
72
|
"temporal": 0.72,
|
|
73
|
-
"
|
|
73
|
+
"hopfield": 0.55
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
],
|
|
@@ -78,32 +78,92 @@ Real response shape (`--json` equivalent):
|
|
|
78
78
|
"query_type": "semantic",
|
|
79
79
|
"channel_weights": {
|
|
80
80
|
"semantic": 0.4,
|
|
81
|
-
"
|
|
81
|
+
"bm25": 0.2,
|
|
82
82
|
"temporal": 0.2,
|
|
83
|
-
"
|
|
83
|
+
"hopfield": 0.2
|
|
84
84
|
},
|
|
85
|
+
"channel_status": {
|
|
86
|
+
"semantic": "ok",
|
|
87
|
+
"bm25": "ok",
|
|
88
|
+
"temporal": "empty",
|
|
89
|
+
"hopfield": "ok",
|
|
90
|
+
"spreading_activation": "no_candidates",
|
|
91
|
+
"entity_graph": "no_embedding",
|
|
92
|
+
"profile": "disabled"
|
|
93
|
+
},
|
|
94
|
+
"incomplete_channels": [],
|
|
85
95
|
"retrieval_time_ms": 134,
|
|
86
96
|
"no_confident_match": false
|
|
87
97
|
}
|
|
88
98
|
```
|
|
89
99
|
|
|
100
|
+
**Read `channel_status` before concluding that nothing is stored.** It reports
|
|
101
|
+
what each retrieval channel did on this query. `channel_weights` says how much
|
|
102
|
+
each channel counts; `channel_status` says whether it ran at all.
|
|
103
|
+
|
|
104
|
+
| status | meaning |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `ok` | the channel ran and contributed candidates |
|
|
107
|
+
| `empty` | it ran and there was genuinely nothing to return |
|
|
108
|
+
| `no_candidates` | it ran but nothing survived fusion |
|
|
109
|
+
| `error` | it raised — **its results are missing from this answer** |
|
|
110
|
+
| `timeout` | it exceeded its guard — **results missing** |
|
|
111
|
+
| `no_embedding` | the query could not be embedded, so it could not run |
|
|
112
|
+
| `disabled` | switched off by configuration |
|
|
113
|
+
| `not_configured` | the backing service is not set up |
|
|
114
|
+
|
|
115
|
+
`semantic`, `bm25`, `temporal`, `hopfield` and `spreading_activation` each
|
|
116
|
+
search and return their own candidates. `profile` is a shortcut that runs before
|
|
117
|
+
them and can answer directly. `entity_graph` produces nothing of its own — it
|
|
118
|
+
re-scores what the others found, by how well each result connects to the
|
|
119
|
+
entities in your question, which is why it reports `no_candidates` when the
|
|
120
|
+
rest come back empty.
|
|
121
|
+
|
|
122
|
+
`empty`, `no_candidates`, `disabled` and `not_configured` are normal. `error`,
|
|
123
|
+
`timeout` and `no_embedding` mean the answer is **incomplete, not negative** —
|
|
124
|
+
say so to the user rather than reporting "no memories found". `incomplete_channels`
|
|
125
|
+
carries the same warning as a plain list.
|
|
126
|
+
|
|
90
127
|
**Refine on low confidence.** `recall` returns confidence signals with every result. If `no_confident_match` is `true` (or `answer_confidence` is low / `abstained` is `true`), do NOT invent a memory — rewrite the query into 1–3 more specific sub-queries (split multi-hop questions; try entity names, synonyms, or broader phrasing) and call `recall` again before concluding nothing was found. A confident match → use it directly. SLM returns fast local results (~1–2s, no server-side LLM round on the hot path) and lets you, the calling model, drive this refinement.
|
|
91
128
|
|
|
92
129
|
### 2. Passing session_id
|
|
93
130
|
|
|
94
|
-
Pass the `session_id` returned by `session_init
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
131
|
+
Pass the `session_id` returned by `session_init`, on **every** recall in that
|
|
132
|
+
session. It does two things.
|
|
133
|
+
|
|
134
|
+
1. **It carries the conversation forward.** Each recall offers its five
|
|
135
|
+
best-ranked results to a small per-session working set of seven slots. A
|
|
136
|
+
memory that keeps coming back is reinforced rather than duplicated, and the
|
|
137
|
+
least-activated slot is the one evicted, so something referenced across
|
|
138
|
+
several turns is hard to lose. Later recalls in the same session rank the
|
|
139
|
+
held memories higher, and turn three is not as cold as turn one. The bias is
|
|
140
|
+
deliberately small — it nudges the order, it never overrides an exact match.
|
|
141
|
+
2. **It attributes engagement to the session**, so a later `report_outcome`
|
|
142
|
+
can close the loop on the right recall.
|
|
143
|
+
|
|
144
|
+
Omitting it costs both: recall still returns correct results, but every turn
|
|
145
|
+
starts cold and no feedback is attributable.
|
|
146
|
+
|
|
147
|
+
**Use the real id, not a made-up one.** An id beginning `http:`, `mcp:`, `cli:`
|
|
148
|
+
or `probe:` is treated as a synthetic per-request label, not a conversation, and
|
|
149
|
+
is excluded from the working set — inventing one per call would otherwise fill
|
|
150
|
+
the registry and evict genuine conversations.
|
|
98
151
|
|
|
99
152
|
### 3. Fast mode
|
|
100
153
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
154
|
+
`fast` controls **one** thing: whether the server runs its own internal LLM
|
|
155
|
+
reformulation round. It does **not** disable any retrieval channel — every
|
|
156
|
+
channel and the reranker run either way. There are four always: meaning,
|
|
157
|
+
keyword, entity graph and time. Spreading activation and Hopfield register as a
|
|
158
|
+
fifth and sixth when their prerequisites are present, so a store sees up to six.
|
|
159
|
+
|
|
160
|
+
Leave it unset. Unset resolves to "skip the internal round", because you are the
|
|
161
|
+
reasoner: you refine the query yourself using the confidence signals above, and
|
|
162
|
+
you do it better than a local model would. Pass `fast=False` only when SLM is
|
|
163
|
+
deployed with no capable client in front of it.
|
|
104
164
|
|
|
105
165
|
```
|
|
106
|
-
recall(query="rate limiting approach", limit=5, session_id="<sid>"
|
|
166
|
+
recall(query="rate limiting approach", limit=5, session_id="<sid>")
|
|
107
167
|
```
|
|
108
168
|
|
|
109
169
|
### 4. Keyword fallback via search
|
|
@@ -138,6 +198,33 @@ once you have the `fact_id` for full content.
|
|
|
138
198
|
|
|
139
199
|
---
|
|
140
200
|
|
|
201
|
+
### 7. Close the loop — say which memories helped
|
|
202
|
+
|
|
203
|
+
Retrieval ranks a memory partly on whether it has actually been useful before.
|
|
204
|
+
That evidence only exists if you supply it.
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
report_outcome(
|
|
208
|
+
memory_ids="f8a2bc91,c31d0f77", # the ids you actually used
|
|
209
|
+
outcome="success", # "success" | "failure" | "partial"
|
|
210
|
+
context="used the JWT expiry decision to write the refresh handler",
|
|
211
|
+
)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Call it when a recall visibly changed what you did: you applied the decision,
|
|
215
|
+
followed the convention, or avoided the gotcha. Report `failure` when a
|
|
216
|
+
confidently-returned memory turned out to be wrong or stale — a negative signal
|
|
217
|
+
is worth as much as a positive one, and it is the only way a stale memory stops
|
|
218
|
+
being promoted.
|
|
219
|
+
|
|
220
|
+
Report only ids you genuinely used. Reporting every returned id marks the
|
|
221
|
+
irrelevant ones useful and trains the ranker toward noise.
|
|
222
|
+
|
|
223
|
+
`report_feedback(fact_id, feedback, query)` is the finer-grained form for a
|
|
224
|
+
single fact and the query that surfaced it.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
141
228
|
## How multi-channel retrieval works
|
|
142
229
|
|
|
143
230
|
`recall` runs multiple candidate producers in parallel — semantic vector similarity,
|
|
@@ -236,4 +323,4 @@ before recalling, then switch back. See `slm-profile` for workspace switching.
|
|
|
236
323
|
|
|
237
324
|
---
|
|
238
325
|
|
|
239
|
-
*SuperLocalMemory v4.
|
|
326
|
+
*SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later*
|
|
@@ -103,8 +103,10 @@ remember(
|
|
|
103
103
|
project: str = "", # project scope, e.g. "superlocalmemory"
|
|
104
104
|
importance: int = 5,# 1–10; see scale below
|
|
105
105
|
session_id: str = "",# from session_init; attributes the write to this session
|
|
106
|
+
session_date: str = "",# when the memory is ABOUT, if not today
|
|
106
107
|
scope: str = None, # v3.6.15 multi-scope: "personal" (default) | "shared" | "global"
|
|
107
108
|
shared_with: str = "",# comma-separated profile_ids for scope="shared"
|
|
109
|
+
idempotency_key: str = "",# replaying the same key will not store a second copy
|
|
108
110
|
)
|
|
109
111
|
```
|
|
110
112
|
|
|
@@ -121,14 +123,44 @@ remember(
|
|
|
121
123
|
|
|
122
124
|
Use 7–10 only for facts that would cause real damage if forgotten.
|
|
123
125
|
|
|
124
|
-
### 4.
|
|
126
|
+
### 4. Date a memory to when it happened
|
|
127
|
+
|
|
128
|
+
`session_date` says **when the memory is about**, as distinct from when you
|
|
129
|
+
wrote it. Omit it and the memory is dated today.
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
remember(
|
|
133
|
+
content="The outage on the payments queue was caused by a stale DNS entry",
|
|
134
|
+
tags="incident,payments,postmortem",
|
|
135
|
+
project="platform",
|
|
136
|
+
session_date="2026-08-14", # YYYY-MM-DD, or a full ISO 8601 timestamp
|
|
137
|
+
session_id="<sid>",
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Use it whenever you are writing something down after the fact — a postmortem, a
|
|
142
|
+
decision taken in a meeting last week, a migration that ran on a known date.
|
|
143
|
+
Time-filtered recall (`window="7d"`, `window="2026-07-01..2026-07-31"`) reads
|
|
144
|
+
event time, so a mis-dated memory is one a time-scoped question cannot find.
|
|
145
|
+
|
|
146
|
+
`session_date` does not change what **kind** of memory it is. A memory that
|
|
147
|
+
describes something planned — "the migration is scheduled for Tuesday", "the
|
|
148
|
+
certificate expires on 2026-09-01" — is stored as a **prospective** memory, and
|
|
149
|
+
recall reports it as `"fact_type": "prospective"`. That is inferred from how the
|
|
150
|
+
content reads, not from the date you pass. Stores written before 4.1.0 spelled
|
|
151
|
+
this type `"temporal"`; that value still reads correctly and needs nothing from
|
|
152
|
+
you.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### 5. One fact per call
|
|
125
157
|
|
|
126
158
|
Store one atomic fact per `remember` call. Do not concatenate multiple unrelated
|
|
127
159
|
points into a single content string — they will be hard to update individually
|
|
128
160
|
and harder to retrieve cleanly. If you have three separate decisions, make three
|
|
129
161
|
calls.
|
|
130
162
|
|
|
131
|
-
###
|
|
163
|
+
### 6. Always set tags and project
|
|
132
164
|
|
|
133
165
|
Untagged, unscoped facts are harder to retrieve and harder to manage. Minimum:
|
|
134
166
|
set `tags` to one or two relevant terms and `project` to the repo/product name.
|
|
@@ -238,4 +270,4 @@ different workspace, use `switch_profile` first. See `slm-profile`.
|
|
|
238
270
|
|
|
239
271
|
---
|
|
240
272
|
|
|
241
|
-
*SuperLocalMemory v4.
|
|
273
|
+
*SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later*
|
|
@@ -121,7 +121,14 @@ remember(content="...", session_id=session_id, tags="auth,decision", project="my
|
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
This attribution is what allows the ranker to learn which recalls led to useful
|
|
124
|
-
outcomes for this project.
|
|
124
|
+
outcomes for this project. It also gives the session a small working set, so
|
|
125
|
+
successive recalls in one conversation build on what the earlier ones surfaced
|
|
126
|
+
instead of each starting cold.
|
|
127
|
+
|
|
128
|
+
**Do not synthesise a session id.** An id beginning `http:`, `mcp:`, `cli:` or
|
|
129
|
+
`probe:` is read as a synthetic per-request label rather than a conversation and
|
|
130
|
+
is deliberately excluded from that working set. Use the one `session_init`
|
|
131
|
+
returned, unchanged, for the whole session.
|
|
125
132
|
|
|
126
133
|
---
|
|
127
134
|
|
|
@@ -177,6 +184,23 @@ never attributed to a project or agent. Over many sessions this compounds:
|
|
|
177
184
|
projects where lifecycle is respected have measurably better retrieval quality
|
|
178
185
|
than projects where session_init is skipped.
|
|
179
186
|
|
|
187
|
+
Within a single session it compounds faster. The session's working set holds the
|
|
188
|
+
memories its recalls have already surfaced, and later recalls rank those higher,
|
|
189
|
+
so a long conversation converges on the material it is actually about.
|
|
190
|
+
|
|
191
|
+
### Closing the loop explicitly
|
|
192
|
+
|
|
193
|
+
Engagement signals say a memory was *shown*. `report_outcome` says it was
|
|
194
|
+
*right*:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
report_outcome(memory_ids="<ids you actually used>", outcome="success")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Send it when a recalled memory changed what you did, and send `failure` when a
|
|
201
|
+
confidently-returned memory turned out to be wrong — that is the only signal
|
|
202
|
+
that stops a stale memory from being promoted. See the `slm-recall` skill.
|
|
203
|
+
|
|
180
204
|
---
|
|
181
205
|
|
|
182
206
|
## CLI fallback (when MCP is unavailable)
|
|
@@ -198,7 +222,9 @@ slm doctor [--json] # preflight check including daemon and embedding worker
|
|
|
198
222
|
| Mistake | Consequence | Fix |
|
|
199
223
|
|---------|-------------|-----|
|
|
200
224
|
| Calling `session_init` twice in one session | Two session IDs; signals split across them | Call once; store the returned ID |
|
|
201
|
-
| Omitting `session_id` from `recall` / `remember` | No learning attribution | Always pass the stored `session_id` |
|
|
225
|
+
| Omitting `session_id` from `recall` / `remember` | No learning attribution, and every turn starts cold | Always pass the stored `session_id` |
|
|
226
|
+
| Inventing a `session_id` such as `mcp:agent` or `http:1234` | Read as synthetic, excluded from the working set | Use the id `session_init` returned |
|
|
227
|
+
| Never reporting an outcome | Ranking cannot tell a useful memory from a merely returned one | `report_outcome` after a recall that changed what you did |
|
|
202
228
|
| Never calling `close_session` | Temporal summaries not written | Call at end of each meaningful work unit |
|
|
203
229
|
| Calling `close_session` without a `session_id` when no prior writes exist | Returns error "No session_id found" | Pass the explicit `session_id` from `session_init` |
|
|
204
230
|
|
|
@@ -227,4 +253,4 @@ explicitly and call `recall` with `include_global`/`include_shared` after
|
|
|
227
253
|
|
|
228
254
|
---
|
|
229
255
|
|
|
230
|
-
*SuperLocalMemory v4.
|
|
256
|
+
*SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later*
|
|
@@ -80,13 +80,17 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
|
|
|
80
80
|
|
|
81
81
|
---
|
|
82
82
|
|
|
83
|
-
## Tool reference (core profile —
|
|
84
|
-
|
|
85
|
-
> The MCP config ships `SLM_MCP_PROFILE=code` and `SLM_AGENT_ID=claude_code` (
|
|
86
|
-
> the
|
|
87
|
-
>
|
|
88
|
-
> `
|
|
89
|
-
>
|
|
83
|
+
## Tool reference (core profile — 18 tools)
|
|
84
|
+
|
|
85
|
+
> The MCP config ships `SLM_MCP_PROFILE=code` and `SLM_AGENT_ID=claude_code` (34 tools):
|
|
86
|
+
> the 18 core tools below **plus** 6 code-graph tools (`build_code_graph`,
|
|
87
|
+
> `get_blast_radius`, `query_graph`, `semantic_search_code`, `get_review_context`,
|
|
88
|
+
> `detect_changes`), 5 portable-evidence tools (`get_brain_evidence_status`,
|
|
89
|
+
> `record_agent_experience`, `record_cognitive_turn`, `finalize_cognitive_turn`,
|
|
90
|
+
> `observe_bounded_loop_evidence`), 3 bounded-loop tools (`slm_loop_run`,
|
|
91
|
+
> `slm_loop_history`, `slm_loop_show`) and 2 usefulness reports (`report_outcome`,
|
|
92
|
+
> `report_feedback`).
|
|
93
|
+
> Use `full` (50 tools) to add mesh coordination. Use `power` (62 tools) for governance
|
|
90
94
|
> and audit tools. See slm-profile for profile switching.
|
|
91
95
|
|
|
92
96
|
| Tool | Signature (key params) | Notes |
|
|
@@ -105,6 +109,10 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
|
|
|
105
109
|
| `slm_cache_set` | `key, value, ttl_seconds=86400` | KV cache set |
|
|
106
110
|
| `slm_cache_get` | `key` | KV cache get; returns hit, value |
|
|
107
111
|
| `slm_optimize_stats` | `()` | Returns compress_runs, tokens_saved_compress, cache_kv_hits |
|
|
112
|
+
| `review_correction` | `case_id, action, expected_version, event_valid_until=None` | Apply, reject or roll back a review-gated correction |
|
|
113
|
+
| `list_corrections` | `limit=100` | Correction cases awaiting review, active profile |
|
|
114
|
+
| `get_memory_summary` | `kind="day", target=""` | Readable summary of a day, project or session |
|
|
115
|
+
| `switch_profile` | `profile_id` | Change the active memory profile; every later call scopes to it |
|
|
108
116
|
|
|
109
117
|
## Skills
|
|
110
118
|
|
|
@@ -129,4 +137,4 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
|
|
|
129
137
|
- **slm-optimize-advisor** — context compression and KV cache
|
|
130
138
|
- **slm-governance-advisor** — scope/role compliance, retention policies, GDPR
|
|
131
139
|
|
|
132
|
-
SuperLocalMemory v4.
|
|
140
|
+
SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: slm-loop
|
|
3
3
|
description: Run gate-verified bounded loops with SuperLocalMemory as the durable ledger. Use when a task has a checkable acceptance condition (tests, schema, lint, reconciliation) and you must iterate until an INDEPENDENT gate passes — never stopping just because the agent believes it is done. `slm loop demo` runs a keyless convergence demo; `slm loop history` and `slm loop show <run_id>` inspect past runs whose every lap is persisted as queryable SLM memory (tag `loop:<name>`). Terminal statuses are DONE / HALT / PAUSE / KILLED / ERROR — report them exactly, never converting HALT/PAUSE/ERROR into success.
|
|
4
4
|
when_to_use: "run a bounded loop, gate-verified task, iterate until tests pass, verify against an independent gate, don't trust the agent's own done claim, slm loop, convergence loop, loop until green, loop ledger, resume a loop"
|
|
5
|
-
allowed-tools: Bash,
|
|
5
|
+
allowed-tools: Bash, recall
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# slm-loop — Bounded, gate-verified agent loops
|
|
@@ -96,4 +96,4 @@ paused, name the approval needed; when errored, quote the short detail.
|
|
|
96
96
|
|
|
97
97
|
---
|
|
98
98
|
|
|
99
|
-
SuperLocalMemory v4.
|
|
99
|
+
SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later
|
|
@@ -30,10 +30,10 @@ project, a client engagement, a production vs staging environment.
|
|
|
30
30
|
|
|
31
31
|
| Profile | Tools | When to use |
|
|
32
32
|
|---------|-------|-------------|
|
|
33
|
-
| `core` |
|
|
34
|
-
| `code` |
|
|
35
|
-
| `full` |
|
|
36
|
-
| `power` |
|
|
33
|
+
| `core` | 18 tools — remember, recall, search, session, optimize | Minimal footprint, no code tools |
|
|
34
|
+
| `code` | 34 tools — core + portable Brain evidence + code graph + profile switching + bounded loops | Default for IDE/coding agents |
|
|
35
|
+
| `full` | 50 tools — code + all memory ops + mesh + bounded loops | Multi-session, team workflows |
|
|
36
|
+
| `power` | 62 tools — full + governance + behavioral tools | Enterprise, admin, audit use cases |
|
|
37
37
|
| `mesh` | 8 tools — mesh coordination only | Lightweight cross-session signalling |
|
|
38
38
|
|
|
39
39
|
The profile is set at MCP server startup via `SLM_MCP_PROFILE` in the MCP config.
|
|
@@ -146,4 +146,4 @@ Name them differently in your MCP config (e.g. `superlocalmemory-personal` and
|
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
149
|
-
*SuperLocalMemory v4.
|
|
149
|
+
*SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later*
|
|
@@ -50,7 +50,7 @@ recall(
|
|
|
50
50
|
query="authentication strategy decision",
|
|
51
51
|
limit=20, # default 20; reduce to 5 for quick pre-task checks
|
|
52
52
|
session_id="<sid>", # pass the session_id returned by session_init
|
|
53
|
-
fast=
|
|
53
|
+
fast=None, # leave unset; see "Fast mode" below for what it controls
|
|
54
54
|
)
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -65,12 +65,12 @@ Real response shape (`--json` equivalent):
|
|
|
65
65
|
"score": 0.87,
|
|
66
66
|
"confidence": 0.91,
|
|
67
67
|
"trust_score": 0.84,
|
|
68
|
-
"fact_type": "
|
|
68
|
+
"fact_type": "semantic",
|
|
69
69
|
"channel_scores": {
|
|
70
70
|
"semantic": 0.88,
|
|
71
|
-
"
|
|
71
|
+
"bm25": 0.61,
|
|
72
72
|
"temporal": 0.72,
|
|
73
|
-
"
|
|
73
|
+
"hopfield": 0.55
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
],
|
|
@@ -78,32 +78,92 @@ Real response shape (`--json` equivalent):
|
|
|
78
78
|
"query_type": "semantic",
|
|
79
79
|
"channel_weights": {
|
|
80
80
|
"semantic": 0.4,
|
|
81
|
-
"
|
|
81
|
+
"bm25": 0.2,
|
|
82
82
|
"temporal": 0.2,
|
|
83
|
-
"
|
|
83
|
+
"hopfield": 0.2
|
|
84
84
|
},
|
|
85
|
+
"channel_status": {
|
|
86
|
+
"semantic": "ok",
|
|
87
|
+
"bm25": "ok",
|
|
88
|
+
"temporal": "empty",
|
|
89
|
+
"hopfield": "ok",
|
|
90
|
+
"spreading_activation": "no_candidates",
|
|
91
|
+
"entity_graph": "no_embedding",
|
|
92
|
+
"profile": "disabled"
|
|
93
|
+
},
|
|
94
|
+
"incomplete_channels": [],
|
|
85
95
|
"retrieval_time_ms": 134,
|
|
86
96
|
"no_confident_match": false
|
|
87
97
|
}
|
|
88
98
|
```
|
|
89
99
|
|
|
100
|
+
**Read `channel_status` before concluding that nothing is stored.** It reports
|
|
101
|
+
what each retrieval channel did on this query. `channel_weights` says how much
|
|
102
|
+
each channel counts; `channel_status` says whether it ran at all.
|
|
103
|
+
|
|
104
|
+
| status | meaning |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `ok` | the channel ran and contributed candidates |
|
|
107
|
+
| `empty` | it ran and there was genuinely nothing to return |
|
|
108
|
+
| `no_candidates` | it ran but nothing survived fusion |
|
|
109
|
+
| `error` | it raised — **its results are missing from this answer** |
|
|
110
|
+
| `timeout` | it exceeded its guard — **results missing** |
|
|
111
|
+
| `no_embedding` | the query could not be embedded, so it could not run |
|
|
112
|
+
| `disabled` | switched off by configuration |
|
|
113
|
+
| `not_configured` | the backing service is not set up |
|
|
114
|
+
|
|
115
|
+
`semantic`, `bm25`, `temporal`, `hopfield` and `spreading_activation` each
|
|
116
|
+
search and return their own candidates. `profile` is a shortcut that runs before
|
|
117
|
+
them and can answer directly. `entity_graph` produces nothing of its own — it
|
|
118
|
+
re-scores what the others found, by how well each result connects to the
|
|
119
|
+
entities in your question, which is why it reports `no_candidates` when the
|
|
120
|
+
rest come back empty.
|
|
121
|
+
|
|
122
|
+
`empty`, `no_candidates`, `disabled` and `not_configured` are normal. `error`,
|
|
123
|
+
`timeout` and `no_embedding` mean the answer is **incomplete, not negative** —
|
|
124
|
+
say so to the user rather than reporting "no memories found". `incomplete_channels`
|
|
125
|
+
carries the same warning as a plain list.
|
|
126
|
+
|
|
90
127
|
**Refine on low confidence.** `recall` returns confidence signals with every result. If `no_confident_match` is `true` (or `answer_confidence` is low / `abstained` is `true`), do NOT invent a memory — rewrite the query into 1–3 more specific sub-queries (split multi-hop questions; try entity names, synonyms, or broader phrasing) and call `recall` again before concluding nothing was found. A confident match → use it directly. SLM returns fast local results (~1–2s, no server-side LLM round on the hot path) and lets you, the calling model, drive this refinement.
|
|
91
128
|
|
|
92
129
|
### 2. Passing session_id
|
|
93
130
|
|
|
94
|
-
Pass the `session_id` returned by `session_init
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
131
|
+
Pass the `session_id` returned by `session_init`, on **every** recall in that
|
|
132
|
+
session. It does two things.
|
|
133
|
+
|
|
134
|
+
1. **It carries the conversation forward.** Each recall offers its five
|
|
135
|
+
best-ranked results to a small per-session working set of seven slots. A
|
|
136
|
+
memory that keeps coming back is reinforced rather than duplicated, and the
|
|
137
|
+
least-activated slot is the one evicted, so something referenced across
|
|
138
|
+
several turns is hard to lose. Later recalls in the same session rank the
|
|
139
|
+
held memories higher, and turn three is not as cold as turn one. The bias is
|
|
140
|
+
deliberately small — it nudges the order, it never overrides an exact match.
|
|
141
|
+
2. **It attributes engagement to the session**, so a later `report_outcome`
|
|
142
|
+
can close the loop on the right recall.
|
|
143
|
+
|
|
144
|
+
Omitting it costs both: recall still returns correct results, but every turn
|
|
145
|
+
starts cold and no feedback is attributable.
|
|
146
|
+
|
|
147
|
+
**Use the real id, not a made-up one.** An id beginning `http:`, `mcp:`, `cli:`
|
|
148
|
+
or `probe:` is treated as a synthetic per-request label, not a conversation, and
|
|
149
|
+
is excluded from the working set — inventing one per call would otherwise fill
|
|
150
|
+
the registry and evict genuine conversations.
|
|
98
151
|
|
|
99
152
|
### 3. Fast mode
|
|
100
153
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
154
|
+
`fast` controls **one** thing: whether the server runs its own internal LLM
|
|
155
|
+
reformulation round. It does **not** disable any retrieval channel — every
|
|
156
|
+
channel and the reranker run either way. There are four always: meaning,
|
|
157
|
+
keyword, entity graph and time. Spreading activation and Hopfield register as a
|
|
158
|
+
fifth and sixth when their prerequisites are present, so a store sees up to six.
|
|
159
|
+
|
|
160
|
+
Leave it unset. Unset resolves to "skip the internal round", because you are the
|
|
161
|
+
reasoner: you refine the query yourself using the confidence signals above, and
|
|
162
|
+
you do it better than a local model would. Pass `fast=False` only when SLM is
|
|
163
|
+
deployed with no capable client in front of it.
|
|
104
164
|
|
|
105
165
|
```
|
|
106
|
-
recall(query="rate limiting approach", limit=5, session_id="<sid>"
|
|
166
|
+
recall(query="rate limiting approach", limit=5, session_id="<sid>")
|
|
107
167
|
```
|
|
108
168
|
|
|
109
169
|
### 4. Keyword fallback via search
|
|
@@ -138,6 +198,33 @@ once you have the `fact_id` for full content.
|
|
|
138
198
|
|
|
139
199
|
---
|
|
140
200
|
|
|
201
|
+
### 7. Close the loop — say which memories helped
|
|
202
|
+
|
|
203
|
+
Retrieval ranks a memory partly on whether it has actually been useful before.
|
|
204
|
+
That evidence only exists if you supply it.
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
report_outcome(
|
|
208
|
+
memory_ids="f8a2bc91,c31d0f77", # the ids you actually used
|
|
209
|
+
outcome="success", # "success" | "failure" | "partial"
|
|
210
|
+
context="used the JWT expiry decision to write the refresh handler",
|
|
211
|
+
)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Call it when a recall visibly changed what you did: you applied the decision,
|
|
215
|
+
followed the convention, or avoided the gotcha. Report `failure` when a
|
|
216
|
+
confidently-returned memory turned out to be wrong or stale — a negative signal
|
|
217
|
+
is worth as much as a positive one, and it is the only way a stale memory stops
|
|
218
|
+
being promoted.
|
|
219
|
+
|
|
220
|
+
Report only ids you genuinely used. Reporting every returned id marks the
|
|
221
|
+
irrelevant ones useful and trains the ranker toward noise.
|
|
222
|
+
|
|
223
|
+
`report_feedback(fact_id, feedback, query)` is the finer-grained form for a
|
|
224
|
+
single fact and the query that surfaced it.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
141
228
|
## How multi-channel retrieval works
|
|
142
229
|
|
|
143
230
|
`recall` runs multiple candidate producers in parallel — semantic vector similarity,
|
|
@@ -236,4 +323,4 @@ before recalling, then switch back. See `slm-profile` for workspace switching.
|
|
|
236
323
|
|
|
237
324
|
---
|
|
238
325
|
|
|
239
|
-
*SuperLocalMemory v4.
|
|
326
|
+
*SuperLocalMemory v4.1.2 · Qualixar · AGPL-3.0-or-later*
|