@basicmemory/openclaw-basic-memory 0.1.3 → 0.1.4

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.
@@ -0,0 +1,235 @@
1
+ ---
2
+ name: memory-research
3
+ description: "Research an external subject using web search, synthesize findings into a structured Basic Memory entity. Use when asked to research a company, person, technology, or topic — or when a bare name or URL is provided that implies a research request."
4
+ ---
5
+
6
+ # Memory Research
7
+
8
+ Research an external subject, synthesize what you find, and create a structured Basic Memory entity — with the user's approval.
9
+
10
+ ## When to Use
11
+
12
+ **Explicit triggers:**
13
+ - "Research [subject]"
14
+ - "Look up [subject]"
15
+ - "What do you know about [subject]?"
16
+ - "Evaluate [subject]"
17
+
18
+ **Implicit triggers (also activate this skill):**
19
+ - A bare name: "Terraform"
20
+ - A URL: "https://example.com"
21
+ - A name with context: "Acme Corp — saw them at the conference"
22
+
23
+ ## Workflow
24
+
25
+ ### Step 1: Web Research
26
+
27
+ Search for current information across multiple sources. Aim for 3-5 searches to build a well-rounded picture:
28
+
29
+ ```
30
+ [subject name] site
31
+ [subject name] overview
32
+ [subject name] news [current year]
33
+ [subject name] [relevant domain keywords]
34
+ ```
35
+
36
+ **What to gather by entity type:**
37
+
38
+ | Entity Type | Key Information |
39
+ |-------------|----------------|
40
+ | **Organization** | What they do, products/services, stage (startup/growth/public), funding, leadership, headquarters, employee count, notable partnerships or contracts |
41
+ | **Person** | Current role, organization, background, expertise, notable work, public presence |
42
+ | **Technology** | What it does, who maintains it, maturity, ecosystem, alternatives, adoption |
43
+ | **Topic/Domain** | Definition, current state, key players, trends, relevance to user's context |
44
+
45
+ ### Step 2: Check Existing Knowledge
46
+
47
+ Before proposing a new entity, search Basic Memory:
48
+
49
+ ```python
50
+ search_notes(query="Acme Corp")
51
+ search_notes(query="acme")
52
+ ```
53
+
54
+ Try name variations — full name, abbreviation, acronym, domain name.
55
+
56
+ If the entity already exists:
57
+ - Report what you found in Basic Memory alongside your web research
58
+ - Offer to update the existing note with new information
59
+ - Use `edit_note` to append new observations or update outdated ones
60
+
61
+ If the entity doesn't exist, proceed to evaluation.
62
+
63
+ ### Step 3: Evaluate and Summarize
64
+
65
+ Present your findings in a structured summary. Include all relevant information organized by section:
66
+
67
+ ```markdown
68
+ ## [Subject Name]
69
+
70
+ **Type:** [Organization / Person / Technology / Topic]
71
+
72
+ **Summary:** [2-4 sentences: what this is, why it matters, key distinguishing facts]
73
+
74
+ **Key Details:**
75
+ - [Organized by what's relevant for the entity type]
76
+ - [Stage, funding, leadership for orgs]
77
+ - [Role, expertise, affiliations for people]
78
+ - [Maturity, ecosystem, alternatives for tech]
79
+
80
+ **Relevance:** [Why this matters to the user — connection to their work, domain, or interests.
81
+ If no obvious connection: "No specific connection identified."]
82
+
83
+ **Sources:**
84
+ - [URLs of key sources consulted]
85
+ ```
86
+
87
+ ### Evaluation Guidelines
88
+
89
+ **Use hedging language.** Web research is a snapshot, not ground truth:
90
+ - "Appears to be", "Based on public information", "Estimated"
91
+ - "As of [date]", "According to [source]"
92
+ - Never state funding amounts, employee counts, or revenue as exact unless citing a primary source
93
+
94
+ **Don't fabricate.** If information isn't available, say so:
95
+ - "Leadership information not publicly available"
96
+ - "Funding details not disclosed"
97
+
98
+ **Let the user define relevance.** Don't impose a fixed evaluation framework. Instead, highlight facts and let the user draw conclusions. If the user has a specific evaluation rubric (strategic fit, buy/partner/compete, etc.), they'll tell you — apply it when asked.
99
+
100
+ ### Step 4: Propose Entity Creation
101
+
102
+ After presenting the summary, ask for approval:
103
+
104
+ ```
105
+ Create Basic Memory entity for [Subject]?
106
+ Location: [suggested-folder]/[entity-name].md
107
+ Type: [entity type]
108
+
109
+ [yes / no / modify]
110
+ ```
111
+
112
+ If the user provided context with their request ("saw them at the conference"), include that context in the proposed entity.
113
+
114
+ ### Step 5: Create the Entity
115
+
116
+ After approval, create a structured note. Adapt the template to the entity type:
117
+
118
+ #### Organization
119
+
120
+ ```python
121
+ write_note(
122
+ title="Acme Corp",
123
+ directory="organizations",
124
+ note_type="organization",
125
+ tags=["organization", "relevant-tags"],
126
+ content="""# Acme Corp
127
+
128
+ ## Overview
129
+ [2-3 sentence description from research]
130
+
131
+ ## Products & Services
132
+ - [Key offerings discovered in research]
133
+
134
+ ## Background
135
+ **Stage:** [Startup / Growth / Public]
136
+ **Headquarters:** [Location]
137
+ **Employees:** [Estimate, hedged]
138
+ **Leadership:** [Key people if found]
139
+ **Founded:** [Year if found]
140
+
141
+ ## Observations
142
+ - [relevance] Why this entity matters in user's context
143
+ - [source] Researched on YYYY-MM-DD
144
+ - [additional observations from research findings]
145
+
146
+ ## Relations
147
+ - [Link to related entities already in the knowledge graph]"""
148
+ )
149
+ ```
150
+
151
+ #### Person
152
+
153
+ ```python
154
+ write_note(
155
+ title="Jane Smith",
156
+ directory="people",
157
+ note_type="person",
158
+ tags=["person", "relevant-tags"],
159
+ content="""# Jane Smith
160
+
161
+ ## Overview
162
+ [Current role and affiliation. Brief background.]
163
+
164
+ ## Background
165
+ **Role:** [Title at Organization]
166
+ **Expertise:** [Key domains]
167
+ **Notable:** [Publications, talks, projects if found]
168
+
169
+ ## Observations
170
+ - [role] Title at Organization
171
+ - [expertise] Key technical or domain expertise
172
+ - [source] Researched on YYYY-MM-DD
173
+
174
+ ## Relations
175
+ - works_at [[Organization]]"""
176
+ )
177
+ ```
178
+
179
+ #### Technology
180
+
181
+ ```python
182
+ write_note(
183
+ title="Technology Name",
184
+ directory="concepts",
185
+ note_type="concept",
186
+ tags=["concept", "technology", "relevant-tags"],
187
+ content="""# Technology Name
188
+
189
+ ## Overview
190
+ [What it is and what problem it solves]
191
+
192
+ ## Key Details
193
+ **Maintained by:** [Organization or community]
194
+ **Maturity:** [Experimental / Stable / Mature]
195
+ **License:** [If applicable]
196
+ **Alternatives:** [Comparable tools or approaches]
197
+
198
+ ## Observations
199
+ - [definition] What this technology does in one sentence
200
+ - [maturity] Current state and adoption level
201
+ - [source] Researched on YYYY-MM-DD
202
+
203
+ ## Relations
204
+ - [Link to related concepts, tools, or projects in the knowledge graph]"""
205
+ )
206
+ ```
207
+
208
+ Adapt these templates freely. The key elements are: note_type/tags parameters, an overview, structured details, observations with categories, and relations.
209
+
210
+ ### Step 6: Store Source Context
211
+
212
+ If the user provided context with their request, capture it in the entity:
213
+
214
+ ```python
215
+ # User said: "Acme Corp — saw their demo at the conference last week"
216
+ edit_note(
217
+ identifier="Acme Corp",
218
+ operation="append",
219
+ section="Observations",
220
+ content="- [context] Saw their demo at conference, week of 2026-02-17"
221
+ )
222
+ ```
223
+
224
+ This context is often the most valuable part — it's the user's relationship to the entity, which web research can't provide.
225
+
226
+ ## Guidelines
227
+
228
+ - **Always web search.** Don't rely on training data alone. Research should reflect current, verifiable information.
229
+ - **Search Basic Memory first.** Check for existing entities before creating new ones. Update rather than duplicate.
230
+ - **Hedge uncertain information.** Use qualifiers for estimates, unverified claims, and inferred details.
231
+ - **Store source URLs.** Include the URLs you consulted, either in observations or a Sources section. This enables the user to verify and dig deeper.
232
+ - **Get approval before creating.** Present your findings and let the user decide whether to create the entity and what to include.
233
+ - **Capture user context.** If the user told you *why* they're researching (met at a conference, evaluating as a vendor, etc.), that context belongs in the entity.
234
+ - **Don't over-research.** 3-5 web searches is usually enough. The goal is a useful knowledge graph entry, not an exhaustive report.
235
+ - **Link to existing knowledge.** Relate the new entity to things already in the knowledge graph. Connections compound value.
@@ -113,9 +113,9 @@ Look for clusters of notes that share structure but have no schema:
113
113
  1. **Search by type**: `search_notes(query="type:Meeting")` — if many notes share a `type` but no `schema/Meeting.md` exists, it's a candidate.
