memorio 4.9.10 → 4.9.31

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/AGENTS.md CHANGED
@@ -1,126 +1,126 @@
1
- # AGENTS.md — working with `memorio`
2
-
3
- Operational conventions for AI coding agents working in a repository that depends on `memorio`.
4
- See `README.md` and `llms.txt` for the full API. This file is decision rules: what to reach for,
5
- when, and the specific footguns this library's own docs flag.
6
-
7
- ## Read this before generating any `memorio` code
8
-
9
- `memorio`'s own `llms.txt` contains an explicit unresolved discrepancy:
10
-
11
- > **Locking — VERIFY BEFORE PUBLISHING:** one source describes per-key locking
12
- > (`state.config.lock()` freezes only `config`); another describes global locking
13
- > (`state.lock()` / `state.unlock()` freezing everything). Do not generate code against this
14
- > section until it's resolved against the real source.
15
-
16
- **Do not write or suggest `.lock()` / `.unlock()` calls with a confident claim about scope**
17
- (per-key vs. global) until you've confirmed the actual signature against the installed
18
- package's type definitions or source — `node_modules/memorio/dist/*.d.ts` — in the target repo.
19
- If you can't confirm it, say so explicitly rather than picking one behavior and presenting it
20
- as fact.
21
-
22
- ## Choosing a layer
23
-
24
- Don't default to `state` for everything just because it's the one-liner in the README. Walk the
25
- decision tree from the README's ["Which layer should I use"](./README.md#which-layer-should-i-use)
26
- section, and in particular:
27
-
28
- | If the data is... | Use | Not |
29
- | --- | --- | --- |
30
- | UI-reactive, doesn't need to survive reload | `state` | `store` (unnecessary persistence) |
31
- | Small, must survive reload, any tab | `store` | `idb` (overkill for simple k/v) |
32
- | Must survive reload, this tab only | `session` | `store` (wrong scope) |
33
- | Relational, needs joins/SQL | `sqlite` | `idb` (no query language) |
34
- | Structured, needs confidence/TTL/source/history | `memory` | `state`/`store` (no lifecycle semantics) |
35
- | Large or structured, browser-only | `idb` | `store` (size/shape limits) |
36
-
37
- `sqlite` and `memory` answer different questions — "what data do I have" vs. "what does the app
38
- believe, and how sure is it." Don't reach for `memory` just because a value happens to come from
39
- an LLM; if it doesn't need confidence scoring, TTL, or supersession history, plain `state`/`store`
40
- is simpler and correct.
41
-
42
- ## Server-side and multi-request code — read this first
43
-
44
- **`state` is a shared global namespace by default.** A value set in one request handler is
45
- visible to every other read of `state` in the same process. There is no automatic per-request
46
- or per-tab isolation.
47
-
48
- Before generating any server-side code (API route, edge function, worker) that could handle more
49
- than one user or request in the same process:
50
-
51
- 1. Create an explicit context per request/tenant: `const ctx = memorio.createContext(id)`, then
52
- read/write via `ctx.state`, never the bare global `state`.
53
- 2. **Generate the context ID from trusted server-side data** (authenticated user id, request-scoped
54
- token) — never directly from client-controlled input. Contexts are a key-prefix convention, not
55
- a hard boundary, so a spoofable ID is a real collision risk, not just a naming concern.
56
- 3. Treat context isolation as *organizational*, not a security boundary. It does not replace
57
- authorization checks at the backend layer — never use it as the only thing standing between
58
- one tenant's data and another's.
59
-
60
- If the code you're generating is client-side (a single browser tab, one user), bare `state` is
61
- fine — this concern is specific to shared-process server/edge code.
62
-
63
- ## Known rough edges — don't paper over these in generated code
64
-
65
- - **`store.quota()` returns `[0, 0]` for the `localStorage` backend** — it's a placeholder, not a
66
- real reading. Don't generate capacity-check logic that branches on its result for `store`.
67
- It may be meaningful for `idb`, but confirm before relying on it there too.
68
- - **`idb` is disabled outright in Node.js/Deno** (calls warn and no-op). Any code that might run
69
- outside a guaranteed browser context must guard: `if (idb.db.support())` or check
70
- `memorio.getCapabilities().hasIndexedDB` — don't rely on the no-op warning alone reaching a log
71
- anyone will see.
72
- - **`sqlite` persistence serializes the entire database on every flush** — not incremental. Never
73
- generate code that calls a persisting write inside a loop; batch writes in one transaction/run
74
- and persist once after the batch, per the README's guidance.
75
- - **`observer('state.some.path', cb)` paths are plain strings, unchecked against `state`'s actual
76
- shape.** A typo or a later rename fails *silently* — the observer just never fires again. Prefer
77
- `memorio.typed<T>()` + `registerSchema()` for anything you'd hate to have silently stop working,
78
- and consider `memorio.pathExists('state.some.path')` as a startup sanity check for
79
- observer-heavy code.
80
- - **`memory.context()` is rule-based (tags/type/confidence/recency), not embedding-based.** Don't
81
- imply semantic/meaning-based retrieval in comments or docs you generate — if the task genuinely
82
- needs free-text similarity search, pair `memorio.memory` (for lifecycle: confidence, TTL,
83
- supersession) with a separate embedding store, don't fake it with `context()` alone.
84
- - **`memorio.logger` records the literal value written**, including tokens or PII, in
85
- `getHistory()` / `exportLogs()`. Never enable it unconditionally on a production path that
86
- touches sensitive data, and never wire `exportLogs()` output to analytics or error reporters
87
- without redaction first.
88
- - **Nothing in `store`, `session`, `idb`, or `memory` is encrypted.** Don't store auth tokens or
89
- regulated data in any of these layers without adding your own encryption — flag it in code
90
- review comments if you see it happening.
91
-
92
- ## React usage
93
-
94
- `useObserver` has two modes — pick deliberately, don't mix them by accident:
95
-
96
- ```tsx
97
- // Auto-discovery: re-runs when any state path touched during the callback changes
98
- useObserver(() => { console.debug('counter:', state.counter) }, state.counter)
99
-
100
- // Explicit deps: only re-runs when the listed paths change
101
- useObserver(() => { console.debug('user:', state.user) }, [state.user])
102
- ```
103
-
104
- `useObserver` is a thin bridge onto `observer` — it inherits the "unchecked path string" caveat
105
- above for any path passed in string form.
106
-
107
- ## Cross-platform code
108
-
109
- Before calling `idb`, `sqlite`, or `devtools`, or before relying on `store`/`session` durability,
110
- check `memorio.getCapabilities()` rather than branching on `memorio.isNode()`/`isBrowser()` alone
111
- — capabilities can differ inside a single platform category (e.g. some edge runtimes expose
112
- `localStorage`, some don't). Generated code that assumes "browser == has IndexedDB" or
113
- "Node == no persistence at all" will be wrong on edge runtimes.
114
-
115
- ## Testing
116
-
117
- When testing `memory` lifecycle behavior (supersession, TTL, confidence), assert on the *history*
118
- being preserved, not just the current `recall()` value — `update()` is documented to supersede,
119
- not overwrite, and a test that only checks the latest value won't catch a regression that
120
- silently starts overwriting instead.
121
-
122
- ## Related examples
123
-
124
- See `examples/` in this repo for runnable reference implementations:
125
- `multi-tenant-context.ts`, `react-observer.tsx`, `semantic-memory.ts`,
126
- `sqlite-batched-writes.ts`, and `cross-platform-guards.ts`.
1
+ # AGENTS.md - working with `memorio`
2
+
3
+ Operational conventions for AI coding agents working in a repository that depends on `memorio`.
4
+ See `README.md` and `llms.txt` for the full API. This file is decision rules: what to reach for,
5
+ when, and the specific footguns this library's own docs flag.
6
+
7
+ ## Read this before generating any `memorio` code
8
+
9
+ `memorio`'s own `llms.txt` contains an explicit unresolved discrepancy:
10
+
11
+ > **Locking - VERIFY BEFORE PUBLISHING:** one source describes per-key locking
12
+ > (`state.config.lock()` freezes only `config`); another describes global locking
13
+ > (`state.lock()` / `state.unlock()` freezing everything). Do not generate code against this
14
+ > section until it's resolved against the real source.
15
+
16
+ **Do not write or suggest `.lock()` / `.unlock()` calls with a confident claim about scope**
17
+ (per-key vs. global) until you've confirmed the actual signature against the installed
18
+ package's type definitions or source - `node_modules/memorio/dist/*.d.ts` - in the target repo.
19
+ If you can't confirm it, say so explicitly rather than picking one behavior and presenting it
20
+ as fact.
21
+
22
+ ## Choosing a layer
23
+
24
+ Don't default to `state` for everything just because it's the one-liner in the README. Walk the
25
+ decision tree from the README's ["Which layer should I use"](./README.md#which-layer-should-i-use)
26
+ section, and in particular:
27
+
28
+ | If the data is... | Use | Not |
29
+ | --- | --- | --- |
30
+ | UI-reactive, doesn't need to survive reload | `state` | `store` (unnecessary persistence) |
31
+ | Small, must survive reload, any tab | `store` | `idb` (overkill for simple k/v) |
32
+ | Must survive reload, this tab only | `session` | `store` (wrong scope) |
33
+ | Relational, needs joins/SQL | `sqlite` | `idb` (no query language) |
34
+ | Structured, needs confidence/TTL/source/history | `memory` | `state`/`store` (no lifecycle semantics) |
35
+ | Large or structured, browser-only | `idb` | `store` (size/shape limits) |
36
+
37
+ `sqlite` and `memory` answer different questions - "what data do I have" vs. "what does the app
38
+ believe, and how sure is it." Don't reach for `memory` just because a value happens to come from
39
+ an LLM; if it doesn't need confidence scoring, TTL, or supersession history, plain `state`/`store`
40
+ is simpler and correct.
41
+
42
+ ## Server-side and multi-request code - read this first
43
+
44
+ **`state` is a shared global namespace by default.** A value set in one request handler is
45
+ visible to every other read of `state` in the same process. There is no automatic per-request
46
+ or per-tab isolation.
47
+
48
+ Before generating any server-side code (API route, edge function, worker) that could handle more
49
+ than one user or request in the same process:
50
+
51
+ 1. Create an explicit context per request/tenant: `const ctx = memorio.createContext(id)`, then
52
+ read/write via `ctx.state`, never the bare global `state`.
53
+ 2. **Generate the context ID from trusted server-side data** (authenticated user id, request-scoped
54
+ token) - never directly from client-controlled input. Contexts are a key-prefix convention, not
55
+ a hard boundary, so a spoofable ID is a real collision risk, not just a naming concern.
56
+ 3. Treat context isolation as *organizational*, not a security boundary. It does not replace
57
+ authorization checks at the backend layer - never use it as the only thing standing between
58
+ one tenant's data and another's.
59
+
60
+ If the code you're generating is client-side (a single browser tab, one user), bare `state` is
61
+ fine - this concern is specific to shared-process server/edge code.
62
+
63
+ ## Known rough edges - don't paper over these in generated code
64
+
65
+ - **`store.quota()` returns `[0, 0]` for the `localStorage` backend** - it's a placeholder, not a
66
+ real reading. Don't generate capacity-check logic that branches on its result for `store`.
67
+ It may be meaningful for `idb`, but confirm before relying on it there too.
68
+ - **`idb` is disabled outright in Node.js/Deno** (calls warn and no-op). Any code that might run
69
+ outside a guaranteed browser context must guard: `if (idb.db.support())` or check
70
+ `memorio.getCapabilities().hasIndexedDB` - don't rely on the no-op warning alone reaching a log
71
+ anyone will see.
72
+ - **`sqlite` persistence serializes the entire database on every flush** - not incremental. Never
73
+ generate code that calls a persisting write inside a loop; batch writes in one transaction/run
74
+ and persist once after the batch, per the README's guidance.
75
+ - **`observer('state.some.path', cb)` paths are plain strings, unchecked against `state`'s actual
76
+ shape.** A typo or a later rename fails *silently* - the observer just never fires again. Prefer
77
+ `memorio.typed<T>()` + `registerSchema()` for anything you'd hate to have silently stop working,
78
+ and consider `memorio.pathExists('state.some.path')` as a startup sanity check for
79
+ observer-heavy code.
80
+ - **`memory.context()` is rule-based (tags/type/confidence/recency), not embedding-based.** Don't
81
+ imply semantic/meaning-based retrieval in comments or docs you generate - if the task genuinely
82
+ needs free-text similarity search, pair `memorio.memory` (for lifecycle: confidence, TTL,
83
+ supersession) with a separate embedding store, don't fake it with `context()` alone.
84
+ - **`memorio.logger` records the literal value written**, including tokens or PII, in
85
+ `getHistory()` / `exportLogs()`. Never enable it unconditionally on a production path that
86
+ touches sensitive data, and never wire `exportLogs()` output to analytics or error reporters
87
+ without redaction first.
88
+ - **Nothing in `store`, `session`, `idb`, or `memory` is encrypted.** Don't store auth tokens or
89
+ regulated data in any of these layers without adding your own encryption - flag it in code
90
+ review comments if you see it happening.
91
+
92
+ ## React usage
93
+
94
+ `useObserver` has two modes - pick deliberately, don't mix them by accident:
95
+
96
+ ```tsx
97
+ // Auto-discovery: re-runs when any state path touched during the callback changes
98
+ useObserver(() => { console.debug('counter:', state.counter) }, state.counter)
99
+
100
+ // Explicit deps: only re-runs when the listed paths change
101
+ useObserver(() => { console.debug('user:', state.user) }, [state.user])
102
+ ```
103
+
104
+ `useObserver` is a thin bridge onto `observer` - it inherits the "unchecked path string" caveat
105
+ above for any path passed in string form.
106
+
107
+ ## Cross-platform code
108
+
109
+ Before calling `idb`, `sqlite`, or `devtools`, or before relying on `store`/`session` durability,
110
+ check `memorio.getCapabilities()` rather than branching on `memorio.isNode()`/`isBrowser()` alone
111
+ - capabilities can differ inside a single platform category (e.g. some edge runtimes expose
112
+ `localStorage`, some don't). Generated code that assumes "browser == has IndexedDB" or
113
+ "Node == no persistence at all" will be wrong on edge runtimes.
114
+
115
+ ## Testing
116
+
117
+ When testing `memory` lifecycle behavior (supersession, TTL, confidence), assert on the *history*
118
+ being preserved, not just the current `recall()` value - `update()` is documented to supersede,
119
+ not overwrite, and a test that only checks the latest value won't catch a regression that
120
+ silently starts overwriting instead.
121
+
122
+ ## Related examples
123
+
124
+ See `examples/` in this repo for runnable reference implementations:
125
+ `multi-tenant-context.ts`, `react-observer.tsx`, `semantic-memory.ts`,
126
+ `sqlite-batched-writes.ts`, and `cross-platform-guards.ts`.