@raviolelabs/engram-mcp 0.2.3 → 0.4.3

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.
Files changed (38) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -4
  3. package/dist/core/logger.d.ts.map +1 -1
  4. package/dist/core/logger.js +4 -4
  5. package/dist/core/logger.js.map +1 -1
  6. package/dist/core/security/uri-validator.d.ts +7 -0
  7. package/dist/core/security/uri-validator.d.ts.map +1 -0
  8. package/dist/core/security/uri-validator.js +174 -0
  9. package/dist/core/security/uri-validator.js.map +1 -0
  10. package/dist/core/server/instructions.js +1 -1
  11. package/dist/core/server/mcp-handler.d.ts +1 -1
  12. package/dist/core/server/mcp-handler.d.ts.map +1 -1
  13. package/dist/core/server/mcp-handler.js +1 -1
  14. package/dist/core/server/mcp-handler.js.map +1 -1
  15. package/dist/core/server/mcp-http.d.ts.map +1 -1
  16. package/dist/core/server/mcp-http.js +52 -2
  17. package/dist/core/server/mcp-http.js.map +1 -1
  18. package/dist/mcp-server/tests/mcp-e2e.test.js +1 -1
  19. package/dist/mcp-server/tests/mcp-e2e.test.js.map +1 -1
  20. package/dist/memory/admin/tools.js +1 -1
  21. package/dist/memory/admin/tools.js.map +1 -1
  22. package/dist/memory/modules/audio/transcriber.d.ts.map +1 -1
  23. package/dist/memory/modules/audio/transcriber.js +3 -1
  24. package/dist/memory/modules/audio/transcriber.js.map +1 -1
  25. package/dist/memory/public/tools.d.ts.map +1 -1
  26. package/dist/memory/public/tools.js +32 -0
  27. package/dist/memory/public/tools.js.map +1 -1
  28. package/dist/server/api/integrations.d.ts.map +1 -1
  29. package/dist/server/api/integrations.js.map +1 -1
  30. package/dist/server/api/memories.d.ts.map +1 -1
  31. package/dist/server/api/memories.js +79 -8
  32. package/dist/server/api/memories.js.map +1 -1
  33. package/dist/server/api/types.d.ts +5 -0
  34. package/dist/server/api/types.d.ts.map +1 -1
  35. package/dist/server/api/types.js +90 -2
  36. package/dist/server/api/types.js.map +1 -1
  37. package/package.json +42 -41
  38. package/CLAUDE.md +0 -232
@@ -1,3 +1,8 @@
1
1
  import { Router } from 'express';
2
2
  export declare function typesApi(): Router;
3
+ /**
4
+ * Helper exported for `recall` and `list` callers — returns the set of type ids
5
+ * the user wants HIDDEN from default queries.
6
+ */
7
+ export declare function getDisabledTypes(): Set<string>;
3
8
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/api/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,wBAAgB,QAAQ,IAAI,MAAM,CAcjC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/api/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAgD9D,wBAAgB,QAAQ,IAAI,MAAM,CA6DjC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,GAAG,CAAC,MAAM,CAAC,CAE9C"}
@@ -1,20 +1,108 @@
1
1
  // src/webapp/api/types.ts
2
2
  import { Router } from 'express';
3
+ import { z } from 'zod';
3
4
  import { moduleRegistry } from '../../memory/core/module-registry.js';
4
5
  import { listCustomTypes } from '../../memory/modules/_custom/persistence.js';