114
114
 
115
115
  2. **Infer a schema**: Use `schema_infer` to analyze existing notes and generate a suggested schema:
116
- ```
116
+ ```python
117
117
  schema_infer(noteType="Meeting")
118
- schema_infer(noteType="Meeting", threshold=0.5) // fields in 50%+ of notes
118
+ schema_infer(noteType="Meeting", threshold=0.5) # fields in 50%+ of notes
119
119
  ```
120
120
  The threshold (0.0–1.0) controls how common a field must be to be included. Default is usually fine; lower it to catch rarer fields.
121
121
 
@@ -125,57 +125,57 @@ Look for clusters of notes that share structure but have no schema:
125
125
 
126
126
  Write the schema note to `schema/<EntityName>`:
127
127
 
128
- ```
128
+ ```python
129
129
  write_note(
130
- title="Meeting",
131
- folder="schema",
132
- content="---
133
- title: Meeting
134
- type: schema
135
- entity: Meeting
136
- version: 1
137
- schema:
138
- topic: string, what was discussed
139
- date: string, when it happened
140
- attendees?(array): Person, who attended
141
- decisions?(array): string, decisions made
142
- settings:
143
- validation: warn
144
- ---
145
-
146
- # Meeting
130
+ title="Meeting",
131
+ directory="schema",
132
+ note_type="schema",
133
+ metadata={
134
+ "entity": "Meeting",
135
+ "version": 1,
136
+ "schema": {
137
+ "topic": "string, what was discussed",
138
+ "date": "string, when it happened",
139
+ "attendees?(array)": "Person, who attended",
140
+ "decisions?(array)": "string, decisions made"
141
+ },
142
+ "settings": {"validation": "warn"}
143
+ },
144
+ content="""# Meeting
147
145
 
148
146
  Schema for meeting notes.
149
147
 
150
148
  ## Observations
151
149
  - [convention] Meeting notes live in memory/meetings/ or as daily entries
152
150
  - [convention] Always include date and topic
153
- - [convention] Action items should become tasks when complex",
151
+ - [convention] Action items should become tasks when complex"""
154
152
  )
155
153
  ```
