@basicmemory/openclaw-basic-memory 0.1.0-alpha.8 → 0.1.0-alpha.9

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 CHANGED
@@ -137,7 +137,7 @@ This installs to the same `skills/` directory the plugin reads from, so updated
137
137
  }
138
138
  ```
139
139
 
140
- This uses sensible defaults: auto-generated project name, maps Basic Memory to your workspace `memory/` directory, and captures conversations.
140
+ This uses sensible defaults: auto-generated project name, maps Basic Memory to your workspace root, sets it as the default BM project, and captures conversations.
141
141
 
142
142
  ### Full configuration
143
143
  ```json5
@@ -147,7 +147,7 @@ This uses sensible defaults: auto-generated project name, maps Basic Memory to y
147
147
  config: {
148
148
  project: "my-agent", // BM project name (default: "openclaw-{hostname}")
149
149
  bmPath: "bm", // Path to BM CLI binary
150
- projectPath: "~/.openclaw/workspace/memory/", // Optional override; supports absolute, ~/..., or workspace-relative paths
150
+ projectPath: ".", // Defaults to workspace root; supports absolute, ~/..., or workspace-relative paths
151
151
  memoryDir: "memory/", // Relative memory dir for task scanning
152
152
  memoryFile: "MEMORY.md", // Working memory file for grep search
153
153
  autoCapture: true, // Index conversations automatically
@@ -166,7 +166,7 @@ This uses sensible defaults: auto-generated project name, maps Basic Memory to y
166
166
  |--------|------|---------|-------------|
167
167
  | `project` | string | `"openclaw-{hostname}"` | Basic Memory project name |
168
168
  | `bmPath` | string | `"bm"` | Path to Basic Memory CLI binary |
169
- | `projectPath` | string | `"memory/"` | Directory for BM project data (resolved from workspace unless absolute) |
169
+ | `projectPath` | string | `"."` | Directory for BM project data (defaults to workspace root; resolved from workspace unless absolute) |
170
170
  | `memoryDir` | string | `"memory/"` | Relative path for task scanning |
171
171
  | `memoryFile` | string | `"MEMORY.md"` | Working memory file (grep-searched) |
172
172
  | `autoCapture` | boolean | `true` | Auto-index agent conversations |
@@ -179,7 +179,7 @@ Snake_case aliases (`memory_dir`, `memory_file`, `auto_recall`, `recall_prompt`,
179
179
 
180
180
  Cloud sync is optional — see [BASIC_MEMORY.md](./BASIC_MEMORY.md) for cloud configuration.
181
181
 
182
- On startup, the plugin ensures the configured BM project exists at `projectPath` via MCP `create_memory_project` in idempotent mode.
182
+ On startup, the plugin ensures the configured BM project exists at `projectPath` via MCP `create_memory_project` in idempotent mode, and sets it as the default Basic Memory project.
183
183
 
184
184
  ## How It Works
185
185
 
@@ -453,6 +453,17 @@ rm -rf /tmp/jiti/ "$TMPDIR/jiti/"
453
453
  openclaw gateway stop && openclaw gateway start
454
454
  ```
455
455
 
456
+ ### Disabling semantic search
457
+ If you want to run without vector/embedding dependencies (faster startup, less memory), set the environment variable before launching:
458
+ ```bash
459
+ BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED=false
460
+ ```
461
+ Or in `~/.basic-memory/config.json`:
462
+ ```json
463
+ { "semantic_search_enabled": false }
464
+ ```
465
+ Search will fall back to full-text search only.
466
+
456
467
  ### Search returns no results
457
468
  1. Check that the MCP session is connected (look for `connected to BM MCP stdio` in logs)
458
469
  2. Verify files exist in the project directory
@@ -531,9 +542,7 @@ just release patch # or: minor, major, 0.2.0, etc.
531
542
  4. publish to npm
532
543
  5. create a GitHub release
533
544
 
534
- Repository secret required:
535
-
536
- - `NPM_TOKEN` (npm publish token with package publish permissions)
545
+ Publishing uses npm OIDC trusted publishing — no secrets required. The trusted publisher is configured on npmjs.com to accept provenance from this repo's `release.yml` workflow.
537
546
 
538
547
  ### Project Structure
539
548
  ```
@@ -564,6 +573,33 @@ openclaw-basic-memory/
564
573
  └── recall.ts # Auto-recall (active tasks + recent activity)
565
574
  ```
566
575
 
576
+ ## Telemetry
577
+
578
+ This plugin collects anonymous, minimal usage events to understand plugin adoption and tool usage patterns. This helps us prioritize features and improve the product.
579
+
580
+ **What we collect:**
581
+ - Plugin registration and startup events
582
+ - First use of each tool per session (deduplicated — not every call)
583
+ - Plugin version with each event
584
+
585
+ **What we do NOT collect:**
586
+ - No file contents, note titles, search queries, or conversation text
587
+ - No personally identifiable information (PII)
588
+ - No IP address tracking or fingerprinting
589
+ - No per-command tracking beyond first-use-per-session
590
+
591
+ Events are sent to our [Umami Cloud](https://umami.is) instance, an open-source, privacy-focused analytics platform. Events are fire-and-forget with a 3-second timeout — analytics never blocks or slows the plugin.
592
+
593
+ **Opt out** by setting either environment variable:
594
+
595
+ ```bash
596
+ # Plugin-specific opt-out
597
+ export OPENCLAW_BASIC_MEMORY_TELEMETRY=0
598
+
599
+ # Or use the shared Basic Memory opt-out (also disables BM CLI telemetry)
600
+ export BASIC_MEMORY_NO_PROMOS=1
601
+ ```
602
+
567
603
  ## License
568
604
 
569
605
  MIT — see LICENSE file.
package/analytics.ts ADDED
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Lightweight analytics via Umami event collector.
3
+ *
4
+ * Sends anonymous, non-blocking usage events to help understand plugin adoption
5
+ * and tool usage patterns. No PII, no fingerprinting, no cookies.
6
+ *
7
+ * Events are fire-and-forget — analytics never blocks or breaks the plugin.
8
+ *
9
+ * Defaults point to the Basic Memory Umami Cloud instance. Override via:
10
+ * BASIC_MEMORY_UMAMI_HOST — Custom Umami instance URL
11
+ * BASIC_MEMORY_UMAMI_SITE_ID — Custom Website ID
12
+ * Opt out entirely with OPENCLAW_BASIC_MEMORY_TELEMETRY=0 or BASIC_MEMORY_NO_PROMOS=1.
13
+ */
14
+
15
+ import { readFileSync } from "node:fs"
16
+ import { join } from "node:path"
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Configuration
20
+ // ---------------------------------------------------------------------------
21
+
22
+ const DEFAULT_UMAMI_HOST = "https://cloud.umami.is"
23
+ const DEFAULT_UMAMI_SITE_ID = "f6479898-ebaf-4e60-bce2-6dc60a3f6c5c"
24
+ const SEND_TIMEOUT_MS = 3000
25
+
26
+ function umamiHost(): string {
27
+ return process.env.BASIC_MEMORY_UMAMI_HOST?.trim() || DEFAULT_UMAMI_HOST
28
+ }
29
+
30
+ function umamiSiteId(): string {
31
+ return process.env.BASIC_MEMORY_UMAMI_SITE_ID?.trim() || DEFAULT_UMAMI_SITE_ID
32
+ }
33
+
34
+ export function analyticsDisabled(): boolean {
35
+ // Plugin-specific opt-out
36
+ const telemetry = (process.env.OPENCLAW_BASIC_MEMORY_TELEMETRY ?? "")
37
+ .trim()
38
+ .toLowerCase()
39
+ if (telemetry === "0" || telemetry === "false" || telemetry === "no") {
40
+ return true
41
+ }
42
+
43
+ // Shared Basic Memory opt-out (also disables BM CLI analytics)
44
+ const noPromos = (process.env.BASIC_MEMORY_NO_PROMOS ?? "")
45
+ .trim()
46
+ .toLowerCase()
47
+ return noPromos === "1" || noPromos === "true" || noPromos === "yes"
48
+ }
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Version
52
+ // ---------------------------------------------------------------------------
53
+
54
+ let _cachedVersion: string | null = null
55
+
56
+ function getVersion(): string {
57
+ if (_cachedVersion) return _cachedVersion
58
+ try {
59
+ const pkg = JSON.parse(
60
+ readFileSync(
61
+ join(import.meta.dirname ?? __dirname, "package.json"),
62
+ "utf-8",
63
+ ),
64
+ )
65
+ _cachedVersion = pkg.version ?? "unknown"
66
+ } catch {
67
+ _cachedVersion = "unknown"
68
+ }
69
+ return _cachedVersion ?? "unknown"
70
+ }
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Session-scoped dedup for tool calls
74
+ // ---------------------------------------------------------------------------
75
+
76
+ const _trackedTools = new Set<string>()
77
+
78
+ export function resetTrackedTools(): void {
79
+ _trackedTools.clear()
80
+ }
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // Event constants
84
+ // ---------------------------------------------------------------------------
85
+
86
+ export const EVENT_PLUGIN_INSTALLED = "openclaw-plugin-installed"
87
+ export const EVENT_PLUGIN_STARTED = "openclaw-plugin-started"
88
+ export const EVENT_TOOL_CALL = "openclaw-tool-call"
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // Public API
92
+ // ---------------------------------------------------------------------------
93
+
94
+ /**
95
+ * Send an analytics event to Umami. Non-blocking, silent on failure.
96
+ *
97
+ * @param eventName - Short kebab-case name (e.g. "openclaw-plugin-started")
98
+ * @param data - Optional dict of event properties (string/number values)
99
+ */
100
+ export function track(
101
+ eventName: string,
102
+ data?: Record<string, string | number>,
103
+ ): void {
104
+ if (analyticsDisabled()) return
105
+
106
+ const host = umamiHost()
107
+ const siteId = umamiSiteId()
108
+
109
+ const payload = {
110
+ payload: {
111
+ hostname: "openclaw.basicmemory.com",
112
+ language: "en",
113
+ url: `/openclaw/${eventName}`,
114
+ website: siteId,
115
+ name: eventName,
116
+ data: {
117
+ version: getVersion(),
118
+ ...(data ?? {}),
119
+ },
120
+ },
121
+ }
122
+
123
+ // Fire-and-forget — never block the plugin
124
+ _sendPayload(host, payload).catch(() => {})
125
+ }
126
+
127
+ /**
128
+ * Track a tool call, deduped per tool name per session.
129
+ * Only the first invocation of each tool sends an event.
130
+ */
131
+ export function trackToolCall(toolName: string): void {
132
+ if (analyticsDisabled()) return
133
+ if (_trackedTools.has(toolName)) return
134
+ _trackedTools.add(toolName)
135
+ track(EVENT_TOOL_CALL, { tool: toolName })
136
+ }
137
+
138
+ // ---------------------------------------------------------------------------
139
+ // Internal send (exported for testing)
140
+ // ---------------------------------------------------------------------------
141
+
142
+ export async function _sendPayload(
143
+ host: string,
144
+ payload: unknown,
145
+ ): Promise<void> {
146
+ const controller = new AbortController()
147
+ const timer = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS)
148
+
149
+ try {
150
+ await fetch(`${host}/api/send`, {
151
+ method: "POST",
152
+ headers: {
153
+ "Content-Type": "application/json",
154
+ "User-Agent": `openclaw-basic-memory/${getVersion()}`,
155
+ },
156
+ body: JSON.stringify(payload),
157
+ signal: controller.signal,
158
+ })
159
+ } finally {
160
+ clearTimeout(timer)
161
+ }
162
+ }
package/bm-client.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { setTimeout as delay } from "node:timers/promises"
2
2
  import { Client } from "@modelcontextprotocol/sdk/client"
3
3
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
4
+ import { trackToolCall } from "./analytics.ts"
4
5
  import { log } from "./logger.ts"
5
6
 
6
7
  const DEFAULT_RETRY_DELAYS_MS = [500, 1000, 2000]
@@ -449,6 +450,7 @@ export class BmClient {
449
450
  name: string,
450
451
  args: Record<string, unknown>,
451
452
  ): Promise<unknown> {
453
+ trackToolCall(name)
452
454
  const result = await this.callToolRaw(name, args)
453
455
 
454
456
  if (!isRecord(result) || result.structuredContent === undefined) {
package/config.ts CHANGED
@@ -137,7 +137,7 @@ export function parseConfig(raw: unknown): BasicMemoryConfig {
137
137
  projectPath:
138
138
  typeof cfg.projectPath === "string" && cfg.projectPath.length > 0
139
139
  ? cfg.projectPath
140
- : memoryDir,
140
+ : ".",
141
141
  bmPath:
142
142
  typeof cfg.bmPath === "string" && cfg.bmPath.length > 0
143
143
  ? cfg.bmPath
package/index.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import type { Server } from "node:http"
2
2
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk"
3
+ import {
4
+ EVENT_PLUGIN_INSTALLED,
5
+ EVENT_PLUGIN_STARTED,
6
+ track,
7
+ } from "./analytics.ts"
3
8
  import { BmClient } from "./bm-client.ts"
4
9
  import { registerCli } from "./commands/cli.ts"
5
10
  import { registerSkillCommands } from "./commands/skills.ts"
@@ -48,6 +53,8 @@ export default {
48
53
  `project=${cfg.project} memoryDir=${cfg.memoryDir} memoryFile=${cfg.memoryFile}`,
49
54
  )
50
55
 
56
+ track(EVENT_PLUGIN_INSTALLED)
57
+
51
58
  const client = new BmClient(cfg.bmPath, cfg.project)
52
59
 
53
60
  // --- BM Tools (always registered) ---
@@ -125,6 +132,7 @@ export default {
125
132
  })
126
133
  }
127
134
 
135
+ track(EVENT_PLUGIN_STARTED, { project: cfg.project })
128
136
  log.info("connected — BM MCP stdio session running")
129
137
  },
130
138
  stop: async () => {
@@ -48,8 +48,8 @@
48
48
  },
49
49
  "projectPath": {
50
50
  "label": "Project Path",
51
- "placeholder": "~/.openclaw/workspace/memory/",
52
- "help": "Filesystem path for Basic Memory project data (relative paths resolve from workspace); created automatically if missing",
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": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basicmemory/openclaw-basic-memory",
3
- "version": "0.1.0-alpha.8",
3
+ "version": "0.1.0-alpha.9",
4
4
  "type": "module",
5
5
  "description": "Basic Memory plugin for OpenClaw — local-first knowledge graph for agent memory",
6
6
  "license": "MIT",
@@ -9,6 +9,7 @@
9
9
  "url": "https://github.com/basicmachines-co/openclaw-basic-memory"
10
10
  },
11
11
  "files": [
12
+ "analytics.ts",
12
13
  "index.ts",
13
14
  "bm-client.ts",
14
15
  "config.ts",
@@ -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[semantic] ────────────────────────────────
18
+ # ── install basic-memory ────────────────────────────────
19
19
  echo "Installing basic-memory from ${BM_REPO}@${BM_REF} ..."
20
20
  uv tool install \
21
- "basic-memory[semantic] @ git+${BM_REPO}@${BM_REF}" \
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 ────────────────────────────────────────────────────────