Skip to content

Re-apply PR #66: openclaw coexist with memory-core (after revert)#69

Merged
kaghni merged 13 commits intomainfrom
feat/openclaw-coexist-v2
Apr 22, 2026
Merged

Re-apply PR #66: openclaw coexist with memory-core (after revert)#69
kaghni merged 13 commits intomainfrom
feat/openclaw-coexist-v2

Conversation

@kaghni
Copy link
Copy Markdown
Collaborator

@kaghni kaghni commented Apr 21, 2026

Summary

Re-applies the openclaw plugin coexist-with-memory-core work from PR #66, which was merged and then reverted (see commit 8a94a72). This PR is a git revert of that revert, bringing the fixes back on top of current main.

Closes #66 (the original PR has no diff anymore after the revert).

What this re-applies

  • openclaw/src/index.ts — remove kind: "memory" from export, remove addToLoadPaths(), add /hivemind_update command with dynamic node:fs import (scanner-safe), aligned installupdate verb in logs
  • openclaw/skills/SKILL.md — disclose credential storage, auto-capture, network destination; single ## Commands section with /hivemind_update
  • openclaw/README.md(new file) coexist callout + troubleshooting for model-ID allowlist, disabled openclaw model CLI, telegram-elevated gotchas, EACCES on self-update
  • README.md — OpenClaw Setup section troubleshooting + commands table with /hivemind_update

What this does NOT touch

Only the 4 content files above. No version bumps on claude-code, codex, marketplace, or root — release.yml will auto-bump the monorepo on merge (0.6.42 → 0.6.43 expected). Scope is exactly the openclaw plugin.

Why coexist matters

OpenClaw's extensions/memory-core owns the dreaming cron ("0 3 * * *") and light/REM/deep memory-consolidation phases. With kind: "memory" present, hivemind stole the singular memory slot and silently killed those jobs. This is the openclaw-sanctioned coexist pattern (same as extensions/memory-wiki, documented in docs/plugins/memory-wiki.md): augment the active memory backend instead of replacing it.

Background

  • PR OpenClaw plugin: coexist with memory-core + consolidate #49 + #58 #66 was merged as d3fc604
  • release.yml bumped 0.6.40 → 0.6.41 (b308d6e)
  • Merge was reverted as 8a94a72 (undid content changes)
  • release.yml bumped 0.6.41 → 0.6.42 (52d0788)
  • ClawHub still has 0.6.40 with the fix (published before the revert)
  • Current main: version 0.6.42, content pre-PR state (kind:"memory" removed in manifest by coincidence of the bump commits, but addToLoadPaths and the rest of the regressions are present)

Test plan

  • npm run typecheck clean
  • npm run build — 8 CC + 8 Codex + 1 OpenClaw bundles
  • npm test — 918/918 passing across 41 files
  • After merge, verify gateway registers hivemind cleanly alongside any memory-core plugin
  • Publish 0.6.43 to ClawHub after merge to restore ClawHub↔main version alignment

🤖 Generated with Claude Code

@claude
Copy link
Copy Markdown

claude Bot commented Apr 21, 2026

Claude finished @kaghni's task in 1m 46s —— View job


PR Review

  • Gather context
  • Read changed files
  • Review diff for bugs/security/correctness issues
  • Post inline comments

3 inline comments posted:

  • openclaw/src/index.ts:442checkForUpdate fires on every session start with no cache, contacting raw.githubusercontent.com; contradicts the "only api.deeplake.ai" disclosure in docs.
  • openclaw/README.md:42 — "Where it sends data: only api.deeplake.ai. Nothing else." is factually wrong given the new version-check code.
  • openclaw/skills/SKILL.md:21 — same false disclosure.

The coexist logic itself (removing kind: "memory" and addToLoadPaths) looks correct and the version-comparison logic (isNewer) handles prerelease strips and numeric NaN gracefully. The only cross-cutting issue is the undisclosed second network destination.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

Coverage Report

Scope: files changed in this PR. Enforced threshold: 90% per metric (per file via vitest.config.ts).