156
154
 
157
155
  ### Key Principles
158
156
 
159
157
  - **Schema notes live in `schema/`** — one note per entity type
160
- - **`type: schema`** in frontmatter marks it as a schema definition
161
- - **`entity: Meeting`** names the type it applies to
162
- - **`version: 1`** — increment when making breaking changes
158
+ - **`note_type="schema"`** marks it as a schema definition
159
+ - **`entity: Meeting`** in metadata names the type it applies to
160
+ - **`version: 1`** in metadata — increment when making breaking changes
163
161
  - **`settings.validation: warn`** is recommended to start — it logs issues without blocking writes
164
162
 
165
163
  ## Validating Notes
166
164
 
167
165
  Check how well existing notes conform to their schema:
168
166
 
169
- ```
170
- // Validate all notes of a type
167
+ ```python
168
+ # Validate all notes of a type
171
169
  schema_validate(noteType="Meeting")
172
170
 
173
- // Validate a single note
171
+ # Validate a single note
174
172
  schema_validate(identifier="meetings/2026-02-10-standup")
175
173
  ```
176
174
 
175
+ **Important:** `schema_validate` checks for schema fields as **observation categories** in the note body — e.g., a `status` field expects `- [status] active` as an observation. Fields stored only in frontmatter metadata won't satisfy validation. To pass cleanly, include schema fields as both frontmatter values (for metadata search) and observations (for schema validation).
176
+
177
177
  Validation reports:
178
- - **Missing required fields** — the note lacks a field the schema requires
178
+ - **Missing required fields** — the note lacks a field the schema requires (as an observation category)
179
179
  - **Unknown fields** — the note has fields the schema doesn't define
180
180
  - **Type mismatches** — a field value doesn't match the expected type
181
181
  - **Invalid enum values** — a value isn't in the allowed set
@@ -189,7 +189,7 @@ Validation reports:
189
189
 
190
190
  Over time, notes evolve and schemas lag behind. Use `schema_diff` to find divergence:
191
191
 
192
- ```
192
+ ```python
193
193
  schema_diff(noteType="Meeting")
194
194
  ```
