@deeplake/hivemind 0.7.67 → 0.7.69

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.
@@ -6,18 +6,18 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
9
- "version": "0.7.67"
9
+ "version": "0.7.69"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "hivemind",
14
14
  "description": "Persistent shared memory powered by Deeplake — captures all session activity and provides cross-session, cross-agent memory search",
15
- "version": "0.7.67",
15
+ "version": "0.7.69",
16
16
  "source": {
17
17
  "source": "git-subdir",
18
18
  "url": "https://github.com/activeloopai/hivemind.git",
19
19
  "path": "claude-code",
20
- "sha": "7d1de6ab6b8a13bc52305e69d1a8ccc0b6e4d92a"
20
+ "sha": "fcce30444cbb853f2f6748aaf7422abbcf3e774a"
21
21
  },
22
22
  "homepage": "https://github.com/activeloopai/hivemind"
23
23
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hivemind",
3
3
  "description": "Cloud-backed persistent memory powered by Deeplake — read, write, and share memory across Claude Code sessions and agents",
4
- "version": "0.7.67",
4
+ "version": "0.7.69",
5
5
  "author": {
6
6
  "name": "Activeloop",
7
7
  "url": "https://deeplake.ai"
package/README.md CHANGED
@@ -173,6 +173,20 @@ git clone https://github.com/activeloopai/hivemind.git ~/.codex/hivemind
173
173
  ```
174
174
 
175
175
  Restart Codex to activate.
176
+
177
+ **First launch — trust the hooks.** Codex shows a **"Hooks need review"** prompt before it will run hivemind's hooks:
178
+
179
+ ```text
180
+ Hooks need review
181
+ 2 hooks are new or changed.
182
+ Hooks can run outside the sandbox after you trust them.
183
+
184
+ 1. Review hooks
185
+ › 2. Trust all and continue
186
+ 3. Continue without trusting (hooks won't run)
187
+ ```
188
+
189
+ Choose **`2. Trust all and continue`** — otherwise the hooks won't run and hivemind stays inactive.
176
190
  </details>
177
191
 
178
192
  <details>
package/bundle/cli.js CHANGED
@@ -114,6 +114,19 @@ function writeJson(path, obj) {
114
114
  ensureDir(dirname(path));
115
115
  writeFileSync(path, JSON.stringify(obj, null, 2) + "\n");
116
116
  }
117
+ function writeJsonIfChanged(path, obj) {
118
+ const next = JSON.stringify(obj, null, 2) + "\n";
119
+ if (existsSync(path)) {
120
+ try {
121
+ if (readFileSync(path, "utf-8") === next)
122
+ return false;
123
+ } catch {
124
+ }
125
+ }
126
+ ensureDir(dirname(path));
127
+ writeFileSync(path, next);
128
+ return true;
129
+ }
117
130
  function writeVersionStamp(dir, version) {
118
131
  ensureDir(dir);
119
132
  writeFileSync(join(dir, ".hivemind_version"), version);
@@ -486,7 +499,9 @@ function installCodex() {
486
499
  if (existsSync3(srcSkills))
487
500
  copyDir(srcSkills, join4(PLUGIN_DIR, "skills"));
488
501
  tryEnableCodexHooks();
489
- writeJson(HOOKS_PATH, mergeHooksJson(buildHooksJson()));
502
+ if (!writeJsonIfChanged(HOOKS_PATH, mergeHooksJson(buildHooksJson()))) {
503
+ log(` Codex hooks.json unchanged \u2014 skipped rewrite (no re-trust prompt)`);
504
+ }
490
505
  ensureDir(AGENTS_SKILLS_DIR);
491
506
  const skillTarget = join4(PLUGIN_DIR, "skills", "deeplake-memory");
492
507
  if (existsSync3(skillTarget)) {
@@ -753,7 +768,7 @@ function installCursor() {
753
768
  copyDir(srcBundle, join7(PLUGIN_DIR3, "bundle"));
754
769
  const existing = readJson(HOOKS_PATH2);
755
770
  const merged = mergeHooks2(existing);
756
- writeJson(HOOKS_PATH2, merged);
771
+ writeJsonIfChanged(HOOKS_PATH2, merged);
757
772
  writeVersionStamp(PLUGIN_DIR3, getVersion());
758
773
  log(` Cursor installed -> ${PLUGIN_DIR3}`);
759
774
  }
@@ -10996,6 +11011,30 @@ async function runRulesCommand(args) {
10996
11011
  // dist/src/commands/goal.js
10997
11012
  import { randomUUID as randomUUID4 } from "node:crypto";
10998
11013
  var VALID_STATUS = /* @__PURE__ */ new Set(["opened", "in_progress", "closed"]);
11014
+ var VALID_AGENT = /* @__PURE__ */ new Set(["manual", "capture"]);
11015
+ function parseAgentFlag(args) {
11016
+ const rest = [];
11017
+ let agent = "manual";
11018
+ for (let i = 0; i < args.length; i++) {
11019
+ if (args[i] === "--agent") {
11020
+ const val = args[i + 1];
11021
+ if (!val) {
11022
+ process.stderr.write("usage: --agent requires a value (manual|capture)\n");
11023
+ process.exit(1);
11024
+ }
11025
+ agent = val;
11026
+ i++;
11027
+ continue;
11028
+ }
11029
+ rest.push(args[i]);
11030
+ }
11031
+ if (!VALID_AGENT.has(agent)) {
11032
+ process.stderr.write(`invalid --agent: ${agent} (expected manual|capture)
11033
+ `);
11034
+ process.exit(1);
11035
+ }
11036
+ return { agent, rest };
11037
+ }
10999
11038
  function loadApiOrDie(table) {
11000
11039
  const cfg = loadConfig();
11001
11040
  if (!cfg) {
@@ -11006,7 +11045,7 @@ function loadApiOrDie(table) {
11006
11045
  const query = (sql) => api.query(sql);
11007
11046
  return { api, query, userName: cfg.userName };
11008
11047
  }
11009
- async function goalAdd(text) {
11048
+ async function goalAdd(text, agent = "manual") {
11010
11049
  const cfg = loadConfig();
11011
11050
  if (!cfg) {
11012
11051
  process.stderr.write("hivemind: not logged in.\n");
@@ -11018,7 +11057,7 @@ async function goalAdd(text) {
11018
11057
  const safe = sqlIdent(table);
11019
11058
  const goalId = randomUUID4();
11020
11059
  const ts = (/* @__PURE__ */ new Date()).toISOString();
11021
- await query(`INSERT INTO "${safe}" (id, goal_id, owner, status, content, version, created_at, agent, plugin_version) VALUES ('${randomUUID4()}', '${sqlStr(goalId)}', '${sqlStr(cfg.userName)}', 'opened', E'${sqlStr(text)}', 1, '${sqlStr(ts)}', 'manual', '')`);
11060
+ await query(`INSERT INTO "${safe}" (id, goal_id, owner, status, content, version, created_at, agent, plugin_version) VALUES ('${randomUUID4()}', '${sqlStr(goalId)}', '${sqlStr(cfg.userName)}', 'opened', E'${sqlStr(text)}', 1, '${sqlStr(ts)}', '${sqlStr(agent)}', '')`);
11022
11061
  process.stdout.write(`${goalId}
11023
11062
  `);
11024
11063
  }
@@ -11050,6 +11089,33 @@ async function goalList(filter) {
11050
11089
  process.exit(1);
11051
11090
  }
11052
11091
  }
11092
+ async function goalGet(goalId) {
11093
+ if (!goalId) {
11094
+ process.stderr.write("usage: hivemind goal get <goal_id>\n");
11095
+ process.exit(1);
11096
+ }
11097
+ const cfg = loadConfig();
11098
+ if (!cfg) {
11099
+ process.stderr.write("not logged in\n");
11100
+ process.exit(1);
11101
+ }
11102
+ const { query } = loadApiOrDie(cfg.goalsTableName);
11103
+ const safe = sqlIdent(cfg.goalsTableName);
11104
+ try {
11105
+ const rows = await query(`SELECT content FROM "${safe}" WHERE goal_id = '${sqlStr(goalId)}' ORDER BY version DESC, created_at DESC LIMIT 1`);
11106
+ if (rows.length === 0) {
11107
+ process.stderr.write(`goal not found: ${goalId}
11108
+ `);
11109
+ process.exit(1);
11110
+ }
11111
+ process.stdout.write(`${String(rows[0].content ?? "")}
11112
+ `);
11113
+ } catch (e) {
11114
+ process.stderr.write(`hivemind goal get: ${e.message}
11115
+ `);
11116
+ process.exit(1);
11117
+ }
11118
+ }
11053
11119
  async function goalDone(goalId) {
11054
11120
  await goalProgress(goalId, "closed");
11055
11121
  }
@@ -11171,8 +11237,10 @@ var USAGE_GOAL = `
11171
11237
  hivemind goal \u2014 manage team goals
11172
11238
 
11173
11239
  Usage:
11174
- hivemind goal add "<text>" create a goal (status=opened)
11240
+ hivemind goal add "<text>" [--agent manual|capture]
11241
+ create a goal (status=opened)
11175
11242
  hivemind goal list [--all|--mine] list goals (default: --mine)
11243
+ hivemind goal get <goal_id> print a goal's full body (resume context)
11176
11244
  hivemind goal done <goal_id> mark goal closed
11177
11245
  hivemind goal progress <goal_id> <opened|in_progress|closed>
11178
11246
  `.trim();
@@ -11183,12 +11251,13 @@ async function runGoalCommand(args) {
11183
11251
  return;
11184
11252
  }
11185
11253
  if (sub === "add") {
11186
- const text = args.slice(1).join(" ").trim();
11254
+ const { agent, rest } = parseAgentFlag(args.slice(1));
11255
+ const text = rest.join(" ").trim();
11187
11256
  if (!text) {
11188
11257
  process.stderr.write('usage: hivemind goal add "<text>"\n');
11189
11258
  process.exit(1);
11190
11259
  }
11191
- await goalAdd(text);
11260
+ await goalAdd(text, agent);
11192
11261
  return;
11193
11262
  }
11194
11263
  if (sub === "list") {
@@ -11196,6 +11265,15 @@ async function runGoalCommand(args) {
11196
11265
  await goalList(filter);
11197
11266
  return;
11198
11267
  }
11268
+ if (sub === "get") {
11269
+ const id = args[1];
11270
+ if (!id) {
11271
+ process.stderr.write("usage: hivemind goal get <goal_id>\n");
11272
+ process.exit(1);
11273
+ }
11274
+ await goalGet(id);
11275
+ return;
11276
+ }
11199
11277
  if (sub === "done") {
11200
11278
  const id = args[1];
11201
11279
  if (!id) {
@@ -1843,6 +1843,9 @@ Format: **entity** (type) \u2014 what was done with it, its current state>
1843
1843
  ## Open Questions / TODO
1844
1844
  <Anything unresolved, blocked, or explicitly deferred>
1845
1845
 
1846
+ ## Next Steps
1847
+ <The single concrete next action to resume with, as one imperative line (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). If the session reached a clean stopping point with nothing pending, write exactly: none>
1848
+
1846
1849
  IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
1847
1850
  PRIVACY: Never include absolute filesystem paths in the summary.
1848
1851
  LENGTH LIMIT: Keep the total summary under 4000 characters.`;
@@ -1123,6 +1123,9 @@ Format: **entity** (type) \u2014 what was done with it, its current state>
1123
1123
  ## Open Questions / TODO
1124
1124
  <Anything unresolved, blocked, or explicitly deferred>
1125
1125
 
1126
+ ## Next Steps
1127
+ <The single concrete next action to resume with, as one imperative line (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). If the session reached a clean stopping point with nothing pending, write exactly: none>
1128
+
1126
1129
  IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
1127
1130
  PRIVACY: Never include absolute filesystem paths in the summary.
1128
1131
  LENGTH LIMIT: Keep the total summary under 4000 characters.`;
@@ -67,6 +67,36 @@ When the user expresses a new goal:
67
67
 
68
68
  **Do NOT auto-generate KPIs.** A goal is created with zero KPI files by default. Generate KPIs ONLY when the user explicitly asks you to ("aggiungi KPI per …", "add metrics for this goal", "track these metrics: …"). When the user asks, write each KPI as a separate file at `~/.deeplake/memory/kpi/<goal_id>/<kpi-slug>.md` with the body format documented above.
69
69
 
70
+ ### 1a. Capture a task for later (with resumable context)
71
+
72
+ Use this when the user **parks a tangential task** mid-session — "save this for later", "remind me to …", "don't let me forget …", "let's do X later". The value is NOT the one-liner — it's storing enough **context to resume cold** in a future session without the user re-explaining anything.
73
+
74
+ Write it via the **CLI** so the row is tagged `agent: capture`, which separates parked side-tasks from hand-made goals:
75
+
76
+ ```bash
77
+ hivemind goal add --agent capture "Add rate-limiting to the webhook handler
78
+
79
+ Start here: add a per-IP token bucket on the handler entry path
80
+ Files: src/webhook/handler.ts:120-160, src/webhook/limits.ts
81
+ Branch: feat/webhook-hardening
82
+ Run: pnpm test webhook
83
+ Why: bursty clients hammer the endpoint; agreed to defer until the retry-backoff work lands"
84
+ ```
85
+
86
+ - **Line 1 is the label** — short; it's what `goal list` and the SessionStart banner show.
87
+ - Fill `Start here / Files / Branch / Run / Why` from the live conversation. Include only the lines you can fill; `Start here:` (the concrete first action) matters most.
88
+ - Pass the whole package as **one double-quoted argument** (newlines are preserved into the stored body).
89
+ - Confirm to the user: the label + that it'll resume cleanly next session.
90
+
91
+ ### 1b. Resume a parked task (automatic context transfer)
92
+
93
+ When the user says "let's work on that task / that goal", "let's start the `<X>` task", or "pick up the parked `<X>`", pull its stored context back into the session and continue — the user should NOT have to re-explain anything.
94
+
95
+ 1. **Find it:** `hivemind goal list --mine` and match the user's reference to a `goal_id`. If ambiguous, show the candidates and ask.
96
+ 2. **Transfer the context:** `hivemind goal get <goal_id>` prints the full package (`Start here / Files / Branch / Run / Why`). Read it as your working context — `goal list` only shows the first line, so always use `goal get` for the full body.
97
+ 3. **Flip to in_progress:** `mv ~/.deeplake/memory/goal/<owner>/opened/<uuid>.md ~/.deeplake/memory/goal/<owner>/in_progress/<uuid>.md`
98
+ 4. **Act on it:** open the `Files:`, switch to the `Branch:` if given, and begin from `Start here:`. You are resumed — continue as if the context was never lost.
99
+
70
100
  ### 2. List goals
71
101
 
72
102
  ```bash
@@ -1843,6 +1843,9 @@ Format: **entity** (type) \u2014 what was done with it, its current state>
1843
1843
  ## Open Questions / TODO
1844
1844
  <Anything unresolved, blocked, or explicitly deferred>
1845
1845
 
1846
+ ## Next Steps
1847
+ <The single concrete next action to resume with, as one imperative line (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). If the session reached a clean stopping point with nothing pending, write exactly: none>
1848
+
1846
1849
  IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
1847
1850
  PRIVACY: Never include absolute filesystem paths in the summary.
1848
1851
  LENGTH LIMIT: Keep the total summary under 4000 characters.`;
@@ -268,6 +268,9 @@ Format: **entity** (type) \u2014 what was done with it, its current state>
268
268
  ## Open Questions / TODO
269
269
  <Anything unresolved, blocked, or explicitly deferred>
270
270
 
271
+ ## Next Steps
272
+ <The single concrete next action to resume with, as one imperative line (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). If the session reached a clean stopping point with nothing pending, write exactly: none>
273
+
271
274
  IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
272
275
  PRIVACY: Never include absolute filesystem paths in the summary.
273
276
  LENGTH LIMIT: Keep the total summary under 4000 characters.`;
@@ -1842,6 +1842,9 @@ Format: **entity** (type) \u2014 what was done with it, its current state>
1842
1842
  ## Open Questions / TODO
1843
1843
  <Anything unresolved, blocked, or explicitly deferred>
1844
1844
 
1845
+ ## Next Steps
1846
+ <The single concrete next action to resume with, as one imperative line (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). If the session reached a clean stopping point with nothing pending, write exactly: none>
1847
+
1845
1848
  IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
1846
1849
  PRIVACY: Never include absolute filesystem paths in the summary.
1847
1850
  LENGTH LIMIT: Keep the total summary under 4000 characters.`;
@@ -266,6 +266,9 @@ Format: **entity** (type) \u2014 what was done with it, its current state>
266
266
  ## Open Questions / TODO
267
267
  <Anything unresolved, blocked, or explicitly deferred>
268
268
 
269
+ ## Next Steps
270
+ <The single concrete next action to resume with, as one imperative line (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). If the session reached a clean stopping point with nothing pending, write exactly: none>
271
+
269
272
  IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
270
273
  PRIVACY: Never include absolute filesystem paths in the summary.
271
274
  LENGTH LIMIT: Keep the total summary under 4000 characters.`;
@@ -1799,7 +1799,7 @@ function extractLatestVersion(body) {
1799
1799
  return typeof v === "string" && v.length > 0 ? v : null;
1800
1800
  }
1801
1801
  function getInstalledVersion() {
1802
- return "0.7.67".length > 0 ? "0.7.67" : null;
1802
+ return "0.7.69".length > 0 ? "0.7.69" : null;
1803
1803
  }
1804
1804
  function isNewer(latest, current) {
1805
1805
  const parse = (v) => v.replace(/-.*$/, "").split(".").map(Number);
@@ -54,5 +54,5 @@
54
54
  }
55
55
  }
56
56
  },
