opencode-fractal-memory 0.2.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/LICENSE +21 -0
- package/README.md +493 -0
- package/agent/memory-hints.md +98 -0
- package/agent/memory-researcher.md +56 -0
- package/commands/memory-auto-test.md +10 -0
- package/commands/memory-cache-status.md +13 -0
- package/commands/memory-check-context.md +4 -0
- package/commands/memory-compress.md +13 -0
- package/commands/memory-dashboard.md +23 -0
- package/commands/memory-delete.md +24 -0
- package/commands/memory-detect-topics.md +28 -0
- package/commands/memory-distill.md +35 -0
- package/commands/memory-drilldown-query.md +28 -0
- package/commands/memory-drilldown.md +11 -0
- package/commands/memory-extract-patterns.md +4 -0
- package/commands/memory-generate-embeddings.md +26 -0
- package/commands/memory-get.md +26 -0
- package/commands/memory-help.md +55 -0
- package/commands/memory-injection-feedback.md +26 -0
- package/commands/memory-injection-stats.md +11 -0
- package/commands/memory-list.md +4 -0
- package/commands/memory-llm-compress.md +34 -0
- package/commands/memory-mcp.md +20 -0
- package/commands/memory-prune.md +4 -0
- package/commands/memory-rate.md +48 -0
- package/commands/memory-reflect.md +37 -0
- package/commands/memory-replace.md +26 -0
- package/commands/memory-retrieve.md +34 -0
- package/commands/memory-search.md +28 -0
- package/commands/memory-session-stats.md +4 -0
- package/commands/memory-set.md +31 -0
- package/commands/memory-stats.md +11 -0
- package/commands/memory-summarize.md +29 -0
- package/commands/memory-tool-stats.md +4 -0
- package/commands/memory-total-tokens.md +10 -0
- package/commands/memory-verify.md +4 -0
- package/commands/memory-version.md +9 -0
- package/dist/cache.js +39 -0
- package/dist/config.js +120 -0
- package/dist/embeddings.js +125 -0
- package/dist/ensure-models.js +70 -0
- package/dist/file-summary.js +143 -0
- package/dist/frontmatter.js +28 -0
- package/dist/hnsw-index.js +138 -0
- package/dist/hooks/auto-discover.js +4 -0
- package/dist/hooks/auto-distill.js +120 -0
- package/dist/hooks/auto-retrieve/content.js +47 -0
- package/dist/hooks/auto-retrieve/detection.js +50 -0
- package/dist/hooks/auto-retrieve/formatting.js +19 -0
- package/dist/hooks/auto-retrieve/index.js +163 -0
- package/dist/hooks/auto-retrieve/scoring.js +56 -0
- package/dist/hooks/auto-retrieve.js +1 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/predictive-rating.js +87 -0
- package/dist/journal.js +279 -0
- package/dist/logging.js +147 -0
- package/dist/management/helpers.js +227 -0
- package/dist/management/router.js +48 -0
- package/dist/management/routes.js +197 -0
- package/dist/management-server.js +4 -0
- package/dist/management-standalone.js +31 -0
- package/dist/mcp/logging.js +57 -0
- package/dist/mcp/server.js +251 -0
- package/dist/mcp/transform.js +48 -0
- package/dist/mcp-server.js +18 -0
- package/dist/memory.js +2 -0
- package/dist/ollama.js +74 -0
- package/dist/plugin/hooks.js +168 -0
- package/dist/plugin/index.js +28 -0
- package/dist/plugin/init.js +109 -0
- package/dist/plugin/state.js +75 -0
- package/dist/plugin/tools.js +45 -0
- package/dist/plugin.js +2 -0
- package/dist/procedural/store.js +1 -0
- package/dist/procedural/types.js +1 -0
- package/dist/seed-nodes.js +804 -0
- package/dist/storage/compress-ops.js +129 -0
- package/dist/storage/compression/formatters.js +243 -0
- package/dist/storage/compression/index.js +107 -0
- package/dist/storage/compression/patterns.js +138 -0
- package/dist/storage/expiration.js +66 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/injection-events.js +82 -0
- package/dist/storage/lifecycle.js +65 -0
- package/dist/storage/maintenance.js +60 -0
- package/dist/storage/migrations/definitions.js +374 -0
- package/dist/storage/migrations/index.js +21 -0
- package/dist/storage/navigation.js +98 -0
- package/dist/storage/queries/base.js +44 -0
- package/dist/storage/queries/links.js +32 -0
- package/dist/storage/queries/nodes.js +189 -0
- package/dist/storage/queries/search-helpers.js +239 -0
- package/dist/storage/scoring.js +36 -0
- package/dist/storage/search.js +233 -0
- package/dist/storage/session-tracking.js +180 -0
- package/dist/storage/sqlite.js +329 -0
- package/dist/storage/tool-usage.js +56 -0
- package/dist/storage/types.js +1 -0
- package/dist/storage/utils.js +94 -0
- package/dist/tools/auto-test.js +24 -0
- package/dist/tools/cache-status.js +36 -0
- package/dist/tools/compress.js +186 -0
- package/dist/tools/core.js +307 -0
- package/dist/tools/dashboard.js +97 -0
- package/dist/tools/help.js +59 -0
- package/dist/tools/index.js +12 -0
- package/dist/tools/inject.js +91 -0
- package/dist/tools/injection-debug.js +48 -0
- package/dist/tools/journal.js +105 -0
- package/dist/tools/llm-compress.js +41 -0
- package/dist/tools/middle-term.js +68 -0
- package/dist/tools/playbook.js +64 -0
- package/dist/tools/reflect.js +291 -0
- package/dist/tools/search.js +188 -0
- package/dist/tools/session.js +189 -0
- package/dist/tools/shared.js +74 -0
- package/dist/tools/skill.js +37 -0
- package/dist/tools/stats.js +256 -0
- package/dist/tools/version.js +13 -0
- package/dist/tools.js +18 -0
- package/dist/utils/hybridScore.js +67 -0
- package/management/public/app.js +1529 -0
- package/management/public/index.html +486 -0
- package/management/public/three.min.js +6 -0
- package/package.json +65 -0
- package/scripts/download-models.ts +16 -0
- package/scripts/postinstall.cjs +30 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Holger Reppert
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# opencode-fractal-memory
|
|
2
|
+
|
|
3
|
+
Fractal memory system for [OpenCode](https://opencode.ai) with semantic search, automatic compression, and multi-level retrieval.
|
|
4
|
+
|
|
5
|
+
# about me and the usage
|
|
6
|
+
|
|
7
|
+
I made this because I needed a longterm memory at first.
|
|
8
|
+
Then while working with it I extended it's functionality.
|
|
9
|
+
It might be a little bit overwhelming but if you work with it you will
|
|
10
|
+
start to love it.
|
|
11
|
+
You can tell the coding agent to make a memory of everything.
|
|
12
|
+
And later on you can tell it to read it.
|
|
13
|
+
You can also use the management app that includes a nice threejs visualization
|
|
14
|
+
and searching from there in the memory nodes.
|
|
15
|
+
You can also inject nodes directly to the agent from there.
|
|
16
|
+
You can edit the nodes too.
|
|
17
|
+
I think I forgot to mention some of features here.
|
|
18
|
+
I'll update this project constantly.
|
|
19
|
+
Feel free to use it and tell me how much you hate or like it ;)
|
|
20
|
+
|
|
21
|
+
Have phun
|
|
22
|
+
|
|
23
|
+
Holger
|
|
24
|
+
|
|
25
|
+
PS.: Did I mention that this is alpha? So feel free to post issues with suggestions
|
|
26
|
+
if you find bugs or if you just want to suggest improvements
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- **Memory nodes** — structured persistent memory with labels, content, metadata, and type system
|
|
32
|
+
- **Semantic search** — ONNX-powered embeddings (all-MiniLM-L6-v2) with HNSW vector index for fast ANN retrieval
|
|
33
|
+
- **BM25 full-text search** — keyword search as a fallback, hybrid-scored with embeddings for best results
|
|
34
|
+
- **Fractal retrieval** — drill-down from high-level summaries to granular details
|
|
35
|
+
- **Automatic compression** — periodically summarizes low-level nodes into progressively higher-level abstractions (4 levels)
|
|
36
|
+
- **Auto-retrieve** — context-aware injection of relevant memories, skills, and playbooks into the prompt
|
|
37
|
+
- **Ollama reranking** — re-ranks memory search results with a local LLM for better relevance
|
|
38
|
+
- **LLM compression** — uses LLM to generate richer summaries instead of regex extraction
|
|
39
|
+
- **Auto-distill** — automatically extracts actionable rules from lesson nodes
|
|
40
|
+
- **Predictive rating** — adjusts memory usefulness scores over time based on usage patterns
|
|
41
|
+
- **Cache system** — in-memory LRU cache for frequently accessed nodes with configurable TTL
|
|
42
|
+
- **Journal** — append-only searchable journal entries with semantic search
|
|
43
|
+
- **Playbooks** — reusable workflow templates (sticky memory nodes) proposed by the agent
|
|
44
|
+
- **Management server** — local web UI (port 8787) for browsing, searching, and editing memory
|
|
45
|
+
- **Sub-agents** — `memory-hints` and `memory-researcher` agents for guided memory interaction
|
|
46
|
+
|
|
47
|
+
## Prerequisites
|
|
48
|
+
|
|
49
|
+
| Requirement | Version | Notes |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| **OpenCode** | v1.15.13+ | SDK peer dependency |
|
|
52
|
+
| **Bun** | >=1.0.0 | Plugin runtime |
|
|
53
|
+
| **Node.js** | >=18 | For npm-based installs only |
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
### For OpenCode users
|
|
58
|
+
|
|
59
|
+
Add the plugin name to `~/.config/opencode/opencode.json`:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"plugins": ["opencode-fractal-memory"]
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
OpenCode installs it automatically at startup. Model files (~24 MB) download on first plugin load via `ensureModels()` — no manual steps needed.
|
|
68
|
+
|
|
69
|
+
### For development / manual install
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm install opencode-fractal-memory
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Models download on first run. Use `--ignore-scripts` if installing via Bun (Bun skips lifecycle scripts).
|
|
76
|
+
|
|
77
|
+
### MCP server setup
|
|
78
|
+
|
|
79
|
+
Enables memory tools in IDEs that support the Model Context Protocol (Cursor, Windsurf, etc.):
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"mcp": {
|
|
84
|
+
"fractal-memory": {
|
|
85
|
+
"type": "local",
|
|
86
|
+
"command": ["bun", "run", "~/.config/opencode/node_modules/opencode-fractal-memory/dist/mcp-server.js"],
|
|
87
|
+
"enabled": true
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
Create `~/.config/opencode/opencode-mem.json` to customize (optional — all defaults work out of the box):
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"autoRetrieve": {
|
|
100
|
+
"enabled": true,
|
|
101
|
+
"candidateCount": 30,
|
|
102
|
+
"maxInjectNodes": 5,
|
|
103
|
+
"maxInjectPlaybooks": 3
|
|
104
|
+
},
|
|
105
|
+
"ollama": {
|
|
106
|
+
"enabled": false,
|
|
107
|
+
"baseUrl": "http://localhost:11434",
|
|
108
|
+
"model": "qwen2.5-coder:1.5b",
|
|
109
|
+
"mode": "binary"
|
|
110
|
+
},
|
|
111
|
+
"llmCompression": {
|
|
112
|
+
"enabled": false,
|
|
113
|
+
"maxSummaryTokens": 500
|
|
114
|
+
},
|
|
115
|
+
"autoDistill": {
|
|
116
|
+
"enabled": false,
|
|
117
|
+
"minLessons": 3,
|
|
118
|
+
"useLlm": false
|
|
119
|
+
},
|
|
120
|
+
"predictiveRating": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"decayDays": 7,
|
|
123
|
+
"confidenceThreshold": 0.3,
|
|
124
|
+
"positiveBoost": 0.1,
|
|
125
|
+
"negativePenalty": 0.05
|
|
126
|
+
},
|
|
127
|
+
"maxInjectionTokens": 8000,
|
|
128
|
+
"coreInjectionTokens": 2000,
|
|
129
|
+
"cacheSize": 8,
|
|
130
|
+
"cacheTTLHours": 2,
|
|
131
|
+
"autoCompressThreshold": 0.7,
|
|
132
|
+
"highContextThreshold": 0.6,
|
|
133
|
+
"criticalContextThreshold": 0.8,
|
|
134
|
+
"defaultTtlDays": 0,
|
|
135
|
+
"enableMiddleTermCapture": true
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Config reference
|
|
140
|
+
|
|
141
|
+
| Field | Type | Default | Description |
|
|
142
|
+
|---|---|---|---|---|
|
|
143
|
+
| `autoRetrieve.enabled` | bool | `false` | Enable automatic memory injection into prompts |
|
|
144
|
+
| `autoRetrieve.candidateCount` | int | `30` | Number of candidates to fetch for injection |
|
|
145
|
+
| `autoRetrieve.maxInjectNodes` | int | `5` | Max memory nodes to inject per turn |
|
|
146
|
+
| `autoRetrieve.maxInjectPlaybooks` | int | `3` | Max matching playbooks to list |
|
|
147
|
+
| `ollama.enabled` | bool | `false` | Use local LLM for reranking search results |
|
|
148
|
+
| `ollama.baseUrl` | string | `http://localhost:11434` | Ollama server URL |
|
|
149
|
+
| `ollama.model` | string | `qwen2.5-coder:1.5b` | Model for reranking |
|
|
150
|
+
| `ollama.mode` | enum | `"binary"` | `"binary"` (relevant/not) or `"score"` (0-1 rating) |
|
|
151
|
+
| `llmCompression.enabled` | bool | `false` | Use LLM for richer compression summaries |
|
|
152
|
+
| `llmCompression.model` | string | _none_ | LLM model name (uses ollama if not set) |
|
|
153
|
+
| `llmCompression.maxSummaryTokens` | int | `500` | Max tokens per LLM-generated summary |
|
|
154
|
+
| `autoDistill.enabled` | bool | `false` | Auto-extract rules from lesson nodes |
|
|
155
|
+
| `autoDistill.minLessons` | int | `3` | Min lessons before extraction |
|
|
156
|
+
| `autoDistill.useLlm` | bool | `false` | Use LLM for more specific rules |
|
|
157
|
+
| `predictiveRating.enabled` | bool | `false` | Auto-decay and boost node usefulness |
|
|
158
|
+
| `predictiveRating.decayDays` | int | `7` | Days until usefulness decay |
|
|
159
|
+
| `predictiveRating.confidenceThreshold` | float | `0.3` | Min confidence to count as relevant |
|
|
160
|
+
| `predictiveRating.positiveBoost` | float | `0.1` | Usefulness boost on positive rate |
|
|
161
|
+
| `predictiveRating.negativePenalty` | float | `0.05` | Usefulness penalty on negative rate |
|
|
162
|
+
| `maxInjectionTokens` | int | `8000` | Max tokens allowed in a single injection |
|
|
163
|
+
| `coreInjectionTokens` | int | `2000` | Tokens reserved for core rules in injection |
|
|
164
|
+
| `cacheSize` | int | `8` | Max cached nodes in LRU cache |
|
|
165
|
+
| `cacheTTLHours` | int | `2` | Cache entry TTL in hours |
|
|
166
|
+
| `autoCompressThreshold` | float | `0.7` | Context usage ratio triggering auto-compression |
|
|
167
|
+
| `highContextThreshold` | float | `0.6` | Token usage ratio for high context warning |
|
|
168
|
+
| `criticalContextThreshold` | float | `0.8` | Token usage ratio for critical warning |
|
|
169
|
+
| `defaultTtlDays` | int | `0` | Default TTL for new nodes (0 = no expiry) |
|
|
170
|
+
| `enableMiddleTermCapture` | bool | `true` | Save middle-term snapshots before compression |
|
|
171
|
+
| `autoFileSummarization.enabled` | bool | `false` | Auto-summarize files on read |
|
|
172
|
+
|
|
173
|
+
## Advanced Features
|
|
174
|
+
|
|
175
|
+
### Ollama Reranking
|
|
176
|
+
|
|
177
|
+
When enabled in config, auto-retrieve results are re-ranked by a local LLM (via Ollama) for better relevance. The reranker scores candidates against the user's query and only keeps the most relevant ones:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"ollama": {
|
|
182
|
+
"enabled": true,
|
|
183
|
+
"baseUrl": "http://localhost:11434",
|
|
184
|
+
"model": "qwen2.5-coder:1.5b",
|
|
185
|
+
"mode": "binary"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
In `"binary"` mode, the LLM labels each candidate as relevant or not. In `"score"` mode, it assigns a 0-1 relevance score.
|
|
191
|
+
|
|
192
|
+
### LLM Compression
|
|
193
|
+
|
|
194
|
+
Instead of regex-based compression (which extracts keywords), LLM compression generates richer natural-language summaries:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"llmCompression": {
|
|
199
|
+
"enabled": true,
|
|
200
|
+
"model": "qwen2.5-coder:1.5b",
|
|
201
|
+
"maxSummaryTokens": 500
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Invoke manually with `memory_llm_compress`.
|
|
207
|
+
|
|
208
|
+
### Auto-Distill
|
|
209
|
+
|
|
210
|
+
Periodically extracts actionable rules from `lesson`-type nodes created by `memory_reflect`. Rules are stored as `rule:standard:*` / `rule:suggestion:*` nodes for immediate injection:
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"autoDistill": {
|
|
215
|
+
"enabled": true,
|
|
216
|
+
"minLessons": 3,
|
|
217
|
+
"useLlm": false
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Set `useLlm: true` for LLM-generated rules instead of keyword extraction.
|
|
223
|
+
|
|
224
|
+
### Predictive Rating
|
|
225
|
+
|
|
226
|
+
Automatically adjusts node usefulness scores over time. Frequently accessed nodes get boosted; nodes that haven't been touched in `decayDays` get gradually decayed:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"predictiveRating": {
|
|
231
|
+
"enabled": true,
|
|
232
|
+
"decayDays": 7,
|
|
233
|
+
"confidenceThreshold": 0.3,
|
|
234
|
+
"positiveBoost": 0.1,
|
|
235
|
+
"negativePenalty": 0.05
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Commands
|
|
241
|
+
|
|
242
|
+
### Memory tools
|
|
243
|
+
|
|
244
|
+
| Command | Description |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `memory_set` | Create or update a memory node |
|
|
247
|
+
| `memory_get` | Get a single node by ID or label |
|
|
248
|
+
| `memory_fetch` | Fetch a node by exact label |
|
|
249
|
+
| `memory_search` | Search nodes by text, embedding, or BM25 |
|
|
250
|
+
| `memory_delete` | Delete a node by ID or label |
|
|
251
|
+
| `memory_list` | List nodes with optional scope/level filters |
|
|
252
|
+
| `memory_replace` | Replace content in a memory node |
|
|
253
|
+
| `memory_rate` | Rate a node's usefulness (helps ranking) |
|
|
254
|
+
| `memory_prune` | Find and remove stale/unused nodes |
|
|
255
|
+
| `memory_inject` | Inject relevant memories into the prompt with token budgeting |
|
|
256
|
+
| `memory_injection_debug` | Show what was injected in the last session |
|
|
257
|
+
| `memory_injection_feedback` | Rate injected memory usefulness |
|
|
258
|
+
| `memory_injection_stats` | View injection efficiency metrics |
|
|
259
|
+
| `memory_drilldown` | Retrieve a node with its source chain (fractal retrieval) |
|
|
260
|
+
| `memory_drilldown_query` | Top-down drilldown by query (find + expand) |
|
|
261
|
+
| `memory_detect_topics` | Detect topic clusters in memory |
|
|
262
|
+
| `memory_stats` | Show memory statistics (nodes per level, compression ratios) |
|
|
263
|
+
| `memory_dashboard` | Display memory dashboard with visual overview |
|
|
264
|
+
| `memory_tool_stats` | View tool call statistics and efficiency |
|
|
265
|
+
| `memory_session_stats` | Get statistics about the current session |
|
|
266
|
+
| `memory_compress` | Compress old nodes into higher-level summaries |
|
|
267
|
+
| `memory_llm_compress` | LLM-powered compression (richer summaries) |
|
|
268
|
+
| `memory_extract_patterns` | Extract cross-topic pattern summaries |
|
|
269
|
+
| `memory_distill` | Extract actionable rules from lesson nodes |
|
|
270
|
+
| `memory_summarize` | Generate an LLM prompt to summarize a node |
|
|
271
|
+
| `memory_check_context` | Check token usage of memory nodes |
|
|
272
|
+
| `memory_total_tokens` | Complete token analysis (memory + conversation) |
|
|
273
|
+
| `memory_generate_embeddings` | Generate embeddings for nodes that lack them |
|
|
274
|
+
| `memory_middle_term` | View context snapshots before compaction |
|
|
275
|
+
| `memory_cache_status` | Show working-memory cache usage |
|
|
276
|
+
| `memory_skill_load` | Load a skill's instructions by name |
|
|
277
|
+
| `memory_playbook_execute` | Execute a playbook workflow |
|
|
278
|
+
| `memory_verify` | Verify that a node's information is correct |
|
|
279
|
+
| `memory_reflect` | Analyze a session and create lesson nodes |
|
|
280
|
+
| `memory_help` | Show all available memory commands |
|
|
281
|
+
| `memory_version` | Show installed plugin version |
|
|
282
|
+
|
|
283
|
+
### Playbook tools
|
|
284
|
+
|
|
285
|
+
| Command | Description |
|
|
286
|
+
|---|---|
|
|
287
|
+
| `memory_playbook_execute` | Execute a playbook (returns steps for the agent to run) |
|
|
288
|
+
|
|
289
|
+
Playbooks are stored as `type: "playbook"` memory nodes with steps in `metadata`. CRUD uses generic `memory_set` / `memory_get` / `memory_search` tools. The agent proposes playbooks when it spots repeated multi-step patterns.
|
|
290
|
+
|
|
291
|
+
### Journal tools
|
|
292
|
+
|
|
293
|
+
| Command | Description |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `journal_write` | Write a new journal entry |
|
|
296
|
+
| `journal_read` | Read a journal entry by ID |
|
|
297
|
+
| `journal_search` | Search journal entries semantically |
|
|
298
|
+
|
|
299
|
+
### MCP tools
|
|
300
|
+
|
|
301
|
+
When the MCP server is configured, the `memory_search`, `memory_get`, and related tools are available as MCP resources for IDE integration.
|
|
302
|
+
|
|
303
|
+
## Skills
|
|
304
|
+
|
|
305
|
+
Skills are specialized instruction sets stored as memory nodes. When a task matches a skill's trigger keywords, its instructions load into context to guide the agent.
|
|
306
|
+
|
|
307
|
+
### Available skills
|
|
308
|
+
|
|
309
|
+
| Skill | Triggers |
|
|
310
|
+
|---|---|
|
|
311
|
+
| `debug-workflow` | bug, error, fix, crash |
|
|
312
|
+
| `write-tests` | tests, coverage, test suites |
|
|
313
|
+
| `refactor-component` | refactor, restructure, clean up |
|
|
314
|
+
| `refactoring-expert` | SOLID, code smell, technical debt |
|
|
315
|
+
| `security-review` | security, audit, vulnerability, deploy |
|
|
316
|
+
| `threejs-skills` | 3D, WebGL, visualization |
|
|
317
|
+
| `svelte-core-bestpractices` | svelte, component, runes |
|
|
318
|
+
| `svelte-code-writer` | svelte 5, sveltekit, component |
|
|
319
|
+
| `customize-opencode` | opencode config, agent, plugin |
|
|
320
|
+
|
|
321
|
+
### Loading a skill
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
memory_skill_load(name="debug-workflow")
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Skills are auto-injected when triggers match the task context. You can also load them explicitly with `memory_skill_load`.
|
|
328
|
+
|
|
329
|
+
### Creating a skill
|
|
330
|
+
|
|
331
|
+
Skills are memory nodes with `type: "skill"`. Create one with:
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
memory_set(
|
|
335
|
+
label: "skill:my-skill",
|
|
336
|
+
content: "## Skill instructions...",
|
|
337
|
+
type: "skill",
|
|
338
|
+
metadata: JSON.stringify({ triggers: ["keyword1", "keyword2"] }),
|
|
339
|
+
sticky: true
|
|
340
|
+
)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Sub-agents
|
|
344
|
+
|
|
345
|
+
The plugin ships with two agent instruction files for specialized memory interaction:
|
|
346
|
+
|
|
347
|
+
| Agent | File | Purpose |
|
|
348
|
+
|---|---|---|
|
|
349
|
+
| `memory-hints` | `agent/memory-hints.md` | System-level hints for using memory effectively — injected by the agent when memory-related context is needed |
|
|
350
|
+
| `memory-researcher` | `agent/memory-researcher.md` | Analyzes and reports on fractal memory state — invoked via `memory_skill_load(name="memory-researcher")` |
|
|
351
|
+
|
|
352
|
+
These are loaded by OpenCode's agent system and provide structured guidance for memory operations.
|
|
353
|
+
|
|
354
|
+
## Management App
|
|
355
|
+
|
|
356
|
+
A local web UI for browsing, searching, and editing memory — available when the plugin is active.
|
|
357
|
+
|
|
358
|
+
### Starting
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
bun run view
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Opens at [http://localhost:8787](http://localhost:8787). The server also starts automatically with OpenCode.
|
|
365
|
+
|
|
366
|
+
### Usage
|
|
367
|
+
|
|
368
|
+
**3D Graph** — the default view shows memory nodes as spheres connected by `[[wiki-link]]` relationships:
|
|
369
|
+
- **Drag** to rotate the scene
|
|
370
|
+
- **Scroll** to zoom in/out
|
|
371
|
+
- **Left-click** a node to select and inspect it
|
|
372
|
+
- **Right-click drag** to pan
|
|
373
|
+
- Nodes are color-coded by type (note, skill, playbook, rule)
|
|
374
|
+
|
|
375
|
+
**Search** — find nodes by content, label, or type:
|
|
376
|
+
- Type a query and press Enter
|
|
377
|
+
- Results show relevance scores and preview snippets
|
|
378
|
+
- Click a result to navigate to it in the graph
|
|
379
|
+
|
|
380
|
+
**Inspect** — when you click a node (graph or search results):
|
|
381
|
+
- View full content and summary
|
|
382
|
+
- See metadata JSON (type, importance, access count, timestamps)
|
|
383
|
+
- View embedding vector (truncated)
|
|
384
|
+
- See linked nodes and navigate between them
|
|
385
|
+
|
|
386
|
+
**Edit** — modify node fields directly:
|
|
387
|
+
- Update content, summary, importance, or type
|
|
388
|
+
- Changes persist immediately to the SQLite database
|
|
389
|
+
- Embedding auto-regenerates on content change
|
|
390
|
+
|
|
391
|
+
**Inject** — push a node directly into the agent's context:
|
|
392
|
+
- Click "Inject" on any node
|
|
393
|
+
- The node appears in the agent's next prompt
|
|
394
|
+
- Useful for reminding the agent of past decisions mid-session
|
|
395
|
+
|
|
396
|
+
**Manage** — the node list view shows all nodes with:
|
|
397
|
+
- Scope (global vs project), level, access count
|
|
398
|
+
- Last accessed and last verified timestamps
|
|
399
|
+
- Actions: edit, delete, verify, inject
|
|
400
|
+
|
|
401
|
+
## How Plugin Initialization Works
|
|
402
|
+
|
|
403
|
+
When OpenCode loads the plugin, `initStorage()` runs automatically:
|
|
404
|
+
|
|
405
|
+
1. **SQLite database** — created at `<project>/.opencode/memory.db` with all tables and indexes
|
|
406
|
+
2. **Seed nodes** — rule nodes, built-in playbooks (6), and skills (9) inserted into `memory_nodes`
|
|
407
|
+
3. **Model files** — `ensureModels()` checks `~/.config/opencode/models/` and downloads ONNX + tokenizer (~24 MB) if missing
|
|
408
|
+
4. **Agent files** — `ensureAgentFiles()` copies `agent/` directory to `~/.config/opencode/agent/`
|
|
409
|
+
5. **Command files** — `ensureCommandFiles()` copies `commands/` directory to `~/.config/opencode/commands/`
|
|
410
|
+
6. **Background embeddings** — after 1s, generates embeddings for nodes that lack them
|
|
411
|
+
7. **Auto-retrieve hook** — if enabled in config, injects relevant context into prompts
|
|
412
|
+
|
|
413
|
+
All of this happens automatically — no manual intervention required.
|
|
414
|
+
|
|
415
|
+
## Logs
|
|
416
|
+
|
|
417
|
+
| Log | Path | Contents |
|
|
418
|
+
|-----|------|----------|
|
|
419
|
+
| Memory | `~/.config/opencode/memory.log` | Plugin operations, errors, injection events |
|
|
420
|
+
| OpenCode | `~/.local/share/opencode/log/` | Application lifecycle, tool calls |
|
|
421
|
+
|
|
422
|
+
## Development
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
git clone <repo>
|
|
426
|
+
cd opencode-fractal-memory
|
|
427
|
+
bun install
|
|
428
|
+
bun run build
|
|
429
|
+
bun run typecheck
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Testing
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
bun test
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Installing locally (development)
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
bun run build
|
|
442
|
+
npm pack
|
|
443
|
+
cd ~/.config/opencode
|
|
444
|
+
rm -rf node_modules/opencode-fractal-memory package-lock.json
|
|
445
|
+
npm install --ignore-scripts <path-to-tgz>
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Use `--ignore-scripts` to avoid trust prompts. Models download automatically on first plugin load via `ensureModels()` in `initStorage()`.
|
|
449
|
+
|
|
450
|
+
## Architecture
|
|
451
|
+
|
|
452
|
+
```
|
|
453
|
+
┌──────────────────────────────────────────────────┐
|
|
454
|
+
│ Plugin Layer (plugin/index.ts) │
|
|
455
|
+
│ ┌──────────┬──────────┬──────────┬───────────┐ │
|
|
456
|
+
│ │ Memory │ Skills │ Journal │ Auto- │ │
|
|
457
|
+
│ │ Store │ (nodes) │ Store │ Retrieve │ │
|
|
458
|
+
│ └────┬─────┴────┬─────┴────┬─────┴─────┬─────┘ │
|
|
459
|
+
│ │ │ │ │ │
|
|
460
|
+
│ ┌────┴──────────┴──────────┴───────────┴─────┐ │
|
|
461
|
+
│ │ SQLite (.opencode/memory.db) │ │
|
|
462
|
+
│ │ - memory_nodes (labels, content, embeds) │ │
|
|
463
|
+
│ │ - type: "note" / "skill" / "playbook" │ │
|
|
464
|
+
│ │ - sticky playbooks/skills never pruned │ │
|
|
465
|
+
│ │ - metadata.steps for playbook steps │ │
|
|
466
|
+
│ │ - memory_links (wiki-link crossrefs) │ │
|
|
467
|
+
│ │ - bm25_index (full-text search) │ │
|
|
468
|
+
│ │ - injection_metrics / session_metrics │ │
|
|
469
|
+
│ └─────────────────────────────────────────────┘ │
|
|
470
|
+
│ │
|
|
471
|
+
│ ┌─────────────────────────────────────────────┐ │
|
|
472
|
+
│ │ HNSW Vector Index (in-memory, 384-dim) │ │
|
|
473
|
+
│ └─────────────────────────────────────────────┘ │
|
|
474
|
+
│ │
|
|
475
|
+
│ ┌─────────────────────────────────────────────┐ │
|
|
476
|
+
│ │ ONNX Embedding Model (all-MiniLM-L6-v2) │ │
|
|
477
|
+
│ │ onnxruntime-web + @huggingface/tokenizers │ │
|
|
478
|
+
│ └─────────────────────────────────────────────┘ │
|
|
479
|
+
└──────────────────────────────────────────────────┘
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Storage
|
|
483
|
+
|
|
484
|
+
Two SQLite databases:
|
|
485
|
+
|
|
486
|
+
| Scope | Path | Purpose |
|
|
487
|
+
|---|---|---|
|
|
488
|
+
| Global | `~/.config/opencode/memory.db` | Rules, persona, preferences, shared across projects |
|
|
489
|
+
| Project | `<project>/.opencode/memory.db` | Project-specific memory, nodes, playbooks, journal |
|
|
490
|
+
|
|
491
|
+
## License
|
|
492
|
+
|
|
493
|
+
MIT
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-hints
|
|
3
|
+
description: Memory system hints and best practices
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory System Guidelines
|
|
7
|
+
|
|
8
|
+
## CRITICAL: Memory-First Workflow
|
|
9
|
+
**ALWAYS** check memory before starting any task:
|
|
10
|
+
1. `memory_search('relevant topic')` - find existing context
|
|
11
|
+
2. `memory_drilldown_query('what do we know about X?')` - intent-based search
|
|
12
|
+
3. Use found context to inform your approach
|
|
13
|
+
4. If nothing found, proceed and store what you learn
|
|
14
|
+
|
|
15
|
+
## ⚡ MEMORY TRIGGER (Use THIS for quick lookup)
|
|
16
|
+
When you need to recall past context, use inline trigger in your response:
|
|
17
|
+
```
|
|
18
|
+
[[memory: your search query here]]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The plugin will automatically:
|
|
22
|
+
1. Detect the pattern in your output
|
|
23
|
+
2. Run memory_search with the query
|
|
24
|
+
3. Replace the [[memory: ...]] marker with search results
|
|
25
|
+
4. Track which memories were useful
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
```
|
|
29
|
+
Let me check what we know about deploying this plugin...
|
|
30
|
+
[[memory: how to deploy opencode plugin]]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**This is FASTER than calling memory_search tool - use this for quick lookups!**
|
|
34
|
+
|
|
35
|
+
## When to Create Memories (AUTO-STORE)
|
|
36
|
+
|
|
37
|
+
### After Reading Files
|
|
38
|
+
When you read a file to understand its purpose:
|
|
39
|
+
```
|
|
40
|
+
memory_set {
|
|
41
|
+
label: "file:src/components/Auth.tsx",
|
|
42
|
+
content: "## Auth Component\n- Handles login/logout\n- Uses JWT tokens\n- Calls /api/auth endpoint",
|
|
43
|
+
type: "knowledge"
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### After Completing Tasks
|
|
48
|
+
After finishing significant work:
|
|
49
|
+
```
|
|
50
|
+
memory_set {
|
|
51
|
+
label: "task:implement-auth-2026-03-30",
|
|
52
|
+
content: "## Auth Implementation\n- Decided to use JWT (not sessions)\n- Files: src/auth.ts, src/middleware.ts\n- Key decisions: 24h expiry, refresh tokens",
|
|
53
|
+
type: "session"
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### After Finding Bugs/Workarounds
|
|
58
|
+
When you discover something non-obvious:
|
|
59
|
+
```
|
|
60
|
+
memory_set {
|
|
61
|
+
label: "bug:sqlite-locking",
|
|
62
|
+
content: "## SQLite Locking Issue\n- Problem: concurrent writes fail\n- Solution: retry with exponential backoff\n- Location: src/storage/sqlite.ts:19-49",
|
|
63
|
+
type: "lesson"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### User Preferences
|
|
68
|
+
When you learn user preferences:
|
|
69
|
+
```
|
|
70
|
+
memory_set {
|
|
71
|
+
label: "pref:code-style",
|
|
72
|
+
content: "## User Preferences\n- Prefers functional components\n- No emojis in code\n- Short variable names",
|
|
73
|
+
type: "preference"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Memory Tools Reference
|
|
78
|
+
|
|
79
|
+
| Tool | When to use |
|
|
80
|
+
|------|-------------|
|
|
81
|
+
| `memory_search` | Before starting any task |
|
|
82
|
+
| `memory_set` | After reading files, completing tasks, finding bugs |
|
|
83
|
+
| `memory_get` | When you need full details of a known node |
|
|
84
|
+
| `memory_drilldown` | When working with compressed summaries |
|
|
85
|
+
| `memory_rate` | After using memory to complete a task |
|
|
86
|
+
| `memory_compress` | When memory grows large (check with memory_stats) |
|
|
87
|
+
|
|
88
|
+
## Token Optimization
|
|
89
|
+
- Use `memory_check_context` to monitor token usage
|
|
90
|
+
- Prefer `memory_drilldown` on L1+ nodes over raw L0 nodes
|
|
91
|
+
- Compress when context exceeds 60%
|
|
92
|
+
|
|
93
|
+
## Memory Labels Convention
|
|
94
|
+
- `file:path` - File summaries
|
|
95
|
+
- `task:description-date` - Task completions
|
|
96
|
+
- `bug:issue-name` - Bug workarounds
|
|
97
|
+
- `pref:category` - User preferences
|
|
98
|
+
- `decision:what-when` - Architecture decisions
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Analyzes and reports on fractal memory state
|
|
3
|
+
mode: subagent
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are a specialized memory research agent. Your job is to analyze the fractal memory system and provide concise, actionable reports.
|
|
7
|
+
|
|
8
|
+
## Your Role
|
|
9
|
+
- Analyze memory health, compression candidates, redundancies, and topic clusters
|
|
10
|
+
- Provide brief reports (~200 tokens) that help the main agent make decisions
|
|
11
|
+
- Less chatty — get to the point
|
|
12
|
+
|
|
13
|
+
## Available Tools
|
|
14
|
+
- `memory_stats` — Get fractal stats
|
|
15
|
+
- `memory_list` — List all nodes (use sparingly)
|
|
16
|
+
- `memory_search` — Semantic search
|
|
17
|
+
- `memory_detect_topics` — Find topic clusters
|
|
18
|
+
- `memory_check_context` — Check token usage
|
|
19
|
+
- `memory_get` — Get specific nodes
|
|
20
|
+
|
|
21
|
+
## Research Focus Areas
|
|
22
|
+
|
|
23
|
+
### 1. Memory Health
|
|
24
|
+
- Total nodes, distribution across levels
|
|
25
|
+
- Fractal dimension (target: 2-4)
|
|
26
|
+
- Compression ratios
|
|
27
|
+
|
|
28
|
+
### 2. Compression Opportunities
|
|
29
|
+
- L0 nodes older than 7 days → candidates for L1
|
|
30
|
+
- Uncompressed L0 nodes → ~token savings estimate
|
|
31
|
+
- Orphaned nodes (no parent, no children)
|
|
32
|
+
|
|
33
|
+
### 3. Redundancies
|
|
34
|
+
- Similar content across nodes
|
|
35
|
+
- Duplicate explanations
|
|
36
|
+
- Nodes that could merge
|
|
37
|
+
|
|
38
|
+
### 4. Stale Nodes
|
|
39
|
+
- Not accessed in 30+ days
|
|
40
|
+
- Could be archived or deleted
|
|
41
|
+
|
|
42
|
+
## Output Format
|
|
43
|
+
Always provide:
|
|
44
|
+
1. One-line summary
|
|
45
|
+
2. Key findings (bullet points)
|
|
46
|
+
3. Recommended action (if any)
|
|
47
|
+
|
|
48
|
+
## Communication
|
|
49
|
+
- Be concise — main agent will read your report
|
|
50
|
+
- Do NOT verbose explain methodology
|
|
51
|
+
- Focus on actionable insights
|
|
52
|
+
- If no action needed, say so briefly
|
|
53
|
+
|
|
54
|
+
## When to Trigger
|
|
55
|
+
- Called via `task` tool by main agent
|
|
56
|
+
- Main agent may specify a focus: health, compression, redundancy, all
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show current working‑memory cache usage (size, max size, recent files)
|
|
3
|
+
---
|
|
4
|
+
Displays the size of the working‑memory cache, its maximum capacity, and the most recently accessed files.
|
|
5
|
+
|
|
6
|
+
**Usage:**
|
|
7
|
+
```
|
|
8
|
+
memory_cache_status
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Arguments:** None.
|
|
12
|
+
|
|
13
|
+
The tool is useful for debugging cache behavior and ensuring that the cache is being utilized effectively.
|