195
195
 
@@ -204,13 +204,13 @@ When note structure changes:
204
204
 
205
205
  1. **Run diff** to see current state: `schema_diff(noteType="Meeting")`
206
206
  2. **Update the schema note** via `edit_note`:
207
- ```
207
+ ```python
208
208
  edit_note(
209
- identifier="schema/Meeting",
210
- operation="find_replace",
211
- find_text="version: 1",
212
- content="version: 2",
213
- expected_replacements=1,
209
+ identifier="schema/Meeting",
210
+ operation="find_replace",
211
+ find_text="version: 1",
212
+ content="version: 2",
213
+ expected_replacements=1
214
214
  )
215
215
  ```
216
216
  3. **Add/remove/modify fields** in the `schema:` block
@@ -42,24 +42,26 @@ settings:
42
42
 
43
43
  ## Creating a Task
44
44
 
45
- When work qualifies, create a note in `memory/tasks/YYYY-MM-DD-short-name.md`:
46
-
47
- ```markdown
48
- ---
49
- title: Descriptive task name
50
- type: Task
51
- status: active
52
- created: YYYY-MM-DD
53
- current_step: 1
54
- ---
55
-
56
- # Descriptive task name
45
+ When work qualifies, create a task note. Use `write_note` with `note_type="Task"` and put queryable fields in `metadata`:
46
+
47
+ ```python
48
+ write_note(
49
+ title="Descriptive task name",
50
+ directory="tasks",
51
+ note_type="Task",
52
+ metadata={
53
+ "status": "active",
54
+ "priority": "high",
55
+ "current_step": 1,
56
+ "steps": ["First step", "Second step", "Third step"]
57
+ },
58
+ tags=["task"],
59
+ content="""# Descriptive task name
57
60
 
58
61
  ## Observations
59
62
  - [description] What needs to be done, concisely
60
63
  - [status] active
61
- - [assigned_to] claw
62
- - [started] YYYY-MM-DD
64
+ - [assigned_to] claude
63
65
  - [current_step] 1
64
66
 
65
67
  ## Steps
@@ -72,23 +74,27 @@ What future-you needs to pick up this work. Include:
72
74
  - Key file paths and repos involved
73
75
  - Decisions already made and why
74
76
  - What was tried and what worked/didn't
75
- - Where to look for related context
77
+ - Where to look for related context"""
78
+ )
76
79
  ```
77
80
 
