@joshuaswarren/openclaw-engram 8.0.1 → 8.0.3

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 CHANGED
@@ -2,346 +2,21 @@
2
2
 
3
3
  A local-first memory plugin for [OpenClaw](https://github.com/openclaw/openclaw) that gives AI agents persistent, searchable long-term memory across conversations.
4
4
 
5
- Engram uses **LLM-powered extraction** (OpenAI Responses API) to intelligently identify what's worth remembering from each conversation, stores memories as plain **markdown files** on disk, and retrieves relevant context via **[QMD](https://github.com/tobi/qmd)** hybrid search (BM25 + vector + reranking).
5
+ Engram uses **LLM-powered extraction** to identify what's worth remembering, stores memories as plain **markdown files** on disk, and retrieves relevant context via **[QMD](https://github.com/tobi/qmd)** hybrid search (BM25 + vector + reranking).
6
6
 
7
- ## Why Engram?
8
-
9
- Most AI memory systems are either too noisy (store everything) or too lossy (store nothing useful). Engram takes a different approach:
10
-
11
- - **Signal detection first** -- A fast local regex scan classifies each turn before any API call happens. High-signal turns (corrections, preferences, identity statements) trigger immediate extraction; low-signal turns are batched.
12
- - **Structured extraction** -- An LLM analyzes buffered turns and extracts typed memories (facts, preferences, corrections, entities, decisions, relationships, principles, commitments, moments, skills) with confidence scores.
13
- - **Automatic consolidation** -- Periodic consolidation passes merge duplicates, update entity profiles, refresh the behavioral profile, and expire stale memories.
14
- - **Local-first storage** -- All memories are plain markdown files with YAML frontmatter. No database, no vendor lock-in. Grep them, version them, back them up however you like.
15
- - **Privacy by default** -- Memories never leave your machine unless you choose to sync them. The LLM extraction call is the only external API call.
16
-
17
- ## Features
18
-
19
- ### Core Features
20
- - **10 memory categories**: fact, preference, correction, entity, decision, relationship, principle, commitment, moment, skill
21
- - **Confidence tiers**: explicit (0.95-1.0), implied (0.70-0.94), inferred (0.40-0.69), speculative (0.00-0.39)
22
- - **TTL on speculative memories**: Auto-expire after 30 days if unconfirmed
23
- - **Lineage tracking**: Memories track their parent IDs through consolidation merges and updates
24
- - **Entity profiles**: Accumulates facts about people, projects, tools, and companies into per-entity files, with automatic name normalization and periodic deduplication
25
- - **Behavioral profile**: A living `profile.md` that evolves as the system learns about the user, with automatic cap and pruning to control token usage
26
- - **Identity reflection**: Optional self-reflection that helps the agent improve over sessions
27
- - **Question generation**: Generates 1-3 curiosity questions per extraction to drive deeper engagement
28
- - **Commitment lifecycle**: Tracks promises and deadlines with configurable decay (default 90 days)
29
- - **Auto-consolidation**: IDENTITY.md reflections are automatically summarized when they exceed 8KB
30
- - **Smart buffer**: Configurable trigger logic (signal-based, turn count, or time-based)
31
- - **QMD integration**: Hybrid search with BM25, vector embeddings, and reranking
32
- - **Graceful degradation**: Works without QMD (falls back to direct file reads) and without an API key (retrieval-only mode)
33
- - **Portability**: Import/export/backup your memory store via CLI (v2.3)
34
- - **CLI**: Search, inspect, and manage memories from the command line
35
- - **Agent tools**: `memory_search`, `memory_store`, `memory_profile`, `memory_entities`, `memory_promote`
36
-
37
- ### v1.2.0 Advanced Features
38
-
39
- All advanced features are **disabled by default** for gradual adoption. Enable them in your config as needed.
40
-
41
- #### Importance Scoring (Zero-LLM)
42
- - **Local heuristic scoring** at extraction time — no API calls
43
- - Five tiers: `critical` (0.9-1.0), `high` (0.7-0.9), `normal` (0.4-0.7), `low` (0.2-0.4), `trivial` (0.0-0.2)
44
- - Scores based on: explicit importance markers, personal info, instructions, emotional content, factual density
45
- - Extracts salient keywords for improved search relevance
46
- - Used for **ranking** (not exclusion) — all memories are still stored and searchable
47
-
48
- #### Access Tracking
49
- - Tracks `accessCount` and `lastAccessed` for each memory
50
- - Batched updates during consolidation (zero retrieval latency impact)
51
- - Enables "working set" prioritization — frequently accessed memories surface higher
52
- - CLI: `openclaw engram access` to view most accessed memories
53
-
54
- #### Recency Boosting
55
- - Recent memories ranked higher in search results
56
- - Configurable weight (0-1, default 0.2)
57
- - Exponential decay with 7-day half-life
58
-
59
- #### Automatic Chunking
60
- - Sentence-boundary splitting for long memories (>150 tokens)
61
- - Target ~200 tokens per chunk with 2-sentence overlap
62
- - Each chunk maintains `parentId` and `chunkIndex` for context reconstruction
63
- - Preserves coherent thoughts — never splits mid-sentence
64
-
65
- #### Contradiction Detection
66
- - QMD similarity search finds candidate conflicts (fast, cheap)
67
- - LLM verification confirms actual contradictions (prevents false positives)
68
- - Auto-resolve when confidence > 0.9
69
- - Full audit trail: old memory marked `status: superseded` with `supersededBy` link
70
- - Nothing is deleted — superseded memories remain searchable explicitly
71
-
72
- #### Memory Linking (Knowledge Graph)
73
- - Typed relationships: `follows`, `references`, `contradicts`, `supports`, `related`
74
- - LLM suggests links during extraction based on semantic connections
75
- - Links stored in frontmatter with strength scores (0-1)
76
- - Enables graph traversal between related memories
77
-
78
- #### Conversation Threading
79
- - Auto-detect thread boundaries (session change or 30-minute gap)
80
- - Auto-generate thread titles from top TF-IDF keywords
81
- - Group memories into conversation threads for context reconstruction
82
- - CLI: `openclaw engram threads` to view threads
83
-
84
- #### Memory Summarization
85
- - Triggered when memory count exceeds threshold (default 1000)
86
- - Compresses old, low-importance, unprotected memories into summaries
87
- - **Archive, not delete** — source memories marked `status: archived`, still searchable
88
- - Protected: recent memories, high-importance, entities, commitments/preferences/decisions
89
- - Summaries stored in `summaries/` directory
90
-
91
- #### Topic Extraction
92
- - TF-IDF analysis of the entire memory corpus
93
- - Extracts top N topics (default 50) during consolidation
94
- - Stored in `state/topics.json`
95
- - CLI: `openclaw engram topics` to view extracted topics
96
-
97
- ### v2.2 Advanced Retrieval
98
-
99
- All v2.2 retrieval features are **disabled by default**. Enable them only if you can tolerate a small latency increase.
100
-
101
- - **Heuristic query expansion** (`queryExpansionEnabled`): Runs a few deterministic, cheap expanded queries (no LLM calls) and merges results.
102
- - **LLM re-ranking** (`rerankEnabled`): Re-scores the top N retrieved memories using a short, timeboxed request.
103
- - Default mode: **local-only** (`rerankProvider: "local"`), fail-open on errors/timeouts.
104
- - **Note:** If QMD is enabled (`qmdEnabled: true`), QMD's `query` command already includes built-in reranking via its bundled reranker model. Enabling `rerankEnabled` on top of QMD results in **redundant double reranking**, which adds latency for marginal quality gain. **Recommendation: keep `rerankEnabled: false` when using QMD.**
105
- - **Feedback loop** (`feedbackEnabled` + `memory_feedback` tool): Store thumbs up/down locally and apply it as a small ranking bias.
106
- - **Negative examples** (`negativeExamplesEnabled` + `memory_feedback_last_recall` tool): Track retrieved-but-not-useful memories and apply a small ranking penalty.
107
- - **Slow query log** (`slowLogEnabled` + `slowLogThresholdMs`): Logs durations and metadata (never content) for local LLM and QMD operations.
108
-
109
- ### v2.3 Import / Export / Backup
110
-
111
- Engram supports **portable exports** and **safe backups** via CLI:
112
-
113
- ```bash
114
- openclaw engram export --format json --out /tmp/engram-export
115
- openclaw engram export --format sqlite --out /tmp/engram.sqlite
116
- openclaw engram export --format md --out /tmp/engram-md
117
-
118
- openclaw engram import --from /tmp/engram-export --format auto
119
- openclaw engram backup --out-dir /tmp/engram-backups --retention-days 14
120
- ```
121
-
122
- If namespaces are enabled (v3.0+), the CLI accepts `--namespace <ns>` for export/import/backup.
123
-
124
- Details: `docs/import-export.md`
125
-
126
- ### v2.4 Context Retention Hardening
127
-
128
- - **Extended hourly summaries** (structured topics/decisions/action items/rejections) are optional:
129
- - Config: `hourlySummariesExtendedEnabled`, `hourlySummariesIncludeToolStats`
130
- - **Conversation semantic recall hook** (optional): index transcript chunks and inject top-K relevant past chunks:
131
- - Config: `conversationIndexEnabled`, `conversationIndexQmdCollection`, `conversationRecallTopK`, `conversationIndexMinUpdateIntervalMs`, `conversationIndexEmbedOnUpdate`
132
- - Tool: `conversation_index_update` (optional `embed: true` override)
133
-
134
- Details: `docs/context-retention.md`
135
-
136
- ### v3.0 Namespaces (Multi-Agent Memory)
137
-
138
- Optional namespaces let multiple agents share a memory store with isolation:
139
-
140
- - Config: `namespacesEnabled`, `defaultNamespace`, `sharedNamespace`, `namespacePolicies`
141
- - Tooling: `memory_store` supports `namespace`; `memory_promote` copies curated items into the shared namespace.
142
-
143
- Details: `docs/namespaces.md`
144
-
145
- ### v4.0 Shared Context (Cross-Agent Shared Intelligence)
146
-
147
- Optional shared-context is a **file-based shared brain** (priorities, agent outputs, feedback, roundtables):
148
-
149
- - Config: `sharedContextEnabled`, `sharedContextDir`, `sharedContextMaxInjectChars`
150
- - Tools: `shared_context_write_output`, `shared_priorities_append`, `shared_feedback_record`, `shared_context_curate_daily`
151
-
152
- Details: `docs/shared-context.md`
153
-
154
- ### v5.0 Compounding Engine
155
-
156
- Optional compounding turns shared feedback into persistent learning:
157
-
158
- - Writes: `memoryDir/compounding/weekly/<YYYY-Www>.md`, `memoryDir/compounding/mistakes.json`
159
- - Tool: `compounding_weekly_synthesize`
160
- - Injection: `compoundingInjectEnabled` (default true when compounding is enabled)
161
-
162
- Details: `docs/compounding.md`
163
-
164
- ### v6.0 Fact Deduplication & Archival
165
-
166
- Two features to keep the memory store lean and fast as it grows:
167
-
168
- #### Content-Hash Deduplication
169
-
170
- Prevents storing semantically identical facts. Before writing any new fact, Engram computes a normalized SHA-256 hash of the content (lowercase, strip punctuation, collapse whitespace) and checks it against a persistent index. Duplicates are silently skipped.
171
-
172
- - **Zero false positives** — exact content match only (after normalization)
173
- - **Persistent index** — stored as `state/fact-hashes.txt`, survives restarts
174
- - **Seeding** — on first enable, the index auto-loads from existing facts on disk
175
- - Config: `factDeduplicationEnabled` (default `true`)
176
-
177
- #### Fact Archival
178
-
179
- Automatically moves old, low-importance, rarely-accessed facts out of the hot search index into an `archive/` directory. Archived facts are still on disk but excluded from QMD queries, keeping retrieval fast.
180
-
181
- Archival runs during the periodic consolidation pass. A fact is archived when **all** of these are true:
182
- - Age exceeds `factArchivalAgeDays` (default 90)
183
- - Importance score is below `factArchivalMaxImportance` (default 0.3)
184
- - Access count is at or below `factArchivalMaxAccessCount` (default 2)
185
- - Category is not in `factArchivalProtectedCategories` (default: commitment, preference, decision, principle)
186
- - Status is `active` (not already superseded/archived)
187
- - Not a correction memory
188
-
189
- Config: `factArchivalEnabled` (default `false`), plus the threshold settings above.
190
-
191
- ## Architecture
192
-
193
- ```
194
- Conversation turn arrives
195
- |
196
- v
197
- Signal scan (local regex, <10ms, free)
198
- |
199
- v
200
- Append to smart buffer
201
- |
202
- v
203
- Trigger check:
204
- HIGH signal? --> Extract NOW (single LLM call)
205
- Buffer >= N? --> Extract BATCH
206
- Time > T? --> Extract BATCH
207
- else --> Keep buffering
208
- |
209
- v
210
- If extracted: content-hash dedup check (skip duplicates)
211
- |
212
- v
213
- Write new markdown files to disk
214
- |
215
- v
216
- Every Nth extraction: Consolidation pass
217
- - Merge/dedup memories
218
- - Merge fragmented entity files
219
- - Update entity profiles
220
- - Update behavioral profile (with cap enforcement)
221
- - Clean expired commitments and TTL memories
222
- - Archive old, low-importance facts (v6.0)
223
- - Auto-consolidate identity reflections
224
- |
225
- v
226
- Background: qmd update (re-index new files)
227
- ```
228
-
229
- Performance note for conversation indexing:
230
- - `conversation_index_update` now runs `qmd update` only by default.
231
- - `qmd embed` is optional (`conversationIndexEmbedOnUpdate: true` or tool param `embed: true`).
232
- - Re-indexing is min-interval gated per session (`conversationIndexMinUpdateIntervalMs`, default 15m).
233
-
234
- ### Retrieval Flow
235
-
236
- ```
237
- Agent session starts
238
- |
239
- v
240
- Read profile.md directly (free, instant)
241
- |
242
- v
243
- QMD search memory collection (relevant memories)
244
- |
245
- v
246
- QMD search global collections (workspace context)
247
- |
248
- v
249
- Optionally inject highest-priority open question
250
- |
251
- v
252
- Combine and inject into system prompt
253
- ```
254
-
255
- ## Hourly Summaries (Cron)
256
-
257
- Engram can generate **hourly summaries** of conversation activity, written to disk under the configured `memoryDir` summaries folder.
258
-
259
- In most installs, the safest setup is to drive this via OpenClaw cron using an **agent turn** (not a tool call directly):
260
- - `sessionTarget: "isolated"`
261
- - `payload.kind: "agentTurn"` that calls `memory_summarize_hourly`
262
- - `delivery.mode: "none"` (so it never posts to Discord)
263
-
264
- Why: some OpenClaw installations restrict `sessionTarget: "main"` to `payload.kind: "systemEvent"` only. If you configure `main` + `toolCall`, it may be repeatedly skipped and summaries will silently stop.
265
-
266
- ## Storage Layout
267
-
268
- All memories are stored as markdown files with YAML frontmatter:
269
-
270
- ```
271
- ~/.openclaw/workspace/memory/local/
272
- ├── profile.md # Living behavioral profile (auto-updated)
273
- ├── entities/ # One markdown file per tracked entity
274
- │ ├── person-jane-doe.md
275
- │ ├── project-my-app.md
276
- │ └── tool-qmd.md
277
- ├── facts/ # Memory entries organized by date
278
- │ └── YYYY-MM-DD/
279
- │ ├── fact-1738789200000-a1b2.md
280
- │ └── preference-1738789200000-c3d4.md
281
- ├── corrections/ # High-weight correction memories
282
- │ └── correction-1738789200000-e5f6.md
283
- ├── archive/ # Archived low-value facts (v6.0)
284
- │ └── YYYY-MM-DD/
285
- │ └── fact-1738789200000-a1b2.md
286
- ├── questions/ # Generated curiosity questions
287
- │ └── q-m1abc-xy.md
288
- ├── threads/ # Conversation threads (v1.2.0)
289
- │ └── thread-1738789200000-a1b2.json
290
- ├── summaries/ # Memory summaries (v1.2.0)
291
- │ └── summary-1738789200000-a1b2.json
292
- ├── config/
293
- │ └── aliases.json # Entity name aliases
294
- └── state/
295
- ├── buffer.json # Current unbatched turns (survives restarts)
296
- ├── meta.json # Extraction count, timestamps, totals
297
- ├── topics.json # Extracted topics (v1.2.0)
298
- └── fact-hashes.txt # Content-hash dedup index (v6.0)
299
- ```
300
-
301
- ### Memory File Format
302
-
303
- Each memory file uses YAML frontmatter:
304
-
305
- ```yaml
306
- ---
307
- id: fact-1738789200000-a1b2
308
- category: fact
309
- created: 2026-02-05T12:00:00.000Z
310
- updated: 2026-02-05T12:00:00.000Z
311
- source: extraction
312
- confidence: 0.85
313
- confidenceTier: implied
314
- tags: ["tools", "preferences"]
315
- entityRef: tool-qmd
316
- ---
317
-
318
- QMD supports hybrid search combining BM25 and vector embeddings with reranking.
319
- ```
320
-
321
- ## Installation
322
-
323
- ### Prerequisites
324
-
325
- - [OpenClaw](https://github.com/openclaw/openclaw) gateway
326
- - An OpenAI API key (for extraction; retrieval works without one)
327
- - [QMD](https://github.com/tobi/qmd) (optional, for hybrid search)
328
-
329
- ### Quick Start (Recommended: npm via OpenClaw)
7
+ ## Quick Install
330
8
 
331
9
  ```bash
332
- # Install from npm (records install provenance in openclaw.json.plugins.installs)
333
10
  openclaw plugins install @joshuaswarren/openclaw-engram --pin
334
11
  ```
335
12
 
336
- Then enable and configure in `openclaw.json`:
13
+ Enable in `openclaw.json`:
337
14
 
338
15
  ```jsonc
339
16
  {
340
17
  "plugins": {
341
18
  "allow": ["openclaw-engram"],
342
- "slots": {
343
- "memory": "openclaw-engram"
344
- },
19
+ "slots": { "memory": "openclaw-engram" },
345
20
  "entries": {
346
21
  "openclaw-engram": {
347
22
  "enabled": true,
@@ -354,514 +29,66 @@ Then enable and configure in `openclaw.json`:
354
29
  }
355
30
  ```
356
31
 
357
- Reload the gateway:
358
-
359
- ```bash
360
- kill -USR1 $(pgrep openclaw-gateway)
361
- ```
362
-
363
- ### Developer Install (from Git)
364
-
365
- Use this only if you are actively developing the plugin.
366
-
367
- ```bash
368
- # Clone into the OpenClaw extensions directory
369
- git clone https://github.com/joshuaswarren/openclaw-engram.git \
370
- ~/.openclaw/extensions/openclaw-engram
371
-
372
- # Install dependencies and build
373
- cd ~/.openclaw/extensions/openclaw-engram
374
- npm ci
375
- npm run build
376
- ```
377
-
378
- ### Set Up QMD Collection (Optional)
379
-
380
- If you have QMD installed, add a collection pointing at the memory directory. Add to `~/.config/qmd/index.yml`:
381
-
382
- ```yaml
383
- openclaw-engram:
384
- path: ~/.openclaw/workspace/memory/local
385
- extensions: [.md]
386
- ```
387
-
388
- Then index:
389
-
390
- ```bash
391
- qmd update && qmd embed
392
- ```
393
-
394
- ### Recommended QMD Patches (as of 2026-02-14)
395
-
396
- The following upstream QMD pull requests contain important performance and stability fixes that have not yet been merged. We recommend applying them locally to your QMD installation at `~/.bun/install/global/node_modules/qmd/`:
397
-
398
- 1. **[PR #166](https://github.com/tobi/qmd/pull/166) — HTTP daemon crash fix** (fixes [#163](https://github.com/tobi/qmd/issues/163))
399
- - The HTTP daemon (`qmd mcp --http --daemon`) crashes on the second MCP request due to transport reuse.
400
- - **Fix**: In `src/mcp.ts`, add `sessionIdGenerator: () => crypto.randomUUID()` to the `WebStandardStreamableHTTPServerTransport` constructor.
401
- - Without this fix, the daemon is unusable for sequential requests.
402
-
403
- 2. **[PR #112](https://github.com/tobi/qmd/pull/112) — Model override environment variables**
404
- - Adds `QMD_EMBED_MODEL`, `QMD_GENERATE_MODEL`, `QMD_RERANK_MODEL`, and `QMD_MODEL_CACHE_DIR` env vars.
405
- - Allows swapping in smaller/faster models at runtime (e.g., Jina Reranker v1-tiny for 185x faster cold-start reranking).
406
- - **Fix**: In `src/llm.ts`, change the `LlamaCpp` constructor to check `process.env.QMD_*` vars as fallback between config and defaults.
407
-
408
- 3. **[PR #117](https://github.com/tobi/qmd/pull/117) — SQLite pathological join fix**
409
- - SQLite may choose a disastrous join order for FTS queries with collection filters, making `qmd search -c <collection>` extremely slow on large indexes.
410
- - **Fix**: In `src/store.ts`, change `JOIN` to `CROSS JOIN` in `searchFTS()` and move join predicates into the `WHERE` clause to preserve left-to-right evaluation order starting from the FTS MATCH.
411
- - Particularly important for large collections (90K+ files like the engram memory store).
412
-
413
- Check [tobi/qmd](https://github.com/tobi/qmd) periodically — once these PRs are merged upstream, a simple `bun install -g github:tobi/qmd` will include them and these local patches can be removed.
414
-
415
- ### Restart the Gateway
32
+ Reload:
416
33
 
417
34
  ```bash
418
35
  kill -USR1 $(pgrep openclaw-gateway)
419
36
  ```
420
37
 
421
- Check the logs to confirm:
422
-
423
- ```bash
424
- tail -f ~/.openclaw/logs/gateway.log
425
- # Should see: [gateway] openclaw-engram: started
426
- ```
427
-
428
- ## Configuration
429
-
430
- All settings are defined in `openclaw.json` under `plugins.entries.openclaw-engram.config`:
431
-
432
- For a full v2.3-v5 setup (including cron and QMD conversation-index collections) and tuning guidance, see:
433
- - `docs/README.md` (docs map, v8 reorg entrypoint)
434
- - `docs/setup-config-tuning.md`
435
- - `docs/import-export.md`
436
- - `docs/context-retention.md`
437
- - `docs/namespaces.md`
438
- - `docs/shared-context.md`
439
- - `docs/compounding.md`
440
-
441
- Bootstrap config path override (for service environments) can be set via env var:
442
- - `OPENCLAW_ENGRAM_CONFIG_PATH=/absolute/path/to/openclaw.json`
443
- - Fallback: `OPENCLAW_CONFIG_PATH`
444
-
445
- ### Core Settings
446
-
447
- | Setting | Default | Description |
448
- |---------|---------|-------------|
449
- | `openaiApiKey` | `(env fallback)` | OpenAI API key or `${ENV_VAR}` reference |
450
- | `model` | `gpt-5.2` | OpenAI model for extraction/consolidation |
451
- | `reasoningEffort` | `low` | Reasoning effort: `none`, `low`, `medium`, `high` |
452
- | `memoryDir` | `~/.openclaw/workspace/memory/local` | Memory storage directory |
453
- | `workspaceDir` | `~/.openclaw/workspace` | Workspace directory (for IDENTITY.md) |
454
- | `debug` | `false` | Enable debug logging |
455
-
456
- ### File Hygiene (Memory File Limits / Truncation Risk)
457
-
458
- OpenClaw may bootstrap workspace markdown files (for example `IDENTITY.md`, `MEMORY.md`) into the prompt on every message.
459
- If those files become large, they can be silently truncated by the gateway's bootstrap budget, which causes "memory loss" without an explicit error.
460
-
461
- Engram can optionally:
462
- - Lint selected workspace files and warn when they are approaching a configured size budget.
463
- - Rotate oversized markdown files into an archive directory, replacing the original with a lean index plus a small tail excerpt for continuity.
464
-
465
- This is **off by default** because it can modify workspace files.
466
-
467
- Example config:
468
-
469
- ```json
470
- {
471
- "fileHygiene": {
472
- "enabled": true,
473
- "lintEnabled": true,
474
- "lintPaths": ["IDENTITY.md", "MEMORY.md"],
475
- "lintBudgetBytes": 20000,
476
- "lintWarnRatio": 0.8,
477
- "rotateEnabled": true,
478
- "rotatePaths": ["IDENTITY.md"],
479
- "rotateMaxBytes": 18000,
480
- "rotateKeepTailChars": 2000,
481
- "archiveDir": ".engram-archive",
482
- "runMinIntervalMs": 300000,
483
- "warningsLogEnabled": false
484
- }
485
- }
486
- ```
487
-
488
- ### Buffer & Trigger Settings
489
-
490
- | Setting | Default | Description |
491
- |---------|---------|-------------|
492
- | `triggerMode` | `smart` | `smart`, `every_n`, or `time_based` |
493
- | `bufferMaxTurns` | `5` | Max buffered turns before forced extraction |
494
- | `bufferMaxMinutes` | `15` | Max minutes before forced extraction |
495
- | `highSignalPatterns` | `[]` | Custom regex patterns for immediate extraction |
496
- | `consolidateEveryN` | `3` | Run consolidation every N extractions |
497
-
498
- ### Retrieval Settings
499
-
500
- | Setting | Default | Description |
501
- |---------|---------|-------------|
502
- | `maxMemoryTokens` | `2000` | Max tokens injected into system prompt |
503
- | `qmdEnabled` | `true` | Use QMD for hybrid search |
504
- | `qmdCollection` | `openclaw-engram` | QMD collection name |
505
- | `qmdMaxResults` | `8` | Max QMD results per search |
506
- | `qmdPath` | `(auto)` | Optional absolute path to `qmd` binary (bypasses PATH discovery) |
507
-
508
- ### v8.0 Phase 1 (Experimental, Token-Budget Focused)
509
-
510
- All options below are safe to leave disabled initially; enable incrementally.
511
-
512
- | Setting | Default | Description |
513
- |---------|---------|-------------|
514
- | `recallPlannerEnabled` | `true` | Lightweight retrieve-vs-think gating (`no_recall`/`minimal`/`full`/`graph_mode`) |
515
- | `recallPlannerMaxQmdResultsMinimal` | `4` | QMD cap when planner selects `minimal` |
516
- | `intentRoutingEnabled` | `false` | Write intent metadata (goal/action/entityTypes) and boost compatible recalls |
517
- | `intentRoutingBoost` | `0.12` | Maximum additive score boost from intent compatibility |
518
- | `verbatimArtifactsEnabled` | `false` | Persist quote-first artifact anchors for high-confidence extracted memories |
519
- | `verbatimArtifactsMinConfidence` | `0.8` | Minimum extraction confidence for artifact writes |
520
- | `verbatimArtifactsMaxRecall` | `5` | Maximum artifact anchors injected per recall |
521
- | `verbatimArtifactCategories` | `["decision","correction","principle","commitment"]` | Categories eligible for artifact extraction |
522
-
523
- ### Local / OpenAI-Compatible Endpoint Settings
524
-
525
- | Setting | Default | Description |
526
- |---------|---------|-------------|
527
- | `localLlmEnabled` | `false` | Enable local/compatible endpoint for extraction + consolidation |
528
- | `localLlmUrl` | `http://localhost:1234/v1` | Base URL for OpenAI-compatible endpoint |
529
- | `localLlmModel` | `local-model` | Model ID to use on the endpoint |
530
- | `localLlmApiKey` | `(unset)` | Optional API key for authenticated endpoints |
531
- | `localLlmHeaders` | `(unset)` | Optional extra headers (for proxy/provider-specific auth/routing) |
532
- | `localLlmAuthHeader` | `true` | Send `Authorization: Bearer <localLlmApiKey>` when key is set |
533
- | `localLlmFallback` | `true` | Fall back to gateway model chain when local endpoint fails |
534
-
535
- Example (`openclaw.json` plugin config):
536
-
537
- ```json
538
- {
539
- "localLlmEnabled": true,
540
- "localLlmUrl": "https://your-openai-compatible-endpoint.example/v1",
541
- "localLlmModel": "your-model-id",
542
- "localLlmApiKey": "${YOUR_ENDPOINT_API_KEY}",
543
- "localLlmHeaders": {
544
- "X-Provider-Routing": "engram-extraction"
545
- },
546
- "localLlmAuthHeader": true,
547
- "localLlmFallback": true
548
- }
549
- ```
550
-
551
- ### V2 Feature Settings
552
-
553
- | Setting | Default | Description |
554
- |---------|---------|-------------|
555
- | `identityEnabled` | `true` | Enable agent identity reflections |
556
- | `injectQuestions` | `false` | Inject open questions into the system prompt |
557
- | `commitmentDecayDays` | `90` | Days before fulfilled/expired commitments are removed |
558
-
559
- ### v2.2 Advanced Retrieval Settings
560
-
561
- See `docs/advanced-retrieval.md` for details and recommended safe defaults.
562
-
563
- | Setting | Default | Description |
564
- |---------|---------|-------------|
565
- | `queryExpansionEnabled` | `false` | Heuristic query expansion (no LLM calls) |
566
- | `queryExpansionMaxQueries` | `4` | Max expanded queries (including original) |
567
- | `queryExpansionMinTokenLen` | `3` | Minimum token length for expansion |
568
- | `rerankEnabled` | `false` | Enable LLM re-ranking (timeboxed; fail-open) |
569
- | `rerankProvider` | `local` | `local` (no cloud calls). `cloud` is reserved/experimental (no-op in v2.2.0). |
570
- | `rerankMaxCandidates` | `20` | Max candidates sent to re-ranker |
571
- | `rerankTimeoutMs` | `8000` | Rerank timeout (ms) |
572
- | `rerankCacheEnabled` | `true` | Cache reranks in-memory |
573
- | `rerankCacheTtlMs` | `3600000` | Rerank cache TTL (ms) |
574
- | `feedbackEnabled` | `false` | Enable `memory_feedback` tool and ranking bias |
575
- | `negativeExamplesEnabled` | `false` | Enable negative examples + ranking penalty (opt-in) |
576
- | `negativeExamplesPenaltyPerHit` | `0.05` | Penalty per "not useful" hit |
577
- | `negativeExamplesPenaltyCap` | `0.25` | Maximum total penalty applied |
578
- | `localLlmHomeDir` | `(auto)` | Optional home directory override for LM Studio settings + helper paths |
579
- | `localLmsCliPath` | `(auto)` | Optional absolute path to `lms` CLI |
580
- | `localLmsBinDir` | `(auto)` | Optional bin dir prepended to PATH for `lms` execution |
581
-
582
- ### v1.2.0 Advanced Feature Settings
583
-
584
- #### Access Tracking & Retrieval
585
-
586
- | Setting | Default | Description |
587
- |---------|---------|-------------|
588
- | `accessTrackingEnabled` | `true` | Track memory access counts and recency |
589
- | `accessTrackingBufferMaxSize` | `100` | Max entries in access buffer before flush |
590
- | `recencyWeight` | `0.2` | Weight for recency boosting (0-1) |
591
- | `boostAccessCount` | `true` | Boost frequently accessed memories in search |
592
-
593
- #### Chunking
594
-
595
- | Setting | Default | Description |
596
- |---------|---------|-------------|
597
- | `chunkingEnabled` | `false` | Enable automatic chunking of long memories |
598
- | `chunkingTargetTokens` | `200` | Target tokens per chunk |
599
- | `chunkingMinTokens` | `150` | Minimum tokens to trigger chunking |
600
- | `chunkingOverlapSentences` | `2` | Number of sentences to overlap between chunks |
601
-
602
- #### Contradiction Detection
603
-
604
- | Setting | Default | Description |
605
- |---------|---------|-------------|
606
- | `contradictionDetectionEnabled` | `false` | Enable LLM-verified contradiction detection |
607
- | `contradictionSimilarityThreshold` | `0.7` | QMD similarity threshold to trigger check |
608
- | `contradictionMinConfidence` | `0.9` | Minimum LLM confidence to auto-resolve |
609
- | `contradictionAutoResolve` | `true` | Automatically supersede contradicted memories |
610
-
611
- #### Memory Linking
38
+ **[Getting Started](docs/getting-started.md)** for QMD setup, first-time config, and verification.
612
39
 
613
- | Setting | Default | Description |
614
- |---------|---------|-------------|
615
- | `memoryLinkingEnabled` | `false` | Enable automatic memory linking |
616
-
617
- #### Conversation Threading
618
-
619
- | Setting | Default | Description |
620
- |---------|---------|-------------|
621
- | `threadingEnabled` | `false` | Enable conversation threading |
622
- | `threadingGapMinutes` | `30` | Minutes of gap to start a new thread |
623
-
624
- #### Memory Summarization
625
-
626
- | Setting | Default | Description |
627
- |---------|---------|-------------|
628
- | `summarizationEnabled` | `false` | Enable automatic memory compression |
629
- | `summarizationTriggerCount` | `1000` | Memory count threshold to trigger |
630
- | `summarizationRecentToKeep` | `300` | Number of recent memories to keep uncompressed |
631
- | `summarizationImportanceThreshold` | `0.3` | Only compress memories with importance below this |
632
- | `summarizationProtectedTags` | `["commitment", "preference", "decision", "principle"]` | Tags that protect memories from compression |
633
-
634
- #### Topic Extraction
635
-
636
- | Setting | Default | Description |
637
- |---------|---------|-------------|
638
- | `topicExtractionEnabled` | `true` | Enable topic extraction during consolidation |
639
- | `topicExtractionTopN` | `50` | Number of top topics to extract |
640
-
641
- ### v6.0 Deduplication & Archival Settings
642
-
643
- | Setting | Default | Description |
644
- |---------|---------|-------------|
645
- | `factDeduplicationEnabled` | `true` | Content-hash dedup prevents storing identical facts |
646
- | `factArchivalEnabled` | `false` | Automatically archive old, low-value facts |
647
- | `factArchivalAgeDays` | `90` | Minimum age (days) before a fact is eligible for archival |
648
- | `factArchivalMaxImportance` | `0.3` | Only archive facts with importance below this threshold |
649
- | `factArchivalMaxAccessCount` | `2` | Only archive facts accessed this many times or fewer |
650
- | `factArchivalProtectedCategories` | `["commitment", "preference", "decision", "principle"]` | Categories that are never archived |
40
+ ## How It Works
651
41
 
652
- ### Trigger Modes
42
+ 1. **Signal scan** — Fast local regex classifies each turn (<10 ms, no API call).
43
+ 2. **Smart buffer** — high-signal turns extract immediately; others batch.
44
+ 3. **Extraction** — One LLM call produces typed memories with confidence scores.
45
+ 4. **Storage** — Plain markdown + YAML frontmatter files; no database.
46
+ 5. **Retrieval** — QMD hybrid search injects relevant context before each agent session.
47
+ 6. **Consolidation** — Periodic pass merges duplicates, updates entity profiles, expires stale entries.
653
48
 
654
- - **`smart`** (default): Extracts immediately on high-signal turns (corrections, preferences, identity statements). Batches low-signal turns until buffer-full or time-elapsed.
655
- - **`every_n`**: Extracts every N turns. Simple and predictable.
656
- - **`time_based`**: Extracts when `bufferMaxMinutes` elapsed since last extraction.
49
+ **[Architecture Overview](docs/architecture/overview.md)** for internals.
657
50
 
658
- ### API Key Configuration
51
+ ## Memory Categories
659
52
 
660
- The plugin resolves the OpenAI API key in this order:
53
+ 10 typed categories: `fact`, `preference`, `correction`, `entity`, `decision`, `relationship`, `principle`, `commitment`, `moment`, `skill`.
661
54
 
662
- 1. `config.openaiApiKey` with `${VAR}` syntax -- resolved from environment
663
- 2. `config.openaiApiKey` as literal string -- used directly
664
- 3. `process.env.OPENAI_API_KEY` -- implicit fallback
665
- 4. None -- extraction disabled, retrieval-only mode (plugin still loads and serves memories)
55
+ ### v8.0 Memory OS (current)
666
56
 
667
- **Gateway note:** The OpenClaw gateway runs as a launchd service with its own environment. If you use `${VAR}` syntax, make sure the variable is in the gateway's launchd plist `EnvironmentVariables`, not just your shell profile.
57
+ - **Memory Boxes** (`memoryBoxesEnabled`) Topic-windowed episode boxes with trace linking.
58
+ - **Episode/Note dual store** (`episodeNoteModeEnabled`) — Episodes preserve event fidelity; notes reconsolidate stable beliefs.
59
+ - **Verbatim Artifacts** (`verbatimArtifactsEnabled`) — High-confidence decisions/constraints stored as trusted retrieval anchors.
60
+ - **Recall Planner** (`recallPlannerEnabled`, default `true`) — Lightweight retrieve-vs-think gating.
668
61
 
669
62
  ## Agent Tools
670
63
 
671
- The plugin registers tools that agents can call during conversations:
672
-
673
64
  | Tool | Description |
674
65
  |------|-------------|
675
- | `memory_search` | Search memories by query string via QMD hybrid search |
676
- | `memory_store` | Explicitly store a memory with category, confidence, and tags |
677
- | `memory_promote` | Promote/copy a curated memory to shared namespace (v3.0+) |
678
- | `memory_profile` | View the current behavioral profile |
679
- | `memory_entities` | List all tracked entities or view a specific entity's facts |
680
- | `memory_summarize_hourly` | Generate hourly summaries |
681
- | `conversation_index_update` | Refresh conversation chunk index (v2.4) |
682
- | `shared_context_write_output` | Write an agent output into shared-context (v4.0) |
683
- | `shared_priorities_append` | Append priorities proposal to inbox (v4.0) |
684
- | `shared_feedback_record` | Record approval/rejection feedback for compounding (v4/v5) |
685
- | `shared_context_curate_daily` | Curate daily roundtable in shared-context (v4.0) |
686
- | `compounding_weekly_synthesize` | Build weekly compounding report + mistakes file (v5.0) |
687
-
688
- ## CLI Commands
689
-
690
- ```bash
691
- # Core commands
692
- openclaw engram stats # Memory statistics (counts, last extraction, etc.)
693
- openclaw engram search "query" # Search memories via QMD
694
- openclaw engram export --format json --out /tmp/engram-export
695
- openclaw engram import --from /tmp/engram-export --format auto
696
- openclaw engram backup --out-dir /tmp/engram-backups --retention-days 14
66
+ | `memory_search` | Semantic search over memories |
67
+ | `memory_store` | Manually store a memory |
68
+ | `memory_profile` | Retrieve the behavioral profile |
69
+ | `memory_entities` | List tracked entities |
70
+ | `memory_promote` | Promote to shared namespace |
71
+ | `memory_feedback` | Record thumbs up/down signal |
72
+
73
+ ## Docs
74
+
75
+ | Guide | Contents |
76
+ |-------|----------|
77
+ | [Getting Started](docs/getting-started.md) | Install, QMD setup, first-time config |
78
+ | [Config Reference](docs/config-reference.md) | Every setting, default, and description |
79
+ | [Operations](docs/operations.md) | Backup, export, hourly summaries, CLI |
80
+ | [Architecture: Overview](docs/architecture/overview.md) | System design and data model |
81
+ | [Architecture: Retrieval Pipeline](docs/architecture/retrieval-pipeline.md) | How recall works |
82
+ | [Architecture: Memory Lifecycle](docs/architecture/memory-lifecycle.md) | Write, consolidation, expiry |
83
+ | [Advanced Retrieval](docs/advanced-retrieval.md) | Reranking, query expansion, feedback |
84
+ | [Import / Export](docs/import-export.md) | Portable backups and migration |
85
+ | [Namespaces](docs/namespaces.md) | Multi-agent memory isolation |
86
+ | [Shared Context](docs/shared-context.md) | Cross-agent shared intelligence |
87
+ | [Compounding](docs/compounding.md) | Weekly synthesis and mistake learning |
88
+ | [Context Retention](docs/context-retention.md) | Transcript indexing and hourly summaries |
89
+
90
+ ## Requirements
697
91
 
698
- # Namespace-aware (v3.0+, when namespacesEnabled=true)
699
- openclaw engram export --format json --out /tmp/engram-shared --namespace shared
700
- openclaw engram import --from /tmp/engram-shared --format auto --namespace shared
701
- openclaw engram backup --out-dir /tmp/engram-backups --namespace main
702
- openclaw engram profile # Display the behavioral profile
703
- openclaw engram entities # List all tracked entities
704
- openclaw engram entities person-name # View specific entity details
705
- openclaw engram questions # List open curiosity questions
706
- openclaw engram identity # Show agent identity reflections
707
-
708
- # v1.2.0 commands
709
- openclaw engram access # Show most accessed memories
710
- openclaw engram access -n 30 # Show top 30 most accessed
711
- openclaw engram flush-access # Manually flush access tracking buffer
712
-
713
- openclaw engram importance # Show importance score distribution
714
- openclaw engram importance -l high # Filter by importance level
715
- openclaw engram importance -n 20 # Show top 20 most important
716
-
717
- openclaw engram chunks # Show chunking statistics
718
- openclaw engram chunks -p <id> # Show chunks for a specific parent
719
-
720
- openclaw engram threads # List conversation threads
721
- openclaw engram threads -t <id> # Show details for a specific thread
722
-
723
- openclaw engram topics # Show extracted topics
724
- openclaw engram topics -n 30 # Show top 30 topics
725
-
726
- openclaw engram summaries # Show memory summaries
727
- openclaw engram summaries -n 10 # Show top 10 most recent summaries
728
- ```
729
-
730
- ## Migration
731
-
732
- Import memories from existing OpenClaw memory systems:
733
-
734
- ```bash
735
- cd ~/.openclaw/extensions/openclaw-engram
736
-
737
- # Full migration (context files + Supermemory + Honcho)
738
- npx tsx scripts/migrate.ts
739
-
740
- # Preview without writing anything
741
- npx tsx scripts/migrate.ts --dry-run
742
-
743
- # Migrate specific sources
744
- npx tsx scripts/migrate.ts --source=context # Context files only
745
- npx tsx scripts/migrate.ts --source=supermemory # Supermemory daily logs
746
- npx tsx scripts/migrate.ts --source=honcho # Honcho API conclusions
747
- ```
748
-
749
- The migration script:
750
- - Deduplicates against existing engram memories
751
- - Categorizes each memory (fact, preference, correction, decision)
752
- - Writes proper frontmatter with source attribution
753
- - Seeds `profile.md` from context files (if it doesn't exist yet)
754
- - Prints a detailed report with counts per source
755
-
756
- After migration, re-index QMD:
757
-
758
- ```bash
759
- qmd update && qmd embed
760
- ```
761
-
762
- ## How It Works
763
-
764
- ### Extraction
765
-
766
- When a trigger fires, the buffered conversation turns are sent to the OpenAI Responses API with a structured output schema (Zod). Empty or whitespace-only turns are filtered out before the API call to avoid errors. The LLM returns:
767
-
768
- - **Facts**: Typed memories with category, content, confidence score, tags, and optional entity reference
769
- - **Entities**: Named entities with their type and newly learned facts
770
- - **Profile updates**: Standalone behavioral statements about the user
771
- - **Questions**: 1-3 curiosity questions the agent wants answered in future sessions
772
- - **Identity reflection**: A brief self-reflection on the agent's own behavior
773
-
774
- ### Consolidation
775
-
776
- Every N extractions, a consolidation pass:
777
-
778
- 1. Compares recent memories against older ones
779
- 2. For each memory, decides: ADD, MERGE, UPDATE, INVALIDATE, or SKIP
780
- 3. MERGE and UPDATE actions track lineage (parent memory IDs)
781
- 4. Updates entity profiles and the behavioral profile
782
- 5. **Merges fragmented entity files** — entities with variant names that resolve to the same canonical form are automatically merged
783
- 6. Cleans expired commitments (fulfilled/expired + past decay period)
784
- 7. Removes TTL-expired speculative memories
785
- 8. **Archives old, low-importance, rarely-accessed facts** (v6.0, when `factArchivalEnabled`)
786
- 9. Auto-consolidates IDENTITY.md if it exceeds 8KB
787
-
788
- ### Entity Normalization
789
-
790
- Entity names are automatically normalized to prevent fragmentation:
791
-
792
- - Names are lowercased and hyphenated (`BlendSupply` → `blend-supply`)
793
- - A configurable alias table maps common variants to canonical names
794
- - Type preferences resolve cross-type duplicates (e.g., `company` wins over `other`)
795
- - The periodic merge pass consolidates any entities that escaped normalization
796
-
797
- ### Profile Management
798
-
799
- The behavioral profile (`profile.md`) is injected into every agent's system prompt to provide user context. To prevent unbounded growth:
800
-
801
- - **Smart consolidation** (threshold: 600 lines): When the profile exceeds this limit during a consolidation pass, the LLM consolidates it — merging duplicate or near-duplicate bullets, removing stale information, and preserving `##` section headers
802
- - Consolidation targets roughly 400 lines, prioritizing quality and durability of observations
803
- - All section structure is preserved; only redundant or superseded bullets are removed
804
-
805
- ### Confidence Tiers
806
-
807
- | Tier | Range | Meaning | TTL |
808
- |------|-------|---------|-----|
809
- | Explicit | 0.95-1.0 | Direct user statement ("I prefer X") | None |
810
- | Implied | 0.70-0.94 | Strong contextual inference | None |
811
- | Inferred | 0.40-0.69 | Pattern recognition from limited evidence | None |
812
- | Speculative | 0.00-0.39 | Tentative hypothesis, needs confirmation | 30 days |
813
-
814
- ## Development
815
-
816
- ```bash
817
- # Watch mode (rebuilds on file changes)
818
- npm run dev
819
-
820
- # Type checking
821
- npm run check-types
822
-
823
- # Build for production
824
- npm run build
825
- ```
826
-
827
- ### Project Structure
828
-
829
- ```
830
- src/
831
- ├── index.ts # Plugin entry point (hooks, tools, CLI registration)
832
- ├── orchestrator.ts # Central coordinator (extraction, consolidation, retrieval)
833
- ├── extraction.ts # OpenAI Responses API client
834
- ├── storage.ts # File-based storage manager (markdown + YAML frontmatter)
835
- ├── buffer.ts # Smart buffer with configurable trigger logic
836
- ├── signal.ts # Local signal detection (regex, zero cost)
837
- ├── schemas.ts # Zod schemas for structured LLM output
838
- ├── types.ts # TypeScript type definitions
839
- ├── config.ts # Config parser with env var resolution
840
- ├── qmd.ts # QMD CLI client (search, update, collection management)
841
- ├── tools.ts # Agent tool definitions
842
- ├── cli.ts # CLI subcommand definitions
843
- ├── logger.ts # Logging utilities
844
- ├── chunking.ts # [v1.2.0] Sentence-boundary chunking for long memories
845
- ├── importance.ts # [v1.2.0] Zero-LLM heuristic importance scoring
846
- ├── threading.ts # [v1.2.0] Conversation threading with TF-IDF titles
847
- └── topics.ts # [v1.2.0] TF-IDF topic extraction across corpus
848
- scripts/
849
- └── migrate.ts # Migration from Honcho, Supermemory, context files
850
- ```
851
-
852
- ## Contributing
853
-
854
- We welcome both issues and pull requests, including AI-assisted contributions.
855
-
856
- - Report bugs: open a GitHub issue (use templates)
857
- - Propose features: open a GitHub issue with scope and expected impact
858
- - Submit PRs: keep scope focused, include tests, and update the changelog
859
-
860
- See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines, review expectations, and changelog policy.
861
- See [CONTRIBUTORS.md](CONTRIBUTORS.md) for contributor recognition.
862
-
863
- **Important:** This is a public repository. Never commit personal data, API keys, memory content, or user-specific configuration. See [CLAUDE.md](CLAUDE.md) and [SECURITY.md](SECURITY.md).
864
-
865
- ## License
866
-
867
- MIT
92
+ - [OpenClaw](https://github.com/openclaw/openclaw) gateway
93
+ - OpenAI API key (extraction only; retrieval works without one)
94
+ - [QMD](https://github.com/tobi/qmd) (optional, recommended for hybrid search)