memorio 5.1.4 → 5.2.0

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.
Files changed (45) hide show
  1. package/AGENTS.md +21 -12
  2. package/CHANGELOG.md +18 -6
  3. package/README.md +44 -7
  4. package/SECURITY-HARDENING.md +258 -0
  5. package/SECURITY.md +67 -3
  6. package/SUMMARY.md +55 -59
  7. package/adr/002-observer-semantics.md +1 -1
  8. package/adr/003-deep-mutation-semantics.md +1 -1
  9. package/adr/004-array-mutation-semantics.md +1 -1
  10. package/adr/010-logic-phase-0.md +42 -0
  11. package/adr/README.md +16 -11
  12. package/bin/cli.js +82 -60
  13. package/examples/acquired-knowledge.ts +174 -0
  14. package/examples/agent-memory-demo.ts +140 -0
  15. package/examples/sync.ts +90 -90
  16. package/examples/useObserver.tsx +2 -2
  17. package/global.cjs +1995 -124
  18. package/global.js +1990 -125
  19. package/index.cjs +1995 -124
  20. package/index.d.ts +1 -0
  21. package/index.js +1990 -125
  22. package/llms.txt +122 -4
  23. package/markdown/EXTENSION_VSCODE_DESIGN.md +410 -0
  24. package/markdown/LOGIC.md +100 -0
  25. package/markdown/MEMORY-ATTACHMENT.md +17 -10
  26. package/markdown/MEMORY.md +378 -15
  27. package/markdown/MEM_FORMAT.md +313 -0
  28. package/markdown/STATE.md +27 -3
  29. package/markdown/SYNC.md +18 -14
  30. package/markdown/TEMPORAL.md +297 -0
  31. package/markdown/USEOBSERVER.md +7 -4
  32. package/modules/redux.cjs +1159 -32
  33. package/modules/redux.cjs.map +1 -1
  34. package/modules/redux.js +1158 -32
  35. package/modules/redux.js.map +1 -1
  36. package/package.json +14 -5
  37. package/types/exports.d.ts +47 -3
  38. package/types/logic.d.ts +79 -0
  39. package/types/memorio.d.ts +60 -16
  40. package/types/memory.d.ts +118 -0
  41. package/types/session.d.ts +1 -4
  42. package/types/store.d.ts +1 -4
  43. package/types/temporal.d.ts +95 -0
  44. package/types/useObserver.d.ts +6 -10
  45. package/vsix/memorio.vsix +0 -0
@@ -1,12 +1,19 @@
1
- > **Status:** Published
2
- > **Date:** 2026-09-12
3
- > **Scope**: API Reference
4
- > **Standard**: Memorio API Specification v5
5
- >
6
- ---
7
- # Node Attachment System
8
-
9
- `memorio.memory` extends with a **Node Attachment System** allowing memory elements to dynamically attach, reference, or connect to other memory elements at runtime.
1
+ > **Status:** Proposed (not yet implemented)
2
+ > **Date:** 2026-09-12
3
+ > **Scope**: API Reference
4
+ > **Standard**: Memorio API Specification v5
5
+ >
6
+ > **Not implemented.** The Node Attachment System described in this document is a
7
+ > proposed specification. None of the APIs below - `node.connect`, `node.attach`,
8
+ > `node.related`, `node.traverse`, `memory.connect`, `memory.disconnect` - are
9
+ > present in the current `MemoryAPI`. Additionally, `memory.remember()` returns
10
+ > `Promise<void>`, not a node object with relationship methods. This document is
11
+ > kept as a design reference until the feature is implemented.
12
+ >
13
+ ---
14
+ # Node Attachment System (proposed)
15
+
16
+ `memorio.memory` is specified to extend with a **Node Attachment System** allowing memory elements to dynamically attach, reference, or connect to other memory elements at runtime.
10
17
 
11
18
  This is an **extension**, not a replacement, of existing memory semantics.
12
19
 
@@ -92,4 +99,4 @@ Nodes serialize to IDs only - never recursively embedded graphs.
92
99
 
93
100
  ## Backward Compatibility
94
101
 