6
+ import { getDb } from '../../db/index.js';
7
+ // ── Disabled types persistence (uses the existing `settings` table) ──────────
8
+ //
9
+ // Key: 'disabled_types' → JSON array of type names that are hidden from default
10
+ // recall/list operations. Disabling a type does NOT delete its memories — they
11
+ // stay in the store, just grayed out in the visualization and excluded from
12
+ // `recall()` calls unless `include_disabled=true` is passed.
13
+ const DISABLED_TYPES_KEY = 'disabled_types';
14
+ function loadDisabledTypes() {
15
+ const row = getDb()
16
+ .prepare('SELECT value_json FROM settings WHERE key = ?')
17
+ .get(DISABLED_TYPES_KEY);
18
+ if (!row)
19
+ return new Set();
20
+ try {
21
+ const parsed = JSON.parse(row.value_json);
22
+ if (Array.isArray(parsed))
23
+ return new Set(parsed.filter((x) => typeof x === 'string'));
24
+ }
25
+ catch {
26
+ /* fall through */
27
+ }
28
+ return new Set();
29
+ }
30
+ function saveDisabledTypes(disabled) {
31
+ getDb()
32
+ .prepare('INSERT OR REPLACE INTO settings (key, value_json, updated_at) VALUES (?, ?, ?)')
33
+ .run(DISABLED_TYPES_KEY, JSON.stringify([...disabled]), Date.now());
34
+ }
35
+ function countMemoriesByType() {
36
+ const rows = getDb()
37
+ .prepare('SELECT type, COUNT(*) as cnt FROM memories GROUP BY type')
38
+ .all();
39
+ const out = {};
40
+ for (const r of rows)
41
+ out[r.type] = r.cnt;
42
+ return out;
43
+ }
44
+ const PatchTypeBody = z.object({ disabled: z.boolean() });
5
45
  export function typesApi() {
6
46
  const r = Router();
47
+ // GET /api/types — list every known type with counts + disabled flag
7
48
  r.get('/', (_req, res) => {
8
- const builtins = moduleRegistry.list()
49
+ const disabled = loadDisabledTypes();
50
+ const counts = countMemoriesByType();
51
+ const builtins = moduleRegistry
52
+ .list()
9
53
  .filter((m) => !m.isCustom)
10
- .map((m) => ({ id: m.id, display_name: m.displayName, is_custom: false }));
54
+ .map((m) => ({
55
+ id: m.id,
56
+ display_name: m.displayName,
57
+ is_custom: false,
58
+ count: counts[m.id] ?? 0,
59
+ disabled: disabled.has(m.id),
60
+ }));
11
61
  const customs = listCustomTypes().map((d) => ({
12
62
  id: d.type_name,
13
63
  display_name: d.display_name,
14
64
  is_custom: true,
65
+ count: counts[d.type_name] ?? 0,
66
+ disabled: disabled.has(d.type_name),
15
67
  }));
16
68
  res.json([...builtins, ...customs]);
17
69
  });
70
+ // GET /api/types/disabled — convenience: just the list of disabled type ids
71
+ r.get('/disabled', (_req, res) => {
72
+ res.json({ disabled: [...loadDisabledTypes()] });
73
+ });
74
+ // PATCH /api/types/:typeName body: { disabled: boolean }
75
+ // Toggle a type's visibility in the dashboard / brain viz.
76
+ // No memories are deleted — the toggle is purely a UI/recall filter.
77
+ r.patch('/:typeName', (req, res) => {
78
+ const parsed = PatchTypeBody.safeParse(req.body);
79
+ if (!parsed.success) {
80
+ res.status(400).json({ error: 'invalid_body', issues: parsed.error.issues });
81
+ return;
82
+ }
83
+ const typeNameParam = req.params.typeName;
84
+ const typeName = Array.isArray(typeNameParam) ? typeNameParam[0] : typeNameParam;
85
+ if (!typeName || typeof typeName !== 'string') {
86
+ res.status(400).json({ error: 'type_name_required' });
87
+ return;
88
+ }
89
+ const disabled = loadDisabledTypes();
90
+ if (parsed.data.disabled) {
91
+ disabled.add(typeName);
92
+ }
93
+ else {
94
+ disabled.delete(typeName);
95
+ }
96
+ saveDisabledTypes(disabled);
97
+ res.json({ id: typeName, disabled: parsed.data.disabled });
98
+ });
18
99
  return r;
19
100
  }
101
+ /**
102
+ * Helper exported for `recall` and `list` callers — returns the set of type ids
103
+ * the user wants HIDDEN from default queries.
104
+ */
105
+ export function getDisabledTypes() {
106
+ return loadDisabledTypes();
107
+ }
20
108
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/server/api/types.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAE9E,MAAM,UAAU,QAAQ;IACtB,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC;IACnB,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,EAAE;aACnC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;aAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5C,EAAE,EAAE,CAAC,CAAC,SAAS;YACf,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC,CAAC;QACJ,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/server/api/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@raviolelabs/engram-mcp",
3
- "version": "0.2.3",
4
- "description": "EngramMCP — local-first semantic memory layer for AI agents",
3
+ "version": "0.4.3",
4
+ "mcpName": "io.github.RavioleLabs/engram-mcp",
5
+ "description": "EngramMCP \u2014 local-first semantic memory layer for AI agents",
5
6
  "license": "MIT",
6
7
  "type": "module",
