@memstack/core 0.7.3 → 0.8.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/README.md +234 -7
- package/dist/index.cjs +665 -116
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +178 -5
- package/dist/index.d.ts +178 -5
- package/dist/index.js +660 -117
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# MemStack
|
|
2
2
|
|
|
3
|
-
> Implementation priority is maintained in the [canonical roadmap](docs/ROADMAP.md).
|
|
4
|
-
|
|
5
3
|
> The open-source memory layer for AI agents — store, retrieve, summarize, and prune.
|
|
6
4
|
|
|
7
5
|
[](https://www.npmjs.com/package/@memstack/core)
|
|
8
6
|
[](https://skills.sh/isiomaC/memstack)
|
|
9
7
|
[](https://registry.modelcontextprotocol.io/?q=io.github.isiomaC%2Fmemstack)
|
|
8
|
+
[](https://glama.ai/mcp/servers/isiomaC/memstack)
|
|
10
9
|
[](https://github.com/isiomaC/memstack/actions/workflows/ci.yml)
|
|
11
10
|
[](https://opensource.org/licenses/MIT)
|
|
12
11
|
[](https://gitmcp.io/isiomaC/memstack)
|
|
@@ -15,11 +14,11 @@
|
|
|
15
14
|
# Use MemStack in your application
|
|
16
15
|
npm install @memstack/core
|
|
17
16
|
|
|
18
|
-
# Give your coding
|
|
19
|
-
npx skills add isiomaC/memstack
|
|
17
|
+
# Give your coding agents the MemStack skill (-g: every project; omit it for this project only)
|
|
18
|
+
npx skills add isiomaC/memstack -g
|
|
20
19
|
```
|
|
21
20
|
|
|
22
|
-
`@memstack/core` is the runtime SDK; the Agent Skill teaches compatible coding agents how to integrate and operate MemStack correctly.
|
|
21
|
+
`@memstack/core` is the runtime SDK; the Agent Skill teaches compatible coding agents how to integrate and operate MemStack correctly. Without `-g`, the skill installs into the current project (`.agents/skills/`, plus a `.claude/skills/` link for Claude Code). Update it later with `npx skills update`.
|
|
23
22
|
|
|
24
23
|
**The problem:** AI agents forget. Every interaction starts from zero. You either stuff everything into the context window (expensive, slow, degrades output quality) or the agent has no memory of past conversations.
|
|
25
24
|
|
|
@@ -27,12 +26,21 @@ npx skills add isiomaC/memstack
|
|
|
27
26
|
|
|
28
27
|
Think of it as the open-source alternative to [Mem0](https://mem0.ai/) — pluggable storage, bring your own LLM, zero vendor lock-in.
|
|
29
28
|
|
|
29
|
+
[](https://glama.ai/mcp/servers/isiomaC/memstack)
|
|
30
|
+
|
|
30
31
|
---
|
|
31
32
|
|
|
32
33
|
## Table of Contents
|
|
33
34
|
|
|
34
35
|
- [Why MemStack](#why-memstack)
|
|
35
36
|
- [Quick Start](#quick-start)
|
|
37
|
+
- [Harness Memory (Claude Code & Codex)](#harness-memory-claude-code--codex)
|
|
38
|
+
- [How it works](#how-it-works)
|
|
39
|
+
- [Commands](#commands)
|
|
40
|
+
- [What `connect` changes](#what-connect-changes)
|
|
41
|
+
- [Projects](#projects)
|
|
42
|
+
- [Storage](#storage)
|
|
43
|
+
- [Troubleshooting](#troubleshooting)
|
|
36
44
|
- [The Memory Pipeline](#the-memory-pipeline)
|
|
37
45
|
- [Store](#1-store)
|
|
38
46
|
- [Retrieve](#2-retrieve)
|
|
@@ -55,7 +63,9 @@ Think of it as the open-source alternative to [Mem0](https://mem0.ai/) — plugg
|
|
|
55
63
|
- [Memory Subsystem](#memory-subsystem)
|
|
56
64
|
- [Export / Import](#export-import)
|
|
57
65
|
- [Health & Close](#health-close)
|
|
66
|
+
- [Harness Memory API](#harness-memory-api)
|
|
58
67
|
- [Configuration](#configuration)
|
|
68
|
+
- [Harness configuration file](#harness-configuration-file)
|
|
59
69
|
- [Advanced Usage](#advanced-usage)
|
|
60
70
|
- [Custom Storage](#custom-storage)
|
|
61
71
|
- [Custom LLM / Embedding](#custom-llm-embedding)
|
|
@@ -94,6 +104,24 @@ Think of it as the open-source alternative to [Mem0](https://mem0.ai/) — plugg
|
|
|
94
104
|
|
|
95
105
|
## Quick Start
|
|
96
106
|
|
|
107
|
+
### Claude Code and Codex
|
|
108
|
+
|
|
109
|
+
Persistent memory across agent harnesses: what you tell Claude Code, Codex
|
|
110
|
+
recalls in the same project, and the reverse.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm install -g @memstack/cli @memstack/mcp better-sqlite3@^11.10.0 # MemStack never installs storage drivers for you
|
|
114
|
+
memstack init # choose an LLM provider and a store
|
|
115
|
+
memstack connect claude-code
|
|
116
|
+
memstack connect codex
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Then, in Claude Code: "Remember that this project uses Hono." In Codex, in the
|
|
120
|
+
same repository: "What framework does this project use?" Codex answers Hono.
|
|
121
|
+
See [Harness Memory](#harness-memory-claude-code--codex) for how it works.
|
|
122
|
+
|
|
123
|
+
### As a library
|
|
124
|
+
|
|
97
125
|
```bash
|
|
98
126
|
npm install @memstack/core
|
|
99
127
|
```
|
|
@@ -122,7 +150,7 @@ import { MemStack, OpenAILLMAdapter, InMemoryStorageAdapter } from "@memstack/co
|
|
|
122
150
|
const llm = new OpenAILLMAdapter({
|
|
123
151
|
apiKey: process.env.DEEPSEEK_API_KEY!,
|
|
124
152
|
baseURL: "https://api.deepseek.com/v1",
|
|
125
|
-
defaultModel: "deepseek-
|
|
153
|
+
defaultModel: "deepseek-flash",
|
|
126
154
|
});
|
|
127
155
|
|
|
128
156
|
const memstack = new MemStack({
|
|
@@ -197,6 +225,113 @@ console.log(response.text);
|
|
|
197
225
|
|
|
198
226
|
---
|
|
199
227
|
|
|
228
|
+
## Harness Memory (Claude Code & Codex)
|
|
229
|
+
|
|
230
|
+
Coding agents forget everything between sessions, and they don't share what
|
|
231
|
+
they learn with each other. MemStack gives Claude Code and Codex one memory
|
|
232
|
+
per project: a decision made with one agent is known to the other, and to
|
|
233
|
+
every later session.
|
|
234
|
+
|
|
235
|
+
### How it works
|
|
236
|
+
|
|
237
|
+
- **Saving.** Each agent gets five MemStack tools (`memory_store`,
|
|
238
|
+
`memory_retrieve`, `memory_get`, `memory_delete`, `memory_stats`) through
|
|
239
|
+
the MCP harness profile. When you say "remember that…", or the agent learns
|
|
240
|
+
a durable fact, decision, preference, or rule, it calls `memory_store`.
|
|
241
|
+
MemStack asks your LLM for a few topic tags, so "uses Hono" can later be
|
|
242
|
+
found by "which framework?". If tagging fails, the memory is still saved.
|
|
243
|
+
- **Recalling.** A session-start hook loads the project's most important
|
|
244
|
+
memories into every new session, so the agent starts out knowing them.
|
|
245
|
+
During a session the agent calls `memory_retrieve` with plain questions.
|
|
246
|
+
Recall runs locally with keyword ranking (BM25 with stemming) and never
|
|
247
|
+
calls the LLM, so it is fast and works offline.
|
|
248
|
+
- **Scope.** Memories belong to the current project. Preferences that apply
|
|
249
|
+
everywhere can be saved as global (`scope: "global"`) and are recalled in
|
|
250
|
+
every project. One project can never read or delete another's memories.
|
|
251
|
+
- **Safety.** Agents don't get bulk or destructive tools, secrets are never to
|
|
252
|
+
be stored (the agents are told so), and the LLM key stays in
|
|
253
|
+
`~/.memstack/config.json` (readable only by you), never in agent configs.
|
|
254
|
+
|
|
255
|
+
### Commands
|
|
256
|
+
|
|
257
|
+
| Command | What it does |
|
|
258
|
+
|---|---|
|
|
259
|
+
| `memstack init` | Choose an LLM provider and a store. Verifies the key with a real request and writes `~/.memstack/config.json`. Non-interactive: `--provider`, `--base-url`, `--model`, `--api-key-env <VAR>`, `--store`, `--path`, `--url`, `--yes`. |
|
|
260
|
+
| `memstack connect <claude-code\|codex>` | Registers MemStack with the agent. Checks the server works first, and undoes everything if a step fails. `--dry-run` shows the changes; `--no-hooks` and `--no-agents-md` skip those parts. |
|
|
261
|
+
| `memstack disconnect <claude-code\|codex>` | Removes everything `connect` added. Your memories are kept. |
|
|
262
|
+
| `memstack status` | Config, storage, the current project, and what each agent has connected. |
|
|
263
|
+
| `memstack doctor` | Diagnoses setup problems and prints the fix for each. `--live` also tests the LLM key. |
|
|
264
|
+
| `memstack memories [query]` | Lists or searches this project's memories. `--global` for global ones, `--delete <id>` to remove one. |
|
|
265
|
+
| `memstack project` | Shows this repository's project ID. `project pin <id>` fixes it in `.memstack.json`; `project merge <old-id>` moves memories from an old ID. |
|
|
266
|
+
|
|
267
|
+
### What `connect` changes
|
|
268
|
+
|
|
269
|
+
`connect` changes only these entries, backs up each file first, and
|
|
270
|
+
`disconnect` restores each file exactly:
|
|
271
|
+
|
|
272
|
+
| Agent | File | Change |
|
|
273
|
+
|---|---|---|
|
|
274
|
+
| Claude Code | `~/.claude.json` | A user-scope `memstack` MCP server, added with `claude mcp add-json`. |
|
|
275
|
+
| Claude Code | `~/.claude/settings.json` | A `SessionStart` hook running `memstack-mcp hook session-start`. |
|
|
276
|
+
| Codex | `~/.codex/config.toml` | A `memstack` MCP server, added with `codex mcp add`. |
|
|
277
|
+
| Codex | `~/.codex/hooks.json` | A `SessionStart` hook. Codex runs it after you approve it once with `/hooks`. |
|
|
278
|
+
| Codex | `~/.codex/AGENTS.md` | A short block between `memstack:begin`/`memstack:end` markers telling Codex to save memories with `memory_store`. |
|
|
279
|
+
|
|
280
|
+
The registered command is the `memstack-mcp` you installed, run by absolute
|
|
281
|
+
path, so it works even when the agent starts without your shell's `PATH`.
|
|
282
|
+
Restart Claude Code, or start a new Codex session, to load it.
|
|
283
|
+
|
|
284
|
+
### Projects
|
|
285
|
+
|
|
286
|
+
The project ID comes from the repository itself, with nothing stored, so it
|
|
287
|
+
stays the same across clones, worktrees, renamed remotes, moved folders, new
|
|
288
|
+
machines, and storage switches:
|
|
289
|
+
|
|
290
|
+
1. a pinned ID in `.memstack.json` at the repository root
|
|
291
|
+
(`memstack project pin <id>`; commit it to share it with your team);
|
|
292
|
+
2. otherwise, the repository's first commit;
|
|
293
|
+
3. for shallow clones, the `origin` remote;
|
|
294
|
+
4. for repositories without commits, the git directory, and outside git, the
|
|
295
|
+
folder. Memories saved before a repository's first commit move to the new
|
|
296
|
+
ID automatically.
|
|
297
|
+
|
|
298
|
+
A fork shares its first commit with the original repository, so on one store
|
|
299
|
+
the two share memories until one of them runs `memstack project pin`.
|
|
300
|
+
|
|
301
|
+
### Storage
|
|
302
|
+
|
|
303
|
+
Any supported store works; pick it in `memstack init`. MemStack never installs
|
|
304
|
+
storage drivers: install the one you need alongside `@memstack/mcp`.
|
|
305
|
+
|
|
306
|
+
| Store | Driver to install | Notes |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| `sqlite` | `better-sqlite3@^11.10.0` | Default; one local file, safe for both agents at once. |
|
|
309
|
+
| `postgres` | `postgres@^3.4.9` | Shared across machines. |
|
|
310
|
+
| `redis` | `ioredis@^5.11.1` | |
|
|
311
|
+
| `disk`, `markdown` | none | Single process only; `doctor` warns when both agents use them. |
|
|
312
|
+
|
|
313
|
+
Switching stores keeps project IDs; move memories with `memstack export` and
|
|
314
|
+
`memstack import`.
|
|
315
|
+
|
|
316
|
+
### Troubleshooting
|
|
317
|
+
|
|
318
|
+
Run `memstack doctor` first; it checks the config file and its permissions,
|
|
319
|
+
the LLM key, the storage driver, each agent's registration, hook, and
|
|
320
|
+
guidance, and starts the server to confirm it answers.
|
|
321
|
+
|
|
322
|
+
- **"memstack-mcp is not installed" or a missing driver:** run the
|
|
323
|
+
`npm install -g …` command it prints.
|
|
324
|
+
- **Codex doesn't load memories at session start:** approve the MemStack hook
|
|
325
|
+
in Codex with `/hooks`.
|
|
326
|
+
- **Codex doesn't save when asked:** check `memstack status` shows the
|
|
327
|
+
`AGENTS.md` guidance as present; reconnect if not.
|
|
328
|
+
- **Memories seem missing:** `memstack project` shows which project you are
|
|
329
|
+
in. Use `memstack project merge <old-id>` to bring memories from an old ID.
|
|
330
|
+
|
|
331
|
+
Details on the MCP server itself: [docs/MCP_SETUP.md](docs/MCP_SETUP.md#harness-profile-claude-code-and-codex).
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
200
335
|
## The Memory Pipeline
|
|
201
336
|
|
|
202
337
|
MemStack's core is a five-stage pipeline. Each stage can be used independently.
|
|
@@ -209,7 +344,7 @@ Every agent interaction becomes a `Memory` with metadata that controls how it's
|
|
|
209
344
|
interface Memory {
|
|
210
345
|
id: string;
|
|
211
346
|
actorId: string; // Who this memory belongs to (user ID, agent ID, session ID)
|
|
212
|
-
memoryType: MemoryType; // "interaction" | "summary" | "observation" | "fact" | "reflection"
|
|
347
|
+
memoryType: MemoryType; // "interaction" | "summary" | "observation" | "fact" | "reflection" | "preference" | "decision" | "instruction"
|
|
213
348
|
content: string; // The actual text
|
|
214
349
|
importance: number; // 0-1 — higher = survives pruning, ranks higher in retrieval
|
|
215
350
|
emotionalValence: number; // -1 to 1 — for tone-aware retrieval
|
|
@@ -505,6 +640,9 @@ const userCount = await ms.memory.count({ actorId: "user-42" });
|
|
|
505
640
|
| `observation` | Passive knowledge — facts, documents, things the agent knows but didn't interact with. | "Company refund policy is 30 days from purchase." |
|
|
506
641
|
| `fact` | Verified knowledge — discrete truths the agent has confirmed. | "The user's subscription tier is Enterprise." |
|
|
507
642
|
| `reflection` | Self-generated insight — the agent thinking about its own experiences. | "I tend to over-explain billing policies — should be more concise." |
|
|
643
|
+
| `preference` | How the user likes things done. | "Prefer small pull requests with one concern each." |
|
|
644
|
+
| `decision` | A choice made, ideally with its reason. | "Chose Hono over Express for edge runtime support." |
|
|
645
|
+
| `instruction` | A standing rule to follow. | "Never commit directly to main." |
|
|
508
646
|
|
|
509
647
|
Types control retrieval behavior — `compileContext()` treats `interaction` and `summary` differently from `observation`. Use types to separate "what happened" from "what I know."
|
|
510
648
|
|
|
@@ -534,6 +672,29 @@ await ms.memory.retrieve({ actorId: "x", query: "login bug", strategy: "hybrid"
|
|
|
534
672
|
- Use `semantic` for RAG, document search, knowledge base queries
|
|
535
673
|
- Use `hybrid` for most agent memory — it balances meaning with significance
|
|
536
674
|
|
|
675
|
+
### Keyword recall on any storage adapter
|
|
676
|
+
|
|
677
|
+
`LexicalRetriever` answers natural questions without embeddings or an LLM
|
|
678
|
+
call, and behaves the same on every storage adapter. It loads the memories
|
|
679
|
+
in the given actors through `retrieve()`, then ranks them in MemStack with
|
|
680
|
+
BM25 over content and tags, with stemming and prefix matching. When nothing
|
|
681
|
+
matches, it returns the most important memories instead.
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
import { LexicalRetriever } from "@memstack/core";
|
|
685
|
+
|
|
686
|
+
const retriever = new LexicalRetriever(storage);
|
|
687
|
+
const { hits, fallback } = await retriever.recall({
|
|
688
|
+
actorIds: ["project:abc", "global"], // Searched together
|
|
689
|
+
query: "What framework does this project use?",
|
|
690
|
+
limit: 10, // Max results
|
|
691
|
+
maxChars: 8000, // Max total content; the top hit is always returned
|
|
692
|
+
});
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Up to 2,000 memories per actor are ranked (`candidateLimit`). Only returned
|
|
696
|
+
memories are marked as accessed.
|
|
697
|
+
|
|
537
698
|
---
|
|
538
699
|
|
|
539
700
|
## Embeddings
|
|
@@ -896,6 +1057,39 @@ const status = await ms.health();
|
|
|
896
1057
|
await ms.close(); // graceful shutdown
|
|
897
1058
|
```
|
|
898
1059
|
|
|
1060
|
+
### Harness Memory API
|
|
1061
|
+
|
|
1062
|
+
The harness features are built on `HarnessMemory`, which works with any
|
|
1063
|
+
storage adapter. Use it to build your own agent integration:
|
|
1064
|
+
|
|
1065
|
+
```typescript
|
|
1066
|
+
import { HarnessMemory, defaultRecallNamespaces, projectNamespace } from "@memstack/core";
|
|
1067
|
+
|
|
1068
|
+
const memory = new HarnessMemory({ storage, llm });
|
|
1069
|
+
|
|
1070
|
+
await memory.remember({
|
|
1071
|
+
namespace: projectNamespace("acme-api"), // or "global"
|
|
1072
|
+
content: "This project uses Hono",
|
|
1073
|
+
kind: "decision", // fact | preference | decision | instruction | observation | ...
|
|
1074
|
+
source: { harness: "my-agent", project: "acme-api" },
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
const { hits, fallback } = await memory.recall({
|
|
1078
|
+
namespaces: defaultRecallNamespaces("acme-api"), // project, then global
|
|
1079
|
+
query: "Which framework do we use?",
|
|
1080
|
+
limit: 10,
|
|
1081
|
+
maxChars: 8000,
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
await memory.get(id, namespaces); // null outside namespaces
|
|
1085
|
+
await memory.forget(id, namespaces); // refuses ids outside namespaces
|
|
1086
|
+
await memory.stats(namespaces); // { "project:acme-api": 3, global: 1 }
|
|
1087
|
+
await memory.moveNamespace(from, to); // e.g. when a project's ID changes
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
`remember` asks the LLM for topic tags (disable with `autoTags: false`); every
|
|
1091
|
+
other method makes no LLM call. `recall` uses [`LexicalRetriever`](#keyword-recall-on-any-storage-adapter).
|
|
1092
|
+
|
|
899
1093
|
---
|
|
900
1094
|
|
|
901
1095
|
## Configuration
|
|
@@ -927,6 +1121,26 @@ const ms = new MemStack({
|
|
|
927
1121
|
});
|
|
928
1122
|
```
|
|
929
1123
|
|
|
1124
|
+
### Harness configuration file
|
|
1125
|
+
|
|
1126
|
+
The CLI and the MCP harness profile read `~/.memstack/config.json` (or
|
|
1127
|
+
`$MEMSTACK_HOME/config.json`), which `memstack init` writes with permissions
|
|
1128
|
+
readable only by you:
|
|
1129
|
+
|
|
1130
|
+
```json
|
|
1131
|
+
{
|
|
1132
|
+
"version": 1,
|
|
1133
|
+
"llm": { "provider": "openai-compatible", "apiKey": "…", "baseURL": "https://api.deepseek.com", "model": "deepseek-flash" },
|
|
1134
|
+
"storage": { "type": "sqlite", "path": "/Users/you/.memstack/memstack.db" }
|
|
1135
|
+
}
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
Environment variables override the file one section at a time: any LLM
|
|
1139
|
+
variable (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `MEMSTACK_OPENAI_BASE_URL`,
|
|
1140
|
+
`MEMSTACK_LLM_MODEL`) replaces the whole `llm` section, and `MEMSTACK_STORAGE`
|
|
1141
|
+
replaces the whole `storage` section, so a key is never sent to another
|
|
1142
|
+
provider's URL.
|
|
1143
|
+
|
|
930
1144
|
---
|
|
931
1145
|
|
|
932
1146
|
## Advanced Usage
|
|
@@ -935,6 +1149,19 @@ const ms = new MemStack({
|
|
|
935
1149
|
|
|
936
1150
|
Implement `StorageProvider` for any database. The interface is 9 methods. See the reference section above for the full contract.
|
|
937
1151
|
|
|
1152
|
+
Optional members, none of them required:
|
|
1153
|
+
|
|
1154
|
+
- `capabilities: { multiProcess?, textSearch? }` declares whether several
|
|
1155
|
+
processes can share the store safely and whether `search()` is native.
|
|
1156
|
+
- `search(query)` provides native full-text search. `LexicalRetriever` uses
|
|
1157
|
+
it when `textSearch` is declared and ranks memories itself otherwise.
|
|
1158
|
+
- `retrieve()` should honor `touch: false` by returning memories without
|
|
1159
|
+
marking them as accessed.
|
|
1160
|
+
|
|
1161
|
+
`SQLiteStorageAdapter` enables WAL and a 5-second busy timeout so several
|
|
1162
|
+
processes can share one database file. Set `walMode: false` or
|
|
1163
|
+
`busyTimeoutMs` to change this.
|
|
1164
|
+
|
|
938
1165
|
### Custom LLM / Embedding
|
|
939
1166
|
|
|
940
1167
|
Implement `LLMProvider` or `EmbeddingProvider` for any service:
|