Skip to content

Releases: activeloopai/hivemind

v0.6.37 — fix(grep): dual-table search + session content normalization

18 Apr 00:08

Choose a tag to compare

Summary

Three independent bugs in the plugin grep interceptor, fixed together because they share a natural refactor into a new src/shell/grep-core.ts module.

1. Fast-path grep ignored the sessions table.
handleGrepDirect in src/hooks/grep-direct.ts received sessionsTable as an argument but only ever queried the memory (summaries) table. Literal quotes, titles, proper nouns that live in the raw dialogue but are paraphrased out of summaries were invisible to the hook. On a LoCoMo benchmark subset (45 questions where v2/v3 scored 0% and the baseline scored 100%), adding sessions lookup recovered 51% of answers. Now we hit both tables in parallel (summary::text on memory, message::text on sessions) and merge results.

2. Session JSON blobs leaked into grep output whole.
A LoCoMo session is stored as a single JSONB row whose serialized {turns:[...]} has zero newlines — ~5700 chars on one line. When grep matched any token, the line-refinement step returned the entire blob. A production event row (capture.ts output) has the same problem at smaller scale: 200–3000 char of JSON wrapping around a small content field. The new normalizeContent function, run before the regex pass, transforms each shape into line-per-unit text:

  • LoCoMo: {turns:[...]}date: ...\nspeakers: ...\n[dia_id] Speaker: text\n... per turn
  • Production user_message[user] <content> (with <recalled-memories> blocks stripped — they duplicate rows that already exist standalone)
  • Production assistant_message[assistant (agent=<subagent_type>)?] <content>
  • Production tool_call[tool:<name>]\ninput: <actionable fields>\nresponse: <extracted content> — tool-aware field extraction drops wrapper noise and response fields duplicated from input (via camel ↔ snake mapping), with side-effect tools (Edit/Write/MultiEdit) collapsing to [wrote <path>].
  • Unknown shapes and parse failures always fall back to raw — normalizeContent never returns null/empty.

3. Shell-path grep had a query that returned 400 on every call.
src/shell/grep-interceptor.ts (used by the deeplake-shell virtual bash and by every Bash command the hook cannot fast-path) ran SELECT path FROM "<table>" WHERE summary <#> '<pattern>' LIMIT 50 as its coarse BM25 filter. The <#> operator returns a float, not a boolean, so the server answered 400 Data type mismatch: argument of WHERE must be type boolean, not type real every time. A try/catch swallowed the error and fell back to scanning the FS cache — functionally correct but slow and noisy. Removed. The interceptor now uses the same LIKE/ILIKE path as the fast-path.

Read-only change

capture.ts, the session-start hook, and the wiki worker are untouched. Every byte capture.ts used to write still lands in sessions.message / memory.summary. Normalization is a read-time view; the raw content is always reachable via direct SQL if anyone needs it.

Measured impact — production (activeloop/hivemind, 3 000 random rows)

Byte reduction of the text Claude sees from sessions.message:

Tool / event rows raw after saved
Bash 772 2 338 KB 1 599 KB 31.6 %
Read 500 2 176 KB 1 678 KB 22.9 %
Grep 207 460 KB 313 KB 32.0 %
Agent 25 318 KB 245 KB 22.9 %
Write 25 204 KB 84 KB 58.6 %
TaskUpdate 64 53 KB 4 KB 91.9 %
ToolSearch 19 14 KB 2 KB 87.3 %
user_message 88 77 KB 20 KB 73.9 %
assistant_message 87 90 KB 54 KB 39.7 %
Overall 3 000 10.1 MB 4.7 MB 53.1 %

Measured impact — LoCoMo benchmark (Gemini-judged, clean tables)

Subset baseline v2 second (0.6.23 stock) v3 (sync bug) this PR
strict-45 (plugin-hard, baseline-easy) 100 % 0 % 0 % 51 %
100-mix (45 strict + 55 random) 74.5 % 28.5 % 20.5 % 47.5 %
250-full 67.8 % 46.2 % 35.0 % run pending on clean tables

