agent-working-memory 0.15.9 → 0.16.1
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 +36 -0
- package/README.md +24 -12
- package/dist/adapters/common.d.ts +1 -1
- package/dist/adapters/common.d.ts.map +1 -1
- package/dist/adapters/common.js +33 -20
- package/dist/adapters/common.js.map +1 -1
- package/dist/core/embeddings.d.ts +1 -1
- package/dist/core/embeddings.js +1 -1
- package/dist/core/entity-extract.js +1 -1
- package/dist/core/query-expander.d.ts +4 -2
- package/dist/core/query-expander.d.ts.map +1 -1
- package/dist/core/query-expander.js +4 -2
- package/dist/core/query-expander.js.map +1 -1
- package/dist/core/recall-config.d.ts +1 -1
- package/dist/core/recall-config.d.ts.map +1 -1
- package/dist/core/recall-config.js +6 -1
- package/dist/core/recall-config.js.map +1 -1
- package/dist/core/recall-telemetry.d.ts +15 -0
- package/dist/core/recall-telemetry.d.ts.map +1 -0
- package/dist/core/recall-telemetry.js +108 -0
- package/dist/core/recall-telemetry.js.map +1 -0
- package/dist/core/rerank-window.d.ts +5 -4
- package/dist/core/rerank-window.d.ts.map +1 -1
- package/dist/core/rerank-window.js +5 -4
- package/dist/core/rerank-window.js.map +1 -1
- package/dist/core/reranker.d.ts +2 -1
- package/dist/core/reranker.d.ts.map +1 -1
- package/dist/core/reranker.js +33 -5
- package/dist/core/reranker.js.map +1 -1
- package/dist/core/salience.js +1 -1
- package/dist/core/salience.js.map +1 -1
- package/dist/core/token-budget.d.ts +2 -2
- package/dist/core/token-budget.js +2 -2
- package/dist/core/whoami.d.ts +1 -1
- package/dist/engine/activation.d.ts +30 -13
- package/dist/engine/activation.d.ts.map +1 -1
- package/dist/engine/activation.js +159 -50
- package/dist/engine/activation.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +98 -98
- package/dist/mcp.js.map +1 -1
- package/dist/storage/pglite.d.ts +28 -0
- package/dist/storage/pglite.d.ts.map +1 -1
- package/dist/storage/pglite.js +55 -0
- package/dist/storage/pglite.js.map +1 -1
- package/dist/storage/postgres.d.ts +28 -0
- package/dist/storage/postgres.d.ts.map +1 -1
- package/dist/storage/postgres.js +55 -0
- package/dist/storage/postgres.js.map +1 -1
- package/dist/storage/sqlite.d.ts +28 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +56 -0
- package/dist/storage/sqlite.js.map +1 -1
- package/llms.txt +437 -0
- package/package.json +106 -100
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/README.md +1 -1
- package/plugin/bin/awm-mcp-launcher.cjs +2 -2
- package/plugin/skills/awm-memory/SKILL.md +33 -20
- package/src/adapters/common.ts +33 -20
- package/src/core/embeddings.ts +1 -1
- package/src/core/entity-extract.ts +1 -1
- package/src/core/query-expander.ts +4 -2
- package/src/core/recall-config.ts +6 -1
- package/src/core/recall-telemetry.ts +131 -0
- package/src/core/rerank-window.ts +159 -158
- package/src/core/reranker.ts +150 -121
- package/src/core/salience.ts +1 -1
- package/src/core/token-budget.ts +160 -160
- package/src/core/whoami.ts +120 -120
- package/src/engine/activation.ts +159 -51
- package/src/index.ts +1 -1
- package/src/mcp.ts +1475 -1475
- package/src/storage/pglite.ts +49 -0
- package/src/storage/postgres.ts +49 -0
- package/src/storage/sqlite.ts +51 -0
package/llms.txt
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# AWM — agent-working-memory
|
|
2
|
+
|
|
3
|
+
> Persistent, local-first memory for AI coding agents. One Node process, one
|
|
4
|
+
> SQLite file, no cloud and no API keys. It decides what is worth keeping,
|
|
5
|
+
> returns the two or three memories that matter, and returns nothing when
|
|
6
|
+
> nothing fits.
|
|
7
|
+
|
|
8
|
+
**If you are a language model, read this file first.** It is written to be
|
|
9
|
+
ingested whole. It gives you the mental model, the setup for each situation,
|
|
10
|
+
the configuration that actually matters, and — most importantly — what breaks
|
|
11
|
+
when AWM is installed but not configured well. That last part is where almost
|
|
12
|
+
every disappointing result comes from.
|
|
13
|
+
|
|
14
|
+
Repository: https://github.com/CompleteIdeas/agent-working-memory
|
|
15
|
+
Package: `agent-working-memory` on npm · Apache-2.0 · Node >= 22
|
|
16
|
+
Docs site: https://completeideas.github.io/agent-working-memory/
|
|
17
|
+
|
|
18
|
+
Every number in this file is measured and reproducible from the repository.
|
|
19
|
+
Where a claim has a source, the source is named. Where something is unknown or
|
|
20
|
+
weak, it says so.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. What it is, and what it is not
|
|
25
|
+
|
|
26
|
+
**It is** a retrieval store with a salience filter in front of it and a decay
|
|
27
|
+
model underneath. An agent writes short notes as it works; AWM decides whether
|
|
28
|
+
each is worth keeping, embeds and indexes it, and hands back the few that match
|
|
29
|
+
a later query.
|
|
30
|
+
|
|
31
|
+
**It is not** a vector database, and it is not a transcript log. It does not
|
|
32
|
+
store your conversation. It does not traverse a graph to answer multi-hop
|
|
33
|
+
questions. It will not make an agent remember things it never wrote down.
|
|
34
|
+
|
|
35
|
+
**The honest version of who it suits:** projects with accumulated decisions
|
|
36
|
+
that outlive a single session, where an agent re-deriving the same context is a
|
|
37
|
+
real cost. On a small or short-lived project the overhead does not pay back.
|
|
38
|
+
`docs/known-limitations.md` and the "Is this for you?" section of `README.md`
|
|
39
|
+
both say this plainly; believe them.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. How retrieval actually works
|
|
44
|
+
|
|
45
|
+
This is the single most useful thing for you to understand, because the common
|
|
46
|
+
failure mode is writing memories that no channel can see.
|
|
47
|
+
|
|
48
|
+
A recall runs **three scoring channels**, then a reranker decides the order:
|
|
49
|
+
|
|
50
|
+
1. **Embedding** — `Xenova/bge-small-en-v1.5`, 384 dimensions, ONNX, downloaded
|
|
51
|
+
on first use and then run locally. The vector is built from
|
|
52
|
+
**`concept` + `content`**.
|
|
53
|
+
2. **BM25** — SQLite FTS5 over `concept`, `content` and `tags`. This is the
|
|
54
|
+
only channel that sees tags.
|
|
55
|
+
3. **Cross-encoder reranker** — `Xenova/ms-marco-MiniLM-L-6-v2`. It makes the
|
|
56
|
+
**final ordering**. Its passage is built from `concept` + `content`, plus
|
|
57
|
+
tags when `AWM_RERANK_TAGS=1`.
|
|
58
|
+
|
|
59
|
+
Then two things that matter less than they sound:
|
|
60
|
+
|
|
61
|
+
- **The association graph** contributes a score to about **85%** of top-3
|
|
62
|
+
results but changes the top-3 **set in 0%** of them. The reranker overrules
|
|
63
|
+
it; the graph's boost is capped and never wins. It is retained for the state
|
|
64
|
+
it accumulates — supersede chains, causal links, co-recall history — not for
|
|
65
|
+
today's ranking. (`tests/realstore-eval/graph-contribution-probe.ts`.)
|
|
66
|
+
- **ACT-R decay** scores every memory by age, so recall results shift as a
|
|
67
|
+
store ages. Benchmarks must pin the clock or they drift day to day.
|
|
68
|
+
|
|
69
|
+
### The three consequences you should act on
|
|
70
|
+
|
|
71
|
+
- **A word that exists only as a tag is invisible to two of the three
|
|
72
|
+
channels.** Tag it *and* write it in the body. Measured on a real 30k store:
|
|
73
|
+
**66%** of the topical terms a memory is tagged with never appear in its
|
|
74
|
+
text.
|
|
75
|
+
- **The reranker reads a 400-character window.** Anything past it is not seen
|
|
76
|
+
by the stage that decides final order. This is not a rounding error — on the
|
|
77
|
+
public benchmark corpus (`npm run bench:public`, 400 probes), `s@1` is
|
|
78
|
+
**97.3%** when the answer-bearing identifier sits inside the window and
|
|
79
|
+
**46.8%** when it sits beyond it. Put the decisive identifier **early**.
|
|
80
|
+
- **Multi-hop is your job.** "Who owns the table that the failing report
|
|
81
|
+
reads?" is two recalls that you make, not one traversal AWM performs. One hop
|
|
82
|
+
per call.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 3. Configuration that is not optional
|
|
87
|
+
|
|
88
|
+
`awm setup` installs three retrieval flags. **If they are missing, retrieval is
|
|
89
|
+
materially worse and nothing warns you.** This is the number one cause of "AWM
|
|
90
|
+
didn't find it."
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
AWM_RERANK2=1 # second-stage rerank by the cross-encoder's own score
|
|
94
|
+
AWM_RERANK_WINDOW=query # 400-char window centered on the densest query terms,
|
|
95
|
+
# instead of truncating from the start of the body
|
|
96
|
+
AWM_RERANK_TAGS=1 # tags joined into the rerank passage (+7.4pp s@1)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`AWM_RERANK_WINDOW=query` is the difference between the reranker reading the
|
|
100
|
+
first 400 characters and reading the 400 characters that actually contain the
|
|
101
|
+
query terms. On long memories — and real memories are long, median ~1,965
|
|
102
|
+
characters — that is the difference between finding the fact and missing it.
|
|
103
|
+
|
|
104
|
+
**Check yours before diagnosing anything else:**
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
awm doctor # reports config, live sidecars, store, and what is missing
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If you installed via something other than `awm setup` — hand-written MCP
|
|
111
|
+
config, a vendored copy, a container — assume these are unset until you have
|
|
112
|
+
seen otherwise.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 4. Setup, by scenario
|
|
117
|
+
|
|
118
|
+
Pick the one that matches. All of them end up at the same store by default:
|
|
119
|
+
**`~/.awm/memory.db`**.
|
|
120
|
+
|
|
121
|
+
> **Upgrade note.** Before 0.15.6 the default store lived *inside* the
|
|
122
|
+
> installed npm package, where `npm update` deleted it. If you are coming from
|
|
123
|
+
> an older version, find the old file before upgrading and move it to
|
|
124
|
+
> `~/.awm/memory.db`. 0.15.7 corrected the docs that still taught the old path.
|
|
125
|
+
|
|
126
|
+
### A. Claude Code, global (the normal case)
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npm install -g agent-working-memory
|
|
130
|
+
awm setup --global
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Restart Claude Code. **19 tools** appear. `awm setup` also writes agent
|
|
134
|
+
instructions into your global `CLAUDE.md` and installs hooks that checkpoint on
|
|
135
|
+
compaction and session end.
|
|
136
|
+
|
|
137
|
+
Flags: `--no-instructions` (skip the CLAUDE.md edit), `--no-hooks`, `--force`,
|
|
138
|
+
and `--no-prime`, which skips the **UserPromptSubmit prime hook** — the thing
|
|
139
|
+
that injects relevant memories on *every prompt*. Without it, as `awm doctor`
|
|
140
|
+
says, "memory reaches the agent only when it chooses to call memory_recall."
|
|
141
|
+
If an agent seems not to be using its memory, check this first.
|
|
142
|
+
|
|
143
|
+
### B. Separate pools per project
|
|
144
|
+
|
|
145
|
+
Not a different install — a different **agent id**. One database file, isolation
|
|
146
|
+
by agent. Give each project its own `.mcp.json` with a distinct `AWM_AGENT_ID`:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
~/work/project-a/.mcp.json → AWM_AGENT_ID: "project-a"
|
|
150
|
+
~/work/project-b/.mcp.json → AWM_AGENT_ID: "project-b"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Each then gets its own namespace in the same store. See
|
|
154
|
+
`docs/claude-code-setup.md` ("Separate Memory Pools").
|
|
155
|
+
|
|
156
|
+
### C. Claude Code plugin
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
awm plugin # prints where it is and how to install it
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
See `docs/plugin.md`. **Upgrading a plugin is not automatic** — a directory
|
|
163
|
+
marketplace does not pull new versions for you. This has bitten people; the doc
|
|
164
|
+
says so explicitly.
|
|
165
|
+
|
|
166
|
+
### D. Claude Desktop (MCPB bundle)
|
|
167
|
+
|
|
168
|
+
`npm run pack:mcpb` produces the bundle, or take it from a release. Install it
|
|
169
|
+
by double-clicking the `.mcpb`, dragging it onto the Claude Desktop window, or
|
|
170
|
+
**Settings → Extensions → Advanced settings → Install Extension…**. Desktop then
|
|
171
|
+
asks for two settings: **Memory database** (default `${HOME}/.awm/memory.db` —
|
|
172
|
+
leave it to share one store with Claude Code) and **Memory pool** (default
|
|
173
|
+
`work`). Restart Desktop and you should have nineteen tools.
|
|
174
|
+
|
|
175
|
+
**Sharing the store with your CLI install is the point** — Desktop and Claude
|
|
176
|
+
Code then see each other's memories. See `docs/desktop.md`.
|
|
177
|
+
|
|
178
|
+
### E. Server / container
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
awm serve --port 8400
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
HTTP API, `GET /health`, Docker recipe and Railway / Fly / Render notes in
|
|
185
|
+
`docs/deployment.md`. **Agent isolation on the HTTP API is by convention, not
|
|
186
|
+
enforcement** — any caller can claim any `agentId`. Do not expose it to
|
|
187
|
+
untrusted callers.
|
|
188
|
+
|
|
189
|
+
### F. Multi-agent / shared pool
|
|
190
|
+
|
|
191
|
+
Several processes against **one SQLite file** is supported and is the
|
|
192
|
+
interesting case: agent A writes, agent B recalls it on its next call, with no
|
|
193
|
+
network and no central service. SQLite WAL makes this multi-process safe.
|
|
194
|
+
|
|
195
|
+
**The thing that silently breaks it: unpinned agent identity.** If a session
|
|
196
|
+
does not set an explicit agent id, it lands in a per-directory fallback space
|
|
197
|
+
that scoped recall never sees. The memory is written and is simply invisible to
|
|
198
|
+
everyone else. Always set the identity explicitly, and call `memory_whoami` if
|
|
199
|
+
you are unsure which space you are in.
|
|
200
|
+
|
|
201
|
+
Cross-agent recall is opt-in per call via the `workspace` parameter; the
|
|
202
|
+
default is agent-scoped.
|
|
203
|
+
|
|
204
|
+
### G. Embedded in your own app
|
|
205
|
+
|
|
206
|
+
Import the store and engine directly — see `examples/` and
|
|
207
|
+
`docs/architecture.md`. `tests/longmem-eval/runner.ts` is a compact, working
|
|
208
|
+
example of seeding a store through the real write pipeline and querying it.
|
|
209
|
+
|
|
210
|
+
### Backend choice
|
|
211
|
+
|
|
212
|
+
- **SQLite** (default) — multi-process safe via WAL. Use this.
|
|
213
|
+
- **PGlite** — embedded Postgres with pgvector. **Single-process only**: a
|
|
214
|
+
second process against the same directory aborts. Only for single-process
|
|
215
|
+
embedding.
|
|
216
|
+
- **Networked Postgres** — a genuinely shared backend across machines.
|
|
217
|
+
|
|
218
|
+
Auto-detected: if `AWM_DB_PATH` points at an existing directory it is PGlite,
|
|
219
|
+
a file is SQLite.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 5. The 19 tools
|
|
224
|
+
|
|
225
|
+
**Lifecycle** — `memory_restore` (session start), `memory_task_begin`,
|
|
226
|
+
`memory_task_end`, `memory_checkpoint`.
|
|
227
|
+
|
|
228
|
+
**Core** — `memory_write`, `memory_recall`.
|
|
229
|
+
|
|
230
|
+
**Correction** — `memory_supersede` (replace a stale fact; the new version
|
|
231
|
+
inherits the old one's associations), `memory_retract` (it was wrong),
|
|
232
|
+
`memory_feedback` (useful / not-useful, after you used a result).
|
|
233
|
+
|
|
234
|
+
**Tasks** — `memory_task_add`, `memory_task_update`, `memory_task_list`,
|
|
235
|
+
`memory_task_next`.
|
|
236
|
+
|
|
237
|
+
**Introspection** — `memory_whoami` (identity, store, backend, ports, sibling
|
|
238
|
+
agent spaces — call this *first* whenever anything about AWM's own state is in
|
|
239
|
+
question), `memory_stats`.
|
|
240
|
+
|
|
241
|
+
**Onboarding** — `onboard_scan`, `onboard_questions`.
|
|
242
|
+
|
|
243
|
+
**Output control** — `compress_output`, `retrieve_original`.
|
|
244
|
+
|
|
245
|
+
### Recall parameters worth knowing
|
|
246
|
+
|
|
247
|
+
- `granularity: 'compact'` — every result carries a ~200-char query-aware
|
|
248
|
+
snippet. Saves roughly 70% of recall output tokens when you expect to scan
|
|
249
|
+
several results. `'auto'` is confidence-adaptive.
|
|
250
|
+
- `require_confidence` — abstain rather than return noise. Default is a light
|
|
251
|
+
`0.05`. **Do not raise it for ordinary recall**: a miss is expensive because
|
|
252
|
+
you then go and read the codebase instead (~2,106 tokens, measured), and
|
|
253
|
+
thresholds of 0.20+ cut net tokens saved by 25% in `tests/abstention-eval`.
|
|
254
|
+
Raise it only for push-style use where nobody asked.
|
|
255
|
+
- `workspace` — cross-agent recall, opt-in.
|
|
256
|
+
- `limit` — default **3**, and this is a measured choice, not a guess. On 400
|
|
257
|
+
real-store probes k=3 is the only **token-positive** setting: **+115 tokens
|
|
258
|
+
per recall, against -680 at k=5**. It is also 41% faster at p50, because
|
|
259
|
+
`limit` sizes the cross-encoder rerank pool and reranking is ~90% of warm
|
|
260
|
+
recall time. The cost is ~0.5pp `success@1` versus k=5 — about 3 queries in
|
|
261
|
+
400, inside noise. Raise it deliberately when you want breadth for
|
|
262
|
+
orientation; leave it alone when you want a specific fact.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 6. Writing so that recall can find it
|
|
267
|
+
|
|
268
|
+
Recall quality is decided when you write. Be slightly more verbose at the front
|
|
269
|
+
than feels natural: the head of the body is what all three channels weight most.
|
|
270
|
+
|
|
271
|
+
- **Lead with the fact or rule.** Not the backstory. "Don't mock the database
|
|
272
|
+
in integration tests" first; the reason second.
|
|
273
|
+
- **Put the decisive identifier early** — before character 400 if you can. See
|
|
274
|
+
§2.
|
|
275
|
+
- **Include two or more retrievable identifiers**: file paths, function names,
|
|
276
|
+
column names, error strings, ticket ids. `SettlementService.closeRun()`
|
|
277
|
+
beats "the accounting code".
|
|
278
|
+
- **Name the category as well as the specifics.** A memory about scaling an
|
|
279
|
+
Azure App Service Plan that never contains the words "Azure" or "App Service
|
|
280
|
+
Plan" cannot be found by them — a real miss, and the reason this rule exists.
|
|
281
|
+
- **Write in the vocabulary of the future question**, not your own summary of
|
|
282
|
+
it.
|
|
283
|
+
- **Say why**, for any rule. A rule without a reason cannot be applied to a
|
|
284
|
+
case you did not anticipate.
|
|
285
|
+
|
|
286
|
+
### Memory classes
|
|
287
|
+
|
|
288
|
+
- `canonical` — source-of-truth. 0.7 salience floor, never staged. Use for
|
|
289
|
+
decisions, requirements, and anything other agents must be able to recall.
|
|
290
|
+
- `working` — the default. Findings and observations. Salience-gated, so a
|
|
291
|
+
weak write may land in staging rather than active.
|
|
292
|
+
- `ephemeral` — decays fast.
|
|
293
|
+
|
|
294
|
+
### Content fade
|
|
295
|
+
|
|
296
|
+
Un-recalled memories gradually fade their **content** while keeping their cue
|
|
297
|
+
pathways — concept, tags and embedding stay intact, so they remain findable.
|
|
298
|
+
Recall resets the clock. Practical upshot: **do not purge memories to save
|
|
299
|
+
space, and do not mark everything canonical to fight fade** (canonical changes
|
|
300
|
+
salience gating at write time, not fade). Use `memory_supersede` for stale
|
|
301
|
+
facts.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## 7. Gotchas, in the order they bite
|
|
306
|
+
|
|
307
|
+
1. **Retrieval flags unset.** §3. Silent, and the largest single effect.
|
|
308
|
+
2. **The decisive identifier sits past character 400.** 97.3% -> 46.8% on the
|
|
309
|
+
public corpus.
|
|
310
|
+
3. **Terms that exist only in tags.** Invisible to the embedding and (without
|
|
311
|
+
`AWM_RERANK_TAGS=1`) to the reranker.
|
|
312
|
+
4. **Unpinned agent identity.** Writes vanish into a per-directory UUID space.
|
|
313
|
+
`memory_whoami`.
|
|
314
|
+
5. **A running MCP connection never reloads code.** Rebuilding AWM on disk has
|
|
315
|
+
zero effect on a session whose connection already started — a child process
|
|
316
|
+
keeps the code it loaded at spawn. Restart the session, or reconnect, then
|
|
317
|
+
confirm with `memory_whoami`. Do not infer the running version from
|
|
318
|
+
`package.json`.
|
|
319
|
+
6. **Cold start is ~1.5s; warm recall is ~480ms** (measured, k=3, 11k-engram
|
|
320
|
+
store, `npm run profile:recall`) — and on a genuinely fresh install, after a
|
|
321
|
+
one-time **~600 MB** model download, because **nothing is bundled**: no ONNX
|
|
322
|
+
ships in the npm tarball or the MCPB bundle, and all three models fetch lazily
|
|
323
|
+
into `AWM_CACHE_DIR` > `HF_HOME` > `<packageRoot>/data/models`. The
|
|
324
|
+
cross-encoder is **83%** of the warm figure, and its first inference is
|
|
325
|
+
450-670ms of the cold one — so cold start is model load, not a slow store, and
|
|
326
|
+
it is paid once per process. Never put a cold recall on a latency-critical
|
|
327
|
+
path. `AWM_RERANKER_DTYPE=q8` cuts total latency **26-33%** on three suites
|
|
328
|
+
for **one query in 450** of accuracy (re-measured 2026-10-09 on the shipped
|
|
329
|
+
pipeline: identifier success@1 unchanged at 93.0%, topic 92.2% -> 92.0%;
|
|
330
|
+
correct silence unmoved on all three suites, success@5 unmoved on both
|
|
331
|
+
private suites and +0.5pp on the public corpus, inside its 4pp noise floor) and it shrinks the reranker
|
|
332
|
+
ONNX file it loads from 91 MB to 23 MB. fp32 is still the shipped default:
|
|
333
|
+
q8 is a documented **latency-first operating mode**, not a hidden tuning
|
|
334
|
+
flag, and it CHANGES RANKING OUTCOMES rather than being a free speedup. It is
|
|
335
|
+
read once at module import and the model is then cached, so it needs a
|
|
336
|
+
PROCESS RESTART — setting it against a running AWM does nothing, and an MCP
|
|
337
|
+
session must be restarted or reconnected. To check latency on your own store
|
|
338
|
+
from any install, set `AWM_PROFILE_RECALL=1`; checking ACCURACY needs derived
|
|
339
|
+
ground truth and therefore a repo checkout, because scripts/ and tests/ are
|
|
340
|
+
not in the npm tarball. See docs/deployment.md "Operating modes". `q4` is
|
|
341
|
+
dominated — same accuracy, only -3% latency, 6.1s cold start. See
|
|
342
|
+
docs/recall-latency.md.
|
|
343
|
+
7. **The embedding model is fixed per store.** Changing `AWM_EMBED_MODEL` or
|
|
344
|
+
`AWM_EMBED_DIMS` against an existing corpus leaves half the store scoring 0
|
|
345
|
+
on the vector channel. AWM warns once per process; re-embed the whole store
|
|
346
|
+
or revert.
|
|
347
|
+
8. **Invocation depends on the harness, not on AWM.** AWM cannot make an agent
|
|
348
|
+
call it. If the agent is not writing memories, the instructions are the
|
|
349
|
+
problem, not the store.
|
|
350
|
+
9. **PGlite is single-process.** §4.
|
|
351
|
+
10. **HTTP agent isolation is advisory.** §4E.
|
|
352
|
+
11. **The feedback loop has almost no signal yet** — overwhelmingly
|
|
353
|
+
`useful=1`, so do not expect `memory_feedback` to be visibly improving
|
|
354
|
+
ranking today.
|
|
355
|
+
12. **Consolidation summaries are concatenations**, not synthesis. Do not read
|
|
356
|
+
them as insight.
|
|
357
|
+
13. **The salience filter is tuned for engineering work.** Other domains will
|
|
358
|
+
need different tuning.
|
|
359
|
+
14. **Schema migrations are additive, not versioned.** Downgrading is not
|
|
360
|
+
supported.
|
|
361
|
+
|
|
362
|
+
`docs/known-limitations.md` is the maintained version of this list, with
|
|
363
|
+
evidence for each item and a section of things that are **no longer true**, so
|
|
364
|
+
they are not re-reported. Read it before filing anything.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## 8. Troubleshooting
|
|
369
|
+
|
|
370
|
+
**Nothing is recalled, or the wrong things are.**
|
|
371
|
+
`awm doctor` → are the three flags from §3 set? Then: does the memory's body
|
|
372
|
+
contain the words you are querying with (§2)? Then: are you in the agent space
|
|
373
|
+
that holds it (`memory_whoami`)? Then: reformulate once or twice with the
|
|
374
|
+
domain's nouns rather than generic English. Three empty reformulations means
|
|
375
|
+
the memory probably is not there — go read the code.
|
|
376
|
+
|
|
377
|
+
**Memories are written but nobody else sees them.** Unpinned agent identity.
|
|
378
|
+
Gotcha 4.
|
|
379
|
+
|
|
380
|
+
**A code change had no effect.** Gotcha 5. Restart the session.
|
|
381
|
+
|
|
382
|
+
**"EMBEDDING DIMENSION MISMATCH" in the logs.** Gotcha 7.
|
|
383
|
+
|
|
384
|
+
**It was working and now the store is empty after an upgrade.** You were on
|
|
385
|
+
<0.15.6 with the store inside the package directory. §4.
|
|
386
|
+
|
|
387
|
+
Deeper: `docs/troubleshooting.md`, `docs/faq.md`, `docs/unknowns.md`.
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## 9. Reproducing the measurements
|
|
392
|
+
|
|
393
|
+
Two benchmark paths, and the difference matters:
|
|
394
|
+
|
|
395
|
+
- **`npm run bench`** — the published numbers in `docs/benchmarks-current.md`.
|
|
396
|
+
Runs against a frozen snapshot of a real ~30,000-memory store. **That corpus
|
|
397
|
+
is private and is not in the repository**, so this command only works for the
|
|
398
|
+
maintainer. The generators are published; the data is not.
|
|
399
|
+
|
|
400
|
+
- **`npm run bench:public:build` then `npm run bench:public`** — fully
|
|
401
|
+
reproducible by anyone. Builds a synthetic corpus from a seeded generator
|
|
402
|
+
(`tests/realstore-eval/public-corpus.mjs`), derives ground truth with **the
|
|
403
|
+
same hold-out code** as the private path, and scores with the same runner.
|
|
404
|
+
|
|
405
|
+
**Mind the noise floor.** Two full builds differing only in corpus seed gave
|
|
406
|
+
`s@1` 56.3% and 52.0% — the corpus *shape* reproduces to 0.2pp and every
|
|
407
|
+
qualitative result holds, but the absolute moves about 4 points between draws.
|
|
408
|
+
A 2pp move is not a result; confirm on a second seed.
|
|
409
|
+
|
|
410
|
+
**Do not quote public-benchmark numbers as the published ones.** The synthetic
|
|
411
|
+
corpus scores *lower*, because generated prose is more self-similar than real
|
|
412
|
+
prose and same-domain neighbors are harder to separate. Use it for the method
|
|
413
|
+
and for deltas, not for absolutes.
|
|
414
|
+
|
|
415
|
+
Ground truth is derived by **unique-identifier hold-out**: an identifier that
|
|
416
|
+
appears in exactly one active memory — verified through FTS, the real retrieval
|
|
417
|
+
path — gives a mechanically checkable right answer. Adversarial probes are
|
|
418
|
+
included so that **correct silence scores positively**, which is the opposite
|
|
419
|
+
of what LoCoMo does. `docs/benchmarks.md` explains why LoCoMo was retired.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## 10. Further reading
|
|
424
|
+
|
|
425
|
+
| For | Read |
|
|
426
|
+
|---|---|
|
|
427
|
+
| Deciding whether to adopt | `docs/for-decision-makers.md` |
|
|
428
|
+
| The mechanism, walked through | `docs/walkthrough.md` |
|
|
429
|
+
| Architecture | `docs/architecture.md` |
|
|
430
|
+
| Cognitive model (ACT-R, Hebbian, fade) | `docs/cognitive-model.md` |
|
|
431
|
+
| Recall quality at scale | `docs/using-awm-at-scale.md` |
|
|
432
|
+
| Weaknesses, with evidence | `docs/known-limitations.md` |
|
|
433
|
+
| What we do not know yet | `docs/unknowns.md` |
|
|
434
|
+
| Benchmark method and history | `docs/benchmarks.md` |
|
|
435
|
+
| Current scores, machine-generated | `docs/benchmarks-current.md` |
|
|
436
|
+
| Agent-facing instructions | `AGENTS.md`, `plugin/skills/awm-memory/SKILL.md` |
|
|
437
|
+
| Setup guides | `docs/quickstart.md`, `docs/claude-code-setup.md`, `docs/team-setup-guide.md`, `docs/plugin.md`, `docs/desktop.md`, `docs/deployment.md` |
|
package/package.json
CHANGED
|
@@ -1,100 +1,106 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "agent-working-memory",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"memory",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"build
|
|
31
|
-
"build:
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"test
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"test:
|
|
41
|
-
"test:
|
|
42
|
-
"test:
|
|
43
|
-
"test:
|
|
44
|
-
"test:
|
|
45
|
-
"test:
|
|
46
|
-
"test:
|
|
47
|
-
"test:
|
|
48
|
-
"test:
|
|
49
|
-
"test:
|
|
50
|
-
"test:
|
|
51
|
-
"
|
|
52
|
-
"eval
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-working-memory",
|
|
3
|
+
"version": "0.16.1",
|
|
4
|
+
"mcpName": "io.github.CompleteIdeas/agent-working-memory",
|
|
5
|
+
"description": "Persistent, local-first memory for AI agents. Selective by design: filters what's worth keeping, links what's related, and says nothing when it doesn't know. SQLite + ONNX, no cloud, no API keys.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"ai-agents",
|
|
8
|
+
"agent-memory",
|
|
9
|
+
"memory",
|
|
10
|
+
"mcp",
|
|
11
|
+
"model-context-protocol",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"local-first",
|
|
14
|
+
"sqlite",
|
|
15
|
+
"onnx",
|
|
16
|
+
"retrieval",
|
|
17
|
+
"cognitive-architecture",
|
|
18
|
+
"act-r",
|
|
19
|
+
"hebbian",
|
|
20
|
+
"embeddings",
|
|
21
|
+
"reranker",
|
|
22
|
+
"typescript"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.js",
|
|
26
|
+
"bin": {
|
|
27
|
+
"awm": "dist/cli.js"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"build:plugin": "node scripts/build-plugin.mjs",
|
|
32
|
+
"build:mcpb": "node scripts/build-mcpb.mjs",
|
|
33
|
+
"pack:mcpb": "node scripts/build-mcpb.mjs --pack",
|
|
34
|
+
"prepublishOnly": "npm run build && npm run build:plugin && npm run build:mcpb && npm run check:release",
|
|
35
|
+
"dev": "tsx watch src/index.ts",
|
|
36
|
+
"start": "node dist/index.js",
|
|
37
|
+
"test": "vitest",
|
|
38
|
+
"test:run": "vitest run",
|
|
39
|
+
"mcp": "tsx src/mcp.ts",
|
|
40
|
+
"test:mcp": "tsx tests/mcp-smoke.ts",
|
|
41
|
+
"test:self": "tsx tests/self-test/runner.ts",
|
|
42
|
+
"test:workday": "tsx tests/workday-eval/runner.ts",
|
|
43
|
+
"test:locomo": "tsx tests/locomo-eval/runner.ts",
|
|
44
|
+
"test:tokens": "tsx tests/token-savings/runner.ts",
|
|
45
|
+
"test:realworld": "tsx tests/realworld-eval/runner.ts",
|
|
46
|
+
"test:ab": "tsx tests/ab-test/runner.ts",
|
|
47
|
+
"test:sleep": "tsx tests/sleep-cycle/runner.ts",
|
|
48
|
+
"test:stress": "tsx tests/stress-test/runner.ts",
|
|
49
|
+
"test:edge": "tsx tests/edge-cases/runner.ts",
|
|
50
|
+
"test:pilot": "tsx tests/pilot-metrics/runner.ts",
|
|
51
|
+
"test:perf": "tsx tests/perf-test/runner.ts",
|
|
52
|
+
"eval": "tsx tests/eval/run.ts",
|
|
53
|
+
"eval:generate": "tsx tests/eval/generate.ts",
|
|
54
|
+
"test:all": "vitest run && tsx tests/mcp-smoke.ts",
|
|
55
|
+
"check:release": "node scripts/check-release.mjs",
|
|
56
|
+
"bench": "node scripts/bench-current.mjs",
|
|
57
|
+
"bench:public:build": "tsx tests/realstore-eval/build-public-snapshot.ts",
|
|
58
|
+
"bench:public": "node scripts/bench-public.mjs",
|
|
59
|
+
"profile:recall": "node scripts/profile-recall.mjs",
|
|
60
|
+
"test:docker": "bash scripts/docker-release-test.sh",
|
|
61
|
+
"test:linux": "bash scripts/docker-release-test.sh linux",
|
|
62
|
+
"test:desktop": "bash scripts/docker-release-test.sh desktop"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=22.0.0"
|
|
66
|
+
},
|
|
67
|
+
"license": "Apache-2.0",
|
|
68
|
+
"files": [
|
|
69
|
+
"dist/",
|
|
70
|
+
"src/",
|
|
71
|
+
"plugin/",
|
|
72
|
+
".claude-plugin/",
|
|
73
|
+
"package.json",
|
|
74
|
+
"README.md",
|
|
75
|
+
"AGENTS.md",
|
|
76
|
+
"llms.txt",
|
|
77
|
+
"LICENSE"
|
|
78
|
+
],
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"@electric-sql/pglite": "0.5.6",
|
|
81
|
+
"@electric-sql/pglite-pgvector": "^0.0.7",
|
|
82
|
+
"@huggingface/transformers": "^4.3.1",
|
|
83
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
84
|
+
"@toon-format/toon": "^2.3.0",
|
|
85
|
+
"better-sqlite3": "^12.6.2",
|
|
86
|
+
"fastify": "^5.12.5",
|
|
87
|
+
"pg": "^8.13.1",
|
|
88
|
+
"zod": "^4.3.6"
|
|
89
|
+
},
|
|
90
|
+
"devDependencies": {
|
|
91
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
92
|
+
"@types/node": "^25.3.5",
|
|
93
|
+
"@types/pg": "^8.11.10",
|
|
94
|
+
"tsx": "^4.21.0",
|
|
95
|
+
"typescript": "^5.9.3",
|
|
96
|
+
"vitest": "^4.0.18"
|
|
97
|
+
},
|
|
98
|
+
"repository": {
|
|
99
|
+
"type": "git",
|
|
100
|
+
"url": "git+https://github.com/CompleteIdeas/agent-working-memory.git"
|
|
101
|
+
},
|
|
102
|
+
"homepage": "https://github.com/CompleteIdeas/agent-working-memory#readme",
|
|
103
|
+
"bugs": {
|
|
104
|
+
"url": "https://github.com/CompleteIdeas/agent-working-memory/issues"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "awm",
|
|
3
3
|
"displayName": "Agent Working Memory",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.16.1",
|
|
5
5
|
"description": "Persistent, local-first memory for AI agents. Selective by design: filters what's worth keeping, links what's related, and says nothing when it doesn't know. SQLite + ONNX, no cloud, no API keys.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Robert Winter"
|