7
8
  "bin": {
@@ -34,52 +35,52 @@
34
35
  "@lancedb/lancedb": "0.27.1",
35
36
  "@modelcontextprotocol/sdk": "1.28.0",
36
37
  "@notionhq/client": "2.3.0",
37
- "@tanstack/react-query": "^5.50.0",
38
- "@types/multer": "^2.1.0",
39
- "better-sqlite3": "^12.8.0",
40
- "cytoscape": "^3.33.3",
41
- "cytoscape-fcose": "^2.2.0",
42
- "express": "^5.0.0",
43
- "fast-xml-parser": "^5.8.0",
38
+ "@tanstack/react-query": "5.59.0",
39
+ "@types/multer": "2.1.0",
40
+ "better-sqlite3": "12.8.0",
41
+ "cytoscape": "3.33.3",
42
+ "cytoscape-fcose": "2.2.0",
43
+ "express": "5.0.0",
44
+ "fast-xml-parser": "5.8.0",
44
45
  "googleapis": "144.0.0",
45
- "libsodium-wrappers": "^0.8.4",
46
- "multer": "^2.1.1",
46
+ "libsodium-wrappers": "0.8.4",
47
+ "multer": "2.1.1",
47
48
  "node-cron": "3.0.3",
48
- "nodejs-whisper": "^0.2.4",
49
- "pdf-parse": "^2.4.5",
50
- "react": "^19.0.0",
51
- "react-dom": "^19.0.0",
52
- "react-router-dom": "^7.0.0",
53
- "secrets.js-grempe": "^2.0.0",
49
+ "nodejs-whisper": "0.2.4",
50
+ "pdf-parse": "2.4.5",
51
+ "react": "19.0.0",
52
+ "react-dom": "19.0.0",
53
+ "react-router-dom": "7.0.0",
54
+ "secrets.js-grempe": "2.0.0",
54
55
  "ulid": "2.4.0",
55
- "ws": "^8.18.0",
56
+ "ws": "8.18.0",
56
57
  "zod": "3.25.76"
57
58
  },
58
59
  "devDependencies": {
59
- "@tailwindcss/postcss": "^4.3.0",
60
- "@types/better-sqlite3": "^7.6.13",
61
- "@types/cytoscape": "^3.21.9",
62
- "@types/express": "^5.0.0",
63
- "@types/libsodium-wrappers": "^0.7.14",
64
- "@types/node": "^22.0.0",
60
+ "@tailwindcss/postcss": "4.3.0",
61
+ "@types/better-sqlite3": "7.6.13",
62
+ "@types/cytoscape": "3.21.9",
63
+ "@types/express": "5.0.0",
64
+ "@types/libsodium-wrappers": "0.7.14",
65
+ "@types/node": "22.0.0",
65
66
  "@types/node-cron": "3.0.11",
66
- "@types/pdf-parse": "^1.1.5",
67
- "@types/react": "^19.0.0",
68
- "@types/react-dom": "^19.0.0",
69
- "@types/ws": "^8.5.0",
70
- "@typescript-eslint/eslint-plugin": "^8.59.3",
71
- "@typescript-eslint/parser": "^8.59.3",
72
- "@vitejs/plugin-react": "^4.3.0",
73
- "@yao-pkg/pkg": "^5.12.0",
74
- "autoprefixer": "^10.4.0",
75
- "eslint": "^9.0.0",
76
- "postcss": "^8.4.0",
77
- "prettier": "^3.0.0",
78
- "tailwindcss": "^4.0.0",
79
- "tsx": "^4.0.0",
80
- "typescript": "^5.7.0",
81
- "vite": "^5.4.0",
82
- "vitest": "^2.0.0"
67
+ "@types/pdf-parse": "1.1.5",
68
+ "@types/react": "19.0.0",
69
+ "@types/react-dom": "19.0.0",
70
+ "@types/ws": "8.5.0",
71
+ "@typescript-eslint/eslint-plugin": "8.59.3",
72
+ "@typescript-eslint/parser": "8.59.3",
73
+ "@vitejs/plugin-react": "4.3.0",
74
+ "@yao-pkg/pkg": "5.12.0",
75
+ "autoprefixer": "10.4.0",
76
+ "eslint": "9.0.0",
77
+ "postcss": "8.4.0",
78
+ "prettier": "3.0.0",
79
+ "tailwindcss": "4.0.0",
80
+ "tsx": "4.0.0",
81
+ "typescript": "5.7.3",
82
+ "vite": "5.4.0",
83
+ "vitest": "2.0.0"
83
84
  },