File layout

  • src/shell/grep-core.ts [new, ~340 lines] — searchDeeplakeTables, normalizeContent, formatToolCall + formatToolInput + formatToolResponse, compileGrepRegex, refineGrepMatches, grepBothTables, buildPathFilter. Plus exported types (GrepMatchParams, ContentRow, SearchOptions).
  • src/hooks/grep-direct.ts [-67 lines] — thin wrapper over grepBothTables. parseBashGrep kept in place.
  • src/shell/grep-interceptor.ts [-24 lines, heavy rewrite] — uses searchDeeplakeTables, keeps the in-memory cache fallback via fs.prefetch + fs.readFile.
  • Rebuilt bundles: claude-code/bundle/{pre-tool-use.js,shell/deeplake-shell.js}, codex/bundle/{pre-tool-use.js,shell/deeplake-shell.js}. Deterministic output from npm run build.

Commits

  1. feat(grep): add shared grep-core with dual-table search + normalization
  2. refactor(grep): fast-path grep delegates to shared grep-core
  3. fix(shell grep): drop broken BM25 query, route through shared core
  4. build: regenerate bundles for dual-table grep + normalize

Test plan

  • npm run ci (typecheck + vitest)
  • claude-code/tests/grep-direct.test.ts and claude-code/tests/grep-interceptor.test.ts pass without edits
  • Manual: HIVEMIND_DEBUG=1 claude -p "Use Grep with pattern=Brave on memory path" — log shows two query start lines (one per table)
  • Manual: Grep on a LoCoMo session path returns per-turn lines, not a raw JSON blob
  • Manual: Grep on a production session path returns [user], [assistant], [tool:...] lines, not raw JSON
  • Re-run the LoCoMo full 250 benchmark on clean tables and confirm v4's 39.4 % regresses upward toward v2's 46.2 % or better.

Non-goals

  • No changes to capture / ingest / wiki worker.
  • No changes to the LoCoMo data or scripts/v2/ingest-plugin.ts.
  • No SQL schema changes.
  • Production sessions still return one row per hook event; aggregating all N rows of a session at Read time (so Claude sees a full conversation rather than the first event) is a follow-up in a separate PR.

v0.6.36 — feat: periodic session summary trigger (time + message count)

17 Apr 19:57

Choose a tag to compare

Summary

Adds periodic session summary generation in addition to the existing SessionEnd / Stop trigger. Summaries now fire automatically during long-running sessions when either:

  • N events have been captured since the last summary (default 150), or
  • H hours have elapsed since the last summary AND at least one new event was captured (default 4).

Configurable via two env vars: HIVEMIND_SUMMARY_EVERY_N_MSGS and HIVEMIND_SUMMARY_EVERY_HOURS.

Applies to both the claude-code and codex plugins. openclaw is unaffected (no summary feature in that build).

Motivation

Today summaries are generated only at session close. For long sessions this means:

  • If the session crashes or is force-killed, hours of work are never summarized.
  • The wiki entry stays empty until the user manually stops the session, so memory search on an active session returns nothing.

Triggering summaries mid-session fixes both problems while keeping SessionEnd as the authoritative final summary.

Design

Per-session sidecar

~/.claude/hooks/summary-state/<session_id>.json:

```json
{ "lastSummaryAt": <epoch_ms>, "lastSummaryCount": , "totalCount": }
```

  • capture.ts increments totalCount after each successful INSERT.
  • wiki-worker.ts updates lastSummaryAt + lastSummaryCount after a successful upload.
  • Never deleted, so --resume continues from the prior state.

Trigger logic (src/hooks/summary-state.ts)

```
msgsSince = totalCount - lastSummaryCount
trigger = (msgsSince >= N)
OR (msgsSince > 0 AND now - lastSummaryAt >= H * 3600_000)
```

The msgsSince > 0 guard prevents generating a duplicate summary when a session is simply idle past the time threshold with nothing new to summarize.

