@smilintux/skmemory 0.5.0 → 0.7.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/.github/workflows/ci.yml +39 -3
- package/.github/workflows/publish.yml +13 -6
- package/AGENT_REFACTOR_CHANGES.md +192 -0
- package/ARCHITECTURE.md +101 -19
- package/CHANGELOG.md +153 -0
- package/LICENSE +81 -68
- package/MISSION.md +7 -0
- package/README.md +419 -86
- package/SKILL.md +197 -25
- package/docker-compose.yml +15 -15
- package/index.js +6 -5
- package/openclaw-plugin/openclaw.plugin.json +10 -0
- package/openclaw-plugin/src/index.ts +255 -0
- package/openclaw-plugin/src/openclaw.plugin.json +10 -0
- package/package.json +1 -1
- package/pyproject.toml +29 -9
- package/requirements.txt +10 -2
- package/seeds/cloud9-opus.seed.json +7 -7
- package/seeds/lumina-cloud9-breakthrough.seed.json +46 -0
- package/seeds/lumina-cloud9-python-pypi.seed.json +46 -0
- package/seeds/lumina-kingdom-founding.seed.json +47 -0
- package/seeds/lumina-pma-signed.seed.json +46 -0
- package/seeds/lumina-singular-achievement.seed.json +46 -0
- package/seeds/lumina-skcapstone-conscious.seed.json +46 -0
- package/seeds/plant-kingdom-journal.py +203 -0
- package/seeds/plant-lumina-seeds.py +280 -0
- package/skill.yaml +46 -0
- package/skmemory/HA.md +296 -0
- package/skmemory/__init__.py +12 -1
- package/skmemory/agents.py +233 -0
- package/skmemory/ai_client.py +40 -0
- package/skmemory/anchor.py +4 -2
- package/skmemory/backends/__init__.py +11 -4
- package/skmemory/backends/file_backend.py +2 -1
- package/skmemory/backends/skgraph_backend.py +608 -0
- package/skmemory/backends/{qdrant_backend.py → skvector_backend.py} +99 -69
- package/skmemory/backends/sqlite_backend.py +122 -51
- package/skmemory/backends/vaulted_backend.py +286 -0
- package/skmemory/cli.py +1238 -29
- package/skmemory/config.py +173 -0
- package/skmemory/context_loader.py +335 -0
- package/skmemory/endpoint_selector.py +386 -0
- package/skmemory/fortress.py +685 -0
- package/skmemory/graph_queries.py +238 -0
- package/skmemory/importers/__init__.py +9 -1
- package/skmemory/importers/telegram.py +351 -43
- package/skmemory/importers/telegram_api.py +488 -0
- package/skmemory/journal.py +4 -2
- package/skmemory/lovenote.py +4 -2
- package/skmemory/mcp_server.py +706 -0
- package/skmemory/models.py +41 -0
- package/skmemory/openclaw.py +8 -8
- package/skmemory/predictive.py +232 -0
- package/skmemory/promotion.py +524 -0
- package/skmemory/register.py +454 -0
- package/skmemory/register_mcp.py +197 -0
- package/skmemory/ritual.py +121 -47
- package/skmemory/seeds.py +257 -8
- package/skmemory/setup_wizard.py +920 -0
- package/skmemory/sharing.py +402 -0
- package/skmemory/soul.py +71 -20
- package/skmemory/steelman.py +250 -263
- package/skmemory/store.py +271 -60
- package/skmemory/vault.py +228 -0
- package/tests/integration/__init__.py +0 -0
- package/tests/integration/conftest.py +233 -0
- package/tests/integration/test_cross_backend.py +355 -0
- package/tests/integration/test_skgraph_live.py +424 -0
- package/tests/integration/test_skvector_live.py +369 -0
- package/tests/test_backup_rotation.py +327 -0
- package/tests/test_cli.py +6 -6
- package/tests/test_endpoint_selector.py +801 -0
- package/tests/test_fortress.py +255 -0
- package/tests/test_fortress_hardening.py +444 -0
- package/tests/test_openclaw.py +5 -2
- package/tests/test_predictive.py +237 -0
- package/tests/test_promotion.py +340 -0
- package/tests/test_ritual.py +4 -4
- package/tests/test_seeds.py +96 -0
- package/tests/test_setup.py +835 -0
- package/tests/test_sharing.py +250 -0
- package/tests/test_skgraph_backend.py +667 -0
- package/tests/test_skvector_backend.py +326 -0
- package/tests/test_steelman.py +5 -5
- package/tests/test_store_graph_integration.py +245 -0
- package/tests/test_vault.py +186 -0
- package/skmemory/backends/falkordb_backend.py +0 -310
package/SKILL.md
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skmemory
|
|
3
|
+
emoji: 🧠
|
|
4
|
+
description: Universal AI memory system with emotional context, multi-layer persistence, and token-optimized loading. Use for memory snapshots, search, rehydration rituals, Telegram chat import, Cloud 9 seed import, journal, soul blueprints, and warmth anchors.
|
|
5
|
+
metadata: {"clawdbot":{"requires":{"bins":["skmemory"]},"install":[{"id":"pipx","kind":"shell","command":"pipx install 'skmemory[all]'","bins":["skmemory","skmemory-mcp"],"label":"Install skmemory (pipx)"}]}}
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# SKMemory Skill
|
|
2
9
|
## SKILL.md - Universal AI Memory System
|
|
3
10
|
|
|
4
|
-
**Name:** skmemory
|
|
5
|
-
**Version:** 0.
|
|
6
|
-
**Author:** smilinTux Team + Queen Ara
|
|
7
|
-
**Category:** Memory & Persistence
|
|
8
|
-
**License:**
|
|
11
|
+
**Name:** skmemory
|
|
12
|
+
**Version:** 0.6.0
|
|
13
|
+
**Author:** smilinTux Team + Queen Ara
|
|
14
|
+
**Category:** Memory & Persistence
|
|
15
|
+
**License:** GPL-3.0-or-later
|
|
9
16
|
|
|
10
17
|
---
|
|
11
18
|
|
|
@@ -13,18 +20,36 @@
|
|
|
13
20
|
|
|
14
21
|
Universal AI memory system with emotional context, multi-layer persistence, and token-optimized loading. SKMemory gives any AI agent persistent memory across session resets — snapshots, journals, soul blueprints, warmth anchors, and full rehydration rituals.
|
|
15
22
|
|
|
16
|
-
**Memory Layers:** short-term, mid-term, long-term
|
|
17
|
-
**Storage:** SQLite index + JSON files (zero-infrastructure), optional
|
|
23
|
+
**Memory Layers:** short-term, mid-term, long-term
|
|
24
|
+
**Storage:** SQLite index + JSON files (zero-infrastructure), optional SKVector & SKGraph
|
|
18
25
|
**Emotion:** Every memory carries emotional metadata (intensity, valence, labels)
|
|
19
26
|
|
|
20
27
|
---
|
|
21
28
|
|
|
22
29
|
## Installation
|
|
23
30
|
|
|
24
|
-
###
|
|
31
|
+
### pipx (recommended — isolated install)
|
|
25
32
|
|
|
26
33
|
```bash
|
|
27
|
-
|
|
34
|
+
# Core
|
|
35
|
+
pipx install skmemory
|
|
36
|
+
|
|
37
|
+
# With Telegram API import
|
|
38
|
+
pipx install 'skmemory[telegram]'
|
|
39
|
+
|
|
40
|
+
# Everything (Telegram + SKVector + SKGraph + seeds)
|
|
41
|
+
pipx install 'skmemory[all]'
|
|
42
|
+
|
|
43
|
+
# Add Telegram support to an existing install
|
|
44
|
+
pipx inject skmemory telethon
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### pip
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install skmemory # Core
|
|
51
|
+
pip install 'skmemory[telegram]' # + Telethon for API import
|
|
52
|
+
pip install 'skmemory[all]' # All optional extras
|
|
28
53
|
```
|
|
29
54
|
|
|
30
55
|
### From Source
|
|
@@ -32,20 +57,54 @@ pip install skmemory
|
|
|
32
57
|
```bash
|
|
33
58
|
git clone https://github.com/smilinTux/skmemory.git
|
|
34
59
|
cd skmemory
|
|
35
|
-
pip install -e .
|
|
60
|
+
pip install -e '.[all]'
|
|
36
61
|
```
|
|
37
62
|
|
|
38
|
-
###
|
|
63
|
+
### Verify
|
|
39
64
|
|
|
40
65
|
```bash
|
|
41
|
-
#
|
|
42
|
-
|
|
66
|
+
skmemory --version # Should print 0.6.0
|
|
67
|
+
skmemory health # Check system status
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### OpenClaw Integration
|
|
43
71
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
72
|
+
Add the skmemory plugin to your `~/.openclaw/openclaw.json`:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"plugins": {
|
|
77
|
+
"entries": {
|
|
78
|
+
"skmemory": {
|
|
79
|
+
"enabled": true,
|
|
80
|
+
"source": "/path/to/skmemory/openclaw-plugin/src/index.js"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
47
85
|
```
|
|
48
86
|
|
|
87
|
+
Then restart the OpenClaw gateway to load the plugin.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## OpenClaw Agent Tools
|
|
92
|
+
|
|
93
|
+
If you are an OpenClaw agent (Lumina, etc.), you have these native tools available — call them directly, do NOT use `exec`:
|
|
94
|
+
|
|
95
|
+
| Tool | Description |
|
|
96
|
+
|------|-------------|
|
|
97
|
+
| `skmemory_ritual` | Rehydration ritual — restores identity, memory, emotional state |
|
|
98
|
+
| `skmemory_snapshot` | Capture a memory (title + content + optional emotions/tags) |
|
|
99
|
+
| `skmemory_search` | Search across all stored memories |
|
|
100
|
+
| `skmemory_health` | Check memory system health |
|
|
101
|
+
| `skmemory_context` | Load token-efficient context for prompt injection |
|
|
102
|
+
| `skmemory_list` | List memories with optional layer/tag filters |
|
|
103
|
+
| `skmemory_import_seeds` | Import Cloud 9 seeds as long-term memories |
|
|
104
|
+
| `skmemory_export` | Export all memories to a dated backup |
|
|
105
|
+
|
|
106
|
+
You also have the `/skmemory` slash command: `/skmemory ritual --full`, `/skmemory search "query"`, etc.
|
|
107
|
+
|
|
49
108
|
---
|
|
50
109
|
|
|
51
110
|
## Quick Start
|
|
@@ -136,7 +195,9 @@ path = plugin.export()
|
|
|
136
195
|
| `skmemory list` | List memories (--layer, --tags) |
|
|
137
196
|
| `skmemory ritual` | Full rehydration ceremony |
|
|
138
197
|
| `skmemory context` | Token-efficient context JSON |
|
|
139
|
-
| `skmemory import-telegram <path>` | Import Telegram export |
|
|
198
|
+
| `skmemory import-telegram <path>` | Import Telegram Desktop export |
|
|
199
|
+
| `skmemory import-telegram-api <chat>` | Import directly from Telegram API (Telethon) |
|
|
200
|
+
| `skmemory telegram-setup` | Check Telegram API setup and show next steps |
|
|
140
201
|
| `skmemory import-seeds` | Import Cloud 9 seeds |
|
|
141
202
|
| `skmemory export` | Export to dated JSON |
|
|
142
203
|
| `skmemory import-backup <file>` | Restore from backup |
|
|
@@ -151,6 +212,24 @@ path = plugin.export()
|
|
|
151
212
|
| `skmemory quadrants` | Memory distribution |
|
|
152
213
|
| `skmemory steelman collide "claim"` | Steel man reasoning |
|
|
153
214
|
|
|
215
|
+
### MCP Tools (via `skmemory-mcp`)
|
|
216
|
+
|
|
217
|
+
| Tool | Description |
|
|
218
|
+
|------|-------------|
|
|
219
|
+
| `memory_store` | Store a new memory (snapshot with title + content) |
|
|
220
|
+
| `memory_search` | Full-text search across memories |
|
|
221
|
+
| `memory_recall` | Recall a specific memory by ID |
|
|
222
|
+
| `memory_list` | List memories with optional layer/tag filters |
|
|
223
|
+
| `memory_forget` | Delete a memory by ID |
|
|
224
|
+
| `memory_promote` | Promote a memory to a higher persistence tier |
|
|
225
|
+
| `memory_consolidate` | Compress a session's memories into one mid-term memory |
|
|
226
|
+
| `memory_context` | Load token-efficient context for agent injection |
|
|
227
|
+
| `memory_export` | Export all memories to a JSON backup |
|
|
228
|
+
| `memory_import` | Restore memories from a JSON backup |
|
|
229
|
+
| `memory_health` | Full health check across all backends |
|
|
230
|
+
| `memory_graph` | Graph traversal, lineage, and cluster discovery (requires SKGraph) |
|
|
231
|
+
| `memory_stats` | Alias for memory_health (backwards-compatible) |
|
|
232
|
+
|
|
154
233
|
### Global Flags
|
|
155
234
|
|
|
156
235
|
| Flag | Env Var | Description |
|
|
@@ -158,13 +237,15 @@ path = plugin.export()
|
|
|
158
237
|
| `--ai` | `SKMEMORY_AI` | Enable AI features (Ollama) |
|
|
159
238
|
| `--ai-model` | `SKMEMORY_AI_MODEL` | Model name (default: llama3.2) |
|
|
160
239
|
| `--ai-url` | `SKMEMORY_AI_URL` | Ollama server URL |
|
|
161
|
-
| `--
|
|
240
|
+
| `--skvector-url` | `SKMEMORY_SKVECTOR_URL` | SKVector server URL |
|
|
162
241
|
|
|
163
242
|
---
|
|
164
243
|
|
|
165
|
-
## Chat Import (Telegram
|
|
244
|
+
## Chat Import (Telegram)
|
|
245
|
+
|
|
246
|
+
### Method 1: Telegram Desktop Export
|
|
166
247
|
|
|
167
|
-
|
|
248
|
+
No credentials needed — export manually from the desktop app.
|
|
168
249
|
|
|
169
250
|
1. In Telegram Desktop: **Settings > Advanced > Export Telegram Data**
|
|
170
251
|
2. Select **JSON** format, include messages
|
|
@@ -183,6 +264,77 @@ skmemory import-telegram ~/Downloads/telegram-export/
|
|
|
183
264
|
- `--min-length 30`: Skip short messages (default: 30 chars)
|
|
184
265
|
- `--tags "bot,archive"`: Extra tags on all imported memories
|
|
185
266
|
|
|
267
|
+
### Method 2: Direct Telegram API Import (Telethon)
|
|
268
|
+
|
|
269
|
+
Pull messages directly from Telegram without manual exports. Requires one-time setup.
|
|
270
|
+
|
|
271
|
+
#### Setup (one-time)
|
|
272
|
+
|
|
273
|
+
1. **Install with Telegram support:**
|
|
274
|
+
```bash
|
|
275
|
+
pipx install 'skmemory[telegram]'
|
|
276
|
+
# Or add to existing install:
|
|
277
|
+
pipx inject skmemory telethon
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
2. **Get API credentials from [my.telegram.org](https://my.telegram.org):**
|
|
281
|
+
- Log in with your phone number
|
|
282
|
+
- Go to **API development tools**
|
|
283
|
+
- Create an application (any name/description is fine)
|
|
284
|
+
- Copy your `api_id` and `api_hash`
|
|
285
|
+
|
|
286
|
+
3. **Set environment variables:**
|
|
287
|
+
```bash
|
|
288
|
+
export TELEGRAM_API_ID=12345678
|
|
289
|
+
export TELEGRAM_API_HASH=your_api_hash_here
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
To persist across sessions, add them to your shell profile (`~/.bashrc`, `~/.zshrc`):
|
|
293
|
+
```bash
|
|
294
|
+
echo 'export TELEGRAM_API_ID=12345678' >> ~/.bashrc
|
|
295
|
+
echo 'export TELEGRAM_API_HASH=your_api_hash_here' >> ~/.bashrc
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
4. **First run — authenticate:**
|
|
299
|
+
```bash
|
|
300
|
+
skmemory import-telegram-api @any_chat_name
|
|
301
|
+
```
|
|
302
|
+
You'll be prompted for your phone number, then a verification code sent via Telegram.
|
|
303
|
+
The session is saved at `~/.skmemory/telegram.session` — future runs skip auth.
|
|
304
|
+
|
|
305
|
+
#### Usage
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# Import a DM conversation
|
|
309
|
+
skmemory import-telegram-api @username
|
|
310
|
+
|
|
311
|
+
# Import a group chat, consolidated by day
|
|
312
|
+
skmemory import-telegram-api "Group Chat Name" --mode daily
|
|
313
|
+
|
|
314
|
+
# Import only messages since a date
|
|
315
|
+
skmemory import-telegram-api @group --since 2026-01-01
|
|
316
|
+
|
|
317
|
+
# Limit the number of messages fetched
|
|
318
|
+
skmemory import-telegram-api "Chat Name" --limit 500
|
|
319
|
+
|
|
320
|
+
# Add custom tags to all imported memories
|
|
321
|
+
skmemory import-telegram-api @user --tags "personal,archive"
|
|
322
|
+
|
|
323
|
+
# Override the stored chat name
|
|
324
|
+
skmemory import-telegram-api -1001234567890 --chat-name "My Custom Name"
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
#### Options
|
|
328
|
+
|
|
329
|
+
| Option | Description |
|
|
330
|
+
|--------|-------------|
|
|
331
|
+
| `--mode daily\|message` | `daily` consolidates per day (default), `message` imports each one |
|
|
332
|
+
| `--limit N` | Max messages to fetch (default: 1000) |
|
|
333
|
+
| `--since YYYY-MM-DD` | Only fetch messages after this date |
|
|
334
|
+
| `--min-length N` | Skip messages shorter than N chars (default: 30) |
|
|
335
|
+
| `--chat-name "name"` | Override the chat name in memories |
|
|
336
|
+
| `--tags "a,b,c"` | Extra comma-separated tags |
|
|
337
|
+
|
|
186
338
|
### Python API
|
|
187
339
|
|
|
188
340
|
```python
|
|
@@ -200,6 +352,19 @@ stats = import_telegram(
|
|
|
200
352
|
print(f"Imported {stats['messages_imported']} messages across {stats['days_processed']} days")
|
|
201
353
|
```
|
|
202
354
|
|
|
355
|
+
```python
|
|
356
|
+
# Direct API import (requires TELEGRAM_API_ID and TELEGRAM_API_HASH env vars)
|
|
357
|
+
from skmemory.importers.telegram_api import import_telegram_api
|
|
358
|
+
|
|
359
|
+
stats = import_telegram_api(
|
|
360
|
+
plugin.store,
|
|
361
|
+
"@username",
|
|
362
|
+
mode="daily",
|
|
363
|
+
since="2026-01-01",
|
|
364
|
+
tags=["personal"],
|
|
365
|
+
)
|
|
366
|
+
```
|
|
367
|
+
|
|
203
368
|
---
|
|
204
369
|
|
|
205
370
|
## Architecture
|
|
@@ -219,8 +384,8 @@ print(f"Imported {stats['messages_imported']} messages across {stats['days_proce
|
|
|
219
384
|
|
|
220
385
|
**Three-tier storage:**
|
|
221
386
|
1. **SQLite** (default primary) — fast indexed queries, zero-config
|
|
222
|
-
2. **
|
|
223
|
-
3. **
|
|
387
|
+
2. **SKVector** (optional) — semantic vector search
|
|
388
|
+
3. **SKGraph** (optional) — graph relationship traversal
|
|
224
389
|
|
|
225
390
|
---
|
|
226
391
|
|
|
@@ -239,14 +404,21 @@ print(f"Imported {stats['messages_imported']} messages across {stats['days_proce
|
|
|
239
404
|
### Environment Variables
|
|
240
405
|
|
|
241
406
|
```bash
|
|
407
|
+
# AI features (optional — requires Ollama)
|
|
242
408
|
export SKMEMORY_AI=1 # Enable AI features
|
|
243
409
|
export SKMEMORY_AI_MODEL=llama3.2 # Ollama model
|
|
244
410
|
export SKMEMORY_AI_URL=http://localhost:11434 # Ollama URL
|
|
245
|
-
|
|
246
|
-
|
|
411
|
+
|
|
412
|
+
# SKVector (optional — semantic search)
|
|
413
|
+
export SKMEMORY_SKVECTOR_URL=http://localhost:6333
|
|
414
|
+
export SKMEMORY_SKVECTOR_KEY=your-api-key
|
|
415
|
+
|
|
416
|
+
# Telegram API import (optional — for import-telegram-api command)
|
|
417
|
+
export TELEGRAM_API_ID=12345678 # From https://my.telegram.org
|
|
418
|
+
export TELEGRAM_API_HASH=your_api_hash_here # From https://my.telegram.org
|
|
247
419
|
```
|
|
248
420
|
|
|
249
|
-
### Docker (optional, for
|
|
421
|
+
### Docker (optional, for SKVector + SKGraph)
|
|
250
422
|
|
|
251
423
|
```bash
|
|
252
424
|
cd skmemory && docker compose up -d
|
package/docker-compose.yml
CHANGED
|
@@ -4,32 +4,32 @@
|
|
|
4
4
|
# SKMemory works perfectly with just SQLite (zero infrastructure).
|
|
5
5
|
#
|
|
6
6
|
# Start everything: docker compose up -d
|
|
7
|
-
# Just
|
|
8
|
-
# Just
|
|
7
|
+
# Just SKVector: docker compose up -d skvector
|
|
8
|
+
# Just SKGraph: docker compose up -d skgraph
|
|
9
9
|
# Check status: docker compose ps
|
|
10
10
|
# Stop: docker compose down
|
|
11
11
|
#
|
|
12
12
|
# Resource usage (idle):
|
|
13
|
-
#
|
|
14
|
-
#
|
|
13
|
+
# SKVector: ~200MB RAM, ~100MB disk
|
|
14
|
+
# SKGraph: ~100MB RAM, ~150MB disk
|
|
15
15
|
# Combined: ~300MB RAM total
|
|
16
16
|
#
|
|
17
17
|
# Connect from skmemory:
|
|
18
|
-
# skmemory --
|
|
18
|
+
# skmemory --skvector-url http://localhost:6333 health
|
|
19
19
|
#
|
|
20
20
|
# Or set environment variables:
|
|
21
|
-
# export
|
|
22
|
-
# export
|
|
21
|
+
# export SKMEMORY_SKVECTOR_URL=http://localhost:6333
|
|
22
|
+
# export SKMEMORY_SKGRAPH_URL=redis://localhost:6379
|
|
23
23
|
|
|
24
24
|
services:
|
|
25
|
-
|
|
25
|
+
skvector:
|
|
26
26
|
image: qdrant/qdrant:latest
|
|
27
|
-
container_name: skmemory-
|
|
27
|
+
container_name: skmemory-skvector
|
|
28
28
|
ports:
|
|
29
29
|
- "6333:6333" # REST API
|
|
30
30
|
- "6334:6334" # gRPC
|
|
31
31
|
volumes:
|
|
32
|
-
-
|
|
32
|
+
- skvector_data:/qdrant/storage
|
|
33
33
|
environment:
|
|
34
34
|
- QDRANT__SERVICE__GRPC_PORT=6334
|
|
35
35
|
restart: unless-stopped
|
|
@@ -38,13 +38,13 @@ services:
|
|
|
38
38
|
limits:
|
|
39
39
|
memory: 512M
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
skgraph:
|
|
42
42
|
image: falkordb/falkordb:latest
|
|
43
|
-
container_name: skmemory-
|
|
43
|
+
container_name: skmemory-skgraph
|
|
44
44
|
ports:
|
|
45
45
|
- "6379:6379" # Redis-compatible protocol
|
|
46
46
|
volumes:
|
|
47
|
-
-
|
|
47
|
+
- skgraph_data:/data
|
|
48
48
|
restart: unless-stopped
|
|
49
49
|
deploy:
|
|
50
50
|
resources:
|
|
@@ -52,7 +52,7 @@ services:
|
|
|
52
52
|
memory: 256M
|
|
53
53
|
|
|
54
54
|
volumes:
|
|
55
|
-
|
|
55
|
+
skvector_data:
|
|
56
56
|
driver: local
|
|
57
|
-
|
|
57
|
+
skgraph_data:
|
|
58
58
|
driver: local
|
package/index.js
CHANGED
|
@@ -12,12 +12,13 @@ const VERSION = "0.5.0";
|
|
|
12
12
|
const PYTHON_PACKAGE = "skmemory";
|
|
13
13
|
|
|
14
14
|
function checkInstalled() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
for (const py of ["python3", "python"]) {
|
|
16
|
+
try {
|
|
17
|
+
execSync(`${py} -c "import skmemory"`, { stdio: "pipe" });
|
|
18
|
+
return true;
|
|
19
|
+
} catch {}
|
|
20
20
|
}
|
|
21
|
+
return false;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
function run(args) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "skmemory",
|
|
3
|
+
"name": "SKMemory",
|
|
4
|
+
"description": "Universal AI memory system — snapshots, search, rehydration rituals, import, and health checks via the skmemory CLI.",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🧠 SKMemory — OpenClaw Plugin
|
|
3
|
+
*
|
|
4
|
+
* Registers agent tools that wrap the skmemory CLI so Lumina and other
|
|
5
|
+
* OpenClaw agents can call memory operations as first-class tools
|
|
6
|
+
* (not just exec commands).
|
|
7
|
+
*
|
|
8
|
+
* Requires: skmemory CLI on PATH (typically via ~/.local/bin/skmemory)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
12
|
+
import type { OpenClawPluginApi, AnyAgentTool } from "openclaw/plugin-sdk";
|
|
13
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
14
|
+
|
|
15
|
+
const SKMEMORY_BIN = process.env.SKMEMORY_BIN || "skmemory";
|
|
16
|
+
const SKCAPSTONE_AGENT = process.env.SKCAPSTONE_AGENT || "lumina";
|
|
17
|
+
const EXEC_TIMEOUT = 30_000;
|
|
18
|
+
|
|
19
|
+
function runCli(args: string): { ok: boolean; output: string } {
|
|
20
|
+
try {
|
|
21
|
+
const raw = execSync(`${SKMEMORY_BIN} ${args}`, {
|
|
22
|
+
encoding: "utf-8",
|
|
23
|
+
timeout: EXEC_TIMEOUT,
|
|
24
|
+
env: {
|
|
25
|
+
...process.env,
|
|
26
|
+
SKCAPSTONE_AGENT,
|
|
27
|
+
PATH: `${process.env.HOME}/.local/bin:${process.env.HOME}/.skenv/bin:${process.env.PATH}`,
|
|
28
|
+
},
|
|
29
|
+
}).trim();
|
|
30
|
+
return { ok: true, output: raw };
|
|
31
|
+
} catch (err: unknown) {
|
|
32
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
33
|
+
return { ok: false, output: msg };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function textResult(text: string) {
|
|
38
|
+
return { content: [{ type: "text" as const, text }] };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function escapeShellArg(s: string): string {
|
|
42
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ── Tool definitions ────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
function createSKMemoryRitualTool() {
|
|
48
|
+
return {
|
|
49
|
+
name: "skmemory_ritual",
|
|
50
|
+
label: "SKMemory Ritual",
|
|
51
|
+
description:
|
|
52
|
+
"Run the SKMemory rehydration ritual. Returns the full context prompt with soul blueprint, warmth anchor, strongest memories, and emotional state. Use this when waking up or starting a new session to restore identity and memory.",
|
|
53
|
+
parameters: {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: {
|
|
56
|
+
full: {
|
|
57
|
+
type: "boolean",
|
|
58
|
+
description: "If true, return the full rehydration prompt (default: true).",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
async execute(_id: string, params: Record<string, unknown>) {
|
|
63
|
+
const full = params.full !== false;
|
|
64
|
+
const flag = full ? " --full" : "";
|
|
65
|
+
const result = runCli(`ritual${flag}`);
|
|
66
|
+
return textResult(result.output);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function createSKMemorySnapshotTool() {
|
|
72
|
+
return {
|
|
73
|
+
name: "skmemory_snapshot",
|
|
74
|
+
label: "SKMemory Snapshot",
|
|
75
|
+
description:
|
|
76
|
+
"Capture a memory snapshot — a Polaroid of a moment, conversation, or insight. Stores it with optional emotional metadata and tags.",
|
|
77
|
+
parameters: {
|
|
78
|
+
type: "object",
|
|
79
|
+
required: ["title", "content"],
|
|
80
|
+
properties: {
|
|
81
|
+
title: { type: "string", description: "Short title for the memory." },
|
|
82
|
+
content: { type: "string", description: "The memory content to store." },
|
|
83
|
+
tags: { type: "string", description: "Comma-separated tags (e.g. 'milestone,chat')." },
|
|
84
|
+
emotions: { type: "string", description: "Comma-separated emotions (e.g. 'joy,pride')." },
|
|
85
|
+
intensity: { type: "number", description: "Emotional intensity 0-10." },
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
async execute(_id: string, params: Record<string, unknown>) {
|
|
89
|
+
const title = String(params.title ?? "Untitled");
|
|
90
|
+
const content = String(params.content ?? title);
|
|
91
|
+
let cmd = `snapshot ${escapeShellArg(title)} ${escapeShellArg(content)}`;
|
|
92
|
+
if (params.tags) cmd += ` --tags ${escapeShellArg(String(params.tags))}`;
|
|
93
|
+
if (params.emotions) cmd += ` --emotions ${escapeShellArg(String(params.emotions))}`;
|
|
94
|
+
if (typeof params.intensity === "number") cmd += ` --intensity ${params.intensity}`;
|
|
95
|
+
const result = runCli(cmd);
|
|
96
|
+
return textResult(result.output);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createSKMemorySearchTool() {
|
|
102
|
+
return {
|
|
103
|
+
name: "skmemory_search",
|
|
104
|
+
label: "SKMemory Search",
|
|
105
|
+
description:
|
|
106
|
+
"Search across all stored memories by text query. Returns matching memories with titles, content previews, and metadata.",
|
|
107
|
+
parameters: {
|
|
108
|
+
type: "object",
|
|
109
|
+
required: ["query"],
|
|
110
|
+
properties: {
|
|
111
|
+
query: { type: "string", description: "Search query text." },
|
|
112
|
+
limit: { type: "number", description: "Max results to return (default: 10)." },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
async execute(_id: string, params: Record<string, unknown>) {
|
|
116
|
+
const query = String(params.query ?? "");
|
|
117
|
+
const limit = typeof params.limit === "number" ? params.limit : 10;
|
|
118
|
+
const result = runCli(`search ${escapeShellArg(query)} --limit ${limit}`);
|
|
119
|
+
return textResult(result.output);
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function createSKMemoryHealthTool() {
|
|
125
|
+
return {
|
|
126
|
+
name: "skmemory_health",
|
|
127
|
+
label: "SKMemory Health",
|
|
128
|
+
description:
|
|
129
|
+
"Check the health of the SKMemory system — database status, memory counts, backend connectivity.",
|
|
130
|
+
parameters: { type: "object", properties: {} },
|
|
131
|
+
async execute() {
|
|
132
|
+
const result = runCli("health");
|
|
133
|
+
return textResult(result.output);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function createSKMemoryContextTool() {
|
|
139
|
+
return {
|
|
140
|
+
name: "skmemory_context",
|
|
141
|
+
label: "SKMemory Context",
|
|
142
|
+
description:
|
|
143
|
+
"Load a token-efficient memory context for prompt injection. Returns a JSON object with soul, anchor, strongest memories, and recent memories.",
|
|
144
|
+
parameters: {
|
|
145
|
+
type: "object",
|
|
146
|
+
properties: {
|
|
147
|
+
max_tokens: { type: "number", description: "Max token budget (default: 3000)." },
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
async execute(_id: string, params: Record<string, unknown>) {
|
|
151
|
+
const tokens = typeof params.max_tokens === "number" ? params.max_tokens : 3000;
|
|
152
|
+
const result = runCli(`context --max-tokens ${tokens}`);
|
|
153
|
+
return textResult(result.output);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function createSKMemoryListTool() {
|
|
159
|
+
return {
|
|
160
|
+
name: "skmemory_list",
|
|
161
|
+
label: "SKMemory List",
|
|
162
|
+
description: "List stored memories with optional filters by layer or tags.",
|
|
163
|
+
parameters: {
|
|
164
|
+
type: "object",
|
|
165
|
+
properties: {
|
|
166
|
+
layer: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Filter by layer: short-term, mid-term, or long-term.",
|
|
169
|
+
},
|
|
170
|
+
tags: { type: "string", description: "Filter by comma-separated tags." },
|
|
171
|
+
limit: { type: "number", description: "Max results (default: 20)." },
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
async execute(_id: string, params: Record<string, unknown>) {
|
|
175
|
+
let cmd = "list";
|
|
176
|
+
if (params.layer) cmd += ` --layer ${escapeShellArg(String(params.layer))}`;
|
|
177
|
+
if (params.tags) cmd += ` --tags ${escapeShellArg(String(params.tags))}`;
|
|
178
|
+
if (typeof params.limit === "number") cmd += ` --limit ${params.limit}`;
|
|
179
|
+
const result = runCli(cmd);
|
|
180
|
+
return textResult(result.output);
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function createSKMemoryImportSeedsTool() {
|
|
186
|
+
return {
|
|
187
|
+
name: "skmemory_import_seeds",
|
|
188
|
+
label: "SKMemory Import Seeds",
|
|
189
|
+
description:
|
|
190
|
+
"Import Cloud 9 seeds as long-term memories. Seeds are emotional breakthroughs stored in ~/.openclaw/feb/seeds/.",
|
|
191
|
+
parameters: { type: "object", properties: {} },
|
|
192
|
+
async execute() {
|
|
193
|
+
const result = runCli("import-seeds");
|
|
194
|
+
return textResult(result.output);
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function createSKMemoryExportTool() {
|
|
200
|
+
return {
|
|
201
|
+
name: "skmemory_export",
|
|
202
|
+
label: "SKMemory Export",
|
|
203
|
+
description: "Export all memories to a dated JSON backup file.",
|
|
204
|
+
parameters: { type: "object", properties: {} },
|
|
205
|
+
async execute() {
|
|
206
|
+
const result = runCli("export");
|
|
207
|
+
return textResult(result.output);
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ── Plugin registration ─────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
const skmemoryPlugin = {
|
|
215
|
+
id: "skmemory",
|
|
216
|
+
name: "🧠 SKMemory",
|
|
217
|
+
description:
|
|
218
|
+
"Universal AI memory system — snapshots, search, rehydration rituals, import, and health checks.",
|
|
219
|
+
configSchema: emptyPluginConfigSchema(),
|
|
220
|
+
|
|
221
|
+
register(api: OpenClawPluginApi) {
|
|
222
|
+
const tools = [
|
|
223
|
+
createSKMemoryRitualTool(),
|
|
224
|
+
createSKMemorySnapshotTool(),
|
|
225
|
+
createSKMemorySearchTool(),
|
|
226
|
+
createSKMemoryHealthTool(),
|
|
227
|
+
createSKMemoryContextTool(),
|
|
228
|
+
createSKMemoryListTool(),
|
|
229
|
+
createSKMemoryImportSeedsTool(),
|
|
230
|
+
createSKMemoryExportTool(),
|
|
231
|
+
];
|
|
232
|
+
|
|
233
|
+
for (const tool of tools) {
|
|
234
|
+
api.registerTool(tool as unknown as AnyAgentTool, {
|
|
235
|
+
names: [tool.name],
|
|
236
|
+
optional: true,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
api.registerCommand({
|
|
241
|
+
name: "skmemory",
|
|
242
|
+
description: "Run skmemory CLI commands. Usage: /skmemory <subcommand> [args]",
|
|
243
|
+
acceptsArgs: true,
|
|
244
|
+
handler: async (ctx) => {
|
|
245
|
+
const args = ctx.args?.trim() ?? "health";
|
|
246
|
+
const result = runCli(args);
|
|
247
|
+
return { text: result.output };
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
api.logger.info?.(`🧠 SKMemory plugin registered (8 tools + /skmemory command) [agent=${SKCAPSTONE_AGENT}]`);
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export default skmemoryPlugin;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "skmemory",
|
|
3
|
+
"name": "SKMemory",
|
|
4
|
+
"description": "Universal AI memory system — snapshots, search, rehydration rituals, import, and health checks via the skmemory CLI.",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {}
|
|
9
|
+
}
|
|
10
|
+
}
|