Releases: activeloopai/hivemind
v0.6.37 — fix(grep): dual-table search + session content normalization
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 —
normalizeContentnever 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 overgrepBothTables.parseBashGrepkept in place.src/shell/grep-interceptor.ts[-24 lines, heavy rewrite] — usessearchDeeplakeTables, keeps the in-memory cache fallback viafs.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 fromnpm run build.
Commits
feat(grep): add shared grep-core with dual-table search + normalizationrefactor(grep): fast-path grep delegates to shared grep-corefix(shell grep): drop broken BM25 query, route through shared corebuild: regenerate bundles for dual-table grep + normalize
Test plan
-
npm run ci(typecheck + vitest) -
claude-code/tests/grep-direct.test.tsandclaude-code/tests/grep-interceptor.test.tspass without edits - Manual:
HIVEMIND_DEBUG=1 claude -p "Use Grep with pattern=Brave on memory path"— log shows twoquery startlines (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)
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.tsincrementstotalCountafter each successful INSERT.wiki-worker.tsupdateslastSummaryAt+lastSummaryCountafter a successful upload.- Never deleted, so
--resumecontinues 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 multipleasync: truecapture 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 slimmedsession-end.ts).src/hooks/codex/spawn-wiki-worker.ts— codex (also used by the slimmedstop.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.tssrc/hooks/spawn-wiki-worker.tssrc/hooks/codex/spawn-wiki-worker.ts
Updated hooks (6):
src/hooks/capture.ts,src/hooks/session-end.ts,src/hooks/wiki-worker.tssrc/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 test→ 353/353 passingnpm 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 →
readStatereturns null, next bump starts fresh. - Stale lock (> 10 min) → reclaimed automatically.
- Clock skew (
lastSummaryAtin 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 -psession withHIVEMIND_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 correctcodexBin/~/.codex/paths, log entries match.
Bugs found and fixed during testing
Number(\"1.5\")was previously accepted asN = 1. Fixed by requiringNumber.isIntegerfor N.- Read-modify-write race between concurrent
capture.tsprocesses: a 5 × 10 burst lost 32/50 counter updates. Fixed by wrappingbumpTotalCountin anopenSync(..., \"wx\")RMW lock.
Commits
- `feat: add platform-agnostic summary-state sidecar module`
- `refactor(claude-code): extract wiki-worker spawn into shared helper`
- `feat(claude-code): persist sidecar state from wiki-worker`
- `feat(claude-code): trigger periodic summary from capture hook`
- `refactor(codex): extract wiki-worker spawn into shared helper`
- `feat(codex): persist sidecar state from wiki-worker`
- `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=10to force a quick trigger; confirm~/.claude/hooks/deeplake-wiki.logshows aPeriodic: threshold hitentry. - Verify the summary appears in the memory table before the session ends.
-
--resumea prior session, add one event, confirm the worker continues from the previouslastSummaryCountrather than starting from zero. - Repeat for the codex plugin via
codex exec.
v0.6.35 — Rename DEEPLAKE_* env vars to HIVEMIND_*
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_*
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
Summary
- The sync claude-code
session-start.tshook was creating placeholder summaries unconditionally, ignoringDEEPLAKE_CAPTURE=false. - Commit 39a5a42 added the
captureEnabledguard tosession-end.ts,session-start-setup.ts, and the codex hooks, butsession-start.tswas missed after the sync/async split. - This PR adds the same guard around
createPlaceholder.ensureTable/ensureSessionsTablestill 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 thememorytable and the wiki log showsplaceholder 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)
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"(wasnull) - 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
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 -namepattern withsqlLike()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
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 -namepattern withsqlLike()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
Summary
- Add
/hivemind_capturecommand to toggle conversation capture on/off - Add
unlinkSyncto OpenClaw esbuild fs wrapper (needed by shared auth.ts) - Fix Deeplake casing in pre-tool-use descriptions (
DeepLake→Deeplake) - 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_capturetoggles capture on/off - Bundle passes OpenClaw security scanner (0 flagged patterns)
- Build + smoke test passes
v0.6.28
What's Changed
Full Changelog: v0.6.27...v0.6.28