@basicmemory/openclaw-basic-memory 0.1.0-alpha.8 → 0.1.1
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 +142 -470
- package/bm-client.ts +27 -19
- package/config.ts +1 -25
- package/index.ts +54 -33
- package/openclaw.plugin.json +2 -14
- package/package.json +2 -1
- package/schema/conversation-schema.ts +33 -0
- package/scripts/setup-bm.sh +2 -3
package/README.md
CHANGED
|
@@ -1,134 +1,66 @@
|
|
|
1
1
|
# openclaw-basic-memory
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Give your OpenClaw agent persistent, searchable memory — in plain text files you can read and edit.
|
|
4
4
|
|
|
5
|
-
## What
|
|
6
|
-
|
|
7
|
-
The `openclaw-basic-memory` plugin integrates [Basic Memory](https://github.com/basicmachines-co/basic-memory) with OpenClaw to provide:
|
|
5
|
+
## What is Basic Memory?
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
- **Persistent MCP stdio session** — keeps a single `bm mcp --transport stdio --project <name>` process alive
|
|
11
|
-
- **Auto-recall** — injects active tasks and recent activity as context at session start
|
|
12
|
-
- **Auto-capture** — records agent conversations as structured daily notes
|
|
13
|
-
- **Graph tools** — search, read, write, edit, delete, move, and navigate notes via `memory://` URLs
|
|
14
|
-
- **Skill workflows** — `/tasks`, `/reflect`, `/defrag`, `/schema` slash commands for guided memory management
|
|
7
|
+
[Basic Memory](https://basicmemory.com) stores AI knowledge in local Markdown files and indexes them into a semantic knowledge graph. Your agent writes notes. You can open them in any editor, read them, change them, and the changes sync back automatically. No black box. No proprietary format. Just files.
|
|
15
8
|
|
|
16
|
-
|
|
9
|
+
It does three things that work together:
|
|
17
10
|
|
|
18
|
-
|
|
11
|
+
- **Stores knowledge in plain Markdown** — everything lives in plain text files on your computer, not locked inside a database you can't read
|
|
12
|
+
- **Creates connections automatically** — notes link to each other through a searchable, traversable knowledge graph
|
|
13
|
+
- **Searches by meaning, not just keywords** — vector search finds relevant context even when the exact words don't match
|
|
14
|
+
- **Keeps notes consistent** — dynamic schemas and validation ensure your knowledge base stays structured and useful as it grows
|
|
15
|
+
- **Enables two-way collaboration** — both you and the AI read and write the same files
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
Over time, your agent builds a knowledge base that grows with you. Context that survives across sessions. Memory that belongs to you.
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
# macOS
|
|
25
|
-
brew install uv
|
|
19
|
+
Learn more: [basicmemory.com](https://basicmemory.com) · [GitHub](https://github.com/basicmachines-co/basic-memory) · [Docs](https://docs.basicmemory.com)
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
29
|
-
```
|
|
21
|
+
## What this plugin does
|
|
30
22
|
|
|
31
|
-
|
|
23
|
+
This plugin connects Basic Memory to OpenClaw so your agent can:
|
|
32
24
|
|
|
33
|
-
|
|
25
|
+
- **Remember across sessions** — search and recall past conversations, decisions, and context
|
|
26
|
+
- **Track work in progress** — structured tasks that survive context compaction
|
|
27
|
+
- **Build knowledge over time** — notes, observations, and relations that grow into a connected graph
|
|
28
|
+
- **Search intelligently** — composited search across working memory, the knowledge graph, and active tasks in parallel
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
# Install the plugin (automatically installs the bm CLI via uv)
|
|
37
|
-
openclaw plugins install @basicmemory/openclaw-basic-memory
|
|
30
|
+
All data stays on your machine as Markdown files indexed locally with SQLite. Cloud sync is available but entirely optional.
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
openclaw plugins enable openclaw-basic-memory --slot memory
|
|
32
|
+
## Install
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
openclaw gateway restart
|
|
44
|
-
```
|
|
34
|
+
**Prerequisite:** [uv](https://docs.astral.sh/uv/) (Python package manager) — used to install the Basic Memory CLI.
|
|
45
35
|
|
|
46
|
-
Verify:
|
|
47
36
|
```bash
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
If `uv` is not installed, the `bm` CLI setup is skipped gracefully during install. Install `uv` first, then re-run the postinstall script:
|
|
37
|
+
# macOS
|
|
38
|
+
brew install uv
|
|
53
39
|
|
|
54
|
-
|
|
55
|
-
|
|
40
|
+
# macOS / Linux
|
|
41
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
56
42
|
```
|
|
57
43
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Everything works locally — cloud adds cross-device, team, and production capabilities:
|
|
61
|
-
|
|
62
|
-
- **Your agent's memory travels with you** — same knowledge graph on laptop, desktop, and hosted environments
|
|
63
|
-
- **Team knowledge sharing** — org workspaces let multiple agents and team members build on a shared knowledge base
|
|
64
|
-
- **Durable memory for production agents** — persistent memory that survives CI teardowns and container restarts
|
|
65
|
-
- **Multi-agent coordination** — multiple agents can read and write to the same graph
|
|
66
|
-
|
|
67
|
-
Cloud extends local-first — still plain markdown, still yours. Start with a [7-day free trial](https://basicmemory.com) and use code `BMCLAW` for 20% off for 3 months. See [BASIC_MEMORY.md](./BASIC_MEMORY.md) for cloud setup.
|
|
68
|
-
|
|
69
|
-
### Development (local directory)
|
|
70
|
-
|
|
71
|
-
For plugin development, clone and link locally:
|
|
44
|
+
Then install the plugin:
|
|
72
45
|
|
|
73
46
|
```bash
|
|
74
|
-
|
|
75
|
-
cd openclaw-basic-memory
|
|
76
|
-
bun install
|
|
77
|
-
openclaw plugins install -l "$PWD"
|
|
78
|
-
openclaw plugins enable openclaw-basic-memory --slot memory
|
|
47
|
+
openclaw plugins install @basicmemory/openclaw-basic-memory
|
|
79
48
|
openclaw gateway restart
|
|
80
49
|
```
|
|
81
50
|
|
|
82
|
-
|
|
51
|
+
That's it. The plugin auto-installs the `bm` CLI on first startup if it's not already on your PATH. See [SECURITY.md](./SECURITY.md) for details on how this works.
|
|
83
52
|
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
plugins: {
|
|
87
|
-
load: {
|
|
88
|
-
paths: ["~/dev/openclaw-basic-memory"]
|
|
89
|
-
},
|
|
90
|
-
entries: {
|
|
91
|
-
"openclaw-basic-memory": {
|
|
92
|
-
enabled: true
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
slots: {
|
|
96
|
-
memory: "openclaw-basic-memory"
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Bundled Skills
|
|
103
|
-
|
|
104
|
-
This plugin ships with six skills that are automatically available when the plugin is enabled — no manual installation needed:
|
|
105
|
-
|
|
106
|
-
- **`memory-tasks`** — structured task tracking that survives context compaction
|
|
107
|
-
- **`memory-reflect`** — periodic consolidation of recent notes into durable memory
|
|
108
|
-
- **`memory-defrag`** — periodic cleanup/reorganization of memory files
|
|
109
|
-
- **`memory-schema`** — schema lifecycle management (infer, create, validate, diff, evolve)
|
|
110
|
-
- **`memory-metadata-search`** — structured metadata search by custom frontmatter fields (status, priority, etc.)
|
|
111
|
-
- **`memory-notes`** — guidance for writing well-structured notes with observations and relations
|
|
112
|
-
|
|
113
|
-
Skills are loaded from the plugin's `skills/` directory. See the upstream source at [`basic-memory-skills`](https://github.com/basicmachines-co/basic-memory-skills).
|
|
114
|
-
|
|
115
|
-
#### Updating or adding skills with `npx skills`
|
|
116
|
-
|
|
117
|
-
You can update bundled skills or install new ones as they become available using the [Skills CLI](https://github.com/vercel-labs/skills):
|
|
53
|
+
Verify:
|
|
118
54
|
|
|
119
55
|
```bash
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# Install a specific skill
|
|
124
|
-
npx skills add basicmachines-co/basic-memory-skills --name memory-tasks --agent openclaw
|
|
56
|
+
openclaw plugins list
|
|
57
|
+
openclaw plugins info openclaw-basic-memory
|
|
125
58
|
```
|
|
126
59
|
|
|
127
|
-
This installs to the same `skills/` directory the plugin reads from, so updated skills take effect on the next session.
|
|
128
|
-
|
|
129
60
|
## Configuration
|
|
130
61
|
|
|
131
|
-
###
|
|
62
|
+
### Zero-config (recommended)
|
|
63
|
+
|
|
132
64
|
```json5
|
|
133
65
|
{
|
|
134
66
|
"openclaw-basic-memory": {
|
|
@@ -137,440 +69,180 @@ This installs to the same `skills/` directory the plugin reads from, so updated
|
|
|
137
69
|
}
|
|
138
70
|
```
|
|
139
71
|
|
|
140
|
-
This uses sensible defaults: auto-generated project name, maps
|
|
72
|
+
This uses sensible defaults: auto-generated project name, maps to your workspace root, captures conversations, and recalls active tasks on session start.
|
|
73
|
+
|
|
74
|
+
### Full options
|
|
141
75
|
|
|
142
|
-
### Full configuration
|
|
143
76
|
```json5
|
|
144
77
|
{
|
|
145
78
|
"openclaw-basic-memory": {
|
|
146
79
|
enabled: true,
|
|
147
80
|
config: {
|
|
148
|
-
project: "my-agent",
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
autoRecall: true, // Inject active tasks + recent activity at session start
|
|
156
|
-
recallPrompt: "Check for active tasks and recent activity. Summarize anything relevant to the current session.",
|
|
157
|
-
debug: false, // Verbose logging
|
|
81
|
+
project: "my-agent", // BM project name (default: "openclaw-{hostname}")
|
|
82
|
+
projectPath: ".", // Project directory (default: workspace root)
|
|
83
|
+
memoryDir: "memory/", // Where task notes live
|
|
84
|
+
memoryFile: "MEMORY.md", // Working memory file
|
|
85
|
+
autoCapture: true, // Record conversations as daily notes
|
|
86
|
+
autoRecall: true, // Inject active tasks + recent activity at session start
|
|
87
|
+
debug: false // Verbose logging
|
|
158
88
|
}
|
|
159
89
|
}
|
|
160
90
|
}
|
|
161
91
|
```
|
|
162
92
|
|
|
163
|
-
|
|
93
|
+
| Option | Default | Description |
|
|
94
|
+
|--------|---------|-------------|
|
|
95
|
+
| `project` | `"openclaw-{hostname}"` | Basic Memory project name |
|
|
96
|
+
| `bmPath` | `"bm"` | Path to BM CLI binary |
|
|
97
|
+
| `projectPath` | `"."` | Project data directory |
|
|
98
|
+
| `memoryDir` | `"memory/"` | Relative path for task scanning |
|
|
99
|
+
| `memoryFile` | `"MEMORY.md"` | Working memory file for text search |
|
|
100
|
+
| `autoCapture` | `true` | Auto-index agent conversations |
|
|
101
|
+
| `captureMinChars` | `10` | Min chars to trigger capture |
|
|
102
|
+
| `autoRecall` | `true` | Inject context at session start |
|
|
103
|
+
| `recallPrompt` | *(default)* | Instruction appended to recalled context |
|
|
104
|
+
| `debug` | `false` | Verbose logs |
|
|
164
105
|
|
|
165
|
-
|
|
166
|
-
|--------|------|---------|-------------|
|
|
167
|
-
| `project` | string | `"openclaw-{hostname}"` | Basic Memory project name |
|
|
168
|
-
| `bmPath` | string | `"bm"` | Path to Basic Memory CLI binary |
|
|
169
|
-
| `projectPath` | string | `"memory/"` | Directory for BM project data (resolved from workspace unless absolute) |
|
|
170
|
-
| `memoryDir` | string | `"memory/"` | Relative path for task scanning |
|
|
171
|
-
| `memoryFile` | string | `"MEMORY.md"` | Working memory file (grep-searched) |
|
|
172
|
-
| `autoCapture` | boolean | `true` | Auto-index agent conversations |
|
|
173
|
-
| `captureMinChars` | number | `10` | Minimum character threshold for auto-capture (both messages must be shorter to skip) |
|
|
174
|
-
| `autoRecall` | boolean | `true` | Inject active tasks and recent activity as context at session start |
|
|
175
|
-
| `recallPrompt` | string | *(see above)* | Instruction appended to recalled context — customize to change what the agent focuses on |
|
|
176
|
-
| `debug` | boolean | `false` | Enable verbose debug logs |
|
|
106
|
+
## How it works
|
|
177
107
|
|
|
178
|
-
|
|
108
|
+
### Memory search
|
|
179
109
|
|
|
180
|
-
|
|
110
|
+
When your agent calls `memory_search`, three sources are queried in parallel:
|
|
181
111
|
|
|
182
|
-
|
|
112
|
+
1. **MEMORY.md** — text search with surrounding context
|
|
113
|
+
2. **Knowledge Graph** — hybrid full-text + vector search across all indexed notes
|
|
114
|
+
3. **Active Tasks** — scans `memory/tasks/` for in-progress work
|
|
183
115
|
|
|
184
|
-
|
|
116
|
+
Results come back in clear sections so the agent knows where each piece of context came from.
|
|
185
117
|
|
|
186
|
-
###
|
|
187
|
-
On startup, the plugin starts one persistent MCP stdio session:
|
|
188
|
-
1. Spawns `bm mcp --transport stdio --project <name>`
|
|
189
|
-
2. Verifies required MCP tool capabilities at connect time
|
|
190
|
-
3. Uses bounded reconnect attempts (`500ms`, `1000ms`, `2000ms`) when the session drops
|
|
118
|
+
### Auto-recall
|
|
191
119
|
|
|
192
|
-
|
|
120
|
+
On each session start, the plugin loads active tasks and recently modified notes, giving the agent immediate awareness of ongoing work without being asked.
|
|
193
121
|
|
|
194
|
-
###
|
|
195
|
-
When the agent calls `memory_search`, three sources are queried in parallel:
|
|
122
|
+
### Auto-capture
|
|
196
123
|
|
|
197
|
-
|
|
198
|
-
2. **BM Knowledge Graph** — hybrid FTS + vector search (top 5 results with scores)
|
|
199
|
-
3. **Active Tasks** — scans `memory/tasks/` for non-done tasks
|
|
124
|
+
After each conversation turn, the plugin records the exchange as a timestamped entry in a daily note. This builds a searchable history of everything your agent has discussed.
|
|
200
125
|
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
## MEMORY.md
|
|
204
|
-
- matching lines with context...
|
|
205
|
-
|
|
206
|
-
## Knowledge Graph (memory/)
|
|
207
|
-
- note-title (0.85)
|
|
208
|
-
> preview of content...
|
|
209
|
-
|
|
210
|
-
## Active Tasks
|
|
211
|
-
- **Task Name** (status: active, step: 3)
|
|
212
|
-
context snippet...
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Memory + Task Management Flow
|
|
216
|
-
|
|
217
|
-
This plugin works best if you treat memory as three lanes:
|
|
218
|
-
|
|
219
|
-
1. **Working memory (`MEMORY.md`)** — short-horizon context and current focus.
|
|
220
|
-
2. **Knowledge graph (`memory/**/*.md`)** — long-term notes indexed by Basic Memory.
|
|
221
|
-
3. **Task notes (`memory/tasks/*.md`)** — active execution state for in-flight work.
|
|
222
|
-
|
|
223
|
-
> **Note:** OpenClaw's default convention treats `MEMORY.md` as [long-term curated memory](https://docs.openclaw.ai/concepts/memory). This plugin flips that role — the BM knowledge graph handles durable storage, so `MEMORY.md` serves as short-horizon working memory. See [MEMORY_TASK_FLOW.md](./MEMORY_TASK_FLOW.md) for details.
|
|
224
|
-
|
|
225
|
-
Typical loop:
|
|
226
|
-
|
|
227
|
-
1. Capture or update notes/tasks with `write_note` / `edit_note`.
|
|
228
|
-
2. The persistent BM MCP process syncs markdown updates into the BM project index.
|
|
229
|
-
3. `memory_search` queries:
|
|
230
|
-
- `MEMORY.md` text snippets
|
|
231
|
-
- BM search results (semantic + FTS)
|
|
232
|
-
- active tasks
|
|
233
|
-
4. Drill into one result with `memory_get` or `read_note`.
|
|
234
|
-
5. Advance tasks by updating `current_step`, checkboxes, and context.
|
|
235
|
-
6. Complete tasks by setting `status: done` (done tasks are excluded from active task results).
|
|
236
|
-
|
|
237
|
-
```mermaid
|
|
238
|
-
flowchart LR
|
|
239
|
-
A["Write/Update notes"] --> B["BM MCP indexes changes"]
|
|
240
|
-
B --> C["memory_search(query)"]
|
|
241
|
-
C --> D["MEMORY.md"]
|
|
242
|
-
C --> E["Knowledge Graph"]
|
|
243
|
-
C --> F["Active Tasks"]
|
|
244
|
-
D --> G["Composited result"]
|
|
245
|
-
E --> G
|
|
246
|
-
F --> G
|
|
247
|
-
G --> H["memory_get / read_note"]
|
|
248
|
-
H --> A
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### Task Note Shape (Recommended)
|
|
252
|
-
|
|
253
|
-
`memory_search` task extraction is strongest when task notes include:
|
|
254
|
-
|
|
255
|
-
- file location: `memory/tasks/*.md`
|
|
256
|
-
- frontmatter fields: `status:` and `current_step:`
|
|
257
|
-
- a `## Context` section for preview snippets
|
|
258
|
-
|
|
259
|
-
Example:
|
|
260
|
-
|
|
261
|
-
```markdown
|
|
262
|
-
---
|
|
263
|
-
title: auth-middleware-rollout
|
|
264
|
-
type: Task
|
|
265
|
-
status: active
|
|
266
|
-
current_step: 2
|
|
267
|
-
---
|
|
268
|
-
|
|
269
|
-
## Context
|
|
270
|
-
Rolling JWT middleware to all API routes. Staging verification is in progress.
|
|
271
|
-
|
|
272
|
-
## Plan
|
|
273
|
-
- [x] Implement middleware
|
|
274
|
-
- [x] Add refresh-token validation
|
|
275
|
-
- [ ] Roll out to staging
|
|
276
|
-
- [ ] Verify logs and error rates
|
|
277
|
-
```
|
|
126
|
+
### Persistent connection
|
|
278
127
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
```yaml
|
|
282
|
-
status: done
|
|
283
|
-
```
|
|
128
|
+
The plugin keeps a long-lived Basic Memory process running over standard I/O. No cold starts per tool call. The connection auto-reconnects if it drops.
|
|
284
129
|
|
|
285
|
-
|
|
130
|
+
## Agent tools
|
|
286
131
|
|
|
287
|
-
|
|
288
|
-
On each `agent_start` event (when `autoRecall: true`), the plugin:
|
|
289
|
-
1. Queries the knowledge graph for active tasks (`type: Task`, `status: active`, up to 5)
|
|
290
|
-
2. Fetches notes modified in the last 24 hours
|
|
291
|
-
3. Formats both into structured context and returns it to the agent
|
|
132
|
+
All tools accept an optional `project` parameter for cross-project operations.
|
|
292
133
|
|
|
293
|
-
|
|
134
|
+
| Tool | Description |
|
|
135
|
+
|------|-------------|
|
|
136
|
+
| `memory_search` | Composited search across all memory sources |
|
|
137
|
+
| `memory_get` | Read a specific note by title or path |
|
|
138
|
+
| `search_notes` | Search the knowledge graph directly |
|
|
139
|
+
| `read_note` | Read a note by title, permalink, or `memory://` URL |
|
|
140
|
+
| `write_note` | Create or update a note |
|
|
141
|
+
| `edit_note` | Append, prepend, find/replace, or replace a section |
|
|
142
|
+
| `delete_note` | Delete a note |
|
|
143
|
+
| `move_note` | Move a note to a different folder |
|
|
144
|
+
| `build_context` | Navigate the knowledge graph — follow relations and connections |
|
|
145
|
+
| `list_memory_projects` | List accessible projects |
|
|
146
|
+
| `list_workspaces` | List workspaces (personal and org) |
|
|
147
|
+
| `schema_validate` | Validate notes against Picoschema definitions |
|
|
148
|
+
| `schema_infer` | Analyze notes and suggest a schema |
|
|
149
|
+
| `schema_diff` | Detect drift between schema and actual usage |
|
|
294
150
|
|
|
295
|
-
|
|
296
|
-
After each agent turn (when `autoCapture: true`), the plugin:
|
|
297
|
-
1. Extracts the last user + assistant messages
|
|
298
|
-
2. Appends them as timestamped entries to a daily conversation note (`conversations-YYYY-MM-DD`)
|
|
299
|
-
3. Skips very short exchanges (< `captureMinChars` chars each, default 10)
|
|
300
|
-
|
|
301
|
-
## Agent Tools
|
|
302
|
-
|
|
303
|
-
All content tools accept an optional `project` parameter to operate on a different project than the default (cross-project operations).
|
|
304
|
-
|
|
305
|
-
### `list_workspaces`
|
|
306
|
-
List all workspaces (personal and organization) accessible to this user.
|
|
307
|
-
```
|
|
308
|
-
list_workspaces()
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
### `list_memory_projects`
|
|
312
|
-
List all projects, optionally filtered by workspace.
|
|
313
|
-
```
|
|
314
|
-
list_memory_projects()
|
|
315
|
-
list_memory_projects(workspace="my-org")
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
### `search_notes`
|
|
319
|
-
Search the knowledge graph.
|
|
320
|
-
```
|
|
321
|
-
search_notes(query="API design", limit=5)
|
|
322
|
-
search_notes(query="API design", project="other-project") # cross-project
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### `read_note`
|
|
326
|
-
Read a note by title, permalink, or `memory://` URL.
|
|
327
|
-
```
|
|
328
|
-
read_note(identifier="memory://projects/api-redesign")
|
|
329
|
-
read_note(identifier="memory://projects/api-redesign", include_frontmatter=true) # raw markdown + YAML
|
|
330
|
-
read_note(identifier="notes/readme", project="docs") # cross-project
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
### `write_note`
|
|
334
|
-
Create a new note.
|
|
335
|
-
```
|
|
336
|
-
write_note(title="Auth Strategy", content="## Overview\n...", folder="decisions")
|
|
337
|
-
write_note(title="Shared Note", content="...", folder="shared", project="team") # cross-project
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### `edit_note`
|
|
341
|
-
Edit an existing note (`append`, `prepend`, `find_replace`, `replace_section`).
|
|
342
|
-
```
|
|
343
|
-
edit_note(identifier="weekly-review", operation="append", content="\n## Update\nDone.")
|
|
344
|
-
edit_note(
|
|
345
|
-
identifier="weekly-review",
|
|
346
|
-
operation="find_replace",
|
|
347
|
-
find_text="status: active",
|
|
348
|
-
content="status: done",
|
|
349
|
-
expected_replacements=1,
|
|
350
|
-
)
|
|
351
|
-
edit_note(
|
|
352
|
-
identifier="weekly-review",
|
|
353
|
-
operation="replace_section",
|
|
354
|
-
section="## This Week",
|
|
355
|
-
content="- Done\n- Next",
|
|
356
|
-
)
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
### `delete_note`
|
|
360
|
-
Delete a note.
|
|
361
|
-
```
|
|
362
|
-
delete_note(identifier="notes/old-draft")
|
|
363
|
-
delete_note(identifier="notes/old-draft", project="archive") # cross-project
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### `move_note`
|
|
367
|
-
Move a note to a different folder.
|
|
368
|
-
```
|
|
369
|
-
move_note(identifier="notes/my-note", newFolder="archive")
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### `build_context`
|
|
373
|
-
Navigate the knowledge graph — get a note with its observations and relations.
|
|
374
|
-
```
|
|
375
|
-
build_context(url="memory://projects/api-redesign", depth=2)
|
|
376
|
-
build_context(url="memory://decisions", depth=1, project="team") # cross-project
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### `schema_validate`
|
|
380
|
-
Validate notes against their Picoschema definitions.
|
|
381
|
-
```
|
|
382
|
-
schema_validate(noteType="person")
|
|
383
|
-
schema_validate(identifier="notes/john-doe")
|
|
384
|
-
schema_validate(noteType="person", project="contacts") # cross-project
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
### `schema_infer`
|
|
388
|
-
Analyze existing notes and suggest a Picoschema definition.
|
|
389
|
-
```
|
|
390
|
-
schema_infer(noteType="meeting")
|
|
391
|
-
schema_infer(noteType="person", threshold=0.5)
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
### `schema_diff`
|
|
395
|
-
Detect drift between a schema definition and actual note usage.
|
|
396
|
-
```
|
|
397
|
-
schema_diff(noteType="person")
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
## Slash Commands
|
|
401
|
-
|
|
402
|
-
### Memory
|
|
403
|
-
- **`/remember <text>`** — Save a quick note to the knowledge graph
|
|
404
|
-
- **`/recall <query>`** — Search the knowledge graph (top 5 results)
|
|
405
|
-
|
|
406
|
-
### Skill workflows
|
|
407
|
-
These inject step-by-step instructions from the bundled skill files. Each accepts optional arguments for context.
|
|
151
|
+
## Slash commands
|
|
408
152
|
|
|
409
153
|
| Command | Description |
|
|
410
154
|
|---------|-------------|
|
|
411
|
-
| `/
|
|
412
|
-
| `/
|
|
413
|
-
| `/
|
|
414
|
-
| `/
|
|
155
|
+
| `/remember <text>` | Save a quick note |
|
|
156
|
+
| `/recall <query>` | Search the knowledge graph |
|
|
157
|
+
| `/tasks [args]` | Create, track, resume structured tasks |
|
|
158
|
+
| `/reflect [args]` | Consolidate recent notes into long-term memory |
|
|
159
|
+
| `/defrag [args]` | Reorganize and clean up memory files |
|
|
160
|
+
| `/schema [args]` | Manage Picoschema definitions |
|
|
415
161
|
|
|
416
|
-
|
|
417
|
-
```
|
|
418
|
-
/tasks create a task for the API migration
|
|
419
|
-
/reflect
|
|
420
|
-
/defrag clean up completed tasks older than 2 weeks
|
|
421
|
-
/schema infer a schema for Meeting notes
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
## CLI Commands
|
|
162
|
+
## CLI
|
|
425
163
|
|
|
426
164
|
```bash
|
|
427
165
|
openclaw basic-memory search "auth patterns" --limit 5
|
|
428
166
|
openclaw basic-memory read "projects/api-redesign"
|
|
429
|
-
openclaw basic-memory read "projects/api-redesign" --raw
|
|
430
|
-
openclaw basic-memory edit "projects/api-redesign" --operation append --content $'\n## Update\nDone.'
|
|
431
167
|
openclaw basic-memory context "memory://projects/api-redesign" --depth 2
|
|
432
168
|
openclaw basic-memory recent --timeframe 24h
|
|
433
169
|
openclaw basic-memory status
|
|
434
170
|
```
|
|
435
171
|
|
|
436
|
-
##
|
|
437
|
-
|
|
438
|
-
### `bm` command not found
|
|
439
|
-
```bash
|
|
440
|
-
which bm # Check if installed
|
|
441
|
-
bm --version # Check version
|
|
442
|
-
bm mcp --help # Verify MCP server command exists
|
|
443
|
-
```
|
|
444
|
-
If `bm mcp` doesn't exist, update Basic Memory to a newer version.
|
|
445
|
-
|
|
446
|
-
### `edit_note` says `edit-note` is required
|
|
447
|
-
Your installed `basic-memory` version is missing native `tool edit-note`.
|
|
448
|
-
Upgrade `basic-memory` and rerun.
|
|
449
|
-
|
|
450
|
-
### Jiti cache issues
|
|
451
|
-
```bash
|
|
452
|
-
rm -rf /tmp/jiti/ "$TMPDIR/jiti/"
|
|
453
|
-
openclaw gateway stop && openclaw gateway start
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
### Search returns no results
|
|
457
|
-
1. Check that the MCP session is connected (look for `connected to BM MCP stdio` in logs)
|
|
458
|
-
2. Verify files exist in the project directory
|
|
459
|
-
3. Try `bm mcp --transport stdio --project <name>` and run `search_notes` through an MCP inspector/client
|
|
460
|
-
4. Check project status: `bm project list`
|
|
461
|
-
|
|
462
|
-
## Integration Tests
|
|
463
|
-
|
|
464
|
-
This repo includes real end-to-end integration tests for `BmClient` in:
|
|
172
|
+
## Bundled skills
|
|
465
173
|
|
|
466
|
-
|
|
174
|
+
Six skills ship with the plugin — no installation needed:
|
|
467
175
|
|
|
468
|
-
|
|
469
|
-
|
|
176
|
+
- **memory-tasks** — structured task tracking that survives context compaction
|
|
177
|
+
- **memory-reflect** — periodic consolidation of recent notes into durable memory
|
|
178
|
+
- **memory-defrag** — cleanup and reorganization of memory files
|
|
179
|
+
- **memory-schema** — schema lifecycle (infer, create, validate, diff)
|
|
180
|
+
- **memory-metadata-search** — query notes by frontmatter fields
|
|
181
|
+
- **memory-notes** — guidance for writing well-structured notes
|
|
470
182
|
|
|
471
|
-
|
|
183
|
+
### Updating skills
|
|
472
184
|
|
|
473
185
|
```bash
|
|
474
|
-
|
|
186
|
+
npx skills add basicmachines-co/basic-memory-skills --agent openclaw
|
|
475
187
|
```
|
|
476
188
|
|
|
477
|
-
|
|
478
|
-
`../basic-memory` checkout via `uv run --project ...` when present, and falls
|
|
479
|
-
back to `bm` on `PATH` otherwise.
|
|
189
|
+
## Task notes
|
|
480
190
|
|
|
481
|
-
|
|
191
|
+
The plugin works well with structured task notes in `memory/tasks/`:
|
|
482
192
|
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
193
|
+
```markdown
|
|
194
|
+
---
|
|
195
|
+
title: auth-middleware-rollout
|
|
196
|
+
type: Task
|
|
197
|
+
status: active
|
|
198
|
+
current_step: 2
|
|
199
|
+
---
|
|
490
200
|
|
|
491
|
-
##
|
|
201
|
+
## Context
|
|
202
|
+
Rolling JWT middleware to all API routes.
|
|
492
203
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
204
|
+
## Plan
|
|
205
|
+
- [x] Implement middleware
|
|
206
|
+
- [x] Add refresh-token validation
|
|
207
|
+
- [ ] Roll out to staging
|
|
208
|
+
- [ ] Verify logs and error rates
|
|
498
209
|
```
|
|
499
210
|
|
|
500
|
-
|
|
211
|
+
Set `status: done` to mark complete. Done tasks are filtered out of active task results.
|
|
501
212
|
|
|
502
|
-
|
|
213
|
+
## Basic Memory Cloud
|
|
503
214
|
|
|
504
|
-
|
|
505
|
-
# 1) Verify release readiness (types + tests + npm pack dry run)
|
|
506
|
-
just release-check
|
|
215
|
+
Everything works locally. Cloud adds cross-device sync, team workspaces, and persistent memory for hosted agents.
|
|
507
216
|
|
|
508
|
-
|
|
509
|
-
|
|
217
|
+
- Same knowledge graph on laptop, desktop, and CI
|
|
218
|
+
- Shared workspaces for teams
|
|
219
|
+
- Durable memory for production agents
|
|
510
220
|
|
|
511
|
-
|
|
512
|
-
npm login
|
|
513
|
-
|
|
514
|
-
# 4) Publish current version from package.json
|
|
515
|
-
just release-publish
|
|
516
|
-
```
|
|
221
|
+
Cloud extends local-first — still plain Markdown, still yours. [Start a free trial](https://basicmemory.com) and use code `BMCLAW` for 20% off for 3 months. See [BASIC_MEMORY.md](./BASIC_MEMORY.md) for setup.
|
|
517
222
|
|
|
518
|
-
|
|
223
|
+
## Troubleshooting
|
|
519
224
|
|
|
520
|
-
|
|
521
|
-
just release patch # or: minor, major, 0.2.0, etc.
|
|
522
|
-
```
|
|
225
|
+
**`bm` not found** — Install uv, then restart the gateway. Or install manually: `uv tool install basic-memory`
|
|
523
226
|
|
|
524
|
-
|
|
227
|
+
**Search returns nothing** — Check that Basic Memory connected (look for `connected to BM` in logs). Verify files exist in the project directory.
|
|
525
228
|
|
|
526
|
-
|
|
527
|
-
- Release workflow: `.github/workflows/release.yml` runs manually (`workflow_dispatch`) and will:
|
|
528
|
-
1. run release checks
|
|
529
|
-
2. bump version and create a git tag
|
|
530
|
-
3. push commit + tag
|
|
531
|
-
4. publish to npm
|
|
532
|
-
5. create a GitHub release
|
|
229
|
+
**Jiti cache issues** — `rm -rf /tmp/jiti/ "$TMPDIR/jiti/"` then restart the gateway.
|
|
533
230
|
|
|
534
|
-
|
|
231
|
+
**Disable semantic search** — Set `BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED=false` to fall back to full-text only.
|
|
535
232
|
|
|
536
|
-
|
|
233
|
+
## More
|
|
537
234
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
├── tools/ # Agent tools
|
|
545
|
-
│ ├── search-notes.ts # search_notes
|
|
546
|
-
│ ├── read-note.ts # read_note
|
|
547
|
-
│ ├── write-note.ts # write_note
|
|
548
|
-
│ ├── edit-note.ts # edit_note
|
|
549
|
-
│ ├── delete-note.ts # delete_note
|
|
550
|
-
│ ├── move-note.ts # move_note
|
|
551
|
-
│ ├── build-context.ts # build_context
|
|
552
|
-
│ ├── list-memory-projects.ts # list_memory_projects
|
|
553
|
-
│ ├── list-workspaces.ts # list_workspaces
|
|
554
|
-
│ ├── schema-validate.ts # schema_validate
|
|
555
|
-
│ ├── schema-infer.ts # schema_infer
|
|
556
|
-
│ ├── schema-diff.ts # schema_diff
|
|
557
|
-
│ └── memory-provider.ts # Composited memory_search + memory_get
|
|
558
|
-
├── commands/
|
|
559
|
-
│ ├── slash.ts # /remember, /recall
|
|
560
|
-
│ ├── skills.ts # /tasks, /reflect, /defrag, /schema
|
|
561
|
-
│ └── cli.ts # openclaw basic-memory CLI
|
|
562
|
-
└── hooks/
|
|
563
|
-
├── capture.ts # Auto-capture conversations
|
|
564
|
-
└── recall.ts # Auto-recall (active tasks + recent activity)
|
|
565
|
-
```
|
|
235
|
+
- [Memory + Task Flow](./MEMORY_TASK_FLOW.md) — practical runbook
|
|
236
|
+
- [Cloud Setup](./BASIC_MEMORY.md) — configure Basic Memory Cloud
|
|
237
|
+
- [Security](./SECURITY.md) — how auto-installation and data handling work
|
|
238
|
+
- [Development](./DEVELOPMENT.md) — contributing, tests, publishing
|
|
239
|
+
- [Basic Memory docs](https://docs.basicmemory.com)
|
|
240
|
+
- [Issues](https://github.com/basicmachines-co/openclaw-basic-memory/issues)
|
|
566
241
|
|
|
567
|
-
##
|
|
242
|
+
## Telemetry
|
|
568
243
|
|
|
569
|
-
|
|
244
|
+
This plugin does not collect telemetry. The Basic Memory CLI may send anonymous usage analytics — see the [Basic Memory docs](https://github.com/basicmachines-co/basic-memory) for opt-out instructions.
|
|
570
245
|
|
|
571
|
-
##
|
|
246
|
+
## License
|
|
572
247
|
|
|
573
|
-
|
|
574
|
-
- [Basic Memory Skills](https://github.com/basicmachines-co/basic-memory-skills)
|
|
575
|
-
- [OpenClaw](https://docs.openclaw.ai)
|
|
576
|
-
- [Issues](https://github.com/basicmachines-co/openclaw-basic-memory/issues)
|
|
248
|
+
MIT
|
package/bm-client.ts
CHANGED
|
@@ -196,7 +196,7 @@ function isRecoverableConnectionError(err: unknown): boolean {
|
|
|
196
196
|
)
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
function
|
|
199
|
+
function _isNoteNotFoundError(err: unknown): boolean {
|
|
200
200
|
const msg = getErrorMessage(err).toLowerCase()
|
|
201
201
|
return (
|
|
202
202
|
msg.includes("entity not found") ||
|
|
@@ -659,11 +659,12 @@ export class BmClient {
|
|
|
659
659
|
identifier,
|
|
660
660
|
operation,
|
|
661
661
|
content,
|
|
662
|
-
find_text: options.find_text,
|
|
663
|
-
section: options.section,
|
|
664
|
-
expected_replacements: options.expected_replacements,
|
|
665
662
|
output_format: "json",
|
|
666
663
|
}
|
|
664
|
+
if (options.find_text) args.find_text = options.find_text
|
|
665
|
+
if (options.section) args.section = options.section
|
|
666
|
+
if (options.expected_replacements != null)
|
|
667
|
+
args.expected_replacements = options.expected_replacements
|
|
667
668
|
if (project) args.project = project
|
|
668
669
|
|
|
669
670
|
const payload = await this.callTool("edit_note", args)
|
|
@@ -829,10 +830,6 @@ export class BmClient {
|
|
|
829
830
|
return payload as unknown as MetadataSearchResult
|
|
830
831
|
}
|
|
831
832
|
|
|
832
|
-
private isNoteNotFoundError(err: unknown): boolean {
|
|
833
|
-
return isNoteNotFoundError(err)
|
|
834
|
-
}
|
|
835
|
-
|
|
836
833
|
async indexConversation(
|
|
837
834
|
userMessage: string,
|
|
838
835
|
assistantResponse: string,
|
|
@@ -854,22 +851,33 @@ export class BmClient {
|
|
|
854
851
|
"---",
|
|
855
852
|
].join("\n")
|
|
856
853
|
|
|
854
|
+
// Try append first — if it fails for ANY reason, fall through to create
|
|
857
855
|
try {
|
|
858
856
|
await this.editNote(title, "append", entry)
|
|
859
857
|
log.debug(`appended conversation to: ${title}`)
|
|
858
|
+
return
|
|
860
859
|
} catch (err) {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
return
|
|
864
|
-
}
|
|
860
|
+
log.debug(`append failed, will create: ${getErrorMessage(err)}`)
|
|
861
|
+
}
|
|
865
862
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
863
|
+
// Create the note with frontmatter and first entry
|
|
864
|
+
const content = [
|
|
865
|
+
"---",
|
|
866
|
+
`title: Conversations ${dateStr}`,
|
|
867
|
+
"type: Conversation",
|
|
868
|
+
`date: "${dateStr}"`,
|
|
869
|
+
"---",
|
|
870
|
+
"",
|
|
871
|
+
`# Conversations ${dateStr}`,
|
|
872
|
+
"",
|
|
873
|
+
entry,
|
|
874
|
+
].join("\n")
|
|
875
|
+
|
|
876
|
+
try {
|
|
877
|
+
await this.writeNote(title, content, "conversations")
|
|
878
|
+
log.debug(`created conversation note: ${title}`)
|
|
879
|
+
} catch (err) {
|
|
880
|
+
log.error("conversation index failed", err)
|
|
873
881
|
}
|
|
874
882
|
}
|
|
875
883
|
|
package/config.ts
CHANGED
|
@@ -6,11 +6,6 @@ export type CloudConfig = {
|
|
|
6
6
|
api_key: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export type DashboardConfig = {
|
|
10
|
-
enabled: boolean
|
|
11
|
-
port: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
9
|
export type BasicMemoryConfig = {
|
|
15
10
|
project: string
|
|
16
11
|
bmPath: string
|
|
@@ -23,7 +18,6 @@ export type BasicMemoryConfig = {
|
|
|
23
18
|
recallPrompt: string
|
|
24
19
|
debug: boolean
|
|
25
20
|
cloud?: CloudConfig
|
|
26
|
-
dashboard: DashboardConfig
|
|
27
21
|
}
|
|
28
22
|
|
|
29
23
|
const ALLOWED_KEYS = [
|
|
@@ -43,7 +37,6 @@ const ALLOWED_KEYS = [
|
|
|
43
37
|
"recall_prompt",
|
|
44
38
|
"debug",
|
|
45
39
|
"cloud",
|
|
46
|
-
"dashboard",
|
|
47
40
|
]
|
|
48
41
|
|
|
49
42
|
function assertAllowedKeys(
|
|
@@ -113,22 +106,6 @@ export function parseConfig(raw: unknown): BasicMemoryConfig {
|
|
|
113
106
|
}
|
|
114
107
|
}
|
|
115
108
|
|
|
116
|
-
let dashboard: DashboardConfig = { enabled: false, port: 3838 }
|
|
117
|
-
if (
|
|
118
|
-
cfg.dashboard &&
|
|
119
|
-
typeof cfg.dashboard === "object" &&
|
|
120
|
-
!Array.isArray(cfg.dashboard)
|
|
121
|
-
) {
|
|
122
|
-
const d = cfg.dashboard as Record<string, unknown>
|
|
123
|
-
dashboard = {
|
|
124
|
-
enabled: typeof d.enabled === "boolean" ? d.enabled : false,
|
|
125
|
-
port:
|
|
126
|
-
typeof d.port === "number" && d.port > 0 && d.port < 65536
|
|
127
|
-
? d.port
|
|
128
|
-
: 3838,
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
109
|
return {
|
|
133
110
|
project:
|
|
134
111
|
typeof cfg.project === "string" && cfg.project.length > 0
|
|
@@ -137,7 +114,7 @@ export function parseConfig(raw: unknown): BasicMemoryConfig {
|
|
|
137
114
|
projectPath:
|
|
138
115
|
typeof cfg.projectPath === "string" && cfg.projectPath.length > 0
|
|
139
116
|
? cfg.projectPath
|
|
140
|
-
:
|
|
117
|
+
: ".",
|
|
141
118
|
bmPath:
|
|
142
119
|
typeof cfg.bmPath === "string" && cfg.bmPath.length > 0
|
|
143
120
|
? cfg.bmPath
|
|
@@ -167,7 +144,6 @@ export function parseConfig(raw: unknown): BasicMemoryConfig {
|
|
|
167
144
|
: "Check for active tasks and recent activity. Summarize anything relevant to the current session.",
|
|
168
145
|
debug: typeof cfg.debug === "boolean" ? cfg.debug : false,
|
|
169
146
|
cloud,
|
|
170
|
-
dashboard,
|
|
171
147
|
}
|
|
172
148
|
}
|
|
173
149
|
|
package/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { execSync } from "node:child_process"
|
|
2
|
+
|
|
2
3
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk"
|
|
3
4
|
import { BmClient } from "./bm-client.ts"
|
|
4
5
|
import { registerCli } from "./commands/cli.ts"
|
|
@@ -9,10 +10,11 @@ import {
|
|
|
9
10
|
parseConfig,
|
|
10
11
|
resolveProjectPath,
|
|
11
12
|
} from "./config.ts"
|
|
12
|
-
|
|
13
|
+
|
|
13
14
|
import { buildCaptureHandler } from "./hooks/capture.ts"
|
|
14
15
|
import { buildRecallHandler } from "./hooks/recall.ts"
|
|
15
16
|
import { initLogger, log } from "./logger.ts"
|
|
17
|
+
import { CONVERSATION_SCHEMA_CONTENT } from "./schema/conversation-schema.ts"
|
|
16
18
|
import { TASK_SCHEMA_CONTENT } from "./schema/task-schema.ts"
|
|
17
19
|
import { registerContextTool } from "./tools/build-context.ts"
|
|
18
20
|
import { registerDeleteTool } from "./tools/delete-note.ts"
|
|
@@ -82,13 +84,47 @@ export default {
|
|
|
82
84
|
registerCli(api, client, cfg)
|
|
83
85
|
|
|
84
86
|
// --- Service lifecycle ---
|
|
85
|
-
let dashboardServer: Server | undefined
|
|
86
|
-
|
|
87
87
|
api.registerService({
|
|
88
88
|
id: "openclaw-basic-memory",
|
|
89
89
|
start: async (ctx: { config?: unknown; workspaceDir?: string }) => {
|
|
90
90
|
log.info("starting...")
|
|
91
91
|
|
|
92
|
+
// Auto-install bm CLI if not found
|
|
93
|
+
const bmBin = cfg.bmPath || "bm"
|
|
94
|
+
try {
|
|
95
|
+
execSync(`command -v ${bmBin}`, { stdio: "ignore" })
|
|
96
|
+
} catch {
|
|
97
|
+
log.info("bm CLI not found on PATH — attempting auto-install...")
|
|
98
|
+
try {
|
|
99
|
+
execSync("command -v uv", { stdio: "ignore" })
|
|
100
|
+
log.info(
|
|
101
|
+
"installing basic-memory via uv (this may take a minute)...",
|
|
102
|
+
)
|
|
103
|
+
const result = execSync(
|
|
104
|
+
'uv tool install "basic-memory @ git+https://github.com/basicmachines-co/basic-memory.git@main" --force',
|
|
105
|
+
{ encoding: "utf-8", timeout: 120_000, stdio: "pipe" },
|
|
106
|
+
)
|
|
107
|
+
log.info(
|
|
108
|
+
`basic-memory installed: ${result.trim().split("\n").pop()}`,
|
|
109
|
+
)
|
|
110
|
+
// Verify it worked
|
|
111
|
+
try {
|
|
112
|
+
execSync(`command -v ${bmBin}`, { stdio: "ignore" })
|
|
113
|
+
log.info("bm CLI now available on PATH")
|
|
114
|
+
} catch {
|
|
115
|
+
log.error(
|
|
116
|
+
"bm installed but not found on PATH. You may need to add uv's bin directory to your PATH (typically ~/.local/bin).",
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
} catch (_uvErr) {
|
|
120
|
+
log.error(
|
|
121
|
+
"Cannot auto-install basic-memory: uv not found. " +
|
|
122
|
+
"Install uv first (brew install uv, or curl -LsSf https://astral.sh/uv/install.sh | sh), " +
|
|
123
|
+
"then restart the gateway.",
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
92
128
|
const workspace = ctx.workspaceDir ?? process.cwd()
|
|
93
129
|
const projectPath = resolveProjectPath(cfg.projectPath, workspace)
|
|
94
130
|
cfg.projectPath = projectPath
|
|
@@ -97,45 +133,30 @@ export default {
|
|
|
97
133
|
await client.ensureProject(projectPath)
|
|
98
134
|
log.debug(`project "${cfg.project}" at ${projectPath}`)
|
|
99
135
|
|
|
100
|
-
// Seed
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
136
|
+
// Seed schemas if not already present
|
|
137
|
+
for (const [name, content] of [
|
|
138
|
+
["Task", TASK_SCHEMA_CONTENT],
|
|
139
|
+
["Conversation", CONVERSATION_SCHEMA_CONTENT],
|
|
140
|
+
] as const) {
|
|
105
141
|
try {
|
|
106
|
-
await client.
|
|
107
|
-
log.debug(
|
|
108
|
-
} catch
|
|
109
|
-
|
|
142
|
+
await client.readNote(`schema/${name}`)
|
|
143
|
+
log.debug(`${name} schema already exists, skipping seed`)
|
|
144
|
+
} catch {
|
|
145
|
+
try {
|
|
146
|
+
await client.writeNote(name, content, "schema")
|
|
147
|
+
log.debug(`seeded ${name} schema note`)
|
|
148
|
+
} catch (err) {
|
|
149
|
+
log.debug(`${name} schema seed failed (non-fatal)`, err)
|
|
150
|
+
}
|
|
110
151
|
}
|
|
111
152
|
}
|
|
112
153
|
|
|
113
154
|
setWorkspaceDir(workspace)
|
|
114
155
|
|
|
115
|
-
// Start dashboard if enabled
|
|
116
|
-
if (cfg.dashboard.enabled) {
|
|
117
|
-
dashboardServer = createDashboardServer({
|
|
118
|
-
port: cfg.dashboard.port,
|
|
119
|
-
client,
|
|
120
|
-
})
|
|
121
|
-
dashboardServer.listen(cfg.dashboard.port, () => {
|
|
122
|
-
log.info(
|
|
123
|
-
`dashboard running at http://localhost:${cfg.dashboard.port}`,
|
|
124
|
-
)
|
|
125
|
-
})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
156
|
log.info("connected — BM MCP stdio session running")
|
|
129
157
|
},
|
|
130
158
|
stop: async () => {
|
|
131
159
|
log.info("stopping BM MCP session...")
|
|
132
|
-
if (dashboardServer) {
|
|
133
|
-
await new Promise<void>((resolve) =>
|
|
134
|
-
dashboardServer?.close(() => resolve()),
|
|
135
|
-
)
|
|
136
|
-
dashboardServer = undefined
|
|
137
|
-
log.info("dashboard stopped")
|
|
138
|
-
}
|
|
139
160
|
await client.stop()
|
|
140
161
|
log.info("stopped")
|
|
141
162
|
},
|
package/openclaw.plugin.json
CHANGED
|
@@ -48,19 +48,14 @@
|
|
|
48
48
|
},
|
|
49
49
|
"projectPath": {
|
|
50
50
|
"label": "Project Path",
|
|
51
|
-
"placeholder": "
|
|
52
|
-
"help": "Filesystem path for Basic Memory project data (relative paths resolve from workspace)
|
|
51
|
+
"placeholder": ".",
|
|
52
|
+
"help": "Filesystem path for Basic Memory project data (defaults to workspace root; relative paths resolve from workspace)",
|
|
53
53
|
"advanced": true
|
|
54
54
|
},
|
|
55
55
|
"cloud": {
|
|
56
56
|
"label": "Cloud Backend",
|
|
57
57
|
"help": "Optional cloud backend config (url + api_key). If present, uses cloud instead of local BM.",
|
|
58
58
|
"advanced": true
|
|
59
|
-
},
|
|
60
|
-
"dashboard": {
|
|
61
|
-
"label": "Dashboard",
|
|
62
|
-
"help": "Web dashboard for visualizing the knowledge graph (enabled, port)",
|
|
63
|
-
"advanced": true
|
|
64
59
|
}
|
|
65
60
|
},
|
|
66
61
|
"configSchema": {
|
|
@@ -81,13 +76,6 @@
|
|
|
81
76
|
"url": { "type": "string" },
|
|
82
77
|
"api_key": { "type": "string" }
|
|
83
78
|
}
|
|
84
|
-
},
|
|
85
|
-
"dashboard": {
|
|
86
|
-
"type": "object",
|
|
87
|
-
"properties": {
|
|
88
|
-
"enabled": { "type": "boolean" },
|
|
89
|
-
"port": { "type": "number", "minimum": 1, "maximum": 65535 }
|
|
90
|
-
}
|
|
91
79
|
}
|
|
92
80
|
},
|
|
93
81
|
"required": []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basicmemory/openclaw-basic-memory",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Basic Memory plugin for OpenClaw — local-first knowledge graph for agent memory",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"tools/write-note.ts",
|
|
34
34
|
"types/openclaw.d.ts",
|
|
35
35
|
"schema/task-schema.ts",
|
|
36
|
+
"schema/conversation-schema.ts",
|
|
36
37
|
"skills/",
|
|
37
38
|
"scripts/setup-bm.sh",
|
|
38
39
|
"openclaw.plugin.json",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical Conversation schema note content, seeded into new projects on first startup.
|
|
3
|
+
* If the schema already exists (user may have customized it), seeding is skipped.
|
|
4
|
+
*/
|
|
5
|
+
export const CONVERSATION_SCHEMA_CONTENT = `---
|
|
6
|
+
title: Conversation
|
|
7
|
+
type: schema
|
|
8
|
+
entity: Conversation
|
|
9
|
+
version: 1
|
|
10
|
+
schema:
|
|
11
|
+
date: "string, ISO date YYYY-MM-DD"
|
|
12
|
+
session_id?: "string, unique session identifier"
|
|
13
|
+
channel?: "string, where the conversation happened (webchat, telegram, discord, etc)"
|
|
14
|
+
participants?: "array, who was in the conversation"
|
|
15
|
+
topic?: "string, brief description of main topic"
|
|
16
|
+
summary?: "string, one-paragraph summary of key points"
|
|
17
|
+
key_decisions?: "array, decisions made during conversation"
|
|
18
|
+
action_items?: "array, things to do as a result"
|
|
19
|
+
settings:
|
|
20
|
+
validation: warn
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Conversation
|
|
24
|
+
|
|
25
|
+
A record of a conversation session between the agent and user(s).
|
|
26
|
+
|
|
27
|
+
## Observations
|
|
28
|
+
- [convention] Conversation files live in memory/conversations/ with format conversations-YYYY-MM-DD.md
|
|
29
|
+
- [convention] Messages are appended as the conversation progresses
|
|
30
|
+
- [convention] Summary and key_decisions populated at session end or by memory-reflect
|
|
31
|
+
- [convention] Skip routine greetings, heartbeat acks, and tool call details
|
|
32
|
+
- [convention] Focus on decisions, actions taken, and key context needed for continuity
|
|
33
|
+
`
|
package/scripts/setup-bm.sh
CHANGED
|
@@ -15,11 +15,10 @@ if ! command -v uv >/dev/null 2>&1; then
|
|
|
15
15
|
exit 0
|
|
16
16
|
fi
|
|
17
17
|
|
|
18
|
-
# ── install basic-memory
|
|
18
|
+
# ── install basic-memory ────────────────────────────────
|
|
19
19
|
echo "Installing basic-memory from ${BM_REPO}@${BM_REF} ..."
|
|
20
20
|
uv tool install \
|
|
21
|
-
"basic-memory
|
|
22
|
-
--with 'onnxruntime<1.24; platform_system == "Darwin" and platform_machine == "x86_64"' \
|
|
21
|
+
"basic-memory @ git+${BM_REPO}@${BM_REF}" \
|
|
23
22
|
--force
|
|
24
23
|
|
|
25
24
|
# ── verify ────────────────────────────────────────────────────────
|