@waynesutton/agent-memory 0.0.1-alpha.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/.claude/settings.json +9 -0
- package/.claude/settings.local.json +7 -0
- package/AGENTS.md +113 -0
- package/CLAUDE.md +79 -0
- package/README.md +1003 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +192 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/parsers/claude-code.d.ts +3 -0
- package/dist/cli/parsers/claude-code.d.ts.map +1 -0
- package/dist/cli/parsers/claude-code.js +75 -0
- package/dist/cli/parsers/claude-code.js.map +1 -0
- package/dist/cli/parsers/codex.d.ts +3 -0
- package/dist/cli/parsers/codex.d.ts.map +1 -0
- package/dist/cli/parsers/codex.js +42 -0
- package/dist/cli/parsers/codex.js.map +1 -0
- package/dist/cli/parsers/conductor.d.ts +3 -0
- package/dist/cli/parsers/conductor.d.ts.map +1 -0
- package/dist/cli/parsers/conductor.js +43 -0
- package/dist/cli/parsers/conductor.js.map +1 -0
- package/dist/cli/parsers/cursor.d.ts +3 -0
- package/dist/cli/parsers/cursor.d.ts.map +1 -0
- package/dist/cli/parsers/cursor.js +50 -0
- package/dist/cli/parsers/cursor.js.map +1 -0
- package/dist/cli/parsers/index.d.ts +12 -0
- package/dist/cli/parsers/index.d.ts.map +1 -0
- package/dist/cli/parsers/index.js +27 -0
- package/dist/cli/parsers/index.js.map +1 -0
- package/dist/cli/parsers/opencode.d.ts +3 -0
- package/dist/cli/parsers/opencode.d.ts.map +1 -0
- package/dist/cli/parsers/opencode.js +72 -0
- package/dist/cli/parsers/opencode.js.map +1 -0
- package/dist/cli/parsers/parsers.test.d.ts +2 -0
- package/dist/cli/parsers/parsers.test.d.ts.map +1 -0
- package/dist/cli/parsers/parsers.test.js +151 -0
- package/dist/cli/parsers/parsers.test.js.map +1 -0
- package/dist/cli/parsers/pi.d.ts +3 -0
- package/dist/cli/parsers/pi.d.ts.map +1 -0
- package/dist/cli/parsers/pi.js +43 -0
- package/dist/cli/parsers/pi.js.map +1 -0
- package/dist/cli/parsers/types.d.ts +25 -0
- package/dist/cli/parsers/types.d.ts.map +1 -0
- package/dist/cli/parsers/types.js +2 -0
- package/dist/cli/parsers/types.js.map +1 -0
- package/dist/cli/parsers/vscode-copilot.d.ts +3 -0
- package/dist/cli/parsers/vscode-copilot.d.ts.map +1 -0
- package/dist/cli/parsers/vscode-copilot.js +69 -0
- package/dist/cli/parsers/vscode-copilot.js.map +1 -0
- package/dist/cli/parsers/zed.d.ts +3 -0
- package/dist/cli/parsers/zed.d.ts.map +1 -0
- package/dist/cli/parsers/zed.js +43 -0
- package/dist/cli/parsers/zed.js.map +1 -0
- package/dist/cli/sync.d.ts +21 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +78 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli/type-extractor.d.ts +25 -0
- package/dist/cli/type-extractor.d.ts.map +1 -0
- package/dist/cli/type-extractor.js +254 -0
- package/dist/cli/type-extractor.js.map +1 -0
- package/dist/cli/type-extractor.test.d.ts +2 -0
- package/dist/cli/type-extractor.test.d.ts.map +1 -0
- package/dist/cli/type-extractor.test.js +173 -0
- package/dist/cli/type-extractor.test.js.map +1 -0
- package/dist/client/http.d.ts +44 -0
- package/dist/client/http.d.ts.map +1 -0
- package/dist/client/http.js +311 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/index.d.ts +158 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +256 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +12 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +13 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +18 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +42 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +39 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/actions.d.ts +42 -0
- package/dist/component/actions.d.ts.map +1 -0
- package/dist/component/actions.js +405 -0
- package/dist/component/actions.js.map +1 -0
- package/dist/component/apiKeyMutations.d.ts +29 -0
- package/dist/component/apiKeyMutations.d.ts.map +1 -0
- package/dist/component/apiKeyMutations.js +149 -0
- package/dist/component/apiKeyMutations.js.map +1 -0
- package/dist/component/apiKeyQueries.d.ts +37 -0
- package/dist/component/apiKeyQueries.d.ts.map +1 -0
- package/dist/component/apiKeyQueries.js +127 -0
- package/dist/component/apiKeyQueries.js.map +1 -0
- package/dist/component/checksum.d.ts +6 -0
- package/dist/component/checksum.d.ts.map +1 -0
- package/dist/component/checksum.js +14 -0
- package/dist/component/checksum.js.map +1 -0
- package/dist/component/checksum.test.d.ts +2 -0
- package/dist/component/checksum.test.d.ts.map +1 -0
- package/dist/component/checksum.test.js +27 -0
- package/dist/component/checksum.test.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +4 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/cronActions.d.ts +3 -0
- package/dist/component/cronActions.d.ts.map +1 -0
- package/dist/component/cronActions.js +38 -0
- package/dist/component/cronActions.js.map +1 -0
- package/dist/component/cronQueries.d.ts +6 -0
- package/dist/component/cronQueries.d.ts.map +1 -0
- package/dist/component/cronQueries.js +38 -0
- package/dist/component/cronQueries.js.map +1 -0
- package/dist/component/crons.d.ts +3 -0
- package/dist/component/crons.d.ts.map +1 -0
- package/dist/component/crons.js +18 -0
- package/dist/component/crons.js.map +1 -0
- package/dist/component/format.d.ts +11 -0
- package/dist/component/format.d.ts.map +1 -0
- package/dist/component/format.js +175 -0
- package/dist/component/format.js.map +1 -0
- package/dist/component/format.test.d.ts +2 -0
- package/dist/component/format.test.d.ts.map +1 -0
- package/dist/component/format.test.js +118 -0
- package/dist/component/format.test.js.map +1 -0
- package/dist/component/mutations.d.ts +158 -0
- package/dist/component/mutations.d.ts.map +1 -0
- package/dist/component/mutations.js +745 -0
- package/dist/component/mutations.js.map +1 -0
- package/dist/component/queries.d.ts +94 -0
- package/dist/component/queries.d.ts.map +1 -0
- package/dist/component/queries.js +574 -0
- package/dist/component/queries.js.map +1 -0
- package/dist/component/schema.d.ts +278 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +161 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +571 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/shared.d.ts +126 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +67 -0
- package/dist/shared.js.map +1 -0
- package/dist/test.d.ts +23 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +21 -0
- package/dist/test.js.map +1 -0
- package/eslint.config.js +15 -0
- package/example/convex/convex.config.ts +7 -0
- package/example/convex/memory.ts +129 -0
- package/llms.md +175 -0
- package/llms.txt +126 -0
- package/package.json +80 -0
- package/prds/API-REFERENCE.md +935 -0
- package/prds/SETUP.md +682 -0
- package/src/cli/index.ts +254 -0
- package/src/cli/parsers/claude-code.ts +80 -0
- package/src/cli/parsers/codex.ts +45 -0
- package/src/cli/parsers/conductor.ts +47 -0
- package/src/cli/parsers/cursor.ts +55 -0
- package/src/cli/parsers/index.ts +30 -0
- package/src/cli/parsers/opencode.ts +84 -0
- package/src/cli/parsers/parsers.test.ts +201 -0
- package/src/cli/parsers/pi.ts +47 -0
- package/src/cli/parsers/types.ts +26 -0
- package/src/cli/parsers/vscode-copilot.ts +78 -0
- package/src/cli/parsers/zed.ts +47 -0
- package/src/cli/sync.ts +110 -0
- package/src/cli/type-extractor.test.ts +241 -0
- package/src/cli/type-extractor.ts +331 -0
- package/src/client/http.ts +415 -0
- package/src/client/index.ts +519 -0
- package/src/component/_generated/api.ts +14 -0
- package/src/component/_generated/dataModel.ts +20 -0
- package/src/component/_generated/server.ts +64 -0
- package/src/component/actions.ts +558 -0
- package/src/component/apiKeyMutations.ts +175 -0
- package/src/component/apiKeyQueries.ts +156 -0
- package/src/component/checksum.test.ts +31 -0
- package/src/component/checksum.ts +13 -0
- package/src/component/convex.config.ts +5 -0
- package/src/component/cronActions.ts +52 -0
- package/src/component/cronQueries.ts +42 -0
- package/src/component/crons.ts +34 -0
- package/src/component/format.test.ts +133 -0
- package/src/component/format.ts +232 -0
- package/src/component/mutations.ts +824 -0
- package/src/component/queries.ts +684 -0
- package/src/component/schema.ts +207 -0
- package/src/mcp/server.ts +695 -0
- package/src/shared.ts +251 -0
- package/src/test.ts +32 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +8 -0
package/prds/SETUP.md
ADDED
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
# Setup Guide — @waynesutton/agent-memory
|
|
2
|
+
|
|
3
|
+
Step-by-step instructions for every integration path.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Node.js 18+
|
|
10
|
+
- A Convex account and project ([convex.dev](https://convex.dev))
|
|
11
|
+
- `CONVEX_URL` from your Convex dashboard
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Path A: Add to an Existing Convex App
|
|
16
|
+
|
|
17
|
+
### Step 1 — Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @waynesutton/agent-memory
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Make sure you already have `convex` and `convex-helpers` installed:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install convex convex-helpers
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Step 2 — Register the Component
|
|
30
|
+
|
|
31
|
+
Edit your `convex/convex.config.ts`:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { defineApp } from "convex/server";
|
|
35
|
+
import agentMemory from "@waynesutton/agent-memory/convex.config.js";
|
|
36
|
+
|
|
37
|
+
const app = defineApp();
|
|
38
|
+
app.use(agentMemory);
|
|
39
|
+
export default app;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 3 — Create Memory Functions
|
|
43
|
+
|
|
44
|
+
Create `convex/memory.ts`:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { v } from "convex/values";
|
|
48
|
+
import { query, mutation, action } from "./_generated/server.js";
|
|
49
|
+
import { components } from "./_generated/api.js";
|
|
50
|
+
import { AgentMemory } from "@waynesutton/agent-memory";
|
|
51
|
+
|
|
52
|
+
const memory = new AgentMemory(components.agentMemory, {
|
|
53
|
+
projectId: "my-project",
|
|
54
|
+
agentId: "my-app", // optional: identifies this agent
|
|
55
|
+
llmApiKey: process.env.OPENAI_API_KEY, // optional: enables intelligent ingest
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Save a memory
|
|
59
|
+
export const remember = mutation({
|
|
60
|
+
args: {
|
|
61
|
+
title: v.string(),
|
|
62
|
+
content: v.string(),
|
|
63
|
+
memoryType: v.union(
|
|
64
|
+
v.literal("instruction"),
|
|
65
|
+
v.literal("learning"),
|
|
66
|
+
v.literal("reference"),
|
|
67
|
+
v.literal("feedback"),
|
|
68
|
+
v.literal("journal"),
|
|
69
|
+
),
|
|
70
|
+
tags: v.optional(v.array(v.string())),
|
|
71
|
+
priority: v.optional(v.float64()),
|
|
72
|
+
},
|
|
73
|
+
returns: v.string(),
|
|
74
|
+
handler: async (ctx, args) => memory.remember(ctx, args),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Search memories
|
|
78
|
+
export const recall = query({
|
|
79
|
+
args: { q: v.string() },
|
|
80
|
+
returns: v.any(),
|
|
81
|
+
handler: async (ctx, args) => memory.search(ctx, args.q),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// List all memories
|
|
85
|
+
export const listAll = query({
|
|
86
|
+
args: {},
|
|
87
|
+
returns: v.any(),
|
|
88
|
+
handler: async (ctx) => memory.list(ctx),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Archive a memory
|
|
92
|
+
export const forget = mutation({
|
|
93
|
+
args: { memoryId: v.string() },
|
|
94
|
+
returns: v.null(),
|
|
95
|
+
handler: async (ctx, args) => {
|
|
96
|
+
await memory.forget(ctx, args.memoryId);
|
|
97
|
+
return null;
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Get context bundle for agent sessions
|
|
102
|
+
export const getContext = query({
|
|
103
|
+
args: {
|
|
104
|
+
activePaths: v.optional(v.array(v.string())),
|
|
105
|
+
},
|
|
106
|
+
returns: v.any(),
|
|
107
|
+
handler: async (ctx, args) =>
|
|
108
|
+
memory.getContextBundle(ctx, { activePaths: args.activePaths }),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// View change history
|
|
112
|
+
export const memoryHistory = query({
|
|
113
|
+
args: { memoryId: v.string() },
|
|
114
|
+
returns: v.any(),
|
|
115
|
+
handler: async (ctx, args) => memory.history(ctx, args.memoryId),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Rate a memory
|
|
119
|
+
export const rateFeedback = mutation({
|
|
120
|
+
args: {
|
|
121
|
+
memoryId: v.string(),
|
|
122
|
+
sentiment: v.union(
|
|
123
|
+
v.literal("positive"),
|
|
124
|
+
v.literal("negative"),
|
|
125
|
+
v.literal("very_negative"),
|
|
126
|
+
),
|
|
127
|
+
comment: v.optional(v.string()),
|
|
128
|
+
},
|
|
129
|
+
returns: v.null(),
|
|
130
|
+
handler: async (ctx, args) => {
|
|
131
|
+
await memory.addFeedback(ctx, args.memoryId, args.sentiment, {
|
|
132
|
+
comment: args.comment,
|
|
133
|
+
});
|
|
134
|
+
return null;
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Intelligently ingest raw text
|
|
139
|
+
export const ingest = action({
|
|
140
|
+
args: { content: v.string() },
|
|
141
|
+
returns: v.any(),
|
|
142
|
+
handler: async (ctx, args) => memory.ingest(ctx, args.content),
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Step 4 — Deploy
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npx convex dev
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Your memories table is now live. Use the Convex dashboard to verify.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Path B: CLI-Only (Sync Local Files)
|
|
157
|
+
|
|
158
|
+
Use the CLI to push/pull memory files without writing any Convex code.
|
|
159
|
+
|
|
160
|
+
### Step 1 — Install Globally (or use npx)
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install -g @waynesutton/agent-memory
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Step 2 — Set Your Convex URL
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
export CONVEX_URL="https://your-deployment.convex.cloud"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Get this from your Convex dashboard under "Settings" > "URL & Deploy Key".
|
|
173
|
+
|
|
174
|
+
### Step 3 — Initialize
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
cd /path/to/your/project
|
|
178
|
+
npx agent-memory init --project my-project --name "My Project"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
This detects which tools are present (Claude Code, Cursor, etc.) and registers the project.
|
|
182
|
+
|
|
183
|
+
### Step 4 — Push Local Memories
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx agent-memory push --project my-project
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
This reads all detected tool files (`.claude/rules/`, `.cursor/rules/`, `AGENTS.md`, etc.) and uploads them to Convex.
|
|
190
|
+
|
|
191
|
+
### Step 5 — Pull to Another Tool
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Pull as Cursor rules
|
|
195
|
+
npx agent-memory pull --project my-project --format cursor
|
|
196
|
+
|
|
197
|
+
# Pull as Claude Code rules
|
|
198
|
+
npx agent-memory pull --project my-project --format claude-code
|
|
199
|
+
|
|
200
|
+
# Pull as AGENTS.md (OpenCode/Codex)
|
|
201
|
+
npx agent-memory pull --project my-project --format opencode
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Path C: MCP Server for AI Agents
|
|
207
|
+
|
|
208
|
+
### Step 1 — Configure for Claude Code
|
|
209
|
+
|
|
210
|
+
Add to `.claude/settings.json` in your project:
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"mcpServers": {
|
|
215
|
+
"agent-memory": {
|
|
216
|
+
"command": "npx",
|
|
217
|
+
"args": ["agent-memory", "mcp", "--project", "my-project"],
|
|
218
|
+
"env": {
|
|
219
|
+
"CONVEX_URL": "https://your-deployment.convex.cloud"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Step 2 — Configure for Cursor
|
|
227
|
+
|
|
228
|
+
Add to `.cursor/mcp.json` in your project:
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"mcpServers": {
|
|
233
|
+
"agent-memory": {
|
|
234
|
+
"command": "npx",
|
|
235
|
+
"args": ["agent-memory", "mcp", "--project", "my-project"],
|
|
236
|
+
"env": {
|
|
237
|
+
"CONVEX_URL": "https://your-deployment.convex.cloud"
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Step 3 — Verify
|
|
245
|
+
|
|
246
|
+
Once configured, your AI agent will have access to 14 tools:
|
|
247
|
+
|
|
248
|
+
- `memory_remember` — save a new memory (with agent/session scoping)
|
|
249
|
+
- `memory_recall` — search by keyword
|
|
250
|
+
- `memory_semantic_recall` — search by meaning (if embedding key provided)
|
|
251
|
+
- `memory_list` — list memories with filters (agent, session, source, tags)
|
|
252
|
+
- `memory_context` — get context bundle
|
|
253
|
+
- `memory_forget` — archive a memory
|
|
254
|
+
- `memory_restore` — restore an archived memory
|
|
255
|
+
- `memory_update` — update a memory
|
|
256
|
+
- `memory_history` — view change audit trail
|
|
257
|
+
- `memory_feedback` — rate a memory as helpful/unhelpful
|
|
258
|
+
- `memory_relate` — create relationship between memories
|
|
259
|
+
- `memory_relations` — view memory graph connections
|
|
260
|
+
- `memory_batch_archive` — archive multiple memories
|
|
261
|
+
- `memory_ingest` — intelligently extract memories from raw text
|
|
262
|
+
|
|
263
|
+
### Step 4 (Optional) — Enable Vector Search
|
|
264
|
+
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"mcpServers": {
|
|
268
|
+
"agent-memory": {
|
|
269
|
+
"command": "npx",
|
|
270
|
+
"args": [
|
|
271
|
+
"agent-memory", "mcp",
|
|
272
|
+
"--project", "my-project",
|
|
273
|
+
"--embedding-api-key", "${env:OPENAI_API_KEY}"
|
|
274
|
+
],
|
|
275
|
+
"env": {
|
|
276
|
+
"CONVEX_URL": "${env:CONVEX_URL}",
|
|
277
|
+
"OPENAI_API_KEY": "${env:OPENAI_API_KEY}"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Step 5 (Optional) — Enable Intelligent Ingest
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"mcpServers": {
|
|
289
|
+
"agent-memory": {
|
|
290
|
+
"command": "npx",
|
|
291
|
+
"args": [
|
|
292
|
+
"agent-memory", "mcp",
|
|
293
|
+
"--project", "my-project",
|
|
294
|
+
"--llm-api-key", "${env:OPENAI_API_KEY}"
|
|
295
|
+
],
|
|
296
|
+
"env": {
|
|
297
|
+
"CONVEX_URL": "${env:CONVEX_URL}",
|
|
298
|
+
"OPENAI_API_KEY": "${env:OPENAI_API_KEY}"
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Step 6 (Optional) — Read-Only Mode
|
|
306
|
+
|
|
307
|
+
For agents that should only read, not write:
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"mcpServers": {
|
|
312
|
+
"agent-memory": {
|
|
313
|
+
"command": "npx",
|
|
314
|
+
"args": ["agent-memory", "mcp", "--project", "my-project", "--read-only"],
|
|
315
|
+
"env": {
|
|
316
|
+
"CONVEX_URL": "${env:CONVEX_URL}"
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Path D: Auto-Sync with Hooks
|
|
326
|
+
|
|
327
|
+
### Claude Code — Sync on Session Start/End
|
|
328
|
+
|
|
329
|
+
Add to `.claude/settings.json`:
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"hooks": {
|
|
334
|
+
"SessionStart": [{
|
|
335
|
+
"hooks": [{
|
|
336
|
+
"type": "command",
|
|
337
|
+
"command": "CONVEX_URL=https://your-deployment.convex.cloud npx agent-memory pull --format claude-code --project my-project"
|
|
338
|
+
}]
|
|
339
|
+
}],
|
|
340
|
+
"SessionEnd": [{
|
|
341
|
+
"hooks": [{
|
|
342
|
+
"type": "command",
|
|
343
|
+
"command": "CONVEX_URL=https://your-deployment.convex.cloud npx agent-memory push --format claude-code --project my-project"
|
|
344
|
+
}]
|
|
345
|
+
}]
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
This ensures:
|
|
351
|
+
- Session starts with latest memories from the cloud
|
|
352
|
+
- Session ends by pushing any new learnings back
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Path E: Using with @convex-dev/agent
|
|
357
|
+
|
|
358
|
+
If your app uses `@convex-dev/agent` for AI agent threads, you can load memories as system prompts:
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
// convex/convex.config.ts
|
|
362
|
+
import { defineApp } from "convex/server";
|
|
363
|
+
import agentMemory from "@waynesutton/agent-memory/convex.config.js";
|
|
364
|
+
import agent from "@convex-dev/agent/convex.config.js";
|
|
365
|
+
|
|
366
|
+
const app = defineApp();
|
|
367
|
+
app.use(agentMemory);
|
|
368
|
+
app.use(agent);
|
|
369
|
+
export default app;
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
// convex/ai.ts
|
|
374
|
+
import { action } from "./_generated/server.js";
|
|
375
|
+
import { components } from "./_generated/api.js";
|
|
376
|
+
import { AgentMemory } from "@waynesutton/agent-memory";
|
|
377
|
+
import { Agent } from "@convex-dev/agent";
|
|
378
|
+
import { v } from "convex/values";
|
|
379
|
+
|
|
380
|
+
const memory = new AgentMemory(components.agentMemory, {
|
|
381
|
+
projectId: "my-app",
|
|
382
|
+
agentId: "my-ai-agent",
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
const myAgent = new Agent(components.agent, {
|
|
386
|
+
model: "claude-sonnet-4-6",
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
export const chat = action({
|
|
390
|
+
args: { message: v.string(), threadId: v.optional(v.string()) },
|
|
391
|
+
returns: v.any(),
|
|
392
|
+
handler: async (ctx, args) => {
|
|
393
|
+
// Load relevant memories (feedback-boosted priority scoring)
|
|
394
|
+
const bundle = await memory.getContextBundle(ctx, {
|
|
395
|
+
activePaths: [], // or pass relevant file paths
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// Build system prompt from memories
|
|
399
|
+
const memoryPrompt = bundle.pinned
|
|
400
|
+
.map((m) => `## ${m.title}\n${m.content}`)
|
|
401
|
+
.join("\n\n---\n\n");
|
|
402
|
+
|
|
403
|
+
// Use agent with memory-augmented instructions
|
|
404
|
+
const thread = await myAgent.createThread(ctx, {
|
|
405
|
+
systemPrompt: `You are a helpful coding assistant.\n\n# Project Knowledge\n\n${memoryPrompt}`,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const result = await myAgent.chat(ctx, {
|
|
409
|
+
threadId: thread._id,
|
|
410
|
+
message: args.message,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
return result;
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Path F: Enable Relevance Decay
|
|
421
|
+
|
|
422
|
+
For projects with many memories, enable automatic relevance decay so stale memories don't dominate context bundles.
|
|
423
|
+
|
|
424
|
+
### Step 1 — Update Project Settings
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
// In a mutation or action context
|
|
428
|
+
await ctx.runMutation(components.agentMemory.mutations.upsertProject, {
|
|
429
|
+
projectId: "my-app",
|
|
430
|
+
name: "My App",
|
|
431
|
+
settings: {
|
|
432
|
+
autoSync: false,
|
|
433
|
+
syncFormats: [],
|
|
434
|
+
decayEnabled: true,
|
|
435
|
+
decayHalfLifeDays: 30, // priority halves every 30 days of no access
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Step 2 — That's It
|
|
441
|
+
|
|
442
|
+
The component runs a daily cron job at 3 AM UTC that:
|
|
443
|
+
1. Finds all non-pinned memories in decay-enabled projects
|
|
444
|
+
2. Reduces priority for memories with low access and old `lastAccessedAt`
|
|
445
|
+
3. Pinned memories (priority >= 0.8) are never decayed
|
|
446
|
+
|
|
447
|
+
Access tracking happens automatically when you use `recordAccess()` or when the `getContextBundle` query returns memories.
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Path G: Custom Ingest Prompts
|
|
452
|
+
|
|
453
|
+
Customize how the intelligent ingest pipeline extracts and deduplicates memories.
|
|
454
|
+
|
|
455
|
+
### Per-Project (persistent)
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
await ctx.runMutation(components.agentMemory.mutations.upsertProject, {
|
|
459
|
+
projectId: "my-app",
|
|
460
|
+
name: "My App",
|
|
461
|
+
settings: {
|
|
462
|
+
autoSync: false,
|
|
463
|
+
syncFormats: [],
|
|
464
|
+
factExtractionPrompt: `Extract only coding conventions, architecture decisions,
|
|
465
|
+
and user preferences. Ignore greetings and ephemeral discussion.`,
|
|
466
|
+
updateDecisionPrompt: `When a new fact contradicts an existing memory,
|
|
467
|
+
always UPDATE the existing memory with the newer information.
|
|
468
|
+
Never create duplicates.`,
|
|
469
|
+
},
|
|
470
|
+
});
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Per-Call (one-time)
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
const result = await memory.ingest(ctx, rawText, {
|
|
477
|
+
customExtractionPrompt: "Extract only security-related decisions...",
|
|
478
|
+
customUpdatePrompt: "Be very conservative — only ADD if truly novel...",
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## Path H: Read-Only HTTP API
|
|
485
|
+
|
|
486
|
+
Expose memories as REST endpoints for dashboards, CI/CD pipelines, and external integrations.
|
|
487
|
+
|
|
488
|
+
### Step 1 — Create API Keys
|
|
489
|
+
|
|
490
|
+
Add a mutation to your app that creates API keys behind your own auth:
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
// convex/memory.ts
|
|
494
|
+
import { AgentMemory } from "@waynesutton/agent-memory";
|
|
495
|
+
import { mutation } from "./_generated/server.js";
|
|
496
|
+
import { components } from "./_generated/api.js";
|
|
497
|
+
|
|
498
|
+
const memory = new AgentMemory(components.agentMemory, {
|
|
499
|
+
projectId: "my-project",
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
export const createApiKey = mutation({
|
|
503
|
+
args: {},
|
|
504
|
+
handler: async (ctx) => {
|
|
505
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
506
|
+
if (!identity) throw new Error("Not authenticated");
|
|
507
|
+
|
|
508
|
+
return await memory.createApiKey(ctx, {
|
|
509
|
+
name: "Dashboard read key",
|
|
510
|
+
permissions: ["list", "search", "context"],
|
|
511
|
+
// Optional: custom rate limit
|
|
512
|
+
// rateLimitOverride: { requestsPerWindow: 200, windowMs: 60000 },
|
|
513
|
+
// Optional: key expiry
|
|
514
|
+
// expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days
|
|
515
|
+
});
|
|
516
|
+
// Returns: { key: "am_<40chars>", keyHash: "..." }
|
|
517
|
+
// ⚠️ The plaintext key is only returned once — store it securely!
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Step 2 — Mount the HTTP Router
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
// convex/http.ts
|
|
526
|
+
import { httpRouter } from "convex/server";
|
|
527
|
+
import { MemoryHttpApi } from "@waynesutton/agent-memory/http";
|
|
528
|
+
import { components } from "./_generated/api";
|
|
529
|
+
|
|
530
|
+
const http = httpRouter();
|
|
531
|
+
|
|
532
|
+
const memoryApi = new MemoryHttpApi(components.agentMemory, {
|
|
533
|
+
corsOrigins: ["https://myapp.com"], // optional, defaults to ["*"]
|
|
534
|
+
});
|
|
535
|
+
memoryApi.mount(http, "/api/memory");
|
|
536
|
+
|
|
537
|
+
export default http;
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Step 3 — Deploy
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
npx convex dev
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Step 4 — Use the API
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
# List memories
|
|
550
|
+
curl -H "Authorization: Bearer am_<your-key>" \
|
|
551
|
+
https://your-deployment.convex.cloud/api/memory/list
|
|
552
|
+
|
|
553
|
+
# Search
|
|
554
|
+
curl -H "Authorization: Bearer am_<your-key>" \
|
|
555
|
+
"https://your-deployment.convex.cloud/api/memory/search?q=API+conventions"
|
|
556
|
+
|
|
557
|
+
# Get context bundle
|
|
558
|
+
curl -H "Authorization: Bearer am_<your-key>" \
|
|
559
|
+
https://your-deployment.convex.cloud/api/memory/context
|
|
560
|
+
|
|
561
|
+
# Export as Cursor format
|
|
562
|
+
curl -H "Authorization: Bearer am_<your-key>" \
|
|
563
|
+
"https://your-deployment.convex.cloud/api/memory/export?format=cursor"
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### Available Endpoints
|
|
567
|
+
|
|
568
|
+
| Path | Permission | Description |
|
|
569
|
+
|------|------------|-------------|
|
|
570
|
+
| `/list` | `list` | List memories with query param filters |
|
|
571
|
+
| `/get?id=<memoryId>` | `get` | Get a single memory |
|
|
572
|
+
| `/search?q=<query>` | `search` | Full-text search |
|
|
573
|
+
| `/context` | `context` | Progressive context bundle |
|
|
574
|
+
| `/export?format=<format>` | `export` | Export in tool format |
|
|
575
|
+
| `/history?id=<memoryId>` | `history` | Memory audit trail |
|
|
576
|
+
| `/relations?id=<memoryId>` | `relations` | Memory graph connections |
|
|
577
|
+
|
|
578
|
+
### Available Permissions
|
|
579
|
+
|
|
580
|
+
`list`, `get`, `search`, `context`, `export`, `history`, `relations`
|
|
581
|
+
|
|
582
|
+
### Rate Limiting
|
|
583
|
+
|
|
584
|
+
- Default: 100 requests per 60 seconds
|
|
585
|
+
- Configurable per-key or per-project
|
|
586
|
+
- Returns `429` with `retryAfterMs` when exceeded
|
|
587
|
+
- Self-contained (no external dependency)
|
|
588
|
+
|
|
589
|
+
### Managing Keys
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
// List keys (never exposes plaintext)
|
|
593
|
+
const keys = await memory.listApiKeys(ctx);
|
|
594
|
+
|
|
595
|
+
// Revoke a key
|
|
596
|
+
await memory.revokeApiKey(ctx, keyHash);
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## Verifying Your Setup
|
|
602
|
+
|
|
603
|
+
### Check Convex Dashboard
|
|
604
|
+
|
|
605
|
+
After deploying, go to your Convex dashboard. You should see the component's tables under the `agentMemory` namespace:
|
|
606
|
+
- `agentMemory:memories`
|
|
607
|
+
- `agentMemory:embeddings`
|
|
608
|
+
- `agentMemory:projects`
|
|
609
|
+
- `agentMemory:syncLog`
|
|
610
|
+
- `agentMemory:memoryHistory`
|
|
611
|
+
- `agentMemory:memoryFeedback`
|
|
612
|
+
- `agentMemory:memoryRelations`
|
|
613
|
+
|
|
614
|
+
### CLI Verification
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
# List memories (should be empty initially)
|
|
618
|
+
npx agent-memory list --project my-project
|
|
619
|
+
|
|
620
|
+
# If you have .claude/rules/ or .cursor/rules/ files, push them
|
|
621
|
+
npx agent-memory push --project my-project
|
|
622
|
+
|
|
623
|
+
# List again to see uploaded memories
|
|
624
|
+
npx agent-memory list --project my-project
|
|
625
|
+
|
|
626
|
+
# Search
|
|
627
|
+
npx agent-memory search "your search term" --project my-project
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### MCP Verification
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# Start the MCP server manually to test
|
|
634
|
+
CONVEX_URL=https://your-deployment.convex.cloud npx agent-memory mcp --project my-project
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
If it starts without errors, you'll see:
|
|
638
|
+
```
|
|
639
|
+
agent-memory MCP server running for project "my-project"
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## Troubleshooting
|
|
645
|
+
|
|
646
|
+
### "CONVEX_URL environment variable is required"
|
|
647
|
+
|
|
648
|
+
Set your deployment URL:
|
|
649
|
+
```bash
|
|
650
|
+
export CONVEX_URL="https://your-deployment.convex.cloud"
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
### "Cannot find module '@waynesutton/agent-memory'"
|
|
654
|
+
|
|
655
|
+
Make sure you installed the package:
|
|
656
|
+
```bash
|
|
657
|
+
npm install @waynesutton/agent-memory
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### MCP server not showing tools in Claude Code
|
|
661
|
+
|
|
662
|
+
1. Check `.claude/settings.json` is valid JSON
|
|
663
|
+
2. Verify `CONVEX_URL` is set in the `env` block
|
|
664
|
+
3. Restart Claude Code after changing MCP config
|
|
665
|
+
|
|
666
|
+
### No memories found after push
|
|
667
|
+
|
|
668
|
+
1. Check the project ID matches between push and list
|
|
669
|
+
2. Verify the Convex dashboard shows data in `agentMemory:memories`
|
|
670
|
+
3. Make sure you have actual tool files (`.claude/rules/*.md`, etc.) in your directory
|
|
671
|
+
|
|
672
|
+
### Ingest not working
|
|
673
|
+
|
|
674
|
+
1. Ensure `--llm-api-key` is passed to the MCP server or `llmApiKey` is set in config
|
|
675
|
+
2. Check your API key is valid and has access to the specified model
|
|
676
|
+
3. The default model is `gpt-4.1-nano` — change with `--llm-model` if needed
|
|
677
|
+
|
|
678
|
+
### Relevance decay not running
|
|
679
|
+
|
|
680
|
+
1. Verify decay is enabled in project settings (`decayEnabled: true`)
|
|
681
|
+
2. The cron runs daily at 3 AM UTC — check the Convex dashboard cron jobs view
|
|
682
|
+
3. Pinned memories (priority >= 0.8) are intentionally excluded from decay
|