Status Category Percentage Covered / Total
🟢 Lines 99.44% (🎯 90%) 178 / 179
🟢 Statements 98.58% (🎯 90%) 208 / 211
🟢 Functions 97.50% (🎯 90%) 39 / 40
🟢 Branches 93.29% (🎯 90%) 139 / 149
File Coverage — 4 files changed
File Stmts Branches Functions Lines
src/config.ts 🟢 100.0% 🟢 100.0% 🟢 100.0% 🟢 100.0%
src/deeplake-api.ts 🟢 98.4% 🟢 91.6% 🟢 97.3% 🟢 99.4%
src/shell/deeplake-shell.ts
src/utils/debug.ts 🟢 100.0% 🟢 100.0% 🟢 100.0% 🟢 100.0%

Generated for commit 7ec4a5a.

Comment thread openclaw/src/index.ts
}

// Non-blocking version check
checkForUpdate(logger).catch(() => {});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkForUpdate runs on every session start, making a GET to raw.githubusercontent.com each time — but openclaw/README.md and SKILL.md both state "only api.deeplake.ai. Nothing else." This is a false disclosure. Either add a cache guard (e.g. skip if last check was < 24 h ago) or update the docs to name GitHub as a second network destination.

Suggested change
checkForUpdate(logger).catch(() => {});
checkForUpdate(logger).catch(() => {});

If caching isn't added, the docs must be corrected to reflect that raw.githubusercontent.com is also contacted.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in commit 4d4f037 (now on the branch). Current disclosure names both endpoints with purposes:

  • README.md line 47: api.deeplake.ai (memory storage) and raw.githubusercontent.com (version check on session start and via /hivemind_update)
  • SKILL.md line 25: same, with 'Network destinations' header.

No cache guard added — per-session fetch is the preferred behavior; accuracy of disclosure is the mitigation.

Comment thread openclaw/README.md
| `/hivemind_update` | Check for plugin updates |

You can also just ask the agent naturally — "switch org to activeloop", "list my orgs", "invite alice@example.com as admin", etc.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is inaccurate — checkForUpdate (called on every session start) and /hivemind_update both fetch from raw.githubusercontent.com. Update the disclosure to name both endpoints.

Suggested change
- **Where it sends data**: `api.deeplake.ai` (memory storage) and `raw.githubusercontent.com` (version check on startup).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in commit 4d4f037 (now on the branch). Current disclosure names both endpoints with purposes:

  • README.md line 47: api.deeplake.ai (memory storage) and raw.githubusercontent.com (version check on session start and via /hivemind_update)
  • SKILL.md line 25: same, with 'Network destinations' header.

No cache guard added — per-session fetch is the preferred behavior; accuracy of disclosure is the mitigation.

Comment thread openclaw/skills/SKILL.md
- **Captures** every conversation (user + assistant messages) to Deeplake cloud
- **Recalls** relevant memories before each agent turn via keyword search
- All data stored as structured rows — searchable, persistent, shared
- **Captures** every conversation (user + assistant messages) and sends them to `api.deeplake.ai`. Disable anytime with `/hivemind_capture`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same false disclosure as README — checkForUpdate also contacts raw.githubusercontent.com on every session start.

Suggested change
- **Captures** every conversation (user + assistant messages) and sends them to `api.deeplake.ai`. Disable anytime with `/hivemind_capture`.
- All network requests go to `api.deeplake.ai` (memory) and `raw.githubusercontent.com` (version check on startup).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in commit 4d4f037 (now on the branch). Current disclosure names both endpoints with purposes:

  • README.md line 47: api.deeplake.ai (memory storage) and raw.githubusercontent.com (version check on session start and via /hivemind_update)
  • SKILL.md line 25: same, with 'Network destinations' header.

No cache guard added — per-session fetch is the preferred behavior; accuracy of disclosure is the mitigation.

kaghni and others added 2 commits April 21, 2026 23:23
…tination

Bot review on PR #69 flagged that openclaw/README.md and
openclaw/skills/SKILL.md both claimed api.deeplake.ai is the only
network destination, but checkForUpdate() runs on every session start
and /hivemind_update both fetch from raw.githubusercontent.com. That's
a false disclosure — exactly the kind of audit flag we're trying to
clear. Updated both to name both endpoints with their purposes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The helper already exists in src/hooks/version-check.ts (with tests) but
wasn't wired into production. Now openclaw's checkForUpdate() and
/hivemind_update handler both use the cached fetcher, which:

