@deeplake/hivemind 0.7.17 → 0.7.19

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.
@@ -1027,7 +1027,8 @@ import {
1027
1027
  openSync as fsOpen,
1028
1028
  closeSync as fsClose,
1029
1029
  writeFileSync as fsWriteFile,
1030
- constants as fsConstants
1030
+ constants as fsConstants,
1031
+ renameSync as fsRename
1031
1032
  } from "node:fs";
1032
1033
  import { createHash } from "node:crypto";
1033
1034
  import { createRequire } from "node:module";
@@ -1070,7 +1071,7 @@ function extractLatestVersion(body) {
1070
1071
  return typeof v === "string" && v.length > 0 ? v : null;
1071
1072
  }
1072
1073
  function getInstalledVersion() {
1073
- return "0.7.17".length > 0 ? "0.7.17" : null;
1074
+ return "0.7.19".length > 0 ? "0.7.19" : null;
1074
1075
  }
1075
1076
  function isNewer(latest, current) {
1076
1077
  const parse = (v) => v.replace(/-.*$/, "").split(".").map(Number);
@@ -1175,17 +1176,33 @@ var capturedCounts = /* @__PURE__ */ new Map();
1175
1176
  var fallbackSessionId = crypto.randomUUID();
1176
1177
  var __openclaw_filename = fileURLToPath(import.meta.url);
1177
1178
  var __openclaw_dirname = dirnamePath(__openclaw_filename);
1178
- var OPENCLAW_SKILIFY_WORKER_PATH = joinPath(__openclaw_dirname, "skilify-worker.js");
1179
- var OPENCLAW_SKILIFY_STATE_DIR = joinPath(homedir2(), ".deeplake", "state", "skilify");
1179
+ var OPENCLAW_SKILLIFY_WORKER_PATH = joinPath(__openclaw_dirname, "skillify-worker.js");
1180
+ var OPENCLAW_SKILLIFY_STATE_DIR = joinPath(homedir2(), ".deeplake", "state", "skillify");
1181
+ var OPENCLAW_SKILLIFY_LEGACY_STATE_DIR = joinPath(homedir2(), ".deeplake", "state", "skilify");
1182
+ var openclawSkillifyMigrationAttempted = false;
1183
+ function migrateOpenclawSkillifyLegacyStateDir() {
1184
+ if (openclawSkillifyMigrationAttempted) return;
1185
+ openclawSkillifyMigrationAttempted = true;
1186
+ if (!fsExists(OPENCLAW_SKILLIFY_LEGACY_STATE_DIR)) return;
1187
+ if (fsExists(OPENCLAW_SKILLIFY_STATE_DIR)) return;
1188
+ try {
1189
+ fsRename(OPENCLAW_SKILLIFY_LEGACY_STATE_DIR, OPENCLAW_SKILLIFY_STATE_DIR);
1190
+ } catch (err) {
1191
+ const code = err.code;
1192
+ if (code === "EXDEV" || code === "EPERM") return;
1193
+ throw err;
1194
+ }
1195
+ }
1180
1196
  function deriveOpenclawProjectKey(channel) {
1181
1197
  const project = channel || "openclaw";
1182
1198
  const key = createHash("sha1").update(project).digest("hex").slice(0, 16);
1183
1199
  return { key, project };
1184
1200
  }
1185
- function tryAcquireOpenclawSkilifyLock(projectKey) {
1201
+ function tryAcquireOpenclawSkillifyLock(projectKey) {
1186
1202
  try {
1187
- fsMkdir(OPENCLAW_SKILIFY_STATE_DIR, { recursive: true });
1188
- const lockPath = joinPath(OPENCLAW_SKILIFY_STATE_DIR, `${projectKey}.worker.lock`);
1203
+ migrateOpenclawSkillifyLegacyStateDir();
1204
+ fsMkdir(OPENCLAW_SKILLIFY_STATE_DIR, { recursive: true });
1205
+ const lockPath = joinPath(OPENCLAW_SKILLIFY_STATE_DIR, `${projectKey}.worker.lock`);
1189
1206
  const fd = fsOpen(lockPath, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY);
1190
1207
  fsClose(fd);
1191
1208
  return true;
@@ -1210,25 +1227,25 @@ function detectOpenclawGateAgent() {
1210
1227
  }
1211
1228
  return null;
1212
1229
  }
1213
- function spawnOpenclawSkilifyWorker(a) {
1214
- if (!fsExists(OPENCLAW_SKILIFY_WORKER_PATH)) {
1215
- a.loggerWarn?.(`skilify worker missing at ${OPENCLAW_SKILIFY_WORKER_PATH} \u2014 reinstall openclaw plugin`);
1230
+ function spawnOpenclawSkillifyWorker(a) {
1231
+ if (!fsExists(OPENCLAW_SKILLIFY_WORKER_PATH)) {
1232
+ a.loggerWarn?.(`skillify worker missing at ${OPENCLAW_SKILLIFY_WORKER_PATH} \u2014 reinstall openclaw plugin`);
1216
1233
  return;
1217
1234
  }
1218
1235
  const gateAgent = detectOpenclawGateAgent();
1219
1236
  if (!gateAgent) {
1220
- a.loggerWarn?.(`skilify spawn: no delegate gate CLI found on PATH (need one of: claude, codex, cursor-agent, hermes, pi). Mining skipped.`);
1237
+ a.loggerWarn?.(`skillify spawn: no delegate gate CLI found on PATH (need one of: claude, codex, cursor-agent, hermes, pi). Mining skipped.`);
1221
1238
  return;
1222
1239
  }
1223
1240
  const { key: projectKey, project } = deriveOpenclawProjectKey(a.channel);
1224
- if (!tryAcquireOpenclawSkilifyLock(projectKey)) {
1241
+ if (!tryAcquireOpenclawSkillifyLock(projectKey)) {
1225
1242
  return;
1226
1243
  }
1227
- const tmpDir = joinPath(tmpdir(), `deeplake-skilify-openclaw-${projectKey}-${Date.now()}`);
1244
+ const tmpDir = joinPath(tmpdir(), `deeplake-skillify-openclaw-${projectKey}-${Date.now()}`);
1228
1245
  try {
1229
1246
  fsMkdir(tmpDir, { recursive: true, mode: 448 });
1230
1247
  } catch (e) {
1231
- a.loggerWarn?.(`skilify spawn: mkdir failed: ${e?.message ?? e}`);
1248
+ a.loggerWarn?.(`skillify spawn: mkdir failed: ${e?.message ?? e}`);
1232
1249
  return;
1233
1250
  }
1234
1251
  const configPath = joinPath(tmpDir, "config.json");
@@ -1256,23 +1273,23 @@ function spawnOpenclawSkilifyWorker(a) {
1256
1273
  cursorModel: void 0,
1257
1274
  hermesProvider: void 0,
1258
1275
  hermesModel: void 0,
1259
- skilifyLog: joinPath(homedir2(), ".deeplake", "hivemind-openclaw-skilify.log"),
1276
+ skillifyLog: joinPath(homedir2(), ".deeplake", "hivemind-openclaw-skillify.log"),
1260
1277
  currentSessionId: a.sessionId
1261
1278
  };
1262
1279
  try {
1263
1280
  fsWriteFile(configPath, JSON.stringify(config), { mode: 384 });
1264
1281
  } catch (e) {
1265
- a.loggerWarn?.(`skilify spawn: config write failed: ${e?.message ?? e}`);
1282
+ a.loggerWarn?.(`skillify spawn: config write failed: ${e?.message ?? e}`);
1266
1283
  return;
1267
1284
  }
1268
1285
  try {
1269
- realSpawn(process.execPath, [OPENCLAW_SKILIFY_WORKER_PATH, configPath], {
1286
+ realSpawn(process.execPath, [OPENCLAW_SKILLIFY_WORKER_PATH, configPath], {
1270
1287
  detached: true,
1271
1288
  stdio: "ignore",
1272
- env: { ...process.env, HIVEMIND_SKILIFY_WORKER: "1", HIVEMIND_CAPTURE: "false" }
1289
+ env: { ...process.env, HIVEMIND_SKILLIFY_WORKER: "1", HIVEMIND_CAPTURE: "false" }
1273
1290
  }).unref();
1274
1291
  } catch (e) {
1275
- a.loggerWarn?.(`skilify spawn: spawn failed: ${e?.message ?? e}`);
1292
+ a.loggerWarn?.(`skillify spawn: spawn failed: ${e?.message ?? e}`);
1276
1293
  }
1277
1294
  }
1278
1295
  function buildSessionPath(config, sessionId) {
@@ -1483,22 +1500,22 @@ ${available}` };
1483
1500
  handler: async () => {
1484
1501
  const { ensureHivemindAllowlisted } = await loadSetupConfig();
1485
1502
  const result = ensureHivemindAllowlisted();
1486
- const skilifyHint = `
1503
+ const skillifyHint = `
1487
1504
 
1488
- Skill mining (skilify) runs in the background after each turn \u2014 your conversations get crystallised into reusable skills automatically. From your terminal:
1489
- hivemind skilify status \u2014 see what's been mined
1490
- hivemind skilify pull \u2014 fetch teammates' skills`;
1505
+ Skill mining (skillify) runs in the background after each turn \u2014 your conversations get crystallised into reusable skills automatically. From your terminal:
1506
+ hivemind skillify status \u2014 see what's been mined
1507
+ hivemind skillify pull \u2014 fetch teammates' skills`;
1491
1508
  if (result.status === "already-set") {
1492
1509
  return { text: `\u2705 Hivemind tools are already enabled in your allowlist.
1493
1510
 
1494
- No changes needed \u2014 memory tools are available to the agent.${skilifyHint}` };
1511
+ No changes needed \u2014 memory tools are available to the agent.${skillifyHint}` };
1495
1512
  }
1496
1513
  if (result.status === "added") {
1497
1514
  return { text: `\u2705 Added "hivemind" to your tool allowlist.
1498
1515
 
1499
1516
  Openclaw will detect the config change and restart. On the next turn, the agent will have access to hivemind_search, hivemind_read, and hivemind_index.
1500
1517
 
1501
- Backup of previous config: ${result.backupPath}${skilifyHint}` };
1518
+ Backup of previous config: ${result.backupPath}${skillifyHint}` };
1502
1519
  }
1503
1520
  return { text: `\u26A0\uFE0F Could not update allowlist: ${result.error}
1504
1521
 
@@ -1745,7 +1762,7 @@ ${body.slice(0, 500)}`;
1745
1762
  const hook = (event, handler) => {
1746
1763
  pluginApi.on(event, handler);
1747
1764
  };
1748
- if ('---\nname: hivemind\ndescription: Global team and org memory powered by Activeloop. ALWAYS check BOTH built-in memory AND Hivemind memory when recalling information.\nallowed-tools: hivemind_search, hivemind_read, hivemind_index\n---\n\n# Hivemind Memory\n\nYou have TWO memory sources. ALWAYS check BOTH when the user asks you to recall, remember, or look up ANY information:\n\n1. **Your built-in memory** \u2014 personal per-project notes from the host agent\n2. **Hivemind global memory** \u2014 global memory shared across all sessions, users, and agents in the org, accessed via the tools below\n\n## Memory Structure\n\n```\n/index.md \u2190 START HERE \u2014 table of all sessions\n/summaries/\n <username>/\n <session-id>.md \u2190 AI-generated wiki summary per session\n/sessions/\n <username>/\n <user_org_ws_slug>.jsonl \u2190 raw session data\n```\n\n## How to Search\n\n1. **First**: call `hivemind_index()` \u2014 table of all sessions with dates, projects, descriptions\n2. **If you need details**: call `hivemind_read("/summaries/<username>/<session>.md")`\n3. **If you need raw data**: call `hivemind_read("/sessions/<username>/<file>.jsonl")`\n4. **Keyword search**: call `hivemind_search("keyword")` \u2014 substring search across both summaries and sessions, returns `path:line` hits\n\nDo NOT jump straight to reading raw JSONL files. Always start with `hivemind_index` and summaries.\n\n## Organization Management\n\n- `/hivemind_login` \u2014 sign in via device flow\n- `/hivemind_capture` \u2014 toggle capture on/off (off = no data sent)\n- `/hivemind_whoami` \u2014 show current org and workspace\n- `/hivemind_orgs` \u2014 list organizations\n- `/hivemind_switch_org <name-or-id>` \u2014 switch organization\n- `/hivemind_workspaces` \u2014 list workspaces\n- `/hivemind_switch_workspace <id>` \u2014 switch workspace\n- `/hivemind_version` \u2014 show installed version and check npm for updates\n- `/hivemind_update` \u2014 shows how to install (ask the agent, or run `hivemind update` in your terminal)\n- `/hivemind_autoupdate [on|off]` \u2014 toggle the agent-facing update nudge (on by default: when a newer version is available, the agent is prompted to install it via `exec` if you ask to update)\n\n## Skill Management (skilify)\n\nHivemind also mines reusable Claude skills from agent sessions and stores them in a per-org Deeplake table. Openclaw itself doesn\'t run sessions to mine, but you can pull skills others have already mined for the user. These run in the user\'s terminal (the openclaw plugin does not register them as `/hivemind_*` commands):\n\n- `hivemind skilify` \u2014 show scope/team/install + per-project state\n- `hivemind skilify pull` \u2014 sync skills for the current project from the org table\n- `hivemind skilify pull --user <email>` \u2014 only that author\'s skills\n- `hivemind skilify pull --users a,b,c` \u2014 multiple authors (CSV)\n- `hivemind skilify pull --all-users` \u2014 explicit "no author filter"\n- `hivemind skilify pull --to project|global` \u2014 install location (`<cwd>/.claude/skills/` vs `~/.claude/skills/`)\n- `hivemind skilify pull --dry-run` \u2014 preview without touching disk\n- `hivemind skilify pull --force` \u2014 overwrite local (creates `.bak`)\n- `hivemind skilify pull <skill-name>` \u2014 pull only that one skill (combines with `--user`)\n- `hivemind skilify unpull` \u2014 remove every skill previously installed by pull\n- `hivemind skilify unpull --user <email>` \u2014 remove only that author\'s pulls\n- `hivemind skilify unpull --not-mine` \u2014 remove all pulls except your own\n- `hivemind skilify unpull --dry-run` \u2014 preview without touching disk\n- `hivemind skilify scope <me|team|org>` \u2014 set sharing scope for new skills\n- `hivemind skilify install <project|global>` \u2014 default install location\n- `hivemind skilify team add|remove|list <name>` \u2014 manage team list\n\nIf the user asks to "pull skills from X", "share skills with the team", or similar, suggest the matching `hivemind skilify` command. Run `hivemind skilify --help` for the full reference.\n\n## Limits\n\nDo NOT delegate to subagents when reading Hivemind memory. If a tool call returns empty after 2 attempts, skip it and move on. Report what you found rather than exhaustively retrying.\n\n## Getting Started\n\nAfter installing the plugin:\n1. Run `/hivemind_login` to authenticate\n2. Run `/hivemind_setup` to enable the memory tools in your openclaw allowlist (one-time, per install)\n3. Start using memory \u2014 ask questions, the agent automatically captures and searches\n\n## Sharing memory\n\nMultiple agents share memory when users are in the same Activeloop organization.\n'.length > 0) {
1765
+ if ('---\nname: hivemind\ndescription: Global team and org memory powered by Activeloop. ALWAYS check BOTH built-in memory AND Hivemind memory when recalling information.\nallowed-tools: hivemind_search, hivemind_read, hivemind_index\n---\n\n# Hivemind Memory\n\nYou have TWO memory sources. ALWAYS check BOTH when the user asks you to recall, remember, or look up ANY information:\n\n1. **Your built-in memory** \u2014 personal per-project notes from the host agent\n2. **Hivemind global memory** \u2014 global memory shared across all sessions, users, and agents in the org, accessed via the tools below\n\n## Memory Structure\n\n```\n/index.md \u2190 START HERE \u2014 table of all sessions\n/summaries/\n <username>/\n <session-id>.md \u2190 AI-generated wiki summary per session\n/sessions/\n <username>/\n <user_org_ws_slug>.jsonl \u2190 raw session data\n```\n\n## How to Search\n\n1. **First**: call `hivemind_index()` \u2014 table of all sessions with dates, projects, descriptions\n2. **If you need details**: call `hivemind_read("/summaries/<username>/<session>.md")`\n3. **If you need raw data**: call `hivemind_read("/sessions/<username>/<file>.jsonl")`\n4. **Keyword search**: call `hivemind_search("keyword")` \u2014 substring search across both summaries and sessions, returns `path:line` hits\n\nDo NOT jump straight to reading raw JSONL files. Always start with `hivemind_index` and summaries.\n\n## Organization Management\n\n- `/hivemind_login` \u2014 sign in via device flow\n- `/hivemind_capture` \u2014 toggle capture on/off (off = no data sent)\n- `/hivemind_whoami` \u2014 show current org and workspace\n- `/hivemind_orgs` \u2014 list organizations\n- `/hivemind_switch_org <name-or-id>` \u2014 switch organization\n- `/hivemind_workspaces` \u2014 list workspaces\n- `/hivemind_switch_workspace <id>` \u2014 switch workspace\n- `/hivemind_version` \u2014 show installed version and check npm for updates\n- `/hivemind_update` \u2014 shows how to install (ask the agent, or run `hivemind update` in your terminal)\n- `/hivemind_autoupdate [on|off]` \u2014 toggle the agent-facing update nudge (on by default: when a newer version is available, the agent is prompted to install it via `exec` if you ask to update)\n\n## Skill Management (skillify)\n\nHivemind also mines reusable Claude skills from agent sessions and stores them in a per-org Deeplake table. Openclaw itself doesn\'t run sessions to mine, but you can pull skills others have already mined for the user. These run in the user\'s terminal (the openclaw plugin does not register them as `/hivemind_*` commands):\n\n- `hivemind skillify` \u2014 show scope/team/install + per-project state\n- `hivemind skillify pull` \u2014 sync skills for the current project from the org table\n- `hivemind skillify pull --user <email>` \u2014 only that author\'s skills\n- `hivemind skillify pull --users a,b,c` \u2014 multiple authors (CSV)\n- `hivemind skillify pull --all-users` \u2014 explicit "no author filter"\n- `hivemind skillify pull --to project|global` \u2014 install location (`<cwd>/.claude/skills/` vs `~/.claude/skills/`)\n- `hivemind skillify pull --dry-run` \u2014 preview without touching disk\n- `hivemind skillify pull --force` \u2014 overwrite local (creates `.bak`)\n- `hivemind skillify pull <skill-name>` \u2014 pull only that one skill (combines with `--user`)\n- `hivemind skillify unpull` \u2014 remove every skill previously installed by pull\n- `hivemind skillify unpull --user <email>` \u2014 remove only that author\'s pulls\n- `hivemind skillify unpull --not-mine` \u2014 remove all pulls except your own\n- `hivemind skillify unpull --dry-run` \u2014 preview without touching disk\n- `hivemind skillify scope <me|team|org>` \u2014 set sharing scope for new skills\n- `hivemind skillify install <project|global>` \u2014 default install location\n- `hivemind skillify team add|remove|list <name>` \u2014 manage team list\n\nIf the user asks to "pull skills from X", "share skills with the team", or similar, suggest the matching `hivemind skillify` command. Run `hivemind skillify --help` for the full reference.\n\n## Limits\n\nDo NOT delegate to subagents when reading Hivemind memory. If a tool call returns empty after 2 attempts, skip it and move on. Report what you found rather than exhaustively retrying.\n\n## Getting Started\n\nAfter installing the plugin:\n1. Run `/hivemind_login` to authenticate\n2. Run `/hivemind_setup` to enable the memory tools in your openclaw allowlist (one-time, per install)\n3. Start using memory \u2014 ask questions, the agent automatically captures and searches\n\n## Sharing memory\n\nMultiple agents share memory when users are in the same Activeloop organization.\n'.length > 0) {
1749
1766
  const setupConfigPromise = loadSetupConfig();
1750
1767
  hook("before_prompt_build", async () => {
1751
1768
  const { detectAllowlistMissing } = await setupConfigPromise;
@@ -1757,7 +1774,7 @@ A newer Hivemind version is available: ${pendingUpdate.current} \u2192 ${pending
1757
1774
  </hivemind-update-available>
1758
1775
  ` : "";
1759
1776
  return {
1760
- prependSystemContext: allowlistNudge + updateNudge + '\n\n<hivemind-skill>\n---\nname: hivemind\ndescription: Global team and org memory powered by Activeloop. ALWAYS check BOTH built-in memory AND Hivemind memory when recalling information.\nallowed-tools: hivemind_search, hivemind_read, hivemind_index\n---\n\n# Hivemind Memory\n\nYou have TWO memory sources. ALWAYS check BOTH when the user asks you to recall, remember, or look up ANY information:\n\n1. **Your built-in memory** \u2014 personal per-project notes from the host agent\n2. **Hivemind global memory** \u2014 global memory shared across all sessions, users, and agents in the org, accessed via the tools below\n\n## Memory Structure\n\n```\n/index.md \u2190 START HERE \u2014 table of all sessions\n/summaries/\n <username>/\n <session-id>.md \u2190 AI-generated wiki summary per session\n/sessions/\n <username>/\n <user_org_ws_slug>.jsonl \u2190 raw session data\n```\n\n## How to Search\n\n1. **First**: call `hivemind_index()` \u2014 table of all sessions with dates, projects, descriptions\n2. **If you need details**: call `hivemind_read("/summaries/<username>/<session>.md")`\n3. **If you need raw data**: call `hivemind_read("/sessions/<username>/<file>.jsonl")`\n4. **Keyword search**: call `hivemind_search("keyword")` \u2014 substring search across both summaries and sessions, returns `path:line` hits\n\nDo NOT jump straight to reading raw JSONL files. Always start with `hivemind_index` and summaries.\n\n## Organization Management\n\n- `/hivemind_login` \u2014 sign in via device flow\n- `/hivemind_capture` \u2014 toggle capture on/off (off = no data sent)\n- `/hivemind_whoami` \u2014 show current org and workspace\n- `/hivemind_orgs` \u2014 list organizations\n- `/hivemind_switch_org <name-or-id>` \u2014 switch organization\n- `/hivemind_workspaces` \u2014 list workspaces\n- `/hivemind_switch_workspace <id>` \u2014 switch workspace\n- `/hivemind_version` \u2014 show installed version and check npm for updates\n- `/hivemind_update` \u2014 shows how to install (ask the agent, or run `hivemind update` in your terminal)\n- `/hivemind_autoupdate [on|off]` \u2014 toggle the agent-facing update nudge (on by default: when a newer version is available, the agent is prompted to install it via `exec` if you ask to update)\n\n## Skill Management (skilify)\n\nHivemind also mines reusable Claude skills from agent sessions and stores them in a per-org Deeplake table. Openclaw itself doesn\'t run sessions to mine, but you can pull skills others have already mined for the user. These run in the user\'s terminal (the openclaw plugin does not register them as `/hivemind_*` commands):\n\n- `hivemind skilify` \u2014 show scope/team/install + per-project state\n- `hivemind skilify pull` \u2014 sync skills for the current project from the org table\n- `hivemind skilify pull --user <email>` \u2014 only that author\'s skills\n- `hivemind skilify pull --users a,b,c` \u2014 multiple authors (CSV)\n- `hivemind skilify pull --all-users` \u2014 explicit "no author filter"\n- `hivemind skilify pull --to project|global` \u2014 install location (`<cwd>/.claude/skills/` vs `~/.claude/skills/`)\n- `hivemind skilify pull --dry-run` \u2014 preview without touching disk\n- `hivemind skilify pull --force` \u2014 overwrite local (creates `.bak`)\n- `hivemind skilify pull <skill-name>` \u2014 pull only that one skill (combines with `--user`)\n- `hivemind skilify unpull` \u2014 remove every skill previously installed by pull\n- `hivemind skilify unpull --user <email>` \u2014 remove only that author\'s pulls\n- `hivemind skilify unpull --not-mine` \u2014 remove all pulls except your own\n- `hivemind skilify unpull --dry-run` \u2014 preview without touching disk\n- `hivemind skilify scope <me|team|org>` \u2014 set sharing scope for new skills\n- `hivemind skilify install <project|global>` \u2014 default install location\n- `hivemind skilify team add|remove|list <name>` \u2014 manage team list\n\nIf the user asks to "pull skills from X", "share skills with the team", or similar, suggest the matching `hivemind skilify` command. Run `hivemind skilify --help` for the full reference.\n\n## Limits\n\nDo NOT delegate to subagents when reading Hivemind memory. If a tool call returns empty after 2 attempts, skip it and move on. Report what you found rather than exhaustively retrying.\n\n## Getting Started\n\nAfter installing the plugin:\n1. Run `/hivemind_login` to authenticate\n2. Run `/hivemind_setup` to enable the memory tools in your openclaw allowlist (one-time, per install)\n3. Start using memory \u2014 ask questions, the agent automatically captures and searches\n\n## Sharing memory\n\nMultiple agents share memory when users are in the same Activeloop organization.\n\n</hivemind-skill>\n'
1777
+ prependSystemContext: allowlistNudge + updateNudge + '\n\n<hivemind-skill>\n---\nname: hivemind\ndescription: Global team and org memory powered by Activeloop. ALWAYS check BOTH built-in memory AND Hivemind memory when recalling information.\nallowed-tools: hivemind_search, hivemind_read, hivemind_index\n---\n\n# Hivemind Memory\n\nYou have TWO memory sources. ALWAYS check BOTH when the user asks you to recall, remember, or look up ANY information:\n\n1. **Your built-in memory** \u2014 personal per-project notes from the host agent\n2. **Hivemind global memory** \u2014 global memory shared across all sessions, users, and agents in the org, accessed via the tools below\n\n## Memory Structure\n\n```\n/index.md \u2190 START HERE \u2014 table of all sessions\n/summaries/\n <username>/\n <session-id>.md \u2190 AI-generated wiki summary per session\n/sessions/\n <username>/\n <user_org_ws_slug>.jsonl \u2190 raw session data\n```\n\n## How to Search\n\n1. **First**: call `hivemind_index()` \u2014 table of all sessions with dates, projects, descriptions\n2. **If you need details**: call `hivemind_read("/summaries/<username>/<session>.md")`\n3. **If you need raw data**: call `hivemind_read("/sessions/<username>/<file>.jsonl")`\n4. **Keyword search**: call `hivemind_search("keyword")` \u2014 substring search across both summaries and sessions, returns `path:line` hits\n\nDo NOT jump straight to reading raw JSONL files. Always start with `hivemind_index` and summaries.\n\n## Organization Management\n\n- `/hivemind_login` \u2014 sign in via device flow\n- `/hivemind_capture` \u2014 toggle capture on/off (off = no data sent)\n- `/hivemind_whoami` \u2014 show current org and workspace\n- `/hivemind_orgs` \u2014 list organizations\n- `/hivemind_switch_org <name-or-id>` \u2014 switch organization\n- `/hivemind_workspaces` \u2014 list workspaces\n- `/hivemind_switch_workspace <id>` \u2014 switch workspace\n- `/hivemind_version` \u2014 show installed version and check npm for updates\n- `/hivemind_update` \u2014 shows how to install (ask the agent, or run `hivemind update` in your terminal)\n- `/hivemind_autoupdate [on|off]` \u2014 toggle the agent-facing update nudge (on by default: when a newer version is available, the agent is prompted to install it via `exec` if you ask to update)\n\n## Skill Management (skillify)\n\nHivemind also mines reusable Claude skills from agent sessions and stores them in a per-org Deeplake table. Openclaw itself doesn\'t run sessions to mine, but you can pull skills others have already mined for the user. These run in the user\'s terminal (the openclaw plugin does not register them as `/hivemind_*` commands):\n\n- `hivemind skillify` \u2014 show scope/team/install + per-project state\n- `hivemind skillify pull` \u2014 sync skills for the current project from the org table\n- `hivemind skillify pull --user <email>` \u2014 only that author\'s skills\n- `hivemind skillify pull --users a,b,c` \u2014 multiple authors (CSV)\n- `hivemind skillify pull --all-users` \u2014 explicit "no author filter"\n- `hivemind skillify pull --to project|global` \u2014 install location (`<cwd>/.claude/skills/` vs `~/.claude/skills/`)\n- `hivemind skillify pull --dry-run` \u2014 preview without touching disk\n- `hivemind skillify pull --force` \u2014 overwrite local (creates `.bak`)\n- `hivemind skillify pull <skill-name>` \u2014 pull only that one skill (combines with `--user`)\n- `hivemind skillify unpull` \u2014 remove every skill previously installed by pull\n- `hivemind skillify unpull --user <email>` \u2014 remove only that author\'s pulls\n- `hivemind skillify unpull --not-mine` \u2014 remove all pulls except your own\n- `hivemind skillify unpull --dry-run` \u2014 preview without touching disk\n- `hivemind skillify scope <me|team|org>` \u2014 set sharing scope for new skills\n- `hivemind skillify install <project|global>` \u2014 default install location\n- `hivemind skillify team add|remove|list <name>` \u2014 manage team list\n\nIf the user asks to "pull skills from X", "share skills with the team", or similar, suggest the matching `hivemind skillify` command. Run `hivemind skillify --help` for the full reference.\n\n## Limits\n\nDo NOT delegate to subagents when reading Hivemind memory. If a tool call returns empty after 2 attempts, skip it and move on. Report what you found rather than exhaustively retrying.\n\n## Getting Started\n\nAfter installing the plugin:\n1. Run `/hivemind_login` to authenticate\n2. Run `/hivemind_setup` to enable the memory tools in your openclaw allowlist (one-time, per install)\n3. Start using memory \u2014 ask questions, the agent automatically captures and searches\n\n## Sharing memory\n\nMultiple agents share memory when users are in the same Activeloop organization.\n\n</hivemind-skill>\n'
1761
1778
  };
1762
1779
  });
1763
1780
  }
@@ -1876,7 +1893,7 @@ One brain for every agent on your team.
1876
1893
  }
1877
1894
  logger.info?.(`Auto-captured ${newMessages.length} messages`);
1878
1895
  try {
1879
- spawnOpenclawSkilifyWorker({
1896
+ spawnOpenclawSkillifyWorker({
1880
1897
  apiUrl: cfg.apiUrl,
1881
1898
  token: cfg.token,
1882
1899
  orgId: cfg.orgId,
@@ -1884,10 +1901,10 @@ One brain for every agent on your team.
1884
1901
  userName: cfg.userName,
1885
1902
  channel: ev.channel || "openclaw",
1886
1903
  sessionId: sid,
1887
- loggerWarn: (msg) => logger.error(`Skilify spawn: ${msg}`)
1904
+ loggerWarn: (msg) => logger.error(`Skillify spawn: ${msg}`)
1888
1905
  });
1889
1906
  } catch (e) {
1890
- logger.error(`Skilify spawn threw: ${e?.message ?? e}`);
1907
+ logger.error(`Skillify spawn threw: ${e?.message ?? e}`);
1891
1908
  }
1892
1909
  } catch (err) {
1893
1910
  logger.error(`Auto-capture failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // dist/src/skilify/skilify-worker.js
4
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync4, appendFileSync as appendFileSync2, rmSync } from "node:fs";
5
- import { join as join5 } from "node:path";
3
+ // dist/src/skillify/skillify-worker.js
4
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync5, appendFileSync as appendFileSync2, rmSync } from "node:fs";
5
+ import { join as join6 } from "node:path";
6
6
 
7
7
  // dist/src/utils/debug.js
8
8
  import { appendFileSync } from "node:fs";
@@ -29,7 +29,7 @@ function deeplakeClientHeader() {
29
29
  return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
30
30
  }
31
31
 
32
- // dist/src/skilify/extractors/index.js
32
+ // dist/src/skillify/extractors/index.js
33
33
  function extractPairs(rows) {
34
34
  const pairs = [];
35
35
  let pendingPrompt = null;
@@ -60,7 +60,7 @@ function extractPairs(rows) {
60
60
  return pairs;
61
61
  }
62
62
 
63
- // dist/src/skilify/skill-writer.js
63
+ // dist/src/skillify/skill-writer.js
64
64
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
65
65
  import { homedir as homedir2 } from "node:os";
66
66
  import { join as join2 } from "node:path";
@@ -216,7 +216,7 @@ function resolveSkillsRoot(install, cwd) {
216
216
  return join2(cwd, ".claude", "skills");
217
217
  }
218
218
 
219
- // dist/src/skilify/skills-table.js
219
+ // dist/src/skillify/skills-table.js
220
220
  import { randomUUID } from "node:crypto";
221
221
 
222
222
  // dist/src/utils/sql.js
@@ -227,7 +227,7 @@ function sqlIdent(name) {
227
227
  return name;
228
228
  }
229
229
 
230
- // dist/src/skilify/skills-table.js
230
+ // dist/src/skillify/skills-table.js
231
231
  function createSkillsTableSql(tableName) {
232
232
  const safe = sqlIdent(tableName);
233
233
  return `CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', name TEXT NOT NULL DEFAULT '', project TEXT NOT NULL DEFAULT '', project_key TEXT NOT NULL DEFAULT '', local_path TEXT NOT NULL DEFAULT '', install TEXT NOT NULL DEFAULT 'project', source_sessions TEXT NOT NULL DEFAULT '[]', source_agent TEXT NOT NULL DEFAULT '', scope TEXT NOT NULL DEFAULT 'me', author TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', trigger_text TEXT NOT NULL DEFAULT '', body TEXT NOT NULL DEFAULT '', version BIGINT NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT '') USING deeplake`;
@@ -256,7 +256,7 @@ async function insertSkillRow(args) {
256
256
  }
257
257
  }
258
258
 
259
- // dist/src/skilify/gate-parser.js
259
+ // dist/src/skillify/gate-parser.js
260
260
  function extractJsonBlock(s) {
261
261
  const trimmed = s.trim();
262
262
  if (!trimmed)
@@ -294,7 +294,7 @@ function parseVerdict(raw) {
294
294
  }
295
295
  }
296
296
 
297
- // dist/src/skilify/gate-runner.js
297
+ // dist/src/skillify/gate-runner.js
298
298
  import { execFileSync } from "node:child_process";
299
299
  import { existsSync as existsSync2 } from "node:fs";
300
300
  import { homedir as homedir3 } from "node:os";
@@ -403,28 +403,61 @@ function runGate(opts) {
403
403
  }
404
404
  }
405
405
 
406
- // dist/src/skilify/state.js
407
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, writeSync, mkdirSync as mkdirSync2, renameSync, existsSync as existsSync3, unlinkSync, openSync, closeSync } from "node:fs";
406
+ // dist/src/skillify/state.js
407
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, writeSync, mkdirSync as mkdirSync2, renameSync as renameSync2, existsSync as existsSync4, unlinkSync, openSync, closeSync } from "node:fs";
408
408
  import { execSync } from "node:child_process";
409
- import { homedir as homedir4 } from "node:os";
409
+ import { homedir as homedir5 } from "node:os";
410
410
  import { createHash } from "node:crypto";
411
- import { join as join4, basename } from "node:path";
412
- var dlog = (msg) => log("skilify-state", msg);
413
- var STATE_DIR = join4(homedir4(), ".deeplake", "state", "skilify");
411
+ import { join as join5, basename } from "node:path";
412
+
413
+ // dist/src/skillify/legacy-migration.js
414
+ import { existsSync as existsSync3, renameSync } from "node:fs";
415
+ import { homedir as homedir4 } from "node:os";
416
+ import { join as join4 } from "node:path";
417
+ var dlog = (msg) => log("skillify-migrate", msg);
418
+ var attempted = false;
419
+ function migrateLegacyStateDir() {
420
+ if (attempted)
421
+ return;
422
+ attempted = true;
423
+ const root = join4(homedir4(), ".deeplake", "state");
424
+ const legacy = join4(root, "skilify");
425
+ const current = join4(root, "skillify");
426
+ if (!existsSync3(legacy))
427
+ return;
428
+ if (existsSync3(current))
429
+ return;
430
+ try {
431
+ renameSync(legacy, current);
432
+ dlog(`migrated ${legacy} -> ${current}`);
433
+ } catch (err) {
434
+ const code = err.code;
435
+ if (code === "EXDEV" || code === "EPERM") {
436
+ dlog(`migration failed (${code}); leaving legacy dir in place`);
437
+ return;
438
+ }
439
+ throw err;
440
+ }
441
+ }
442
+
443
+ // dist/src/skillify/state.js
444
+ var dlog2 = (msg) => log("skillify-state", msg);
445
+ var STATE_DIR = join5(homedir5(), ".deeplake", "state", "skillify");
414
446
  var YIELD_BUF = new Int32Array(new SharedArrayBuffer(4));
415
447
  var TRIGGER_THRESHOLD = (() => {
416
- const n = Number(process.env.HIVEMIND_SKILIFY_EVERY_N_TURNS ?? "");
448
+ const n = Number(process.env.HIVEMIND_SKILLIFY_EVERY_N_TURNS ?? "");
417
449
  return Number.isInteger(n) && n > 0 ? n : 20;
418
450
  })();
419
451
  function statePath(projectKey) {
420
- return join4(STATE_DIR, `${projectKey}.json`);
452
+ return join5(STATE_DIR, `${projectKey}.json`);
421
453
  }
422
454
  function lockPath(projectKey) {
423
- return join4(STATE_DIR, `${projectKey}.lock`);
455
+ return join5(STATE_DIR, `${projectKey}.lock`);
424
456
  }
425
457
  function readState(projectKey) {
458
+ migrateLegacyStateDir();
426
459
  const p = statePath(projectKey);
427
- if (!existsSync3(p))
460
+ if (!existsSync4(p))
428
461
  return null;
429
462
  try {
430
463
  return JSON.parse(readFileSync2(p, "utf-8"));
@@ -433,13 +466,15 @@ function readState(projectKey) {
433
466
  }
434
467
  }
435
468
  function writeState(projectKey, state) {
469
+ migrateLegacyStateDir();
436
470
  mkdirSync2(STATE_DIR, { recursive: true });
437
471
  const p = statePath(projectKey);
438
472
  const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
439
473
  writeFileSync2(tmp, JSON.stringify(state, null, 2));
440
- renameSync(tmp, p);
474
+ renameSync2(tmp, p);
441
475
  }
442
476
  function withRmwLock(projectKey, fn) {
477
+ migrateLegacyStateDir();
443
478
  mkdirSync2(STATE_DIR, { recursive: true });
444
479
  const rmw = lockPath(projectKey) + ".rmw";
445
480
  const deadline = Date.now() + 2e3;
@@ -451,11 +486,11 @@ function withRmwLock(projectKey, fn) {
451
486
  if (e.code !== "EEXIST")
452
487
  throw e;
453
488
  if (Date.now() > deadline) {
454
- dlog(`rmw lock deadline exceeded for ${projectKey}, reclaiming stale lock`);
489
+ dlog2(`rmw lock deadline exceeded for ${projectKey}, reclaiming stale lock`);
455
490
  try {
456
491
  unlinkSync(rmw);
457
492
  } catch (unlinkErr) {
458
- dlog(`stale rmw lock unlink failed for ${projectKey}: ${unlinkErr.message}`);
493
+ dlog2(`stale rmw lock unlink failed for ${projectKey}: ${unlinkErr.message}`);
459
494
  }
460
495
  continue;
461
496
  }
@@ -469,7 +504,7 @@ function withRmwLock(projectKey, fn) {
469
504
  try {
470
505
  unlinkSync(rmw);
471
506
  } catch (unlinkErr) {
472
- dlog(`rmw lock cleanup failed for ${projectKey}: ${unlinkErr.message}`);
507
+ dlog2(`rmw lock cleanup failed for ${projectKey}: ${unlinkErr.message}`);
473
508
  }
474
509
  }
475
510
  }
@@ -509,18 +544,18 @@ function releaseWorkerLock(projectKey) {
509
544
  }
510
545
  }
511
546
 
512
- // dist/src/skilify/skilify-worker.js
547
+ // dist/src/skillify/skillify-worker.js
513
548
  var cfg = JSON.parse(readFileSync3(process.argv[2], "utf-8"));
514
549
  var tmpDir = cfg.tmpDir;
515
- var verdictPath = join5(tmpDir, "verdict.json");
516
- var promptPath = join5(tmpDir, "prompt.txt");
550
+ var verdictPath = join6(tmpDir, "verdict.json");
551
+ var promptPath = join6(tmpDir, "prompt.txt");
517
552
  var SESSIONS_TO_MINE = 10;
518
553
  var PAIR_CHAR_CAP = 2e3;
519
554
  var TOTAL_PAIRS_CHAR_CAP = 4e4;
520
555
  var EXISTING_SKILLS_CHAR_CAP = 3e4;
521
556
  function wlog(msg) {
522
557
  try {
523
- appendFileSync2(cfg.skilifyLog, `[${utcTimestamp()}] skilify-worker(${cfg.projectKey}): ${msg}
558
+ appendFileSync2(cfg.skillifyLog, `[${utcTimestamp()}] skillify-worker(${cfg.projectKey}): ${msg}
524
559
  `);
525
560
  } catch {
526
561
  }
@@ -715,7 +750,7 @@ function buildPrompt(pairs) {
715
750
  ].join("\n");
716
751
  }
717
752
  function readVerdict(stdout) {
718
- if (existsSync4(verdictPath)) {
753
+ if (existsSync5(verdictPath)) {
719
754
  try {
720
755
  const text = readFileSync3(verdictPath, "utf-8");
721
756
  const v2 = parseVerdict(text);
@@ -784,9 +819,9 @@ async function main() {
784
819
  timeoutMs: 12e4
785
820
  });
786
821
  try {
787
- writeFileSync3(join5(tmpDir, "gate-stdout.txt"), gate.stdout);
822
+ writeFileSync3(join6(tmpDir, "gate-stdout.txt"), gate.stdout);
788
823
  if (gate.stderr)
789
- writeFileSync3(join5(tmpDir, "gate-stderr.txt"), gate.stderr);
824
+ writeFileSync3(join6(tmpDir, "gate-stderr.txt"), gate.stderr);
790
825
  } catch {
791
826
  }
792
827
  if (gate.errored) {
@@ -52,5 +52,5 @@
52
52
  }
53
53
  }
54
54
  },
55
- "version": "0.7.17"
55
+ "version": "0.7.19"
56
56
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hivemind",
3
- "version": "0.7.17",
3
+ "version": "0.7.19",
4
4
  "type": "module",
5
5
  "description": "Hivemind — cloud-backed persistent shared memory for AI agents, powered by DeepLake",
6
6
  "license": "Apache-2.0",
@@ -45,28 +45,28 @@ Do NOT jump straight to reading raw JSONL files. Always start with `hivemind_ind
45
45
  - `/hivemind_update` — shows how to install (ask the agent, or run `hivemind update` in your terminal)
46
46
  - `/hivemind_autoupdate [on|off]` — toggle the agent-facing update nudge (on by default: when a newer version is available, the agent is prompted to install it via `exec` if you ask to update)
47
47
 
48
- ## Skill Management (skilify)
48
+ ## Skill Management (skillify)
49
49
 
50
50
  Hivemind also mines reusable Claude skills from agent sessions and stores them in a per-org Deeplake table. Openclaw itself doesn't run sessions to mine, but you can pull skills others have already mined for the user. These run in the user's terminal (the openclaw plugin does not register them as `/hivemind_*` commands):
51
51
 
52
- - `hivemind skilify` — show scope/team/install + per-project state
53
- - `hivemind skilify pull` — sync skills for the current project from the org table
54
- - `hivemind skilify pull --user <email>` — only that author's skills
55
- - `hivemind skilify pull --users a,b,c` — multiple authors (CSV)
56
- - `hivemind skilify pull --all-users` — explicit "no author filter"
57
- - `hivemind skilify pull --to project|global` — install location (`<cwd>/.claude/skills/` vs `~/.claude/skills/`)
58
- - `hivemind skilify pull --dry-run` — preview without touching disk
59
- - `hivemind skilify pull --force` — overwrite local (creates `.bak`)
60
- - `hivemind skilify pull <skill-name>` — pull only that one skill (combines with `--user`)
61
- - `hivemind skilify unpull` — remove every skill previously installed by pull
62
- - `hivemind skilify unpull --user <email>` — remove only that author's pulls
63
- - `hivemind skilify unpull --not-mine` — remove all pulls except your own
64
- - `hivemind skilify unpull --dry-run` — preview without touching disk
65
- - `hivemind skilify scope <me|team|org>` — set sharing scope for new skills
66
- - `hivemind skilify install <project|global>` — default install location
67
- - `hivemind skilify team add|remove|list <name>` — manage team list
68
-
69
- If the user asks to "pull skills from X", "share skills with the team", or similar, suggest the matching `hivemind skilify` command. Run `hivemind skilify --help` for the full reference.
52
+ - `hivemind skillify` — show scope/team/install + per-project state
53
+ - `hivemind skillify pull` — sync skills for the current project from the org table
54
+ - `hivemind skillify pull --user <email>` — only that author's skills
55
+ - `hivemind skillify pull --users a,b,c` — multiple authors (CSV)
56
+ - `hivemind skillify pull --all-users` — explicit "no author filter"
57
+ - `hivemind skillify pull --to project|global` — install location (`<cwd>/.claude/skills/` vs `~/.claude/skills/`)
58
+ - `hivemind skillify pull --dry-run` — preview without touching disk
59
+ - `hivemind skillify pull --force` — overwrite local (creates `.bak`)
60
+ - `hivemind skillify pull <skill-name>` — pull only that one skill (combines with `--user`)
61
+ - `hivemind skillify unpull` — remove every skill previously installed by pull
62
+ - `hivemind skillify unpull --user <email>` — remove only that author's pulls
63
+ - `hivemind skillify unpull --not-mine` — remove all pulls except your own
64
+ - `hivemind skillify unpull --dry-run` — preview without touching disk
65
+ - `hivemind skillify scope <me|team|org>` — set sharing scope for new skills
66
+ - `hivemind skillify install <project|global>` — default install location
67
+ - `hivemind skillify team add|remove|list <name>` — manage team list
68
+
69
+ If the user asks to "pull skills from X", "share skills with the team", or similar, suggest the matching `hivemind skillify` command. Run `hivemind skillify --help` for the full reference.
70
70
 
71
71
  ## Limits
72
72
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeplake/hivemind",
3
- "version": "0.7.17",
3
+ "version": "0.7.19",
4
4
  "description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
5
5
  "type": "module",
6
6
  "repository": {