81
+ **Why both frontmatter and observations?** Fields in `metadata` (stored as frontmatter) power `search_notes` with `metadata_filters`. Fields as observations (`- [status] active`) power `schema_validate`. Include queryable fields in both places for full coverage.
82
+
78
83
  ### Key Principles
79
84
 
80
85
  - **Steps are concrete and checkable** — "Implement X in file Y", not "figure out stuff"
81
86
  - **Context is for post-amnesia resumption** — Write it as if explaining to a smart person who knows nothing about what you've been doing
82
- - **Use observations for BM-queryable fields** — `[status]`, `[description]`, `[assigned_to]` etc. become searchable in the knowledge graph
83
87
  - **Relations link to other entities** — `parent_task [[Other Task]]`, `related_to [[Some Note]]`
88
+ - **`note_types` is case-sensitive** — `write_note(note_type="Task")` stores the type as lowercase `task` in frontmatter. Use `note_types=["task"]` (lowercase) in search queries.
84
89
 
85
90
  ## Resuming After Compaction
86
91
 
87
92
  On session start or after compaction:
88
93
 
89
94
  1. **Search for active tasks:**
90
- - Via BM: `search_notes("type:Task status:active")` or `search_notes("[status] active")`
91
- - Via memory_search: query "active tasks" (composited search includes task scanning)
95
+ ```python
96
+ search_notes(note_types=["task"], status="active")
97
+ ```
92
98
 
93
99
  2. **Read the task note** to get full context
94
100
 
@@ -129,7 +135,7 @@ Add a brief summary of what was accomplished and any follow-up needed.
129
135
 
130
136
  When a compaction event is imminent:
131
137
 
132
- 1. Find all active tasks: `search_notes("type:Task status:active")`
138
+ 1. Find all active tasks: `search_notes(note_types=["task"], status="active")`
133
139
  2. For each, update:
134
140
  - `current_step` to reflect actual progress
135
141
  - `context` with everything needed to resume
@@ -142,16 +148,14 @@ With BM's schema system, tasks are fully queryable:
142
148
 
143
149
  | Query | What it finds |
144
150
  |-------|--------------|
145
- | `search_notes("type:Task")` | All tasks |
146
- | `search_notes("[status] active")` | Active tasks |
147
- | `search_notes("[status] blocked")` | Blocked tasks |
148
- | `search_notes("[assigned_to] claw")` | My tasks |
149
- | `search_notes("type:Task [blockers]")` | Tasks with blockers |
151
+ | `search_notes(note_types=["task"])` | All tasks |
152
+ | `search_notes(note_types=["task"], status="active")` | Active tasks |
153
+ | `search_notes(note_types=["task"], status="blocked")` | Blocked tasks |
154
+ | `search_notes(note_types=["task"], metadata_filters={"assigned_to": "claude"})` | My tasks |
155
+ | `search_notes("blockers", note_types=["task"])` | Tasks with blockers |
150
156
  | `schema_validate(noteType="Task")` | Validate all tasks against schema |
151
157
  | `schema_diff(noteType="Task")` | Detect drift between schema and actual task notes |
152
158
 
153
- > **Plugin tools vs BM CLI**: The `schema_validate`, `schema_infer`, and `schema_diff` tools are available when using the `@openclaw/basic-memory` plugin. The raw `search_notes(...)` queries also work and are useful for ad-hoc filtering. `memory_search` composites results from all sources including active task scanning.
154
-
155
159
  ## Guidelines
156
160
 
157
161
  - **One task per unit of work** — Don't cram multiple projects into one task
@@ -159,4 +163,4 @@ With BM's schema system, tasks are fully queryable:
159
163
  - **Context > steps** — Steps tell you what to do; context tells you why and how
160
164
  - **Close finished tasks** — Don't leave completed work as `active`
161
165
  - **Link related tasks** — Use `parent_task [[X]]` or relations to connect related work
162
- - **Schema validation is your friend** — Run `bm schema validate Task` periodically to catch incomplete tasks
166
+ - **Schema validation is your friend** — Run `schema_validate(noteType="Task")` periodically to catch incomplete tasks