@jungjaehoon/clawdbot-mama 0.1.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/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # @jungjaehoon/clawdbot-mama
2
+
3
+ MAMA Memory Plugin for Clawdbot Gateway - Direct integration without HTTP overhead.
4
+
5
+ ## Features
6
+
7
+ - **Direct Gateway Integration**: Embeds MAMA logic directly into Clawdbot Gateway
8
+ - **4 Native Tools**: `mama_search`, `mama_save`, `mama_load_checkpoint`, `mama_update`
9
+ - **Semantic Search**: Vector-based decision retrieval using sqlite-vec
10
+ - **Decision Graph**: Track decision evolution with `builds_on`, `debates`, `synthesizes` edges
11
+
12
+ ## Installation
13
+
14
+ ### From npm (recommended)
15
+
16
+ ```bash
17
+ clawdbot plugins install @jungjaehoon/clawdbot-mama
18
+ ```
19
+
20
+ ### From source (development)
21
+
22
+ ```bash
23
+ # Clone the repo
24
+ git clone https://github.com/jungjaehoon-lifegamez/MAMA.git
25
+ cd MAMA
26
+
27
+ # Install dependencies
28
+ pnpm install
29
+
30
+ # Link plugin for development
31
+ ln -s $(pwd)/packages/clawdbot-plugin ~/.config/clawdbot/extensions/mama
32
+
33
+ # Restart gateway
34
+ systemctl --user restart clawdbot-gateway
35
+ ```
36
+
37
+ ## Configuration
38
+
39
+ Add to your `~/.clawdbot/clawdbot.json`:
40
+
41
+ ```json
42
+ {
43
+ "plugins": {
44
+ "slots": {
45
+ "memory": "mama"
46
+ },
47
+ "entries": {
48
+ "mama": {
49
+ "enabled": true
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## Tools
57
+
58
+ ### mama_search
59
+
60
+ Search semantic memory for relevant past decisions.
61
+
62
+ ```
63
+ Query: "authentication strategy"
64
+ Returns: Decisions ranked by semantic similarity
65
+ ```
66
+
67
+ ### mama_save
68
+
69
+ Save a decision or checkpoint to semantic memory.
70
+
71
+ ```
72
+ type: "decision" | "checkpoint"
73
+
74
+ # For decisions:
75
+ topic: "auth_strategy"
76
+ decision: "Use JWT with refresh tokens"
77
+ reasoning: "More secure than session cookies..."
78
+ confidence: 0.8
79
+
80
+ # For checkpoints:
81
+ summary: "Completed auth implementation"
82
+ next_steps: "Add rate limiting"
83
+ ```
84
+
85
+ ### mama_load_checkpoint
86
+
87
+ Resume previous session by loading the latest checkpoint.
88
+
89
+ ### mama_update
90
+
91
+ Update outcome of a previous decision.
92
+
93
+ ```
94
+ id: "decision_xxx"
95
+ outcome: "success" | "failed" | "partial"
96
+ reason: "Works well in production"
97
+ ```
98
+
99
+ ## Architecture
100
+
101
+ ```
102
+ Clawdbot Gateway
103
+ └── MAMA Plugin (this package)
104
+ └── @jungjaehoon/mama-server
105
+ ├── mama-api.js (high-level API)
106
+ ├── memory-store.js (SQLite + sqlite-vec)
107
+ └── embeddings.js (Transformers.js)
108
+ ```
109
+
110
+ Key design: NO HTTP/REST - MAMA logic is directly embedded into the Gateway for minimal latency (~5ms vs ~180ms with MCP).
111
+
112
+ ## Related Packages
113
+
114
+ - [@jungjaehoon/mama-server](https://www.npmjs.com/package/@jungjaehoon/mama-server) - MCP server for Claude Desktop
115
+ - [MAMA Plugin](https://github.com/jungjaehoon-lifegamez/MAMA/tree/main/packages/claude-code-plugin) - Claude Code plugin
116
+
117
+ ## License
118
+
119
+ MIT
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "mama",
3
+ "name": "MAMA Memory",
4
+ "description": "Memory-Augmented MCP Architecture - Semantic decision memory",
5
+ "kind": "memory",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "dbPath": {
11
+ "type": "string",
12
+ "description": "Path to MAMA SQLite database"
13
+ }
14
+ }
15
+ }
16
+ }
package/index.ts ADDED
@@ -0,0 +1,345 @@
1
+ /**
2
+ * MAMA Clawdbot Plugin - Direct Gateway Integration
3
+ *
4
+ * NO HTTP/REST - MAMA 로직을 Gateway에 직접 임베드
5
+ * better-sqlite3 + sqlite-vec로 벡터 검색
6
+ */
7
+
8
+ import { Type } from "@sinclair/typebox";
9
+ import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
10
+ import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
11
+ import path from "node:path";
12
+ import os from "node:os";
13
+
14
+ // MAMA 모듈 경로 - workspace dependency에서 resolve
15
+ const MAMA_MODULE_PATH = require.resolve("@jungjaehoon/mama-server/src/mama/mama-api.js").replace("/mama-api.js", "");
16
+
17
+ // Singleton state
18
+ let initialized = false;
19
+ let mama: any = null;
20
+
21
+ /**
22
+ * Initialize MAMA (lazy, once)
23
+ */
24
+ async function initMAMA(): Promise<void> {
25
+ if (initialized) return;
26
+
27
+ // Set DB path
28
+ process.env.MAMA_DB_PATH = process.env.MAMA_DB_PATH ||
29
+ path.join(os.homedir(), ".claude/mama-memory.db");
30
+
31
+ try {
32
+ // Load mama-api (high-level API)
33
+ mama = require(path.join(MAMA_MODULE_PATH, "mama-api.js"));
34
+
35
+ // Initialize database via memory-store
36
+ const memoryStore = require(path.join(MAMA_MODULE_PATH, "memory-store.js"));
37
+ await memoryStore.initDB();
38
+
39
+ initialized = true;
40
+ console.log("[MAMA Plugin] Initialized with direct module integration");
41
+ } catch (err: any) {
42
+ console.error("[MAMA Plugin] Init failed:", err.message);
43
+ throw err;
44
+ }
45
+ }
46
+
47
+ const mamaPlugin = {
48
+ id: "mama",
49
+ name: "MAMA Memory",
50
+ description: "Semantic decision memory - Direct Gateway integration (no HTTP)",
51
+ kind: "memory" as const,
52
+ configSchema: emptyPluginConfigSchema(),
53
+
54
+ register(api: ClawdbotPluginApi) {
55
+
56
+ // =====================================================
57
+ // mama_search - 시맨틱 메모리 검색
58
+ // =====================================================
59
+ api.registerTool({
60
+ name: "mama_search",
61
+ description: `Search semantic memory for relevant past decisions.
62
+
63
+ **ALWAYS use BEFORE making architectural decisions:**
64
+ - Find if this problem was solved before
65
+ - Recall reasoning and lessons learned
66
+ - Avoid repeating past mistakes
67
+ - Check for related decisions to link
68
+
69
+ **Returns:** Decisions ranked by semantic similarity with:
70
+ - Topic, decision, reasoning
71
+ - Similarity score (0-100%)
72
+ - Decision ID (for linking/updating)
73
+
74
+ **Example queries:** "authentication", "database choice", "error handling"`,
75
+
76
+ parameters: Type.Object({
77
+ query: Type.String({
78
+ description: "Search query - topic, question, or keywords"
79
+ }),
80
+ limit: Type.Optional(Type.Number({
81
+ description: "Max results (default: 5)"
82
+ })),
83
+ }),
84
+
85
+ async execute(_id: string, params: Record<string, unknown>) {
86
+ try {
87
+ await initMAMA();
88
+
89
+ const query = String(params.query || "").trim();
90
+ if (!query) {
91
+ return { content: [{ type: "text", text: "Error: query required" }] };
92
+ }
93
+
94
+ const limit = Math.min(Number(params.limit) || 5, 20);
95
+
96
+ // Use mama.suggest() for semantic search
97
+ const result = await mama.suggest(query, { limit, threshold: 0.5 });
98
+
99
+ if (!result?.results?.length) {
100
+ return {
101
+ content: [{ type: "text", text: `No decisions found for "${query}". This may be a new topic.` }]
102
+ };
103
+ }
104
+
105
+ // Format output
106
+ let output = `Found ${result.results.length} related decisions:\n\n`;
107
+ result.results.forEach((r: any, idx: number) => {
108
+ const pct = Math.round((r.similarity || 0) * 100);
109
+ output += `**${idx + 1}. ${r.topic}** [${pct}% match]\n`;
110
+ output += ` Decision: ${r.decision}\n`;
111
+ output += ` Reasoning: ${(r.reasoning || "").substring(0, 150)}...\n`;
112
+ output += ` ID: \`${r.id}\` | Outcome: ${r.outcome || "pending"}\n\n`;
113
+ });
114
+
115
+ return { content: [{ type: "text", text: output }] };
116
+ } catch (err: any) {
117
+ return { content: [{ type: "text", text: `MAMA error: ${err.message}` }] };
118
+ }
119
+ },
120
+ });
121
+
122
+ // =====================================================
123
+ // mama_save - 결정 또는 체크포인트 저장
124
+ // =====================================================
125
+ api.registerTool({
126
+ name: "mama_save",
127
+ description: `Save a decision or checkpoint to semantic memory.
128
+
129
+ **DECISION - Use when:**
130
+ - Making architectural choices
131
+ - Learning a lesson (success or failure)
132
+ - Establishing a pattern/convention
133
+ - Choosing between alternatives
134
+
135
+ **CHECKPOINT - Use when:**
136
+ - Ending a session (save state)
137
+ - Reaching a milestone
138
+ - Before switching tasks
139
+
140
+ **Link decisions:** Add "builds_on: decision_xxx" in reasoning to create graph edges.`,
141
+
142
+ parameters: Type.Object({
143
+ type: Type.Union([
144
+ Type.Literal("decision"),
145
+ Type.Literal("checkpoint"),
146
+ ], { description: "'decision' or 'checkpoint'" }),
147
+
148
+ topic: Type.Optional(Type.String({
149
+ description: "[Decision] Topic ID e.g. 'auth_strategy'"
150
+ })),
151
+ decision: Type.Optional(Type.String({
152
+ description: "[Decision] The decision e.g. 'Use JWT with refresh tokens'"
153
+ })),
154
+ reasoning: Type.Optional(Type.String({
155
+ description: "[Decision] Why. End with 'builds_on: <id>' to link."
156
+ })),
157
+ confidence: Type.Optional(Type.Number({
158
+ description: "[Decision] 0.0-1.0 (default: 0.8)"
159
+ })),
160
+
161
+ summary: Type.Optional(Type.String({
162
+ description: "[Checkpoint] What was accomplished"
163
+ })),
164
+ next_steps: Type.Optional(Type.String({
165
+ description: "[Checkpoint] What to do next"
166
+ })),
167
+ }),
168
+
169
+ async execute(_id: string, params: Record<string, unknown>) {
170
+ try {
171
+ await initMAMA();
172
+
173
+ const saveType = String(params.type);
174
+
175
+ if (saveType === "checkpoint") {
176
+ const summary = String(params.summary || "");
177
+ if (!summary) {
178
+ return { content: [{ type: "text", text: "Error: summary required for checkpoint" }] };
179
+ }
180
+
181
+ // mama.saveCheckpoint returns lastInsertRowid directly (not {id: ...})
182
+ const checkpointId = await mama.saveCheckpoint(
183
+ summary,
184
+ [],
185
+ String(params.next_steps || "")
186
+ );
187
+
188
+ return {
189
+ content: [{ type: "text", text: `Checkpoint saved (id: ${checkpointId})` }]
190
+ };
191
+ }
192
+
193
+ // Decision - use mama.save()
194
+ const topic = String(params.topic || "");
195
+ const decision = String(params.decision || "");
196
+ const reasoning = String(params.reasoning || "");
197
+
198
+ if (!topic || !decision || !reasoning) {
199
+ return {
200
+ content: [{ type: "text", text: "Error: topic, decision, and reasoning all required" }]
201
+ };
202
+ }
203
+
204
+ const confidence = Number(params.confidence) || 0.8;
205
+
206
+ // Use mama.save() API
207
+ const result = await mama.save({
208
+ topic,
209
+ decision,
210
+ reasoning,
211
+ confidence,
212
+ type: "assistant_insight",
213
+ });
214
+
215
+ // result contains: { id, similar_decisions, warning, collaboration_hint }
216
+ let msg = `Decision saved (id: ${result.id})`;
217
+ if (result.warning) {
218
+ msg += `\n⚠️ ${result.warning}`;
219
+ }
220
+ if (result.collaboration_hint) {
221
+ msg += `\n💡 ${result.collaboration_hint}`;
222
+ }
223
+
224
+ return { content: [{ type: "text", text: msg }] };
225
+ } catch (err: any) {
226
+ return { content: [{ type: "text", text: `MAMA error: ${err.message}` }] };
227
+ }
228
+ },
229
+ });
230
+
231
+ // =====================================================
232
+ // mama_load_checkpoint - 체크포인트 로드
233
+ // =====================================================
234
+ api.registerTool({
235
+ name: "mama_load_checkpoint",
236
+ description: `Load latest checkpoint to resume previous session.
237
+
238
+ **Use at session start to:**
239
+ - Restore previous context
240
+ - See where you left off
241
+ - Get planned next steps
242
+
243
+ Also returns recent decisions for context.`,
244
+
245
+ parameters: Type.Object({}),
246
+
247
+ async execute(_id: string, _params: Record<string, unknown>) {
248
+ try {
249
+ await initMAMA();
250
+
251
+ // Use mama.loadCheckpoint() and mama.list()
252
+ const checkpoint = await mama.loadCheckpoint();
253
+ const recentResult = await mama.list({ limit: 5 });
254
+ const recent = recentResult?.decisions || [];
255
+
256
+ if (!checkpoint) {
257
+ let msg = "No checkpoint found - fresh start.";
258
+ if (recent?.length) {
259
+ msg += "\n\nRecent decisions:\n";
260
+ recent.forEach((d: any) => {
261
+ msg += `- ${d.topic}: ${d.decision}\n`;
262
+ });
263
+ }
264
+ return { content: [{ type: "text", text: msg }] };
265
+ }
266
+
267
+ let msg = `**Checkpoint** (${new Date(checkpoint.timestamp).toLocaleString()})\n\n`;
268
+ msg += `**Summary:**\n${checkpoint.summary}\n\n`;
269
+
270
+ if (checkpoint.next_steps) {
271
+ msg += `**Next Steps:**\n${checkpoint.next_steps}\n\n`;
272
+ }
273
+
274
+ if (recent?.length) {
275
+ msg += `**Recent Decisions:**\n`;
276
+ recent.forEach((d: any) => {
277
+ msg += `- **${d.topic}**: ${d.decision} (${d.outcome || "pending"})\n`;
278
+ });
279
+ }
280
+
281
+ return { content: [{ type: "text", text: msg }] };
282
+ } catch (err: any) {
283
+ return { content: [{ type: "text", text: `MAMA error: ${err.message}` }] };
284
+ }
285
+ },
286
+ });
287
+
288
+ // =====================================================
289
+ // mama_update - 결과 업데이트
290
+ // =====================================================
291
+ api.registerTool({
292
+ name: "mama_update",
293
+ description: `Update outcome of a previous decision.
294
+
295
+ **Use when you learn if a decision worked:**
296
+ - SUCCESS: Worked well
297
+ - FAILED: Didn't work (include reason)
298
+ - PARTIAL: Partially worked
299
+
300
+ Helps future sessions learn from experience.`,
301
+
302
+ parameters: Type.Object({
303
+ id: Type.String({ description: "Decision ID to update" }),
304
+ outcome: Type.Union([
305
+ Type.Literal("success"),
306
+ Type.Literal("failed"),
307
+ Type.Literal("partial"),
308
+ ]),
309
+ reason: Type.Optional(Type.String({
310
+ description: "Why it succeeded/failed/partial"
311
+ })),
312
+ }),
313
+
314
+ async execute(_id: string, params: Record<string, unknown>) {
315
+ try {
316
+ await initMAMA();
317
+
318
+ const decisionId = String(params.id || "");
319
+ const outcome = String(params.outcome || "").toUpperCase();
320
+ const reason = String(params.reason || "");
321
+
322
+ if (!decisionId || !outcome) {
323
+ return { content: [{ type: "text", text: "Error: id and outcome required" }] };
324
+ }
325
+
326
+ // mama.updateOutcome(id, { outcome, failure_reason, limitation })
327
+ await mama.updateOutcome(decisionId, {
328
+ outcome,
329
+ failure_reason: outcome === "FAILED" ? reason : undefined,
330
+ limitation: outcome === "PARTIAL" ? reason : undefined,
331
+ });
332
+
333
+ return {
334
+ content: [{ type: "text", text: `Decision ${decisionId} updated to ${outcome}` }]
335
+ };
336
+ } catch (err: any) {
337
+ return { content: [{ type: "text", text: `MAMA error: ${err.message}` }] };
338
+ }
339
+ },
340
+ });
341
+
342
+ },
343
+ };
344
+
345
+ export default mamaPlugin;
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@jungjaehoon/clawdbot-mama",
3
+ "version": "0.1.0",
4
+ "description": "MAMA Memory Plugin for Clawdbot - Semantic decision memory with reasoning graph",
5
+ "type": "module",
6
+ "main": "index.ts",
7
+ "clawdbot": {
8
+ "extensions": [
9
+ "./index.ts"
10
+ ]
11
+ },
12
+ "scripts": {
13
+ "test": "echo 'No tests yet'",
14
+ "clean": "rm -rf node_modules"
15
+ },
16
+ "keywords": [
17
+ "clawdbot",
18
+ "clawdbot-plugin",
19
+ "memory",
20
+ "semantic-search",
21
+ "decision-tracking",
22
+ "mama"
23
+ ],
24
+ "author": "SpineLift Team",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/jungjaehoon-lifegamez/MAMA.git",
29
+ "directory": "packages/clawdbot-plugin"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/jungjaehoon-lifegamez/MAMA/issues"
33
+ },
34
+ "homepage": "https://github.com/jungjaehoon-lifegamez/MAMA#readme",
35
+ "peerDependencies": {
36
+ "clawdbot": ">=2026.1.24"
37
+ },
38
+ "dependencies": {
39
+ "@jungjaehoon/mama-server": "^1.5.8",
40
+ "@sinclair/typebox": "^0.32.0"
41
+ },
42
+ "files": [
43
+ "index.ts",
44
+ "clawdbot.plugin.json",
45
+ "README.md"
46
+ ]
47
+ }