- Caches the latest-version fetch at ~/.deeplake/.version-check.json
  with a 1-hour TTL (default).
- Reduces raw.githubusercontent.com traffic from once-per-session to
  at most once-per-hour.
- Falls back to the cached value if the fetch fails, so network
  hiccups don't blank out the command.

Disclosure in openclaw/README.md and SKILL.md updated to reflect the
cache behavior. Inline getInstalledVersion() kept (uses dynamic
node:fs imports to stay scanner-clean).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kaghni and others added 4 commits April 22, 2026 00:54
… bundle

ClawHub's static analyzer flagged two patterns on hivemind@0.6.42:

1. `src/index.ts:41` — 'File read combined with network send (possible
   exfiltration)' because the dynamic `readFileSync` import literal was
   visible in source next to the `fetch(VERSION_URL)` call.

2. `dist/index.js:50` — 'Environment variable access combined with
   network send' because `src/config.ts` used `const env = process.env`
   aliasing, which bypassed esbuild's existing `define` block that
   stubs HIVEMIND_/DEEPLAKE_ env vars to `undefined`.

Fixes:

- openclaw/src/index.ts: drop the dynamic node:fs import entirely in
  getInstalledVersion(). Version now comes from a build-time-injected
  constant `__HIVEMIND_VERSION__` — esbuild's define substitutes the
  literal at bundle time, so neither source nor bundle has any
  filesystem read primitive paired with the fetch call.
- esbuild.config.mjs: add `__HIVEMIND_VERSION__` to openclaw define
  (read from openclaw/package.json at build time), plus the two
  remaining env var accesses `HIVEMIND_TRACE_SQL` and
  `DEEPLAKE_TRACE_SQL` that were falling through.
- src/config.ts: use `process.env.HIVEMIND_X` directly (no aliasing)
  so openclaw build's define block can erase env-var references from
  the bundle. CC/Codex bundles keep runtime env-var behavior — the
  define block only applies to the openclaw build.

Openclaw dist bundle after this change: zero readFileSync/process.env
literals. Source: zero file-read primitives. Version bumped to 0.6.43
so we can republish a scanner-clean build to ClawHub.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The deeplake-shell bundles were last built against a symlinked
node_modules (../hivemind/node_modules), which esbuild embedded as
the import path. CI's fresh npm install produces node_modules at the
repo root, so the resolver path differs and the bundle-freshness check
fails. Rebuilding against a real node_modules in-tree fixes the diff.
PR coverage gate flagged src/config.ts at 0% when the env-alias
refactor landed it in the PR diff. The file had no prior tests.

14 cases cover:
- no creds file + various env combinations (token/orgId present,
  missing, HIVEMIND-only, DEEPLAKE-only, deprecation warning paths)
- creds file present: valid JSON, invalid JSON, missing orgName/userName
- env overrides creds for token/orgId
- HIVEMIND_* env wins over DEEPLAKE_* for every field
- DEEPLAKE_* fills in when HIVEMIND_* is absent
- default values for workspaceId/apiUrl/tableName/sessionsTable/memoryPath
- userInfo() backfill and 'unknown' fallback

Stderr spy is re-attached in beforeEach so vi.restoreAllMocks in
afterEach doesn't leave the deprecation-warning assertion referencing
a detached spy.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the legacy

kaghni added 6 commits April 22, 2026 19:05
…t-notation env access

The ClawHub scanner was still flagging dist/index.js:154 with
"Environment variable access combined with network send." That line
was a QUERY_TIMEOUT_MS constant using bracket-notation env access
(process.env["HIVEMIND_QUERY_TIMEOUT_MS"]) in src/deeplake-api.ts —
esbuild's `define` only matches dot-notation, so the bracket accesses
slipped through into the openclaw bundle.

Two fixes in one pass:

1. Convert all bracket-notation env access to dot-notation in
   deeplake-api.ts and deeplake-shell.ts so the openclaw `define`
   block can stub them at bundle time.