Concurrency

  • RMW lock around sidecar increments (`.rmw` via openSync(..., \"wx\")). Prevents lost updates when multiple async: true capture processes run in parallel.
  • Per-session worker lock (`.lock`) prevents two periodic workers from running concurrently for the same session. Stale locks (> 10 min) are auto-reclaimed.

Shared spawn helpers

  • src/hooks/spawn-wiki-worker.ts — claude-code (also used by the slimmed session-end.ts).
  • src/hooks/codex/spawn-wiki-worker.ts — codex (also used by the slimmed stop.ts).

Both extracted from existing per-hook code. Shrinks:

  • session-end.ts: 153 → 46 lines.
  • codex/stop.ts: 233 → 132 lines.

Files changed

New modules (3):

  • src/hooks/summary-state.ts
  • src/hooks/spawn-wiki-worker.ts
  • src/hooks/codex/spawn-wiki-worker.ts

Updated hooks (6):

  • src/hooks/capture.ts, src/hooks/session-end.ts, src/hooks/wiki-worker.ts
  • src/hooks/codex/capture.ts, src/hooks/codex/stop.ts, src/hooks/codex/wiki-worker.ts

Regenerated bundles (6): claude-code + codex capture/session-end(stop)/wiki-worker.

Verification

Unit / build

  • npm test353/353 passing
  • npm run build → 8 CC + 8 Codex + 1 OpenClaw bundles

Scenario coverage (module-level)

  • N-trigger fires exactly at N events.
  • Time-trigger fires only after H hours and a new event.
  • Idle session past H hours → no trigger (no redundant summary).
  • --resume: sidecar is preserved across restarts.

Edge cases tested

  • Env vars: -1, 0, abc, \"\", 1.5 → all fall back to defaults (N must be a positive integer; H must be a positive finite number).
  • Corrupt / empty sidecar → readState returns null, next bump starts fresh.
  • Stale lock (> 10 min) → reclaimed automatically.
  • Clock skew (lastSummaryAt in the future) → N-trigger still works; time-trigger correctly blocked by msgsSince guard.
  • Multi-session isolation → each session has independent sidecar + lock.
  • Concurrent capture processes (20 parallel, 5 × 10 burst) → previously lost 32/50 updates, now zero loss after the RMW lock fix.

End-to-end

  • claude-code: real claude -p session with HIVEMIND_SUMMARY_EVERY_N_MSGS=5 → threshold hit at event 5, worker spawned, summary uploaded, sidecar updated, lock released.
  • codex: real codex exec + direct bundle invocation with primed sidecar → threshold crossed, worker spawned with correct codexBin / ~/.codex/ paths, log entries match.

Bugs found and fixed during testing

  1. Number(\"1.5\") was previously accepted as N = 1. Fixed by requiring Number.isInteger for N.
  2. Read-modify-write race between concurrent capture.ts processes: a 5 × 10 burst lost 32/50 counter updates. Fixed by wrapping bumpTotalCount in an openSync(..., \"wx\") RMW lock.

Commits

  1. `feat: add platform-agnostic summary-state sidecar module`
  2. `refactor(claude-code): extract wiki-worker spawn into shared helper`
  3. `feat(claude-code): persist sidecar state from wiki-worker`
  4. `feat(claude-code): trigger periodic summary from capture hook`
  5. `refactor(codex): extract wiki-worker spawn into shared helper`
  6. `feat(codex): persist sidecar state from wiki-worker`
  7. `feat(codex): trigger periodic summary from capture hook`

Commits 1/2/5 are pure refactors. 3/4/6/7 are the behavior change.

Test plan

  • Install the bumped plugin on a fresh machine.
  • Run a session with HIVEMIND_SUMMARY_EVERY_N_MSGS=10 to force a quick trigger; confirm ~/.claude/hooks/deeplake-wiki.log shows a Periodic: threshold hit entry.
  • Verify the summary appears in the memory table before the session ends.
  • --resume a prior session, add one event, confirm the worker continues from the previous lastSummaryCount rather than starting from zero.
  • Repeat for the codex plugin via codex exec.

v0.6.35 — Rename DEEPLAKE_* env vars to HIVEMIND_*

17 Apr 08:27

Choose a tag to compare

Summary

Renames all 13 env vars from DEEPLAKE_* prefix to HIVEMIND_*:

Old New
DEEPLAKE_TOKEN HIVEMIND_TOKEN
DEEPLAKE_ORG_ID HIVEMIND_ORG_ID
DEEPLAKE_WORKSPACE_ID HIVEMIND_WORKSPACE_ID
DEEPLAKE_API_URL HIVEMIND_API_URL
DEEPLAKE_TABLE HIVEMIND_TABLE
DEEPLAKE_SESSIONS_TABLE HIVEMIND_SESSIONS_TABLE
DEEPLAKE_MEMORY_PATH HIVEMIND_MEMORY_PATH
DEEPLAKE_CAPTURE HIVEMIND_CAPTURE
DEEPLAKE_DEBUG HIVEMIND_DEBUG
DEEPLAKE_MOUNT HIVEMIND_MOUNT
DEEPLAKE_AUTH_CMD HIVEMIND_AUTH_CMD
DEEPLAKE_TRACE_SQL HIVEMIND_TRACE_SQL
DEEPLAKE_WIKI_WORKER HIVEMIND_WIKI_WORKER

Test plan

  • npm test — 353 tests pass
  • npm run build — all 17 bundles built clean

Note: This is a breaking change. Users who set DEEPLAKE_CAPTURE=false etc. will need to switch to HIVEMIND_CAPTURE=false.

v0.6.34 — Rename DEEPLAKE_* env vars to HIVEMIND_*

17 Apr 08:22

Choose a tag to compare

Summary

Renames all 13 env vars from DEEPLAKE_* prefix to HIVEMIND_*:

Old New
DEEPLAKE_TOKEN HIVEMIND_TOKEN
DEEPLAKE_ORG_ID HIVEMIND_ORG_ID
DEEPLAKE_WORKSPACE_ID HIVEMIND_WORKSPACE_ID
DEEPLAKE_API_URL HIVEMIND_API_URL
DEEPLAKE_TABLE HIVEMIND_TABLE
DEEPLAKE_SESSIONS_TABLE HIVEMIND_SESSIONS_TABLE
DEEPLAKE_MEMORY_PATH HIVEMIND_MEMORY_PATH
DEEPLAKE_CAPTURE HIVEMIND_CAPTURE
DEEPLAKE_DEBUG HIVEMIND_DEBUG
DEEPLAKE_MOUNT HIVEMIND_MOUNT
DEEPLAKE_AUTH_CMD HIVEMIND_AUTH_CMD
DEEPLAKE_TRACE_SQL HIVEMIND_TRACE_SQL
DEEPLAKE_WIKI_WORKER HIVEMIND_WIKI_WORKER

Test plan

  • npm test — 353 tests pass
  • npm run build — all 17 bundles built clean

Note: This is a breaking change. Users who set DEEPLAKE_CAPTURE=false etc. will need to switch to HIVEMIND_CAPTURE=false.

v0.6.33 — fix: respect DEEPLAKE_CAPTURE=false in claude-code session-start hook

16 Apr 20:12

Choose a tag to compare

Summary

  • The sync claude-code session-start.ts hook was creating placeholder summaries unconditionally, ignoring DEEPLAKE_CAPTURE=false.
  • Commit 39a5a42 added the captureEnabled guard to session-end.ts, session-start-setup.ts, and the codex hooks, but session-start.ts was missed after the sync/async split.
  • This PR adds the same guard around createPlaceholder. ensureTable / ensureSessionsTable still run unconditionally so fast-path queries continue to see fresh data.

Impact observed

During a 250-question locomo retrieval benchmark the memory table grew from the expected 272 rows (one summary per session) to 416 rows — 144 stray placeholder rows written by each claude -p subprocess the benchmark spawned, despite those subprocesses being launched with DEEPLAKE_CAPTURE=false. The extra rows diluted grep/BM25 results and measurably hurt retrieval accuracy for that run.

Test plan

  • npm run ci (typecheck + vitest)
  • Start a session with DEEPLAKE_CAPTURE=false claude -p 'hello' and confirm no new row appears in the memory table and the wiki log shows placeholder skipped (DEEPLAKE_CAPTURE=false).
  • Start a normal session without the env var and confirm the placeholder is still created (default behavior unchanged).
  • Re-run the locomo plugin benchmark and verify the memory table stays at 272 rows.

v0.6.32 — fix: auto-update broken since Claude Code v2.1.94 (cache layout)

16 Apr 04:19

Choose a tag to compare

Problem

Auto-update has been silently broken for all Claude Code users since v2.1.94 (April 7, 2026 — 9 days ago).

In v2.1.94, Claude Code changed CLAUDE_PLUGIN_ROOT to resolve to the cache directory instead of the marketplace source. The cache layout does not include a package.json with the plugin version:

# Marketplace (before v2.1.94) — worked
marketplaces/hivemind/package.json → {"name":"hivemind","version":"0.6.30"}

# Cache (v2.1.94+) — broken
cache/hivemind/hivemind/0.6.31/package.json → does not exist
cache/hivemind/hivemind/0.6.31/bundle/package.json → {"type":"module"} (no version)

getInstalledVersion() walks up from bundle/ looking for package.json with name: "hivemind", never finds one, returns null, and the version check is skipped entirely.

The Codex hook was not affected because it already reads .codex-plugin/plugin.json as a primary source.

Fix

Read .claude-plugin/plugin.json as the primary version source in both session-start.ts and session-start-setup.ts, matching what Codex already does. This file exists in both cache and marketplace layouts:

cache/hivemind/hivemind/0.6.31/.claude-plugin/plugin.json → {"name":"hivemind","version":"0.6.31"}

Also removes the last deeplake_sync_table() call that was missed in the previous cleanup.

Test plan

  • 534 unit tests passing
  • 3 new tests: verify bundles contain plugin.json read + plugin.json exists with valid semver
  • Tested manually from cache directory: getInstalledVersion() returns "0.6.31" (was null)
  • Verified auto-update log: "version up to date: 0.6.31" (was silent skip)

v0.6.31 — perf: async hooks, fast-path VFS reads, security fixes

16 Apr 03:47

Choose a tag to compare

Summary

Major performance overhaul for the Hivemind plugin. Three key areas: async session startup, direct SQL fast-path for all memory reads, and security hardening.

1. Async session startup

Split session-start into two hooks:

  • Sync (50ms): read credentials, inject context — Claude/Codex starts immediately
  • Async (background): table creation, placeholder row, version check, auto-update

For Codex (no async hook support), the setup is spawned as a detached child process.

2. Direct SQL fast-path for all VFS reads

Every read command on the virtual filesystem now executes a single direct SQL query instead of spawning a Node.js shell process that loads the entire file tree (400+ rows).

Command Before After Speedup
grep 143.9s / 108q 0.46s / 1q 312x
cat 995ms / 3q 151ms / 1q 7x
head 1065ms / 3q 142ms / 1q 8x
ls 920ms / 2q 128ms / 1q 7x
find 916ms / 2q 172ms / 1q 5x
wc -l 1077ms / 4q 144ms / 1q 8x

Handles real-world patterns Claude generates: 2>/dev/null, 2>&1 | head -N, cat f | grep | head.

Smart table routing: /sessions/* queries sessions table directly, /summaries/* queries memory only.

Virtual index.md generation for both CC and Codex.

3. Security fixes

  • Validate git tag as semver before shell interpolation in codex auto-update
  • Escape find -name pattern with sqlLike() before SQL interpolation

4. Other improvements

  • Removed deeplake_sync_table() from all hooks (11 occurrences, 100-300ms each)
  • SQL query tracing via DEEPLAKE_DEBUG=1 / DEEPLAKE_TRACE_SQL=1
  • Shared grep module (grep-direct.ts) for CC and Codex
  • Fixed grep interceptor mount="/" bug
  • CI: test coverage reporting in workflow summary
  • CI: use PR description as release body

Test plan

  • 531 unit tests passing (vitest), 80.6% statement coverage
  • 25 new parseBashGrep() tests for all flag combinations
  • 49 command variants tested (42 fast-path, 8 shell expected, 0 broken)
  • E2E tested on activeloop/hivemind (405 files) — both CC and Codex
  • Fresh workspace test (test_plugin/test3) — tables created correctly
  • Auto-update tested with version downgrade — both CC and Codex

v0.6.30 — perf: async hooks, fast-path VFS reads, security fixes

16 Apr 03:29

Choose a tag to compare

Summary

Major performance overhaul for the Hivemind plugin. Three key areas: async session startup, direct SQL fast-path for all memory reads, and security hardening.

1. Async session startup

Split session-start into two hooks:

  • Sync (50ms): read credentials, inject context — Claude/Codex starts immediately
  • Async (background): table creation, placeholder row, version check, auto-update

For Codex (no async hook support), the setup is spawned as a detached child process.

2. Direct SQL fast-path for all VFS reads

Every read command on the virtual filesystem now executes a single direct SQL query instead of spawning a Node.js shell process that loads the entire file tree (400+ rows).

Command Before After Speedup
grep 143.9s / 108q 0.46s / 1q 312x
cat 995ms / 3q 151ms / 1q 7x
head 1065ms / 3q 142ms / 1q 8x
ls 920ms / 2q 128ms / 1q 7x
find 916ms / 2q 172ms / 1q 5x
wc -l 1077ms / 4q 144ms / 1q 8x

Handles real-world patterns Claude generates: 2>/dev/null, 2>&1 | head -N, cat f | grep | head.

Smart table routing: /sessions/* queries sessions table directly, /summaries/* queries memory only.

Virtual index.md generation for both CC and Codex.

3. Security fixes

  • Validate git tag as semver before shell interpolation in codex auto-update
  • Escape find -name pattern with sqlLike() before SQL interpolation

4. Other improvements

  • Removed deeplake_sync_table() from all hooks (11 occurrences, 100-300ms each)
  • SQL query tracing via DEEPLAKE_DEBUG=1 / DEEPLAKE_TRACE_SQL=1
  • Shared grep module (grep-direct.ts) for CC and Codex
  • Fixed grep interceptor mount="/" bug
  • CI: test coverage reporting in workflow summary
  • CI: use PR description as release body

Test plan

  • 531 unit tests passing (vitest), 80.6% statement coverage
  • 25 new parseBashGrep() tests for all flag combinations
  • 49 command variants tested (42 fast-path, 8 shell expected, 0 broken)
  • E2E tested on activeloop/hivemind (405 files) — both CC and Codex
  • Fresh workspace test (test_plugin/test3) — tables created correctly
  • Auto-update tested with version downgrade — both CC and Codex

v0.6.29 — Add /hivemind_capture toggle and fix Deeplake casing

16 Apr 03:21

Choose a tag to compare

Summary

  • Add /hivemind_capture command to toggle conversation capture on/off
  • Add unlinkSync to OpenClaw esbuild fs wrapper (needed by shared auth.ts)
  • Fix Deeplake casing in pre-tool-use descriptions (DeepLakeDeeplake)
  • Fix duplicate post-build import in esbuild config

Test plan

  • Recall working — 5 memories recalled per turn
  • Capture working — openclaw sessions written to Deeplake sessions table
  • /hivemind_capture toggles capture on/off
  • Bundle passes OpenClaw security scanner (0 flagged patterns)
  • Build + smoke test passes

v0.6.28

15 Apr 20:20

Choose a tag to compare

What's Changed

  • Add /hivemind_capture toggle and fix Deeplake casing by @kaghni in #51

Full Changelog: v0.6.27...v0.6.28