@basicmemory/openclaw-basic-memory 0.24.0 → 1.0.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 +24 -12
- package/bm-client.ts +302 -112
- package/commands/cli.ts +5 -6
- package/commands/slash.ts +4 -4
- package/context-engine/basic-memory-context-engine.ts +74 -9
- package/context-engine/types.ts +21 -0
- package/dist/bm-client.d.ts +61 -12
- package/dist/bm-client.js +250 -101
- package/dist/commands/cli.d.ts +1 -1
- package/dist/commands/cli.js +5 -5
- package/dist/commands/slash.d.ts +1 -1
- package/dist/commands/slash.js +4 -3
- package/dist/context-engine/basic-memory-context-engine.d.ts +20 -1
- package/dist/context-engine/basic-memory-context-engine.js +50 -2
- package/dist/context-engine/types.d.ts +9 -0
- package/dist/context-engine/types.js +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.js +79 -69
- package/dist/memory/basic-memory-capability.d.ts +19 -0
- package/dist/memory/basic-memory-capability.js +190 -0
- package/dist/tools/build-context.d.ts +1 -1
- package/dist/tools/build-context.js +12 -4
- package/dist/tools/delete-note.d.ts +1 -1
- package/dist/tools/delete-note.js +2 -1
- package/dist/tools/edit-note.d.ts +1 -1
- package/dist/tools/edit-note.js +22 -12
- package/dist/tools/list-memory-projects.d.ts +1 -1
- package/dist/tools/list-memory-projects.js +2 -1
- package/dist/tools/list-workspaces.d.ts +1 -1
- package/dist/tools/list-workspaces.js +4 -4
- package/dist/tools/move-note.d.ts +1 -1
- package/dist/tools/move-note.js +2 -1
- package/dist/tools/read-note.d.ts +1 -1
- package/dist/tools/read-note.js +2 -1
- package/dist/tools/schema-diff.d.ts +1 -1
- package/dist/tools/schema-diff.js +2 -1
- package/dist/tools/schema-infer.d.ts +1 -1
- package/dist/tools/schema-infer.js +2 -1
- package/dist/tools/schema-validate.d.ts +1 -1
- package/dist/tools/schema-validate.js +2 -1
- package/dist/tools/search-notes.d.ts +1 -1
- package/dist/tools/search-notes.js +13 -6
- package/dist/tools/write-note.d.ts +1 -1
- package/dist/tools/write-note.js +11 -12
- package/index.ts +93 -84
- package/memory/basic-memory-capability.ts +253 -0
- package/openclaw.plugin.json +0 -2
- package/package.json +6 -5
- package/skills/manifest.json +5 -0
- package/skills/memory-agents/SKILL.md +23 -10
- package/skills/memory-capture/SKILL.md +29 -18
- package/skills/memory-comark/SKILL.md +17 -6
- package/skills/memory-continue/SKILL.md +47 -27
- package/skills/memory-curate/SKILL.md +40 -24
- package/skills/memory-defrag/SKILL.md +18 -7
- package/skills/memory-doctor/SKILL.md +93 -0
- package/skills/memory-ingest/SKILL.md +33 -17
- package/skills/memory-lifecycle/SKILL.md +35 -22
- package/skills/memory-literary-analysis/SKILL.md +112 -75
- package/skills/memory-metadata-search/SKILL.md +39 -28
- package/skills/memory-notes/SKILL.md +75 -50
- package/skills/memory-okf/SKILL.md +27 -15
- package/skills/memory-onboarding/SKILL.md +20 -9
- package/skills/memory-onboarding/references/assistant-setup.md +1 -1
- package/skills/memory-onboarding/references/conventions.md +4 -4
- package/skills/memory-onboarding/references/domain-playbooks.md +1 -1
- package/skills/memory-onboarding/references/schema-guide.md +9 -8
- package/skills/memory-quest/SKILL.md +18 -7
- package/skills/memory-reflect/SKILL.md +25 -13
- package/skills/memory-research/SKILL.md +28 -13
- package/skills/memory-schema/SKILL.md +36 -24
- package/skills/memory-tasks/SKILL.md +34 -22
- package/tools/build-context.ts +14 -5
- package/tools/delete-note.ts +2 -2
- package/tools/edit-note.ts +27 -14
- package/tools/list-memory-projects.ts +6 -2
- package/tools/list-workspaces.ts +8 -5
- package/tools/move-note.ts +2 -2
- package/tools/read-note.ts +2 -2
- package/tools/schema-diff.ts +2 -2
- package/tools/schema-infer.ts +2 -2
- package/tools/schema-validate.ts +2 -2
- package/tools/search-notes.ts +18 -7
- package/tools/write-note.ts +12 -12
- package/dist/tools/memory-provider.d.ts +0 -15
- package/dist/tools/memory-provider.js +0 -275
- package/tools/memory-provider.ts +0 -336
|
@@ -7,6 +7,17 @@ description: "Capture a working thread's current state into one coherent Basic M
|
|
|
7
7
|
|
|
8
8
|
Capture the gist of a working thread — the decisions made, insights surfaced, and context built — into a single coherent Basic Memory note that reflects where the thread has landed.
|
|
9
9
|
|
|
10
|
+
## Project scope
|
|
11
|
+
|
|
12
|
+
If the project is unknown, discover it with `bm_project(command="list")`.
|
|
13
|
+
Pass a nonempty `project` on every note, folder, context and schema call, even
|
|
14
|
+
with one project or a qualified `memory://` URL. Use the chosen project's name,
|
|
15
|
+
`workspace/project`, or external ID; `<project>` below is a placeholder for it.
|
|
16
|
+
Recent activity also requires `project`. Search accepts `project` for one
|
|
17
|
+
project, `projects` for selected projects, or `all_projects=True` explicitly.
|
|
18
|
+
Discovery and bundled manuals need no project. Keep the same scope when following
|
|
19
|
+
returned paths, paginating, or recovering from a refusal.
|
|
20
|
+
|
|
10
21
|
## Purpose
|
|
11
22
|
|
|
12
23
|
A thread has a beginning, middle, and end. Things change as the conversation progresses: an early decision gets revised, a problem looks different in light of new information, a trade-off is settled differently than it first seemed. When this skill is invoked, capture the **current state of understanding**, not the history of how it got there.
|
|
@@ -33,31 +44,31 @@ To rewrite the same note on re-capture instead of duplicating, key the note to a
|
|
|
33
44
|
|
|
34
45
|
> **Example (hosts with a JSONL transcript):** some agents write a per-session transcript whose filename is a stable session UUID. If yours does, you can derive the id from the most-recently-modified transcript file and use it as `thread_id`. This is optional — only do it if your host actually exposes such a transcript.
|
|
35
46
|
|
|
36
|
-
**If no stable id is available**, match the existing note by title/topic instead: search for a note covering the same thread (`
|
|
47
|
+
**If no stable id is available**, match the existing note by title/topic instead: search for a note covering the same thread (`bm_search(query="<topic>", project="<project>")`), and if you find the one this thread already produced, rewrite it. Omit `thread_id` and rely on a consistent title.
|
|
37
48
|
|
|
38
49
|
## Decision Flow
|
|
39
50
|
|
|
40
51
|
1. **Determine the thread key.** Use a stable session/thread id if your agent exposes one; otherwise plan to match by title/topic.
|
|
41
52
|
2. **Search Basic Memory** for the existing thread note.
|
|
42
|
-
- With a thread id, use `
|
|
53
|
+
- With a thread id, use `filters` (not `query`) — full-text query doesn't reliably match YAML frontmatter custom fields:
|
|
43
54
|
```python
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
bm_search(
|
|
56
|
+
filters={"thread_id": "<thread-id>"},
|
|
46
57
|
project="<project>"
|
|
47
58
|
)
|
|
48
59
|
```
|
|
49
60
|
- Without one, search by topic and identify the note this thread already produced:
|
|
50
61
|
```python
|
|
51
|
-
|
|
62
|
+
bm_search(query="<thread topic>", project="<project>")
|
|
52
63
|
```
|
|
53
64
|
3. **If a match is found:**
|
|
54
65
|
- Read the existing note as JSON (use the full permalink returned by search) and keep its `checksum`
|
|
55
66
|
- Synthesize a new version that integrates the latest understanding from the conversation
|
|
56
|
-
- Overwrite via `
|
|
67
|
+
- Overwrite via `bm_write` with `overwrite=True` and `expected_checksum` set to that checksum using the returned `file_path` as `identifier` (same `thread_id` if used). A `REVISION_CONFLICT` error means another session changed the note since you read it: read it again and re-synthesize
|
|
57
68
|
4. **If no match is found:**
|
|
58
69
|
- Synthesize the note from the conversation
|
|
59
|
-
- If you have a thread id, pass `metadata={"thread_id": "<thread-id>"}` to `
|
|
60
|
-
- Save it. If `
|
|
70
|
+
- If you have a thread id, pass `metadata={"thread_id": "<thread-id>"}` to `bm_write` (it surfaces as a custom frontmatter field)
|
|
71
|
+
- Save it. If `bm_write` lists similar existing notes, check whether one of them is this thread's note before keeping the new one
|
|
61
72
|
|
|
62
73
|
## Synthesis Rules
|
|
63
74
|
|
|
@@ -125,23 +136,23 @@ The title should reflect the thread's topic. On update, the title can be refined
|
|
|
125
136
|
## MCP Tools Used
|
|
126
137
|
|
|
127
138
|
```python
|
|
128
|
-
# Find existing thread note by thread id (use
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
# Find existing thread note by thread id (use filters, not query)
|
|
140
|
+
bm_search(
|
|
141
|
+
filters={"thread_id": "<thread-id>"},
|
|
131
142
|
project="<project>"
|
|
132
143
|
)
|
|
133
144
|
|
|
134
145
|
# Or, without a thread id, find it by topic
|
|
135
|
-
|
|
146
|
+
bm_search(query="<thread topic>", project="<project>")
|
|
136
147
|
|
|
137
148
|
# Read existing thread note (use the full permalink from search results)
|
|
138
|
-
|
|
149
|
+
bm_read(
|
|
139
150
|
identifier="<full-permalink>",
|
|
140
151
|
project="<project>"
|
|
141
152
|
)
|
|
142
153
|
|
|
143
154
|
# Create
|
|
144
|
-
|
|
155
|
+
bm_write(
|
|
145
156
|
title="<title>",
|
|
146
157
|
content="<markdown body — frontmatter is generated from title/tags/metadata>",
|
|
147
158
|
directory="<folder>",
|
|
@@ -151,11 +162,11 @@ write_note(
|
|
|
151
162
|
)
|
|
152
163
|
|
|
153
164
|
# Overwrite an existing note (same path), only the revision you read
|
|
154
|
-
existing =
|
|
155
|
-
|
|
156
|
-
|
|
165
|
+
existing = bm_read(identifier="<full-permalink>", output_format="json", project="<project>")
|
|
166
|
+
bm_write(
|
|
167
|
+
identifier=existing["file_path"],
|
|
168
|
+
title="<updated title>",
|
|
157
169
|
content="<new content>",
|
|
158
|
-
directory="<same folder>",
|
|
159
170
|
tags=["..."],
|
|
160
171
|
metadata={"thread_id": "<same thread-id>"}, # omit if no stable id
|
|
161
172
|
overwrite=True,
|
|
@@ -19,6 +19,17 @@ The full vocabulary, every prop, and every data grammar are in
|
|
|
19
19
|
[references/components.md](references/components.md). Read it before using a
|
|
20
20
|
component you have not used before.
|
|
21
21
|
|
|
22
|
+
## Project scope
|
|
23
|
+
|
|
24
|
+
If the project is unknown, discover it with `bm_project(command="list")`.
|
|
25
|
+
Pass a nonempty `project` on every note, folder, context and schema call, even
|
|
26
|
+
with one project or a qualified `memory://` URL. Use the chosen project's name,
|
|
27
|
+
`workspace/project`, or external ID; `<project>` below is a placeholder for it.
|
|
28
|
+
Recent activity also requires `project`. Search accepts `project` for one
|
|
29
|
+
project, `projects` for selected projects, or `all_projects=True` explicitly.
|
|
30
|
+
Discovery and bundled manuals need no project. Keep the same scope when following
|
|
31
|
+
returned paths, paginating, or recovering from a refusal.
|
|
32
|
+
|
|
22
33
|
## Pick a component
|
|
23
34
|
|
|
24
35
|
Most notes need only these. The reference has the rest (39 in total).
|
|
@@ -138,13 +149,13 @@ Semantics to state honestly in the surrounding prose:
|
|
|
138
149
|
|
|
139
150
|
### Check the rendered result before you quote it
|
|
140
151
|
|
|
141
|
-
In Basic Memory Cloud, `
|
|
152
|
+
In Basic Memory Cloud, `bm_read(identifier="<note>", view="text", project="<project>")` returns the note as a reader
|
|
142
153
|
sees it: every component as plain Markdown, with live queries run now. Read it
|
|
143
154
|
back after writing a live view and confirm the view has rows before you state a
|
|
144
155
|
number in prose. A query over a field no note has renders an empty view.
|
|
145
156
|
|
|
146
157
|
Elsewhere, only the browser runs the query, so run the equivalent read yourself
|
|
147
|
-
(for example `
|
|
158
|
+
(for example `bm_search` with metadata filters; see the
|
|
148
159
|
memory-metadata-search skill).
|
|
149
160
|
|
|
150
161
|
A live chart's body is its **snapshot**: the rows readers see when live data
|
|
@@ -154,7 +165,7 @@ as a snapshot in prose and keep them in the chart's row grammar.
|
|
|
154
165
|
|
|
155
166
|
## Edit a note that already has components
|
|
156
167
|
|
|
157
|
-
- Change one component with `
|
|
168
|
+
- Change one component with `bm_edit` (`find_replace` on its directive line or
|
|
158
169
|
rows). Do not rewrite the whole note to change one value.
|
|
159
170
|
- The rich editor normalizes formatting when a person edits the note: attribute
|
|
160
171
|
order changes and YAML blocks come back as JSON. Values survive; do not fight
|
|
@@ -168,9 +179,9 @@ as a snapshot in prose and keep them in the chart's row grammar.
|
|
|
168
179
|
## When a component shows an error
|
|
169
180
|
|
|
170
181
|
A broken component renders a coded problem and a fix inside its own frame; the
|
|
171
|
-
rest of the note still renders. In Basic Memory Cloud, `
|
|
172
|
-
`
|
|
173
|
-
(they never block the write), so fix them right away with `
|
|
182
|
+
rest of the note still renders. In Basic Memory Cloud, `bm_write` and
|
|
183
|
+
`bm_edit` list these problems under **Component problems** in their result
|
|
184
|
+
(they never block the write), so fix them right away with `bm_edit`. `comark(7)` in the manual
|
|
174
185
|
(`memory://man/comark(7)`) is a quick reference to the syntax and codes. The
|
|
175
186
|
codes you will meet most:
|
|
176
187
|
|
|
@@ -7,6 +7,17 @@ description: "Resume prior work by rebuilding context from the Basic Memory grap
|
|
|
7
7
|
|
|
8
8
|
Resume previous work by reconstructing context from the Basic Memory knowledge graph, so the assistant can pick up across sessions instead of starting cold.
|
|
9
9
|
|
|
10
|
+
## Project scope
|
|
11
|
+
|
|
12
|
+
If the project is unknown, discover it with `bm_project(command="list")`.
|
|
13
|
+
Pass a nonempty `project` on every note, folder, context and schema call, even
|
|
14
|
+
with one project or a qualified `memory://` URL. Use the chosen project's name,
|
|
15
|
+
`workspace/project`, or external ID; `<project>` below is a placeholder for it.
|
|
16
|
+
Recent activity also requires `project`. Search accepts `project` for one
|
|
17
|
+
project, `projects` for selected projects, or `all_projects=True` explicitly.
|
|
18
|
+
Discovery and bundled manuals need no project. Keep the same scope when following
|
|
19
|
+
returned paths, paginating, or recovering from a refusal.
|
|
20
|
+
|
|
10
21
|
## When to Use
|
|
11
22
|
|
|
12
23
|
- Starting a new session and you need to pick up where you left off
|
|
@@ -21,31 +32,32 @@ Resume previous work by reconstructing context from the Basic Memory knowledge g
|
|
|
21
32
|
|
|
22
33
|
If it's unclear, ask:
|
|
23
34
|
- What topic or project should you resume?
|
|
24
|
-
- What
|
|
35
|
+
- What since matters?
|
|
25
36
|
- Any specific aspect to focus on?
|
|
26
37
|
|
|
27
38
|
### 2. Gather Context with MCP Tools
|
|
28
39
|
|
|
29
|
-
**Known topic — use `
|
|
40
|
+
**Known topic — use `bm_context`.** Navigate the graph from a starting point, following relations outward:
|
|
30
41
|
|
|
31
42
|
```python
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
bm_context(
|
|
44
|
+
identifier="memory://topic-or-note-name",
|
|
34
45
|
depth=2, # how many relation hops to follow
|
|
35
|
-
|
|
46
|
+
since="7d", # only include changes in this window
|
|
47
|
+
project="<project>",
|
|
36
48
|
)
|
|
37
49
|
```
|
|
38
50
|
|
|
39
|
-
**No clear starting point — use `
|
|
51
|
+
**No clear starting point — use `bm_project(command="recent", project="<project>")`.** See what's changed and let it surface the thread:
|
|
40
52
|
|
|
41
53
|
```python
|
|
42
|
-
|
|
54
|
+
bm_project(command="recent", since="3d", project="<project>")
|
|
43
55
|
```
|
|
44
56
|
|
|
45
|
-
**Looking for something specific — use `
|
|
57
|
+
**Looking for something specific — use `bm_search`.** Find candidate notes by keyword:
|
|
46
58
|
|
|
47
59
|
```python
|
|
48
|
-
|
|
60
|
+
bm_search(query="async client refactor", page_size=10, project="<project>")
|
|
49
61
|
```
|
|
50
62
|
|
|
51
63
|
### 3. Read the Key Notes
|
|
@@ -53,17 +65,17 @@ search_notes(query="async client refactor", page_size=10)
|
|
|
53
65
|
Once you've identified the relevant notes, read them in full:
|
|
54
66
|
|
|
55
67
|
```python
|
|
56
|
-
|
|
68
|
+
bm_read(identifier="note-title-or-permalink", project="<project>")
|
|
57
69
|
```
|
|
58
70
|
|
|
59
71
|
For long notes, pick before you pay for bodies. `compact=True` drops bodies from
|
|
60
|
-
search results (and observations from `
|
|
72
|
+
search results (and observations from `bm_context`), and a line range or a
|
|
61
73
|
section reads only the part you need:
|
|
62
74
|
|
|
63
75
|
```python
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
76
|
+
bm_search(query="async client refactor", compact=True, project="<project>")
|
|
77
|
+
bm_read(identifier="note-title-or-permalink", start_line=120, end_line=180, project="<project>")
|
|
78
|
+
bm_read(identifier="note-title-or-permalink", section="Status", project="<project>")
|
|
67
79
|
```
|
|
68
80
|
|
|
69
81
|
### 4. Present Context to the User
|
|
@@ -76,7 +88,7 @@ Summarize what you found, incrementally:
|
|
|
76
88
|
|
|
77
89
|
## Memory URL Reference
|
|
78
90
|
|
|
79
|
-
`
|
|
91
|
+
`bm_context` and `bm_read` both accept `memory://` URLs. `bm_read` resolves one exact note; use `bm_context` for wildcard patterns that gather groups of notes.
|
|
80
92
|
|
|
81
93
|
```
|
|
82
94
|
memory://note-title # a single note by permalink
|
|
@@ -89,7 +101,7 @@ Use a specific note URL to anchor on one starting point; use a wildcard to pull
|
|
|
89
101
|
|
|
90
102
|
## Timeframe Reference
|
|
91
103
|
|
|
92
|
-
`
|
|
104
|
+
`bm_context` and `bm_project(command="recent", project="<project>")` accept natural-language timeframes:
|
|
93
105
|
|
|
94
106
|
| Timeframe | Meaning |
|
|
95
107
|
|-----------|---------|
|
|
@@ -106,10 +118,10 @@ Use a specific note URL to anchor on one starting point; use a wildcard to pull
|
|
|
106
118
|
|
|
107
119
|
```python
|
|
108
120
|
# 1. Read the spec / project note
|
|
109
|
-
|
|
121
|
+
bm_read(identifier="SPEC-24: Postgres Database Migration", project="<project>")
|
|
110
122
|
|
|
111
123
|
# 2. Pull in related context and recent changes via the graph
|
|
112
|
-
|
|
124
|
+
bm_context(identifier="memory://SPEC-24*", since="7d", project="<project>")
|
|
113
125
|
```
|
|
114
126
|
|
|
115
127
|
Then summarize: the goals, what's completed, what's pending, and any blockers or open decisions.
|
|
@@ -118,10 +130,10 @@ Then summarize: the goals, what's completed, what's pending, and any blockers or
|
|
|
118
130
|
|
|
119
131
|
```python
|
|
120
132
|
# 1. Check recent activity
|
|
121
|
-
|
|
133
|
+
bm_project(command="recent", since="3d", project="<project>")
|
|
122
134
|
|
|
123
135
|
# 2. Read notes from the recent sessions it surfaces
|
|
124
|
-
|
|
136
|
+
bm_read(identifier="relevant-note", project="<project>")
|
|
125
137
|
```
|
|
126
138
|
|
|
127
139
|
Then list the modified notes with brief descriptions and ask which thread to dive into.
|
|
@@ -130,10 +142,10 @@ Then list the modified notes with brief descriptions and ask which thread to div
|
|
|
130
142
|
|
|
131
143
|
```python
|
|
132
144
|
# 1. Find the topic
|
|
133
|
-
|
|
145
|
+
bm_search(query="topic keywords", project="<project>")
|
|
134
146
|
|
|
135
147
|
# 2. Build context from the best match, following its relations
|
|
136
|
-
|
|
148
|
+
bm_context(identifier="memory://found-note-permalink", depth=2, project="<project>")
|
|
137
149
|
```
|
|
138
150
|
|
|
139
151
|
Then present the full picture — the note plus its connected context.
|
|
@@ -143,16 +155,24 @@ Then present the full picture — the note plus its connected context.
|
|
|
143
155
|
Project names are user-specific. To discover what's available before scoping a search or `memory://` URL:
|
|
144
156
|
|
|
145
157
|
```python
|
|
146
|
-
|
|
158
|
+
bm_project(command="list")
|
|
147
159
|
```
|
|
148
160
|
|
|
149
|
-
|
|
161
|
+
A qualified `memory://` URL (e.g. `memory://research/papers/crdt`) must agree
|
|
162
|
+
with `project`; the prefix does not replace that required parameter.
|
|
163
|
+
|
|
164
|
+
For an explicitly broader search, use one of these scopes instead:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
bm_search(query="topic keywords", projects=["research", "team/engineering"])
|
|
168
|
+
bm_search(query="topic keywords", all_projects=True)
|
|
169
|
+
```
|
|
150
170
|
|
|
151
171
|
## Guidelines
|
|
152
172
|
|
|
153
|
-
1. **Start broad, then narrow.** Get an overview with `
|
|
173
|
+
1. **Start broad, then narrow.** Get an overview with `bm_project(command="recent", project="<project>")` or a wildcard `bm_context`, then drill into specific notes.
|
|
154
174
|
2. **Present incrementally.** Share what you find as you go rather than holding everything until the end.
|
|
155
|
-
3. **Follow relations.** The graph's connections are the point — `
|
|
156
|
-
4. **Check multiple projects.** Specs may live separately from implementation notes; discover projects with `
|
|
175
|
+
3. **Follow relations.** The graph's connections are the point — `bm_context` with `depth` surfaces context you wouldn't find by reading one note.
|
|
176
|
+
4. **Check multiple projects.** Specs may live separately from implementation notes; discover projects with `bm_project(command="list")`.
|
|
157
177
|
5. **Confirm understanding.** Verify the reconstructed context is what the user actually needs before acting on it.
|
|
158
178
|
6. **Capture new progress.** As the resumed work advances, write it back to the graph (see the **memory-notes** skill) so the next session can continue too.
|
|
@@ -9,6 +9,17 @@ Maintain a healthy, well-connected knowledge graph. As notes accumulate, it pays
|
|
|
9
9
|
|
|
10
10
|
This skill curates the **knowledge graph** — the notes, relations, and tags that make up the knowledge base. (For the notes' content — splitting bloated notes, consolidating scattered facts, retiring stale entries — see **memory-defrag**.)
|
|
11
11
|
|
|
12
|
+
## Project scope
|
|
13
|
+
|
|
14
|
+
If the project is unknown, discover it with `bm_project(command="list")`.
|
|
15
|
+
Pass a nonempty `project` on every note, folder, context and schema call, even
|
|
16
|
+
with one project or a qualified `memory://` URL. Use the chosen project's name,
|
|
17
|
+
`workspace/project`, or external ID; `<project>` below is a placeholder for it.
|
|
18
|
+
Recent activity also requires `project`. Search accepts `project` for one
|
|
19
|
+
project, `projects` for selected projects, or `all_projects=True` explicitly.
|
|
20
|
+
Discovery and bundled manuals need no project. Keep the same scope when following
|
|
21
|
+
returned paths, paginating, or recovering from a refusal.
|
|
22
|
+
|
|
12
23
|
## When to Use
|
|
13
24
|
|
|
14
25
|
- Asked to organize, clean up, or improve the knowledge base
|
|
@@ -26,12 +37,12 @@ Orphans have no relations to other notes — they're islands in the graph.
|
|
|
26
37
|
|
|
27
38
|
```python
|
|
28
39
|
# List notes, then read each to inspect its Relations section
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
bm_search(query="*", mode="text", page_size=50, project="<project>")
|
|
41
|
+
bm_read(identifier="note-to-check", project="<project>")
|
|
31
42
|
# Orphans have an empty (or missing) Relations section
|
|
32
43
|
```
|
|
33
44
|
|
|
34
|
-
`query="*"` lists everything only with `
|
|
45
|
+
`query="*"` lists everything only with `mode="text"`. A note whose body
|
|
35
46
|
links to other notes, with wikilinks or ordinary Markdown links, is not an
|
|
36
47
|
orphan even without a Relations section.
|
|
37
48
|
|
|
@@ -47,9 +58,9 @@ If the `bm` CLI is available, `bm orphans` lists notes with no relations in one
|
|
|
47
58
|
Analyze a note's content and propose meaningful connections.
|
|
48
59
|
|
|
49
60
|
```python
|
|
50
|
-
|
|
61
|
+
bm_read(identifier="note-to-analyze", project="<project>")
|
|
51
62
|
# Pull out key terms, then search for related notes
|
|
52
|
-
|
|
63
|
+
bm_search(query="key terms from the note", project="<project>")
|
|
53
64
|
```
|
|
54
65
|
|
|
55
66
|
Suggest relations based on shared topics, complementary content (problem/solution,
|
|
@@ -67,14 +78,15 @@ question/answer), sequence (part 1 → part 2), or hierarchy (parent concept →
|
|
|
67
78
|
|
|
68
79
|
Custom relation types are fine — use whatever verb is descriptive.
|
|
69
80
|
|
|
70
|
-
Add a confirmed relation with `
|
|
81
|
+
Add a confirmed relation with `bm_edit`:
|
|
71
82
|
|
|
72
83
|
```python
|
|
73
|
-
|
|
84
|
+
bm_edit(
|
|
74
85
|
identifier="API Design Decisions",
|
|
75
|
-
|
|
86
|
+
command="insert_after_section",
|
|
76
87
|
section="Relations",
|
|
77
88
|
content="- depends_on [[Rate Limiter]]",
|
|
89
|
+
project="<project>",
|
|
78
90
|
)
|
|
79
91
|
```
|
|
80
92
|
|
|
@@ -82,10 +94,11 @@ edit_note(
|
|
|
82
94
|
`## Relations`. Then append the section instead:
|
|
83
95
|
|
|
84
96
|
```python
|
|
85
|
-
|
|
97
|
+
bm_edit(
|
|
86
98
|
identifier="API Design Decisions",
|
|
87
|
-
|
|
99
|
+
command="append",
|
|
88
100
|
content="\n## Relations\n- depends_on [[Rate Limiter]]",
|
|
101
|
+
project="<project>",
|
|
89
102
|
)
|
|
90
103
|
```
|
|
91
104
|
|
|
@@ -94,7 +107,7 @@ edit_note(
|
|
|
94
107
|
Find notes that may cover the same ground.
|
|
95
108
|
|
|
96
109
|
```python
|
|
97
|
-
|
|
110
|
+
bm_search(query="topic keywords", project="<project>")
|
|
98
111
|
# Compare results for: similar titles, overlapping observations,
|
|
99
112
|
# shared tags, close-together timestamps
|
|
100
113
|
```
|
|
@@ -107,36 +120,38 @@ search_notes(query="topic keywords")
|
|
|
107
120
|
|
|
108
121
|
```python
|
|
109
122
|
# Point an older note at the one that replaces it
|
|
110
|
-
|
|
123
|
+
bm_edit(
|
|
111
124
|
identifier="DB Schema v1",
|
|
112
|
-
|
|
125
|
+
command="insert_after_section",
|
|
113
126
|
section="Relations",
|
|
114
127
|
content="- updates [[DB Schema v2]]",
|
|
128
|
+
project="<project>",
|
|
115
129
|
)
|
|
116
130
|
```
|
|
117
131
|
|
|
118
132
|
### 4. Folder Organization Review
|
|
119
133
|
|
|
120
134
|
```python
|
|
121
|
-
|
|
135
|
+
bm_find(path="/", depth=3, project="<project>")
|
|
122
136
|
```
|
|
123
137
|
|
|
124
138
|
Look for overcrowded folders, single-note folders, inconsistent naming, and notes
|
|
125
139
|
that belong elsewhere. Suggest grouping related notes into topic folders, adding
|
|
126
140
|
subfolders for large categories, and a consistent naming convention. Move misplaced
|
|
127
|
-
notes with `
|
|
141
|
+
notes with `bm_move`. By default the permalink stays the same after a move, so links keep resolving. Projects with `update_permalinks_on_move` enabled rewrite it from the new path.
|
|
128
142
|
|
|
129
143
|
```python
|
|
130
|
-
|
|
144
|
+
bm_move(
|
|
131
145
|
identifier="API Design Decisions",
|
|
132
|
-
|
|
146
|
+
destination="architecture/api-design-decisions.md",
|
|
147
|
+
project="<project>",
|
|
133
148
|
)
|
|
134
149
|
```
|
|
135
150
|
|
|
136
151
|
### 5. Tag Consistency
|
|
137
152
|
|
|
138
153
|
```python
|
|
139
|
-
|
|
154
|
+
bm_search(query="*", mode="text", page_size=100, project="<project>")
|
|
140
155
|
# Inspect tag patterns across results
|
|
141
156
|
```
|
|
142
157
|
|
|
@@ -151,7 +166,7 @@ Look for:
|
|
|
151
166
|
After finding a cluster of related notes, build a navigation hub.
|
|
152
167
|
|
|
153
168
|
```python
|
|
154
|
-
|
|
169
|
+
bm_write(
|
|
155
170
|
title="Architecture Decisions Index",
|
|
156
171
|
directory="indexes",
|
|
157
172
|
tags=["architecture", "index"],
|
|
@@ -174,6 +189,7 @@ A hub linking architecture-related decisions and patterns.
|
|
|
174
189
|
|
|
175
190
|
## Relations
|
|
176
191
|
- indexes [[Architecture]]""",
|
|
192
|
+
project="<project>",
|
|
177
193
|
)
|
|
178
194
|
```
|
|
179
195
|
|
|
@@ -182,19 +198,19 @@ A hub linking architecture-related decisions and patterns.
|
|
|
182
198
|
Find notes lacking structure and fill them in.
|
|
183
199
|
|
|
184
200
|
```python
|
|
185
|
-
|
|
201
|
+
bm_read(identifier="sparse-note", project="<project>")
|
|
186
202
|
```
|
|
187
203
|
|
|
188
204
|
If the note is missing an Observations section, suggest categories. If it has no
|
|
189
205
|
Relations, suggest links. If it has no tags, suggest relevant ones. If it lacks
|
|
190
|
-
context, suggest adding background. Apply with `
|
|
206
|
+
context, suggest adding background. Apply with `bm_edit`.
|
|
191
207
|
|
|
192
208
|
## Curation Workflows
|
|
193
209
|
|
|
194
210
|
Scale the pass to the request. A health check reports orphans, likely duplicates,
|
|
195
|
-
recent activity (`
|
|
211
|
+
recent activity (`bm_project(command="recent", project="<project>")`), and folder distribution. A deep session works
|
|
196
212
|
through the capabilities above in whatever order the findings suggest. A topic pass
|
|
197
|
-
maps one subject with `
|
|
213
|
+
maps one subject with `bm_search` and `bm_context`, fills the gaps it finds, and
|
|
198
214
|
ends with a hub note.
|
|
199
215
|
|
|
200
216
|
## Best Practices
|
|
@@ -204,7 +220,7 @@ ends with a hub note.
|
|
|
204
220
|
3. **Preserve permalinks.** Changing a permalink breaks inbound `memory://` links. Moves keep the permalink by default (unless the project enables `update_permalinks_on_move`).
|
|
205
221
|
4. **Explain suggestions.** Say *why* a relation or merge makes sense.
|
|
206
222
|
5. **Respect the existing system.** Enhance the user's organization — don't impose a new taxonomy.
|
|
207
|
-
6. **Show the graph.** Use `
|
|
223
|
+
6. **Show the graph.** Use `bm_context` to help the user see how notes connect.
|
|
208
224
|
|
|
209
225
|
## Example Conversations
|
|
210
226
|
|
|
@@ -10,6 +10,17 @@ time notes grow past their topic, the same fact lands in several places, old
|
|
|
10
10
|
facts contradict new ones, and finished work lingers. Defrag fixes the content;
|
|
11
11
|
**memory-curate** handles links, relations, and tags.
|
|
12
12
|
|
|
13
|
+
## Project scope
|
|
14
|
+
|
|
15
|
+
If the project is unknown, discover it with `bm_project(command="list")`.
|
|
16
|
+
Pass a nonempty `project` on every note, folder, context and schema call, even
|
|
17
|
+
with one project or a qualified `memory://` URL. Use the chosen project's name,
|
|
18
|
+
`workspace/project`, or external ID; `<project>` below is a placeholder for it.
|
|
19
|
+
Recent activity also requires `project`. Search accepts `project` for one
|
|
20
|
+
project, `projects` for selected projects, or `all_projects=True` explicitly.
|
|
21
|
+
Discovery and bundled manuals need no project. Keep the same scope when following
|
|
22
|
+
returned paths, paginating, or recovering from a refusal.
|
|
23
|
+
|
|
13
24
|
## When to Run
|
|
14
25
|
|
|
15
26
|
- **Periodic**: weekly or every other week
|
|
@@ -25,18 +36,18 @@ Walk the whole project, not just recent changes. Stale content is usually in
|
|
|
25
36
|
notes nobody touched lately.
|
|
26
37
|
|
|
27
38
|
```python
|
|
28
|
-
# Every folder and note
|
|
29
|
-
#
|
|
30
|
-
|
|
39
|
+
# Every folder and note within depth 10. Page until has_more is false;
|
|
40
|
+
# descend into deeper folders separately if the project has them.
|
|
41
|
+
bm_find(path="/", depth=10, page_size=100, project="<project>")
|
|
31
42
|
|
|
32
43
|
# Recently busy notes, to look at first
|
|
33
|
-
|
|
44
|
+
bm_project(command="recent", since="30d", output_format="json", page_size=50, project="<project>")
|
|
34
45
|
|
|
35
46
|
# Notes on one topic, to spot overlap
|
|
36
|
-
|
|
47
|
+
bm_search(query="launch plan", project="<project>")
|
|
37
48
|
|
|
38
49
|
# Commitments due on or before today: finished work that lingers, or overdue items
|
|
39
|
-
|
|
50
|
+
bm_search(time_kind="due", valid_overlaps="(,2026-10-14]", project="<project>")
|
|
40
51
|
```
|
|
41
52
|
|
|
42
53
|
Read every note you might change, in full. For each, note its topic, size, last
|
|
@@ -105,7 +116,7 @@ status: proposed
|
|
|
105
116
|
- Make one change at a time. Read each note as JSON before you edit it and pass
|
|
106
117
|
its checksum as `expected_checksum`, so the edit applies only to the revision
|
|
107
118
|
you read; on a checksum conflict, read again and recheck the plan line. Keep
|
|
108
|
-
relations pointing at the right note after a split or move (`
|
|
119
|
+
relations pointing at the right note after a split or move (`bm_move` keeps
|
|
109
120
|
links working; a new note needs links added).
|
|
110
121
|
|
|
111
122
|
### 5. Record what was done
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-doctor
|
|
3
|
+
description: "Check local Basic Memory projects with bm doctor, explain the findings, and run the suggested fixes once the user agrees. Use when search misses or repeats notes, or a save looks lost."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Doctor
|
|
7
|
+
|
|
8
|
+
`bm doctor` checks the user's local Basic Memory projects and reports what is
|
|
9
|
+
wrong. Each problem comes with the command that fixes it, when one exists.
|
|
10
|
+
Doctor's checks only read; they never change a project's notes or index. The
|
|
11
|
+
fixes it suggests do change things, so run them only after the user agrees.
|
|
12
|
+
|
|
13
|
+
This skill needs a shell with the `bm` (or `basic-memory`) command.
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- Search misses a note the user knows exists, or returns the same note twice
|
|
18
|
+
- A note was saved but its file did not change, or the reverse
|
|
19
|
+
- The user asks whether Basic Memory is working, or to "check" or "fix" it
|
|
20
|
+
- After a crash, an interrupted import, or moving a project's folder
|
|
21
|
+
|
|
22
|
+
## Run It
|
|
23
|
+
|
|
24
|
+
Start with the report alone. It is fast and has a stable JSON shape:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bm doctor --skip-self-test --json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Add `--project NAME` to check one project. Without `--skip-self-test`, doctor
|
|
31
|
+
also runs a self-test: it writes, indexes and searches a note in a throwaway
|
|
32
|
+
sandbox, which takes a few seconds and proves the install itself works. Run it
|
|
33
|
+
when the report is clean but something still seems broken.
|
|
34
|
+
|
|
35
|
+
## Read the Report
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"projects": [
|
|
40
|
+
{
|
|
41
|
+
"name": "work",
|
|
42
|
+
"findings": [
|
|
43
|
+
{
|
|
44
|
+
"check": "search_index",
|
|
45
|
+
"severity": "error",
|
|
46
|
+
"summary": "1 search row does not match a current note, observation or relation.",
|
|
47
|
+
"evidence": ["entity id=99, entity_id=99"],
|
|
48
|
+
"action": {"kind": "reindex_search", "full": true},
|
|
49
|
+
"command": "bm reindex --search --full --project work"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"has_errors": true
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"skipped_cloud_projects": ["research"],
|
|
56
|
+
"self_test": {"outcome": "skipped"},
|
|
57
|
+
"has_errors": true
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Severity | Meaning | What to do |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `error` | Will not go away without a fix | Offer the `command`; if it is null, explain the evidence |
|
|
64
|
+
| `warning` | Needs attention, may recover on its own | Offer the `command` if there is one |
|
|
65
|
+
| `info` | Expected while work is in progress | Mention it; a running server finishes it, and the `command` finishes it now |
|
|
66
|
+
|
|
67
|
+
Indexing catches up in the background. A duplicate, missing or extra search row
|
|
68
|
+
is a `warning` while file indexing is still running, because the pass may clear
|
|
69
|
+
it, and becomes an `error` once indexing has settled. If the report has only `info` findings, nothing is wrong. When no
|
|
70
|
+
Basic Memory server is running, nothing indexes in the background, so offer the
|
|
71
|
+
`command` on an `info` finding too.
|
|
72
|
+
|
|
73
|
+
Cloud projects are listed under `skipped_cloud_projects`: they are indexed on the
|
|
74
|
+
server, and local commands cannot fix them.
|
|
75
|
+
|
|
76
|
+
## Fix
|
|
77
|
+
|
|
78
|
+
1. Summarize the findings for the user in plain words: which project, what is
|
|
79
|
+
wrong, and what the fix does. Group findings that share a command.
|
|
80
|
+
2. Show each `command` exactly as doctor printed it and ask before running it.
|
|
81
|
+
`bm reindex --search --full` re-reads every file in the project and can take
|
|
82
|
+
a while on a large one.
|
|
83
|
+
3. Run the commands the user approves.
|
|
84
|
+
4. Run `bm doctor --skip-self-test --json` again and confirm the findings are gone.
|
|
85
|
+
|
|
86
|
+
When a finding has no `command`, do not invent one. Say what the evidence shows
|
|
87
|
+
(for example, which files changed on disk while a newer save was waiting) and
|
|
88
|
+
let the user decide.
|
|
89
|
+
|
|
90
|
+
## Exit Codes
|
|
91
|
+
|
|
92
|
+
`bm doctor` exits 0 when there are no errors and the self-test passed (or was
|
|
93
|
+
skipped), and 1 otherwise. Warnings and info never fail it.
|