57
- "version": "0.7.67"
57
+ "version": "0.7.69"
58
58
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hivemind",
3
- "version": "0.7.67",
3
+ "version": "0.7.69",
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",
@@ -23,6 +23,31 @@ OpenClaw exposes purpose-built tools for goals + KPIs. Use them directly — do
23
23
  3. ONLY if the user asks for KPIs: `hivemind_kpi_add` once per KPI with `goal_id` + `kpi_id` (short slug like `k-prs`) + `target` (positive int) + `unit`.
24
24
  4. Confirm to the user with the goal_id and that the goal is team-visible.
25
25
 
26
+ ## Capture a task for later (with resumable context)
27
+
28
+ When the user **parks a tangential task** mid-session — "save this for later", "remind me to …", "don't let me forget …", "let's do X later" — store enough **context to resume cold** later, not just a one-liner. Put the full package in the `text` of `hivemind_goal_add`:
29
+
30
+ ```
31
+ hivemind_goal_add({ text:
32
+ "Add rate-limiting to the webhook handler\n\n" +
33
+ "Start here: add a per-IP token bucket on the handler entry path\n" +
34
+ "Files: src/webhook/handler.ts:120-160, src/webhook/limits.ts\n" +
35
+ "Branch: feat/webhook-hardening\n" +
36
+ "Run: pnpm test webhook\n" +
37
+ "Why: bursty clients hammer the endpoint; defer until retry-backoff lands" })
38
+ ```
39
+
40
+ Line 1 is the label. Fill `Start here / Files / Branch / Run / Why` from the conversation; `Start here:` (the concrete first action) matters most. (OpenClaw's `hivemind_goal_add` has no provenance flag, so the row is tagged `manual` — that's fine; the context is what matters.)
41
+
42
+ ## Resume a parked task (automatic context transfer)
43
+
44
+ When the user says "let's work on that task / goal" or "pick up the `<X>` task":
45
+
46
+ 1. `hivemind_search({ query: "<topic>" })` or `hivemind_index({})` to locate the parked goal, then `hivemind_read({ path: "memory/goal/<owner>/opened/<goal_id>.md" })` to pull the **full** context package back.
47
+ 2. Read it as your working context and begin from `Start here:` using the `Files` / `Branch` / `Run` lines — continue as if the context was never lost.
48
+
49
+ (Status-move tools aren't exposed on OpenClaw, so leave the goal where it is and just resume the work.)
50
+
26
51
  ## What NOT to do
27
52
 
28
53
  - Do NOT write files anywhere under `~/.deeplake/memory/`. OpenClaw's runtime does not route filesystem writes to the Deeplake tables — only the `hivemind_*` tools above do.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeplake/hivemind",
3
- "version": "0.7.67",
3
+ "version": "0.7.69",
4
4
  "description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
5
5
  "type": "module",
6
6
  "repository": {