@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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +14 -0
- package/bundle/cli.js +85 -7
- package/codex/bundle/capture.js +3 -0
- package/codex/bundle/stop.js +3 -0
- package/codex/skills/hivemind-goals/SKILL.md +30 -0
- package/cursor/bundle/capture.js +3 -0
- package/cursor/bundle/session-end.js +3 -0
- package/hermes/bundle/capture.js +3 -0
- package/hermes/bundle/session-end.js +3 -0
- package/openclaw/dist/index.js +1 -1
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/openclaw/skills/hivemind-goals/SKILL.md +25 -0
- package/package.json +1 -1
|
@@ -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.
|
|
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.
|
|
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": "
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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)}', '
|
|
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>"
|
|
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
|
|
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) {
|
package/codex/bundle/capture.js
CHANGED
|
@@ -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.`;
|
package/codex/bundle/stop.js
CHANGED
|
@@ -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
|
package/cursor/bundle/capture.js
CHANGED
|
@@ -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.`;
|
package/hermes/bundle/capture.js
CHANGED
|
@@ -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.`;
|
package/openclaw/dist/index.js
CHANGED
|
@@ -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.
|
|
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);
|
package/openclaw/package.json
CHANGED
|
@@ -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.
|