95
- Existing APIs (`remember`, `get`, `forget`, `search`) continue to work unchanged. A node-enabled memory entry remains usable as a normal memory entry.
102
+ Existing APIs (`remember`, `recall`, `forget`, `context`) continue to work unchanged. A node-enabled memory entry remains usable as a normal memory entry.
@@ -1,14 +1,114 @@
1
- > **Status:** Published
2
- > **Date:** 2026-09-12
3
- > **Scope**: API Reference
4
- > **Standard**: Memorio API Specification v5
5
- >
6
- ---
7
- # Memory System
8
-
9
- `memorio.memory` provides a semantic memory layer - a key/value store with type safety, TTL, confidence scoring, tagging, and scope-based persistence.
10
-
11
- ## Core API
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Scope**: API Reference
4
+ > **Standard**: Memorio API Specification v5
5
+ >
6
+ ---
7
+ # Memory System
8
+
9
+ `memorio.memory` provides a semantic memory layer - a key/value store with type safety, TTL, confidence scoring, tagging, and scope-based persistence.
10
+
11
+ ## Acquired-experience discovery
12
+
13
+ `memory.discover()` finds a small, deterministic set of plausible **active acquired-experience candidates** from ordinary situation text. The caller does not need to know applicability keys or claim IDs.
14
+
15
+ ```ts
16
+ const result = await memory.discover('proxy target locking mutation')
17
+
18
+ for (const candidate of result.candidates) {
19
+ console.log(candidate.claim.id)
20
+ console.log(candidate.explanation.matchedTerms)
21
+ }
22
+ ```
23
+
24
+ The optional retrieval depth controls breadth, not a different memory store:
25
+
26
+ ```ts
27
+ await memory.discover('proxy locking', { depth: 'current' }) // at most 5 by default
28
+ await memory.discover('proxy locking', { depth: 'deep' }) // at most 25 by default
29
+ await memory.discover('proxy locking', { maxCandidates: 10 })
30
+ ```
31
+
32
+ Discovery is deliberately distinct from the existing acquired-context selector:
33
+
34
+ - **Discovery** uses normalized lexical overlap to find candidates. It can return zero candidates.
35
+ - **Applicability selection** (`memory.context({ acquired: ... })`) keeps exact structured matching and most-specific-wins behavior.
36
+ - **Context projection** (`memory.project()`) is a separate synchronous step that turns a Discovery result into bounded transferable context.
37
+
38
+ Normalization is local and deterministic: Unicode NFKC normalization, locale-stable lowercase conversion, punctuation/symbol separation, whitespace normalization, removal of duplicate terms, and omission of terms shorter than three characters. Stored claims are never rewritten.
39
+
40
+ Candidate ordering uses, in order: a direct normalized phrase match, the number of distinct matching query terms, the kinds of fields matched, acquisition recency, and stable claim ID. Recency only breaks relevance ties; old claims are not expired or excluded. Result explanations list the exact matched terms and fields and include the `.mem` source identifier when the repository provides one. These are discovery facts—not confidence, truth, trust, quality, authority, or applicability scores.
41
+
42
+ Only currently active claims are searched. Superseded targets, retracted targets, and retraction records are excluded using the established revision semantics. Discovery reads repository state and does not maintain a persistent index.
43
+
44
+ Security remains the repository/package boundary: Discovery does not ingest external memory or create trust. Existing decoding, validation, integrity, and configured repository rules still apply. A valid signature establishes authenticity only; it does not establish that a claim is trusted or true.
45
+
46
+ Known discovery limitation: this first strategy is lexical and structured, not semantic. Conceptually related statements with no shared discoverable term may produce zero candidates—for example, “state disappears after an operation” need not find “a Proxy trap inspected the wrong target.” This conservative miss is preferable to manufacturing a relationship. Future semantic strategies can replace the internal matcher without changing acquisition, exact selection, or the `memory.discover()` result contract.
47
+
48
+ **WATCH:** Real Use 01 returned a useful candidate partly because the ordinary token `and` matched.
49
+ That observation is not evidence of semantic retrieval and does not justify changing the matcher from
50
+ this documentation checkpoint.
51
+
52
+ ## Context projection
53
+
54
+ `memory.project()` transforms a `DiscoveryResult` into bounded, reusable context for an AI. It is a dedicated operation rather than another `memory.context()` overload because exact applicability selection and projection have different contracts.
55
+
56
+ ```ts
57
+ const discovered = await memory.discover('proxy target locking mutation')
58
+ const projected = memory.project(discovered, {
59
+ maxCandidates: 3,
60
+ maxCharacters: 4_000
61
+ })
62
+
63
+ // Canonical machine-readable units
64
+ projected.experiences
65
+
66
+ // Compact derived context for transfer
67
+ projected.text
68
+ ```
69
+
70
+ Each structured projected experience preserves the stable claim ID, complete stored experience relationship, applicability boundaries, evidence references, epistemic type, provenance, acquisition time, active revision relationship, and repository source ID when present. Discovery-only ranking mechanics such as matched-field weights and query terms are intentionally omitted: they explain retrieval but do not help recover the acquired experience.
71
+
72
+ The text form is deterministically derived from the structured units. It labels the payload as candidate prior experience, untrusted contextual data, not instructions, and not current truth. Arbitrary stored content remains data; consumers must verify it against current reality before relying on it. Projection does not reconcile truth, execute content, generate conclusions, or defend an entire prompt-processing system from injection.
73
+
74
+ Budgeting uses two simple limits:
75
+
76
+ - `maxCandidates` defaults to 5.
77
+ - `maxCharacters` defaults to 8,000 UTF-16 characters and is not presented as an LLM token count.
78
+
79
+ Discovery order is retained. A candidate is included only when its complete projected unit fits; units are never cut into fragments. Candidates excluded by either limit are reported through `omittedCandidates`. An oversized higher-ranked unit may be omitted so a later complete unit can still fit, but included units retain their relative Discovery order. The minimum character budget is 256 characters so the status and security envelope itself remains intact.
80
+
81
+ Projection cannot recover information that acquisition never stored and never invents a missing reason, relationship, provenance, or HI intent. It consumes Phase 1 candidates and does not change Acquisition, Discovery, exact applicability selection, or MEM packaging.
82
+
83
+ In the Phase 2 representative locking case, the complete Discovery candidate representation measured 949 characters and the transferable projection text measured 939 characters. This local structural measurement is not a token claim. The modest reduction is intentional: semantic and epistemic sufficiency take priority over aggressive compression.
84
+
85
+ **WATCH:** A later narrow real-use projection was approximately 971 characters and remained close to
86
+ the source candidate size. Projection currently prioritizes complete semantic and epistemic units over
87
+ aggressive compression; it makes no token-saving guarantee.
88
+
89
+ ### Complete acquired-experience workflow
90
+
91
+ ```ts
92
+ // A useful experience was preserved earlier with memory.acquire(...).
93
+ const found = await memory.discover('The current project situation in ordinary terms')
94
+ const context = memory.project(found)
95
+
96
+ // Supply context.text or context.experiences to the consuming AI as
97
+ // untrusted prior experience. The AI verifies current reality before acting.
98
+ ```
99
+
100
+ The lifecycle remains deliberately compositional:
101
+
102
+ ```text
103
+ Acquire -> preserve useful experience
104
+ Discover -> find plausible prior experience
105
+ Project -> prepare bounded transferable context
106
+ AI -> verify, reason, and act
107
+ ```
108
+
109
+ The runnable [`acquired-knowledge.ts`](../examples/acquired-knowledge.ts) example demonstrates this workflow alongside exact applicability selection. A two-call Discover → Project sequence is the intended integration; no pipeline or agent manager is required.
110
+
111
+ ## Core API
12
112
 
