apex-memory 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 EIGA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # apex-memory
2
+
3
+ [![CI](https://github.com/JJerryChoi/apex-memory/actions/workflows/ci.yml/badge.svg)](https://github.com/JJerryChoi/apex-memory/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/apex-memory.svg)](https://www.npmjs.com/package/apex-memory)
5
+ [![npm downloads](https://img.shields.io/npm/dm/apex-memory.svg)](https://www.npmjs.com/package/apex-memory)
6
+
7
+ **Persistent memory for AI coding agents.**
8
+
9
+ Give your AI coding agent memory that survives across sessions. apex-memory is an [MCP](https://modelcontextprotocol.io) server that lets agents save decisions, patterns, bugs, and context — then recall them exactly when needed.
10
+
11
+ - **One install, works everywhere** — MCP-native, works with Claude Code, Cursor, Windsurf, and any MCP-compatible editor
12
+ - **Zero infrastructure** — local SQLite database, no servers, no accounts
13
+ - **Built for coding agents** — categories like `decision`, `architecture`, `bug`, `pattern` designed for real development workflows
14
+ - **Full-text search** — find any memory instantly with FTS5-powered search
15
+
16
+ ## Quick Start
17
+
18
+ ### Claude Code
19
+
20
+ ```bash
21
+ claude mcp add apex-memory -- npx apex-memory
22
+ ```
23
+
24
+ That's it. Your agent now has persistent memory.
25
+
26
+ ### Cursor
27
+
28
+ Add to your MCP settings (`.cursor/mcp.json`):
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "apex-memory": {
34
+ "command": "npx",
35
+ "args": ["apex-memory"]
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ See the [Cursor setup guide](docs/guides/cursor.md) for full details and troubleshooting.
42
+
43
+ ### Windsurf
44
+
45
+ Open `~/.codeium/windsurf/mcp_config.json` (via `Cmd+Shift+P` → "Windsurf: Open MCP Config") and add:
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "apex-memory": {
51
+ "command": "npx",
52
+ "args": ["apex-memory"]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ See the [Windsurf setup guide](docs/guides/windsurf.md) for full details and troubleshooting.
59
+
60
+ ### Other MCP Clients
61
+
62
+ apex-memory works with any MCP-compatible client. Point it at:
63
+
64
+ ```bash
65
+ npx apex-memory
66
+ ```
67
+
68
+ The server communicates over stdio using the standard MCP protocol. See the [generic MCP setup guide](docs/guides/generic-mcp.md) for examples with VS Code, Continue.dev, and custom clients.
69
+
70
+ ## Tools
71
+
72
+ apex-memory gives your agent 9 tools:
73
+
74
+ | Tool | Description |
75
+ |------|-------------|
76
+ | `save_memory` | Save knowledge, decisions, patterns, or context with categories, tags, and importance scoring (1–5) |
77
+ | `search_memories` | Full-text search across all memories (supports AND, OR, NOT, phrases) |
78
+ | `recall` | Retrieve recent memories filtered by project, category, or tags |
79
+ | `delete_memory` | Remove a specific memory by ID |
80
+ | `decay_memories` | Archive old low-importance memories that were never accessed — keeps the store clean |
81
+ | `start_session` | Begin a coding session tied to a project |
82
+ | `end_session` | End a session with a summary of what was accomplished |
83
+ | `list_sessions` | View past coding sessions |
84
+ | `memory_stats` | Get statistics about stored memories and sessions |
85
+
86
+ ## How It Works
87
+
88
+ When your agent encounters something worth remembering — an architectural decision, a tricky bug fix, a user preference — it calls `save_memory`:
89
+
90
+ ```
91
+ save_memory({
92
+ content: "User prefers functional components over class components in React",
93
+ category: "preference",
94
+ tags: ["react", "components"],
95
+ project: "frontend-app"
96
+ })
97
+ ```
98
+
99
+ Next session, the agent recalls context before starting work:
100
+
101
+ ```
102
+ recall({ project: "frontend-app" })
103
+ ```
104
+
105
+ Or searches for something specific:
106
+
107
+ ```
108
+ search_memories({ query: "authentication AND JWT" })
109
+ ```
110
+
111
+ ### Categories
112
+
113
+ Organize memories by what they represent:
114
+
115
+ | Category | Use for |
116
+ |----------|---------|
117
+ | `decision` | Architectural and design decisions |
118
+ | `pattern` | Code patterns and conventions |
119
+ | `bug` | Bugs encountered and their fixes |
120
+ | `architecture` | System design and structure |
121
+ | `preference` | User and team preferences |
122
+ | `learning` | Lessons learned |
123
+ | `context` | Project context and background |
124
+ | `general` | Everything else |
125
+
126
+ ### Sessions
127
+
128
+ Track coding sessions to group related memories:
129
+
130
+ ```
131
+ start_session({ project: "api-server" })
132
+ // ... agent works, saves memories with the session_id ...
133
+ end_session({ session_id: "...", summary: "Refactored auth middleware to use JWT" })
134
+ ```
135
+
136
+ ## Storage
137
+
138
+ All data is stored locally in `~/.apex-memory/memory.db` — a SQLite database with WAL mode and FTS5 full-text search. No data leaves your machine.
139
+
140
+ ## Pricing
141
+
142
+ | Tier | What you get | Price |
143
+ |------|-------------|-------|
144
+ | **Free** | Local storage, unlimited sessions, single machine | $0 |
145
+ | **Pro** | Cloud sync across machines, search API, up to 1GB | $9/workspace/month |
146
+ | **Team** | Shared multi-agent memory, analytics, unlimited storage | $29/workspace/month |
147
+
148
+ The free tier is fully functional. Pro and Team tiers are coming soon.
149
+
150
+ ## Why apex-memory?
151
+
152
+ | | apex-memory | Mem0 | Letta | OneContext |
153
+ |---|---|---|---|---|
154
+ | **Built for coding agents** | Yes | General purpose | General purpose | General purpose |
155
+ | **MCP-native** | Yes | No | No | No |
156
+ | **Zero infrastructure** | Yes (SQLite) | Requires server | Requires server | Cloud-only |
157
+ | **Install time** | 30 seconds | Minutes | Minutes | Minutes |
158
+ | **Works with Claude Code** | Yes | Manual integration | Manual integration | No |
159
+ | **Session tracking** | Built-in | No | No | No |
160
+ | **Full-text search** | FTS5 | Vector search | Vector search | Vector search |
161
+ | **Open source** | MIT | Partial | Yes | No |
162
+
163
+ apex-memory is purpose-built for the coding agent workflow. It's not a general-purpose memory layer — it's the memory system your AI coding agent should have had from day one.
164
+
165
+ ## Contributing
166
+
167
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
168
+
169
+ ## License
170
+
171
+ [MIT](LICENSE)
@@ -0,0 +1,39 @@
1
+ import Database from "better-sqlite3";
2
+ export interface Memory {
3
+ id: string;
4
+ content: string;
5
+ category: string;
6
+ tags: string;
7
+ project: string;
8
+ session_id: string | null;
9
+ importance: number;
10
+ access_count: number;
11
+ last_accessed_at: string | null;
12
+ created_at: string;
13
+ updated_at: string;
14
+ deleted_at: string | null;
15
+ }
16
+ export interface Session {
17
+ id: string;
18
+ project: string;
19
+ summary: string | null;
20
+ started_at: string;
21
+ ended_at: string | null;
22
+ }
23
+ export declare function createDatabase(dbPath?: string): Database.Database;
24
+ export declare function saveMemory(db: Database.Database, content: string, category: string, tags: string[], project: string, sessionId?: string, importance?: number): Memory;
25
+ export declare function searchMemories(db: Database.Database, query: string, project?: string, limit?: number): Memory[];
26
+ export declare function recallMemories(db: Database.Database, project?: string, category?: string, tags?: string[], limit?: number): Memory[];
27
+ export declare function deleteMemory(db: Database.Database, id: string): boolean;
28
+ export declare function decayMemories(db: Database.Database, dayThreshold?: number, maxImportance?: number): number;
29
+ export declare function startSession(db: Database.Database, project: string): Session;
30
+ export declare function endSession(db: Database.Database, sessionId: string, summary: string): Session | null;
31
+ export declare function listSessions(db: Database.Database, project?: string, limit?: number): Session[];
32
+ export declare function getStats(db: Database.Database): {
33
+ memories: number;
34
+ sessions: number;
35
+ projects: string[];
36
+ };
37
+ export declare function getSyncState(db: Database.Database, key: string): string | null;
38
+ export declare function setSyncState(db: Database.Database, key: string, value: string): void;
39
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAMtC,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAqDD,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CA+DjE;AAYD,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,GAAE,MAAU,GACrB,MAAM,CAwBR;AAED,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,GAAE,MAAW,GACjB,MAAM,EAAE,CAqCV;AAED,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,EAAE,EACf,KAAK,GAAE,MAAW,GACjB,MAAM,EAAE,CA6BV;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAMvE;AAED,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,YAAY,GAAE,MAAW,EACzB,aAAa,GAAE,MAAU,GACxB,MAAM,CAYR;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAST;AAED,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,GAAG,IAAI,CAUhB;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,GAAE,MAAW,GACjB,OAAO,EAAE,CASX;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAK1G;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG9E;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEpF"}
@@ -0,0 +1,257 @@
1
+ import Database from "better-sqlite3";
2
+ import { randomUUID } from "node:crypto";
3
+ import { existsSync, mkdirSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { homedir } from "node:os";
6
+ function getDbPath() {
7
+ const dir = join(homedir(), ".apex-memory");
8
+ if (!existsSync(dir)) {
9
+ mkdirSync(dir, { recursive: true });
10
+ }
11
+ return join(dir, "memory.db");
12
+ }
13
+ function runMigrations(db) {
14
+ const columns = db.pragma("table_info(memories)").map((c) => c.name);
15
+ if (!columns.includes("importance")) {
16
+ db.exec(`ALTER TABLE memories ADD COLUMN importance INTEGER NOT NULL DEFAULT 3`);
17
+ }
18
+ if (!columns.includes("access_count")) {
19
+ db.exec(`ALTER TABLE memories ADD COLUMN access_count INTEGER NOT NULL DEFAULT 0`);
20
+ }
21
+ if (!columns.includes("last_accessed_at")) {
22
+ db.exec(`ALTER TABLE memories ADD COLUMN last_accessed_at TEXT`);
23
+ }
24
+ if (!columns.includes("deleted_at")) {
25
+ db.exec(`ALTER TABLE memories ADD COLUMN deleted_at TEXT`);
26
+ }
27
+ if (!columns.includes("updated_at")) {
28
+ db.exec(`ALTER TABLE memories ADD COLUMN updated_at TEXT`);
29
+ db.exec(`UPDATE memories SET updated_at = created_at WHERE updated_at IS NULL`);
30
+ }
31
+ // Ensure sync_state table exists (idempotent)
32
+ db.exec(`
33
+ CREATE TABLE IF NOT EXISTS sync_state (
34
+ key TEXT PRIMARY KEY,
35
+ value TEXT NOT NULL
36
+ )
37
+ `);
38
+ // Update memories_au trigger to exclude soft-deleted rows from FTS
39
+ db.exec(`
40
+ DROP TRIGGER IF EXISTS memories_au;
41
+ CREATE TRIGGER memories_au AFTER UPDATE ON memories BEGIN
42
+ INSERT INTO memories_fts(memories_fts, rowid, content, category, tags, project)
43
+ VALUES('delete', old.rowid, old.content, old.category, old.tags, old.project);
44
+ INSERT INTO memories_fts(rowid, content, category, tags, project)
45
+ SELECT new.rowid, new.content, new.category, new.tags, new.project
46
+ WHERE new.deleted_at IS NULL;
47
+ END
48
+ `);
49
+ }
50
+ export function createDatabase(dbPath) {
51
+ const path = dbPath ?? getDbPath();
52
+ const db = new Database(path);
53
+ db.pragma("journal_mode = WAL");
54
+ db.pragma("foreign_keys = ON");
55
+ db.exec(`
56
+ CREATE TABLE IF NOT EXISTS memories (
57
+ id TEXT PRIMARY KEY,
58
+ content TEXT NOT NULL,
59
+ category TEXT NOT NULL DEFAULT 'general',
60
+ tags TEXT NOT NULL DEFAULT '',
61
+ project TEXT NOT NULL DEFAULT '',
62
+ session_id TEXT,
63
+ importance INTEGER NOT NULL DEFAULT 3,
64
+ access_count INTEGER NOT NULL DEFAULT 0,
65
+ last_accessed_at TEXT,
66
+ created_at TEXT NOT NULL,
67
+ updated_at TEXT,
68
+ deleted_at TEXT
69
+ );
70
+
71
+ CREATE TABLE IF NOT EXISTS sessions (
72
+ id TEXT PRIMARY KEY,
73
+ project TEXT NOT NULL DEFAULT '',
74
+ summary TEXT,
75
+ started_at TEXT NOT NULL,
76
+ ended_at TEXT
77
+ );
78
+
79
+ CREATE TABLE IF NOT EXISTS sync_state (
80
+ key TEXT PRIMARY KEY,
81
+ value TEXT NOT NULL
82
+ );
83
+
84
+ CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
85
+ content, category, tags, project,
86
+ content=memories, content_rowid=rowid
87
+ );
88
+
89
+ CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
90
+ INSERT INTO memories_fts(rowid, content, category, tags, project)
91
+ VALUES (new.rowid, new.content, new.category, new.tags, new.project);
92
+ END;
93
+
94
+ CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
95
+ INSERT INTO memories_fts(memories_fts, rowid, content, category, tags, project)
96
+ VALUES('delete', old.rowid, old.content, old.category, old.tags, old.project);
97
+ END;
98
+
99
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
100
+ INSERT INTO memories_fts(memories_fts, rowid, content, category, tags, project)
101
+ VALUES('delete', old.rowid, old.content, old.category, old.tags, old.project);
102
+ INSERT INTO memories_fts(rowid, content, category, tags, project)
103
+ SELECT new.rowid, new.content, new.category, new.tags, new.project
104
+ WHERE new.deleted_at IS NULL;
105
+ END;
106
+ `);
107
+ runMigrations(db);
108
+ return db;
109
+ }
110
+ function touchMemories(db, ids) {
111
+ if (ids.length === 0)
112
+ return;
113
+ const now = new Date().toISOString();
114
+ const placeholders = ids.map(() => "?").join(",");
115
+ db.prepare(`UPDATE memories SET access_count = access_count + 1, last_accessed_at = ?, updated_at = ?
116
+ WHERE id IN (${placeholders})`).run(now, now, ...ids);
117
+ }
118
+ export function saveMemory(db, content, category, tags, project, sessionId, importance = 3) {
119
+ const id = randomUUID();
120
+ const now = new Date().toISOString();
121
+ const tagsStr = tags.join(",");
122
+ db.prepare(`INSERT INTO memories (id, content, category, tags, project, session_id, importance, access_count, last_accessed_at, created_at, updated_at, deleted_at)
123
+ VALUES (?, ?, ?, ?, ?, ?, ?, 0, NULL, ?, ?, NULL)`).run(id, content, category, tagsStr, project, sessionId ?? null, importance, now, now);
124
+ return {
125
+ id,
126
+ content,
127
+ category,
128
+ tags: tagsStr,
129
+ project,
130
+ session_id: sessionId ?? null,
131
+ importance,
132
+ access_count: 0,
133
+ last_accessed_at: null,
134
+ created_at: now,
135
+ updated_at: now,
136
+ deleted_at: null,
137
+ };
138
+ }
139
+ export function searchMemories(db, query, project, limit = 20) {
140
+ let rows;
141
+ if (project) {
142
+ rows = db
143
+ .prepare(`SELECT m.* FROM memories m
144
+ JOIN memories_fts f ON m.rowid = f.rowid
145
+ WHERE memories_fts MATCH ? AND m.project = ? AND m.deleted_at IS NULL
146
+ ORDER BY rank
147
+ LIMIT ?`)
148
+ .all(query, project, limit);
149
+ }
150
+ else {
151
+ rows = db
152
+ .prepare(`SELECT m.* FROM memories m
153
+ JOIN memories_fts f ON m.rowid = f.rowid
154
+ WHERE memories_fts MATCH ? AND m.deleted_at IS NULL
155
+ ORDER BY rank
156
+ LIMIT ?`)
157
+ .all(query, limit);
158
+ }
159
+ // Deduplicate — FTS5 join can return duplicate rows
160
+ const seen = new Set();
161
+ const results = rows.filter((m) => {
162
+ if (seen.has(m.id))
163
+ return false;
164
+ seen.add(m.id);
165
+ return true;
166
+ });
167
+ const searchNow = new Date().toISOString();
168
+ touchMemories(db, results.map((m) => m.id));
169
+ for (const m of results) {
170
+ m.access_count += 1;
171
+ m.last_accessed_at = searchNow;
172
+ }
173
+ return results;
174
+ }
175
+ export function recallMemories(db, project, category, tags, limit = 20) {
176
+ let sql = `SELECT * FROM memories WHERE deleted_at IS NULL`;
177
+ const params = [];
178
+ if (project) {
179
+ sql += ` AND project = ?`;
180
+ params.push(project);
181
+ }
182
+ if (category) {
183
+ sql += ` AND category = ?`;
184
+ params.push(category);
185
+ }
186
+ if (tags && tags.length > 0) {
187
+ for (const tag of tags) {
188
+ sql += ` AND tags LIKE ?`;
189
+ params.push(`%${tag}%`);
190
+ }
191
+ }
192
+ sql += ` ORDER BY created_at DESC LIMIT ?`;
193
+ params.push(limit);
194
+ const results = db.prepare(sql).all(...params);
195
+ const recallNow = new Date().toISOString();
196
+ touchMemories(db, results.map((m) => m.id));
197
+ for (const m of results) {
198
+ m.access_count += 1;
199
+ m.last_accessed_at = recallNow;
200
+ }
201
+ return results;
202
+ }
203
+ export function deleteMemory(db, id) {
204
+ const now = new Date().toISOString();
205
+ const result = db
206
+ .prepare(`UPDATE memories SET deleted_at = ?, updated_at = ? WHERE id = ? AND deleted_at IS NULL`)
207
+ .run(now, now, id);
208
+ return result.changes > 0;
209
+ }
210
+ export function decayMemories(db, dayThreshold = 30, maxImportance = 2) {
211
+ const now = new Date().toISOString();
212
+ const result = db
213
+ .prepare(`UPDATE memories SET deleted_at = ?, updated_at = ?
214
+ WHERE importance <= ?
215
+ AND access_count = 0
216
+ AND deleted_at IS NULL
217
+ AND created_at < datetime('now', ? || ' days')`)
218
+ .run(now, now, maxImportance, `-${dayThreshold}`);
219
+ return result.changes;
220
+ }
221
+ export function startSession(db, project) {
222
+ const id = randomUUID();
223
+ const now = new Date().toISOString();
224
+ db.prepare(`INSERT INTO sessions (id, project, started_at) VALUES (?, ?, ?)`).run(id, project, now);
225
+ return { id, project, summary: null, started_at: now, ended_at: null };
226
+ }
227
+ export function endSession(db, sessionId, summary) {
228
+ const now = new Date().toISOString();
229
+ const result = db.prepare(`UPDATE sessions SET summary = ?, ended_at = ? WHERE id = ?`).run(summary, now, sessionId);
230
+ if (result.changes === 0)
231
+ return null;
232
+ return db.prepare(`SELECT * FROM sessions WHERE id = ?`).get(sessionId);
233
+ }
234
+ export function listSessions(db, project, limit = 20) {
235
+ if (project) {
236
+ return db
237
+ .prepare(`SELECT * FROM sessions WHERE project = ? ORDER BY started_at DESC LIMIT ?`)
238
+ .all(project, limit);
239
+ }
240
+ return db
241
+ .prepare(`SELECT * FROM sessions ORDER BY started_at DESC LIMIT ?`)
242
+ .all(limit);
243
+ }
244
+ export function getStats(db) {
245
+ const memoriesCount = db.prepare(`SELECT COUNT(*) as count FROM memories WHERE deleted_at IS NULL`).get().count;
246
+ const sessionsCount = db.prepare(`SELECT COUNT(*) as count FROM sessions`).get().count;
247
+ const projects = db.prepare(`SELECT DISTINCT project FROM memories WHERE project != '' AND deleted_at IS NULL ORDER BY project`).all().map(r => r.project);
248
+ return { memories: memoriesCount, sessions: sessionsCount, projects };
249
+ }
250
+ export function getSyncState(db, key) {
251
+ const row = db.prepare(`SELECT value FROM sync_state WHERE key = ?`).get(key);
252
+ return row?.value ?? null;
253
+ }
254
+ export function setSyncState(db, key, value) {
255
+ db.prepare(`INSERT INTO sync_state (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(key, value);
256
+ }
257
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/build/index.js ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { createDatabase } from "./database.js";
5
+ import { registerTools } from "./tools.js";
6
+ const server = new McpServer({
7
+ name: "apex-memory",
8
+ version: "0.1.0",
9
+ });
10
+ const db = createDatabase();
11
+ registerTools(server, db);
12
+ async function main() {
13
+ const transport = new StdioServerTransport();
14
+ await server.connect(transport);
15
+ console.error("apex-memory v0.1.0 running on stdio");
16
+ }
17
+ main().catch((error) => {
18
+ console.error("Fatal error:", error);
19
+ process.exit(1);
20
+ });
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;AAC5B,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAE1B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;AACvD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type Database from "better-sqlite3";
3
+ export declare function registerTools(server: McpServer, db: Database.Database): void;
4
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAa3C,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CA4P5E"}
package/build/tools.js ADDED
@@ -0,0 +1,193 @@
1
+ import { z } from "zod";
2
+ import { saveMemory, searchMemories, recallMemories, deleteMemory, decayMemories, startSession, endSession, listSessions, getStats, } from "./database.js";
3
+ export function registerTools(server, db) {
4
+ server.tool("save_memory", "Save a piece of knowledge, decision, pattern, or context for future recall. Use categories like: decision, pattern, bug, architecture, preference, learning, context.", {
5
+ content: z.string().describe("The memory content to save"),
6
+ category: z
7
+ .string()
8
+ .default("general")
9
+ .describe("Category: decision, pattern, bug, architecture, preference, learning, context, general"),
10
+ tags: z
11
+ .array(z.string())
12
+ .default([])
13
+ .describe("Tags for filtering and organization"),
14
+ project: z
15
+ .string()
16
+ .default("")
17
+ .describe("Project name this memory belongs to"),
18
+ session_id: z
19
+ .string()
20
+ .optional()
21
+ .describe("Session ID if this memory is part of an active session"),
22
+ importance: z
23
+ .number()
24
+ .int()
25
+ .min(1)
26
+ .max(5)
27
+ .default(3)
28
+ .describe("Importance score 1-5 (1=low/ephemeral, 3=default, 5=critical decision)"),
29
+ }, async ({ content, category, tags, project, session_id, importance }) => {
30
+ const memory = saveMemory(db, content, category, tags, project, session_id, importance);
31
+ return {
32
+ content: [
33
+ {
34
+ type: "text",
35
+ text: `Saved memory ${memory.id}\nCategory: ${memory.category}\nProject: ${memory.project || "(global)"}\nTags: ${memory.tags || "(none)"}\nImportance: ${memory.importance}/5`,
36
+ },
37
+ ],
38
+ };
39
+ });
40
+ server.tool("search_memories", "Full-text search across all stored memories. Returns the most relevant matches.", {
41
+ query: z.string().describe("Search query (supports FTS5 syntax: AND, OR, NOT, phrases)"),
42
+ project: z
43
+ .string()
44
+ .optional()
45
+ .describe("Filter to a specific project"),
46
+ limit: z.number().default(20).describe("Max results to return"),
47
+ }, async ({ query, project, limit }) => {
48
+ const memories = searchMemories(db, query, project, limit);
49
+ if (memories.length === 0) {
50
+ return {
51
+ content: [{ type: "text", text: "No memories found matching your query." }],
52
+ };
53
+ }
54
+ const formatted = memories
55
+ .map((m) => `[${m.id}] (${m.category}) [importance:${m.importance}] ${m.project ? `[${m.project}]` : ""} ${m.created_at}\n${m.content}${m.tags ? `\nTags: ${m.tags}` : ""}`)
56
+ .join("\n---\n");
57
+ return {
58
+ content: [{ type: "text", text: `Found ${memories.length} memories:\n\n${formatted}` }],
59
+ };
60
+ });
61
+ server.tool("recall", "Retrieve recent memories filtered by project, category, or tags. Use at the start of a session to restore context.", {
62
+ project: z
63
+ .string()
64
+ .optional()
65
+ .describe("Filter to a specific project"),
66
+ category: z
67
+ .string()
68
+ .optional()
69
+ .describe("Filter by category"),
70
+ tags: z
71
+ .array(z.string())
72
+ .optional()
73
+ .describe("Filter by tags (all must match)"),
74
+ limit: z.number().default(20).describe("Max results to return"),
75
+ }, async ({ project, category, tags, limit }) => {
76
+ const memories = recallMemories(db, project, category, tags, limit);
77
+ if (memories.length === 0) {
78
+ return {
79
+ content: [{ type: "text", text: "No memories found with the given filters." }],
80
+ };
81
+ }
82
+ const formatted = memories
83
+ .map((m) => `[${m.id}] (${m.category}) [importance:${m.importance}] ${m.project ? `[${m.project}]` : ""} ${m.created_at}\n${m.content}${m.tags ? `\nTags: ${m.tags}` : ""}`)
84
+ .join("\n---\n");
85
+ return {
86
+ content: [{ type: "text", text: `Recalled ${memories.length} memories:\n\n${formatted}` }],
87
+ };
88
+ });
89
+ server.tool("delete_memory", "Delete a specific memory by ID.", {
90
+ id: z.string().describe("The memory ID to delete"),
91
+ }, async ({ id }) => {
92
+ const deleted = deleteMemory(db, id);
93
+ return {
94
+ content: [
95
+ {
96
+ type: "text",
97
+ text: deleted ? `Deleted memory ${id}` : `Memory ${id} not found`,
98
+ },
99
+ ],
100
+ };
101
+ });
102
+ server.tool("decay_memories", "Archive (delete) low-importance memories that have never been accessed and are older than a threshold. Keeps the memory store clean by removing stale, low-value context.", {
103
+ day_threshold: z
104
+ .number()
105
+ .int()
106
+ .min(1)
107
+ .default(30)
108
+ .describe("Delete memories older than this many days (default 30)"),
109
+ max_importance: z
110
+ .number()
111
+ .int()
112
+ .min(1)
113
+ .max(4)
114
+ .default(2)
115
+ .describe("Only delete memories with importance <= this value (default 2; never deletes importance 5)"),
116
+ }, async ({ day_threshold, max_importance }) => {
117
+ const deleted = decayMemories(db, day_threshold, max_importance);
118
+ return {
119
+ content: [
120
+ {
121
+ type: "text",
122
+ text: deleted === 0
123
+ ? `No memories decayed. No stale low-importance memories found older than ${day_threshold} days.`
124
+ : `Decayed ${deleted} memories (importance ≤ ${max_importance}, never accessed, older than ${day_threshold} days).`,
125
+ },
126
+ ],
127
+ };
128
+ });
129
+ server.tool("start_session", "Start a new coding session. Returns a session ID to associate memories with this session.", {
130
+ project: z.string().describe("Project name for this session"),
131
+ }, async ({ project }) => {
132
+ const session = startSession(db, project);
133
+ return {
134
+ content: [
135
+ {
136
+ type: "text",
137
+ text: `Started session ${session.id}\nProject: ${session.project}\nStarted: ${session.started_at}`,
138
+ },
139
+ ],
140
+ };
141
+ });
142
+ server.tool("end_session", "End a coding session with a summary of what was accomplished.", {
143
+ session_id: z.string().describe("The session ID to end"),
144
+ summary: z.string().describe("Summary of what was accomplished in this session"),
145
+ }, async ({ session_id, summary }) => {
146
+ const session = endSession(db, session_id, summary);
147
+ if (!session) {
148
+ return {
149
+ content: [{ type: "text", text: `Session ${session_id} not found` }],
150
+ };
151
+ }
152
+ return {
153
+ content: [
154
+ {
155
+ type: "text",
156
+ text: `Ended session ${session.id}\nProject: ${session.project}\nDuration: ${session.started_at} → ${session.ended_at}\nSummary: ${session.summary}`,
157
+ },
158
+ ],
159
+ };
160
+ });
161
+ server.tool("list_sessions", "List past coding sessions, optionally filtered by project.", {
162
+ project: z
163
+ .string()
164
+ .optional()
165
+ .describe("Filter to a specific project"),
166
+ limit: z.number().default(20).describe("Max results to return"),
167
+ }, async ({ project, limit }) => {
168
+ const sessions = listSessions(db, project, limit);
169
+ if (sessions.length === 0) {
170
+ return {
171
+ content: [{ type: "text", text: "No sessions found." }],
172
+ };
173
+ }
174
+ const formatted = sessions
175
+ .map((s) => `[${s.id}] ${s.project} | ${s.started_at} → ${s.ended_at ?? "active"}${s.summary ? `\n ${s.summary}` : ""}`)
176
+ .join("\n");
177
+ return {
178
+ content: [{ type: "text", text: `Sessions:\n\n${formatted}` }],
179
+ };
180
+ });
181
+ server.tool("memory_stats", "Get statistics about stored memories and sessions.", {}, async () => {
182
+ const stats = getStats(db);
183
+ return {
184
+ content: [
185
+ {
186
+ type: "text",
187
+ text: `Memories: ${stats.memories}\nSessions: ${stats.sessions}\nProjects: ${stats.projects.length > 0 ? stats.projects.join(", ") : "(none)"}`,
188
+ },
189
+ ],
190
+ };
191
+ });
192
+ }
193
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "apex-memory",
3
+ "version": "0.2.0",
4
+ "description": "Persistent memory MCP server for AI coding agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "apex-memory": "build/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc && chmod 755 build/index.js",
11
+ "dev": "tsc --watch",
12
+ "test": "vitest run",
13
+ "test:watch": "vitest",
14
+ "test:coverage": "vitest run --coverage"
15
+ },
16
+ "files": [
17
+ "build",
18
+ "!build/__tests__"
19
+ ],
20
+ "keywords": [
21
+ "mcp",
22
+ "memory",
23
+ "ai",
24
+ "coding-agents",
25
+ "persistent-context"
26
+ ],
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/JJerryChoi/apex-memory.git"
31
+ },
32
+ "homepage": "https://github.com/JJerryChoi/apex-memory#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/JJerryChoi/apex-memory/issues"
35
+ },
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.12.0",
38
+ "better-sqlite3": "^11.0.0",
39
+ "zod": "^3.24.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/better-sqlite3": "^7.6.0",
43
+ "@types/node": "^22.0.0",
44
+ "typescript": "^5.7.0",
45
+ "vitest": "^4.0.18"
46
+ }
47
+ }