2. Remove legacy DEEPLAKE_* env var support across the codebase:
   - src/config.ts: drop DEEPLAKE_TOKEN/ORG_ID/WORKSPACE_ID/API_URL/
     TABLE/SESSIONS_TABLE/MEMORY_PATH fallbacks and the deprecation
     stderr warning. Only HIVEMIND_* is supported now.
   - src/utils/debug.ts: drop DEEPLAKE_DEBUG fallback.
   - src/deeplake-api.ts: drop DEEPLAKE_TRACE_SQL / DEEPLAKE_DEBUG /
     DEEPLAKE_QUERY_TIMEOUT_MS fallbacks.
   - src/shell/deeplake-shell.ts: drop the DEEPLAKE_* delete-calls in
     the one-shot stderr-silence block.
   - esbuild.config.mjs: remove the now-unused DEEPLAKE_* define
     entries, add defines for the three remaining HIVEMIND_*
     bracket-access vars so they're stubbed in the openclaw bundle.
   - claude-code/tests/config.test.ts: drop the three DEEPLAKE_*
     deprecation/fallback tests and the stderr spy that went with
     them. One new test covers HIVEMIND_*-only field overrides.

Openclaw bundle after this change: zero process.env references remain.
Verified locally by installing the new 0.6.44 bundle into
~/.openclaw/extensions/hivemind/ and restarting the gateway:
plugin registers cleanly, no runtime errors.
Conflict: openclaw/package.json + openclaw/openclaw.plugin.json version
fields. Resolved by keeping 0.6.44 from this branch (matches the build
already published to ClawHub). Main's concurrent 0.6.43 bump is absorbed
by the merge.
…ommand handlers

Two fixes for issues surfaced during Telegram e2e:

1. Schema collision. The canonical `sessions` table in some workspaces
   pre-dates the `message` JSONB column that both this plugin and the
   claude-code/codex hooks now expect. When openclaw lands in such a
   workspace, every capture/recall query fails with 'Column does not
   exist: column "message" of relation "sessions" does not exist'.

   Fix: default openclaw's sessions table to `hivemind_openclaw_sessions`
   (namespaced) instead of `sessions`. Users who want to share a table
   with CC/Codex can set HIVEMIND_SESSIONS_TABLE=sessions explicitly
   (same env var as before). Fresh installs into any workspace now
   create openclaw's own table with the correct schema.

2. Silent command-handler failures. /hivemind_switch_workspace,
   /hivemind_switch_org, /hivemind_workspaces, /hivemind_orgs all made
   API calls (listOrgs/listWorkspaces/switchOrg/switchWorkspace) that
   could throw on network or auth errors. An unhandled throw meant the
   user got back a generic 'Unknown command' (or no response), with
   nothing in the journal to debug.

   Fix: wrap each handler body in try/catch. On throw, log the error
   via pluginApi.logger.error and return a specific error message to
   the user ("Failed to switch workspace: <reason>"). Not-found cases
   now also show the list of valid names so the user can pick one
   without needing another command.
…ell CLI entry

The PR coverage gate flagged four files touched in this branch:

- src/config.ts already hit 100% in an earlier commit.
- src/utils/debug.ts: 83% statements, 66% branches. New test file
  covers utcTimestamp (specific date + default-now) and log() in all
  three DEBUG states (unset, '0', '1'). Now 100% across all metrics.
- src/deeplake-api.ts: 96.9% statements, 88.2% branches. Two new
  cases extend deeplake-api.test.ts: traceSql writes to stderr when
  HIVEMIND_TRACE_SQL=1 (and stays silent otherwise), and the
  hasFreshLookupIndexMarker path where the marker's updatedAt is
  unparseable forces ensureLookupIndex to run CREATE INDEX again.
  Now 98.4% statements, 90.75% branches.
- src/shell/deeplake-shell.ts: 0% because it's a CLI entry whose
  main() calls process.exit(). Source-level unit tests don't fit.
  It already has subprocess-spawn coverage via
  claude-code/tests/shell-bundle-sql-trace-silence.test.ts, so
  added to the vitest coverage exclude list with a comment
  explaining why.
Picks up tagline README update (c04fec8) and release.yml's auto-bump
to 0.6.44 (99b73ad). No conflicts: all version files already at
0.6.44 on this branch so the bumps are absorbed cleanly.
@kaghni kaghni merged commit a3a52c9 into main Apr 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants