@nguyentamdat/mempalace 1.0.0 → 1.0.2
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 +66 -16
- package/package.json +4 -3
- package/src/commands/compress.ts +2 -1
- package/src/config.ts +7 -0
- package/src/convo-miner.ts +2 -1
- package/src/layers.ts +7 -7
- package/src/mcp-server.ts +1 -1
- package/src/miner.ts +3 -2
- package/src/palace-graph.ts +1 -1
- package/src/searcher.ts +5 -5
package/README.md
CHANGED
|
@@ -6,27 +6,66 @@ A structured, persistent memory system for AI agents — featuring a palace meta
|
|
|
6
6
|
|
|
7
7
|
This is a **Bun/TypeScript** port of the original [mempalace](https://github.com/milla-jovovich/mempalace) by [milla-jovovich](https://github.com/milla-jovovich).
|
|
8
8
|
|
|
9
|
+
> **OpenCode users**: See [opencode-mempalace](https://github.com/nguyentamdat/opencode-mempalace) for plug-and-play integration.
|
|
10
|
+
|
|
9
11
|
## Requirements
|
|
10
12
|
|
|
11
13
|
- [Bun](https://bun.sh/) ≥ 1.0
|
|
12
|
-
- [ChromaDB](https://www.trychroma.com/) server running
|
|
14
|
+
- [ChromaDB](https://www.trychroma.com/) server running
|
|
13
15
|
|
|
14
16
|
## Install
|
|
15
17
|
|
|
16
18
|
```bash
|
|
19
|
+
npm install @nguyentamdat/mempalace
|
|
20
|
+
# or
|
|
17
21
|
git clone https://github.com/nguyentamdat/mempalace-js.git
|
|
18
22
|
cd mempalace-js
|
|
19
23
|
bun install
|
|
20
24
|
```
|
|
21
25
|
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
### 1. Start ChromaDB
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Docker (recommended)
|
|
32
|
+
docker run -d --name chromadb -p 127.0.0.1:8001:8000 \
|
|
33
|
+
-v chromadb-data:/chroma/chroma --restart unless-stopped \
|
|
34
|
+
chromadb/chroma:latest
|
|
35
|
+
|
|
36
|
+
# Or pip
|
|
37
|
+
pip install chromadb
|
|
38
|
+
chroma run --port 8001
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Configure
|
|
42
|
+
|
|
43
|
+
The default ChromaDB URL is `http://localhost:8000`. Override via environment variable or config:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Environment variable
|
|
47
|
+
export CHROMA_URL=http://localhost:8001
|
|
48
|
+
|
|
49
|
+
# Or in ~/.mempalace/config.json
|
|
50
|
+
{
|
|
51
|
+
"chroma_url": "http://localhost:8001",
|
|
52
|
+
"palace_path": "~/.mempalace/palace",
|
|
53
|
+
"collection_name": "mempalace_drawers",
|
|
54
|
+
"topic_wings": ["work", "personal", "technical", "creative"]
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Initialize
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bun run src/index.ts init /path/to/project
|
|
62
|
+
```
|
|
63
|
+
|
|
22
64
|
## Usage
|
|
23
65
|
|
|
24
66
|
### CLI
|
|
25
67
|
|
|
26
68
|
```bash
|
|
27
|
-
# Initialize a new palace
|
|
28
|
-
bun run src/index.ts init
|
|
29
|
-
|
|
30
69
|
# Mine project files into the palace
|
|
31
70
|
bun run src/index.ts mine --mode projects --path ./my-project
|
|
32
71
|
|
|
@@ -36,7 +75,7 @@ bun run src/index.ts mine --mode convos --path ./transcripts
|
|
|
36
75
|
# Search memories
|
|
37
76
|
bun run src/index.ts search "some query"
|
|
38
77
|
|
|
39
|
-
# Compress memories with AAAK dialect
|
|
78
|
+
# Compress memories with AAAK dialect (~30x reduction)
|
|
40
79
|
bun run src/index.ts compress
|
|
41
80
|
|
|
42
81
|
# Load memory layers (wake-up)
|
|
@@ -54,23 +93,29 @@ bun run src/index.ts status
|
|
|
54
93
|
Run as a JSON-RPC MCP server over stdin/stdout (19 tools):
|
|
55
94
|
|
|
56
95
|
```bash
|
|
57
|
-
bun run src/mcp-server.ts
|
|
96
|
+
CHROMA_URL=http://localhost:8001 bun run src/mcp-server.ts
|
|
58
97
|
```
|
|
59
98
|
|
|
60
|
-
Tools
|
|
99
|
+
Tools: `mempalace_search`, `mempalace_kg_query`, `mempalace_kg_timeline`, `mempalace_kg_add`, `mempalace_kg_invalidate`, `mempalace_diary_write`, `mempalace_diary_read`, `mempalace_status`, `mempalace_list_wings`, `mempalace_list_rooms`, `mempalace_get_taxonomy`, `mempalace_add_drawer`, `mempalace_delete_drawer`, `mempalace_check_duplicate`, `mempalace_traverse`, `mempalace_find_tunnels`, `mempalace_graph_stats`, `mempalace_get_aaak_spec`.
|
|
61
100
|
|
|
62
101
|
## Architecture
|
|
63
102
|
|
|
64
103
|
### Palace Structure
|
|
65
104
|
|
|
66
105
|
```
|
|
67
|
-
|
|
68
|
-
├──
|
|
106
|
+
~/.mempalace/
|
|
107
|
+
├── palace/ (ChromaDB collection data reference)
|
|
108
|
+
├── config.json (palace configuration)
|
|
109
|
+
├── entity_registry.json
|
|
110
|
+
├── identity.txt (Layer 0 — who am I)
|
|
111
|
+
└── knowledge_graph.db (SQLite)
|
|
112
|
+
|
|
113
|
+
Palace (in ChromaDB)
|
|
114
|
+
├── Wings (top-level categories: work, personal, technical, etc.)
|
|
69
115
|
│ └── Rooms (specific topics within a wing)
|
|
70
|
-
│ └── Drawers (individual memories
|
|
71
|
-
├──
|
|
72
|
-
|
|
73
|
-
└── Config (config.json, entity_registry.json, identity.txt)
|
|
116
|
+
│ └── Drawers (individual memories with metadata)
|
|
117
|
+
├── Diary wing (per-agent daily entries)
|
|
118
|
+
└── Embeddings (DefaultEmbeddingFunction)
|
|
74
119
|
```
|
|
75
120
|
|
|
76
121
|
### Memory Layers
|
|
@@ -84,7 +129,7 @@ Palace (~/.mempalace/)
|
|
|
84
129
|
|
|
85
130
|
### AAAK Compression Dialect
|
|
86
131
|
|
|
87
|
-
A compact encoding format for memories that reduces token usage while preserving meaning.
|
|
132
|
+
A compact encoding format for memories that reduces token usage ~30x while preserving meaning. Uses 3-letter entity codes, emotion markers, pipe-separated fields, and importance stars (★–★★★★★).
|
|
88
133
|
|
|
89
134
|
### Knowledge Graph
|
|
90
135
|
|
|
@@ -94,7 +139,8 @@ SQLite-based temporal entity-relationship graph with validity windows and confid
|
|
|
94
139
|
|
|
95
140
|
| Module | Description |
|
|
96
141
|
|--------|-------------|
|
|
97
|
-
| `config.ts` | Palace configuration
|
|
142
|
+
| `config.ts` | Palace configuration (env vars, config.json, defaults) |
|
|
143
|
+
| `mcp-server.ts` | JSON-RPC MCP server (19 tools) |
|
|
98
144
|
| `knowledge-graph.ts` | Temporal entity-relationship graph (bun:sqlite) |
|
|
99
145
|
| `dialect.ts` | AAAK compression dialect |
|
|
100
146
|
| `layers.ts` | 4-layer memory stack |
|
|
@@ -110,7 +156,6 @@ SQLite-based temporal entity-relationship graph with validity windows and confid
|
|
|
110
156
|
| `room-detector-local.ts` | Room detection from folder structure |
|
|
111
157
|
| `spellcheck.ts` | Optional spell correction |
|
|
112
158
|
| `split-mega-files.ts` | Split concatenated transcripts |
|
|
113
|
-
| `mcp-server.ts` | JSON-RPC MCP server (19 tools) |
|
|
114
159
|
|
|
115
160
|
## Tests
|
|
116
161
|
|
|
@@ -118,6 +163,11 @@ SQLite-based temporal entity-relationship graph with validity windows and confid
|
|
|
118
163
|
bun test
|
|
119
164
|
```
|
|
120
165
|
|
|
166
|
+
## Related
|
|
167
|
+
|
|
168
|
+
- [opencode-mempalace](https://github.com/nguyentamdat/opencode-mempalace) — OpenCode plugin for automatic integration
|
|
169
|
+
- [mempalace](https://github.com/milla-jovovich/mempalace) — Original Python implementation
|
|
170
|
+
|
|
121
171
|
## Acknowledgements
|
|
122
172
|
|
|
123
173
|
This project is a Bun/TypeScript port of the original [mempalace](https://github.com/milla-jovovich/mempalace) by [milla-jovovich](https://github.com/milla-jovovich). All credit for the palace architecture, AAAK compression dialect, knowledge graph design, memory layer system, and MCP tool definitions goes to their work.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nguyentamdat/mempalace",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Give your AI a memory. No API key required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
"mcp": "bun run src/mcp-server.ts"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
+
"@clack/prompts": "^0.9.1",
|
|
16
17
|
"chromadb": "^1.9.2",
|
|
18
|
+
"chromadb-default-embed": "^2.14.0",
|
|
17
19
|
"citty": "^0.1.6",
|
|
18
|
-
"js-yaml": "^4.1.0"
|
|
19
|
-
"@clack/prompts": "^0.9.1"
|
|
20
|
+
"js-yaml": "^4.1.0"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
|
22
23
|
"@types/js-yaml": "^4.0.9",
|
package/src/commands/compress.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineCommand } from "citty";
|
|
2
2
|
import { resolvePalacePath } from "../cli";
|
|
3
|
+
import { MempalaceConfig } from "../config";
|
|
3
4
|
|
|
4
5
|
export default defineCommand({
|
|
5
6
|
meta: { description: "Compress drawers using AAAK Dialect (~30x reduction)" },
|
|
@@ -40,7 +41,7 @@ export default defineCommand({
|
|
|
40
41
|
let client: InstanceType<typeof ChromaClient>;
|
|
41
42
|
let col: Awaited<ReturnType<InstanceType<typeof ChromaClient>["getCollection"]>>;
|
|
42
43
|
try {
|
|
43
|
-
client = new ChromaClient({ path:
|
|
44
|
+
client = new ChromaClient({ path: new MempalaceConfig().chromaUrl });
|
|
44
45
|
col = await client.getCollection({
|
|
45
46
|
name: "mempalace_drawers",
|
|
46
47
|
embeddingFunction: new DefaultEmbeddingFunction(),
|
package/src/config.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { homedir } from "os";
|
|
|
10
10
|
|
|
11
11
|
export const DEFAULT_PALACE_PATH = join(homedir(), ".mempalace", "palace");
|
|
12
12
|
export const DEFAULT_COLLECTION_NAME = "mempalace_drawers";
|
|
13
|
+
export const DEFAULT_CHROMA_URL = process.env.CHROMA_URL ?? "http://localhost:8000";
|
|
13
14
|
|
|
14
15
|
export const DEFAULT_TOPIC_WINGS = [
|
|
15
16
|
"emotions",
|
|
@@ -89,6 +90,12 @@ export class MempalaceConfig {
|
|
|
89
90
|
return (this.fileConfig.hall_keywords as Record<string, string[]>) ?? DEFAULT_HALL_KEYWORDS;
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
get chromaUrl(): string {
|
|
94
|
+
const envVal = process.env.CHROMA_URL;
|
|
95
|
+
if (envVal) return envVal;
|
|
96
|
+
return (this.fileConfig.chroma_url as string) ?? DEFAULT_CHROMA_URL;
|
|
97
|
+
}
|
|
98
|
+
|
|
92
99
|
init(): string {
|
|
93
100
|
mkdirSync(this.configDir, { recursive: true });
|
|
94
101
|
if (!existsSync(this.configFile)) {
|
package/src/convo-miner.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { mkdirSync, readdirSync, statSync } from "node:fs";
|
|
3
3
|
import { basename, extname, resolve } from "node:path";
|
|
4
4
|
import { ChromaClient } from "chromadb";
|
|
5
|
+
import { MempalaceConfig } from "./config";
|
|
5
6
|
|
|
6
7
|
import { extractMemories } from "./general-extractor";
|
|
7
8
|
import { normalize } from "./normalize";
|
|
@@ -163,7 +164,7 @@ export function detectConvoRoom(content: string): string {
|
|
|
163
164
|
|
|
164
165
|
export async function getCollection(palacePath: string): Promise<DrawerCollection> {
|
|
165
166
|
mkdirSync(palacePath, { recursive: true });
|
|
166
|
-
const client = new ChromaClient();
|
|
167
|
+
const client = new ChromaClient({ path: new MempalaceConfig().chromaUrl });
|
|
167
168
|
return client.getOrCreateCollection({ name: COLLECTION_NAME });
|
|
168
169
|
}
|
|
169
170
|
|
package/src/layers.ts
CHANGED
|
@@ -146,8 +146,8 @@ async function loadDialect(): Promise<DialectLike> {
|
|
|
146
146
|
return dialectPromise;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
async function getCollection(
|
|
150
|
-
const client = new ChromaClient({ path:
|
|
149
|
+
async function getCollection(collectionName: string): Promise<Collection> {
|
|
150
|
+
const client = new ChromaClient({ path: new MempalaceConfig().chromaUrl });
|
|
151
151
|
return await client.getCollection({ name: collectionName } as never);
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -198,7 +198,7 @@ export class Layer1 {
|
|
|
198
198
|
let collection: Collection;
|
|
199
199
|
|
|
200
200
|
try {
|
|
201
|
-
collection = await getCollection(this.
|
|
201
|
+
collection = await getCollection(this.collectionName);
|
|
202
202
|
} catch {
|
|
203
203
|
return "## L1 — No palace found. Run: mempalace mine <dir>";
|
|
204
204
|
}
|
|
@@ -294,7 +294,7 @@ export class Layer2 {
|
|
|
294
294
|
let collection: Collection;
|
|
295
295
|
|
|
296
296
|
try {
|
|
297
|
-
collection = await getCollection(this.
|
|
297
|
+
collection = await getCollection(this.collectionName);
|
|
298
298
|
} catch {
|
|
299
299
|
return "No palace found.";
|
|
300
300
|
}
|
|
@@ -354,7 +354,7 @@ export class Layer3 {
|
|
|
354
354
|
let collection: Collection;
|
|
355
355
|
|
|
356
356
|
try {
|
|
357
|
-
collection = await getCollection(this.
|
|
357
|
+
collection = await getCollection(this.collectionName);
|
|
358
358
|
} catch {
|
|
359
359
|
return "No palace found.";
|
|
360
360
|
}
|
|
@@ -402,7 +402,7 @@ export class Layer3 {
|
|
|
402
402
|
let collection: Collection;
|
|
403
403
|
|
|
404
404
|
try {
|
|
405
|
-
collection = await getCollection(this.
|
|
405
|
+
collection = await getCollection(this.collectionName);
|
|
406
406
|
} catch {
|
|
407
407
|
return [];
|
|
408
408
|
}
|
|
@@ -499,7 +499,7 @@ export class MemoryStack {
|
|
|
499
499
|
};
|
|
500
500
|
|
|
501
501
|
try {
|
|
502
|
-
const collection = await getCollection(
|
|
502
|
+
const collection = await getCollection(new MempalaceConfig().collectionName);
|
|
503
503
|
result.totalDrawers = await collection.count();
|
|
504
504
|
} catch {
|
|
505
505
|
result.totalDrawers = 0;
|
package/src/mcp-server.ts
CHANGED
|
@@ -176,7 +176,7 @@ function toDirection(value: unknown): KgDirection {
|
|
|
176
176
|
|
|
177
177
|
async function getCollection(create = false): Promise<DrawerCollection | null> {
|
|
178
178
|
try {
|
|
179
|
-
const client = new ChromaClient();
|
|
179
|
+
const client = new ChromaClient({ path: config.chromaUrl });
|
|
180
180
|
if (create) {
|
|
181
181
|
return await client.getOrCreateCollection({
|
|
182
182
|
name: config.collectionName,
|
package/src/miner.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { basename, extname, relative, resolve } from "node:path";
|
|
10
10
|
import { ChromaClient, DefaultEmbeddingFunction, IncludeEnum } from "chromadb";
|
|
11
11
|
import yaml from "js-yaml";
|
|
12
|
+
import { MempalaceConfig } from "./config";
|
|
12
13
|
|
|
13
14
|
export const READABLE_EXTENSIONS = new Set([
|
|
14
15
|
".txt",
|
|
@@ -291,7 +292,7 @@ export async function getCollection(
|
|
|
291
292
|
palacePath: string,
|
|
292
293
|
): Promise<DrawerCollection> {
|
|
293
294
|
mkdirSync(palacePath, { recursive: true });
|
|
294
|
-
const client = new ChromaClient();
|
|
295
|
+
const client = new ChromaClient({ path: new MempalaceConfig().chromaUrl });
|
|
295
296
|
return client.getOrCreateCollection({ name: COLLECTION_NAME });
|
|
296
297
|
}
|
|
297
298
|
|
|
@@ -562,7 +563,7 @@ export async function mine(
|
|
|
562
563
|
export async function status(palacePath: string): Promise<void> {
|
|
563
564
|
try {
|
|
564
565
|
mkdirSync(palacePath, { recursive: true });
|
|
565
|
-
const client = new ChromaClient();
|
|
566
|
+
const client = new ChromaClient({ path: new MempalaceConfig().chromaUrl });
|
|
566
567
|
const collection = await client.getCollection({
|
|
567
568
|
name: COLLECTION_NAME,
|
|
568
569
|
embeddingFunction: new DefaultEmbeddingFunction(),
|
package/src/palace-graph.ts
CHANGED
|
@@ -37,7 +37,7 @@ export async function getCollection(
|
|
|
37
37
|
config: MempalaceConfig = new MempalaceConfig(),
|
|
38
38
|
): Promise<ChromaCollection | null> {
|
|
39
39
|
try {
|
|
40
|
-
const client = new ChromaClient({ path: config.
|
|
40
|
+
const client = new ChromaClient({ path: config.chromaUrl });
|
|
41
41
|
return (await client.getCollection({
|
|
42
42
|
name: config.collectionName,
|
|
43
43
|
embeddingFunction: undefined as any,
|
package/src/searcher.ts
CHANGED
|
@@ -38,7 +38,7 @@ function buildWhereFilter(wing?: string, room?: string) {
|
|
|
38
38
|
async function getDrawerCollection(palacePath: string) {
|
|
39
39
|
const config = new MempalaceConfig();
|
|
40
40
|
const collectionName = config.collectionName;
|
|
41
|
-
const client = new ChromaClient({ path:
|
|
41
|
+
const client = new ChromaClient({ path: config.chromaUrl });
|
|
42
42
|
const embeddingFunction = new DefaultEmbeddingFunction();
|
|
43
43
|
|
|
44
44
|
try {
|
|
@@ -69,8 +69,8 @@ export async function search({
|
|
|
69
69
|
|
|
70
70
|
try {
|
|
71
71
|
const kwargs = {
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
queryTexts: [query],
|
|
73
|
+
nResults: nResults,
|
|
74
74
|
include: ["documents", "metadatas", "distances"],
|
|
75
75
|
} as unknown as DrawerQueryParams;
|
|
76
76
|
|
|
@@ -141,8 +141,8 @@ export async function searchMemories({
|
|
|
141
141
|
|
|
142
142
|
try {
|
|
143
143
|
const kwargs = {
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
queryTexts: [query],
|
|
145
|
+
nResults: nResults,
|
|
146
146
|
include: ["documents", "metadatas", "distances"],
|
|
147
147
|
} as unknown as DrawerQueryParams;
|
|
148
148
|
|