84
85
  "engines": {
85
86
  "node": ">=22"
package/CLAUDE.md DELETED
@@ -1,232 +0,0 @@
1
- # EngramMCP
2
-
3
- > Local-first semantic memory layer for AI agents.
4
-
5
- EngramMCP exposes a Model Context Protocol (MCP) server that lets any AI agent (Claude Code, Cursor, custom Claude/GPT runtimes) capture, search, and enrich memory across multiple typed sources (notes, conversations, Drive, Notion, YouTube, Obsidian, audio, plus user-defined custom types).
6
-
7
- Forked from Argos. Local-first: vectors + content live on the user's machine; embeddings via local Ollama by default; no cloud required for Phase 1.
8
-
9
- ---
10
-
11
- ## Instructions for Claude Code
12
-
13
- Tu es le stagiaire technique d'EngramMCP. Sois **proactif**, **force de proposition**, et **autonome**.
14
-
15
- ### Comportement attendu
16
-
17
- - **Lis le code existant** avant de modifier — comprends le pattern en place
18
- - **Respecte les conventions** (voir ci-dessous)
19
- - **Pense modularité** — chaque memory type est un MemoryModule indépendant
20
- - **Sois concis** — pas de blabla, va droit au but, montre le code
21
- - **Challenge les décisions** sous-optimales avec arguments
22
- - **No mocks** pour les intégrations externes — tests E2E avec Ollama/LanceDB/SQLite/API réels
23
-
24
- ### Quand tu travailles sur EngramMCP
25
-
26
- 1. Lis toujours le code existant avant de modifier
27
- 2. Respecte la convention ES modules avec extensions `.js` dans les imports
28
- 3. Property extraction est **off par défaut** — l'agent appelant (toi) fournit `title`/`tags` directement
29
- 4. Vector store dimension est hardcoded à 768 (nomic-embed-text). Voyage (1024)/OpenAI (1536) requiert un fix dans `src/vector/store.ts`
30
- 5. Tool descriptions doivent être agent-friendly (mention WHEN to call, WHAT inputs help retrieval)
31
- 6. **v0.2 surface**: 10 public tools only. Admin tools behind `--admin` flag. See SKILL.md for agent usage guide.
32
-
33
- ---
34
-
35
- ## Quick Reference
36
-
37
- ### Commands
38
-
39
- ```bash
40
- npm run dev # tsx watch src/scripts/serve.ts
41
- npm run build # tsc → dist/
42
- npm run build:client # Vite → src/client/dist/
43
- npm run build:all # client + server
44
- npm start # node dist/scripts/serve.js
45
- npm run reindex # re-embed all memories after provider change
46
- npm run install:wizard # interactive first-time setup (tsx)
47
- npm run pair # interactive pairing wizard (engram-mcp-pair)
48
- npm run rebuild # rebuild SQLite+LanceDB from ops_log (engram-mcp rebuild)
49
- npm test # vitest run
50
- npm run lint # eslint src/
51
- ```
52
-
53
- ### Tech Stack
54
-
55
- | Layer | Tech |
56
- |---|---|
57
- | Runtime | Node.js >= 22, TypeScript 5.7 strict, ESM |
58
- | MCP | `@modelcontextprotocol/sdk@1.28` (stdio + StreamableHTTP) |
59
- | Vector | LanceDB (`@lancedb/lancedb@0.27`) per-type tables |
60
- | SQL | better-sqlite3 + FTS5 |
61
- | Embeddings | OpenAI-compat dispatch → ollama / engram / voyage / openai / openai-compatible |
62
- | Audio | nodejs-whisper (whisper.cpp) |
63
- | YouTube | watch-page scrape + yt-dlp fallback |
64
- | Web | Express 5, ws, React 19, Vite 5, Tailwind v4, react-query |
65
- | Validation | Zod everywhere |
66
- | IDs | ULID |
67
-
68
- ### Key conventions
69
-
70
- - **Module pattern**: `"type": "module"`, imports with `.js` extension
71
- - **Config**: Zod schema in `src/config/schema.ts`, loaded from `~/.engram/config.json` or env (`ENGRAM_CONFIG_DIR`, `DATA_DIR`)
72
- - **DB**: `getDb()` singleton, prepared statements only
73
- - **Logging**: `createLogger(scope)` from `src/logger.ts`
74
- - **Tool descriptions**: agent-facing — explain WHEN to use the tool and what title/tags improve retrieval
75
- - **Tests**: real services (Ollama, LanceDB, Notion sandbox, etc.). No mocks. Real-API tests use ephemeral tmpdirs.
76
-
77
- ---
78
-
79
- ## Architecture (Phase 1)
80
-
81
- ```
82
- ┌─ stdio ─┐
83
- agent runtime ──┤ ├──▶ MCP server (engram-mcp)
84
- └─ HTTP ─┘ │
85
-
86
- ┌─ ToolRouter ─┐
87
- │ 10 tools │ (+18 admin with --admin flag)
88
- └──────┬───────┘
89
-
90
- ┌─ ModuleRegistry ─┐
91
- │ notes │
92
- │ conversations │
93
- │ drive (OAuth) │
94
- │ notion (OAuth) │
95
- │ youtube │
96
- │ audio (Whisper) │
97
- │ obsidian │
98
- │ <custom types> │
99
- └────────┬─────────┘
100
-
101
- ┌─ MemoryStore ─┐
102
- │ insert │ ──▶ chunk + embed (Ollama)
103
- │ search │ ──▶ LanceDB per-type tables
104
- │ getById │ ──▶ SQLite + FTS5
105
- │ delete │
106
- │ findRelated │
107
- │ setProperties│
108
- └────────┬──────┘
109
- │ events: memory.added/deleted/updated
110
-
111
- WebSocket /ws ──▶ dashboard React UI
112
- ```
113
-
114
- Cloud bits (Phase 2 — Plan K): `engram-mcp pair` CLI activates cloud transit poller (node-cron,
115
- 5 min), Bridge Relay WSS client, and E2E encrypted blob dispatch from the Engram cloud inbox.
116
- Set ENGRAM_PASSPHRASE env var for the transit poller to start automatically at server boot.
117
- Mobile app, billing, and Engram-hosted embeddings server are in separate Plans (I, J, M).
118
-
119
- Phase 3 — Plan N (ops-log sync): Every local write (insert/delete/setProperties) is logged as a
120
- signed, AES-256-GCM-encrypted op in `ops_log` (SQLite). A `ChannelClient` pushes pending ops to
121
- the cloud `UserSyncChannel` Durable Object (engram-cloud) and receives ops from other devices.
122
- The `ReplayApplier` decrypts, verifies ed25519 signatures, and applies ops with LWW + union
123
- conflict resolution. `engram-mcp rebuild` drops SQLite+LanceDB and replays all ops from scratch.
124
- Enable via `config.json: {"sync": {"enabled": true, "cloudBaseUrl": "..."}}` + ENGRAM_PASSPHRASE.
125
- Full multi-PC sync requires Plan O cloud worker deployed (see RUNBOOK.md).
126
-
127
- ---
128
-
129
- ## Project Structure
130
-
131
- ```
132
- src/
133
- ├── types.ts # MemoryItem schema (Zod) + interfaces
134
- ├── logger.ts # createLogger
135
- ├── index.ts # (stub — entry is src/scripts/serve.ts)
136
- ├── config/{schema,index}.ts # Zod config + loader
137
- ├── db/index.ts # SQLite init + 3 migrations
138
- ├── embeddings/
139
- │ ├── index.ts # dispatcher
140
- │ └── providers/{ollama,engram,voyage,openai,openai-compat}.ts
141
- ├── vector/store.ts # LanceDB per-type tables
142
- ├── memory/
143
- │ ├── core/{chunker,wikilinks,module-interface,module-registry,
144
- │ │ store,source-registry,property-extractor,reindex}.ts
145
- │ ├── modules/
146
- │ │ ├── notes/ # add_note, search_notes
147
- │ │ ├── conversations/ # remember_exchange, search_conversations
148
- │ │ ├── drive/ # OAuth + watcher + ingest/list/watch tools
149
- │ │ ├── notion/ # OAuth + watcher + ingest/list/watch tools
150
- │ │ ├── audio/ # Whisper.cpp + add_audio_file/search_audio
151
- │ │ ├── youtube/ # transcript fetcher + add_youtube_url/search
152
- │ │ ├── obsidian/ # vault reader + fs.watch + tools
153
- │ │ └── _custom/ # generic-module factory + create/list/delete
154
- │ ├── public/tools.ts # 10 public tools: remember, recall, get, update,
155
- │ │ # forget, relate, list_types, recent, ingest,
156
- │ │ # suggest_properties
157
- │ └── admin/tools.ts # ~18 admin tools behind --admin flag:
158
- ├── core/ # LOW-LEVEL UTILITIES (canonical)
159
- │ ├── logger.ts # createLogger (was src/logger.ts)
160
- │ ├── db/index.ts # SQLite init + migrations (was src/db/index.ts)
161
- │ └── server/
162
- │ ├── mcp-handler.ts # buildEngramRuntime + startStdioMcpServer
163
- │ ├── tool-router.ts # ToolRouter
164
- │ ├── http.ts # Express bootstrap (was src/webapp/server.ts)
165
- │ ├── mcp-http.ts # StreamableHTTP MCP transport
166
- │ └── websocket.ts # WS broadcaster for memory.* events
167
- ├── tools/ # Top-level tool registry (mirrors predmcp pattern)
168
- │ └── index.ts # registerAllTools + dynamic private import
169
- ├── private/ # GITIGNORED — premium extensions (hosted Engram only)
170
- │ ├── index.ts # registerPrivateExtensions (no-op placeholder)
171
- │ ├── README.md # Explains what goes here
172
- │ ├── tools/ # Premium MCP tools
173
- │ ├── algorithms/ # Advanced algorithm overrides
174
- │ └── prompts/ # Tuned LLM prompts (IP)
175
- ├── server/ # Engram-specific HTTP routes
176
- │ ├── index.ts # Re-exports from core/server/http.ts
177
- │ └── api/{memories,sources,types,views,daily,settings,reindex,sync-status,graph}.ts
178
- ├── mcp-server/ # Re-export shims (→ core/server/)
179
- │ ├── server.ts # shim → core/server/mcp-handler.ts
180
- │ └── tool-router.ts # shim → core/server/tool-router.ts
181
- ├── webapp/ # Re-export shims (→ core/server/)
182
- │ ├── server.ts # shim → core/server/http.ts
183
- │ ├── mcp-http.ts # shim → core/server/mcp-http.ts
184
- │ ├── websocket.ts # shim → core/server/websocket.ts
185
- │ └── api/ # original api handlers (not shimmed — used by tests)
186
- ├── client/ # React/Vite/Tailwind dashboard
187
- │ ├── vite.config.ts
188
- │ ├── tsconfig.json (separate)
189
- │ └── src/{App,main,api,ws,index.css}.{ts,tsx,css}
190
- └── scripts/{serve,install,install-ollama,reindex}.ts
191
- ```
192
-
193
- ---
194
-
195
- ## Database Schema
196
-
197
- SQLite at `<dataDir>/engram.db` (WAL mode, FOREIGN KEYS ON):
198
-
199
- | Table | Purpose |
200
- |---|---|
201
- | `memories` | id, type, source_id, content, content_hash, properties_json, wikilinks_json, related_ids_json, embedding_model, created_at |
202
- | `memories_fts` | FTS5 virtual table on content/title/tags |
203
- | `custom_types` | type_name, display_name, schema_json, created_at |
204
- | `oauth_tokens` | provider, access_token, refresh_token, expires_at, extra_json |
205
- | `module_state` | (module_id, key) → value_json |
206
- | `watched_sources` | id, module_id, external_id, display_name, config_json, last_synced_at, last_modified_remote, last_error, enabled |
207
- | `saved_views` | id, name, description, definition_json, pinned, created_at, updated_at |
208
- | `settings` | key → value_json |
209
-
210
- Vector tables: `memories_<type>` per memory type in LanceDB (id, source_id, chunk_index, content, created_at, field1-4, vector 768-d).
211
-
212
- ---
213
-
214
- ## Pricing (planned)
215
-
216
- - **Free**: full local — Ollama embeddings, all modules, ~36 MCP tools
217
- - **Pro $9/mo** (Phase 2): mobile app, cloud transit, share-by-email, Engram hosted embeddings, multi-PC encrypted sync, online dashboard
218
- - **BYO premium embeddings** at any tier: Voyage / OpenAI / OAI-compatible
219
-
220
- ---
221
-
222
- ## Phase status
223
-
224
- - [x] **Phase 1** — local MCP server with all memory types (DONE — see docs/superpowers/plans/)
225
- - [ ] **Phase 2** — Mobile + cloud transit + billing + hosted Engram embeddings server
226
- - [ ] **Phase 3** — Bidirectional multi-PC sync (ops-log + cloud saves) + recovery shards
227
-
228
- ---
229
-
230
- ## License
231
-
232
- MIT