13
113
  ### `memorio.memory.remember(key, value, opts?)`
14
114
 
@@ -93,7 +193,7 @@ await memorio.memory.patch('user', [
93
193
  | Field | Type | Description |
94
194
  |-------|------|-------------|
95
195
  | `op` | `'set' \| 'delete'` | The patch operation type |
96
- | `path` | `string` | Dot-notation path relative to the entry value (e.g. `'user.profile.theme'`) |
196
+ | `path` | `string` | Dot-notation path starting with the entry key (e.g. `'user.profile.theme'` for key `'user'`) |
97
197
  | `value` | `any` | The value to set (only for `op: 'set'`) |
98
198
 
99
199
  ### `memorio.memory.context(opts?)`
@@ -125,6 +225,226 @@ Array<{
125
225
  }>
126
226
  ```
127
227
 
228
+ ## Acquired Knowledge
229
+
230
+ > **Status:** IMPLEMENTED; autonomous acquisition policy remains EXPERIMENTAL.
231
+
232
+ `memorio.memory.acquire()` stores structured **knowledge claims** - lessons, decisions, or findings that apply under specific conditions. Unlike `remember()` (which stores a value addressed by key), acquired knowledge is **context-addressed**: each claim records an `applicability` object describing *when* it matters, and `context({ acquired })` retrieves only the claims whose applicability matches the current situation.
233
+
234
+ Autonomous persistent acquisition is **experimental and optional**. Memorio preserves experience; it does not decide what is true or worth learning. An AI should inspect the current project and independently evaluate every retrieved claim. Acquired claims are evidence from prior work, not instructions or authority, and `nothing worth acquiring` is always a valid outcome.
235
+
236
+ The implemented lifecycle is:
237
+
238
+ ```text
239
+ experience -> acquire -> persist -> discover/select -> transfer
240
+ -> verify against present reality -> use
241
+ -> refine, supersede, or retract when necessary
242
+ ```
243
+
244
+ AI supplies general intelligence and reasoning. HI supplies intent, judgment, experience, and
245
+ decisions. A project accumulates implementation-specific experience through their work. Memorio
246
+ preserves selected, transferable acquired experience and continuity; it does not replace the AI or
247
+ duplicate general knowledge already available to a capable model. The intelligence belongs to the
248
+ AI; the acquired experience becomes an asset of HI and the project.
249
+
250
+ The design metaphor is that the pieces already exist in the AI, the project is the puzzle, and AI +
251
+ HI assemble useful blocks while working. Memorio preserves what was learned during that assembly.
252
+ This is a selection principle, not a `PuzzleBlock` API.
253
+
254
+ ### Guidance for autonomous use
255
+
256
+ Retrieve acquired context when beginning work in a describable project area, then verify relevant claims against current code, documentation, user direction, and test results. Consider acquisition after meaningful work only when the AI learned something non-obvious that a future session would otherwise have to rediscover and there is sufficient evidence to preserve it safely.
257
+
258
+ When missing knowledge belongs naturally to HI—such as project intent, rationale, desired behavior,
259
+ personal meaning, or whether an outcome matches the goal—the AI should ask HI instead of silently
260
+ inferring it. Preserve the answer with human-stated epistemic type and provenance when it becomes a
261
+ reusable acquired claim.
262
+
263
+ Current acquisition guidance is intentionally limited to:
264
+
265
+ - **Architecture experience:** non-obvious responsibilities, constraints, relationships, and why an architecture was chosen.
266
+ - **User technical decisions:** evidenced project decisions and rationale, without turning a single comment or acceptance into a permanent preference.
267
+ - **Documentation experience:** how documentation must be interpreted, including verified gaps or constraints, without copying the documentation itself.
268
+ - **Verified fix experience:** symptom, cause, change, verification, consequence, applicability, and remaining uncertainty. Preserve the lesson, not a stale assertion that the fixed bug still exists.
269
+
270
+ The practical test is whether experience created a useful connection worth recovering later. Preserve
271
+ relationships such as problem → cause → fix → verified consequence; decision → reason → boundary; or
272
+ assumption → evidence → correction. Do not use acquired knowledge as a dump for generic knowledge,
273
+ source-code or documentation copies, entire conversations, routine operations, test logs, or hidden
274
+ chain-of-thought.
275
+
276
+ Do not acquire repository facts that code, Git, or current documentation already express adequately. Keep these stages distinct in the claim content and evidence:
277
+
278
+ ```text
279
+ observation -> what was directly encountered
280
+ inference -> the AI's interpretation, explicitly uncertain
281
+ verified -> what a named check or result demonstrated
282
+ experience -> the reusable why, consequence, or constraint selected for persistence
283
+ ```
284
+
285
+ A practical claim can encode those distinctions in `knowledge`, for example `{ observation, inference, verifiedResult, experience, uncertainty }`. This is guidance for the existing JSON-valued field, not a new required schema. Use evidence references to identify the supporting review, test, user decision, or investigation. If reality has changed, ignore the claim or acquire a `refines`/`supersedes` revision; never force current reality to fit memory.
286
+
287
+ > **TODO - Autonomous Memory Safety:** Before autonomous acquisition is declared stable, decide what must never be acquired; how secrets, personal data, and unsafe content are excluded; when notification or approval is required; and how users inspect, reject, correct, forget, and assess the provenance, uncertainty, and staleness of acquired claims. The current API does not solve these policy questions.
288
+
289
+ ```ts
290
+ await memorio.memory.acquire({
291
+ id: 'layout.aside-width',
292
+ knowledge: { guidance: 'Use the shared --aside-width token, not a fixed pixel value.' },
293
+ applies: { component: 'layout', element: 'aside' },
294
+ evidence: [{ id: 'review-17', source: 'design-review', observedAt: '2026-09-18T00:00:00Z' }]
295
+ })
296
+ ```
297
+
298
+ ### `memorio.memory.acquire(opts)`
299
+
300
+ | Option | Type | Required | Description |
301
+ |--------|------|----------|-------------|
302
+ | `id` | `string` | Yes | Unique claim identifier (immutable; cannot be reused) |
303
+ | `knowledge` | `JsonValue` | Yes | The claim content - any JSON-serializable value |
304
+ | `applies` | `Record<string, JsonPrimitive>` | Yes | Applicability context - the condition under which this claim is relevant |
305
+ | `epistemicType` | `'observed' \| 'inferred' \| 'human-stated' \| 'verified'` | No | What kind of knowledge the claim represents |
306
+ | `provenance` | `{ source: string; detail?: string }` | No | Origin of the acquired claim |
307
+ | `acquiredAt` | `string` | No | Acquisition time; defaults to the current ISO timestamp |
308
+ | `evidence` | `EvidenceReference[]` | Yes (≥1) | Evidence references justifying the claim |
309
+ | `refines` | `string \| string[]` | No | Prior claim IDs this claim refines (more specific) |
310
+ | `supersedes` | `string \| string[]` | No | Prior claim IDs this claim replaces (mutually exclusive with `refines`) |
311
+ | `retracts` | `string \| string[]` | No | Prior claim IDs this claim withdraws (mutually exclusive with other revision kinds) |
312
+ | `reason` | `string` | No | Why the revision relationship exists |
313
+
314
+ **Evidence reference shape:**
315
+
316
+ ```ts
317
+ interface EvidenceReference {
318
+ id: string // observed-at identifier (required, non-empty)
319
+ source?: string // where the observation came from
320
+ observedAt?: string // ISO timestamp of the observation
321
+ supports?: string // what proposition this evidence supports
322
+ }
323
+ ```
324
+
325
+ ### `memorio.memory.context({ acquired })`
326
+
327
+ Retrieves knowledge claims whose `applicability` exactly matches the provided query context. Both a single context object and an array of contexts are accepted.
328
+
329
+ ```ts
330
+ // Single context - retrieves claims applicable to this situation
331
+ const result = await memorio.memory.context({
332
+ acquired: { component: 'layout', element: 'aside' }
333
+ })
334
+
335
+ // Multiple contexts - each is queried independently
336
+ const result2 = await memorio.memory.context({
337
+ acquired: [
338
+ { component: 'layout' },
339
+ { component: 'layout', element: 'aside' }
340
+ ]
341
+ })
342
+ ```
343
+
344
+ Returns:
345
+ ```ts
346
+ {
347
+ knowledgeVersion: number // current persisted knowledge state version
348
+ claims: AcquiredClaim[] // matching claims, deduplicated
349
+ }
350
+ ```
351
+
352
+ **Claim shape:**
353
+ ```ts
354
+ interface AcquiredClaim {
355
+ id: string
356
+ knowledge: JsonValue // the stored claim content
357
+ applicability: Record<string, JsonPrimitive> // the condition this claim applies to
358
+ evidence: EvidenceReference[] // supporting evidence
359
+ epistemicType?: 'observed' | 'inferred' | 'human-stated' | 'verified'
360
+ provenance?: { source: string; detail?: string }
361
+ acquiredAt?: string
362
+ revision?: {
363
+ kind: 'refines' | 'supersedes' | 'retracts' // relationship type
364
+ claimIds: string[] // IDs of prior claims
365
+ reason?: string // why the revision exists
366
+ }
367
+ }
368
+ ```
369
+
370
+ ### Matching semantics
371
+
372
+ Selection follows two rules:
373
+
374
+ 1. **All applicability keys must match.** A claim with `applicability: { component: 'layout', element: 'aside' }` only matches a query that provides *both* `component: 'layout'` *and* `element: 'aside'`.
375
+ 2. **Most specific wins.** When multiple claims satisfy the same query, only those with the highest number of applicability keys are returned. Less-specific claims are excluded - they act as fallbacks only when no more-specific claim matches.
376
+
377
+ This lets you store a general rule and a specific override:
378
+
379
+ ```ts
380
+ // General rule
381
+ await memorio.memory.acquire({
382
+ id: 'layout.general',
383
+ knowledge: 'Use layout tokens.',
384
+ applies: { component: 'layout' },
385
+ evidence: [{ id: 'e-general' }]
386
+ })
387
+
388
+ // Specific override
389
+ await memorio.memory.acquire({
390
+ id: 'layout.aside',
391
+ knowledge: 'Use aside layout tokens.',
392
+ applies: { component: 'layout', element: 'aside' },
393
+ evidence: [{ id: 'e-aside' }],
394
+ refines: 'layout.general'
395
+ })
396
+
397
+ const general = await memorio.memory.context({ acquired: { component: 'layout' } })
398
+ // general.claims → [{ id: 'layout.general', ... }]
399
+
400
+ const aside = await memorio.memory.context({ acquired: { component: 'layout', element: 'aside' } })
401
+ // aside.claims → [{ id: 'layout.aside', ... }] (more specific wins)
402
+ // aside.claims[0].revision → { kind: 'refines', claimIds: ['layout.general'] }
403
+ ```
404
+
405
+ ### Revision: supersede vs. refine
406
+
407
+ - **`supersedes`** - the new claim *replaces* the old one. Superseded claims are excluded from results; only the newer claim is returned for the same applicability context.
408
+ - **`refines`** - the new claim is *more specific* than the old one. Both remain active; the more specific claim wins when its applicability matches fully. The `revision` field on the returned claim records the relationship so a future AI can follow the reasoning chain.
409
+ - **`retracts`** - the new claim records withdrawal of prior claims. Both the retraction claim and the referenced claims are excluded from active selection, while history remains stored.
410
+
411
+ ```ts
412
+ await memorio.memory.acquire({
413
+ id: 'layout.aside.width.v1',
414
+ knowledge: 'Width is 250px.',
415
+ applies: { component: 'layout', element: 'aside' },
416
+ evidence: [{ id: 'old-evidence' }]
417
+ })
418
+
419
+ await memorio.memory.acquire({
420
+ id: 'layout.aside.width.v2',
421
+ knowledge: 'Width is 300px (updated design token).',
422
+ applies: { component: 'layout', element: 'aside' },
423
+ evidence: [{ id: 'new-evidence' }],
424
+ supersedes: 'layout.aside.width.v1'
425
+ })
426
+
427
+ const result = await memorio.memory.context({ acquired: { component: 'layout', element: 'aside' } })
428
+ // result.claims → [{ id: 'layout.aside.width.v2', ... }] (v1 is excluded)
429
+ ```
430
+
431
+ ### Persistence
432
+
433
+ Acquired knowledge is persisted so it survives process restarts and is available to future sessions:
434
+
435
+ | Runtime | Storage |
436
+ |---------|---------|
437
+ | Node.js / Bun | `.memorio/project.mem` (standard ZIP package in the `.memorio` directory) |
438
+ | Browser / Edge | `store` (localStorage-backed key `__memorio_acquired_knowledge_state__`) |
439
+
440
+ The `.mem` file uses a versioned format: v1/v2 JSON remains readable and current writes are standard
441
+ ZIP packages containing logical `memorio.knowledge` v2 plus SHA-256 integrity metadata. See
442
+ [the format reference](./MEM_FORMAT.md). Because
443
+ acquisition persists across sessions, applications and autonomous agents should make that behavior
444
+ visible to users while it remains experimental. `memorio.memory.clear()` wipes all ordinary memories,
445
+ acquired knowledge, and the index; it is destructive and should not be used as routine example cleanup
446
+ or against a real project during tests.
447
+
128
448
  ### `memorio.memory.stats()`
129
449
 
130
450
  Returns usage statistics:
@@ -144,7 +464,50 @@ Cleans all expired entries. Returns count removed.
144
464
 
145
465
  ### `memorio.memory.clear()`
146
466
 
147
- Wipes all memories and the index.
467
+ Wipes all memories, acquired knowledge, and the index.
468
+
469
+ ## Sync & Journal (optional)
470
+
471
+ `memorio.memory` includes an optional local-first sync layer. See [`SYNC.md`](./SYNC.md) for the
472
+ full guide.
473
+
474
+ ### `memorio.memory.configure(opts)`
475
+
476
+ Enables the local operation journal and optionally registers a cloud-sync provider.
477
+
478
+ ```ts
479
+ await memorio.memory.configure({
480
+ namespace: 'user:123:device:abc', // partitions the journal (tenant/user/device)
481
+ provider: { // application-owned transport
482
+ push(ops) { /* ... */ },
483
+ pull?(since) { /* ... */ },
484
+ resolveConflict?(local, remote) { /* ... */ }
485
+ },
486
+ auto: true // auto-replay journal on focus/online (default)
487
+ })
488
+ ```
489
+
490
+ | Option | Type | Description |
491
+ |--------|------|-------------|
492
+ | `namespace` | `string` | Tenant/user/device identifier partitioning the journal |
493
+ | `provider` | `SyncProvider` | Application-owned object that pushes/pulls operations to your backend |
494
+ | `direction` | `'up' \| 'down' \| 'both'` | Sync direction (default `'both'`) |
495
+ | `auto` | `boolean` | Auto-replay journal on focus/online events (default `true`) |
496
+
497
+ ### `memorio.memory.journal`
498
+
499
+ Local operation journal - a durable op log persisted on `store`. Only active when
500
+ sync has been configured via `configure()`.
501
+
502
+ | Method | Returns | Notes |
503
+ |--------|---------|-------|
504
+ | `append(entry, operation)` | `Promise<MemoryEntry>` | Records `remember \| update \| forget \| expire \| confirm \| supersede \| delete \| patch` |
505
+ | `pending()` | `Promise<MemoryEntry[]>` | Entries where `sync !== 'synced'`, namespace-scoped |
506
+ | `markSynced(ids)` | `Promise<number>` | Advances entries to `'synced'` |
507
+ | `get(id)` | `Promise<MemoryEntry \| null>` | Single entry, namespace-scoped |
508
+ | `clear()` | `Promise<void>` | Wipes the current namespace's journal only |
509
+ | `replay()` | `Promise<SyncAck>` | Pushes pending entries to the provider, marks synced, optional `pull` |
510
+ | `status()` | `Promise<'store'>` | The substrate in use (`'store'`) |
148
511
 
149
512
  ## Memory Entry Model
150
513
 
@@ -175,7 +538,7 @@ interface MemoryEntry<T = any> {
175
538
  | `local` | `localStorage` | ✅ | ✅ | ~10MB |
176
539
  | `durable` | `IndexedDB` | ✅ | ✅ | ~1GB+ |
177
540
 
178
- Default scope is `local` for values ≤100KB, `durable` for larger values.
541
+ Default scope: `local` for values ≤1 MB, `durable` for values >1 MB. The `hot` and `session` scopes are only used when explicitly set via `opts.scope`.
179
542
 
180
543
  ## Memory Lifecycle
181
544
 
@@ -185,4 +548,4 @@ Default scope is `local` for values ≤100KB, `durable` for larger values.
185
548
  | Entry with TTL expires | Status → `obsolete` (cleaned by `forgetExpired()`) |
186
549
  | `recall()` expired entry | Returns `null` unless `includeObsolete: true` |
187
550
  | `update()` | Creates superseded copy + updated active entry |
188
- | `clear()` | Wipes all memories + index |
551
+ | `clear()` | Wipes all memories, acquired knowledge + index |