@gamaze/hicortex 0.3.16 → 0.4.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 +102 -78
- package/dist/cli.js +10 -4
- package/dist/consolidate.js +33 -2
- package/dist/db.js +5 -1
- package/dist/init.d.ts +3 -1
- package/dist/init.js +375 -55
- package/dist/license.js +1 -0
- package/dist/llm.d.ts +1 -0
- package/dist/llm.js +49 -4
- package/dist/mcp-server.js +62 -2
- package/dist/nightly.js +172 -3
- package/dist/prompts.d.ts +1 -1
- package/dist/prompts.js +41 -13
- package/dist/storage.js +5 -4
- package/dist/types.d.ts +2 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,137 +1,159 @@
|
|
|
1
|
-
# @gamaze/hicortex —
|
|
1
|
+
# @gamaze/hicortex — Self-Learning Memory for AI Agents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Your agents learn from every session — successes and mistakes. Hicortex captures experiences, distills lessons, and applies them automatically. Connect multiple agents to shared memory and they improve together, overnight.
|
|
4
4
|
|
|
5
|
-
Works with **OpenClaw** (in-process plugin) and
|
|
5
|
+
Works with **Claude Code** (primary), **OpenClaw** (in-process plugin), and any MCP-compatible agent.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Website:** [hicortex.gamaze.com](https://hicortex.gamaze.com) · **Docs:** [hicortex.gamaze.com/docs](https://hicortex.gamaze.com/docs/)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- LLM provider (auto-detected from OC config or `ANTHROPIC_API_KEY` for CC)
|
|
11
|
-
- ~500MB disk for database + embedding model
|
|
12
|
-
|
|
13
|
-
## Install — OpenClaw
|
|
9
|
+
## Install — Server Mode (single machine)
|
|
14
10
|
|
|
15
11
|
```bash
|
|
16
|
-
|
|
17
|
-
openclaw gateway restart
|
|
12
|
+
npx @gamaze/hicortex init
|
|
18
13
|
```
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
Detects your environment, installs a persistent MCP server daemon, auto-detects Ollama/Claude CLI/API keys, and registers with Claude Code. One command.
|
|
21
16
|
|
|
22
|
-
## Install —
|
|
17
|
+
## Install — Client Mode (multi-client)
|
|
23
18
|
|
|
24
19
|
```bash
|
|
25
|
-
npx @gamaze/hicortex init
|
|
20
|
+
npx @gamaze/hicortex init --server https://your-server.example.com
|
|
26
21
|
```
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
Connects to a remote Hicortex server. Sessions are distilled locally (privacy), memories are sent to the shared server. No local database needed.
|
|
29
24
|
|
|
30
|
-
|
|
25
|
+
## Install — OpenClaw
|
|
31
26
|
|
|
32
27
|
```bash
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
# Register with CC
|
|
37
|
-
claude mcp add hicortex --transport http http://localhost:8787/sse
|
|
28
|
+
openclaw plugins install @gamaze/hicortex
|
|
29
|
+
openclaw gateway restart
|
|
38
30
|
```
|
|
39
31
|
|
|
40
|
-
##
|
|
41
|
-
|
|
42
|
-
Optional config for OC (add to plugin entry in `~/.openclaw/openclaw.json`):
|
|
43
|
-
|
|
44
|
-
| Field | Default | Description |
|
|
45
|
-
|-------|---------|-------------|
|
|
46
|
-
| `licenseKey` | _(none)_ | License key. Free tier (250 memories) without key. |
|
|
47
|
-
| `llmBaseUrl` | _(auto)_ | Override LLM base URL |
|
|
48
|
-
| `llmApiKey` | _(auto)_ | Override LLM API key |
|
|
49
|
-
| `llmModel` | _(auto)_ | Override model for scoring and distillation |
|
|
50
|
-
| `reflectModel` | _(auto)_ | Override model for nightly reflection |
|
|
51
|
-
| `consolidateHour` | `2` | Hour (0-23, local time) for nightly consolidation |
|
|
52
|
-
| `dbPath` | _(auto)_ | Custom database path |
|
|
32
|
+
## Requirements
|
|
53
33
|
|
|
54
|
-
|
|
34
|
+
- Node.js 18+
|
|
35
|
+
- LLM: Ollama 9b+ (recommended), Claude CLI, or API key (Anthropic, OpenAI, etc.)
|
|
36
|
+
- ~500MB disk for database + embedding model
|
|
55
37
|
|
|
56
38
|
## What Happens Automatically
|
|
57
39
|
|
|
58
40
|
| When | What | How |
|
|
59
41
|
|------|------|-----|
|
|
60
|
-
| Agent start | Recent lessons injected into context |
|
|
61
|
-
| Agent end | Conversation captured
|
|
62
|
-
| Nightly |
|
|
42
|
+
| Agent start | Recent lessons injected into context | CLAUDE.md block / OC hook |
|
|
43
|
+
| Agent end | Conversation captured | CC: nightly transcript scan / OC: hook |
|
|
44
|
+
| Nightly | Distill → score → reflect → link → inject | Automatic pipeline |
|
|
63
45
|
|
|
64
|
-
## Agent Tools
|
|
46
|
+
## Agent Tools (MCP)
|
|
65
47
|
|
|
66
|
-
|
|
48
|
+
6 tools available via MCP:
|
|
67
49
|
|
|
68
|
-
- **hicortex_search** — Semantic search across all stored
|
|
50
|
+
- **hicortex_search** — Semantic search across all stored memories
|
|
69
51
|
- **hicortex_context** — Get recent decisions and project state
|
|
70
|
-
- **hicortex_ingest** — Store a
|
|
52
|
+
- **hicortex_ingest** — Store a memory directly
|
|
71
53
|
- **hicortex_lessons** — Get actionable lessons from reflection
|
|
54
|
+
- **hicortex_update** — Fix incorrect memories (re-embeds on content change)
|
|
55
|
+
- **hicortex_delete** — Remove memories with cascade cleanup
|
|
72
56
|
|
|
73
57
|
Skills: `/learn` to save explicit learnings.
|
|
74
58
|
|
|
75
59
|
## CLI Commands
|
|
76
60
|
|
|
77
61
|
```bash
|
|
78
|
-
npx @gamaze/hicortex server
|
|
79
|
-
npx @gamaze/hicortex init
|
|
80
|
-
npx @gamaze/hicortex
|
|
81
|
-
npx @gamaze/hicortex
|
|
82
|
-
npx @gamaze/hicortex
|
|
62
|
+
npx @gamaze/hicortex server # Start MCP server (port 8787)
|
|
63
|
+
npx @gamaze/hicortex init # Set up server mode
|
|
64
|
+
npx @gamaze/hicortex init --server <url> # Set up client mode
|
|
65
|
+
npx @gamaze/hicortex nightly # Run distill + consolidate
|
|
66
|
+
npx @gamaze/hicortex nightly --dry-run # Preview without changes
|
|
67
|
+
npx @gamaze/hicortex status # Show config, DB stats
|
|
68
|
+
npx @gamaze/hicortex uninstall # Remove CC integration (keeps DB)
|
|
83
69
|
```
|
|
84
70
|
|
|
85
71
|
## Architecture
|
|
86
72
|
|
|
87
73
|
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
│
|
|
91
|
-
│
|
|
92
|
-
│
|
|
93
|
-
│
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
└── Shared DB at ~/.hicortex/hicortex.db
|
|
74
|
+
Client (MBP) Server (bedrock) Client (MBA)
|
|
75
|
+
┌──────────┐ ┌──────────────┐ ┌──────────┐
|
|
76
|
+
│CC sessions│ │ Shared DB │ │CC sessions│
|
|
77
|
+
│ ↓ │ POST │ │ POST │ ↓ │
|
|
78
|
+
│ Distill │──/ingest───→│ Embed+Store │←/ingest──│ Distill │
|
|
79
|
+
│ (local) │ │ ↓ │ │ (local) │
|
|
80
|
+
│ │ MCP │ Consolidate │ MCP │ │
|
|
81
|
+
│ CC ←│──(search)───│ (score,link, │──(search)→│ CC │
|
|
82
|
+
│ │ │ reflect) │ │ │
|
|
83
|
+
└──────────┘ └──────────────┘ └──────────┘
|
|
99
84
|
|
|
100
85
|
Shared core:
|
|
101
|
-
├── SQLite + sqlite-vec + FTS5
|
|
86
|
+
├── SQLite + sqlite-vec + FTS5
|
|
102
87
|
├── bge-small-en-v1.5 embeddings (ONNX, local CPU)
|
|
103
|
-
├── BM25 + vector search with RRF fusion
|
|
104
|
-
└── Multi-provider LLM (20+ providers)
|
|
88
|
+
├── BM25 + vector search with RRF fusion + graph traversal
|
|
89
|
+
└── Multi-provider LLM (Ollama, Claude CLI, 20+ cloud providers)
|
|
105
90
|
```
|
|
106
91
|
|
|
107
|
-
##
|
|
92
|
+
## Configuration
|
|
108
93
|
|
|
109
|
-
|
|
94
|
+
Config at `~/.hicortex/config.json`. Created by `init`. Key options:
|
|
95
|
+
|
|
96
|
+
| Field | Description |
|
|
97
|
+
|-------|-------------|
|
|
98
|
+
| `mode` | `"server"` (default) or `"client"` |
|
|
99
|
+
| `serverUrl` | Remote server URL (client mode) |
|
|
100
|
+
| `llmModel` | Model for importance scoring |
|
|
101
|
+
| `distillModel` | Model for session distillation (9b+ recommended) |
|
|
102
|
+
| `reflectModel` | Model for nightly reflection (largest available) |
|
|
103
|
+
| `reflectBaseUrl` | Separate Ollama instance for reflection |
|
|
104
|
+
| `authToken` | Bearer token for endpoint auth |
|
|
105
|
+
| `licenseKey` | License key for higher tiers |
|
|
106
|
+
|
|
107
|
+
Full docs: [hicortex.gamaze.com/docs/configuration.html](https://hicortex.gamaze.com/docs/configuration.html)
|
|
108
|
+
|
|
109
|
+
## REST API
|
|
110
|
+
|
|
111
|
+
| Endpoint | Method | Auth | Description |
|
|
112
|
+
|----------|--------|------|-------------|
|
|
113
|
+
| `/health` | GET | No | Server status, memory count, version |
|
|
114
|
+
| `/ingest` | POST | Yes | Accept pre-distilled memories from clients |
|
|
115
|
+
| `/sse` | GET | Yes | MCP SSE stream for agent connections |
|
|
116
|
+
| `/messages` | POST | Yes | MCP message endpoint |
|
|
110
117
|
|
|
111
118
|
## Pricing
|
|
112
119
|
|
|
113
|
-
| Tier | Price | Memories |
|
|
114
|
-
|
|
115
|
-
| Free | $0 | 250 |
|
|
116
|
-
| Pro | $9/month | Unlimited |
|
|
117
|
-
|
|
|
118
|
-
|
|
|
120
|
+
| Tier | Price | Memories | Clients |
|
|
121
|
+
|------|-------|----------|---------|
|
|
122
|
+
| Free | $0 | 250 | Unlimited (trial) |
|
|
123
|
+
| Pro | $9/month | Unlimited | Single |
|
|
124
|
+
| Team | $29/month | Unlimited | Unlimited |
|
|
125
|
+
| Lifetime | $149 | Unlimited | Single |
|
|
119
126
|
|
|
120
|
-
|
|
127
|
+
[hicortex.gamaze.com](https://hicortex.gamaze.com)
|
|
121
128
|
|
|
122
129
|
## Uninstall
|
|
123
130
|
|
|
124
|
-
**OpenClaw:**
|
|
125
131
|
```bash
|
|
126
|
-
|
|
132
|
+
npx @gamaze/hicortex uninstall # Claude Code
|
|
133
|
+
openclaw plugins uninstall hicortex # OpenClaw
|
|
127
134
|
```
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
npx @gamaze/hicortex uninstall
|
|
132
|
-
```
|
|
136
|
+
Database preserved by default. Remove all data: `rm -rf ~/.hicortex`
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
## Configure — OpenClaw
|
|
139
|
+
|
|
140
|
+
Optional config (add to plugin entry in `~/.openclaw/openclaw.json`):
|
|
141
|
+
|
|
142
|
+
| Field | Default | Description |
|
|
143
|
+
|-------|---------|-------------|
|
|
144
|
+
| `licenseKey` | _(none)_ | License key. Free tier (250 memories) without key. |
|
|
145
|
+
| `llmBaseUrl` | _(auto)_ | Override LLM base URL |
|
|
146
|
+
| `llmApiKey` | _(auto)_ | Override LLM API key |
|
|
147
|
+
| `llmModel` | _(auto)_ | Override model for scoring and distillation |
|
|
148
|
+
| `reflectModel` | _(auto)_ | Override model for nightly reflection |
|
|
149
|
+
| `consolidateHour` | `2` | Hour (0-23, local time) for nightly consolidation |
|
|
150
|
+
| `dbPath` | _(auto)_ | Custom database path |
|
|
151
|
+
|
|
152
|
+
For CC, set environment variables: `ANTHROPIC_API_KEY` (auto-detected), or `HICORTEX_LLM_BASE_URL` + `HICORTEX_LLM_API_KEY` + `HICORTEX_LLM_MODEL` for custom providers.
|
|
153
|
+
|
|
154
|
+
## Database
|
|
155
|
+
|
|
156
|
+
Canonical location: `~/.hicortex/hicortex.db`. Existing OC installations at `~/.openclaw/data/hicortex.db` are automatically migrated on upgrade.
|
|
135
157
|
|
|
136
158
|
## Development
|
|
137
159
|
|
|
@@ -152,6 +174,8 @@ npm test
|
|
|
152
174
|
|
|
153
175
|
**First startup slow:** The embedding model (~130MB) downloads on first run. Allow up to 2 minutes.
|
|
154
176
|
|
|
155
|
-
**Server won't start (CC):** Check `~/.hicortex/
|
|
177
|
+
**Server won't start (CC):** Check `~/.hicortex/nightly.log` for errors. Verify port 8787 is free: `lsof -i :8787`.
|
|
156
178
|
|
|
157
179
|
**Multiple CC sessions:** The HTTP server handles multiple concurrent sessions. Do not use stdio transport — it spawns separate processes per session.
|
|
180
|
+
|
|
181
|
+
**Ollama timeout on large sessions:** Hicortex uses streaming mode with 3 retries (30s, 60s, 120s backoff). If first call fails (model loading), retry handles it automatically.
|
package/dist/cli.js
CHANGED
|
@@ -26,14 +26,17 @@ switch (command) {
|
|
|
26
26
|
});
|
|
27
27
|
break;
|
|
28
28
|
}
|
|
29
|
-
case "init":
|
|
29
|
+
case "init": {
|
|
30
|
+
const serverArg = process.argv.indexOf("--server");
|
|
31
|
+
const serverUrl = serverArg !== -1 ? process.argv[serverArg + 1] : undefined;
|
|
30
32
|
import("./init.js").then(({ runInit }) => {
|
|
31
|
-
runInit().catch((err) => {
|
|
33
|
+
runInit({ serverUrl }).catch((err) => {
|
|
32
34
|
console.error("[hicortex] Init failed:", err);
|
|
33
35
|
process.exit(1);
|
|
34
36
|
});
|
|
35
37
|
});
|
|
36
38
|
break;
|
|
39
|
+
}
|
|
37
40
|
case "nightly": {
|
|
38
41
|
const dryRun = process.argv.includes("--dry-run");
|
|
39
42
|
import("./nightly.js").then(({ runNightly }) => {
|
|
@@ -66,8 +69,9 @@ switch (command) {
|
|
|
66
69
|
Usage: hicortex <command> [options]
|
|
67
70
|
|
|
68
71
|
Commands:
|
|
69
|
-
server Start the MCP HTTP/SSE server
|
|
70
|
-
init Set up Hicortex
|
|
72
|
+
server Start the MCP HTTP/SSE server (server mode)
|
|
73
|
+
init Set up Hicortex (server mode, local DB + daemon)
|
|
74
|
+
init --server <url> Set up as client (remote server, local distillation)
|
|
71
75
|
nightly Run nightly distill + consolidate + inject
|
|
72
76
|
status Show current configuration and stats
|
|
73
77
|
uninstall Remove CC integration (preserves DB)
|
|
@@ -75,10 +79,12 @@ Commands:
|
|
|
75
79
|
Options:
|
|
76
80
|
server --port <n> Port (default: 8787)
|
|
77
81
|
server --host <h> Host (default: 127.0.0.1)
|
|
82
|
+
nightly --dry-run Preview without changes
|
|
78
83
|
|
|
79
84
|
Examples:
|
|
80
85
|
npx @gamaze/hicortex server
|
|
81
86
|
npx @gamaze/hicortex init
|
|
87
|
+
npx @gamaze/hicortex init --server https://myserver.example.com
|
|
82
88
|
npx @gamaze/hicortex status`);
|
|
83
89
|
process.exit(command ? 1 : 0);
|
|
84
90
|
}
|
package/dist/consolidate.js
CHANGED
|
@@ -228,7 +228,12 @@ async function stageReflection(db, memories, llm, budget, embedFn, dryRun) {
|
|
|
228
228
|
return `[${project}] [${agent}] ${content}`;
|
|
229
229
|
});
|
|
230
230
|
const memoriesBlock = lines.join("\n\n");
|
|
231
|
-
|
|
231
|
+
// Feed recent lessons to prevent duplicates and enable escalation
|
|
232
|
+
const recentLessons = storage.getLessons(db, 7).slice(0, 10);
|
|
233
|
+
const recentBlock = recentLessons.length > 0
|
|
234
|
+
? recentLessons.map(l => `- ${l.content.slice(0, 150)}`).join("\n")
|
|
235
|
+
: undefined;
|
|
236
|
+
const prompt = (0, prompts_js_1.reflection)(memoriesBlock, recentBlock);
|
|
232
237
|
if (dryRun) {
|
|
233
238
|
return { lessons_generated: 0, skipped: false };
|
|
234
239
|
}
|
|
@@ -250,10 +255,12 @@ async function stageReflection(db, memories, llm, budget, embedFn, dryRun) {
|
|
|
250
255
|
if (!lessonText)
|
|
251
256
|
continue;
|
|
252
257
|
const project = String(lo.project ?? "global");
|
|
258
|
+
const lessonType = String(lo.type ?? "principle");
|
|
253
259
|
const severity = String(lo.severity ?? "important");
|
|
254
260
|
const confidence = String(lo.confidence ?? "medium");
|
|
255
261
|
const sourcePattern = String(lo.source_pattern ?? "");
|
|
256
262
|
let content = `## Lesson: ${lessonText}\n\n`;
|
|
263
|
+
content += `**Type:** ${lessonType}\n`;
|
|
257
264
|
content += `**Severity:** ${severity}\n`;
|
|
258
265
|
content += `**Confidence:** ${confidence}\n`;
|
|
259
266
|
if (sourcePattern)
|
|
@@ -307,9 +314,10 @@ async function stageLinks(db, memories, embedFn, dryRun) {
|
|
|
307
314
|
for (const neighbor of neighbors) {
|
|
308
315
|
const similarity = 1.0 - neighbor.distance;
|
|
309
316
|
if (similarity > CONSOLIDATE_LINK_THRESHOLD) {
|
|
317
|
+
const relationship = classifyRelationship(mem, neighbor, similarity);
|
|
310
318
|
if (!dryRun) {
|
|
311
319
|
try {
|
|
312
|
-
storage.addLink(db, mem.id, neighbor.id,
|
|
320
|
+
storage.addLink(db, mem.id, neighbor.id, relationship, similarity);
|
|
313
321
|
autoLinked++;
|
|
314
322
|
}
|
|
315
323
|
catch {
|
|
@@ -328,6 +336,29 @@ async function stageLinks(db, memories, embedFn, dryRun) {
|
|
|
328
336
|
}
|
|
329
337
|
return { auto_linked: autoLinked, failed };
|
|
330
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* Classify the relationship between two memories based on type, temporal ordering, and similarity.
|
|
341
|
+
*/
|
|
342
|
+
function classifyRelationship(source, target, similarity) {
|
|
343
|
+
// Lesson derived from episode(s)
|
|
344
|
+
if (source.memory_type === "lesson" && target.memory_type === "episode")
|
|
345
|
+
return "derives";
|
|
346
|
+
if (target.memory_type === "lesson" && source.memory_type === "episode")
|
|
347
|
+
return "derives";
|
|
348
|
+
// Same type + very high similarity + different timestamps → newer updates older
|
|
349
|
+
if (source.memory_type === target.memory_type &&
|
|
350
|
+
similarity > 0.8 &&
|
|
351
|
+
source.created_at !== target.created_at) {
|
|
352
|
+
return "updates";
|
|
353
|
+
}
|
|
354
|
+
// Same project, moderate similarity → extends
|
|
355
|
+
if (source.project && target.project &&
|
|
356
|
+
source.project === target.project &&
|
|
357
|
+
similarity > 0.55 && similarity <= 0.8) {
|
|
358
|
+
return "extends";
|
|
359
|
+
}
|
|
360
|
+
return "relates_to";
|
|
361
|
+
}
|
|
331
362
|
// ---------------------------------------------------------------------------
|
|
332
363
|
// Stage 4: Decay & Prune
|
|
333
364
|
// ---------------------------------------------------------------------------
|
package/dist/db.js
CHANGED
|
@@ -103,7 +103,8 @@ CREATE TABLE IF NOT EXISTS memories (
|
|
|
103
103
|
source_session TEXT,
|
|
104
104
|
project TEXT,
|
|
105
105
|
privacy TEXT DEFAULT 'WORK',
|
|
106
|
-
memory_type TEXT DEFAULT 'episode'
|
|
106
|
+
memory_type TEXT DEFAULT 'episode',
|
|
107
|
+
updated_at TIMESTAMP
|
|
107
108
|
);
|
|
108
109
|
|
|
109
110
|
CREATE TABLE IF NOT EXISTS memory_links (
|
|
@@ -184,6 +185,9 @@ function migrate(db) {
|
|
|
184
185
|
db.exec("UPDATE memories SET ingested_at = created_at");
|
|
185
186
|
db.exec("CREATE INDEX IF NOT EXISTS idx_memories_ingested ON memories(ingested_at)");
|
|
186
187
|
}
|
|
188
|
+
if (!colNames.has("updated_at")) {
|
|
189
|
+
db.exec("ALTER TABLE memories ADD COLUMN updated_at TIMESTAMP");
|
|
190
|
+
}
|
|
187
191
|
}
|
|
188
192
|
/**
|
|
189
193
|
* Return database statistics.
|
package/dist/init.d.ts
CHANGED